summaryrefslogtreecommitdiffstats
path: root/sbin
diff options
context:
space:
mode:
Diffstat (limited to 'sbin')
-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