全部博文(43)
分类: LINUX
2011-12-01 19:07:55
上 面简要介绍了Linux2.4内核和2.6内核的initrd的处理流程,为了使读者对于Linux2.6内核的initrd的处理有一个更加深入的认 识,下面将对Linuxe2.6内核初始化部分同initrd密切相关的代码给予一个比较细致的分析,为了讲述方便,进一步明确几个代码分析中使用的概 念:
rootfs: 一个基于内存的文件系统,是linux在初始化时加载的第一个文件系统,关于它的进一步介绍可以参考文献[4]。
initramfs: initramfs同本文的主题关系不是很大,但是代码中涉及到了initramfs,为了更好的理解代码,这里对其进行简单的介绍。Initramfs 是在 kernel 2.5中引入的技术,实际上它的含义就是:在内核镜像中附加一个cpio包,这个cpio包中包含了一个小型的文件系统,当内核启动时,内核将这个 cpio包解开,并且将其中包含的文件系统释放到rootfs中,内核中的一部分初始化代码会放到这个文件系统中,作为用户层进程来执行。这样带来的明显 的好处是精简了内核的初始化代码,而且使得内核的初始化过程更容易定制。Linux 2.6.12内核的 initramfs还没有什么实质性的东西,一个包含完整功能的initramfs的实现可能还需要一个缓慢的过程。对于initramfs的进一步了解 可以参考文献[1][2][3]。
cpio-initrd: 前面已经定义过,指linux2.6内核使用的cpio格式的initrd。
image-initrd: 前面已经定义过,专指传统的文件镜像格式的initrd。
realfs: 用户最终使用的真正的文件系统。
内 核的初始化代码位于 init/main.c 中的 static int init(void * unused)函数中。同initrd的处理相关部分函数调用层次如下图,笔者按照这个层次对每一个函数都给予了比较详细的分析,为了更好的说明,下面列 出的代码中删除了同本文主题不相关的部分:
init函数是内核所有初始化代码的入口,代码如下,其中只保留了同initrd相关部分的代码。
代码[1]:populate_rootfs函数负责加载initramfs和cpio-initrd,对于populate_rootfs函数的细节后面会讲到。
代码[2]:如果rootfs的根目录下中包含/init进程,则赋予execute_command,在init函数的末尾会被执行。否则执行prepare_namespace函数,initrd是在该函数中被加载的。
代码[3]:将控制台设置为标准输入,后续的两个sys_dup(0),则复制标准输入为标准输出和标准错误输出。
代 码[4]:如果rootfs中存在init进程,就将后续的处理工作交给该init进程。其实这段代码的含义是如果加载了cpio-initrd则交给 cpio-initrd中的/init处理,否则会执行realfs中的init.读者可能会问:如果加载了cpio-initrd, 那么realfs中的init进程不是没有机会运行了吗?确实,如果加载了cpio-initrd,那么内核就不负责执行realfs的init进程了, 而是将这个执行任务交给了cpio-initrd的init进程。解开fedora core4的initrd文件,会发现根目录的下的init文件是一个脚本,在该脚本的最后一行有这样一段代码:
……….. switchroot --movedev /sysroot |
就是switchroot语句负责加载realfs,以及执行realfs的init进程。
对cpio-initrd的处理
对cpio-initrd的处理位于populate_rootfs函数中。
代码[1]:加载initramfs, initramfs位于地址__initramfs_start处,是内核在编译过程中生成的,initramfs的是作为内核的一部分而存在的,不是 boot loader加载的。前面提到了现在initramfs没有任何实质内容。
代码[2]:判断是否加载了initrd.无论哪种格式的initrd,都会被boot loader加载到地址initrd_start处。
代码[3]:判断加载的是不是cpio-initrd.实际上 unpack_to_rootfs有两个功能一个是释放cpio包,另一个就是判断是不是cpio包, 这是通过最后一个参数来区分的, 0:释放 1:查看。
代码[4]:如果是cpio-initrd则将其内容释放出来到rootfs中。
代码[5]:如果不是cpio-initrd,则认为是一个image-initrd,将其内容保存到/initrd.image中。在后面的image-initrd的处理代码中会读取/initrd.image.
对image-initrd的处理在prepare_namespace函数里,包含了对image-initrd进行处理的代码,相关代码如下:
代码[1]:执行initrd_load函数,将initrd载入,如果载入成功的话initrd_load函数会将realfs的根设置为当前目录。
代码[2]:将当前目录即realfs的根mount为Linux VFS的根。initrd_load函数执行完后,将真正的文件系统的根设置为当前目录。