NSLU2-Linux
view · edit · print · history

How to mount disks by label

The order in which USB devices are initialised at boot time is somewhat random. This is problematic in the case of disks as the SCSI drive identifiers (sda, sdb etc) normally used to refer to them in /etc/fstab are allocated sequentially. One way to avoid this problem is to give labels to each of the filesystems and to refer to them using those labels in /etc/fstab.

If your slug always seems to power on with its drives in the same order, you may just be lucky. Maybe next week you'll add a new peripheral and it will all change. In my case I replaced a failed flash drive with a new one and subsequently the two drives swapped around on each boot.

This page is written with Debian / NSLU2 in mind. It is probably somewhat applicable to other NSLU2 software distributions. Users of other distributions, please add comments.

The basic procedure is as follows:

  1. Add labels to your filesystems.
  2. Change /etc/fstab to use the labels.
  3. Change the kernel command line to use a label for the root disk.

Adding labels to filesystems

Note that the labels apply to partitions, not to disks.

For ext2 and ext3 filesystems you can use the tune2fs program to add labels:

# tune2fs -L root /dev/sda1

Where -L specifies the name you'll be assigning the drive (in this case, "root")

For your swap partition you can set a label using mkswap, but you need to swapoff first:

# swapoff -a
# mkswap -L swap /dev/sda2
# swapon -a

Choose labels that use characters that are legal in filenames. In particular I suggest not using the "/" character in labels since it breaks the /dev/disk stuff described below. This is an interesting point because I believe that RedHat may have standardised on using "/" as the label on the root filesystem; this works for them because they use an alternative "LABEL=" syntax instead of /dev/disk.

OpenWrt uses the same "LABEL=" syntax as RedHat. So the "/etc/fstab" entries will differ from the Debian entries below. NOTE: I haven't tested the 'root' label, as my boot device is connected directly to the slug and does not change disk ID.

At this point you should reboot, as the kernel will not be fully aware of the labels until the affected filesystems are remounted.

/dev/disk

Have a look at /dev/disk:

