aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWill Drewry <wad@chromium.org>2010-08-31 16:47:07 -0400
committerJens Axboe <jaxboe@fusionio.com>2010-09-15 10:14:03 -0400
commitb5af921ec02333e943efb59aca4f56b78fc0e100 (patch)
treefcf966ccbee9c5f8b8f652100f033bc781b91b91
parenteec7ecfede74bb996060efefd5c157acd5794e8a (diff)
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>
-rw-r--r--block/genhd.c9
-rw-r--r--init/do_mounts.c66
2 files changed, 73 insertions, 2 deletions
diff --git a/block/genhd.c b/block/genhd.c
index c8da12055264..5c9c503de423 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -642,6 +642,7 @@ void __init printk_all_partitions(void)
642 struct hd_struct *part; 642 struct hd_struct *part;
643 char name_buf[BDEVNAME_SIZE]; 643 char name_buf[BDEVNAME_SIZE];
644 char devt_buf[BDEVT_SIZE]; 644 char devt_buf[BDEVT_SIZE];
645 u8 uuid[PARTITION_META_INFO_UUIDLTH * 2 + 1];
645 646
646 /* 647 /*
647 * Don't show empty devices or things that have been 648 * Don't show empty devices or things that have been
@@ -660,10 +661,14 @@ void __init printk_all_partitions(void)
660 while ((part = disk_part_iter_next(&piter))) { 661 while ((part = disk_part_iter_next(&piter))) {
661 bool is_part0 = part == &disk->part0; 662 bool is_part0 = part == &disk->part0;
662 663
663 printk("%s%s %10llu %s", is_part0 ? "" : " ", 664 uuid[0] = 0;
665 if (part->info)
666 part_unpack_uuid(part->info->uuid, uuid);
667
668 printk("%s%s %10llu %s %s", is_part0 ? "" : " ",
664 bdevt_str(part_devt(part), devt_buf), 669 bdevt_str(part_devt(part), devt_buf),
665 (unsigned long long)part->nr_sects >> 1, 670 (unsigned long long)part->nr_sects >> 1,
666 disk_name(disk, part->partno, name_buf)); 671 disk_name(disk, part->partno, name_buf), uuid);
667 if (is_part0) { 672 if (is_part0) {
668 if (disk->driverfs_dev != NULL && 673 if (disk->driverfs_dev != NULL &&
669 disk->driverfs_dev->driver != NULL) 674 disk->driverfs_dev->driver != NULL)
diff --git a/init/do_mounts.c b/init/do_mounts.c
index 02e3ca4fc527..804f9c6ba216 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -58,6 +58,60 @@ static int __init readwrite(char *str)
58__setup("ro", readonly); 58__setup("ro", readonly);
59__setup("rw", readwrite); 59__setup("rw", readwrite);
60 60
61/**
62 * match_dev_by_uuid - callback for finding a partition using its uuid
63 * @dev: device passed in by the caller
64 * @data: opaque pointer to a 36 byte char array with a UUID
65 *
66 * Returns 1 if the device matches, and 0 otherwise.
67 */
68static int __init match_dev_by_uuid(struct device *dev, void *data)
69{
70 u8 *uuid = data;
71 struct hd_struct *part = dev_to_part(dev);
72
73 if (!part->info)
74 goto no_match;
75
76 if (memcmp(uuid, part->info->uuid, sizeof(part->info->uuid)))
77 goto no_match;
78
79 return 1;
80no_match:
81 return 0;
82}
83
84
85/**
86 * devt_from_partuuid - looks up the dev_t of a partition by its UUID
87 * @uuid: 36 byte char array containing a hex ascii UUID
88 *
89 * The function will return the first partition which contains a matching
90 * UUID value in its partition_meta_info struct. This does not search
91 * by filesystem UUIDs.
92 *
93 * Returns the matching dev_t on success or 0 on failure.
94 */
95static dev_t __init devt_from_partuuid(char *uuid_str)
96{
97 dev_t res = 0;
98 struct device *dev = NULL;
99 u8 uuid[16];
100
101 /* Pack the requested UUID in the expected format. */
102 part_pack_uuid(uuid_str, uuid);
103
104 dev = class_find_device(&block_class, NULL, uuid, &match_dev_by_uuid);
105 if (!dev)
106 goto done;
107
108 res = dev->devt;
109 put_device(dev);
110
111done:
112 return res;
113}
114
61/* 115/*
62 * Convert a name into device number. We accept the following variants: 116 * Convert a name into device number. We accept the following variants:
63 * 117 *
@@ -68,6 +122,8 @@ __setup("rw", readwrite);
68 * of partition - device number of disk plus the partition number 122 * of partition - device number of disk plus the partition number
69 * 5) /dev/<disk_name>p<decimal> - same as the above, that form is 123 * 5) /dev/<disk_name>p<decimal> - same as the above, that form is
70 * used when disk name of partitioned disk ends on a digit. 124 * used when disk name of partitioned disk ends on a digit.
125 * 6) PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF representing the
126 * unique id of a partition if the partition table provides it.
71 * 127 *
72 * If name doesn't have fall into the categories above, we return (0,0). 128 * If name doesn't have fall into the categories above, we return (0,0).
73 * block_class is used to check if something is a disk name. If the disk 129 * 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 dev_t res = 0; 138 dev_t res = 0;
83 int part; 139 int part;
84 140
141 if (strncmp(name, "PARTUUID=", 9) == 0) {
142 name += 9;
143 if (strlen(name) != 36)
144 goto fail;
145 res = devt_from_partuuid(name);
146 if (!res)
147 goto fail;
148 goto done;
149 }
150
85 if (strncmp(name, "/dev/", 5) != 0) { 151 if (strncmp(name, "/dev/", 5) != 0) {
86 unsigned maj, min; 152 unsigned maj, min;
87 153