From 1ad7e89940d5ac411928189e1a4a01901dbf590f Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Thu, 8 Nov 2012 16:12:25 -0800 Subject: block: store partition_meta_info.uuid as a string This will allow other types of UUID to be stored here, aside from true UUIDs. This also simplifies code that uses this field, since it's usually constructed from a, used as a, or compared to other, strings. Note: A simplistic approach here would be to set uuid_str[36]=0 whenever a /PARTNROFF option was found to be present. However, this modifies the input string, and causes subsequent calls to devt_from_partuuid() not to see the /PARTNROFF option, which causes different results. In order to avoid misleading future maintainers, this parameter is marked const. Signed-off-by: Stephen Warren Cc: Tejun Heo Cc: Will Drewry Cc: Kay Sievers Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe --- init/do_mounts.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'init') diff --git a/init/do_mounts.c b/init/do_mounts.c index f8a66424360d..b28ec5819325 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -69,23 +69,28 @@ __setup("ro", readonly); __setup("rw", readwrite); #ifdef CONFIG_BLOCK +struct uuidcmp { + const char *uuid; + int len; +}; + /** * match_dev_by_uuid - callback for finding a partition using its uuid * @dev: device passed in by the caller - * @data: opaque pointer to a 36 byte char array with a UUID + * @data: opaque pointer to the desired struct uuidcmp to match * * Returns 1 if the device matches, and 0 otherwise. */ static int match_dev_by_uuid(struct device *dev, void *data) { - u8 *uuid = data; + struct uuidcmp *cmp = data; struct hd_struct *part = dev_to_part(dev); if (!part->info) goto no_match; - if (memcmp(uuid, part->info->uuid, sizeof(part->info->uuid))) - goto no_match; + if (strncasecmp(cmp->uuid, part->info->uuid, cmp->len)) + goto no_match; return 1; no_match: @@ -95,7 +100,7 @@ no_match: /** * devt_from_partuuid - looks up the dev_t of a partition by its UUID - * @uuid: min 36 byte char array containing a hex ascii UUID + * @uuid: char array containing ascii UUID * * The function will return the first partition which contains a matching * UUID value in its partition_meta_info struct. This does not search @@ -106,11 +111,11 @@ no_match: * * Returns the matching dev_t on success or 0 on failure. */ -static dev_t devt_from_partuuid(char *uuid_str) +static dev_t devt_from_partuuid(const char *uuid_str) { dev_t res = 0; + struct uuidcmp cmp; struct device *dev = NULL; - u8 uuid[16]; struct gendisk *disk; struct hd_struct *part; int offset = 0; @@ -118,6 +123,9 @@ static dev_t devt_from_partuuid(char *uuid_str) if (strlen(uuid_str) < 36) goto done; + cmp.uuid = uuid_str; + cmp.len = 36; + /* Check for optional partition number offset attributes. */ if (uuid_str[36]) { char c = 0; @@ -134,10 +142,8 @@ static dev_t devt_from_partuuid(char *uuid_str) } } - /* Pack the requested UUID in the expected format. */ - part_pack_uuid(uuid_str, uuid); - - dev = class_find_device(&block_class, NULL, uuid, &match_dev_by_uuid); + dev = class_find_device(&block_class, NULL, &cmp, + &match_dev_by_uuid); if (!dev) goto done; -- cgit v1.2.3-59-g8ed1b From 283f8fc03927b0ef42a2faa60a0df5ec8c612edb Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Thu, 8 Nov 2012 16:12:27 -0800 Subject: init: reduce PARTUUID min length to 1 from 36 Reduce the minimum length for a root=PARTUUID= parameter to be considered valid from 36 to 1. EFI/GPT partition UUIDs are always exactly 36 characters long, hence the previous limit. However, the next patch will support DOS/MBR UUIDs too, which have a different, shorter, format. Instead of validating any particular length, just ensure that at least some non-empty value was given by the user. Also, consider a missing UUID value to be a parsing error, in the same vein as if /PARTNROFF exists and can't be parsed. As such, make both error cases print a message and disable rootwait. Convert to pr_err while we're at it. Signed-off-by: Stephen Warren Cc: Tejun Heo Cc: Will Drewry Cc: Kay Sievers Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe --- init/do_mounts.c | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) (limited to 'init') diff --git a/init/do_mounts.c b/init/do_mounts.c index b28ec5819325..c950d7c93f98 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -119,27 +119,29 @@ static dev_t devt_from_partuuid(const char *uuid_str) struct gendisk *disk; struct hd_struct *part; int offset = 0; - - if (strlen(uuid_str) < 36) - goto done; + bool clear_root_wait = false; + char *slash; cmp.uuid = uuid_str; - cmp.len = 36; + slash = strchr(uuid_str, '/'); /* Check for optional partition number offset attributes. */ - if (uuid_str[36]) { + if (slash) { char c = 0; /* Explicitly fail on poor PARTUUID syntax. */ - if (sscanf(&uuid_str[36], - "/PARTNROFF=%d%c", &offset, &c) != 1) { - printk(KERN_ERR "VFS: PARTUUID= is invalid.\n" - "Expected PARTUUID=[/PARTNROFF=%%d]\n"); - if (root_wait) - printk(KERN_ERR - "Disabling rootwait; root= is invalid.\n"); - root_wait = 0; + if (sscanf(slash + 1, + "PARTNROFF=%d%c", &offset, &c) != 1) { + clear_root_wait = true; goto done; } + cmp.len = slash - uuid_str; + } else { + cmp.len = strlen(uuid_str); + } + + if (!cmp.len) { + clear_root_wait = true; + goto done; } dev = class_find_device(&block_class, NULL, &cmp, @@ -164,6 +166,13 @@ static dev_t devt_from_partuuid(const char *uuid_str) no_offset: put_device(dev); done: + if (clear_root_wait) { + pr_err("VFS: PARTUUID= is invalid.\n" + "Expected PARTUUID=[/PARTNROFF=%%d]\n"); + if (root_wait) + pr_err("Disabling rootwait; root= is invalid.\n"); + root_wait = 0; + } return res; } #endif -- cgit v1.2.3-59-g8ed1b From d33b98fc82b0908e91fb05ae081acaed7323f9d2 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Thu, 8 Nov 2012 16:12:28 -0800 Subject: block: partition: msdos: provide UUIDs for partitions The MSDOS/MBR partition table includes a 32-bit unique ID, often referred to as the NT disk signature. When combined with a partition number within the table, this can form a unique ID similar in concept to EFI/GPT's partition UUID. Constructing and recording this value in struct partition_meta_info allows MSDOS partitions to be referred to on the kernel command-line using the following syntax: root=PARTUUID=0002dd75-01 Signed-off-by: Stephen Warren Cc: Tejun Heo Cc: Will Drewry Cc: Kay Sievers Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe --- block/partitions/msdos.c | 21 +++++++++++++++++++-- init/do_mounts.c | 4 ++++ 2 files changed, 23 insertions(+), 2 deletions(-) (limited to 'init') diff --git a/block/partitions/msdos.c b/block/partitions/msdos.c index 5f79a6677c69..8752a5d26565 100644 --- a/block/partitions/msdos.c +++ b/block/partitions/msdos.c @@ -94,6 +94,17 @@ static int aix_magic_present(struct parsed_partitions *state, unsigned char *p) return ret; } +static void set_info(struct parsed_partitions *state, int slot, + u32 disksig) +{ + struct partition_meta_info *info = &state->parts[slot].info; + + snprintf(info->uuid, sizeof(info->uuid), "%08x-%02x", disksig, + slot); + info->volname[0] = 0; + state->parts[slot].has_info = true; +} + /* * Create devices for each logical partition in an extended partition. * The logical partitions form a linked list, with each entry being @@ -106,7 +117,8 @@ static int aix_magic_present(struct parsed_partitions *state, unsigned char *p) */ static void parse_extended(struct parsed_partitions *state, - sector_t first_sector, sector_t first_size) + sector_t first_sector, sector_t first_size, + u32 disksig) { struct partition *p; Sector sect; @@ -166,6 +178,7 @@ static void parse_extended(struct parsed_partitions *state, } put_partition(state, state->next, next, size); + set_info(state, state->next, disksig); if (SYS_IND(p) == LINUX_RAID_PARTITION) state->parts[state->next].flags = ADDPART_FLAG_RAID; loopct = 0; @@ -437,6 +450,7 @@ int msdos_partition(struct parsed_partitions *state) struct partition *p; struct fat_boot_sector *fb; int slot; + u32 disksig; data = read_part_sector(state, 0, §); if (!data) @@ -491,6 +505,8 @@ int msdos_partition(struct parsed_partitions *state) #endif p = (struct partition *) (data + 0x1be); + disksig = le32_to_cpup((__le32 *)(data + 0x1b8)); + /* * Look for partitions in two passes: * First find the primary and DOS-type extended partitions. @@ -515,11 +531,12 @@ int msdos_partition(struct parsed_partitions *state) put_partition(state, slot, start, n); strlcat(state->pp_buf, " <", PAGE_SIZE); - parse_extended(state, start, size); + parse_extended(state, start, size, disksig); strlcat(state->pp_buf, " >", PAGE_SIZE); continue; } put_partition(state, slot, start, size); + set_info(state, slot, disksig); if (SYS_IND(p) == LINUX_RAID_PARTITION) state->parts[slot].flags = ADDPART_FLAG_RAID; if (SYS_IND(p) == DM6_PARTITION) diff --git a/init/do_mounts.c b/init/do_mounts.c index c950d7c93f98..1d1b6348f903 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -189,6 +189,10 @@ done: * used when disk name of partitioned disk ends on a digit. * 6) PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF representing the * unique id of a partition if the partition table provides it. + * The UUID may be either an EFI/GPT UUID, or refer to an MSDOS + * partition using the format SSSSSSSS-PP, where SSSSSSSS is a zero- + * filled hex representation of the 32-bit "NT disk signature", and PP + * is a zero-filled hex representation of the 1-based partition number. * 7) PARTUUID=/PARTNROFF= to select a partition in relation to * a partition with a known unique id. * -- cgit v1.2.3-59-g8ed1b