# tree /dev/disk
/dev/disk
|-- by-id
|   |-- usb-JetFlash_TS1GJFV30_DZPCOJC7 -> ../../sdb
|   |-- usb-JetFlash_TS1GJFV30_DZPCOJC7-part1 -> ../../sdb1
|   |-- usb-JetFlash_TS1GJFV30_DZPCOJC7-part2 -> ../../sdb2
|   |-- usb-USB_2.0_Flash_Disk_a86144e24194b3 -> ../../sda
|   `-- usb-USB_2.0_Flash_Disk_a86144e24194b3-part1 -> ../../sda1
|-- by-label
|   |-- data -> ../../sda1
|   |-- root -> ../../sdb1
|   `-- swap -> ../../sdb2
|-- by-path
|   |-- pci-0000:00:01.2-usb-0:1:1.0-scsi-0:0:0:0 -> ../../sdb
|   |-- pci-0000:00:01.2-usb-0:1:1.0-scsi-0:0:0:0-part1 -> ../../sdb1
|   |-- pci-0000:00:01.2-usb-0:1:1.0-scsi-0:0:0:0-part2 -> ../../sdb2
|   |-- pci-0000:00:01.2-usb-0:2.5:1.0-scsi-0:0:0:0 -> ../../sda
|   `-- pci-0000:00:01.2-usb-0:2.5:1.0-scsi-0:0:0:0-part1 -> ../../sda1
`-- by-uuid
    |-- 71b2f940-7e96-4e4f-be18-d712073780b8 -> ../../sdb2
    |-- 72ff7f86-243d-4e8f-91cd-40540a60cc1c -> ../../sdb1
    `-- 950b2fb6-9a1e-4bce-85a7-bb796a96a061 -> ../../sda1

I believe that these symlinks are all created by udev. You should be able to see the labels that you've just added under /dev/disk/by-label. If you prefer cryptic UUIDs to human-readable labels for some reason you can use the links in /dev/by-uuid. The /dev/by-path links may provide a way to refer to a disk by the hub port that it is connected to, if that is useful to you.

/etc/fstab

You can now edit /etc/fstab to refer to partitions using their labels instead of the hard-coded /dev/sd names. Mine now looks like this:

proc            	/proc   proc    defaults        0 0
/dev/disk/by-label/root	/	ext3    noatime		1 1
/dev/disk/by-label/swap	none    swap    sw              0 0
/dev/disk/by-label/data	/data	ext3	noatime		0 0

Or for OpenSlug: (You may have to label the partitions on another system)

proc            	/proc   proc    defaults        0 0
LABEL=root		/	ext3    noatime		1 1
LABEL=swap		none    swap    sw              0 0
LABEL=data		/data	ext3	noatime		0 0

NOTE: The 'root' entry is untested as stated in the previous note

I suggest checking to see if you have any other files in /etc that use /dev/sd. I didn't find any.

# grep -R 'sd[ab]' /etc

Kernel command line

The kernel doesn't look in /etc/fstab to find the root partition, because /etc/fstab isn't mounted at that time. Instead, the root partition is specified on the kernel command line using the root= parameter; if nothing is specified a default is used.

For Debian / NSLU2, changing the kernel command line is described on ChangeKernelCommandLine. Currently it's a bit complicated. You need to add a parameter something like:

root=/dev/disk/by-label/root

Root filesystem bug

Note: the below section is no longer needed for Debian Lenny 5.0.4 (bug solved); you can just use the APEX tool (apex-env command) without worry about the MTD block, to add the root disk by label as described in the above section. Next, reflash the flash (takes also care of the actual flashing) with the command update-initramfs -k all -u. End of note.

At the time of writing the Debian / NSLU2 distribution has a bug which will cause the root disk that you specify on the kernel command line to be ignored. The problem is inside the initramfs. You can work around this by setting the root device in a new /etc/initramfs-tools/conf.d file and recreating the initramfs. The kernel command line root parameter will still be ignored.

  1. echo "ROOT=<Your root device>" > /etc/initramfs-tools/conf.d/my-root-device-hack
  2. update-initramfs -k all -u
    1. update-initramfs: Generating /boot/initrd.img-2.6.18-3-ixp4xx
  3. flash-kernel
    1. Flashing kernel: done.
    2. Flashing initramfs: done.

If you want to fix it so that the kernel command line parameter is not ignored, or if you use a custom initramfs or for some other reason can not use update-initramfs, here is an outline of how to fix the bug properly. For more details of how to manage initramfs files, have a look at BuildImage. You probably need to do most of this as root as otherwise the cpio archive that you create will have the wrong ownership information on the files.

  1. Get your existing initramfs archive from either
    1. /dev/mtdblock4; check the partition number in /proc/mtd (look for Ramdisk), strip the 16-byte header and change the endianness.
    2. slugimage -u; you want the ramdisk.gz file. No header to strip, not sure about endianness.
    3. /boot/initrd.img, if you haven't previously changed it. No header to strip, endianness is correct.
  2. Unpack: mkdir tmp; cd tmp; zcat ../mtd4.bin | cpio -i
  3. Now fix the bug. Just move conf/param.conf to conf/conf.d/default_root. Leave an empty file in conf/param.conf.
  4. Repack: find . | cpio --quiet -o -H newc | gzip -9 > ../new-mtd4.bin
  5. Reflash. Either:
    1. Package using slugimage and then upslug2. I'm not sure about padding or endianness requirements if you do this.
    2. cat into /dev/mtdblock4. In this case you need to prepend a 16-byte header containing the length in the first four bytes (big endian), pad with zeros to the length of the mtd partition and byte swap. I suggest sanity-checking the first few bytes using od -x | head to see if the format (especially length and endianness) looks the same as your current /dev/mtdblock4 contents. Zero-padding seems to be essential as junk after the end of the gzip data can make the kernel decide that it is not looking at an initramfs.
    3. Use flash_kernel. I've not looked at this.
  6. Cross fingers and reboot.
Page last modified on June 19, 2010, at 03:04 PM