Using UUID to specify the root file system location

4 minute read

In embedded systems it is common to store the root file system in a SD card or eMMC type of media. Typically the kernel command line has something like: root=/dev/mmcblk0p2 to tell the kernel where to look for the root file system.

What is the problem with such approach?

First, the mmc block device number can vary. For example: let’s consider a system with one eMMC and one SD card slot where the root file system is stored in the eMMC. The eMMC block device that the kernel registers can vary depending if the slot card has a SD card inserted or not.

Also, depending on the kernel version the mmc block number may also change as the mmc block number is not determistic.

This means that passing the mmc block device for specifying the rootfs location is not a robust approach.

What can be done instead?

Several attempts have been made to fix this in the mmc core kernel code by adding aliases so that the mmc core code could parse them from device tree.

None of these attempts have been accepted. The answer to this type of problem is called UUID (Universally Unique IDentifier).

How to use UUID to specify the root file system location?

Here is an example of an issue that I faced recently on a imx6sl-evk board:

U-Boot passes root=/dev/mmcblk0p2, which works fine for NXP kernel 4.1 kernel version, but when trying to boot it with a 4.13.x kernel it is not possible to mount the rootfs and it fails like this:

Waiting for root device /dev/mmcblk0p2...

The rootfs mount failure happens because the SD card is not located at mmcblk0 with mainline kernel. In this case it is at mmclblk1:

[    1.895919] mmc0: SDHCI controller on 2190000.usdhc [2190000.usdhc] using DMA
[    1.984725] mmc1: SDHCI controller on 2194000.usdhc [2194000.usdhc] using DMA
[    2.061089] mmc1: new high speed SDHC card at address 0007
[    2.069568] mmcblk1: mmc1:0007 SD08G 7.21 GiB
[    2.075189] mmc2: SDHCI controller on 2198000.usdhc [2198000.usdhc] using DMA
[    2.089228]  mmcblk1: p1 p2

Please note that the imx6sl-evk board has three SD card slots (registered as mmc0, mmc1 and mmc2).

If I manually change it to root=/dev/mmcblk1p2 then it will be able to mount the rootfs just fine with this kernel, but it will not work with NXP 4.1 kernel.

U-Boot can be changed in such a way that the hardcoded mmcblk is removed and UUID is used instead.

Here is a patch I did for U-Boot to fix this problem:

From 81ce266740b76e16c83d73909edb6ab9214abfcb Mon Sep 17 00:00:00 2001
From: Fabio Estevam <fabio.estevam@nxp.com>
Date: Sun, 1 Oct 2017 11:02:54 -0300
Subject: [PATCH 1/2] mx6slevk: Use PARTUUID to specify the rootfs location

mx6slevk can run different kernel versions, such as NXP 4.1 or mainline.

Currently the rootfs location is passed via mmcblk number and the
problem with this approach is that the mmcblk number for the SD card
changes depending on the kernel version.

In order to avoid such issue, use the UUID method to specify the
rootfs location.

Signed-off-by: Fabio Estevam <fabio.estevam@nxp.com>
---
 configs/mx6slevk_defconfig | 1 +
 include/configs/mx6slevk.h | 5 +++--
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/configs/mx6slevk_defconfig b/configs/mx6slevk_defconfig
index 1c28942..c876c6b 100644
--- a/configs/mx6slevk_defconfig
+++ b/configs/mx6slevk_defconfig
@@ -32,6 +32,7 @@ CONFIG_DM=y
 CONFIG_DM_GPIO=y
 CONFIG_DM_I2C=y
 CONFIG_DM_MMC=y
+CONFIG_CMD_PART=y
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_STMICRO=y
 CONFIG_PHYLIB=y
diff --git a/include/configs/mx6slevk.h b/include/configs/mx6slevk.h
index 25c83e8..c82ef2c 100644
--- a/include/configs/mx6slevk.h
+++ b/include/configs/mx6slevk.h
@@ -53,9 +53,9 @@
 	"ip_dyn=yes\0" \
 	"mmcdev=1\0" \
 	"mmcpart=1\0" \
-	"mmcroot=/dev/mmcblk0p2 rootwait rw\0" \
+	"finduuid=part uuid mmc 1:2 uuid\0" \
 	"mmcargs=setenv bootargs console=${console},${baudrate} " \
-		"root=${mmcroot}\0" \
+		"root=PARTUUID=${uuid} rootwait rw\0" \
 	"loadbootscript=" \
 		"fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${script};\0" \
 	"bootscript=echo Running bootscript from mmc ...; " \
@@ -63,6 +63,7 @@
 	"loadimage=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${image}\0" \
 	"loadfdt=fatload mmc ${mmcdev}:${mmcpart} ${fdt_addr} ${fdt_file}\0" \
 	"mmcboot=echo Booting from mmc ...; " \
+		"run finduuid; " \
 		"run mmcargs; " \
 		"if test ${boot_fdt} = yes || test ${boot_fdt} = try; then " \
 			"if run loadfdt; then " \
-- 
2.7.4

, which basically selects the CONFIG_CMD_PART=y option so that the part command becomes availabe and change the kernel command line to use UUID instead of the hardcoded mmc block.

The part uuid mmc 1:2 uuid means:

  • Read the UUID from mmc device 1 (which is the boot medium of this board), partition 2 (which is the SD card partition where the rootfs is stored) and store it in the uuid variable.

With such approach the rootfs can be always correctly found in both NXP kernel 4.1 version as well as in mainline 4.13.x.

Conclusion: if you have a system with multiple SD/eMMC ports and need to change/upgrade kernel versions the UUID method is a convenient and robust way to specify the location of the rootfs.