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 <linux/romfs_fs.h>
 #include <linux/cramfs_fs.h>
 
+#ifdef CONFIG_ROOT_FS_ID
+#include <linux/genhd.h>
+#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

