Linux系统内存磁盘初始化技术详细解析

JavaGG 发布于 2009/05/07 11:20
阅读 703
收藏 1

Linux内存初始化技术(initrd)用于支持两阶段的系统引导过程,是在系统启动过程中被挂载的临时root文件系统(译者注:这里的root文件系统是指的根文件系统)。initrd包含很多可执行程序和驱动,并允许在临时的内存磁盘根文件系统被卸载,内存被释放后挂载真实的root文件系统。在许多嵌入式Linux文件系统中,initrd是最终的根文件系统。这篇文章主要讲解了linux2.6内核的initrd技术,包括在内核中的创建及使用。
1 什么是内存磁盘初始化?
initrd挂载优先级高于真实根文件系统,它被邦定在内核上,做为内核启动过程的一部分被加载(load)。然后,做为两阶段引导过程的第一部分,内核挂载(mount)initrd,用于获得并加载真实有效的文件系统。
为了达到这个目的,initrd包含有最起码的目录与程序,例如insmod,来安装内核模块到内核中。
对于桌面或服务器linux,initrd是临时文件系统,它的生存周期很短,仅仅是做为到达真实根文件系统的桥梁。但对于没有存储设备的嵌入式系统来说,它才是永久性的根文件系统。本篇文章对这两方面均有涉及。
2 深入分析initrdL
initrd包含有必须的程序和系统文件,用于支持系统的启动的第二阶段过程。创建初始化内存的方法,是随着你所使用的系统版本而改变的。从Fedora Core3以后,initrd就由回送设备(loop device)建立。什么是回送设备?它是一个设备驱动,允许你将一个文件挂载为块设备,并对其文件系统做出描述。也许loop device并不存在与你的内核中,但是你能够通过内核的配置工具(make menuconfig)打开它。路径是:Device Drivers-》Block Devices-》LoopBack Device support。下面为检查命令:

# mkdir temp ; cd temp 

# cp /boot/initrd.img.gz . 

# gunzip initrd.img.gz 

# mount -t ext -o loop initrd.img /mnt/initrd 

# ls -la /mnt/initrd 

#
现在,你可以通过查看/mnt/initrd的子目录来查看initrd的内容。需要注意的是,即使你的initrd镜像文件并不是以.gz做为后缀名,但是你同样可以通过增加此后缀名来让gunzip打开它。
从Fedora Core3开始,默认的initrd镜像就是一个压缩的gpio归档文件。除了用挂载文件的方式以外,你同样可以通过cpio归档的方式来将其挂载成使用了回送设备的压缩镜像。你可以通过以下的指令来检查这个cpio归档文件的内容:
# mkdir temp ; cd temp 

# cp /boot/initrd-2.6.14.2.img initrd-2.6.14.2.img.gz 

# gunzip initrd-2.6.14.2.img.gz 

# cpio -i --make-DirectorIEs < initrd-2.6.14.2.img
你看到的结果将是一个小型根文件系统,如下所示:
# ls -la 

# 

drwxr-xr-x 10 root root 4096 May 7 02:48 . 

drwxr-x--- 15 root root 4096 May 7 00:54 .. 

drwxr-xr-x 2 root root 4096 May 7 02:48 bin 

drwxr-xr-x 2 root root 4096 May 7 02:48 dev 

drwxr-xr-x 4 root root 4096 May 7 02:48 etc 

-rwxr-xr-x 1 root root 812 May 7 02:48 init 

-rw-r--r-- 1 root root 1723392 May 7 02:45 initrd-2.6.14.2.img 

drwxr-xr-x 2 root root 4096 May 7 02:48 lib 

drwxr-xr-x 2 root root 4096 May 7 02:48 loopfs 

drwxr-xr-x 2 root root 4096 May 7 02:48 proc 

lrwxrwxrwx 1 root root 3 May 7 02:48 sbin -> bin 

drwxr-xr-x 2 root root 4096 May 7 02:48 sys 

drwxr-xr-x 2 root root 4096 May 7 02:48 sysroot 

#
一些小的,但是很有必要的程序组合能在./bin目录下得到,包括nash(它不是一个shell,而是一个脚本解释工具),用于加载内核模块的insmod,以及lvm等。
上面所示目录中,相对比较有趣的是root目录下的初始化文件。这些文件,和传统的linux启动过程中一样,是在initrd镜像被解压缩到RAM中时生成的。待会我们将继续探讨这个问题。
3 创建initrd的工具。
现在,让我们回到一开始的讨论:initrd的镜像是如何被创建的?在传统的linux系统中,initrd是在linux build的时候被创建的。像mkinitrd这样的许许多多的工具,都能够用于通过必须的库和模块来自动构建一个用于过渡到真实根文件系统的initrd。事实上,mkinitrd工具是一个脚本文件,因此,我们能够很清楚得看到,这个过程是如何进行的。同样的,YAIRD (Yet Another Mkinitrd)工具,也允许我们自定制每一个initrd被构建的阶段。
4 自己动手,打造自定义的初始化内存盘
由于很多基于linux的嵌入式系统都没有硬盘驱动器,initrd也可以做为永久性的根文件系统。下面我就将告诉你们,如何创建一个initrd镜像。我使用的是标准linux桌面系统,因此大家即使没有嵌入式目标设备也可以照着做。除了交叉编译以外,嵌入式目标文件的构建过程是相同的。
#!/bin/bash 

