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:
parent
cdc83afc7f
commit
658667dbfa
@ -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
|
||||
|
111
sbin/fsck/fsck.c
111
sbin/fsck/fsck.c
@ -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. */
|
||||
|
@ -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
|
||||
|
@ -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 *)));
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user