aboutsummaryrefslogtreecommitdiffstats
path: root/init
diff options
context:
space:
mode:
authorWill Drewry <wad@chromium.org>2011-11-02 16:38:59 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-11-02 19:07:01 -0400
commit79975f1327850ef198ada994c2fc44b7d1ea8935 (patch)
treecff91dd5d697858a2cc84da392aa87e61a0bf3d2 /init
parentf567a18590742b811287b7512fb0908deac4eef7 (diff)
init: add root=PARTUUID=UUID/PARTNROFF=%d support
Expand root=PARTUUID=UUID syntax to support selecting a root partition by integer offset from a known, unique partition. This approach provides similar properties to specifying a device and partition number, but using the UUID as the unique path prior to evaluating the offset. For example, root=PARTUUID=99DE9194-FC15-4223-9192-FC243948F88B/PARTNROFF=1 selects the partition with UUID 99DE.. then select the next partition. This change is motivated by a particular usecase in Chromium OS where the bootloader can easily determine what partition it is on (by UUID) but doesn't perform general partition table walking. That said, support for this model provides a direct mechanism for the user to modify the root partition to boot without specifically needing to extract each UUID or update the bootloader explicitly when the root partition UUID is changed (if it is recreated to be larger, for instance). Pinning to a /boot-style partition UUID allows the arbitrary root partition reconfiguration/modifications with slightly less ambiguity than just [dev][partition] and less stringency than the specific root partition UUID. [sfr@canb.auug.org.au: fix init sections warning] Signed-off-by: Will Drewry <wad@chromium.org> Cc: Kay Sievers <kay.sievers@vrfy.org> Cc: Randy Dunlap <rdunlap@xenotime.net> Cc: Namhyung Kim <namhyung@gmail.com> Cc: Trond Myklebust <Trond.Myklebust@netapp.com> Cc: Jens Axboe <axboe@kernel.dk> Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'init')
-rw-r--r--init/do_mounts.c48
1 files changed, 43 insertions, 5 deletions
diff --git a/init/do_mounts.c b/init/do_mounts.c
index c0851a8e030c..0f6e1d985a3b 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -28,7 +28,7 @@ int __initdata rd_doload; /* 1 = load RAM disk, 0 = don't load */
28int root_mountflags = MS_RDONLY | MS_SILENT; 28int root_mountflags = MS_RDONLY | MS_SILENT;
29static char * __initdata root_device_name; 29static char * __initdata root_device_name;
30static char __initdata saved_root_name[64]; 30static char __initdata saved_root_name[64];
31static int __initdata root_wait; 31static int root_wait;
32 32
33dev_t ROOT_DEV; 33dev_t ROOT_DEV;
34 34
@@ -85,12 +85,15 @@ no_match:
85 85
86/** 86/**
87 * devt_from_partuuid - looks up the dev_t of a partition by its UUID 87 * devt_from_partuuid - looks up the dev_t of a partition by its UUID
88 * @uuid: 36 byte char array containing a hex ascii UUID 88 * @uuid: min 36 byte char array containing a hex ascii UUID
89 * 89 *
90 * The function will return the first partition which contains a matching 90 * The function will return the first partition which contains a matching
91 * UUID value in its partition_meta_info struct. This does not search 91 * UUID value in its partition_meta_info struct. This does not search
92 * by filesystem UUIDs. 92 * by filesystem UUIDs.
93 * 93 *
94 * If @uuid is followed by a "/PARTNROFF=%d", then the number will be
95 * extracted and used as an offset from the partition identified by the UUID.
96 *
94 * Returns the matching dev_t on success or 0 on failure. 97 * Returns the matching dev_t on success or 0 on failure.
95 */ 98 */
96static dev_t devt_from_partuuid(char *uuid_str) 99static dev_t devt_from_partuuid(char *uuid_str)
@@ -98,6 +101,28 @@ static dev_t devt_from_partuuid(char *uuid_str)
98 dev_t res = 0; 101 dev_t res = 0;
99 struct device *dev = NULL; 102 struct device *dev = NULL;
100 u8 uuid[16]; 103 u8 uuid[16];
104 struct gendisk *disk;
105 struct hd_struct *part;
106 int offset = 0;
107
108 if (strlen(uuid_str) < 36)
109 goto done;
110
111 /* Check for optional partition number offset attributes. */
112 if (uuid_str[36]) {
113 char c = 0;
114 /* Explicitly fail on poor PARTUUID syntax. */
115 if (sscanf(&uuid_str[36],
116 "/PARTNROFF=%d%c", &offset, &c) != 1) {
117 printk(KERN_ERR "VFS: PARTUUID= is invalid.\n"
118 "Expected PARTUUID=<valid-uuid-id>[/PARTNROFF=%%d]\n");
119 if (root_wait)
120 printk(KERN_ERR
121 "Disabling rootwait; root= is invalid.\n");
122 root_wait = 0;
123 goto done;
124 }
125 }
101 126
102 /* Pack the requested UUID in the expected format. */ 127 /* Pack the requested UUID in the expected format. */
103 part_pack_uuid(uuid_str, uuid); 128 part_pack_uuid(uuid_str, uuid);
@@ -107,8 +132,21 @@ static dev_t devt_from_partuuid(char *uuid_str)
107 goto done; 132 goto done;
108 133
109 res = dev->devt; 134 res = dev->devt;
110 put_device(dev);
111 135
136 /* Attempt to find the partition by offset. */
137 if (!offset)
138 goto no_offset;
139
140 res = 0;
141 disk = part_to_disk(dev_to_part(dev));
142 part = disk_get_part(disk, dev_to_part(dev)->partno + offset);
143 if (part) {
144 res = part_devt(part);
145 put_device(part_to_dev(part));
146 }
147
148no_offset:
149 put_device(dev);
112done: 150done:
113 return res; 151 return res;
114} 152}
@@ -126,6 +164,8 @@ done:
126 * used when disk name of partitioned disk ends on a digit. 164 * used when disk name of partitioned disk ends on a digit.
127 * 6) PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF representing the 165 * 6) PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF representing the
128 * unique id of a partition if the partition table provides it. 166 * unique id of a partition if the partition table provides it.
167 * 7) PARTUUID=<UUID>/PARTNROFF=<int> to select a partition in relation to
168 * a partition with a known unique id.
129 * 169 *
130 * If name doesn't have fall into the categories above, we return (0,0). 170 * If name doesn't have fall into the categories above, we return (0,0).
131 * block_class is used to check if something is a disk name. If the disk 171 * block_class is used to check if something is a disk name. If the disk
@@ -143,8 +183,6 @@ dev_t name_to_dev_t(char *name)
143#ifdef CONFIG_BLOCK 183#ifdef CONFIG_BLOCK
144 if (strncmp(name, "PARTUUID=", 9) == 0) { 184 if (strncmp(name, "PARTUUID=", 9) == 0) {
145 name += 9; 185 name += 9;
146 if (strlen(name) != 36)
147 goto fail;
148 res = devt_from_partuuid(name); 186 res = devt_from_partuuid(name);
149 if (!res) 187 if (!res)
150 goto fail; 188 goto fail;