Pages

Monday, November 18, 2013

Initial Ramdisk

A short howto for using a initial ramdisk (initrd) in Slackware Linux.
A initrd is very handy when you need a special module already during booting and you don't want to recompile the entire kernel. So let's get started directly by creating a simple initrd without any particular modules etc:

# mkinitrd -r /dev/sda1 -f ext4 -o /boot/initrd-$(uname -r).img

The above command will create a very basic initrd. The options ar the following

-r : your root partition, in my case /dev/sda1
-f : your file system for your root partition, in my case ext4
-o : the output file

An initrd is a cpio packaged compressed with gzip. The command mkinitrd will automatically use your current running kernel (the kernel that you used for booting). Just execute uname to get your current kernel version:

# uname -r
3.2.29


The above information will be used for the file name (the output file). In my case it is /boot/initrd-3.2.29.img. The next thing you need to do is to add the initrd to your boot loader. If you're using Slackware Linux then it will be lilo (in most cases). Just edit /etc/lilo.conf like the following example:

# vi /etc/lilo.conf
...
image = /boot/vmlinuz
  root = /dev/sda1
  label = Linux
  read-only
  initrd = /boot/initrd-3.2.29.img
...


Note the last line: it has the leading initrd option with the same path and filename which I've defined for my initrd output file. The last thing you need to do is to reinstall lilo:

# lilo
Added Linux  +  *
...


Every entry with the initrd option has a + now. Finally reboot your system to make sure that your initrd loads and that your Linux boots correctly.
Let's take a little closer look at your initrd. When creating a initrd the complete initrd will be available in /boot/initrd-tree. You can cd to it, change files etc. A few interesting files are:

/boot/initrd-tree/rootdev

That file holds the information for the root partition - /dev/sda1

/boot/initrd-tree/rootfs

As the name already suggest that files hold the information for the root filesystem - ext4

/boot/initrd-tree/load_kernel_modules

If you need to pass options to your modules then edit the above file. The idea is to create a initrd first, then edit the above and finally recreate your initrd. A sample configuration can be found at the end.

/boot/initrd-tree/init

A very interesting file. It's just a shell skript for substituting a real init. In case that you have trouble with your initrd then you can add a /bin/ash in that script and you will get a shell during the execution of the initrd. Press CTRL+d to continue executing your initrd and booting. A sample could look like this (before cleaning up the udev db):

# vi /boot/initrd-tree/init
...
/bin/ash

# Need to make sure OPTIONS+="db_persist" exists for all dm devices
# That should be handled in /sbin/mkinitrd now
/sbin/udevadm info --cleanup-db
/sbin/udevadm control --exit
...


Nearly at the end of the init script add /bin/ash and a shell starts before the initrd executes a switch_root.
Every change you make needs a recreation of the initrd and a reinstall of lilo!
In case that you've messed up your initrd and you want/need to clean up your initrd-tree then you can use the -c option:

# mkinitrd -c -r /dev/sda1 -f ext4 -o /boot/initrd-$(uname -r).img

The above command will clean up /boot/initrd-tree first before creating a new initrd. All changes (eg. in /boot/initrd-tree/init) you've made will be lost!
To add a module use the -m option:

# mkinitrd -m radeon -r /dev/sda1 -f ext4 -o /boot/initrd-$(uname -r).img

That will add the radeon including all depending modules to your initrd. Multiple modules can be added by using a colon:

# mkinitrd -m radeon:brcmsmac -r /dev/sda1 -f ext4 -o /boot/initrd-$(uname -r).img

All depending modules for radeon and brcmsmac will added too.

If you need to pass options to your modules then edit the file load_kernel_modules inside the initrd-tree directory. First create your initrd as usual. The following example is for my old workstation where I need to the avoid_D3 parameter to the via_rhine module. I've create the initrd initially this way:

# mkinitrd -m via_rhine -h /dev/sda1 -r /dev/sda2 -f ext4 -o /boot/initrd-$(uname -r).img
...


Then I've edited the load_kernel_modules files and added the avoid_D3 parameter to the modprobe command:

# vi /boot/initrd-tree/load_kernel_modules
modprobe -v mii
modprobe -v via-rhine avoid_D3=1


The last step was to recreate the initrd again. The changes I've made kept untouched:

# mkinitrd -m via_rhine -h /dev/sda1 -r /dev/sda2 -f ext4 -o /boot/initrd-$(uname -r).img
...


If you're using ACPI (see Suspend to disk/ram with Linux) for suspending to harddisk then don't forget the -h option for resuming your system from your swap (/dev/sda2):

# mkinitrd -h /dev/sda2 -r /dev/sda1 -f ext4 -o /boot/initrd-$(uname -r).img

The -h option will fill the file /boot/initrd-tree/resumedev with the given device. After that your initrd will try to resume from that device.

After all that make sure that you always reinstall lilo when using a initrd with Slackware Linux (in case that you're using lilo) and have made changes to it.

Updated 10/06/2015: added an example how to add parameters for modules