The Loopback Root Filesystem HOWTO: How To Create a Loopback Root Device

Next Previous Contents

## 3. How To Create a Loopback Root Device

Now that the general principles are explained the method of creating the loopback device can be explained.

## 3.1 Requirements

To create the loopback root device will require a number of things.

- A working Linux system.
- A way to copy large files onto the target DOS partition.

Most important is access to an installed Linux system. This is because the loop device can only be created under Linux. This will mean that it is not possible to bootstrap a working system from nothing. The requirements of the Linux system that you use is that you can compile a kernel on it.

Once the loopback device is created it will be a large file. I have used an 80 MB files, but while this was sufficient for an X terminal it may not be enough if you want to use it for much else. This file must be copied onto the DOS partition, so either a network or a lot of floppy disks must be used.

The software that you will require includes

- `LOADLIN` version 1.6 or above
- A version of `mount` that supports loopback devices
- A version of the kernel that supports the required options.

All of these should be standard for recent Linux installations.

## 3.2 Creating the Linux Kernel

I created the loopback device using Linux kernel version 2.0.31, other versions should also work, but they must have at least the options listed below.

The kernel options that you will need to enable are the following:

- RAM disk support (`CONFIG_BLK_DEV_RAM`).
- Initial RAM disk (initrd) support (`CONFIG_BLK_DEV_INITRD`).
- Loop device support (`CONFIG_BLK_DEV_LOOP`).
- fat fs support (`CONFIG_FAT_FS`).
- msdos fs support (`CONFIG_MSDOS_FS`).

The first two are for the RAM disk device itself and the initial ram disk device. The next one is the loop back filesystem option. The last two are the msdos filesystem support which is required to mount the DOS partitition.

Compiling a kernel without modules is the easiest option, although if you do want modules then it should be possible although I have not tried it. If modules are used then you should make sure that you have the options above compiled in and not as modules themselves.

Depending on the kernel version that you have you may need to apply a kernel patch. It is a very simple one that allows the loopback device to be used as the root filesystem.

- Kernel versions before 2.0.0; I have no information about these.
- Kernel version 2.0.0 to 2.0.34; you need to apply the kernel patch for 2.0.x kernels as shown below.
- Kernel version 2.0.35 to 2.0.x; no kernel patch is required.
- Kernel version 2.1.x; you need to apply the kernel patch for 2.0.x or 2.2.x kernels as shown below, depending on the exact 2.1.x version.
- Kernel version 2.2.0 to 2.2.10; you need to apply the kernel patch for 2.2.x kernels as shown below.
- Kernel version 2.3.x; you need to apply the kernel patch for 2.2.x kernels as shown below.

For 2.0.x kernels the file `/init/main.c` needs to have a single line added to it as shown by the modified version below. The line that says `"loop", 0x0700` is the one that was added.

> `

>     static void parse_root_dev(char * line)
>     {
>             int base = 0;
>             static struct dev_name_struct {
>                     const char *name;
>                     const int num;
>             } devices[] = {
>                     { "nfs",     0x00ff },
>                     { "loop",    0x0700 },
>                     { "hda",     0x0300 },

>     ...

>                     { "sonycd",  0x1800 },
>                     { NULL, 0 }
>             };

>     ...

>     }

> `

For 2.2.x kernels the file `/init/main.c` needs to have three lines added to it as shown by the modified version below. The line that says `"loop", 0x0700` and the ones either side of it are the ones that were added.

> `

>     static struct dev_name_struct {
>             const char *name;
>             const int num;
>     } root_dev_names[] __initdata = {
>     #ifdef CONFIG_ROOT_NFS
>             { "nfs",     0x00ff },
>     #endif
>     #ifdef CONFIG_BLK_DEV_LOOP
>             { "loop",    0x0700 },
>     #endif
>     #ifdef CONFIG_BLK_DEV_IDE
>             { "hda",     0x0300 },

>     ...

>             { "ddv", DDV_MAJOR << 8},
>     #endif
>             { NULL, 0 }
>     };

> `

Once the kernel is configured it should be compiled to produce a `zImage` file (`make zImage`). This file will be `arch/i386/boot/zImage` when compiled.

## 3.3 Creating the Initial Ramdisk Device

The initial ramdisk is most easily created as a loopback device from the start. You will need to do this as root, the commands that you need to execute are listed below, they are assumed to be run from root's home directory (`/root`).

