17c478bd9Sstevel@tonic-gate /*
223a1cceaSRoger A. Faulkner * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
348bbca81SDaniel Hoffman * Copyright (c) 2016 by Delphix. All rights reserved.
47c478bd9Sstevel@tonic-gate */
57c478bd9Sstevel@tonic-gate
67c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
7*bfbf29e2SToomas Soome /* All Rights Reserved */
87c478bd9Sstevel@tonic-gate
97c478bd9Sstevel@tonic-gate /*
107c478bd9Sstevel@tonic-gate * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
117c478bd9Sstevel@tonic-gate * All rights reserved.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted
147c478bd9Sstevel@tonic-gate * provided that: (1) source distributions retain this entire copyright
157c478bd9Sstevel@tonic-gate * notice and comment, and (2) distributions including binaries display
167c478bd9Sstevel@tonic-gate * the following acknowledgement: ``This product includes software
177c478bd9Sstevel@tonic-gate * developed by the University of California, Berkeley and its contributors''
187c478bd9Sstevel@tonic-gate * in the documentation or other materials provided with the distribution
197c478bd9Sstevel@tonic-gate * and in all advertising materials mentioning features or use of this
207c478bd9Sstevel@tonic-gate * software. Neither the name of the University nor the names of its
217c478bd9Sstevel@tonic-gate * contributors may be used to endorse or promote products derived
227c478bd9Sstevel@tonic-gate * from this software without specific prior written permission.
237c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
247c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
257c478bd9Sstevel@tonic-gate * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
267c478bd9Sstevel@tonic-gate */
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gate #include <stdio.h>
29355d6bb5Sswilcox #include <stdlib.h>
30355d6bb5Sswilcox #include <unistd.h>
31355d6bb5Sswilcox #include <stdarg.h>
32355d6bb5Sswilcox #include <libadm.h>
33355d6bb5Sswilcox #include <note.h>
347c478bd9Sstevel@tonic-gate #include <sys/param.h>
357c478bd9Sstevel@tonic-gate #include <sys/types.h>
367c478bd9Sstevel@tonic-gate #include <sys/mntent.h>
377c478bd9Sstevel@tonic-gate #include <sys/filio.h>
387c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fs.h>
397c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
407c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_acl.h>
41355d6bb5Sswilcox #include <sys/fs/ufs_inode.h>
42355d6bb5Sswilcox #include <sys/fs/ufs_log.h>
437c478bd9Sstevel@tonic-gate #define _KERNEL
447c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fsdir.h>
457c478bd9Sstevel@tonic-gate #undef _KERNEL
467c478bd9Sstevel@tonic-gate #include <sys/mnttab.h>
477c478bd9Sstevel@tonic-gate #include <sys/types.h>
487c478bd9Sstevel@tonic-gate #include <sys/stat.h>
49355d6bb5Sswilcox #include <fcntl.h>
50355d6bb5Sswilcox #include <signal.h>
517c478bd9Sstevel@tonic-gate #include <string.h>
527c478bd9Sstevel@tonic-gate #include <ctype.h>
537c478bd9Sstevel@tonic-gate #include <sys/vfstab.h>
547c478bd9Sstevel@tonic-gate #include <sys/lockfs.h>
557c478bd9Sstevel@tonic-gate #include <errno.h>
56355d6bb5Sswilcox #include <sys/cmn_err.h>
57355d6bb5Sswilcox #include <sys/dkio.h>
58355d6bb5Sswilcox #include <sys/vtoc.h>
59355d6bb5Sswilcox #include <sys/efi_partition.h>
60355d6bb5Sswilcox #include <fslib.h>
61355d6bb5Sswilcox #include <inttypes.h>
62355d6bb5Sswilcox #include "fsck.h"
637c478bd9Sstevel@tonic-gate
64*bfbf29e2SToomas Soome struct bufarea *pbp;
65*bfbf29e2SToomas Soome struct bufarea *pdirbp;
66355d6bb5Sswilcox caddr_t mount_point = NULL;
67*bfbf29e2SToomas Soome static struct bufarea bufhead; /* head of list of other blks in filesys */
68*bfbf29e2SToomas Soome char *elock_combuf;
69*bfbf29e2SToomas Soome char *elock_mountp;
70*bfbf29e2SToomas Soome static struct lockfs *lfp; /* current lockfs status */
71355d6bb5Sswilcox
72355d6bb5Sswilcox static int64_t diskreads, totalreads; /* Disk cache statistics */
73355d6bb5Sswilcox
74355d6bb5Sswilcox static int log_checksum(int32_t *, int32_t *, int);
75355d6bb5Sswilcox static void vdirerror(fsck_ino_t, caddr_t, va_list);
76355d6bb5Sswilcox static struct mnttab *search_mnttab(caddr_t, caddr_t, caddr_t, size_t);
77355d6bb5Sswilcox static struct vfstab *search_vfstab(caddr_t, caddr_t, caddr_t, size_t);
78355d6bb5Sswilcox static void vpwarn(caddr_t, va_list);
7923a1cceaSRoger A. Faulkner static int getaline(FILE *, caddr_t, int);
80355d6bb5Sswilcox static struct bufarea *alloc_bufarea(void);
81355d6bb5Sswilcox static void rwerror(caddr_t, diskaddr_t, int rval);
82355d6bb5Sswilcox static void debugclean(void);
83355d6bb5Sswilcox static void report_io_prob(caddr_t, diskaddr_t, size_t, ssize_t);
84355d6bb5Sswilcox static void freelogblk(daddr32_t);
85355d6bb5Sswilcox static void verrexit(caddr_t, va_list);
86355d6bb5Sswilcox static void vpfatal(caddr_t, va_list);
87355d6bb5Sswilcox static diskaddr_t get_device_size(int, caddr_t);
88355d6bb5Sswilcox static diskaddr_t brute_force_get_device_size(int);
89355d6bb5Sswilcox static void cg_constants(int, daddr32_t *, daddr32_t *, daddr32_t *,
90355d6bb5Sswilcox daddr32_t *, daddr32_t *, daddr32_t *);
917c478bd9Sstevel@tonic-gate
92355d6bb5Sswilcox int
ftypeok(struct dinode * dp)93355d6bb5Sswilcox ftypeok(struct dinode *dp)
947c478bd9Sstevel@tonic-gate {
957c478bd9Sstevel@tonic-gate switch (dp->di_mode & IFMT) {
967c478bd9Sstevel@tonic-gate
977c478bd9Sstevel@tonic-gate case IFDIR:
987c478bd9Sstevel@tonic-gate case IFREG:
997c478bd9Sstevel@tonic-gate case IFBLK:
1007c478bd9Sstevel@tonic-gate case IFCHR:
1017c478bd9Sstevel@tonic-gate case IFLNK:
1027c478bd9Sstevel@tonic-gate case IFSOCK:
1037c478bd9Sstevel@tonic-gate case IFIFO:
1047c478bd9Sstevel@tonic-gate case IFSHAD:
1057c478bd9Sstevel@tonic-gate case IFATTRDIR:
1067c478bd9Sstevel@tonic-gate return (1);
1077c478bd9Sstevel@tonic-gate
1087c478bd9Sstevel@tonic-gate default:
1097c478bd9Sstevel@tonic-gate if (debug)
110355d6bb5Sswilcox (void) printf("bad file type 0%o\n", dp->di_mode);
1117c478bd9Sstevel@tonic-gate return (0);
1127c478bd9Sstevel@tonic-gate }
1137c478bd9Sstevel@tonic-gate }
1147c478bd9Sstevel@tonic-gate
115355d6bb5Sswilcox int
acltypeok(struct dinode * dp)116355d6bb5Sswilcox acltypeok(struct dinode *dp)
1177c478bd9Sstevel@tonic-gate {
1187c478bd9Sstevel@tonic-gate if (CHECK_ACL_ALLOWED(dp->di_mode & IFMT))
1197c478bd9Sstevel@tonic-gate return (1);
1207c478bd9Sstevel@tonic-gate
1217c478bd9Sstevel@tonic-gate if (debug)
122355d6bb5Sswilcox (void) printf("bad file type for acl I=%d: 0%o\n",
123355d6bb5Sswilcox dp->di_shadow, dp->di_mode);
1247c478bd9Sstevel@tonic-gate return (0);
1257c478bd9Sstevel@tonic-gate }
1267c478bd9Sstevel@tonic-gate
127355d6bb5Sswilcox NOTE(PRINTFLIKE(1))
128355d6bb5Sswilcox int
reply(caddr_t fmt,...)129355d6bb5Sswilcox reply(caddr_t fmt, ...)
1307c478bd9Sstevel@tonic-gate {
131355d6bb5Sswilcox va_list ap;
1327c478bd9Sstevel@tonic-gate char line[80];
1337c478bd9Sstevel@tonic-gate
1347c478bd9Sstevel@tonic-gate if (preen)
135355d6bb5Sswilcox pfatal("INTERNAL ERROR: GOT TO reply() in preen mode");
1367c478bd9Sstevel@tonic-gate
1377c478bd9Sstevel@tonic-gate if (mflag) {
138355d6bb5Sswilcox /*
139355d6bb5Sswilcox * We don't know what's going on, so don't potentially
140355d6bb5Sswilcox * make things worse by having errexit() write stuff
141355d6bb5Sswilcox * out to disk.
142355d6bb5Sswilcox */
143355d6bb5Sswilcox (void) printf(
144355d6bb5Sswilcox "\n%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n",
145355d6bb5Sswilcox devname);
146355d6bb5Sswilcox exit(EXERRFATAL);
1477c478bd9Sstevel@tonic-gate }
1487c478bd9Sstevel@tonic-gate
149355d6bb5Sswilcox va_start(ap, fmt);
150355d6bb5Sswilcox (void) putchar('\n');
151355d6bb5Sswilcox (void) vprintf(fmt, ap);
152355d6bb5Sswilcox (void) putchar('?');
153355d6bb5Sswilcox (void) putchar(' ');
154355d6bb5Sswilcox va_end(ap);
155355d6bb5Sswilcox
1567c478bd9Sstevel@tonic-gate if (nflag || fswritefd < 0) {
157355d6bb5Sswilcox (void) printf(" no\n\n");
1587c478bd9Sstevel@tonic-gate return (0);
1597c478bd9Sstevel@tonic-gate }
1607c478bd9Sstevel@tonic-gate if (yflag) {
161355d6bb5Sswilcox (void) printf(" yes\n\n");
1627c478bd9Sstevel@tonic-gate return (1);
1637c478bd9Sstevel@tonic-gate }
164355d6bb5Sswilcox (void) fflush(stdout);
16523a1cceaSRoger A. Faulkner if (getaline(stdin, line, sizeof (line)) == EOF)
1667c478bd9Sstevel@tonic-gate errexit("\n");
167355d6bb5Sswilcox (void) printf("\n");
168355d6bb5Sswilcox if (line[0] == 'y' || line[0] == 'Y') {
1697c478bd9Sstevel@tonic-gate return (1);
170355d6bb5Sswilcox } else {
1717c478bd9Sstevel@tonic-gate return (0);
1727c478bd9Sstevel@tonic-gate }
1737c478bd9Sstevel@tonic-gate }
1747c478bd9Sstevel@tonic-gate
175355d6bb5Sswilcox int
getaline(FILE * fp,caddr_t loc,int maxlen)17623a1cceaSRoger A. Faulkner getaline(FILE *fp, caddr_t loc, int maxlen)
1777c478bd9Sstevel@tonic-gate {
1787c478bd9Sstevel@tonic-gate int n;
179355d6bb5Sswilcox caddr_t p, lastloc;
1807c478bd9Sstevel@tonic-gate
1817c478bd9Sstevel@tonic-gate p = loc;
1827c478bd9Sstevel@tonic-gate lastloc = &p[maxlen-1];
1837c478bd9Sstevel@tonic-gate while ((n = getc(fp)) != '\n') {
1847c478bd9Sstevel@tonic-gate if (n == EOF)
1857c478bd9Sstevel@tonic-gate return (EOF);
1867c478bd9Sstevel@tonic-gate if (!isspace(n) && p < lastloc)
187355d6bb5Sswilcox *p++ = (char)n;
1887c478bd9Sstevel@tonic-gate }
189355d6bb5Sswilcox *p = '\0';
190355d6bb5Sswilcox /* LINTED pointer difference won't overflow */
1917c478bd9Sstevel@tonic-gate return (p - loc);
1927c478bd9Sstevel@tonic-gate }
193355d6bb5Sswilcox
1947c478bd9Sstevel@tonic-gate /*
1957c478bd9Sstevel@tonic-gate * Malloc buffers and set up cache.
1967c478bd9Sstevel@tonic-gate */
197355d6bb5Sswilcox void
bufinit(void)198355d6bb5Sswilcox bufinit(void)
1997c478bd9Sstevel@tonic-gate {
2007c478bd9Sstevel@tonic-gate struct bufarea *bp;
2017c478bd9Sstevel@tonic-gate int bufcnt, i;
202355d6bb5Sswilcox caddr_t bufp;
2037c478bd9Sstevel@tonic-gate
204355d6bb5Sswilcox bufp = malloc((size_t)sblock.fs_bsize);
205355d6bb5Sswilcox if (bufp == NULL)
206355d6bb5Sswilcox goto nomem;
2077c478bd9Sstevel@tonic-gate initbarea(&cgblk);
208355d6bb5Sswilcox cgblk.b_un.b_buf = bufp;
2097c478bd9Sstevel@tonic-gate bufhead.b_next = bufhead.b_prev = &bufhead;
2107c478bd9Sstevel@tonic-gate bufcnt = MAXBUFSPACE / sblock.fs_bsize;
2117c478bd9Sstevel@tonic-gate if (bufcnt < MINBUFS)
2127c478bd9Sstevel@tonic-gate bufcnt = MINBUFS;
2137c478bd9Sstevel@tonic-gate for (i = 0; i < bufcnt; i++) {
2147c478bd9Sstevel@tonic-gate bp = (struct bufarea *)malloc(sizeof (struct bufarea));
215355d6bb5Sswilcox if (bp == NULL) {
2167c478bd9Sstevel@tonic-gate if (i >= MINBUFS)
217355d6bb5Sswilcox goto noalloc;
218355d6bb5Sswilcox goto nomem;
219355d6bb5Sswilcox }
220355d6bb5Sswilcox
221355d6bb5Sswilcox bufp = malloc((size_t)sblock.fs_bsize);
222355d6bb5Sswilcox if (bufp == NULL) {
223355d6bb5Sswilcox free((void *)bp);
224355d6bb5Sswilcox if (i >= MINBUFS)
225355d6bb5Sswilcox goto noalloc;
226355d6bb5Sswilcox goto nomem;
2277c478bd9Sstevel@tonic-gate }
228355d6bb5Sswilcox initbarea(bp);
2297c478bd9Sstevel@tonic-gate bp->b_un.b_buf = bufp;
2307c478bd9Sstevel@tonic-gate bp->b_prev = &bufhead;
2317c478bd9Sstevel@tonic-gate bp->b_next = bufhead.b_next;
2327c478bd9Sstevel@tonic-gate bufhead.b_next->b_prev = bp;
2337c478bd9Sstevel@tonic-gate bufhead.b_next = bp;
2347c478bd9Sstevel@tonic-gate }
235355d6bb5Sswilcox noalloc:
2367c478bd9Sstevel@tonic-gate bufhead.b_size = i; /* save number of buffers */
2377c478bd9Sstevel@tonic-gate pbp = pdirbp = NULL;
238355d6bb5Sswilcox return;
239355d6bb5Sswilcox
240355d6bb5Sswilcox nomem:
241355d6bb5Sswilcox errexit("cannot allocate buffer pool\n");
242355d6bb5Sswilcox /* NOTREACHED */
243355d6bb5Sswilcox }
244355d6bb5Sswilcox
245355d6bb5Sswilcox /*
246355d6bb5Sswilcox * Undo a bufinit().
247355d6bb5Sswilcox */
248355d6bb5Sswilcox void
unbufinit(void)249355d6bb5Sswilcox unbufinit(void)
250355d6bb5Sswilcox {
251355d6bb5Sswilcox int cnt;
252355d6bb5Sswilcox struct bufarea *bp, *nbp;
253355d6bb5Sswilcox
254355d6bb5Sswilcox cnt = 0;
255355d6bb5Sswilcox for (bp = bufhead.b_prev; bp != NULL && bp != &bufhead; bp = nbp) {
256355d6bb5Sswilcox cnt++;
257355d6bb5Sswilcox flush(fswritefd, bp);
258355d6bb5Sswilcox nbp = bp->b_prev;
259355d6bb5Sswilcox /*
260355d6bb5Sswilcox * We're discarding the entire chain, so this isn't
261355d6bb5Sswilcox * technically necessary. However, it doesn't hurt
262355d6bb5Sswilcox * and lint's data flow analysis is much happier
263355d6bb5Sswilcox * (this prevents it from thinking there's a chance
264355d6bb5Sswilcox * of our using memory elsewhere after it's been released).
265355d6bb5Sswilcox */
266355d6bb5Sswilcox nbp->b_next = bp->b_next;
267355d6bb5Sswilcox bp->b_next->b_prev = nbp;
268355d6bb5Sswilcox free((void *)bp->b_un.b_buf);
269355d6bb5Sswilcox free((void *)bp);
270355d6bb5Sswilcox }
271355d6bb5Sswilcox
272355d6bb5Sswilcox if (bufhead.b_size != cnt)
273355d6bb5Sswilcox errexit("Panic: cache lost %d buffers\n",
2741493b746SMilan Cermak bufhead.b_size - cnt);
2757c478bd9Sstevel@tonic-gate }
2767c478bd9Sstevel@tonic-gate
2777c478bd9Sstevel@tonic-gate /*
2787c478bd9Sstevel@tonic-gate * Manage a cache of directory blocks.
2797c478bd9Sstevel@tonic-gate */
2807c478bd9Sstevel@tonic-gate struct bufarea *
getdatablk(daddr32_t blkno,size_t size)281355d6bb5Sswilcox getdatablk(daddr32_t blkno, size_t size)
2827c478bd9Sstevel@tonic-gate {
2837c478bd9Sstevel@tonic-gate struct bufarea *bp;
2847c478bd9Sstevel@tonic-gate
2857c478bd9Sstevel@tonic-gate for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next)
286355d6bb5Sswilcox if (bp->b_bno == fsbtodb(&sblock, blkno)) {
2877c478bd9Sstevel@tonic-gate goto foundit;
288355d6bb5Sswilcox }
2897c478bd9Sstevel@tonic-gate for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev)
2907c478bd9Sstevel@tonic-gate if ((bp->b_flags & B_INUSE) == 0)
2917c478bd9Sstevel@tonic-gate break;
2927c478bd9Sstevel@tonic-gate if (bp == &bufhead) {
2937c478bd9Sstevel@tonic-gate bp = alloc_bufarea();
294355d6bb5Sswilcox if (bp == NULL) {
2957c478bd9Sstevel@tonic-gate errexit("deadlocked buffer pool\n");
296355d6bb5Sswilcox /* NOTREACHED */
297355d6bb5Sswilcox }
2987c478bd9Sstevel@tonic-gate }
299355d6bb5Sswilcox /*
300355d6bb5Sswilcox * We're at the same logical level as getblk(), so if there
301355d6bb5Sswilcox * are any errors, we'll let our caller handle them.
302355d6bb5Sswilcox */
303355d6bb5Sswilcox diskreads++;
304355d6bb5Sswilcox (void) getblk(bp, blkno, size);
305355d6bb5Sswilcox
3067c478bd9Sstevel@tonic-gate foundit:
3077c478bd9Sstevel@tonic-gate totalreads++;
3087c478bd9Sstevel@tonic-gate bp->b_cnt++;
3097c478bd9Sstevel@tonic-gate /*
310355d6bb5Sswilcox * Move the buffer to head of linked list if it isn't
3117c478bd9Sstevel@tonic-gate * already there.
3127c478bd9Sstevel@tonic-gate */
3137c478bd9Sstevel@tonic-gate if (bufhead.b_next != bp) {
3147c478bd9Sstevel@tonic-gate bp->b_prev->b_next = bp->b_next;
3157c478bd9Sstevel@tonic-gate bp->b_next->b_prev = bp->b_prev;
3167c478bd9Sstevel@tonic-gate bp->b_prev = &bufhead;
3177c478bd9Sstevel@tonic-gate bp->b_next = bufhead.b_next;
3187c478bd9Sstevel@tonic-gate bufhead.b_next->b_prev = bp;
3197c478bd9Sstevel@tonic-gate bufhead.b_next = bp;
3207c478bd9Sstevel@tonic-gate }
3217c478bd9Sstevel@tonic-gate bp->b_flags |= B_INUSE;
3227c478bd9Sstevel@tonic-gate return (bp);
3237c478bd9Sstevel@tonic-gate }
3247c478bd9Sstevel@tonic-gate
325355d6bb5Sswilcox void
brelse(struct bufarea * bp)3267c478bd9Sstevel@tonic-gate brelse(struct bufarea *bp)
3277c478bd9Sstevel@tonic-gate {
3287c478bd9Sstevel@tonic-gate bp->b_cnt--;
3297c478bd9Sstevel@tonic-gate if (bp->b_cnt == 0) {
3307c478bd9Sstevel@tonic-gate bp->b_flags &= ~B_INUSE;
3317c478bd9Sstevel@tonic-gate }
3327c478bd9Sstevel@tonic-gate }
3337c478bd9Sstevel@tonic-gate
3347c478bd9Sstevel@tonic-gate struct bufarea *
getblk(struct bufarea * bp,daddr32_t blk,size_t size)335355d6bb5Sswilcox getblk(struct bufarea *bp, daddr32_t blk, size_t size)
3367c478bd9Sstevel@tonic-gate {
3377c478bd9Sstevel@tonic-gate diskaddr_t dblk;
3387c478bd9Sstevel@tonic-gate
3397c478bd9Sstevel@tonic-gate dblk = fsbtodb(&sblock, blk);
3407c478bd9Sstevel@tonic-gate if (bp->b_bno == dblk)
3417c478bd9Sstevel@tonic-gate return (bp);
3427c478bd9Sstevel@tonic-gate flush(fswritefd, bp);
343355d6bb5Sswilcox bp->b_errs = fsck_bread(fsreadfd, bp->b_un.b_buf, dblk, size);
3447c478bd9Sstevel@tonic-gate bp->b_bno = dblk;
3457c478bd9Sstevel@tonic-gate bp->b_size = size;
3467c478bd9Sstevel@tonic-gate return (bp);
3477c478bd9Sstevel@tonic-gate }
3487c478bd9Sstevel@tonic-gate
349355d6bb5Sswilcox void
flush(int fd,struct bufarea * bp)350355d6bb5Sswilcox flush(int fd, struct bufarea *bp)
3517c478bd9Sstevel@tonic-gate {
3527c478bd9Sstevel@tonic-gate int i, j;
3537c478bd9Sstevel@tonic-gate caddr_t sip;
3547c478bd9Sstevel@tonic-gate long size;
3557c478bd9Sstevel@tonic-gate
3567c478bd9Sstevel@tonic-gate if (!bp->b_dirty)
3577c478bd9Sstevel@tonic-gate return;
358355d6bb5Sswilcox
359355d6bb5Sswilcox /*
360355d6bb5Sswilcox * It's not our buf, so if there are errors, let whoever
361355d6bb5Sswilcox * acquired it deal with the actual problem.
362355d6bb5Sswilcox */
3637c478bd9Sstevel@tonic-gate if (bp->b_errs != 0)
3647c478bd9Sstevel@tonic-gate pfatal("WRITING ZERO'ED BLOCK %lld TO DISK\n", bp->b_bno);
3657c478bd9Sstevel@tonic-gate bp->b_dirty = 0;
3667c478bd9Sstevel@tonic-gate bp->b_errs = 0;
3677c478bd9Sstevel@tonic-gate bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
368355d6bb5Sswilcox if (bp != &sblk) {
3697c478bd9Sstevel@tonic-gate return;
370355d6bb5Sswilcox }
371355d6bb5Sswilcox
372355d6bb5Sswilcox /*
373355d6bb5Sswilcox * We're flushing the superblock, so make sure all the
374355d6bb5Sswilcox * ancillary bits go out as well.
375355d6bb5Sswilcox */
3767c478bd9Sstevel@tonic-gate sip = (caddr_t)sblock.fs_u.fs_csp;
3777c478bd9Sstevel@tonic-gate for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
3787c478bd9Sstevel@tonic-gate size = sblock.fs_cssize - i < sblock.fs_bsize ?
3797c478bd9Sstevel@tonic-gate sblock.fs_cssize - i : sblock.fs_bsize;
3807c478bd9Sstevel@tonic-gate bwrite(fswritefd, sip,
3817c478bd9Sstevel@tonic-gate fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
3827c478bd9Sstevel@tonic-gate size);
3837c478bd9Sstevel@tonic-gate sip += size;
3847c478bd9Sstevel@tonic-gate }
3857c478bd9Sstevel@tonic-gate }
3867c478bd9Sstevel@tonic-gate
387355d6bb5Sswilcox static void
rwerror(caddr_t mesg,diskaddr_t blk,int rval)388355d6bb5Sswilcox rwerror(caddr_t mesg, diskaddr_t blk, int rval)
3897c478bd9Sstevel@tonic-gate {
390355d6bb5Sswilcox int olderr = errno;
391355d6bb5Sswilcox
392355d6bb5Sswilcox if (!preen)
393355d6bb5Sswilcox (void) printf("\n");
3947c478bd9Sstevel@tonic-gate
395355d6bb5Sswilcox if (rval == -1)
396355d6bb5Sswilcox pfatal("CANNOT %s: DISK BLOCK %lld: %s",
397355d6bb5Sswilcox mesg, blk, strerror(olderr));
398355d6bb5Sswilcox else
399355d6bb5Sswilcox pfatal("CANNOT %s: DISK BLOCK %lld", mesg, blk);
400355d6bb5Sswilcox
401355d6bb5Sswilcox if (reply("CONTINUE") == 0) {
402355d6bb5Sswilcox exitstat = EXERRFATAL;
4037c478bd9Sstevel@tonic-gate errexit("Program terminated\n");
404355d6bb5Sswilcox }
4057c478bd9Sstevel@tonic-gate }
4067c478bd9Sstevel@tonic-gate
407355d6bb5Sswilcox void
ckfini(void)408355d6bb5Sswilcox ckfini(void)
4097c478bd9Sstevel@tonic-gate {
410355d6bb5Sswilcox int64_t percentage;
411355d6bb5Sswilcox
412355d6bb5Sswilcox if (fswritefd < 0)
413355d6bb5Sswilcox return;
4147c478bd9Sstevel@tonic-gate
415355d6bb5Sswilcox flush(fswritefd, &sblk);
4167c478bd9Sstevel@tonic-gate /*
417355d6bb5Sswilcox * Were we using a backup superblock?
4187c478bd9Sstevel@tonic-gate */
4197c478bd9Sstevel@tonic-gate if (havesb && sblk.b_bno != SBOFF / dev_bsize) {
420355d6bb5Sswilcox if (preen || reply("UPDATE STANDARD SUPERBLOCK") == 1) {
421355d6bb5Sswilcox sblk.b_bno = SBOFF / dev_bsize;
422355d6bb5Sswilcox sbdirty();
423355d6bb5Sswilcox flush(fswritefd, &sblk);
424355d6bb5Sswilcox }
4257c478bd9Sstevel@tonic-gate }
4267c478bd9Sstevel@tonic-gate flush(fswritefd, &cgblk);
427355d6bb5Sswilcox if (cgblk.b_un.b_buf != NULL) {
428355d6bb5Sswilcox free((void *)cgblk.b_un.b_buf);
4297c478bd9Sstevel@tonic-gate cgblk.b_un.b_buf = NULL;
4307c478bd9Sstevel@tonic-gate }
431355d6bb5Sswilcox unbufinit();
432355d6bb5Sswilcox pbp = NULL;
433355d6bb5Sswilcox pdirbp = NULL;
434355d6bb5Sswilcox if (debug) {
435355d6bb5Sswilcox /*
436355d6bb5Sswilcox * Note that we only count cache-related reads.
437355d6bb5Sswilcox * Anything that called fsck_bread() or getblk()
438355d6bb5Sswilcox * directly are explicitly not cached, so they're not
439355d6bb5Sswilcox * included here.
440355d6bb5Sswilcox */
441355d6bb5Sswilcox if (totalreads != 0)
442355d6bb5Sswilcox percentage = diskreads * 100 / totalreads;
443355d6bb5Sswilcox else
444355d6bb5Sswilcox percentage = 0;
445355d6bb5Sswilcox
446355d6bb5Sswilcox (void) printf("cache missed %lld of %lld reads (%lld%%)\n",
447355d6bb5Sswilcox (longlong_t)diskreads, (longlong_t)totalreads,
448355d6bb5Sswilcox (longlong_t)percentage);
4497c478bd9Sstevel@tonic-gate }
450355d6bb5Sswilcox
4517c478bd9Sstevel@tonic-gate (void) close(fsreadfd);
4527c478bd9Sstevel@tonic-gate (void) close(fswritefd);
453355d6bb5Sswilcox fsreadfd = -1;
454355d6bb5Sswilcox fswritefd = -1;
4557c478bd9Sstevel@tonic-gate }
4567c478bd9Sstevel@tonic-gate
457355d6bb5Sswilcox int
fsck_bread(int fd,caddr_t buf,diskaddr_t blk,size_t size)458355d6bb5Sswilcox fsck_bread(int fd, caddr_t buf, diskaddr_t blk, size_t size)
4597c478bd9Sstevel@tonic-gate {
460355d6bb5Sswilcox caddr_t cp;
461355d6bb5Sswilcox int i;
4627c478bd9Sstevel@tonic-gate int errs;
4637c478bd9Sstevel@tonic-gate offset_t offset = ldbtob(blk);
4647c478bd9Sstevel@tonic-gate offset_t addr;
4657c478bd9Sstevel@tonic-gate
466355d6bb5Sswilcox /*
467355d6bb5Sswilcox * In our universe, nothing exists before the superblock, so
468355d6bb5Sswilcox * just pretend it's always zeros. This is the complement of
469355d6bb5Sswilcox * bwrite()'s ignoring write requests into that space.
470355d6bb5Sswilcox */
471355d6bb5Sswilcox if (blk < SBLOCK) {
472355d6bb5Sswilcox if (debug)
473355d6bb5Sswilcox (void) printf(
474355d6bb5Sswilcox "WARNING: fsck_bread() passed blkno < %d (%lld)\n",
475355d6bb5Sswilcox SBLOCK, (longlong_t)blk);
476355d6bb5Sswilcox (void) memset(buf, 0, (size_t)size);
477355d6bb5Sswilcox return (1);
4787c478bd9Sstevel@tonic-gate }
479355d6bb5Sswilcox
480f763a6cdScasper if (llseek(fd, offset, SEEK_SET) < 0) {
481355d6bb5Sswilcox rwerror("SEEK", blk, -1);
482355d6bb5Sswilcox }
483355d6bb5Sswilcox
484355d6bb5Sswilcox if ((i = read(fd, buf, size)) == size) {
4857c478bd9Sstevel@tonic-gate return (0);
486355d6bb5Sswilcox }
487355d6bb5Sswilcox rwerror("READ", blk, i);
488f763a6cdScasper if (llseek(fd, offset, SEEK_SET) < 0) {
489355d6bb5Sswilcox rwerror("SEEK", blk, -1);
4907c478bd9Sstevel@tonic-gate }
4917c478bd9Sstevel@tonic-gate errs = 0;
492355d6bb5Sswilcox (void) memset(buf, 0, (size_t)size);
4937c478bd9Sstevel@tonic-gate pwarn("THE FOLLOWING SECTORS COULD NOT BE READ:");
4947c478bd9Sstevel@tonic-gate for (cp = buf, i = 0; i < btodb(size); i++, cp += DEV_BSIZE) {
4957c478bd9Sstevel@tonic-gate addr = ldbtob(blk + i);
496f763a6cdScasper if (llseek(fd, addr, SEEK_SET) < 0 ||
4977c478bd9Sstevel@tonic-gate read(fd, cp, (int)secsize) < 0) {
498355d6bb5Sswilcox iscorrupt = 1;
499355d6bb5Sswilcox (void) printf(" %llu", blk + (u_longlong_t)i);
5007c478bd9Sstevel@tonic-gate errs++;
5017c478bd9Sstevel@tonic-gate }
5027c478bd9Sstevel@tonic-gate }
503355d6bb5Sswilcox (void) printf("\n");
5047c478bd9Sstevel@tonic-gate return (errs);
5057c478bd9Sstevel@tonic-gate }
5067c478bd9Sstevel@tonic-gate
507355d6bb5Sswilcox void
bwrite(int fd,caddr_t buf,diskaddr_t blk,int64_t size)508355d6bb5Sswilcox bwrite(int fd, caddr_t buf, diskaddr_t blk, int64_t size)
5097c478bd9Sstevel@tonic-gate {
510355d6bb5Sswilcox int i;
5117c478bd9Sstevel@tonic-gate int n;
512355d6bb5Sswilcox caddr_t cp;
5137c478bd9Sstevel@tonic-gate offset_t offset = ldbtob(blk);
5147c478bd9Sstevel@tonic-gate offset_t addr;
5157c478bd9Sstevel@tonic-gate
5167c478bd9Sstevel@tonic-gate if (fd < 0)
5177c478bd9Sstevel@tonic-gate return;
5187c478bd9Sstevel@tonic-gate if (blk < SBLOCK) {
5197c478bd9Sstevel@tonic-gate if (debug)
520355d6bb5Sswilcox (void) printf(
521355d6bb5Sswilcox "WARNING: Attempt to write illegal blkno %lld on %s\n",
522355d6bb5Sswilcox (longlong_t)blk, devname);
5237c478bd9Sstevel@tonic-gate return;
5247c478bd9Sstevel@tonic-gate }
525f763a6cdScasper if (llseek(fd, offset, SEEK_SET) < 0) {
526355d6bb5Sswilcox rwerror("SEEK", blk, -1);
527355d6bb5Sswilcox }
528355d6bb5Sswilcox if ((i = write(fd, buf, (int)size)) == size) {
5297c478bd9Sstevel@tonic-gate fsmodified = 1;
5307c478bd9Sstevel@tonic-gate return;
5317c478bd9Sstevel@tonic-gate }
532355d6bb5Sswilcox rwerror("WRITE", blk, i);
533f763a6cdScasper if (llseek(fd, offset, SEEK_SET) < 0) {
534355d6bb5Sswilcox rwerror("SEEK", blk, -1);
5357c478bd9Sstevel@tonic-gate }
5367c478bd9Sstevel@tonic-gate pwarn("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
5377c478bd9Sstevel@tonic-gate for (cp = buf, i = 0; i < btodb(size); i++, cp += DEV_BSIZE) {
5387c478bd9Sstevel@tonic-gate n = 0;
5397c478bd9Sstevel@tonic-gate addr = ldbtob(blk + i);
540f763a6cdScasper if (llseek(fd, addr, SEEK_SET) < 0 ||
5417c478bd9Sstevel@tonic-gate (n = write(fd, cp, DEV_BSIZE)) < 0) {
542355d6bb5Sswilcox iscorrupt = 1;
543355d6bb5Sswilcox (void) printf(" %llu", blk + (u_longlong_t)i);
5447c478bd9Sstevel@tonic-gate } else if (n > 0) {
5457c478bd9Sstevel@tonic-gate fsmodified = 1;
5467c478bd9Sstevel@tonic-gate }
5477c478bd9Sstevel@tonic-gate
5487c478bd9Sstevel@tonic-gate }
549355d6bb5Sswilcox (void) printf("\n");
5507c478bd9Sstevel@tonic-gate }
5517c478bd9Sstevel@tonic-gate
5527c478bd9Sstevel@tonic-gate /*
553355d6bb5Sswilcox * Allocates the specified number of contiguous fragments.
5547c478bd9Sstevel@tonic-gate */
5557c478bd9Sstevel@tonic-gate daddr32_t
allocblk(int wantedfrags)556355d6bb5Sswilcox allocblk(int wantedfrags)
5577c478bd9Sstevel@tonic-gate {
558355d6bb5Sswilcox int block, leadfrag, tailfrag;
559355d6bb5Sswilcox daddr32_t selected;
560355d6bb5Sswilcox size_t size;
561355d6bb5Sswilcox struct bufarea *bp;
5627c478bd9Sstevel@tonic-gate
563355d6bb5Sswilcox /*
564355d6bb5Sswilcox * It's arguable whether we should just fail, or instead
565355d6bb5Sswilcox * error out here. Since we should only ever be asked for
566355d6bb5Sswilcox * a single fragment or an entire block (i.e., sblock.fs_frag),
567355d6bb5Sswilcox * we'll fail out because anything else means somebody
568355d6bb5Sswilcox * changed code without considering all of the ramifications.
569355d6bb5