Hi Ted,

I found fsck to trash my HDs quite badly everytime on rebooting after
killing my machine.
I akso found out about the reason: I use scsidev
(http://www.garloff.de/kurt/linux/scsidev/) to maintain a proper
mapping of harddisks to userspace in varying SCSI configs.

fsck's approach to find out, whether partitions are on the same drive is
rather flawed, IMHO. It has a compiled in (!) list of base names which is
compares the the names in fstab to and determines that way whether fs are
on the same harddisk.

I don't like this:
* The list is not even configurable
* It needs to keep this list in sync with the actual device names used

It can think of two possibilities to get out of this:
* Use a pseudo-intelligent algorithm to parse the names, and assuming that
  names with only the last type of charcter (normally the digits at the edn,
  but we could also allow for letters) are on the same device
* Using the device numbers for this info.

I implemented the second approach. One disadvantage is that the number
of partitions is not the same on every device. I took into account, that IDE
allows for 64 and assumed 16 on every other device. Works flawlessly for me.
Patch is attached (against 1.17). Please consider to apply it. (If you care
about protability, we can of course provide our own list of IDE Majors
instead of using the one from linux headers.)

Regards,
-- 
Kurt Garloff                   <[EMAIL PROTECTED]>         [Eindhoven, NL]
Physics: Plasma simulations <[EMAIL PROTECTED]>   [TU Eindhoven, NL] 
Linux: SCSI, Security          <[EMAIL PROTECTED]>   [SuSE Nuernberg, FRG]
 (See mail header or public key servers for PGP2 and GPG public keys.)
--- misc/fsck.c.orig    Tue Oct 26 19:10:21 1999
+++ misc/fsck.c Sun Feb  6 23:44:42 2000
@@ -50,11 +50,17 @@
 #if HAVE_ERRNO_H
 #include <errno.h>
 #endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
 #include <malloc.h>
 
 #include "../version.h"
 #include "fsck.h"
 #include "get_device_by_label.h"
+#if HAVE_LINUX_MAJOR_H
+# include <linux/major.h>
+#endif
 
 #ifndef _PATH_MNTTAB
 #define        _PATH_MNTTAB    "/etc/fstab"
@@ -77,46 +83,6 @@
        NULL
 };
 
-#ifdef DEV_DSK_DEVICES
-static const char *base_devices[] = {
-       "/dev/dsk/hda",
-       "/dev/dsk/hdb",
-       "/dev/dsk/hdc",
-       "/dev/dsk/hdd",
-       "/dev/dsk/hd1a",
-       "/dev/dsk/hd1b",
-       "/dev/dsk/hd1c",
-       "/dev/dsk/hd1d",
-       "/dev/dsk/sda",
-       "/dev/dsk/sdb",
-       "/dev/dsk/sdc",
-       "/dev/dsk/sdd",
-       "/dev/dsk/sde",
-       "/dev/dsk/sdf",
-       "/dev/dsk/sdg",
-       NULL
-};
-#else
-static const char *base_devices[] = {
-       "/dev/hda",
-       "/dev/hdb",
-       "/dev/hdc",
-       "/dev/hdd",
-       "/dev/hd1a",
-       "/dev/hd1b",
-       "/dev/hd1c",
-       "/dev/hd1d",
-       "/dev/sda",
-       "/dev/sdb",
-       "/dev/sdc",
-       "/dev/sdd",
-       "/dev/sde",
-       "/dev/sdf",
-       "/dev/sdg",
-       NULL
-};
-#endif
-
 /*
  * Global variables for options
  */
@@ -199,12 +165,21 @@
 {
        if (i->prog)
                free(i->prog);
-       if (i->device)
-               free(i->device);
        free(i);
        return;
 }
 
+static dev_t get_devno (const char *device)
+{
+       int err;
+       struct stat st;
+       err = stat (device, &st);
+       if (err)
+               return 0;
+       else
+               return st.st_rdev;
+}
+       
 static int parse_fstab_line(char *line, struct fs_info **ret_fs)
 {
        char    *device, *mntpnt, *type, *opts, *freq, *passno, *cp;
@@ -240,7 +215,9 @@
        fs->passno = passno ? atoi(passno) : -1;
        fs->flags = 0;
        fs->next = NULL;
-
+#if HAVE_SYS_STAT_H
+       fs->dev = get_devno (fs->device);
+#endif
        *ret_fs = fs;
 
        return 0;
@@ -439,7 +416,7 @@
        inst->pid = pid;
        inst->prog = string_copy(prog);
        inst->type = string_copy(type);
-       inst->device = string_copy(device);
+       inst->dev = get_devno(device);
        inst->start_time = time(0);
        inst->next = NULL;
 
@@ -512,14 +489,14 @@
                if (sig == SIGINT) {
                        status = EXIT_UNCORRECTED;
                } else {
-                       printf("Warning... %s for device %s exited "
+                       printf("Warning... %s for device %02x:%02x exited "
                               "with signal %d.\n",
-                              inst->prog, inst->device, sig);
+                              inst->prog, major(inst->dev), minor(inst->dev), sig);
                        status = EXIT_ERROR;
                }
        } else {
-               printf("%s %s: status is %x, should never happen.\n",
-                      inst->prog, inst->device, status);
+               printf("%s 0x%x: status is %02x:%02x, should never happen.\n",
+                      inst->prog, major(inst->dev), minor(inst->dev), status);
                status = EXIT_ERROR;
        }
        inst->exit_status = status;
@@ -675,37 +652,41 @@
 }
 
 /*
- * 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.
- */
-static const char *base_device(char *device)
-{
-       const char **base;
-
-       for (base = base_devices; *base; base++) {
-               if (!strncmp(*base, device, strlen(*base)))
-                       return *base;
-       }
-       return device;
-}
-
-/*
  * Returns TRUE if a partition on the same disk is already being
  * checked.
  */
-static int device_already_active(char *device)
+static int device_already_active(dev_t dev)
 {
        struct fsck_instance *inst;
-       const char *base = base_device(device);
 
        if (force_all_parallel)
                return 0;
 
        for (inst = instance_list; inst; inst = inst->next) {
-               if (!strcmp(base, base_device(inst->device)))
-                       return 1;
+               if (major (inst->dev) == major (dev)) {
+#if HAVE_LINUX_MAJOR_H
+                       switch (major(dev)) {
+                           case IDE0_MAJOR:
+                           case IDE1_MAJOR:
+                           case IDE2_MAJOR:
+                           case IDE3_MAJOR:
+                           case IDE4_MAJOR:
+                           case IDE5_MAJOR:
+                           case IDE6_MAJOR:
+                           case IDE7_MAJOR:
+                           case IDE8_MAJOR:
+                           case IDE9_MAJOR:
+                               if ((minor (inst->dev) & 0xc0) == (minor (dev) & 0xc0))
+                                       return 1;
+                           default:
+                               if ((minor (inst->dev) & 0xf0) == (minor (dev) & 0xf0))
+                                       return 1;
+                       }
+#else
+                       if ((minor (inst->dev) & 0xf0) == (minor (dev) & 0xf0))
+                               return 1;
+#endif
+               }
        }
        return 0;
 }
@@ -770,7 +751,7 @@
                         * already been spawned, then we need to defer
                         * this to another pass.
                         */
-                       if (device_already_active(fs->device)) {
+                       if (device_already_active(fs->dev)) {
                                pass_done = 0;
                                continue;
                        }

PGP signature

Reply via email to