initrd + busybox error

richard at richard at
Tue Jul 8 01:07:11 PDT 2003

On 2003-07-07 12:38:08 +0000, Pedro Salazar wrote:
> For now, I'll try to solve the modules dependences (I don't know if the
> script error is also dependent), but I would like to understand tour
> approach about the root filesystem mounting.
My system uses LVM on the root partition. LVM provides a flexible
way of mapping physical block devices to logical block devices,
but the logical devices cannot be accessed until the map is loaded
into the kernel. LVM-2 provides a much cleaner way for the a boot
loader to implement this, but my solution predates LVM-2, so it is
a bit clunky but not actually broken even though I have updated
my logical volumes to LVM-2 format. One day I will fix it.

Grub (patched) can read LVM's, so I can load a kernel and initrd from
them. I have compiled LVM into the kernel, because if LVM was a module
it could not be removed without first unmounting the root partition.
That is not sufficient to mount an LVM, first we need the map. The
commands to create the map, and load it into the kernel are:

vgchange -a y

For these to work, /proc must be mounted, and /etc writeable (yuck).
My initrd contains some empty directories as mount points, a linuxrc
program made by trimming the code for vgscan and vgchange and putting
them into a C program with a little glue so all three can share a
static link to glibc (one of the tricks used by busybox to save space).

Here are the guts of my linuxrc:
int main(__attribute__((unused)) int argc, __attribute__((unused)) char **argv)
        const char *vgscan[]={ "/sbin/vgscan", "vgscan", NULL };
        const char *vgchange[]={ "/sbin/vgchange", "vgchange", "-a", "y", NULL };

        printf(_(PACKAGE "-" LVMBOOT_VERSION " running as %s\n"), program_invocation_short_name);
        do_or_die(mount, "proc", "/proc", "proc", MS_MGC_VAL|MS_NODEV|MS_NOEXEC|MS_NOSUID, "");
        do_or_die(mount, "tmp",  "/tmp", "tmpfs", MS_MGC_VAL|MS_NODEV|MS_NOEXEC|MS_NOSUID, "");
        do_or_die(mkdir, "/tmp/lvm", 0700);
        do_or_die(mount, "/tmp/lvm", "/etc", "bind", MS_MGC_VAL|MS_BIND|MS_NODEV|MS_NOEXEC|MS_NOSUID, "");
        if (vgscan_main(  sizeof(vgscan  )/sizeof(*vgscan)  -1,   vgscan)) exit(EXIT_FAILURE);
        if (vgchange_main(sizeof(vgchange)/sizeof(*vgchange)-1, vgchange)) exit(EXIT_FAILURE);
        do_or_warn(umount, "/etc");
        do_or_warn(umount, "/proc");
        return EXIT_SUCCESS;

const char *...    this is how vgscan and vgchange expect to see their
                   command line arguments.
do_or_die          run a library command. If that fails, convert the
                   arguments to human readable form, print them in an
                   error message and exit.
do_or_warn         Like do or die, but does not exit.

All my linuxrc does is set up the environment needed for vgscan and
vgchange, run them, and tidy up a little. The initrd is on a romfs,
so it cannot be modified. I use a tmpfs bound to /etc to pick up
the files created by vgscan. These files can be needed if I want to
change the map while the system is running, so /tmp is not unmounted.

Here is a listing of /initrd (with the ramdisk mounted):
drwxr-xr-x    1 root     root           32 Jan  1  1970 dev
drwxr-xr-x    1 root     root           32 Jan  1  1970 etc
-rwxr-xr-x    1 root     root       494020 Jan  1  1970 linuxrc
drwxr-xr-x    1 root     root           32 Jan  1  1970 proc
drwxr-xr-x    1 root     root           32 Jan  1  1970 root
drwxr-xr-x    1 root     root           32 Jan  1  1970 tmp

All the directories are empty (/dev from devfs). I am reasonably
certain that /initrd/root is cruft from before I understood the 2.4.20
boot process. The /root directory used by the kernel as a mount point
for the final root device is on rootfs, and linuxrc runs in a chroot
environment set up by the kernel (initrd mounted at /old in rootfs).

After my linuxrc exits, the kernel does all the work of mounting
the root device at /root of rootfs, and running init with its root
directory set to /root. As my root partition contains /initrd/
the kernel changes the mount point of the initrd to that.

My initscripts do the final tidyup - put the files created by vgscan
in /var/lib/misc/lvm/ where they can be reached by symlinks from /etc,
unmount /initrd/tmp, /initrd and free the initrd block device.

Most of the documentation for initial ram discs was writen before
linux kernel 2.4.19. I skipped that kernel because of risks with the
ide drivers, so I went from 2.4.18 to 2.4.20-pre? (ide fixed, and
improved frame buffer support for my graphic card). As I had a known
good ram disc image to 2.4.18, I thought I was on the trail of a
kernel bug when the image did not work on 2.4.20-pre?. The code in
/usr/src/linux-2.4.21/init/{main,mounts}.c very clearly does half
the work that was required before 2.4.19. I was going to write an
update for /usr/src/linux-2.4.21/Documentation/initrd.txt, but got
bogged down because my test iamge would not mount. By the time I
had worked out the problem (the kernel did not recogised cramfs),
I had other things to do.

Unsubscribe: send email to listar at
and put 'unsubscribe blfs-support' in the subject header of the message

More information about the blfs-support mailing list