[PATCH] Initramfs docs update
New section on creating an external initramfs image using cpio (with script), a warning about bad advice in the cpio man page, a bit of debugging advice (hello world and rdinit=/bin/sh), and a few minor tweaks to other parts of it. Signed-off-by: Rob Landley <rob@landley.net> Cc: "H. Peter Anvin" <hpa@zytor.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
fa366ad5d7
commit
e7b6905582
|
@ -70,11 +70,13 @@ tmpfs mounts. See Documentation/filesystems/tmpfs.txt for more information.
|
|||
What is rootfs?
|
||||
---------------
|
||||
|
||||
Rootfs is a special instance of ramfs, which is always present in 2.6 systems.
|
||||
(It's used internally as the starting and stopping point for searches of the
|
||||
kernel's doubly-linked list of mount points.)
|
||||
Rootfs is a special instance of ramfs (or tmpfs, if that's enabled), which is
|
||||
always present in 2.6 systems. You can't unmount rootfs for approximately the
|
||||
same reason you can't kill the init process; rather than having special code
|
||||
to check for and handle an empty list, it's smaller and simpler for the kernel
|
||||
to just make sure certain lists can't become empty.
|
||||
|
||||
Most systems just mount another filesystem over it and ignore it. The
|
||||
Most systems just mount another filesystem over rootfs and ignore it. The
|
||||
amount of space an empty instance of ramfs takes up is tiny.
|
||||
|
||||
What is initramfs?
|
||||
|
@ -92,14 +94,16 @@ out of that.
|
|||
|
||||
All this differs from the old initrd in several ways:
|
||||
|
||||
- The old initrd was a separate file, while the initramfs archive is linked
|
||||
into the linux kernel image. (The directory linux-*/usr is devoted to
|
||||
generating this archive during the build.)
|
||||
- The old initrd was always a separate file, while the initramfs archive is
|
||||
linked into the linux kernel image. (The directory linux-*/usr is devoted
|
||||
to generating this archive during the build.)
|
||||
|
||||
- The old initrd file was a gzipped filesystem image (in some file format,
|
||||
such as ext2, that had to be built into the kernel), while the new
|
||||
such as ext2, that needed a driver built into the kernel), while the new
|
||||
initramfs archive is a gzipped cpio archive (like tar only simpler,
|
||||
see cpio(1) and Documentation/early-userspace/buffer-format.txt).
|
||||
see cpio(1) and Documentation/early-userspace/buffer-format.txt). The
|
||||
kernel's cpio extraction code is not only extremely small, it's also
|
||||
__init data that can be discarded during the boot process.
|
||||
|
||||
- The program run by the old initrd (which was called /initrd, not /init) did
|
||||
some setup and then returned to the kernel, while the init program from
|
||||
|
@ -124,13 +128,14 @@ Populating initramfs:
|
|||
|
||||
The 2.6 kernel build process always creates a gzipped cpio format initramfs
|
||||
archive and links it into the resulting kernel binary. By default, this
|
||||
archive is empty (consuming 134 bytes on x86). The config option
|
||||
CONFIG_INITRAMFS_SOURCE (for some reason buried under devices->block devices
|
||||
in menuconfig, and living in usr/Kconfig) can be used to specify a source for
|
||||
the initramfs archive, which will automatically be incorporated into the
|
||||
resulting binary. This option can point to an existing gzipped cpio archive, a
|
||||
directory containing files to be archived, or a text file specification such
|
||||
as the following example:
|
||||
archive is empty (consuming 134 bytes on x86).
|
||||
|
||||
The config option CONFIG_INITRAMFS_SOURCE (for some reason buried under
|
||||
devices->block devices in menuconfig, and living in usr/Kconfig) can be used
|
||||
to specify a source for the initramfs archive, which will automatically be
|
||||
incorporated into the resulting binary. This option can point to an existing
|
||||
gzipped cpio archive, a directory containing files to be archived, or a text
|
||||
file specification such as the following example:
|
||||
|
||||
dir /dev 755 0 0
|
||||
nod /dev/console 644 0 0 c 5 1
|
||||
|
@ -146,23 +151,84 @@ as the following example:
|
|||
Run "usr/gen_init_cpio" (after the kernel build) to get a usage message
|
||||
documenting the above file format.
|
||||
|
||||
One advantage of the text file is that root access is not required to
|
||||
One advantage of the configuration file is that root access is not required to
|
||||
set permissions or create device nodes in the new archive. (Note that those
|
||||
two example "file" entries expect to find files named "init.sh" and "busybox" in
|
||||
a directory called "initramfs", under the linux-2.6.* directory. See
|
||||
Documentation/early-userspace/README for more details.)
|
||||
|
||||
The kernel does not depend on external cpio tools, gen_init_cpio is created
|
||||
from usr/gen_init_cpio.c which is entirely self-contained, and the kernel's
|
||||
boot-time extractor is also (obviously) self-contained. However, if you _do_
|
||||
happen to have cpio installed, the following command line can extract the
|
||||
generated cpio image back into its component files:
|
||||
The kernel does not depend on external cpio tools. If you specify a
|
||||
directory instead of a configuration file, the kernel's build infrastructure
|
||||
creates a configuration file from that directory (usr/Makefile calls
|
||||
scripts/gen_initramfs_list.sh), and proceeds to package up that directory
|
||||
using the config file (by feeding it to usr/gen_init_cpio, which is created
|
||||
from usr/gen_init_cpio.c). The kernel's build-time cpio creation code is
|
||||
entirely self-contained, and the kernel's boot-time extractor is also
|
||||
(obviously) self-contained.
|
||||
|
||||
The one thing you might need external cpio utilities installed for is creating
|
||||
or extracting your own preprepared cpio files to feed to the kernel build
|
||||
(instead of a config file or directory).
|
||||
|
||||
The following command line can extract a cpio image (either by the above script
|
||||
or by the kernel build) back into its component files:
|
||||
|
||||
cpio -i -d -H newc -F initramfs_data.cpio --no-absolute-filenames
|
||||
|
||||
The following shell script can create a prebuilt cpio archive you can
|
||||
use in place of the above config file:
|
||||
|
||||
#!/bin/sh
|
||||
|
||||
# Copyright 2006 Rob Landley <rob@landley.net> and TimeSys Corporation.
|
||||
# Licensed under GPL version 2
|
||||
|
||||
if [ $# -ne 2 ]
|
||||
then
|
||||
echo "usage: mkinitramfs directory imagename.cpio.gz"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -d "$1" ]
|
||||
then
|
||||
echo "creating $2 from $1"
|
||||
(cd "$1"; find . | cpio -o -H newc | gzip) > "$2"
|
||||
else
|
||||
echo "First argument must be a directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
Note: The cpio man page contains some bad advice that will break your initramfs
|
||||
archive if you follow it. It says "A typical way to generate the list
|
||||
of filenames is with the find command; you should give find the -depth option
|
||||
to minimize problems with permissions on directories that are unwritable or not
|
||||
searchable." Don't do this when creating initramfs.cpio.gz images, it won't
|
||||
work. The Linux kernel cpio extractor won't create files in a directory that
|
||||
doesn't exist, so the directory entries must go before the files that go in
|
||||
those directories. The above script gets them in the right order.
|
||||
|
||||
External initramfs images:
|
||||
--------------------------
|
||||
|
||||
If the kernel has initrd support enabled, an external cpio.gz archive can also
|
||||
be passed into a 2.6 kernel in place of an initrd. In this case, the kernel
|
||||
will autodetect the type (initramfs, not initrd) and extract the external cpio
|
||||
archive into rootfs before trying to run /init.
|
||||
|
||||
This has the memory efficiency advantages of initramfs (no ramdisk block
|
||||
device) but the separate packaging of initrd (which is nice if you have
|
||||
non-GPL code you'd like to run from initramfs, without conflating it with
|
||||
the GPL licensed Linux kernel binary).
|
||||
|
||||
It can also be used to supplement the kernel's built-in initamfs image. The
|
||||
files in the external archive will overwrite any conflicting files in
|
||||
the built-in initramfs archive. Some distributors also prefer to customize
|
||||
a single kernel image with task-specific initramfs images, without recompiling.
|
||||
|
||||
Contents of initramfs:
|
||||
----------------------
|
||||
|
||||
An initramfs archive is a complete self-contained root filesystem for Linux.
|
||||
If you don't already understand what shared libraries, devices, and paths
|
||||
you need to get a minimal root filesystem up and running, here are some
|
||||
references:
|
||||
|
@ -176,13 +242,36 @@ code against, along with some related utilities. It is BSD licensed.
|
|||
|
||||
I use uClibc (http://www.uclibc.org) and busybox (http://www.busybox.net)
|
||||
myself. These are LGPL and GPL, respectively. (A self-contained initramfs
|
||||
package is planned for the busybox 1.2 release.)
|
||||
package is planned for the busybox 1.3 release.)
|
||||
|
||||
In theory you could use glibc, but that's not well suited for small embedded
|
||||
uses like this. (A "hello world" program statically linked against glibc is
|
||||
over 400k. With uClibc it's 7k. Also note that glibc dlopens libnss to do
|
||||
name lookups, even when otherwise statically linked.)
|
||||
|
||||
A good first step is to get initramfs to run a statically linked "hello world"
|
||||
program as init, and test it under an emulator like qemu (www.qemu.org) or
|
||||
User Mode Linux, like so:
|
||||
|
||||
cat > hello.c << EOF
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
printf("Hello world!\n");
|
||||
sleep(999999999);
|
||||
}
|
||||
EOF
|
||||
gcc -static hello2.c -o init
|
||||
echo init | cpio -o -H newc | gzip > test.cpio.gz
|
||||
# Testing external initramfs using the initrd loading mechanism.
|
||||
qemu -kernel /boot/vmlinuz -initrd test.cpio.gz /dev/zero
|
||||
|
||||
When debugging a normal root filesystem, it's nice to be able to boot with
|
||||
"init=/bin/sh". The initramfs equivalent is "rdinit=/bin/sh", and it's
|
||||
just as useful.
|
||||
|
||||
Why cpio rather than tar?
|
||||
-------------------------
|
||||
|
||||
|
@ -241,7 +330,7 @@ the above threads) is:
|
|||
Future directions:
|
||||
------------------
|
||||
|
||||
Today (2.6.14), initramfs is always compiled in, but not always used. The
|
||||
Today (2.6.16), initramfs is always compiled in, but not always used. The
|
||||
kernel falls back to legacy boot code that is reached only if initramfs does
|
||||
not contain an /init program. The fallback is legacy code, there to ensure a
|
||||
smooth transition and allowing early boot functionality to gradually move to
|
||||
|
@ -258,8 +347,9 @@ and so on.
|
|||
|
||||
This kind of complexity (which inevitably includes policy) is rightly handled
|
||||
in userspace. Both klibc and busybox/uClibc are working on simple initramfs
|
||||
packages to drop into a kernel build, and when standard solutions are ready
|
||||
and widely deployed, the kernel's legacy early boot code will become obsolete
|
||||
and a candidate for the feature removal schedule.
|
||||
packages to drop into a kernel build.
|
||||
|
||||
But that's a while off yet.
|
||||
The klibc package has now been accepted into Andrew Morton's 2.6.17-mm tree.
|
||||
The kernel's current early boot code (partition detection, etc) will probably
|
||||
be migrated into a default initramfs, automatically created and used by the
|
||||
kernel build.
|
||||
|
|
Loading…
Reference in New Issue