This patch will allow you from something like lilo to do the following:

linux root=/dev/hda1,/dev/hdb1,/dev/hdd1

which will cause the kernel to attempt to probe all three devices in order
until it finds one with a valid filesytem.  This is handy for people that
move devices around a lot (ie the devices changes ID) and provides an easy
and direct solution for bootable cd-roms that could be on anyone of
several types of cdrom device.

caveates:  I don't know much about initrd and the change_root() handling,
to the best of my knowledge this co-exists happily.

I'm not on the list so if you have replies of any nature be sure to cc me
directly.  thanks,

t. camp

--cut here--
diff --recursive --unified --ignore-all-space 
linux/Documentation/kernel-parameters.txt 
linux-2.4.0.8/Documentation/kernel-parameters.txt
--- linux/Documentation/kernel-parameters.txt   Tue Sep  5 13:51:14 2000
+++ linux-2.4.0.8/Documentation/kernel-parameters.txt   Fri Nov 24 16:51:12 2000
@@ -473,7 +473,11 @@
 
        ro              [KNL] Mount root device read-only on boot.
 
-       root=           [KNL] root filesystem.
+       root=           [KNL] root filesystem, comma separated list of up
+                       to eight /dev/ entries will be tried in order 
+                       presented until kernel suceeds in mounting a 
+                       filesystem, multiple independant 'root=' entries
+                       allowed as well.
 
        rw              [KNL] Mount root device read-write on boot.
 
diff --recursive --unified --ignore-all-space linux/fs/super.c linux-2.4.0.8/fs/super.c
--- linux/fs/super.c    Fri Aug 11 14:31:45 2000
+++ linux-2.4.0.8/fs/super.c    Fri Nov 24 17:00:29 2000
@@ -18,6 +18,8 @@
  *    Torbjörn Lindh ([EMAIL PROTECTED]), April 14, 1996.
  *  Added devfs support: Richard Gooch <[EMAIL PROTECTED]>, 13-JAN-1998
  *  Heavily rewritten for 'one fs - one tree' dcache architecture. AV, Mar 2000
+ *  Modifications to mount_root for trying a list of root devices.
+ *                     Tracy Camp <[EMAIL PROTECTED]> 11/22/00
  */
 
 #include <linux/config.h>
@@ -1447,27 +1449,33 @@
        struct block_device *bdev = NULL;
        mode_t mode;
        int retval;
+       int root_device_index = 0;
        void *handle;
        char path[64];
        int path_start = -1;
 
 #ifdef CONFIG_ROOT_NFS
        void *data;
-       if (MAJOR(ROOT_DEV) != UNNAMED_MAJOR)
+       if (MAJOR(ROOT_DEV) != UNNAMED_MAJOR) {
                goto skip_nfs;
+               }
        fs_type = get_fs_type("nfs");
-       if (!fs_type)
+       if (!fs_type) {
                goto no_nfs;
+               }
        ROOT_DEV = get_unnamed_dev();
        if (!ROOT_DEV)
                /*
                 * Your /linuxrc sucks worse than MSExchange - that's the
                 * only way you could run out of anon devices at that point.
                 */
+               {
                goto no_anon;
+               }
        data = nfs_root_data();
-       if (!data)
+       if (!data) {
                goto no_server;
+               }
        sb = read_super(ROOT_DEV, NULL, fs_type, root_mountflags, data, 1);
        if (sb)
                /*
@@ -1475,7 +1483,9 @@
                 * chance anyway (no memory for vfsmnt and we _will_ need it,
                 * no matter which fs we try to mount).
                 */
+               {
                goto mount_it;
+               }
 no_server:
        put_unnamed_dev(ROOT_DEV);
 no_anon:
@@ -1497,8 +1507,9 @@
                printk(KERN_NOTICE "(Warning, this kernel has no ramdisk support)\n");
 #else
                /* rd_doload is 2 for a dual initrd/ramload setup */
-               if(rd_doload==2)
+               if(rd_doload==2) {
                        rd_load_secondary();
+                       }
                else
 #endif
                {
@@ -1507,13 +1518,21 @@
                }
        }
 #endif
