summaryrefslogtreecommitdiff
path: root/target/linux/patches/2.6.36/uuid.patch
blob: 2e6c61df9677d0b9f157579d2429e53358fa2db2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# DP: Add support for specifying the root device using UUIDs on the
# DP: kernel command line like this without the need for an initrd:
# DP: linux ... root=UUID=ce40d6b2-18eb-4a75-aefe-7ddb0995ce63
# DP:
# DP: Written © 2010 by Thorsten Glaser <tg@debian.org>
# DP: Idea from 1999 by David Balazic <david.balazic@uni-mb.si>

--- linux-2.6.36/block/genhd.c~	Wed Oct 20 22:30:22 2010
+++ linux-2.6.36/block/genhd.c	Sat Nov 20 23:14:03 2010
@@ -35,7 +35,7 @@ struct kobject *block_depr;
 static DEFINE_MUTEX(ext_devt_mutex);
 static DEFINE_IDR(ext_devt_idr);
 
-static struct device_type disk_type;
+struct device_type disk_type;
 
 /**
  * disk_get_part - get partition
@@ -1019,7 +1019,7 @@ static char *block_devnode(struct device *dev, mode_t 
 	return NULL;
 }
 
-static struct device_type disk_type = {
+struct device_type disk_type = {
 	.name		= "disk",
 	.groups		= disk_attr_groups,
 	.release	= disk_release,
--- linux-2.6.36/init/do_mounts.c~	Wed Oct 20 22:30:22 2010
+++ linux-2.6.36/init/do_mounts.c	Sat Nov 20 23:16:07 2010
@@ -32,6 +32,84 @@ static int __initdata root_wait;
 
 dev_t ROOT_DEV;
 
+#ifdef CONFIG_EXT2_FS
+/* support for root=UUID=ce40d6b2-18eb-4a75-aefe-7ddb0995ce63 bootargs */
+
+#include <linux/buffer_head.h>
+#include <linux/ext2_fs.h>
+
+__u8 root_dev_label[16];
+int root_dev_type;	/* 0 = normal (/dev/hda1, 0301); 1 = UUID; 3 = bad */
+
+/* imported from block/genhd.c after removing its static qualifier */
+extern struct device_type disk_type;
+
+static __u8 __init fromhex(char c)
+{
+	if (c >= '0' && c <= '9')
+		return (c - '0');
+	c &= ~32;
+	if (c >= 'A' && c <= 'F')
+		return (c - 'A' + 10);
+	return (0xFF);
+}
+
+static void __init parse_uuid(const char *s)
+{
+	int i;
+	__u8 j, k;
+
+	if (strlen(s) != 36 || s[8] != '-' || s[13] != '-' ||
+	    s[18] != '-' || s[23] != '-')
+		goto bad_uuid;
+	for (i = 0; i < 16; i++) {
+		if (*s == '-')
+			++s;
+		j = fromhex(*s++);
+		k = fromhex(*s++);
+		if (j == 0xFF || k == 0xFF)
+			goto bad_uuid;
+		root_dev_label[i] = (j << 4) | k;
+	}
+	return;
+ bad_uuid:
+	/* we cannot panic here, defer */
+	root_dev_type = 3;
+}
+
+static int __init check_dev(dev_t devt, int blocksize)
+{
+	/* most of this taken from fs/ext2/super.c */
+
+	struct buffer_head * bh;
+	struct ext2_super_block * es;
+	struct block_device *bdev;
+	unsigned long sb_block = 1;
+	unsigned long logic_sb_block;
+	unsigned long offset = 0;
+	int rv = 0;
+
+	bdev = bdget(devt);
+
+	if (blocksize != BLOCK_SIZE) {
+		logic_sb_block = (sb_block*BLOCK_SIZE) / blocksize;
+		offset = (sb_block*BLOCK_SIZE) % blocksize;
+	} else {
+		logic_sb_block = sb_block;
+	}
+
+	if (!(bh = __bread(bdev, logic_sb_block, blocksize)))
+		return (0);
+	es = (struct ext2_super_block *)(((char *)bh->b_data) + offset);
+	if (le16_to_cpu(es->s_magic) == EXT2_SUPER_MAGIC) {
+		if (!memcmp(es->s_uuid, root_dev_label, 16))
+			rv = 1;
+	}
+	brelse(bh);
+	return (rv);
+}
+#endif /* CONFIG_EXT2_FS for UUID support */
+
 static int __init load_ramdisk(char *str)
 {
 	rd_doload = simple_strtol(str,NULL,0) & 3;
@@ -148,6 +226,13 @@ done:
 static int __init root_dev_setup(char *line)
 {
 	strlcpy(saved_root_name, line, sizeof(saved_root_name));
+#ifdef CONFIG_EXT2_FS
+	root_dev_type = 0;
+	if (!strncmp(line, "UUID=", 5)) {
+		root_dev_type = 1;
+		parse_uuid(line + 5);
+	}
+#endif /* CONFIG_EXT2_FS for UUID support */
 	return 1;
 }
 
@@ -333,6 +418,45 @@ void __init change_floppy(char *fmt, ...)
 
 void __init mount_root(void)
 {
+#ifdef CONFIG_EXT2_FS
+	/* UUID support */
+	if (root_dev_type == 1) {
+		int blocksize;
+
+		/* from block/genhd.c printk_all_partitions */
+		struct class_dev_iter iter;
+		struct device *dev;
+
+		class_dev_iter_init(&iter, &block_class, NULL, &disk_type);
+		while (root_dev_type && (dev = class_dev_iter_next(&iter))) {
+			struct gendisk *disk = dev_to_disk(dev);
+			struct disk_part_iter piter;
+			struct hd_struct *part;
+			if (get_capacity(disk) == 0 ||
+			    (disk->flags & GENHD_FL_SUPPRESS_PARTITION_INFO))
+				continue;
+			blocksize = queue_logical_block_size(disk->queue);
+
+			disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0);
+			while (root_dev_type && (part = disk_part_iter_next(&piter))) {
+				/* avoid empty or too small partitions */
+				if (part->nr_sects < 8)
+					continue;
+				if (check_dev(part_devt(part), blocksize)) {
+					ROOT_DEV = part_devt(part);
+					root_dev_type = 0;
+				}
+			}
+			disk_part_iter_exit(&piter);
+		}
+		class_dev_iter_exit(&iter);
+	}
+	if (root_dev_type == 1)
+		printk(KERN_ERR "VFS: Unable to find root by UUID %s.\n", saved_root_name + 5);
+	else if (root_dev_type == 3)
+		panic("Badly formatted UUID %s was supplied as kernel parameter root", saved_root_name + 5);
+#endif /* CONFIG_EXT2_FS for UUID support */
+
 #ifdef CONFIG_ROOT_NFS
 	if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) {
 		if (mount_nfs_root())