Commit b5af921e authored by Will Drewry's avatar Will Drewry Committed by Jens Axboe

init: add support for root devices specified by partition UUID

This is the third patch in a series which adds support for
storing partition metadata, optionally, off of the hd_struct.

One major use for that data is being able to resolve partition
by other identities than just the index on a block device.  Device
enumeration varies by platform and there's a benefit to being able
to use something like EFI GPT's GUIDs to determine the correct
block device and partition to mount as the root.

This change adds that support to root= by adding support for
the following syntax:

  root=PARTUUID=hex-uuid
Signed-off-by: default avatarWill Drewry <wad@chromium.org>
Signed-off-by: default avatarJens Axboe <jaxboe@fusionio.com>
parent eec7ecfe
...@@ -642,6 +642,7 @@ void __init printk_all_partitions(void) ...@@ -642,6 +642,7 @@ void __init printk_all_partitions(void)
struct hd_struct *part; struct hd_struct *part;
char name_buf[BDEVNAME_SIZE]; char name_buf[BDEVNAME_SIZE];
char devt_buf[BDEVT_SIZE]; char devt_buf[BDEVT_SIZE];
u8 uuid[PARTITION_META_INFO_UUIDLTH * 2 + 1];
/* /*
* Don't show empty devices or things that have been * Don't show empty devices or things that have been
...@@ -660,10 +661,14 @@ void __init printk_all_partitions(void) ...@@ -660,10 +661,14 @@ void __init printk_all_partitions(void)
while ((part = disk_part_iter_next(&piter))) { while ((part = disk_part_iter_next(&piter))) {
bool is_part0 = part == &disk->part0; bool is_part0 = part == &disk->part0;
printk("%s%s %10llu %s", is_part0 ? "" : " ", uuid[0] = 0;
if (part->info)
part_unpack_uuid(part->info->uuid, uuid);
printk("%s%s %10llu %s %s", is_part0 ? "" : " ",
bdevt_str(part_devt(part), devt_buf), bdevt_str(part_devt(part), devt_buf),
(unsigned long long)part->nr_sects >> 1, (unsigned long long)part->nr_sects >> 1,
disk_name(disk, part->partno, name_buf)); disk_name(disk, part->partno, name_buf), uuid);
if (is_part0) { if (is_part0) {
if (disk->driverfs_dev != NULL && if (disk->driverfs_dev != NULL &&
disk->driverfs_dev->driver != NULL) disk->driverfs_dev->driver != NULL)
......
...@@ -58,6 +58,60 @@ static int __init readwrite(char *str) ...@@ -58,6 +58,60 @@ static int __init readwrite(char *str)
__setup("ro", readonly); __setup("ro", readonly);
__setup("rw", readwrite); __setup("rw", readwrite);
/**
* 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
*
* Returns 1 if the device matches, and 0 otherwise.
*/
static int __init match_dev_by_uuid(struct device *dev, void *data)
{
u8 *uuid = 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;
return 1;
no_match:
return 0;
}
/**
* devt_from_partuuid - looks up the dev_t of a partition by its UUID
* @uuid: 36 byte char array containing a hex 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
* by filesystem UUIDs.
*
* Returns the matching dev_t on success or 0 on failure.
*/
static dev_t __init devt_from_partuuid(char *uuid_str)
{
dev_t res = 0;
struct device *dev = NULL;
u8 uuid[16];
/* 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);
if (!dev)
goto done;
res = dev->devt;
put_device(dev);
done:
return res;
}
/* /*
* Convert a name into device number. We accept the following variants: * Convert a name into device number. We accept the following variants:
* *
...@@ -68,6 +122,8 @@ __setup("rw", readwrite); ...@@ -68,6 +122,8 @@ __setup("rw", readwrite);
* of partition - device number of disk plus the partition number * of partition - device number of disk plus the partition number
* 5) /dev/<disk_name>p<decimal> - same as the above, that form is * 5) /dev/<disk_name>p<decimal> - same as the above, that form is
* used when disk name of partitioned disk ends on a digit. * 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.
* *
* If name doesn't have fall into the categories above, we return (0,0). * If name doesn't have fall into the categories above, we return (0,0).
* block_class is used to check if something is a disk name. If the disk * block_class is used to check if something is a disk name. If the disk
...@@ -82,6 +138,16 @@ dev_t name_to_dev_t(char *name) ...@@ -82,6 +138,16 @@ dev_t name_to_dev_t(char *name)
dev_t res = 0; dev_t res = 0;
int part; int part;
if (strncmp(name, "PARTUUID=", 9) == 0) {
name += 9;
if (strlen(name) != 36)
goto fail;
res = devt_from_partuuid(name);
if (!res)
goto fail;
goto done;
}
if (strncmp(name, "/dev/", 5) != 0) { if (strncmp(name, "/dev/", 5) != 0) {
unsigned maj, min; unsigned maj, min;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment