summaryrefslogtreecommitdiffstats
path: root/fsck/fsck.c
diff options
context:
space:
mode:
authorKarel Zak2010-08-19 15:33:45 +0200
committerKarel Zak2010-08-19 15:33:45 +0200
commit0c0f93fcc37d02d9ab6d159f964da378d424199e (patch)
treed8ab6318379cea0f9f2b23e8d4a99a2434c64d6b /fsck/fsck.c
parenttests: add blkid test for partitioned RAID0 (diff)
downloadkernel-qcow2-util-linux-0c0f93fcc37d02d9ab6d159f964da378d424199e.tar.gz
kernel-qcow2-util-linux-0c0f93fcc37d02d9ab6d159f964da378d424199e.tar.xz
kernel-qcow2-util-linux-0c0f93fcc37d02d9ab6d159f964da378d424199e.zip
fsck: improve whole-disk check, detect stacked devices
The current heuristic for conversion from partition to whole-disk is based on device names. It's pretty poor. This patch replaces this code with blkid_devno_to_wholedisk(). This solution is based on /sys FS and it works for arbitrary partitioned devices. The another problem is the way how fsck determines stacked devices. The current code checks device name for "md" prefix only. It does not care about DM, dm-ccypt, and so on. This patch uses /sys/block/.../slaves/, but it does not fully resolves dependencies between all devices. The method is simple -- fsck does not check stacked devices in parallel with any other device. Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'fsck/fsck.c')
-rw-r--r--fsck/fsck.c89
1 files changed, 62 insertions, 27 deletions
diff --git a/fsck/fsck.c b/fsck/fsck.c
index 7577eff13..e7526f9e6 100644
--- a/fsck/fsck.c
+++ b/fsck/fsck.c
@@ -42,6 +42,8 @@
#include <errno.h>
#include <malloc.h>
#include <signal.h>
+#include <dirent.h>
+#include <blkid.h>
#include "fsprobe.h"
@@ -217,8 +219,6 @@ static void parse_escape(char *word)
static void free_instance(struct fsck_instance *i)
{
free(i->prog);
- free(i->device);
- free(i->base_device);
free(i);
return;
}
@@ -240,6 +240,8 @@ static struct fs_info *create_fs_device(const char *device, const char *mntpnt,
fs->passno = passno;
fs->flags = 0;
fs->next = NULL;
+ fs->disk = 0;
+ fs->stacked = 0;
if (!filesys_info)
filesys_info = fs;
@@ -414,8 +416,7 @@ static int progress_active(NOARGS)
* 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;
@@ -452,7 +453,7 @@ static int execute(const char *type, const char *device, const char *mntpt,
}
}
- argv[argc++] = string_copy(device);
+ argv[argc++] = string_copy(fs->device);
argv[argc] = 0;
s = find_fsck(prog);
@@ -464,7 +465,7 @@ static int execute(const char *type, const char *device, const char *mntpt,
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");
@@ -492,9 +493,8 @@ static int execute(const char *type, const char *device, const char *mntpt,
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;
/*
@@ -597,12 +597,12 @@ static struct fsck_instance *wait_one(int flags)
} 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;
@@ -641,7 +641,7 @@ ret_inst:
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;
}
@@ -698,7 +698,7 @@ static void fsck_device(struct fs_info *fs, int interactive)
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);
@@ -924,40 +924,75 @@ static int ignore(struct fs_info *fs)
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;
}
@@ -1038,7 +1073,7 @@ static int check_all(NOARGS)
* 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;
}