diff options
Diffstat (limited to 'sbin')
-rw-r--r-- | sbin/fsck_ffs/dir.c | 29 | ||||
-rw-r--r-- | sbin/fsck_ffs/fsck.h | 21 | ||||
-rw-r--r-- | sbin/fsck_ffs/fsutil.c | 49 | ||||
-rw-r--r-- | sbin/fsck_ffs/inode.c | 24 | ||||
-rw-r--r-- | sbin/fsck_ffs/main.c | 94 | ||||
-rw-r--r-- | sbin/fsck_ffs/pass1.c | 20 | ||||
-rw-r--r-- | sbin/fsck_ffs/pass2.c | 3 | ||||
-rw-r--r-- | sbin/fsck_ffs/pass3.c | 3 | ||||
-rw-r--r-- | sbin/fsck_ffs/pass5.c | 260 | ||||
-rw-r--r-- | sbin/fsck_ffs/preen.c | 1 | ||||
-rw-r--r-- | sbin/fsck_ffs/setup.c | 62 | ||||
-rw-r--r-- | sbin/quotacheck/preen.c | 1 |
12 files changed, 399 insertions, 168 deletions
diff --git a/sbin/fsck_ffs/dir.c b/sbin/fsck_ffs/dir.c index 5def8b2..94c6ead 100644 --- a/sbin/fsck_ffs/dir.c +++ b/sbin/fsck_ffs/dir.c @@ -41,6 +41,7 @@ static const char rcsid[] = #include <sys/param.h> #include <sys/time.h> +#include <sys/sysctl.h> #include <ufs/ufs/dinode.h> #include <ufs/ufs/dir.h> @@ -53,7 +54,10 @@ static const char rcsid[] = char *lfname = "lost+found"; int lfmode = 01777; -struct dirtemplate emptydir = { 0, DIRBLKSIZ }; +struct dirtemplate emptydir = { + 0, DIRBLKSIZ, DT_UNKNOWN, 0, "", + 0, 0, DT_UNKNOWN, 0, "" +}; struct dirtemplate dirhead = { 0, 12, DT_DIR, 1, ".", 0, DIRBLKSIZ - 12, DT_DIR, 2, ".." @@ -107,7 +111,7 @@ dirscan(idesc) { register struct direct *dp; register struct bufarea *bp; - int dsize, n; + u_int dsize, n; long blksiz; char dbuf[DIRBLKSIZ]; @@ -324,7 +328,7 @@ adjust(idesc, lcnt) * in preen mode, and are on a filesystem using soft updates, * then just toss any partially allocated files. */ - if (resolved && preen && usedsoftdep) { + if (resolved && (preen || bkgrdflag) && usedsoftdep) { clri(idesc, "UNREF", 1); return; } else { @@ -362,8 +366,19 @@ adjust(idesc, lcnt) printf(" (ADJUSTED)\n"); } if (preen || reply("ADJUST") == 1) { - dp->di_nlink -= lcnt; - inodirty(); + if (bkgrdflag == 0) { + dp->di_nlink -= lcnt; + inodirty(); + } else { + cmd.value = idesc->id_number; + cmd.size = -lcnt; + if (debug) + printf("adjrefcnt ino %d amt %d\n", + (long)cmd.value, cmd.size); + if (sysctl(adjrefcnt, MIBSIZE, 0, 0, + &cmd, sizeof cmd) == -1) + rwerror("ADJUST INODE", cmd.value); + } } } } @@ -448,6 +463,10 @@ linkup(orphan, parentdir, name) pinode(orphan); if (preen && dp->di_size == 0) return (0); + if (cursnapshot != 0) { + pfatal("FILE LINKUP IN SNAPSHOT"); + return (0); + } if (preen) printf(" (RECONNECTED)\n"); else diff --git a/sbin/fsck_ffs/fsck.h b/sbin/fsck_ffs/fsck.h index 7365767..e598b35 100644 --- a/sbin/fsck_ffs/fsck.h +++ b/sbin/fsck_ffs/fsck.h @@ -102,14 +102,18 @@ struct bufarea cgblk; /* cylinder group blocks */ struct bufarea *pdirbp; /* current directory contents */ struct bufarea *pbp; /* current inode block */ -#define dirty(bp) (bp)->b_dirty = 1 +#define dirty(bp) \ + if (fswritefd < 0) \ + pfatal("SETTING DIRTY FLAG IN READ_ONLY MODE\n"); \ + else \ + (bp)->b_dirty = 1 #define initbarea(bp) \ (bp)->b_dirty = 0; \ (bp)->b_bno = (ufs_daddr_t)-1; \ (bp)->b_flags = 0; -#define sbdirty() sblk.b_dirty = 1 -#define cgdirty() cgblk.b_dirty = 1 +#define sbdirty() dirty(&sblk) +#define cgdirty() dirty(&cgblk) #define sblock (*sblk.b_un.b_fs) #define cgrp (*cgblk.b_un.b_cg) @@ -188,12 +192,21 @@ struct inoinfo { long numdirs, dirhash, listmax, inplast; long countdirs; /* number of directories we actually found */ +#define MIBSIZE 3 /* size of fsck sysctl MIBs */ +int adjrefcnt[MIBSIZE]; /* MIB command to adjust inode reference cnt */ +int adjblkcnt[MIBSIZE]; /* MIB command to adjust inode block count */ +int freefiles[MIBSIZE]; /* MIB command to free a set of files */ +int freedirs[MIBSIZE]; /* MIB command to free a set of directories */ +int freeblks[MIBSIZE]; /* MIB command to free a set of data blocks */ +struct fsck_cmd cmd; /* sysctl filesystem update commands */ +char snapname[BUFSIZ]; /* when doing snapshots, the name of the file */ char *cdevname; /* name of device being checked */ long dev_bsize; /* computed value of DEV_BSIZE */ long secsize; /* actual disk sector size */ char fflag; /* force check, ignore clean flag */ char nflag; /* assume a no response */ char yflag; /* assume a yes response */ +int bkgrdflag; /* use a snapshot to run on an active system */ int bflag; /* location of alternate super block */ int debug; /* output debugging info */ int cvtlevel; /* convert to newer file system format */ @@ -205,7 +218,6 @@ char preen; /* just fix normal inconsistencies */ char rerun; /* rerun fsck. Only used in non-preen mode */ int returntosingle; /* 1 => return to single user mode on exit */ char resolved; /* cleared if unresolved changes => not clean */ -int markclean; /* mark file system clean when done */ char havesb; /* superblock has been read */ char skipclean; /* skip clean file systems if preening */ int fsmodified; /* 1 => write done to file system */ @@ -302,6 +314,7 @@ void pinode __P((ino_t ino)); void propagate __P((void)); void pwarn __P((const char *fmt, ...)); int reply __P((char *question)); +void rwerror __P((char *mesg, ufs_daddr_t blk)); void setinodebuf __P((ino_t)); int setup __P((char *dev)); void voidquit __P((int)); diff --git a/sbin/fsck_ffs/fsutil.c b/sbin/fsck_ffs/fsutil.c index 2217f3c..fa06dfb 100644 --- a/sbin/fsck_ffs/fsutil.c +++ b/sbin/fsck_ffs/fsutil.c @@ -60,8 +60,6 @@ static const char rcsid[] = long diskreads, totalreads; /* Disk cache statistics */ -static void rwerror __P((char *mesg, ufs_daddr_t blk)); - int ftypeok(dp) struct dinode *dp; @@ -95,7 +93,7 @@ reply(question) pfatal("INTERNAL ERROR: GOT TO reply()"); persevere = !strcmp(question, "CONTINUE"); printf("\n"); - if (!persevere && (nflag || fswritefd < 0)) { + if (!persevere && (nflag || (fswritefd < 0 && bkgrdflag == 0))) { printf("%s? no\n\n", question); resolved = 0; return (0); @@ -239,11 +237,15 @@ flush(fd, bp) if (!bp->b_dirty) return; + bp->b_dirty = 0; + if (fswritefd < 0) { + pfatal("WRITING IN READ_ONLY MODE.\n"); + return; + } if (bp->b_errs != 0) pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n", (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ", bp->b_bno); - bp->b_dirty = 0; bp->b_errs = 0; bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); if (bp != &sblk) @@ -256,7 +258,7 @@ flush(fd, bp) } } -static void +void rwerror(mesg, blk) char *mesg; ufs_daddr_t blk; @@ -264,7 +266,7 @@ rwerror(mesg, blk) if (preen == 0) printf("\n"); - pfatal("CANNOT %s: BLK %ld", mesg, blk); + pfatal("CANNOT %s: %ld", mesg, blk); if (reply("CONTINUE") == 0) exit(EEXIT); } @@ -276,12 +278,31 @@ ckfini(markclean) register struct bufarea *bp, *nbp; int ofsmodified, cnt = 0; + if (bkgrdflag) { + unlink(snapname); + if ((!(sblock.fs_flags & FS_UNCLEAN)) != markclean) { + cmd.value = FS_UNCLEAN; + cmd.size = markclean ? -1 : 1; + if (sysctlbyname("vfs.ffs.setflags", 0, 0, + &cmd, sizeof cmd) == -1) + rwerror("SET FILESYSTEM FLAGS", FS_UNCLEAN); + if (!preen) { + printf("\n***** FILE SYSTEM MARKED %s *****\n", + markclean ? "CLEAN" : "DIRTY"); + if (!markclean) + rerun = 1; + } + } else if (!preen && !markclean) { + printf("\n***** FILE SYSTEM STILL DIRTY *****\n"); + rerun = 1; + } + } if (fswritefd < 0) { (void)close(fsreadfd); return; } flush(fswritefd, &sblk); - if (havesb && sblk.b_bno != SBOFF / dev_bsize && + if (havesb && sblk.b_bno != SBOFF / dev_bsize && cursnapshot == 0 && !preen && reply("UPDATE STANDARD SUPERBLOCK")) { sblk.b_bno = SBOFF / dev_bsize; sbdirty(); @@ -299,7 +320,7 @@ ckfini(markclean) if (bufhead.b_size != cnt) errx(EEXIT, "panic: lost %d buffers", bufhead.b_size - cnt); pbp = pdirbp = (struct bufarea *)0; - if (sblock.fs_clean != markclean) { + if (cursnapshot == 0 && sblock.fs_clean != markclean) { sblock.fs_clean = markclean; sbdirty(); ofsmodified = fsmodified; @@ -336,12 +357,12 @@ bread(fd, buf, blk, size) offset = blk; offset *= dev_bsize; if (lseek(fd, offset, 0) < 0) - rwerror("SEEK", blk); + rwerror("SEEK BLK", blk); else if (read(fd, buf, (int)size) == size) return (0); - rwerror("READ", blk); + rwerror("READ BLK", blk); if (lseek(fd, offset, 0) < 0) - rwerror("SEEK", blk); + rwerror("SEEK BLK", blk); errs = 0; memset(buf, 0, (size_t)size); printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:"); @@ -379,15 +400,15 @@ bwrite(fd, buf, blk, size) offset = blk; offset *= dev_bsize; if (lseek(fd, offset, 0) < 0) - rwerror("SEEK", blk); + rwerror("SEEK BLK", blk); else if (write(fd, buf, (int)size) == size) { fsmodified = 1; return; } resolved = 0; - rwerror("WRITE", blk); + rwerror("WRITE BLK", blk); if (lseek(fd, offset, 0) < 0) - rwerror("SEEK", blk); + rwerror("SEEK BLK", blk); printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize) if (write(fd, cp, (int)dev_bsize) != dev_bsize) { diff --git a/sbin/fsck_ffs/inode.c b/sbin/fsck_ffs/inode.c index 8b2f14b..51df724 100644 --- a/sbin/fsck_ffs/inode.c +++ b/sbin/fsck_ffs/inode.c @@ -41,6 +41,7 @@ static const char rcsid[] = #include <sys/param.h> #include <sys/time.h> +#include <sys/sysctl.h> #include <ufs/ufs/dinode.h> #include <ufs/ufs/dir.h> @@ -187,7 +188,9 @@ iblock(idesc, ilevel, isize) continue; (void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu", (u_long)idesc->id_number); - if (dofix(idesc, buf)) { + if (usedsoftdep) { + pfatal(buf); + } else if (dofix(idesc, buf)) { *ap = 0; dirty(bp); } @@ -481,10 +484,21 @@ clri(idesc, type, flag) if (preen) printf(" (CLEARED)\n"); n_files--; - (void)ckinode(dp, idesc); - clearinode(dp); - inoinfo(idesc->id_number)->ino_state = USTATE; - inodirty(); + if (bkgrdflag == 0) { + (void)ckinode(dp, idesc); + inoinfo(idesc->id_number)->ino_state = USTATE; + clearinode(dp); + inodirty(); + } else { + cmd.value = idesc->id_number; + cmd.size = -dp->di_nlink; + if (debug) + printf("adjrefcnt ino %d amt %d\n", + (long)cmd.value, cmd.size); + if (sysctl(adjrefcnt, MIBSIZE, 0, 0, + &cmd, sizeof cmd) == -1) + rwerror("ADJUST INODE", cmd.value); + } } } diff --git a/sbin/fsck_ffs/main.c b/sbin/fsck_ffs/main.c index 7ee4ef0b..a9e7e90 100644 --- a/sbin/fsck_ffs/main.c +++ b/sbin/fsck_ffs/main.c @@ -83,8 +83,7 @@ main(argc, argv) sync(); skipclean = 1; - markclean = 1; - while ((ch = getopt(argc, argv, "b:c:dfm:npy")) != -1) { + while ((ch = getopt(argc, argv, "b:Bc:dfm:npy")) != -1) { switch (ch) { case 'b': skipclean = 0; @@ -92,6 +91,10 @@ main(argc, argv) printf("Alternate super block location: %d\n", bflag); break; + case 'B': + bkgrdflag = 1; + break; + case 'c': skipclean = 0; cvtlevel = argtoi('c', "conversion level", optarg, 10); @@ -183,9 +186,12 @@ checkfilesys(filesys, mntpt, auxdata, child) int child; { ufs_daddr_t n_ffree, n_bfree; + struct ufs_args args; struct dups *dp; - struct statfs *mntbuf; + struct statfs *mntp; struct zlncnt *zlnp; + ufs_daddr_t blks; + ufs_daddr_t files; int cylno; if (preen && child) @@ -193,6 +199,44 @@ checkfilesys(filesys, mntpt, auxdata, child) cdevname = filesys; if (debug && preen) pwarn("starting\n"); + + /* + * If we are to do a background check: + * Get the mount point information of the filesystem + * create snapshot file + * return created snapshot file + * if not found, clear bkgrdflag and proceed with normal fsck + */ + mntp = getmntpt(filesys); + if (bkgrdflag) { + if (mntp == NULL) { + bkgrdflag = 0; + pwarn("NOT MOUNTED, CANNOT RUN IN BACKGROUND\n"); + } else if ((mntp->f_flags & MNT_SOFTDEP) == 0) { + bkgrdflag = 0; + pwarn("NOT USING SOFT UPDATES, CANNOT RUN IN BACKGROUND\n"); + } else if ((mntp->f_flags & MNT_RDONLY) != 0) { + bkgrdflag = 0; + pwarn("MOUNTED READ-ONLY, CANNOT RUN IN BACKGROUND\n"); + } else { + snprintf(snapname, sizeof snapname, "%s/.fsck_snapshot", + mntp->f_mntonname); + args.fspec = snapname; + while (mount("ffs", mntp->f_mntonname, + mntp->f_flags | MNT_UPDATE | MNT_SNAPSHOT, + &args) < 0) { + if (errno == EEXIST && unlink(snapname) == 0) + continue; + bkgrdflag = 0; + pwarn("CANNOT CREATE SNAPSHOT %s: %s\n", + snapname, strerror(errno)); + break; + } + if (bkgrdflag != 0) + filesys = snapname; + } + } + switch (setup(filesys)) { case 0: if (preen) @@ -206,12 +250,6 @@ checkfilesys(filesys, mntpt, auxdata, child) sblock.fs_cstotal.cs_nffree * 100.0 / sblock.fs_dsize); return (0); } - - /* - * Get the mount point information of the filesystem, if - * it is available. - */ - mntbuf = getmntpt(filesys); /* * Cleared if any questions answered no. Used to decide if @@ -223,7 +261,7 @@ checkfilesys(filesys, mntpt, auxdata, child) */ if (preen == 0) { printf("** Last Mounted on %s\n", sblock.fs_fsmnt); - if (mntbuf != NULL && mntbuf->f_flags & MNT_ROOTFS) + if (mntp != NULL && mntp->f_flags & MNT_ROOTFS) printf("** Root file system\n"); printf("** Phase 1 - Check Blocks and Sizes\n"); } @@ -272,20 +310,26 @@ checkfilesys(filesys, mntpt, auxdata, child) */ n_ffree = sblock.fs_cstotal.cs_nffree; n_bfree = sblock.fs_cstotal.cs_nbfree; + files = maxino - ROOTINO - sblock.fs_cstotal.cs_nifree - n_files; + blks = n_blks + + sblock.fs_ncg * (cgdmin(&sblock, 0) - cgsblock(&sblock, 0)); + blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0); + blks += howmany(sblock.fs_cssize, sblock.fs_fsize); + blks = maxfsblock - (n_ffree + sblock.fs_frag * n_bfree) - blks; + if (bkgrdflag && (files > 0 || blks > 0)) { + countdirs = sblock.fs_cstotal.cs_ndir - countdirs; + pwarn("Reclaimed: %d directories, %d files, %d fragments\n", + countdirs, files - countdirs, blks); + } pwarn("%ld files, %ld used, %ld free ", n_files, n_blks, n_ffree + sblock.fs_frag * n_bfree); printf("(%d frags, %d blocks, %.1f%% fragmentation)\n", n_ffree, n_bfree, n_ffree * 100.0 / sblock.fs_dsize); - if (debug && - (n_files -= maxino - ROOTINO - sblock.fs_cstotal.cs_nifree)) - printf("%d files missing\n", n_files); if (debug) { - n_blks += sblock.fs_ncg * - (cgdmin(&sblock, 0) - cgsblock(&sblock, 0)); - n_blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0); - n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize); - if (n_blks -= maxfsblock - (n_ffree + sblock.fs_frag * n_bfree)) - printf("%d blocks missing\n", n_blks); + if (files < 0) + printf("%d inodes missing\n", -files); + if (blks < 0) + printf("%d blocks missing\n", -blks); if (duplist != NULL) { printf("The following duplicate blocks remain:"); for (dp = duplist; dp; dp = dp->next) @@ -321,7 +365,7 @@ checkfilesys(filesys, mntpt, auxdata, child) /* * Check to see if the filesystem is mounted read-write. */ - if (mntbuf != NULL && (mntbuf->f_flags & MNT_RDONLY) == 0) + if (bkgrdflag == 0 && mntp != NULL && (mntp->f_flags & MNT_RDONLY) == 0) resolved = 0; ckfini(resolved); @@ -334,7 +378,7 @@ checkfilesys(filesys, mntpt, auxdata, child) printf("\n***** FILE SYSTEM WAS MODIFIED *****\n"); if (rerun) printf("\n***** PLEASE RERUN FSCK *****\n"); - if (mntbuf != NULL) { + if (mntp != NULL) { struct ufs_args args; int ret; /* @@ -342,16 +386,16 @@ checkfilesys(filesys, mntpt, auxdata, child) * it unless it is read-write, so we can continue using it * as safely as possible. */ - if (mntbuf->f_flags & MNT_RDONLY) { + if (mntp->f_flags & MNT_RDONLY) { args.fspec = 0; args.export.ex_flags = 0; args.export.ex_root = 0; - ret = mount("ufs", mntbuf->f_mntonname, - mntbuf->f_flags | MNT_UPDATE | MNT_RELOAD, &args); + ret = mount("ufs", mntp->f_mntonname, + mntp->f_flags | MNT_UPDATE | MNT_RELOAD, &args); if (ret == 0) return (0); pwarn("mount reload of '%s' failed: %s\n\n", - mntbuf->f_mntonname, strerror(errno)); + mntp->f_mntonname, strerror(errno)); } if (!fsmodified) return (0); diff --git a/sbin/fsck_ffs/pass1.c b/sbin/fsck_ffs/pass1.c index 3d09bd0..3a5e408 100644 --- a/sbin/fsck_ffs/pass1.c +++ b/sbin/fsck_ffs/pass1.c @@ -41,6 +41,7 @@ static const char rcsid[] = #include <sys/param.h> #include <sys/stat.h> +#include <sys/sysctl.h> #include <ufs/ufs/dinode.h> #include <ufs/ufs/dir.h> @@ -265,7 +266,7 @@ checkinode(inumber, idesc) * Fake ndb value so direct/indirect block checks below * will detect any garbage after symlink string. */ - if (dp->di_size < sblock.fs_maxsymlinklen) { + if (dp->di_size < (u_int64_t)sblock.fs_maxsymlinklen) { ndb = howmany(dp->di_size, sizeof(ufs_daddr_t)); if (ndb > NDADDR) { j = ndb - NDADDR; @@ -343,9 +344,20 @@ checkinode(inumber, idesc) printf(" (CORRECTED)\n"); else if (reply("CORRECT") == 0) return; - dp = ginode(inumber); - dp->di_blocks = idesc->id_entryno; - inodirty(); + if (bkgrdflag == 0) { + dp = ginode(inumber); + dp->di_blocks = idesc->id_entryno; + inodirty(); + } else { + cmd.value = idesc->id_number; + cmd.size = idesc->id_entryno - dp->di_blocks; + if (debug) + printf("adjblkcnt ino %d amount %d\n", + (long)cmd.value, cmd.size); + if (sysctl(adjblkcnt, MIBSIZE, 0, 0, + &cmd, sizeof cmd) == -1) + rwerror("ADJUST INODE BLOCK COUNT", cmd.value); + } } return; unknown: diff --git a/sbin/fsck_ffs/pass2.c b/sbin/fsck_ffs/pass2.c index cbd5d9f..f7f7bcd 100644 --- a/sbin/fsck_ffs/pass2.c +++ b/sbin/fsck_ffs/pass2.c @@ -43,6 +43,7 @@ static const char rcsid[] = #include <ufs/ufs/dinode.h> #include <ufs/ufs/dir.h> +#include <ufs/ffs/fs.h> #include <err.h> #include <string.h> @@ -444,6 +445,8 @@ again: pwarn("%s %s %s\n", pathbuf, "IS AN EXTRANEOUS HARD LINK TO DIRECTORY", namebuf); + if (cursnapshot != 0) + break; if (preen) { printf(" (REMOVED)\n"); n = 1; diff --git a/sbin/fsck_ffs/pass3.c b/sbin/fsck_ffs/pass3.c index 730af5f..8e43636 100644 --- a/sbin/fsck_ffs/pass3.c +++ b/sbin/fsck_ffs/pass3.c @@ -78,7 +78,8 @@ pass3() * them in DSTATE which will cause them to be pitched * in pass 4. */ - if (preen && resolved && usedsoftdep && state == DSTATE) { + if ((preen || bkgrdflag) && + resolved && usedsoftdep && state == DSTATE) { if (inp->i_dotdot >= ROOTINO) inoinfo(inp->i_dotdot)->ino_linkcnt++; continue; diff --git a/sbin/fsck_ffs/pass5.c b/sbin/fsck_ffs/pass5.c index 5da84b8..45ca865 100644 --- a/sbin/fsck_ffs/pass5.c +++ b/sbin/fsck_ffs/pass5.c @@ -40,6 +40,7 @@ static const char rcsid[] = #endif /* not lint */ #include <sys/param.h> +#include <sys/sysctl.h> #include <ufs/ufs/dinode.h> #include <ufs/ffs/fs.h> @@ -49,16 +50,18 @@ static const char rcsid[] = #include "fsck.h" +static void check_maps __P((u_char *, u_char *, int, int, char *, int *, + int, int)); + void pass5() { int c, blk, frags, basesize, sumsize, mapsize, savednrpos = 0; - int inomapsize, blkmapsize, astart, aend, ustart, uend; + int inomapsize, blkmapsize; struct fs *fs = &sblock; struct cg *cg = &cgrp; - ufs_daddr_t dbase, dmax; - ufs_daddr_t d; - long i, j, k, l, m, n; + ufs_daddr_t dbase, dmax, d; + int i, j, excessdirs; struct csum *cs; struct csum cstotal; struct inodesc idesc[3]; @@ -92,7 +95,7 @@ pass5() i = fs->fs_contigsumsize; fs->fs_contigsumsize = MIN(fs->fs_maxcontig, FS_MAXCONTIG); - if (CGSIZE(fs) > fs->fs_bsize) { + if (CGSIZE(fs) > (u_int)fs->fs_bsize) { pwarn("CANNOT %s CLUSTER MAPS\n", doit); fs->fs_contigsumsize = i; } else if (preen || @@ -232,14 +235,14 @@ pass5() break; default: - if (j < ROOTINO) + if (j < (int)ROOTINO) break; errx(EEXIT, "BAD STATE %d FOR INODE I=%ld", inoinfo(j)->ino_state, j); } } if (c == 0) - for (i = 0; i < ROOTINO; i++) { + for (i = 0; i < (int)ROOTINO; i++) { setbit(cg_inosused(newcg), i); newcg->cg_cs.cs_nifree--; } @@ -301,7 +304,8 @@ pass5() cstotal.cs_nifree += newcg->cg_cs.cs_nifree; cstotal.cs_ndir += newcg->cg_cs.cs_ndir; cs = &fs->fs_cs(fs, c); - if (memcmp(&newcg->cg_cs, cs, sizeof *cs) != 0 && + if (cursnapshot == 0 && + memcmp(&newcg->cg_cs, cs, sizeof *cs) != 0 && dofix(&idesc[0], "FREE BLK COUNT(S) WRONG IN SUPERBLK")) { memmove(cs, &newcg->cg_cs, sizeof *cs); sbdirty(); @@ -311,7 +315,8 @@ pass5() cgdirty(); continue; } - if ((memcmp(newcg, cg, basesize) != 0 || + if (cursnapshot == 0 && + (memcmp(newcg, cg, basesize) != 0 || memcmp(&cg_blktot(newcg)[0], &cg_blktot(cg)[0], sumsize) != 0) && dofix(&idesc[2], "SUMMARY INFORMATION BAD")) { @@ -320,101 +325,25 @@ pass5() &cg_blktot(newcg)[0], (size_t)sumsize); cgdirty(); } - if (debug) { - for (i = 0; i < inomapsize; i++) { - j = cg_inosused(newcg)[i]; - k = cg_inosused(cg)[i]; - if (j == k) - continue; - for (m = 0, l = 1; m < NBBY; m++, l <<= 1) { - if ((j & l) == (k & l)) - continue; - n = c * fs->fs_ipg + i * NBBY + m; - if ((j & l) != 0) - pwarn("%s INODE %d MARKED %s\n", - "ALLOCATED", n, "FREE"); - else - pwarn("%s INODE %d MARKED %s\n", - "UNALLOCATED", n, "USED"); - } - } - astart = ustart = -1; - for (i = 0; i < blkmapsize; i++) { - j = cg_blksfree(cg)[i]; - k = cg_blksfree(newcg)[i]; - if (j == k) - continue; - for (m = 0, l = 1; m < NBBY; m++, l <<= 1) { - if ((j & l) == (k & l)) - continue; - n = c * fs->fs_fpg + i * NBBY + m; - if ((j & l) != 0) { - if (astart == -1) { - astart = aend = n; - continue; - } - if (aend + 1 == n) { - aend = n; - continue; - } - pwarn("%s FRAGS %d-%d %s\n", - "ALLOCATED", astart, aend, - "MARKED FREE"); - astart = aend = n; - } else { - if (ustart == -1) { - ustart = uend = n; - continue; - } - if (uend + 1 == n) { - uend = n; - continue; - } - pwarn("%s FRAGS %d-%d %s\n", - "UNALLOCATED", ustart, uend, - "MARKED USED"); - ustart = uend = n; - } - } - } - if (astart != -1) - pwarn("%s FRAGS %d-%d %s\n", - "ALLOCATED", astart, aend, - "MARKED FREE"); - if (ustart != -1) - pwarn("%s FRAGS %d-%d %s\n", - "UNALLOCATED", ustart, uend, - "MARKED USED"); - } - if (usedsoftdep) { - for (i = 0; i < inomapsize; i++) { - j = cg_inosused(newcg)[i]; - if ((cg_inosused(cg)[i] & j) == j) - continue; - for (k = 0; k < NBBY; k++) { - if ((j & (1 << k)) == 0) - continue; - if (cg_inosused(cg)[i] & (1 << k)) - continue; - pwarn("ALLOCATED INODE %d MARKED FREE\n", - c * fs->fs_ipg + i * NBBY + k); - } - } - for (i = 0; i < blkmapsize; i++) { - j = cg_blksfree(cg)[i]; - if ((cg_blksfree(newcg)[i] & j) == j) - continue; - for (k = 0; k < NBBY; k++) { - if ((j & (1 << k)) == 0) - continue; - if (cg_blksfree(newcg)[i] & (1 << k)) - continue; - pwarn("ALLOCATED FRAG %d MARKED FREE\n", - c * fs->fs_fpg + i * NBBY + k); - } + if (bkgrdflag != 0 || usedsoftdep || debug) { + excessdirs = cg->cg_cs.cs_ndir - newcg->cg_cs.cs_ndir; + if (excessdirs < 0) { + pfatal("LOST %d DIRECTORIES\n", -excessdirs); + excessdirs = 0; } + if (excessdirs > 0) + check_maps(cg_inosused(newcg), cg_inosused(cg), + inomapsize, cg->cg_cgx * fs->fs_ipg, "DIR", + freedirs, 0, excessdirs); + check_maps(cg_inosused(newcg), cg_inosused(cg), + inomapsize, cg->cg_cgx * fs->fs_ipg, "FILE", + freefiles, excessdirs, fs->fs_ipg); + check_maps(cg_blksfree(cg), cg_blksfree(newcg), + blkmapsize, cg->cg_cgx * fs->fs_fpg, "FRAG", + freeblks, 0, fs->fs_fpg); } - if (memcmp(cg_inosused(newcg), cg_inosused(cg), mapsize) != 0 && + if (cursnapshot == 0 && + memcmp(cg_inosused(newcg), cg_inosused(cg), mapsize) != 0 && dofix(&idesc[1], "BLK(S) MISSING IN BIT MAPS")) { memmove(cg_inosused(cg), cg_inosused(newcg), (size_t)mapsize); @@ -423,7 +352,8 @@ pass5() } if (fs->fs_postblformat == FS_42POSTBLFMT) fs->fs_nrpos = savednrpos; - if (memcmp(&cstotal, &fs->fs_cstotal, sizeof *cs) != 0 + if (cursnapshot == 0 && + memcmp(&cstotal, &fs->fs_cstotal, sizeof *cs) != 0 && dofix(&idesc[0], "FREE BLK COUNT(S) WRONG IN SUPERBLK")) { memmove(&fs->fs_cstotal, &cstotal, sizeof *cs); fs->fs_ronly = 0; @@ -431,3 +361,127 @@ pass5() sbdirty(); } } + +static void +check_maps(map1, map2, mapsize, startvalue, name, opcode, skip, limit) + u_char *map1; /* map of claimed allocations */ + u_char *map2; /* map of determined allocations */ + int mapsize; /* size of above two maps */ + int startvalue; /* resource value for first element in map */ + char *name; /* name of resource found in maps */ + int *opcode; /* sysctl opcode to free resource */ + int skip; /* number of entries to skip before starting to free */ + int limit; /* limit on number of entries to free */ +{ +# define BUFSIZE 16 + char buf[BUFSIZE]; + long i, j, k, l, m, n, size; + int astart, aend, ustart, uend; + + astart = ustart = aend = uend = -1; + for (i = 0; i < mapsize; i++) { + j = *map1++; + k = *map2++; + if (j == k) + continue; + for (m = 0, l = 1; m < NBBY; m++, l <<= 1) { + if ((j & l) == (k & l)) + continue; + n = startvalue + i * NBBY + m; + if ((j & l) != 0) { + if (astart == -1) { + astart = aend = n; + continue; + } + if (aend + 1 == n) { + aend = n; + continue; + } + if (astart == aend) + pfatal("ALLOCATED %s %d MARKED FREE\n", + name, astart); + else + pfatal("%s %sS %d-%d MARKED FREE\n", + "ALLOCATED", name, astart, aend); + astart = aend = n; + } else { + if (ustart == -1) { + ustart = uend = n; + continue; + } + if (uend + 1 == n) { + uend = n; + continue; + } + size = uend - ustart + 1; + if (size <= skip) { + skip -= size; + ustart = uend = n; + continue; + } + if (skip > 0) { + ustart += skip; + size -= skip; + skip = 0; + } + if (size > limit) + size = limit; + if (debug && size == 1) + pwarn("%s %s %d MARKED USED\n", + "UNALLOCATED", name, ustart); + else if (debug) + pwarn("%s %sS %d-%d MARKED USED\n", + "UNALLOCATED", name, ustart, + ustart + size - 1); + if (bkgrdflag != 0) { + cmd.value = ustart; + cmd.size = size; + if (sysctl(opcode, MIBSIZE, 0, 0, + &cmd, sizeof cmd) == -1) { + snprintf(buf, BUFSIZE, + "FREE %s", name); + rwerror(buf, cmd.value); + } + } + limit -= size; + if (limit <= 0) + return; + ustart = uend = n; + } + } + } + if (astart != -1) + if (astart == aend) + pfatal("ALLOCATED %s %d MARKED FREE\n", name, astart); + else + pfatal("ALLOCATED %sS %d-%d MARKED FREE\n", + name, astart, aend); + if (ustart != -1) { + size = uend - ustart + 1; + if (size <= skip) + return; + if (skip > 0) { + ustart += skip; + size -= skip; + } + if (size > limit) + size = limit; + if (debug) { + if (size == 1) + pwarn("UNALLOCATED %s %d MARKED USED\n", + name, ustart); + else + pwarn("UNALLOCATED %sS %d-%d MARKED USED\n", + name, ustart, ustart + size - 1); + } + if (bkgrdflag != 0) { + cmd.value = ustart; + cmd.size = size; + if (sysctl(opcode, MIBSIZE, 0, 0, &cmd, + sizeof cmd) == -1) { + snprintf(buf, BUFSIZE, "FREE %s", name); + rwerror(buf, cmd.value); + } + } + } +} diff --git a/sbin/fsck_ffs/preen.c b/sbin/fsck_ffs/preen.c index 4ad426f..aee801e 100644 --- a/sbin/fsck_ffs/preen.c +++ b/sbin/fsck_ffs/preen.c @@ -44,6 +44,7 @@ static const char rcsid[] = #include <sys/wait.h> #include <ufs/ufs/dinode.h> +#include <ufs/ffs/fs.h> #include <ctype.h> #include <errno.h> diff --git a/sbin/fsck_ffs/setup.c b/sbin/fsck_ffs/setup.c index 24000be..bd928fb 100644 --- a/sbin/fsck_ffs/setup.c +++ b/sbin/fsck_ffs/setup.c @@ -86,25 +86,73 @@ setup(dev) skipclean = fflag ? 0 : preen; if (stat(dev, &statb) < 0) { printf("Can't stat %s: %s\n", dev, strerror(errno)); + if (bkgrdflag) { + unlink(snapname); + bkgrdflag = 0; + } return (0); } if ((statb.st_mode & S_IFMT) != S_IFCHR && (statb.st_mode & S_IFMT) != S_IFBLK) { - if ((statb.st_flags & SF_SNAPSHOT) != 0) { + if (bkgrdflag != 0 && (statb.st_flags & SF_SNAPSHOT) == 0) { + unlink(snapname); + printf("background fsck lacks a snapshot\n"); + exit(EEXIT); + } + if ((statb.st_flags & SF_SNAPSHOT) != 0 && cvtlevel == 0) { cursnapshot = statb.st_ino; } else { - pfatal("%s is not a disk device", dev); - if (reply("CONTINUE") == 0) - return (0); + if (cvtlevel == 0 || + (statb.st_flags & SF_SNAPSHOT) == 0) { + if (preen && bkgrdflag) { + unlink(snapname); + bkgrdflag = 0; + } + pfatal("%s is not a disk device", dev); + if (reply("CONTINUE") == 0) { + if (bkgrdflag) { + unlink(snapname); + bkgrdflag = 0; + } + return (0); + } + } else { + if (bkgrdflag) { + unlink(snapname); + bkgrdflag = 0; + } + pfatal("cannot convert a snapshot"); + exit(EEXIT); + } } } if ((fsreadfd = open(dev, O_RDONLY)) < 0) { + if (bkgrdflag) { + unlink(snapname); + bkgrdflag = 0; + } printf("Can't open %s: %s\n", dev, strerror(errno)); return (0); } + if (bkgrdflag) { + unlink(snapname); + size = MIBSIZE; + if (sysctlnametomib("vfs.ffs.adjrefcnt", adjrefcnt, &size) < 0|| + sysctlnametomib("vfs.ffs.adjblkcnt", adjblkcnt, &size) < 0|| + sysctlnametomib("vfs.ffs.freefiles", freefiles, &size) < 0|| + sysctlnametomib("vfs.ffs.freedirs", freedirs, &size) < 0 || + sysctlnametomib("vfs.ffs.freeblks", freeblks, &size) < 0) { + pfatal("kernel lacks background fsck support\n"); + exit(EEXIT); + } + cmd.version = FFS_CMD_VERSION; + cmd.handle = fsreadfd; + fswritefd = -1; + } if (preen == 0) printf("** %s", dev); - if (nflag || (fswritefd = open(dev, O_WRONLY)) < 0) { + if (bkgrdflag == 0 && + (nflag || (fswritefd = open(dev, O_WRONLY)) < 0)) { fswritefd = -1; if (preen) pfatal("NO WRITE ACCESS"); @@ -178,7 +226,7 @@ setup(dev) } if (sblock.fs_interleave < 1 || sblock.fs_interleave > sblock.fs_nsect) { - pwarn("IMPOSSIBLE INTERLEAVE=%d IN SUPERBLOCK", + pfatal("IMPOSSIBLE INTERLEAVE=%d IN SUPERBLOCK", sblock.fs_interleave); sblock.fs_interleave = 1; if (preen) @@ -190,7 +238,7 @@ setup(dev) } if (sblock.fs_npsect < sblock.fs_nsect || sblock.fs_npsect > sblock.fs_nsect*2) { - pwarn("IMPOSSIBLE NPSECT=%d IN SUPERBLOCK", + pfatal("IMPOSSIBLE NPSECT=%d IN SUPERBLOCK", sblock.fs_npsect); sblock.fs_npsect = sblock.fs_nsect; if (preen) diff --git a/sbin/quotacheck/preen.c b/sbin/quotacheck/preen.c index 4ad426f..aee801e 100644 --- a/sbin/quotacheck/preen.c +++ b/sbin/quotacheck/preen.c @@ -44,6 +44,7 @@ static const char rcsid[] = #include <sys/wait.h> #include <ufs/ufs/dinode.h> +#include <ufs/ffs/fs.h> #include <ctype.h> #include <errno.h> |