123456781234567812345678123456781234567812345678123456781234567812345678
On Tue Mar 29 05:31:49 PST 2005, Rachita Kothiyal rachitako at
in.ibm.com asked:> 1. Is it possible to load an initrd from initramfs ?
> How would you do this if the initramfs is being loaded dynamically
> in the kernel (ie having the initramfs as initrd )
> Because in this case, you will say root = /dev/initrd and specify
> 'initrd' as your 'initramfs source file'
> How will you specify the second initrd source?
Yes, it is possible. You would have to wrap the initrd as a cpio
fragment creating /initrd, which is where the kernel puts all the
initrd data when the test for initramfs fails. [ok, there's another]
The test for /init is separate, however if that is found then the
kernel will not load the initrd into /dev/ram*. Read on ...
and on Tue Mar 29 06:11:22 PST 2005 Rachita asked:> 1. Had one more basic query, how are initrd and initramfs different ?
>
> Of what I understand, the following are the differnces:
>
> a. initrd's format is ext2 filesysstem(compressed) while that of
> initramfs is compressed cpio(newc) archive.
> But when we are loading the initramfs dynamically, we are inturn
> using initrd...
The initrd format is a block device image that is copied by the kernel
into a ram disk device at the end of the boot sequence. The kernel
recognizes about half a dozen formats to read a specified number of
blocks (common code with multi-floppy loading) or the data can be
compressed and be any file system compiled into the kernel. Some file
systems require additional arguments to work (e.g. rootffstyperootflags= and the
ramdisk block size flag) since ramdisks can not
have their block sizes changed once initialized).
The initramfs format is a series of newc format compatible cpios, each
optionally compressed. The contents are unpacked into the kernels
rootfs, a variant of ramfs which serves as the root of all mount trees.
The kernel uncompresses and unpacks initramfs into rootfs before any
driver initcalls are made.
A design goal for initramfs was that independent pieces could be loaded
by a suitably intelligent boot loader. Rather than require all
architectures to add yet another mechanism to the boot loaders to pass
the initramfs data, which would hinder deployment, and noting that the
initramfs intends to make initrd redundant, the choice was made to have
the kernel scan the initrd image, and if it meets the requirements for
an initramfs, for it to be treated as such and unpacked. Otherwise the
data is copied into rootfs as /initrd for later handling. In either
case the initrd area is freed at this point in the boot sequence.
Actually, there are two sources for initramfs data. One is the
always-linked in cpio built in usr/, and the second is the
overloaded initrd mechanism. Since the former is always built and
is unpacked first, and the unpack decision is independent of the
/init, one could use the new mechanism and load their /init via the
config option and leave the initrd as a traditional image without a
cpio wrapper.
> b. initramfs gets unpacked and comes into action a little earlier than
> initrd..in linux-src/init/main.c:init()....initramfs does not do
> prepare_namespace() at all while initrd goes thru it.
True. Actually, prepare_namespace contains the code to handle the
initrd semantics. When /init exists, everything in prepare_namespace
that is required must be implemented by /init and its friends in the
initramfs. Well, it is possible today to load files for drivers in
rootfs and not create /init, allowing prepare_namespace to run. However,
after boot those files will remain inaccessible but taking up space in
ram.
> 2. How is initramfs better over initrd? Isnt it just redundant? What
> are we achiveing by initramfs that initrd does not provide ?
Since the data is unpacked earlier, in theory a driver could do
request_firmware() and it could succeed during the boot process. I say
in theory because I have not heard anyone actually use this, and I am
worried that all the "oops this is too early to call exec" patches
have
caused us to delay the agent exec to beyond the point its results are
needed. [The other approach is to load the driver as a module.]
Everything done in prepare_namespace() and beyond can be done in user
space. Some of that code is rather complex (specifically the nfs mount
code, the ip dhcp code it brings along with it, and the raid volume
discovery code). Moving it to userspace reduces the constraints for
adding new features to this code (did you say you wanted to encrypt your
root?)
Another feature of initramfs is a boot loader could be told to load only
the pieces you need (don't load the nfs code on a disk boot, don't load
disk drivers on a net boot). This could reduce the memory demand.
Removing the dependancy of CONFIG_INITRD on CONFIG_BLOCK_DEV_RAM, one
can remove the ramdisk driver if it is not otherwise required.
Since the initramfs can contain several independent pieces, a fragment
can be specified that overwrites a file previously supplied. There are
a few limitations, however. Symlink semantics mean that you can not
overwrite it (only affect its target), and the current implementation
does not truncate the file before filling it, resulting in trailing
remans of the previous file when overwriting with a smaller file. While
most binary formats work in this situation, config files and shell
scripts may not behave as expected.
You didn't ask the reverse, what have we lost. One feature that was
lost was the ability to defer the interpretation of the initrd data to
user programs on the "real root" with a read-once policy (by
specifying
noinitrd and reading /dev/initrd). Yes, one could code that with a init
in initramfs that moved the /initrd file, but that is not implemented.
A second observation is that memory may be more fragmented during driver
initialization, since the initrd area is copied into ram (and, if
initramfs, uncompressed), potentially making large contiguous
allocations fail. This effect is more pronounced when the initrd is
stored in directly mapped flash (as arm can do). I haven't heard of
this as a problem in real life, although I also don't follow many
embedded discussion lists.
> 3. Like in the case of initramfs, even in the case of initrd, it is
> mounted
> as root. Then why do we pass root=/dev/initrd in case of initramfs
> while
> root=<root_device> incase of initrd?
Actually, initramfs is not mounted as root. initramfs is expanded into
the root that is already mounted. The difference is that you can not
pivot_root and unmount it. (Well, you can try, but the kernel breaks).
Regarding root=, both /dev/ram0 and <root_device> can be passed to the
kernel in the case of initrd, although they imply different execution
environments (the latter are for the older, deprecated practice of
running /linuxrc on the initrd which allows /proc/real-root-device to
change root=, while the former says make this the root device, with
provision to change it later via pivot_root).
If the rootfs contains /init, which today implies one of the initramfs
mechanisms populated it, and which is how the new mechanism to avoid
prepare_namespace is triggered, then the kernel never uses the rootparameter, so
its value is arbitrary. It is this init's responsibility
to look for /initrd and deal with it as desired. Also, /dev/initrd has
not existed for a few revisions of 2.6.
Hmm... it occurs to me that the sample kinit code may not fall back to
/proc/real-root-device when root= is not specified ...
I hope this answered your questions. I've been using initramfs and
rootfs as my root file system in one applicatioin for 2 full years, back
when one had to patch out the call to prepare_namespace, and have a
"bootloader" for my environment that allows me to choose each boot
what
pieces are loaded. The separate pieces feature has allowed significant
time savings both in time spent building file systems, and in time spent
not loading pieces that are not required for the specific test run.
Loading with the initrd mechanism has saved many links of the kernel
since it went in.
milton