The Difference Between Initrd and Initramfs

The difference between initrd and initramfs?


Dentry (and inode) cache

Filesystem subsystem in Linux has three layers. The VFS (virtual filesystem), which implements the system calls interface and handles crossing mountpoints and default permission and limits checks. Below it are the drivers for individual filesystems and those in turn interface to drivers for block devices (disks, memory cards, etc.; network interfaces are exception).

The interface between VFS and filesystem are several classes (it's plain C, so structures containing pointers to functions and such, but it's object-oriented interface conceptually). The main three classes are inode, which describes any object (file or directory) in a filesystem, dentry, which describes entry in a directory and file, which describes file open by a process. When mounted, the filesystem driver creates inode and dentry for it's root and the other ones are created on demand when process wants to access a file and eventually expired. That's a dentry and inode cache.

Yes, it does mean that for every open file and any directory down to root there has to be inode and dentry structures allocated in kernel memory representing it.

Page cache

In Linux, each memory page that contains userland data is represented by unified page structure. This might mark the page as either anonymous (might be swapped to swap space if available) or associate it with inode on some filesystem (might be written back to and re-read from the filesystem) and it can be part of any number of memory maps, i.e. visible in address space of some process. The sum of all pages currently loaded in memory is the page cache.

The pages are used to implement mmap interface and while regular read and write system calls can be implemented by the filesystem by other means, majority of interfaces uses generic function that also uses pages. There are generic functions, that when file read is requested allocate pages and call the filesystem to fill them in, one by one. For block-device-based filesystem, it just calculates appropriate addresses and delegates this filling to the block device driver.

ramdev (ramdisk)

Ramdev is regular block device. This allows layering any filesystem on top of it, but it is restricted by the block device interface. And that has just methods to fill in a page allocated by the caller and write it back. That's exactly what is needed for real block devices like disks, memory cards, USB mass storage and such, but for ramdisk it means, that the data exist in memory twice, once in the memory of the ramdev and once in the memory allocated by the caller.

This is the old way of implementing initrd. From times when initrd was rare and exotic occurence.

tmpfs

Tmpfs is different. It's a dummy filesystem. The methods it provides to VFS are the absolute bare minimum to make it work (as such it's excellent documentation of what the inode, dentry and file methods should do). Files only exist if there is corresponding inode and dentry in the inode cache, created when the file is created and never expired unless the file is deleted. The pages are associated to files when data is written and otherwise behave as anonymous ones (data may be stored to swap, page structures remain in use as long as the file exists).

This means there are no extra copies of the data in memory and the whole thing is a lot simpler and due to that slightly faster too. It simply uses the data structures, that serve as cache for any other filesystem, as it's primary storage.

This is the new way of implementing initrd (initramfs, but the image is still called just initrd).

It is also the way of implementing "posix shared memory" (which simply means tmpfs is mounted on /dev/shm and applications are free to create files there and mmap them; simple and efficient) and recently even /tmp and /run (or /var/run) often have tmpfs mounted especially on notebooks to keep disks from having to spin up or avoid some wear in case of SSDs.

What is contained in Android's init on initrd.img?

Here's a brief explanation of android bootup and init

  • On android bootup , the bootloader locates and loads the linux
    kernel. The linux kernel boots into the userspace from the
    kernelspace using the initramfs functionality in the kernel.
  • The ramdisk is essentially a disk image that contains everything
    associated with the root filesystem of the device, essentially the '/
    ' directory. The initramfs mounts the ramdisk into memory ( a
    temporary filesystem ) .
  • Later, initramfs looks into the memory and loads and executes the
    init binary. The ramdisk.img has C files which configure what init
    does .
  • Init is the first process executed in the userspace which is
    responsible for getting the core userspace functionality up and
    running.
  • initrc files , the ones responsible for configuring what init
    actually does have set of instructions with scripts which run on
    certain event triggers ( such as on init, on fs, on boot).
  • init keeps on running and monitors the system for certain changes in
    the properties (triggers). Instructions associated with these
    triggers are executed upon change in the properties. (Such as USB Debugging on/off)
  • Additionally, init executes native processes called services
    which are essentially daemons such as installd, logd, ueventd etc. init also restarts services that may exit/killed. Daemon processes
    have limited ability to communicate to each other and use local
    sockets to read and write data from.

To read further you can refer here and this youtube video