# Housekeeping... 

rm -f /tmp/ramdisk.img 

rm -f /tmp/ramdisk.img.gz 

# Ramdisk Constants 

RDSIZE=4000 

BLKSIZE=1024 

# Create an empty ramdisk image 

dd if=/dev/zero of=/tmp/ramdisk.img bs=$BLKSIZE count=$RDSIZE 

# Make it an ext2 mountable file system 

/sbin/mke2fs -F -m 0 -b $BLKSIZE /tmp/ramdisk.img $RDSIZE 

# Mount it so that we can populate 

mount /tmp/ramdisk.img /mnt/initrd -t ext2 -o loop=/dev/loop0 

# Populate the filesystem (subDirectorIEs) 

mkdir /mnt/initrd/bin 

mkdir /mnt/initrd/sys 

mkdir /mnt/initrd/dev 

mkdir /mnt/initrd/proc 

# Grab busybox and create the symbolic links 

pushd /mnt/initrd/bin 

cp /usr/local/src/busybox-1.1.1/busybox . 

ln -s busybox ash 

ln -s busybox mount 

ln -s busybox echo 

ln -s busybox ls 

ln -s busybox cat 

ln -s busybox ps 

ln -s busybox dmesg 

ln -s busybox sysctl 

popd 

# Grab the necessary dev files 

cp -a /dev/console /mnt/initrd/dev 

cp -a /dev/ramdisk /mnt/initrd/dev 

cp -a /dev/ram0 /mnt/initrd/dev 

cp -a /dev/null /mnt/initrd/dev 

cp -a /dev/tty1 /mnt/initrd/dev 

cp -a /dev/tty2 /mnt/initrd/dev 

# Equate sbin with bin 

pushd /mnt/initrd 

ln -s bin sbin 

popd 

# Create the init file 

cat >> /mnt/initrd/linuxrc << EOF 

#!/bin/ash 

echo 

echo "Simple initrd is active" 

echo 

mount -t proc /proc /proc 

mount -t sysfs none /sys 

/bin/ash --login 

EOF 

chmod +x /mnt/initrd/linuxrc 

# Finish up... 

umount /mnt/initrd 

gzip -9 /tmp/ramdisk.img 

cp /tmp/ramdisk.img.gz /boot/ramdisk.img.gz
想创建initrd的话,你需要首先创建一个空文件,将/dev/zero(0字符流)做为ramdisk.img的输入。得到的文件大小大约是4MB(有4000个1K的块组成)。接下来,用mke2fs命令来创建一个使用这个空文件的ext2文件系统。现在,这个文件就是一个ext2文件系统。ok,接下来,以回路设备的形式挂载这个文件到/mnt/initrd,现在,你就在挂载点拥有一个代表着ext2文件系统的目录,并用与存放你的initrd。其他大多数的脚本语句都是用于实现这个功能。
下一步,就是创建一些必须的子目录,用于生成你的根文件系统: /bin, /sys, /dev, 和 /pro。这里只需要少数几个目录,例如,没有/lib。但是它们已经包含了大部分功能。
如果想让你的根文件系统发挥更大的作用,请使用 BusyBox。这个工具是一个包含了许多独立工具的镜像,这些独立的工具你都能在linux中找到( ash, a等等wk, sed, insmod)。BusyBox的优势在于,它把它们集合在了一起,并分享了公用的部分,从而极大缩小了镜像的体积。这对于嵌入式系统来讲,是非常理想的。请将BustBox镜像从它的源目录中复制出来,到你的/bin目录下,这样,很多指向BusyBox工具集的符号链接将被创建,BusyBox能确定哪一个工具将被使用,并自动引用它。这个/bin目录下被创建的链接的小型集合将用于对启动脚本的支持。
再下一步,就是一小部分特殊设备文件的创建。我从我的/dev文件夹中直接拷贝了出来,别忘了加上-a选项来保持它们原有的属性。
倒数第二步,就是生成linuxrc文件。在内核挂载了内存盘之后,它将搜索并执行相关的启动文件,如果没有找到,内核就将linuxrc文件做为其启动脚本。你最好在这个文件中对环境变量做一些基本设置,例如挂载/proc文件系统等。除了/proc外,我还挂载了/sys文件系统,将消息发送给终端。最后,我调用ash并通过它和根文件系统交互。最后记住,用chmod把linuxrc文件的属性改为可执行。
最后,你的根文件系统算是ok了。现在它并没有被挂载,用gzip将它压缩,并将压缩后的文件ramdisk.img.gz拷贝到/boot目录下,这样它就能被GRUB调用。
想要构建你的初始化ram盘的话,你只需要调用mkird,镜像就将自动创建并拷贝到/boot目录下。
相关文章:
Linux内存映射技术 新专题:揭秘Linux内存管理 (T002)

加载中
返回顶部
顶部