+printk("VFS: trying to find root device\n");
+
+       for(root_device_index = 0; root_device_index < number_root_devs; 
+root_device_index++) {
 
-       devfs_make_root (root_device_name);
-       handle = devfs_find_handle (NULL, ROOT_DEVICE_NAME,
-                                   MAJOR (ROOT_DEV), MINOR (ROOT_DEV),
-                                   DEVFS_SPECIAL_BLK, 1);
-       if (handle)  /*  Sigh: bd*() functions only paper over the cracks  */
+printk("VFS: trying %s at index %d\n",&root_device_name[root_device_index][0], 
+root_device_index);
+               if(root_device_name[root_device_index][0] != '\0')
        {
+                       ROOT_DEV = 
+name_to_kdev_t(&root_device_name[root_device_index][0]); /* translate */
+                       }
+               devfs_make_root (&root_device_name[root_device_index][0]);
+ 
+               handle = devfs_find_handle (NULL, 
+&root_device_name[root_device_index][0], MAJOR (ROOT_DEV), MINOR (ROOT_DEV), 
+DEVFS_SPECIAL_BLK, 1);
+
+/*  Sigh: bd*() functions only paper over the cracks  */
+               if (handle)  {
            unsigned major, minor;
 
            devfs_get_maj_min (handle, &major, &minor);
@@ -1524,17 +1543,20 @@
         * Probably pure paranoia, but I'm less than happy about delving into
         * devfs crap and checking it right now. Later.
         */
-       if (!ROOT_DEV)
+               if (!ROOT_DEV) {
                panic("I have no root and I want to scream");
+                       }
 
        bdev = bdget(kdev_t_to_nr(ROOT_DEV));
-       if (!bdev)
+               if (!bdev) {
                panic(__FUNCTION__ ": unable to allocate root device");
+                       }
        bdev->bd_op = devfs_get_ops (handle);
        path_start = devfs_generate_path (handle, path + 5, sizeof (path) - 5);
        mode = FMODE_READ;
-       if (!(root_mountflags & MS_RDONLY))
+               if (!(root_mountflags & MS_RDONLY)) {
                mode |= FMODE_WRITE;
+                       }
        retval = blkdev_get(bdev, mode, 0, BDEV_FS);
        if (retval == -EROFS) {
                root_mountflags |= MS_RDONLY;
@@ -1545,11 +1567,9 @@
                 * Allow the user to distinguish between failed open
                 * and bad superblock on root device.
                 */
-               printk ("VFS: Cannot open root device \"%s\" or %s\n",
-                       root_device_name, kdevname (ROOT_DEV));
-               printk ("Please append a correct \"root=\" boot option\n");
-               panic("VFS: Unable to mount root fs on %s",
-                       kdevname(ROOT_DEV));
+                       printk ("VFS: Cannot open root device \"%s\" or %s\n", 
+&root_device_name[root_device_index][0], kdevname (ROOT_DEV));
+                       printk("VFS: Unable to mount root fs on %s\n", 
+kdevname(ROOT_DEV));
+                       continue;
        }
 
        check_disk_change(ROOT_DEV);
@@ -1560,39 +1580,45 @@
        }
 
        read_lock(&file_systems_lock);
-       for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) {
-               if (!(fs_type->fs_flags & FS_REQUIRES_DEV))
+               for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) 
+                       {
+                       if (!(fs_type->fs_flags & FS_REQUIRES_DEV)) {
                        continue;
-               if (!try_inc_mod_count(fs_type->owner))
+                               }
+                       if (!try_inc_mod_count(fs_type->owner)) {
                        continue;
+                               }
                read_unlock(&file_systems_lock);
                sb = read_super(ROOT_DEV,bdev,fs_type,root_mountflags,NULL,1);
-               if (sb) 
+                       if (sb) {
                        goto mount_it;
+                               }
                read_lock(&file_systems_lock);
                put_filesystem(fs_type);
        }
        read_unlock(&file_systems_lock);
-       panic("VFS: Unable to mount root fs on %s", kdevname(ROOT_DEV));
+               printk("VFS: Unable to mount root fs on %s\n", kdevname(ROOT_DEV));
+               }
+       printk("VFS: Please append a correct \"root=\" boot option\n");
+       panic("VFS: Unable to mount any root fs at all");
 
 mount_it:
-       printk ("VFS: Mounted root (%s filesystem)%s.\n",
-               fs_type->name,
-               (sb->s_flags & MS_RDONLY) ? " readonly" : "");
+       printk ("VFS: Mounted root (%s filesystem)%s.\n", fs_type->name, (sb->s_flags 
+& MS_RDONLY) ? " readonly" : "");
        if (path_start >= 0) {
-               devfs_mk_symlink (NULL, "root", DEVFS_FL_DEFAULT,
-                                 path + 5 + path_start, NULL, NULL);
+               devfs_mk_symlink (NULL, "root", DEVFS_FL_DEFAULT, path + 5 + 
+path_start, NULL, NULL);
                memcpy (path + path_start, "/dev/", 5);
                vfsmnt = add_vfsmnt(NULL, sb->s_root, path + path_start);
        }