> `

>     mkdir /root/initrd
>     dd if=/dev/zero of=initrd.img bs=1k count=1024
>     mke2fs -i 1024 -b 1024 -m 5 -F -v initrd.img
>     mount initrd.img /root/initrd -t ext2 -o loop
>     cd initrd
>     [create the files]
>     cd ..
>     umount /root/initrd
>     gzip -c -9 initrd.img > initrdgz.img

> `

There are a number of steps to this, but they can be described as follows.

1. Create a mount point for the initial ramdisk (an empty directory).
2. Create an empty file of the size required. Here I have used 1024kB, you may need less or more depending on the contents, (the size is the last parameter).
3. Make an ext2 filesystem on the empty file.
4. Mount the file onto the mount point, this uses the loopback device.
5. Change to the mounted loopback device.
6. Create the files that are required (see below for details).
7. Move out of the mounted loopback device.
8. Unmount the device.
9. Create a compressed version for use later.

Contents Of The Initial Ramdisk

The files that you will need on the ramdisk are the minimum requirements to be able to execute any commands.

- `/linuxrc` The script that is run to mount the msdos file system (see below).
- `/lib/*` The dynamic linker and the libraries that the programs need.
- `/etc/*` The cache used by the dynamic linker (not strictly needed, but does stop it complaining).
- `/bin/*` A shell interpreter (`ash` because it is smaller than `bash`. The `mount` and `losetup` programs for handling the DOS disk and setting up the loopback devices.
- `/dev/*` The devices that will be used. You need `/dev/zero` for `ld-linux.so`, `/dev/hda*` to mount the msdos disk and `/dev/loop*` for the lopback device.
- `/mnt` An empty directory to mount the msdos disk on.

The initial ramdisk that I used is listed below, the contents come to about 800kB when the overhead of the filesystem are taken into account.

> `

>     total 18
>     drwxr-xr-x   2 root     root         1024 Jun  2 13:57 bin
>     drwxr-xr-x   2 root     root         1024 Jun  2 13:47 dev
>     drwxr-xr-x   2 root     root         1024 May 20 07:43 etc
>     drwxr-xr-x   2 root     root         1024 May 27 07:57 lib
>     -rwxr-xr-x   1 root     root          964 Jun  3 08:47 linuxrc
>     drwxr-xr-x   2 root     root        12288 May 27 08:08 lost+found
>     drwxr-xr-x   2 root     root         1024 Jun  2 14:16 mnt

>     ./bin:
>     total 168
>     -rwxr-xr-x   1 root     root        60880 May 27 07:56 ash
>     -rwxr-xr-x   1 root     root         5484 May 27 07:56 losetup
>     -rwsr-xr-x   1 root     root        28216 May 27 07:56 mount
>     lrwxrwxrwx   1 root     root            3 May 27 08:08 sh -> ash

>     ./dev:
>     total 0
>     brw-r--r--   1 root     root       3,   0 May 20 07:43 hda
>     brw-r--r--   1 root     root       3,   1 May 20 07:43 hda1
>     brw-r--r--   1 root     root       3,   2 Jun  2 13:46 hda2
>     brw-r--r--   1 root     root       3,   3 Jun  2 13:46 hda3
>     brw-r--r--   1 root     root       7,   0 May 20 07:43 loop0
>     brw-r--r--   1 root     root       7,   1 Jun  2 13:47 loop1
>     crw-r--r--   1 root     root       1,   3 May 20 07:42 null
>     crw-r--r--   1 root     root       5,   0 May 20 07:43 tty
>     crw-r--r--   1 root     root       4,   1 May 20 07:43 tty1
>     crw-r--r--   1 root     root       1,   5 May 20 07:42 zero

>     ./etc:
>     total 3
>     -rw-r--r--   1 root     root         2539 May 20 07:43 ld.so.cache

>     ./lib:
>     total 649
>     lrwxrwxrwx   1 root     root           18 May 27 08:08 ld-linux.so.1 -> ld-linux.so.1.7.14
>     -rwxr-xr-x   1 root     root        21367 May 20 07:44 ld-linux.so.1.7.14
>     lrwxrwxrwx   1 root     root           14 May 27 08:08 libc.so.5 -> libc.so.5.3.12
>     -rwxr-xr-x   1 root     root       583795 May 20 07:44 libc.so.5.3.12

>     ./lost+found:
>     total 0

>     ./mnt:
>     total 0

> `

The only complex steps about this are the devices in `dev`. Use the `mknod` program to create them, use the existing devices in `/dev` as a template to get the required parameters.

The /linuxrc file

The `/linuxrc` file on the initial ramdisk is required to do all of the preparations so that the loopback device can be used for the root partition when it exits.

The example below tries to mount `/dev/hda1` as an msdos partition and if it succeeds then sets up the files `/linux/linuxdsk.img` as `/dev/loop0` and `/linux/linuxswp.img` as `/dev/loop1`.

> `

>     #!/bin/sh

>     echo INITRD: Trying to mount /dev/hda1 as msdos

>     if /bin/mount -n -t msdos /dev/hda1 /mnt; then

>        echo INITRD: Mounted OK
>        /bin/losetup /dev/loop0 /mnt/linux/linuxdsk.img
>        /bin/losetup /dev/loop1 /mnt/linux/linuxswp.img
>        exit 0

>     else

>        echo INITRD: Mount failed
>        exit 1

>     fi

> `

The first device `/dev/loop0` will become the root device and the second one `/dev/loop1` will become the swap space.

If you want to be able to write to the DOS partition as a non-root user when you have finished then you should use `mount -n -t msdos /dev/hda1 /mnt -o uid=0,gid=0,umask=000,quiet` instead. This will map all accesses to the DOS partition to root and set the permissions appropriately.

## 3.4 Creating The Root Device

The root device that you will be using is the file `linuxdsk.img`. You will need to create this in the same way that the initial ramdisk was created, but bigger. You can install any Linux installation that you like onto this disk.

The easiest way might be to copy an existing Linux installation into it. An alternative is to install a new Linux installation onto it.

Assuming that you have done this, there are some minor changes that you must make.

The `/etc/fstab` file must reference the root partition and the swap using the two loopback devices that are setup on the initial ramdisk.

> `

>     /dev/loop0     /      ext2   defaults 1 1
>     /dev/loop1     swap   swap   defaults 1 1

> `

This will ensure that when the real root device is used the kernel will not be confused about where the root device is. It will also allow the swap space to be added in the same way a swap partition is normally used. You should remove any other reference to a root disk device or swap partition.

If you want to be able to read the DOS partition after Linux has started then you will need to make a number of extra small changes.

Create a directory called `/initrd`, this is where the initial ramdisk will be mounted once the loopback root filesystem is mounted.

Create a symbolic link called `/DOS` that points to `/initrd/mnt` where the real DOS parition will be mounted.

Add a line into the rc file that mounts the disks. This should run the command `mount -f -t msdos /dev/hda1 /initrd/mnt`, this will create a 'fake' mount of the DOS partition so that all programs (like `df`) will know that the DOS partition is mounted and where to find it. If you used different options in the `/linuxrc` file that obviously you should use them here also.

There is no need to have a Linux kernel on this root device since that is already loaded earlier. If you are using modules however then you should include them on this device as normal.

## 3.5 Creating the Swap Device

The root device that you will be using is the file `linuxswap.img`. The swap device is very simple to create. Create an empty file as was done for the initial ramdisk and then run `mkswap linuxswap.img` to intialise it.

The size of the swap space will depend on what you plan to do with the installed system, but I would recommend between 8MB and the amount of RAM that you have.

## 3.6 Creating the MSDOS Directory

The files that are going to be used need to be moved onto the DOS partition.

The files that are required in the DOS directory called `C:\LINUX` are the following:

- `LINUXDSK.IMG` The disk image that will become the root device.
- `LINUXSWP.IMG` The swap space.

## 3.7 Creating the Boot Floppy

The boot floppy that is used is just a normal DOS format bootable floppy.

This is created using `format a: /s` from DOS.

Onto this disk you will need to create an `AUTOEXEC.BAT` file (as below) and copy the kernel, compressed initial ramdisk and `LOADLIN` executable.

- `AUTOEXEC.BAT` The DOS automatically executed batch file.
- `LOADLIN.EXE` The `LOADLIN` program executable.
- `ZIMAGE` The Linux kernel.
- `INITRDGZ.IMG` The compressed initial ramdisk image.

The `AUTOEXEC.BAT` file should contain just one line as below.

> `

>     \loadlin \zImage initrd=\initrdgz.img root=/dev/loop0 ro

> `

This specifies the kernel image to use, the initial ramdisk image, the root device after the initial ramdisk has finished and that the root partition is to be mounted read-only.

Next Previous Contents