If I build linux kernel from source, does it contain initramfs inside by default?


If I build linux kernel from source, does it contain initramfs inside by default?

Yes, but it will be empty (by default).

As stated in Documentation/filesystems/ramfs-rootfs-initramfs.txt:

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).

You can populate the initramfs with either an internal or external cpio archive.

Use CONFIG_INITRAMFS_SOURCE to point to a cpio archive file, which will be embedded into the kernel image.

Otherwise an (external) cpio archive file can be specified during boot by using the old initrd mechanism.

If an initrd/initramfs is passed to the arm64 kernel at boot, it must reside entirely within a 1 GB aligned physical memory window of up to 32 GB in size that fully covers the kernel Image as well.


The cpio archive needs to contain an init file in order to inhibit the further processing for mounting a root filesystem. As documented:

After extracting, the kernel checks to see if rootfs contains a file "init",
and if so it executes it as PID 1.
If found, this init process is responsible for bringing the system the
rest of the way up, including locating and mounting the real root device (if
any).
If rootfs does not contain an init program after the embedded cpio
archive is extracted into it, the kernel will fall through to the older code
to locate and mount a root partition, then exec some variant of /sbin/init
out of that.

Busybox can be built to provide that init file.


ADDENDUM

I had found CONFIG_INITRAMFS_SOURCE value in my old .config file (year 2013~2014) was set to just empty (set to " ").

A string of a single space does not make sense.

Did you mean an empty string, as in "" which is the default value?
The default value means that no archive for the initramfs is to be built with the kernel image.

Now I just now found CONFIG_RD_GZIP=y too in the file.

That simply enables support for loading of a gzip-encoded initial ramdisk or cpio buffer. It is just one of several compression methods available that can be configured. There could also be support for bzip2, LZMA, XZ, LZO, and LZ4.

The salient configuration symbol would be CONFIG_BLK_DEV_RAM, which would enable RAM disk support.

At that time we put busybox120.gz file under arch/sparc/boot before doing linux 'make sImage'. so I guess when there is a .gz file under arch/sparc/boot, the kernel build system uses that .gz file as the initramfs.

No, simply storing a file in a directory is not going to cause inclusion in the kernel build.

Since no initramfs file is specified, the likeliest use of that busybox120.gz file would be for a ramdisk.

Archives are typically named with .cpio or .tar filename extensions. Your file has neither, so that could mean that it is not an archive. The absence of an archive extension could mean that it is an image file, which would never be used for a ramfs but could be used for a ramdisk (or initrd).

AFAIK an image (or archive) for the initrd is loaded by the boot program (ref: Using the initial RAM disk (initrd)) rather than linked in.

Check the kernel command line used with that kernel image.

Are there parameters that specify a ramdisk, e.g. initrd=... and/or root=/dev/ram0?

Be sure that you do not conflate initramfs and initrd. See Documentation/filesystems/ramfs-rootfs-initramfs.txt and
The difference between initrd and initramfs?

Is it possible to boot the Linux kernel without creating an initrd image?

initrd/initramfs is optional and not a requirement. bzImage is the pure kernel image and can be booted directly by the bootloader. However it might be neccesary to execute some tasks (loading filesystem modules, drivers for disk access, mounting the root file system from some exchangeable media without fixed name/path, etc.) that would usually require access to a filesystem and userspace tools.

That's what initramfs is for: It is a CPIO archive that gets attached to the kernel image (the kernel image is the container for the initramfs not other way round) either in the kernel image itself, or by the bootloader at boot time.

That CPIO archive contains an initial rootfs with the modules required to setup all devices to access the proper root filesystem and some programs to identify those devices, load the modules, do some other startup tasks remount the proper root file system to / and start /sbin/init

initrd is similar, with the main difference that it is an filesystem image, that may be and usually is compressed. The kernel must have support for the filesystem used built in and will mount this image as the initial /.

Since CPIO is simpler by several orders of magnitudes, initramfs is prefered over initrd, as this saves both the requirement for any filesystem modules being built in and also makes initramfs creation easier. Instead of having to create an ext2 image, loopdevice mount and populate it, it boils down to a simple archive creation, not unlike using tar.

However if you compile your kernel with all required drivers and modules built into the kernel image, and your root file system device has a fixed name in the system you don't need a initramfs as the kernel can do things by itself then.



Related Topics



Leave a reply



Submit