summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormckusick <mckusick@FreeBSD.org>2001-03-21 09:48:03 +0000
committermckusick <mckusick@FreeBSD.org>2001-03-21 09:48:03 +0000
commitdc0e22cfaf1b407ad08776ab7386543ad024a76c (patch)
treec406042339ede0ab9e543e4797322cadaef35d82
parent37fbaa04c47b8d96f06c60428b244c77e3597218 (diff)
downloadFreeBSD-src-dc0e22cfaf1b407ad08776ab7386543ad024a76c.zip
FreeBSD-src-dc0e22cfaf1b407ad08776ab7386543ad024a76c.tar.gz
Additions to run checks on live filesystems. This change will not
affect current systems until fsck is modified to use these new facilities. To try out this change, set the fsck passno to zero in /etc/fstab to cause the filesystem to be mounted without running fsck, then run `fsck_ffs -p -B <filesystem>' after the system has been brought up multiuser to run a background cleanup on <filesystem>. Note that the <filesystem> in question must have soft updates enabled.
-rw-r--r--sbin/fsck_ffs/dir.c29
-rw-r--r--sbin/fsck_ffs/fsck.h21
-rw-r--r--sbin/fsck_ffs/fsutil.c49
-rw-r--r--sbin/fsck_ffs/inode.c24
-rw-r--r--sbin/fsck_ffs/main.c94
-rw-r--r--sbin/fsck_ffs/pass1.c20
-rw-r--r--sbin/fsck_ffs/pass2.c3
-rw-r--r--sbin/fsck_ffs/pass3.c3
-rw-r--r--sbin/fsck_ffs/pass5.c260
-rw-r--r--sbin/fsck_ffs/preen.c1
-rw-r--r--sbin/fsck_ffs/setup.c62
-rw-r--r--sbin/quotacheck/preen.c1
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>
OpenPOWER on IntegriCloud