Add support for running foreground (-F) and background (-B) checks.

Traditionally, fsck is invoked before the filesystems are mounted
and all checks are done to completion at that time. If background
checking is available, fsck is invoked twice. It is first invoked
at the traditional time, before the filesystems are mounted, with
the -F flag to do checking on all the filesystems that cannot do
background checking. It is then invoked a second time, after the
system has completed going multiuser, with the -B flag to do checking
on all the filesystems that can do background checking. Unlike
the foreground checking, the background checking is started
asynchonously so that other system activity can proceed even on
the filesystems that are being checked.

At the moment, only the fast filesystem supports background checking.
To be able to do background checking, a filesystem 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 (i.e., not listed as `noauto' in /etc/fstab).

These changes are the final piece needed to support background
filesystem checking. They will not have any effect until you update
your /etc/rc to invoke fsck in its new mode of operation. I am
still playing around with exactly what those changes should be
and should be committing them later this week.
This commit is contained in:
mckusick 2001-04-25 07:18:22 +00:00
parent cdc83afc7f
commit 658667dbfa
5 changed files with 219 additions and 49 deletions

View File

@ -37,6 +37,7 @@
.Sh SYNOPSIS
.Nm
.Op Fl dvplfyn
.Op Fl B | F
.Op Fl l Ar maxparallel
.Op Fl t Ar fstype
.Op Fl T Ar fstype : Ns Ar fsoptions
@ -52,9 +53,29 @@ file or in the command line for consistency.
It is normally used in the script
.Pa /etc/rc
during automatic reboot.
If no filesystems are specified, and ``preen'' mode is enabled (
.Fl p
option)
Traditionally,
.Nm
is invoked before the filesystems are mounted
and all checks are done to completion at that time.
If background checking is available,
.Nm
is invoked twice.
It is first invoked at the traditional time,
before the filesystems are mounted, with the
.Fl F
flag to do checking on all the filesystems
that cannot do background checking.
It is then invoked a second time,
after the system has completed going multiuser, with the
.Fl B
flag to do checking on all the filesystems
that can do background checking.
Unlike the foreground checking,
the background checking is started asynchonously
so that other system activity can proceed
even on the filesystems that are being checked.
.Pp
If no filesystems are specified
.Nm
reads the table
.Pa /etc/fstab
@ -99,6 +120,42 @@ Causes
to assume no as the answer to all operator questions, except "CONTINUE?".
.It Fl p
Enter preen mode.
In preen mode, only a restricted class of innocuous
filesystem inconsistencies will be corrected.
If unexpected inconsistencies caused by hardware or
software failures are encounted, the check program
will exit with a failure.
See the manual pages for the individual check programs
for a list of the sorts of failures that they correct
when running in preen mode.
.It Fl F
Run in foreground mode.
The check program for each filesystem is invoked with the
.Fl F
flag to determine whether it wishes to run as part of
the boot up sequence,
or if it is able to do its job in background after the
system is up and running.
A non-zero exit code indicates that it wants to run in foreground
and the check program is invoked.
A zero exit code indicates that it is able to run later in background
and just a deferred message is printed.
.It Fl B
Run in background mode.
The check program for each filesystem is invoked with the
.Fl F
flag to determine whether it wishes to run as part of
the boot up sequence,
or if it is able to do its job in background after the
system is up and running.
A non-zero exit code indicates that it wanted to run in foreground
which is assumed to have been done, so the filesystem is skipped.
A zero exit code indicates that it is able to run in background
so the check program is invoked with the
.Fl B
flag to indicate that a check on the active filesystem should be done.
When running in background mode,
only one filesystem at a time will be checked.
.It Fl t Ar fstype
Invoke
.Nm

View File

@ -78,10 +78,11 @@ struct entry {
static char *options = NULL;
static int flags = 0;
static int forceflag = 0;
int main __P((int, char *[]));
static int checkfs __P((const char *, const char *, const char *, void *,
static int checkfs __P((const char *, const char *, const char *, char *,
pid_t *));
static int selected __P((const char *));
static void addoption __P((char *));
@ -92,7 +93,7 @@ static void catopt __P((char **, const char *));
static void mangle __P((char *, int *, const char ***, int *));
static const char *getfslab __P((const char *));
static void usage __P((void));
static void *isok __P((struct fstab *));
static int isok __P((struct fstab *));
int
main(argc, argv)
@ -110,8 +111,14 @@ main(argc, argv)
TAILQ_INIT(&selhead);
TAILQ_INIT(&opthead);
while ((i = getopt(argc, argv, "dvpfnyl:t:T:")) != -1)
while ((i = getopt(argc, argv, "BdvpfFnyl:t:T:")) != -1)
switch (i) {
case 'B':
if (flags & CHECK_BACKGRD)
errx(1, "Cannot specify -B and -F.");
flags |= DO_BACKGRD;
break;
case 'd':
flags |= CHECK_DEBUG;
break;
@ -120,16 +127,27 @@ main(argc, argv)
flags |= CHECK_VERBOSE;
break;
case 'F':
if (flags & DO_BACKGRD)
errx(1, "Cannot specify -B and -F.");
flags |= CHECK_BACKGRD;
break;
case 'p':
flags |= CHECK_PREEN;
/*FALLTHROUGH*/
case 'n':
case 'f':
case 'y':
globopt[1] = i;
catopt(&options, globopt);
break;
case 'f':
forceflag = 1;
globopt[1] = i;
catopt(&options, globopt);
break;
case 'l':
warnx("Ignoring obsolete -l option\n");
break;
@ -165,8 +183,9 @@ main(argc, argv)
for (; argc--; argv++) {
const char *spec, *type, *cp;
const char *spec, *mntpt, *type, *cp;
char device[MAXPATHLEN];
struct statfs *mntp;
spec = *argv;
cp = strrchr(spec, '/');
@ -175,48 +194,98 @@ main(argc, argv)
_PATH_DEV, spec);
spec = device;
}
mntp = getmntpt(spec);
if (mntp != NULL) {
spec = mntp->f_mntfromname;
mntpt = mntp->f_mntonname;
}
if ((fs = getfsfile(spec)) == NULL &&
(fs = getfsspec(spec)) == NULL) {
if (vfstype == NULL)
vfstype = getfslab(spec);
type = vfstype;
}
else {
devcheck(spec);
} else {
spec = fs->fs_spec;
type = fs->fs_vfstype;
mntpt = fs->fs_file;
if (BADTYPE(fs->fs_type))
errx(1, "%s has unknown file system type.",
spec);
}
if ((flags & CHECK_BACKGRD) &&
checkfs(type, spec, mntpt, "-F", NULL) == 0) {
printf("%s: DEFER FOR BACKGROUND CHECKING\n", *argv);
continue;
}
if ((flags & DO_BACKGRD) && forceflag == 0 &&
checkfs(type, spec, mntpt, "-F", NULL) != 0)
continue;
rval |= checkfs(type, devcheck(spec), *argv, NULL, NULL);
rval |= checkfs(type, spec, mntpt, NULL, NULL);
}
return rval;
}
static void *
static int
isok(fs)
struct fstab *fs;
{
int i;
if (fs->fs_passno == 0)
return NULL;
return (0);
if (BADTYPE(fs->fs_type))
return NULL;
return (0);
if (!selected(fs->fs_vfstype))
return NULL;
return fs;
return (0);
/*
* If the -B flag has been given, then process the needed
* background checks. Background checks cannot be run on
* filesystems that will be mounted read-only or that were
* not mounted at boot time (typically those marked `noauto').
* If these basic tests are passed, check with the filesystem
* itself to see if it is willing to do background checking
* by invoking its check program with the -F flag.
*/
if (flags & DO_BACKGRD) {
if (!strcmp(fs->fs_type, FSTAB_RO))
return (0);
if (getmntpt(fs->fs_spec) == NULL)
return (0);
if (checkfs(fs->fs_vfstype, fs->fs_spec, fs->fs_file, "-F", 0))
return (0);
return (1);
}
/*
* If the -F flag has been given, then consider deferring the
* check to background. Background checks cannot be run on
* filesystems that will be mounted read-only or that will
* not be mounted at boot time (e.g., marked `noauto'). If
* these basic tests are passed, check with the filesystem
* itself to see if it is willing to defer to background
* checking by invoking its check program with the -F flag.
*/
if ((flags & CHECK_BACKGRD) == 0 || !strcmp(fs->fs_type, FSTAB_RO))
return (1);
for (i = strlen(fs->fs_mntops) - 6; i >= 0; i--)
if (!strncmp(&fs->fs_mntops[i], "noauto", 6))
break;
if (i >= 0)
return (1);
if (checkfs(fs->fs_vfstype, fs->fs_spec, fs->fs_file, "-F", NULL) != 0)
return (1);
printf("%s: DEFER FOR BACKGROUND CHECKING\n", fs->fs_spec);
return (0);
}
static int
checkfs(pvfstype, spec, mntpt, auxarg, pidp)
checkfs(pvfstype, spec, mntpt, auxopt, pidp)
const char *pvfstype, *spec, *mntpt;
void *auxarg;
char *auxopt;
pid_t *pidp;
{
/* List of directories containing fsck_xxx subcommands. */
@ -256,6 +325,10 @@ checkfs(pvfstype, spec, mntpt, auxarg, pidp)
catopt(&optbuf, options);
if (extra)
catopt(&optbuf, extra);
if (auxopt)
catopt(&optbuf, auxopt);
else if (flags & DO_BACKGRD)
catopt(&optbuf, "-B");
maxargc = 64;
argv = emalloc(sizeof(char *) * maxargc);
@ -285,7 +358,7 @@ checkfs(pvfstype, spec, mntpt, auxarg, pidp)
return (1);
case 0: /* Child. */
if (flags & CHECK_DEBUG)
if ((flags & CHECK_DEBUG) && auxopt == NULL)
_exit(0);
/* Go find an executable. */

View File

@ -51,9 +51,11 @@ __RCSID("$NetBSD: fsutil.c,v 1.7 1998/07/30 17:41:03 thorpej Exp $");
#include <errno.h>
#include <fstab.h>
#include <err.h>
#include <paths.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include "fsutil.h"
@ -263,6 +265,47 @@ devcheck(origname)
return (origname);
}
/*
* Get the mount point information for name.
*/
struct statfs *
getmntpt(name)
const char *name;
{
struct stat devstat, mntdevstat;
char device[sizeof(_PATH_DEV) - 1 + MNAMELEN];
char *devname;
struct statfs *mntbuf, *statfsp;
int i, mntsize, isdev;
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++) {
statfsp = &mntbuf[i];
devname = statfsp->f_mntfromname;
if (*devname != '/') {
strcpy(device, _PATH_DEV);
strcat(device, devname);
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 (statfsp);
}
statfsp = NULL;
return (statfsp);
}
#if 0
/*
* XXX this code is from NetBSD, but fails in FreeBSD because we

View File

@ -48,15 +48,18 @@ const char *blockcheck __P((const char *));
const char *devcheck __P((const char *));
const char *cdevname __P((void));
void setcdevname __P((const char *, int));
struct statfs *getmntpt __P((const char *));
int hotroot __P((void));
void *emalloc __P((size_t));
void *erealloc __P((void *, size_t));
char *estrdup __P((const char *));
#define CHECK_PREEN 1
#define CHECK_VERBOSE 2
#define CHECK_DEBUG 4
#define CHECK_PREEN 0x0001
#define CHECK_VERBOSE 0x0002
#define CHECK_DEBUG 0x0004
#define CHECK_BACKGRD 0x0008
#define DO_BACKGRD 0x0010
struct fstab;
int checkfstab __P((int, void *(*)(struct fstab *),
int (*) (const char *, const char *, const char *, void *, pid_t *)));
int checkfstab __P((int, int (*)(struct fstab *),
int (*) (const char *, const char *, const char *, char *, pid_t *)));

View File

@ -64,7 +64,6 @@ struct partentry {
char *p_devname; /* device name */
char *p_mntpt; /* mount point */
char *p_type; /* filesystem type */
void *p_auxarg; /* auxiliary argument */
};
TAILQ_HEAD(part, partentry) badh;
@ -81,23 +80,22 @@ TAILQ_HEAD(disk, diskentry) diskh;
static int nrun = 0, ndisks = 0;
static struct diskentry *finddisk __P((const char *));
static void addpart __P((const char *, const char *, const char *, void *));
static void addpart __P((const char *, const char *, const char *));
static int startdisk __P((struct diskentry *,
int (*)(const char *, const char *, const char *, void *, pid_t *)));
int (*)(const char *, const char *, const char *, char *, pid_t *)));
static void printpart __P((void));
int
checkfstab(flags, docheck, checkit)
int flags;
void *(*docheck) __P((struct fstab *));
int (*checkit) __P((const char *, const char *, const char *, void *,
int (*docheck) __P((struct fstab *));
int (*checkit) __P((const char *, const char *, const char *, char *,
pid_t *));
{
struct fstab *fs;
struct diskentry *d, *nextdisk;
struct partentry *p;
int ret, pid, retcode, passno, sumstatus, status, nextpass;
void *auxarg;
const char *name;
TAILQ_INIT(&badh);
@ -116,20 +114,18 @@ checkfstab(flags, docheck, checkit)
return (8);
}
while ((fs = getfsent()) != 0) {
if ((auxarg = (*docheck)(fs)) == NULL)
continue;
name = fs->fs_spec;
if (fs->fs_passno > passno && fs->fs_passno < nextpass)
nextpass = fs->fs_passno;
if (passno != fs->fs_passno)
if (passno != fs->fs_passno || (*docheck)(fs) == 0)
continue;
if (flags & CHECK_DEBUG)
printf("pass %d, name %s\n", passno, name);
if ((flags & CHECK_PREEN) == 0 || passno == 1) {
if ((flags & CHECK_PREEN) == 0 || passno == 1 ||
(flags & DO_BACKGRD) != 0) {
if (name == NULL) {
if (flags & CHECK_PREEN)
return 8;
@ -137,7 +133,7 @@ checkfstab(flags, docheck, checkit)
continue;
}
sumstatus = (*checkit)(fs->fs_vfstype,
name, fs->fs_file, auxarg, NULL);
name, fs->fs_file, NULL, NULL);
if (sumstatus)
return (sumstatus);
@ -149,11 +145,11 @@ checkfstab(flags, docheck, checkit)
sumstatus |= 8;
continue;
}
addpart(fs->fs_vfstype, name, fs->fs_file,
auxarg);
addpart(fs->fs_vfstype, name, fs->fs_file);
}
if ((flags & CHECK_PREEN) == 0 || passno == 1)
if ((flags & CHECK_PREEN) == 0 || passno == 1 ||
(flags & DO_BACKGRD) != 0)
continue;
if (flags & CHECK_DEBUG) {
@ -304,9 +300,8 @@ printpart()
static void
addpart(type, devname, mntpt, auxarg)
addpart(type, devname, mntpt)
const char *type, *devname, *mntpt;
void *auxarg;
{
struct diskentry *d = finddisk(devname);
struct partentry *p;
@ -321,7 +316,6 @@ addpart(type, devname, mntpt, auxarg)
p->p_devname = estrdup(devname);
p->p_mntpt = estrdup(mntpt);
p->p_type = estrdup(type);
p->p_auxarg = auxarg;
TAILQ_INSERT_TAIL(&d->d_part, p, p_entries);
}
@ -330,14 +324,14 @@ addpart(type, devname, mntpt, auxarg)
static int
startdisk(d, checkit)
struct diskentry *d;
int (*checkit) __P((const char *, const char *, const char *, void *,
int (*checkit) __P((const char *, const char *, const char *, char *,
pid_t *));
{
struct partentry *p = TAILQ_FIRST(&d->d_part);
int rv;
while ((rv = (*checkit)(p->p_type, p->p_devname, p->p_mntpt,
p->p_auxarg, &d->d_pid)) != 0 && nrun > 0)
NULL, &d->d_pid)) != 0 && nrun > 0)
sleep(10);
if (rv == 0)