-       else
+       else {
                vfsmnt = add_vfsmnt(NULL, sb->s_root, "/dev/root");
+               }
        /* FIXME: if something will try to umount us right now... */
        if (vfsmnt) {
                set_fs_root(current->fs, vfsmnt, sb->s_root);
                set_fs_pwd(current->fs, vfsmnt, sb->s_root);
-               if (bdev)
+               if (bdev) {
                        bdput(bdev); /* sb holds a reference */
+                       }
                return;
        }
        panic("VFS: add_vfsmnt failed for root fs");
@@ -1735,6 +1761,8 @@
        struct nameidata devfs_nd, nd;
        int error = 0;
 
+printk("fs/super.c:change_root() called\n");
+
        read_lock(&current->fs->lock);
        old_rootmnt = mntget(current->fs->rootmnt);
        read_unlock(&current->fs->lock);
@@ -1752,6 +1780,15 @@
                } else 
                        path_release(&devfs_nd);
        }
+/* this function seems to only be used when after an initrd usage,
+* so the actual value of ROOT_DEV hasn't been determined until mount_root
+* is called, because we try a list of root devices before giving up,
+* this ROOT_DEV global is somewhat misleading now, as its only valid after
+* a call to mount_root because mount_root ignores the ROOT_DEV value 
+* except for nfs and ram mount attempts going in, but will realise 
+* to not mount RAM again so it should be okay to leave this be. 
+*              - 11/22/00 <[EMAIL PROTECTED]>
+*/
        ROOT_DEV = new_root_dev;
        mount_root();
 #if 1
diff --recursive --unified --ignore-all-space linux/include/linux/fs.h 
linux-2.4.0.8/include/linux/fs.h
--- linux/include/linux/fs.h    Fri Sep  8 12:52:42 2000
+++ linux-2.4.0.8/include/linux/fs.h    Thu Nov 23 21:25:52 2000
@@ -1200,7 +1200,10 @@
 unsigned long generate_cluster(kdev_t, int b[], int);
 unsigned long generate_cluster_swab32(kdev_t, int b[], int);
 extern kdev_t ROOT_DEV;
-extern char root_device_name[];
+/* following added 11/22/00 by Tracy Camp <[EMAIL PROTECTED]> */
+extern char root_device_name[8][64];
+extern int number_root_devs;
+extern kdev_t name_to_kdev_t(char *);
 
 
 extern void show_buffers(void);
diff --recursive --unified --ignore-all-space linux/init/main.c 
linux-2.4.0.8/init/main.c
--- linux/init/main.c   Fri Sep  1 14:25:26 2000
+++ linux-2.4.0.8/init/main.c   Fri Nov 24 16:57:15 2000
@@ -7,6 +7,11 @@
  *  Added initrd & change_root: Werner Almesberger & Hans Lermen, Feb '96
  *  Moan early if gcc is old, avoiding bogus kernels - Paul Gortmaker, May '96
  *  Simplified starting of init:  Michael A. Griffith <[EMAIL PROTECTED]> 
+ *
+ *  11/22/00 - added support for up to 8 comma separated and multiple root= 
+ *  arguements. Modified root_dev_setup, and name_to_kdev_t, other changes in
+ *  fs/super.c and include/linux/fs.h to support processing root device list.
+ *  Tracy Camp <[EMAIL PROTECTED]>
  */
 
 #define __KERNEL_SYSCALLS__
@@ -129,7 +134,8 @@
 
 int root_mountflags = MS_RDONLY;
 char *execute_command;
-char root_device_name[64];
+char root_device_name[8][64];
+int number_root_devs = 0;
 
 
 static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };
@@ -257,13 +263,13 @@
        { NULL, 0 }
 };
 
-kdev_t __init name_to_kdev_t(char *line)
-{
+kdev_t __init name_to_kdev_t(char *line) {
        int base = 0;
+       struct dev_name_struct *dev = root_dev_names;
 
        if (strncmp(line,"/dev/",5) == 0) {
-               struct dev_name_struct *dev = root_dev_names;
                line += 5;
+               }
                do {
                        int len = strlen(dev->name);
                        if (strncmp(line,dev->name,len) == 0) {
@@ -272,25 +278,51 @@
                                break;
                        }
                        dev++;
-               } while (dev->name);
        }
+       while (dev->name);
        return to_kdev_t(base + simple_strtoul(line,NULL,base?10:16));
 }
 
