[OE-core] [PATCH v3] boot-directdisk: mount root by MBR disk signature for Linux 3.8+

Jonathan Liu net147 at gmail.com
Tue Jul 9 23:22:41 UTC 2013


On 10/07/2013 7:48 AM, Darren Hart wrote:
> On Wed, 2013-07-10 at 00:12 +1000, Jonathan Liu wrote:
>> The root device is currently set as /dev/hda2. However, this is
>> only correct if it's the first IDE drive. If booting off the first SATA
>> drive instead, it would be /dev/sda2. It's not the first drive, neither
>> /dev/hda2 or /dev/sda2 would be correct.
>>
>> The solution to this has typically been to use the filesystem UUID to
>> specify the root device but this requires extra support in the initrd.
>> Linux 3.8 introduces the ability to specify the root device using the
>> MBR disk signature and the partition number which is much simpler to
>> use and avoids the extra overhead of an initrd.
>>
>> This change uses the MBR disk signature to specify the root device when
>> using Linux 3.8+ and CONFIG_BLOCK (required for root=PARTUUID=)
>> is enabled in the kernel.
>>
>> This has been tested with QEMU x86 and Intel Desktop Board D2500HN using
>> an image recipe inheriting boot-directdisk and core-image.
>>
>> Signed-off-by: Jonathan Liu <net147 at gmail.com>
>> ---
>>   meta/classes/boot-directdisk.bbclass | 30 +++++++++++++++++++++++++++++-
>>   1 file changed, 29 insertions(+), 1 deletion(-)
>>
>> diff --git a/meta/classes/boot-directdisk.bbclass b/meta/classes/boot-directdisk.bbclass
>> index efeadab..f97060f 100644
>> --- a/meta/classes/boot-directdisk.bbclass
>> +++ b/meta/classes/boot-directdisk.bbclass
>> @@ -35,7 +35,9 @@ BOOTDD_EXTRA_SPACE ?= "16384"
>>   # Get the build_syslinux_cfg() function from the syslinux class
>>   
>>   AUTO_SYSLINUXCFG = "1"
>> -SYSLINUX_ROOT ?= "root=/dev/sda2"
>> +SYSLINUX_FIXED_ROOT = "root=/dev/sda2"
>> +SYSLINUX_UUID_ROOT = "root=PARTUUID=${DISK_SIGNATURE}-02"
> Why  '=' and not '?=' for the above? Shouldn't the user be able to
> override these?
Ok.
>
>> +SYSLINUX_ROOT ?= "${@'${SYSLINUX_UUID_ROOT}' if has_kernel_mbr_partuuid_support(d) else '${SYSLINUX_FIXED_ROOT}'}"
>>   SYSLINUX_TIMEOUT ?= "10"
>>   
>>   inherit syslinux
>> @@ -98,6 +100,10 @@ build_boot_dd() {
>>   	parted $IMAGE set 1 boot on
>>   	parted $IMAGE print
>>   
>> +	# Disk signature generated by parted isn't really random, so use our own generated signature
>> +	echo -ne "$(echo ${DISK_SIGNATURE} | fold -w 2 | tac | paste -sd '' | sed 's/\(..\)/\\x&/g')" | \
>> +		dd of=$IMAGE bs=1 seek=440 conv=notrunc
> Oi! So, can "fold -w 2 | tac | paste -sd '' be replaced with "rev" from
> the standard util-linux package?
>
> And the sed command... just insert "\x" every two characters? That
> doesn't seem to add any more randomness.... maybe I'm missing the point
> here?
fold -w 2 | tac | paste -sd '' is to reverse the hex bytes. the sed 
command is to convert the hex bytes aabbccdd to \xaa\xbb\xcc\xdd and 
pass to echo -ne to convert the hex bytes to binary. I can remove fold 
-w 2 | tac | paste -sd '' and add rev after converting to binary.
>
>
>> +
>>   	OFFSET=`expr $END2 / 512`
>>   	dd if=${STAGING_DATADIR}/syslinux/mbr.bin of=$IMAGE conv=notrunc
>>   	dd if=$HDDIMG of=$IMAGE conv=notrunc seek=1 bs=512
>> @@ -113,4 +119,26 @@ python do_bootdirectdisk() {
>>       bb.build.exec_func('build_boot_dd', d)
>>   }
>>   
>> +def generate_disk_signature():
>> +    import uuid
>> +    return str(uuid.uuid4())[:8]
>> +
>> +def get_kernel_version(d):
>> +    import subprocess
>> +    version_cmd = r"grep '^VERSION\s*=' '%s/Makefile' | grep -o '[0-9]*$'" % (d.getVar("STAGING_KERNEL_DIR", True))
>> +    version = int(subprocess.Popen(version_cmd, shell=True, stdout=subprocess.PIPE).communicate()[0])
>> +    patchlevel_cmd = r"grep '^PATCHLEVEL\s*=' '%s/Makefile' | grep -o '[0-9]*$'" % (d.getVar("STAGING_KERNEL_DIR", True))
>> +    patchlevel = int(subprocess.Popen(patchlevel_cmd, shell=True, stdout=subprocess.PIPE).communicate()[0])
>> +    return (version, patchlevel)
>> +
>> +def has_kernel_config_option(option, d):
>> +    import subprocess
>> +    grep_cmd = r"grep '^CONFIG_%s=y$' '%s/.config'" % (option, d.getVar("STAGING_KERNEL_DIR", True))
>> +    return subprocess.call(grep_cmd, shell=True, stdout=subprocess.PIPE) == 0
> Is there a specific kernel option to test for the MBR disk signature
> support or is that inherent in the block drivers now? It would be nice
> if we could skip the kernel version check, that code looks dangerously
> fragile (no fault of yours).
The commit which adds the support is 
https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/commit/?id=d33b98fc82b0908e91fb05ae081acaed7323f9d2. 
https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/init/do_mounts.c?id=refs/tags/v3.8.13 
indicates PARTUUID= support is only enabled with CONFIG_BLOCK.
Alternatively, instead of checking kernel version I could just add an 
option to enable the PARTUUID support and add a comment in the class 
that you need Linux 3.8+ with CONFIG_BLOCK. It would be disabled by 
default in that case and if they are using an older kernel version with 
the feature manually backported, they can explicitly enable it.
>
>> +
>> +def has_kernel_mbr_partuuid_support(d):
>> +    return get_kernel_version(d) >= (3, 8) and has_kernel_config_option("BLOCK", d)
>> +
>> +DISK_SIGNATURE := "${@generate_disk_signature()}"
>> +
>>   addtask bootdirectdisk before do_build
Regards,
Jonathan



More information about the Openembedded-core mailing list