Changes to find the root device by its label. --- fs/Config.in | 3 + init/do_mounts.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) diff --git a/fs/Config.in b/fs/Config.in index 04d4d64..d48af3b 100644 --- a/fs/Config.in +++ b/fs/Config.in @@ -92,6 +92,9 @@ dep_mbool ' QNX4FS write support (DANGEROUS)' CONFIG_QNX4FS_RW $CONFIG_QNX4FS_F tristate 'ROM file system support' CONFIG_ROMFS_FS tristate 'Second extended fs support' CONFIG_EXT2_FS +if [ "$CONFIG_EXT2_FS" = "y" ]; then + bool 'Select root file-system by ext2 UUID or LABEL' CONFIG_ROOT_FS_ID +fi tristate 'System V/Xenix/V7/Coherent file system support' CONFIG_SYSV_FS diff --git a/init/do_mounts.c b/init/do_mounts.c index cbdee28..2f4f0b2 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -17,6 +17,10 @@ #include #include +#ifdef CONFIG_ROOT_FS_ID +#include +#endif + #define BUILD_CRAMDISK extern int get_filesystem_list(char * buf); @@ -290,6 +294,17 @@ static int __init root_dev_setup(char *line) ROOT_DEV = name_to_kdev_t(line); memset (root_device_name, 0, sizeof root_device_name); if (strncmp (line, "/dev/", 5) == 0) line += 5; +#ifdef CONFIG_ROOT_FS_ID + if (line[0] == '"') { + /* root="LABEL=foo ext2 label" */ + for (i = 0; i < sizeof root_device_name - 1; ++i) { + ch = line[i+1]; + if ((ch == '"') || (ch == '\0')) break; + root_device_name[i] = ch; + } + return 1; + } +#endif for (i = 0; i < sizeof root_device_name - 1; ++i) { ch = line[i]; @@ -301,6 +316,15 @@ static int __init root_dev_setup(char *line) __setup("root=", root_dev_setup); +#ifdef CONFIG_ROOT_FS_ID +static int __init root_label_dev_setup(char *line) +{ + return root_dev_setup(line); +} + +__setup("root-label=", root_label_dev_setup); +#endif + static char * __initdata root_mount_data; static int __init root_data_setup(char *str) { @@ -394,6 +418,101 @@ static int __init mount_nfs_root(void) } #endif +#ifdef CONFIG_ROOT_FS_ID +/** + * root_dev_check_id: check if partition has an ext2 LABEL or UUID. + * Based on code from fs/ext2/super.c + */ +static int __init root_dev_check_id(kdev_t dev, int label, const char *data) +{ + int blocksize; + unsigned long logic_sb_block = 1; + unsigned long offset = 0; + struct buffer_head *bh; + struct ext2_super_block *es; + + blocksize = get_hardsect_size(dev); + if (blocksize < BLOCK_SIZE) { + blocksize = BLOCK_SIZE; + } + else if (blocksize != BLOCK_SIZE) { + logic_sb_block = BLOCK_SIZE / blocksize; + offset = BLOCK_SIZE % blocksize; + } + + bh = bread(dev, logic_sb_block, blocksize); + if (bh == NULL) + return 0; + + es = (struct ext2_super_block *)((char *)bh->b_data + offset); + if (le16_to_cpu(es->s_magic) != EXT2_SUPER_MAGIC) + return 0; + + if (label) { + return (strcmp(es->s_volume_name, data) == 0); + } + else { + /* ex: de4ab150-0847-48ba-b1a9-e487b64ec503 */ + char uuid[40]; + int i, j; + for (i=0, j=0; i<16; i++, j+=2) { + if ((j==8) || (j==13) || (j==18) || (j==23)) + uuid[j++] = '-'; + sprintf(uuid + j, "%2.2x", (unsigned char)(es->s_uuid[i])); + } + return (strcmp(uuid, data) == 0); + } + + return 0; +} + +static void __init root_dev_resolve_id(void) +{ + struct gendisk *gp; + kdev_t dev; + int n; + char *data; + int label = 0; + + if (MAJOR(ROOT_DEV) != UNNAMED_MAJOR) + return; + + if (strncmp(root_device_name, "LABEL=", 6) == 0) { + label = 1; + data = root_device_name + 6; + } + else if (strncmp(root_device_name, "UUID=", 5) == 0) { + label = 0; + data = root_device_name + 5; + } + else { + return; + } + + for (gp=gendisk_head; gp; gp = gp->next) { + for (n = 0; n < (gp->nr_real << gp->minor_shift); n++) { + /* skip too small partitions */ + if (gp->part[n].nr_sects < 8) + continue; + dev = MKDEV(gp->major, n); + if (root_dev_check_id(dev, label, data)) { + ROOT_DEV = dev; + break; + } + } + } + + if (MAJOR(ROOT_DEV) != UNNAMED_MAJOR) { + printk("VFS: Resolving %s to %s\n", root_device_name, + kdevname(ROOT_DEV)); + sprintf(root_device_name, "%x", kdev_t_to_nr(ROOT_DEV)); + } + else { + printk("VFS: Can't resolve %s\n", root_device_name); + } +} +#endif + static int __init create_dev(char *name, kdev_t dev, char *devfs_name) { void *handle; @@ -772,6 +891,9 @@ static void __init mount_root(void) ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0); } #endif +#ifdef CONFIG_ROOT_FS_ID + root_dev_resolve_id(); +#endif devfs_make_root(root_device_name); create_dev("/dev/root", ROOT_DEV, root_device_name); #ifdef CONFIG_BLK_DEV_FD