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: Will Drewry <wad@chromium.org>
Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
This commit is contained in:
Will Drewry 2010-08-31 15:47:07 -05:00 committed by Jens Axboe
parent eec7ecfede
commit b5af921ec0
2 changed files with 73 additions and 2 deletions

View file

@ -642,6 +642,7 @@ void __init printk_all_partitions(void)
struct hd_struct *part;
char name_buf[BDEVNAME_SIZE];
char devt_buf[BDEVT_SIZE];
u8 uuid[PARTITION_META_INFO_UUIDLTH * 2 + 1];
/*
* Don't show empty devices or things that have been
@ -660,10 +661,14 @@ void __init printk_all_partitions(void)
while ((part = disk_part_iter_next(&piter))) {
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),
(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 (disk->driverfs_dev != NULL &&
disk->driverfs_dev->driver != NULL)

View file

@ -58,6 +58,60 @@ static int __init readwrite(char *str)
__setup("ro", readonly);
__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:
*
@ -68,6 +122,8 @@ __setup("rw", readwrite);
* of partition - device number of disk plus the partition number
* 5) /dev/<disk_name>p<decimal> - same as the above, that form is
* 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).
* 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)
dev_t res = 0;
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) {
unsigned maj, min;