endif
if BUILD_FSCK
+if BUILD_LIBBLKID
SUBDIRS += fsck
endif
+endif
ACLOCAL_AMFLAGS = -I m4
sbin_PROGRAMS = fsck
dist_man_MANS = fsck.8
-fsck_SOURCES = base_device.c fsck.c fsck.h $(top_srcdir)/lib/ismounted.c \
+fsck_SOURCES = fsck.c fsck.h $(top_srcdir)/lib/ismounted.c \
$(top_srcdir)/lib/fsprobe.c $(top_srcdir)/lib/canonicalize.c
fsck_LDADD =
fsck_CFLAGS = $(AM_CFLAGS)
+++ /dev/null
-/*
- * base_device.c
- *
- * Return the "base device" given a particular device; this is used to
- * assure that we only fsck one partition on a particular drive at any
- * one time. Otherwise, the disk heads will be seeking all over the
- * place. If the base device can not be determined, return NULL.
- *
- * The base_device() function returns an allocated string which must
- * be freed.
- *
- * Written by Theodore Ts'o, <tytso@mit.edu>
- *
- * Copyright (C) 2000 Theodore Ts'o.
- *
- * %Begin-Header%
- * This file may be redistributed under the terms of the GNU Public
- * License.
- * %End-Header%
- */
-#include <stdio.h>
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#if HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#include <ctype.h>
-#include <string.h>
-
-#include "fsck.h"
-
-/*
- * Required for the uber-silly devfs /dev/ide/host1/bus2/target3/lun3
- * pathames.
- */
-static const char *devfs_hier[] = {
- "host", "bus", "target", "lun", 0
-};
-
-char *base_device(const char *device)
-{
- char *str, *cp;
- const char **hier, *disk;
- int len;
-
- str = malloc(strlen(device)+1);
- if (!str)
- return NULL;
- strcpy(str, device);
- cp = str;
-
- /* Skip over /dev/; if it's not present, give up. */
- if (strncmp(cp, "/dev/", 5) != 0)
- goto errout;
- cp += 5;
-
- /* Skip over /dev/dsk/... */
- if (strncmp(cp, "dsk/", 4) == 0)
- cp += 4;
-
- /*
- * For md devices, we treat them all as if they were all
- * on one disk, since we don't know how to parallelize them.
- */
- if (cp[0] == 'm' && cp[1] == 'd') {
- *(cp+2) = 0;
- return str;
- }
-
- /* Handle DAC 960 devices */
- if (strncmp(cp, "rd/", 3) == 0) {
- cp += 3;
- if (cp[0] != 'c' || cp[2] != 'd' ||
- !isdigit(cp[1]) || !isdigit(cp[3]))
- goto errout;
- *(cp+4) = 0;
- return str;
- }
-
- /* Now let's handle /dev/hd* and /dev/sd* devices.... */
- if ((cp[0] == 'h' || cp[0] == 's') && (cp[1] == 'd')) {
- cp += 2;
- /* If there's a single number after /dev/hd, skip it */
- if (isdigit(*cp))
- cp++;
- /* What follows must be an alpha char, or give up */
- if (!isalpha(*cp))
- goto errout;
- *(cp + 1) = 0;
- return str;
- }
-
- /* Now let's handle devfs (ugh) names */
- len = 0;
- if (strncmp(cp, "ide/", 4) == 0)
- len = 4;
- if (strncmp(cp, "scsi/", 5) == 0)
- len = 5;
- if (len) {
- cp += len;
- /*
- * Now we proceed down the expected devfs hierarchy.
- * i.e., .../host1/bus2/target3/lun4/...
- * If we don't find the expected token, followed by
- * some number of digits at each level, abort.
- */
- for (hier = devfs_hier; *hier; hier++) {
- len = strlen(*hier);
- if (strncmp(cp, *hier, len) != 0)
- goto errout;
- cp += len;
- while (*cp != '/' && *cp != 0) {
- if (!isdigit(*cp))
- goto errout;
- cp++;
- }
- cp++;
- }
- *(cp - 1) = 0;
- return str;
- }
-
- /* Now handle devfs /dev/disc or /dev/disk names */
- disk = 0;
- if (strncmp(cp, "discs/", 6) == 0)
- disk = "disc";
- else if (strncmp(cp, "disks/", 6) == 0)
- disk = "disk";
- if (disk) {
- cp += 6;
- if (strncmp(cp, disk, 4) != 0)
- goto errout;
- cp += 4;
- while (*cp != '/' && *cp != 0) {
- if (!isdigit(*cp))
- goto errout;
- cp++;
- }
- *cp = 0;
- return str;
- }
-
-errout:
- free(str);
- return NULL;
-}
-
-#ifdef DEBUG
-int main(int argc, char** argv)
-{
- const char *base;
- char buf[256], *cp;
-
- while (1) {
- if (fgets(buf, sizeof(buf), stdin) == NULL)
- break;
- cp = strchr(buf, '\n');
- if (cp)
- *cp = 0;
- cp = strchr(buf, '\t');
- if (cp)
- *cp = 0;
- base = base_device(buf);
- printf("%s\t%s\n", buf, base ? base : "NONE");
- }
- exit(0);
-}
-#endif
fsck will attempt to check them in parallel, although it will avoid running
multiple filesystem checks on the same physical disk.
.sp
+.B fsck
+does not check stacked devices (RAIDs, dm-crypt, ...) in parallel with any other
+device. See below for FSCK_FORCE_ALL_PARALLEL setting. The /sys filesystem is
+used to detemine dependencies between devices.
+.sp
Hence, a very common configuration in
.I /etc/fstab
files is to set the root filesystem to have a
.B FSCK_FORCE_ALL_PARALLEL
If this environment variable is set,
.B fsck
-will attempt to run all of the specified filesystems in parallel,
-regardless of whether the filesystems appear to be on the same
-device. (This is useful for RAID systems or high-end storage systems
-such as those sold by companies such as IBM or EMC.)
+will attempt to run all of the specified filesystems in parallel, regardless of
+whether the filesystems appear to be on the same device. (This is useful for
+RAID systems or high-end storage systems such as those sold by companies such
+as IBM or EMC.) Note that the fs_passno value is still used.
.TP
.B FSCK_MAX_INST
This environment variable will limit the maximum number of file system
#include <errno.h>
#include <malloc.h>
#include <signal.h>
+#include <dirent.h>
+#include <blkid.h>
#include "fsprobe.h"
static void free_instance(struct fsck_instance *i)
{
free(i->prog);
- free(i->device);
- free(i->base_device);
free(i);
return;
}
fs->passno = passno;
fs->flags = 0;
fs->next = NULL;
+ fs->disk = 0;
+ fs->stacked = 0;
if (!filesys_info)
filesys_info = fs;
* Execute a particular fsck program, and link it into the list of
* child processes we are waiting for.
*/
-static int execute(const char *type, const char *device, const char *mntpt,
- int interactive)
+static int execute(const char *type, struct fs_info *fs, int interactive)
{
char *s, *argv[80], prog[80];
int argc, i;
}
}
- argv[argc++] = string_copy(device);
+ argv[argc++] = string_copy(fs->device);
argv[argc] = 0;
s = find_fsck(prog);
if (verbose || noexecute) {
printf("[%s (%d) -- %s] ", s, num_running,
- mntpt ? mntpt : device);
+ fs->mountpt ? fs->mountpt : fs->device);
for (i=0; i < argc; i++)
printf("%s ", argv[i]);
printf("\n");
inst->pid = pid;
inst->prog = string_copy(prog);
inst->type = string_copy(type);
- inst->device = string_copy(device);
- inst->base_device = base_device(device);
inst->start_time = time(0);
+ inst->fs = fs;
inst->next = NULL;
/*
} else {
printf(_("Warning... %s for device %s exited "
"with signal %d.\n"),
- inst->prog, inst->device, sig);
+ inst->prog, inst->fs->device, sig);
status = EXIT_ERROR;
}
} else {
printf(_("%s %s: status is %x, should never happen.\n"),
- inst->prog, inst->device, status);
+ inst->prog, inst->fs->device, status);
status = EXIT_ERROR;
}
inst->exit_status = status;
instance_list = inst->next;
if (verbose > 1)
printf(_("Finished with %s (exit status %d)\n"),
- inst->device, inst->exit_status);
+ inst->fs->device, inst->exit_status);
num_running--;
return inst;
}
type = DEFAULT_FSTYPE;
num_running++;
- retval = execute(type, fs->device, fs->mountpt, interactive);
+ retval = execute(type, fs, interactive);
if (retval) {
fprintf(stderr, _("%s: Error %d while executing fsck.%s "
"for %s\n"), progname, retval, type, fs->device);
return 0;
}
+static int count_slaves(dev_t disk)
+{
+ DIR *dir;
+ struct dirent *dp;
+ char dirname[PATH_MAX];
+ int count = 0;
+
+ snprintf(dirname, sizeof(dirname),
+ "/sys/dev/block/%u:%u/slaves/",
+ major(disk), minor(disk));
+
+ if (!(dir = opendir(dirname)))
+ return -1;
+
+ while ((dp = readdir(dir)) != 0) {
+#ifdef _DIRENT_HAVE_D_TYPE
+ if (dp->d_type != DT_UNKNOWN && dp->d_type != DT_LNK)
+ continue;
+#endif
+ if (dp->d_name[0] == '.' &&
+ ((dp->d_name[1] == 0) ||
+ ((dp->d_name[1] == '.') && (dp->d_name[2] == 0))))
+ continue;
+
+ count++;
+ }
+ closedir(dir);
+ return count;
+}
+
/*
* Returns TRUE if a partition on the same disk is already being
* checked.
*/
-static int device_already_active(char *device)
+static int disk_already_active(struct fs_info *fs)
{
struct fsck_instance *inst;
- char *base;
if (force_all_parallel)
return 0;
-#ifdef BASE_MD
- /* Don't check a soft raid disk with any other disk */
- if (instance_list &&
- (!strncmp(instance_list->device, BASE_MD, sizeof(BASE_MD)-1) ||
- !strncmp(device, BASE_MD, sizeof(BASE_MD)-1)))
+ if (instance_list && instance_list->fs->stacked)
+ /* any instance for a stacked device is already running */
return 1;
-#endif
- base = base_device(device);
+ if (!fs->disk) {
+ struct stat st;
+ dev_t disk;
+
+ if (!stat(fs->device, &st) &&
+ !blkid_devno_to_wholedisk(st.st_rdev, NULL, 0, &disk)) {
+ fs->disk = disk;
+ fs->stacked = count_slaves(disk);
+ }
+ }
+
/*
* If we don't know the base device, assume that the device is
* already active if there are any fsck instances running.
+ *
+ * Don't check a stacked device with any other disk too.
*/
- if (!base)
+ if (!fs->disk || fs->stacked)
return (instance_list != 0);
+
for (inst = instance_list; inst; inst = inst->next) {
- if (!inst->base_device || !strcmp(base, inst->base_device)) {
- free(base);
+ if (!inst->fs->disk || fs->disk == inst->fs->disk)
return 1;
- }
}
- free(base);
return 0;
}
* already been spawned, then we need to defer
* this to another pass.
*/
- if (device_already_active(fs->device)) {
+ if (disk_already_active(fs)) {
pass_done = 0;
continue;
}
int freq;
int passno;
int flags;
+ dev_t disk;
+ int stacked;
struct fs_info *next;
};
time_t start_time;
char * prog;
char * type;
- char * device;
- char * base_device;
+ struct fs_info *fs;
struct fsck_instance *next;
};