-static int __init root_dev_setup(char *line)
-{
+static int __init root_dev_setup(char *line) {
        int i;
        char ch;
 
-       ROOT_DEV = name_to_kdev_t(line);
-       memset (root_device_name, 0, sizeof root_device_name);
-       if (strncmp (line, "/dev/", 5) == 0) line += 5;
-       for (i = 0; i < sizeof root_device_name - 1; ++i)
-       {
+/* number_root_devs is initially 0 and not touched except for 
+incrementing, so this function should be re-callable with the
+desired results */
+       if (strncmp (line, "/dev/", 5) == 0) {
+               line += 5;
+               }
+       memset (root_device_name, 0, sizeof root_device_name[number_root_devs]);
+       for (i = 0; i < sizeof root_device_name[number_root_devs] - 1; ++i) {
            ch = line[i];
-           if ( isspace (ch) || (ch == ',') || (ch == '\0') ) break;
-           root_device_name[i] = ch;
+           if ( ch == ',') {
+               if(number_root_devs == 0) {
+                       ROOT_DEV = 
+name_to_kdev_t(&root_device_name[number_root_devs][0]); 
+                       }
+               number_root_devs++;
+               if(number_root_devs >= 8) {
+                       break;
        }
+               i++;
+               line += i;
+               i = 0;
+               if (strncmp (line, "/dev/", 5) == 0) {
+                       line += 5;
+                       }
+               ch = line[i];
+               memset (root_device_name[number_root_devs], 0, sizeof 
+root_device_name[number_root_devs]);
+               }
+           if ( isspace (ch) || (ch == '\0') ) {
+               if(number_root_devs == 0) {
+                       ROOT_DEV = 
+name_to_kdev_t(&root_device_name[number_root_devs][0]); 
+                       }
+               number_root_devs++;
+               break;
+               }
+           root_device_name[number_root_devs][i] = ch;
+       }
+printk("root_dev_setup number_root_devs: %d\n",number_root_devs);
        return 1;
 }
 
@@ -543,10 +575,8 @@
        sti();
        calibrate_delay();
 #ifdef CONFIG_BLK_DEV_INITRD
-       if (initrd_start && !initrd_below_start_ok &&
-                       initrd_start < min_low_pfn << PAGE_SHIFT) {
-               printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "
-                   "disabling it.\n",initrd_start,min_low_pfn << PAGE_SHIFT);
+       if (initrd_start && !initrd_below_start_ok && initrd_start < min_low_pfn << 
+PAGE_SHIFT) {
+               printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - " 
+"disabling it.\n",initrd_start,min_low_pfn << PAGE_SHIFT);
                initrd_start = 0;
        }
 #endif
@@ -693,10 +723,10 @@
        sock_init();
 
 #ifdef CONFIG_BLK_DEV_INITRD
-       real_root_dev = ROOT_DEV;
+       real_root_dev = ROOT_DEV; /* as decided upon by root_dev_setup() */
        real_root_mountflags = root_mountflags;
-       if (initrd_start && mount_initrd) root_mountflags &= ~MS_RDONLY;
-       else mount_initrd =0;
+       if (initrd_start && mount_initrd) { root_mountflags &= ~MS_RDONLY; }
+       else { mount_initrd =0; }
 #endif
 
        do_initcalls();
@@ -717,23 +747,22 @@
 
 #ifdef CONFIG_BLK_DEV_INITRD
        root_mountflags = real_root_mountflags;
-       if (mount_initrd && ROOT_DEV != real_root_dev
-           && MAJOR(ROOT_DEV) == RAMDISK_MAJOR && MINOR(ROOT_DEV) == 0) {
+       if (mount_initrd && ROOT_DEV != real_root_dev && MAJOR(ROOT_DEV) == 
+RAMDISK_MAJOR && MINOR(ROOT_DEV) == 0) {
                int error;
                int i, pid;
 
                pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
-               if (pid>0)
+               if (pid>0) {
                        while (pid != wait(&i));
-               if (MAJOR(real_root_dev) != RAMDISK_MAJOR
-                    || MINOR(real_root_dev) != 0) {
+                       }
+               if (MAJOR(real_root_dev) != RAMDISK_MAJOR || MINOR(real_root_dev) != 
+0) {
 #ifdef CONFIG_BLK_DEV_MD
                        md_run_setup();
 #endif
                        error = change_root(real_root_dev,"/initrd");
-                       if (error)
-                               printk(KERN_ERR "Change root to /initrd: "
-                                   "error %d\n",error);
+                       if (error) {
+                               printk(KERN_ERR "Change root to /initrd: error 
+%d\n",error);
+                               }
                }
        }
 #endif

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
Please read the FAQ at http://www.tux.org/lkml/

Reply via email to