From 15fca934f63619777be51e7b38a7f55dc69294d1 Mon Sep 17 00:00:00 2001 From: Kirk McKusick Date: Tue, 24 Apr 2001 22:38:08 +0000 Subject: [PATCH] Add support for the -F flag which determines whether a specified filesystem needs foreground checking (usually at boot time) or can defer to background checking (after the system is up and running). See the manual page, fsck_ffs(8), for details on the -F and -B options. These options are primarily intended for use by the fsck front end. All output is directed to stdout so that the output is coherent when redirected to a file or a pipe. Unify the code with the fsck front end that allows either a device or a mount point to be specified as the argument to be checked. --- sbin/fsck_ffs/fsck.h | 1 + sbin/fsck_ffs/fsck_ffs.8 | 89 +++++++++++++++------------------------ sbin/fsck_ffs/fsutil.c | 20 +++++---- sbin/fsck_ffs/main.c | 76 +++++++++++++++++++++++++-------- sbin/fsck_ffs/utilities.c | 14 +++++- 5 files changed, 117 insertions(+), 83 deletions(-) diff --git a/sbin/fsck_ffs/fsck.h b/sbin/fsck_ffs/fsck.h index 813202becd79..9321560cdae7 100644 --- a/sbin/fsck_ffs/fsck.h +++ b/sbin/fsck_ffs/fsck.h @@ -212,6 +212,7 @@ int cvtlevel; /* convert to newer file system format */ int doinglevel1; /* converting to new cylinder group format */ int doinglevel2; /* converting to new inode format */ int newinofmt; /* filesystem has new inode format */ +int bkgrdcheck; /* determine if background check is possible */ char usedsoftdep; /* just fix soft dependency inconsistencies */ char preen; /* just fix normal inconsistencies */ char rerun; /* rerun fsck. Only used in non-preen mode */ diff --git a/sbin/fsck_ffs/fsck_ffs.8 b/sbin/fsck_ffs/fsck_ffs.8 index a666fdad8ee8..1422d90bb012 100644 --- a/sbin/fsck_ffs/fsck_ffs.8 +++ b/sbin/fsck_ffs/fsck_ffs.8 @@ -42,41 +42,14 @@ .Nd filesystem consistency check and interactive repair .Sh SYNOPSIS .Nm -.Fl p -.Op Fl f -.Op Fl m Ar mode -.Op Ar filesystem -.Ar ... -.Nm -.Op Fl ny +.Op Fl BFpfny .Op Fl b Ar block# .Op Fl c Ar level -.Op Fl l Ar maxparallel .Op Fl m Ar mode -.Op Ar filesystem +.Ar filesystem .Ar ... .Sh DESCRIPTION -The first form of -.Nm -preens a standard set of filesystems or the specified filesystems. -It is normally used in the script -.Pa /etc/rc -during automatic reboot. -Here -.Nm -reads the table -.Pa /etc/fstab -to determine which filesystems to check. -Only partitions in fstab that are mounted ``rw,'' ``rq'' or ``ro'' -and that have non-zero pass number are checked. -Filesystems with pass number 1 (normally just the root filesystem) -are checked one at a time. -When pass 1 completes, all remaining filesystems are checked, -running one process per disk drive. -The disk drive containing each filesystem is inferred from the longest prefix -of the device name that ends in a digit; the remaining characters are assumed -to be the partition designator. -.Pp +The specified disk partitions and/or filesystems are checked. In "preen" mode the clean flag of each filesystem's superblock is examined and only those filesystems that are not marked clean are checked. @@ -166,17 +139,40 @@ will default to a .Fl n action. .Pp -.Nm Fsck -has more consistency checks than -its predecessors -.Em check , dcheck , fcheck , -and -.Em icheck -combined. -.Pp The following flags are interpreted by -.Nm . +.Nm .Bl -tag -width indent +.It Fl F +Determine whether the filesystem needs to be cleaned immediately +in foreground, or if its cleaning can be deferred to background. +To be eligible for background cleaning it must have been running +with soft updates, not have been marked as needing a foreground check, +and be mounted and writable when the background check is to be done. +If these conditions are met, then +.Nm +exits with a zero exit status. +Otherwise it exits with a non-zero exit status. +If the filesystem is clean, +it will exit with a non-zero exit status so that the clean status +of the filesystem can be verified and reported during the foreground +checks. +Note that when invoked with the +.Fl F +flag, no cleanups are done. +The only thing that +.Nm +does is to determine whether a foreground or background +check is needed and exit with an appropriate status code. +.It Fl B +A check is done on the specified and possibly active filesystem. +The set of corrections that can be done is limited to those done +when running in preen mode (see the +.Fl p +flag). +If unexpected errors are found, +the filesystem is marked as needing a foreground check and +.Nm +exits without attempting any further cleaning. .It Fl b Use the block specified immediately after the flag as the super block for the filesystem. Block 32 is usually @@ -220,12 +216,6 @@ Force to check .Sq clean filesystems when preening. -.It Fl l -Limit the number of parallel checks to the number specified in the following -argument. -By default, the limit is the number of disks, running one process per disk. -If a smaller limit is given, the disks are checked round-robin, one filesystem -at a time. .It Fl m Use the mode specified in octal immediately after the flag as the permission bits to use when creating the @@ -250,12 +240,6 @@ this should be used with great caution as this is a free license to continue after essentially unlimited trouble has been encountered. .El .Pp -If no filesystems are given to -.Nm -then a default list of filesystems is read from -the file -.Pa /etc/fstab . -.Pp Inconsistencies checked are as follows: .Pp .Bl -enum -compact @@ -312,9 +296,6 @@ If the .Pa lost+found directory does not exist, it is created. If there is insufficient space its size is increased. -.Pp -Because of inconsistencies between the block device and the buffer cache, -the raw device should always be used. .Sh FILES .Bl -tag -width /etc/fstab -compact .It Pa /etc/fstab diff --git a/sbin/fsck_ffs/fsutil.c b/sbin/fsck_ffs/fsutil.c index c743acab83aa..325fe5cd53cb 100644 --- a/sbin/fsck_ffs/fsutil.c +++ b/sbin/fsck_ffs/fsutil.c @@ -264,6 +264,8 @@ rwerror(mesg, blk) ufs_daddr_t blk; { + if (bkgrdcheck) + exit(EEXIT); if (preen == 0) printf("\n"); pfatal("CANNOT %s: %ld", mesg, blk); @@ -645,10 +647,10 @@ pfatal(fmt, va_alist) va_start(ap); #endif if (!preen) { - (void)vfprintf(stderr, fmt, ap); + (void)vfprintf(stdout, fmt, ap); va_end(ap); if (usedsoftdep) - (void)fprintf(stderr, + (void)fprintf(stdout, "\nUNEXPECTED SOFT UPDATE INCONSISTENCY\n"); /* * Force foreground fsck to clean up inconsistency. @@ -659,7 +661,7 @@ pfatal(fmt, va_alist) if (sysctlbyname("vfs.ffs.setflags", 0, 0, &cmd, sizeof cmd) == -1) pwarn("CANNOT SET FS_NEEDSFSCK FLAG\n"); - fprintf(stderr, "CANNOT RUN IN BACKGROUND\n"); + fprintf(stdout, "CANNOT RUN IN BACKGROUND\n"); ckfini(0); exit(EEXIT); } @@ -667,9 +669,9 @@ pfatal(fmt, va_alist) } if (cdevname == NULL) cdevname = "fsck"; - (void)fprintf(stderr, "%s: ", cdevname); - (void)vfprintf(stderr, fmt, ap); - (void)fprintf(stderr, + (void)fprintf(stdout, "%s: ", cdevname); + (void)vfprintf(stdout, fmt, ap); + (void)fprintf(stdout, "\n%s: UNEXPECTED%sINCONSISTENCY; RUN fsck MANUALLY.\n", cdevname, usedsoftdep ? " SOFT UPDATE " : " "); /* @@ -706,8 +708,8 @@ pwarn(fmt, va_alist) va_start(ap); #endif if (preen) - (void)fprintf(stderr, "%s: ", cdevname); - (void)vfprintf(stderr, fmt, ap); + (void)fprintf(stdout, "%s: ", cdevname); + (void)vfprintf(stdout, fmt, ap); va_end(ap); } @@ -730,7 +732,7 @@ panic(fmt, va_alist) va_start(ap); #endif pfatal("INTERNAL INCONSISTENCY:"); - (void)vfprintf(stderr, fmt, ap); + (void)vfprintf(stdout, fmt, ap); va_end(ap); exit(EEXIT); } diff --git a/sbin/fsck_ffs/main.c b/sbin/fsck_ffs/main.c index 83bb3126a2f7..930a4c46d7fe 100644 --- a/sbin/fsck_ffs/main.c +++ b/sbin/fsck_ffs/main.c @@ -63,8 +63,6 @@ static const char rcsid[] = #include "fsck.h" -int returntosingle; - static void usage __P((void)); static int argtoi __P((int flag, char *req, char *str, int base)); static int docheck __P((struct fstab *fsp)); @@ -84,7 +82,7 @@ main(argc, argv) sync(); skipclean = 1; - while ((ch = getopt(argc, argv, "b:Bc:dfm:npy")) != -1) { + while ((ch = getopt(argc, argv, "b:Bc:dfFm:npy")) != -1) { switch (ch) { case 'b': skipclean = 0; @@ -109,6 +107,10 @@ main(argc, argv) skipclean = 0; break; + case 'F': + bkgrdcheck = 1; + break; + case 'm': lfmode = argtoi('m', "mode", optarg, 8); if (lfmode &~ 07777) @@ -154,7 +156,7 @@ main(argc, argv) (void)setrlimit(RLIMIT_DATA, &rlimit); } while (argc-- > 0) - (void)checkfilesys(blockcheck(*argv++), 0, 0L, 0); + (void)checkfilesys(*argv++, 0, 0L, 0); if (returntosingle) ret = 2; @@ -193,15 +195,46 @@ checkfilesys(filesys, mntpt, auxdata, child) struct zlncnt *zlnp; ufs_daddr_t blks; ufs_daddr_t files; - int cylno; + int cylno, size; if (preen && child) (void)signal(SIGQUIT, voidquit); cdevname = filesys; if (debug && preen) pwarn("starting\n"); + /* + * Make best effort to get the disk name. Check first to see + * if it is listed among the mounted filesystems. Failing that + * check to see if it is listed in /etc/fstab. + */ + mntp = getmntpt(filesys); + if (mntp != NULL) + filesys = mntp->f_mntfromname; + else + filesys = blockcheck(filesys); + /* + * If -F flag specified, check to see whether a background check + * is possible and needed. If possible and needed, exit with + * status zero. Otherwise exit with status non-zero. A non-zero + * exit status will cause a foreground check to be run. + */ sblock_init(); - + if (bkgrdcheck) { + if ((fsreadfd = open(filesys, O_RDONLY)) < 0 || readsb(0) == 0) + exit(3); /* Cannot read superblock */ + close(fsreadfd); + if (sblock.fs_flags & FS_NEEDSFSCK) + exit(4); /* Earlier background failed */ + if ((sblock.fs_flags & FS_DOSOFTDEP) == 0) + exit(5); /* Not running soft updates */ + size = MIBSIZE; + if (sysctlnametomib("vfs.ffs.adjrefcnt", adjrefcnt, &size) < 0) + exit(6); /* Lacks kernel support */ + if ((mntp == NULL && sblock.fs_clean == 1) || + (mntp != NULL && (sblock.fs_flags & FS_UNCLEAN) == 0)) + exit(7); /* Filesystem clean, report it now */ + exit(0); + } /* * If we are to do a background check: * Get the mount point information of the filesystem @@ -209,7 +242,6 @@ checkfilesys(filesys, mntpt, auxdata, child) * return created snapshot file * if not found, clear bkgrdflag and proceed with normal fsck */ - mntp = getmntpt(filesys); if (bkgrdflag) { if (mntp == NULL) { bkgrdflag = 0; @@ -432,7 +464,7 @@ checkfilesys(filesys, mntpt, auxdata, child) } /* - * Get the directory that the device is mounted on. + * Get the mount point information for name. */ static struct statfs * getmntpt(name) @@ -441,27 +473,35 @@ getmntpt(name) struct stat devstat, mntdevstat; char device[sizeof(_PATH_DEV) - 1 + MNAMELEN]; char *devname; - struct statfs *mntbuf; - int i, mntsize; + struct statfs *mntbuf, *statfsp; + int i, mntsize, isdev; - if (stat(name, &devstat) != 0 || - !(S_ISCHR(devstat.st_mode) || S_ISBLK(devstat.st_mode))) + if (stat(name, &devstat) != 0) return (NULL); + if (S_ISCHR(devstat.st_mode) || S_ISBLK(devstat.st_mode)) + isdev = 1; + else + isdev = 0; mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); for (i = 0; i < mntsize; i++) { - if (strcmp(mntbuf[i].f_fstypename, "ufs") != 0) - continue; - devname = mntbuf[i].f_mntfromname; + statfsp = &mntbuf[i]; + devname = statfsp->f_mntfromname; if (*devname != '/') { strcpy(device, _PATH_DEV); strcat(device, devname); - devname = device; + strcpy(statfsp->f_mntfromname, device); + } + if (isdev == 0) { + if (strcmp(name, statfsp->f_mntonname)) + continue; + return (statfsp); } if (stat(devname, &mntdevstat) == 0 && mntdevstat.st_rdev == devstat.st_rdev) - return (&mntbuf[i]); + return (statfsp); } - return (NULL); + statfsp = NULL; + return (statfsp); } static void diff --git a/sbin/fsck_ffs/utilities.c b/sbin/fsck_ffs/utilities.c index 81b96e652674..e584c8f30c22 100644 --- a/sbin/fsck_ffs/utilities.c +++ b/sbin/fsck_ffs/utilities.c @@ -52,6 +52,7 @@ static const char rcsid[] = #include #include #include +#include #include #include #include @@ -64,11 +65,20 @@ blockcheck(origname) char *origname; { struct stat stslash, stblock, stchar; - char *newname, *raw; + char *newname, *raw, *cp; struct fstab *fsinfo; int retried = 0, len; + static char device[MAXPATHLEN]; newname = origname; + if (stat(newname, &stblock) < 0) { + cp = strrchr(newname, '/'); + if (cp == 0) { + (void)snprintf(device, sizeof(device), "%s%s", + _PATH_DEV, newname); + newname = device; + } + } retry: if (stat(newname, &stblock) < 0) { printf("Can't stat %s: %s\n", newname, strerror(errno)); @@ -90,7 +100,7 @@ blockcheck(origname) printf( "Can't resolve %s to character special device.\n", origname); - return (0); + return (origname); } newname = fsinfo->fs_spec; retried++;