快捷搜索:   服务器  安全  linux 安全  MYSQL  dedecms

精通initramfs构建stepbystep(十二)

    三十五、测试一下

  通过前十一节的内容,我们可以说已经完全掌握了init ramfs构建的方法,那么现在就测试一下,拿一个实际的init ramfs来分析,看我们是否能理解多少。

  我们选择Debian 4.0 AMD64 版本的init ramfs作为目标进行分析,它的init ramfs文件是initrd.img-2.6.18-6-amd64。首先用cpio命令把init ramfs文件解开,然后打开其中的init脚本文件具体分析。好了,大家利用前面各节的知识开始吧。

  作为提示,在这里转载一篇文章,来自http://blog.chinaunix.net/u/12679/showart_429816.html:

  initrd执行顺序

  这是安装过程中的笔记,放这里希望对大家有用。错误之处请指正。

  (系统为debian etch, 以安装后默认的initrd.img-2.6.18-5为例)

  解开initrd文件:

  例如有initrd文件/boot/initrd.img, 用file命令看到这是个gzip压缩的文件,可以用下面的命令解开查看:

  代码:

  mkdir /boot/myinit

  cd /boot/myinit

  zcat ../initrd.img | cpio -id(注:用mkinitrd命令默认产生的是cramfs格式的。如果文件格式是压缩的ramfs文件系统,可以直接mount之后查看:mount -t cramfs /boot/initrd.img /mnt/)

  如果是2.6内核,因为采用的是cpio压缩,方法如下:

  cp /boot/initrd-***.img initrd.img.gz

  gunzip initrd.img.gz

  mkdir initrd

  mv initrd.img initrd

  cd initrd

  cpio -mdiv < initrd.img

  在当前目录下就有一些目录和文件init,其中文件init是启动时加载initrd之后执行的脚本。

  目录结构:

  /bin/: 文件有busybox, mknod, sh, uname, cat, mount, pivot_root等

  --------/sbin/: 文件有modprobe, depmod, udevd, udevdtrigger

  --------/lib/: 文件有:

  ----------------(1) 可执行文件需要的动态库

  ----------------(2) modules/: 内核模块

  ----------------(3) udev/: udev需要的可执行文件

  --------/lib64/: 文件有:x86_64程序装载器

  --------/etc/: 与modprobe, udev相关的配置文件

  --------/conf/: 有如下的文件

  ----------------(1) modules: 列出了需要加载的模块

  ----------------(2) arch.conf: 设置变量DPKG_ARCH=amd64

  ----------------(3) initramfs.conf: 定义了一些变量

  --------/scripts/:

  ----------------有如下的文件:

  ----------------functions: 定义了一些方便使用的函数

  ----------------local和nfs: mount根目录时执行的脚本,一般mount本地系统,执行local

  ----------------有如下的目录,其中放置各阶段执行的脚本:

  ----------------init_top/

  ----------------init_premount/

  ----------------init_bottom/

  ----------------local_top/

  ----------------local_premount/

  ----------------local_bottom/

  --------/init: 启动时加载initrd之后执行的脚本

  生成initrd文件:

  find . |cpio -o --dereference -H newc | gzip -9 > ../initrd.img

  init文件执行流程:

  --------1) 创建目录/dev, /root, /sys, /proc, /tmp, /var/lock,其中/root是下面根文件系统要mount的位置

  --------2) mount系统proc和sys

  --------3) 执行脚本/etc/udev/udev.conf,仅定义变量

  --------4) mount udev设备:mount -t tmpfs -o size= udev /dev

  --------5) 创建/dev/console, /dev/null, /dev/.initramfs

  --------6) 导入/conf目录下的initramfs.conf, /conf/conf.d/目录以及/scripts/functions定义的变量和函数, 并且根据传递的内核参数设置相应的变量,其中比较重要的变量有:

  ----------------a) rootdelay=<时间>, 加载根文件系统前等待的时间。如果根文件系统在U盘上,一定要在这里或在grub的kernel后加上这个参数,等待发现U盘后再mount根文件系统,否则会出现找不到根文件系统的错误.

  ----------------b) panic=<时间> 系统panic后,隔多长时间再reboot。当你试验新内核或新initrd,经常panic而不想按开机按钮时可以加上这个参数

  --------7) depmod -a 在/lib/modules/<内核版本号>/目录下产生modules.dep文件

  --------8) 执行init_top目录下的脚本文件。这里只有一个framebuffer,它处理内核参数video=,vga=,splash等参数, 另外创建节点/dev/tty[0-8]

  --------9) 用modprobe按顺序加载/conf/modules列出的模块。注意,udev需要unix模块,否则会出现错误: udevd[606]: error initializing udev socket

  --------10) 执行/scripts/init-premount/下的脚本文件。

  -------------10.1) 文件thermal: 它根据DPKG_ARCH的不同值加载相应需要的模块,并且加载fan和thermal模块。

  -------------10.2) 文件udev: 执行如下过程:

  ------------------------a) mkdir -p /dev/.udev/db

  ------------------------b) udevd --daemon 以daemon形式启动udevd,大概用于监视hotplug设备的插拔

  ------------------------c) mkdir -p /dev/.udev/queue/ (不知道这两个mkdir的用途)

  ------------------------d) udevtrigger 对于coldplug的设备,(也就是开机前插入的设备),触发设备的uevents,以便内核处理

  ------------------------e) udevsettle 等待,直到内核uevents事件处理完

  --------11) 执行/scripts/local, 它完成mount根文件系统的过程:

  ----------------11.1) 首先执行local-top/目录下的脚本

  ------------------------11.1.1) 文件udev_helper:

  ----------------------------------a) 针对根文件系统设备(如通常的/dev/sda1, /dev/sda2等)不存在的情况,加载了模块ide_generic。我可以针对找不到硬盘的情况,加载模块aic94xx, sd_mod.

  ----------------11.2) 如果根文件系统设备还不存在,则年等待一段时间(默认180s),过了这段时间还找不到根文件系统设备就panic.

  ----------------11.3) 取得根文件系统的类型:先看有没有传递参数rootfstype=,如果没有就执行/bin/fstype,如果还不知道文件系统类型就执行/lib/udev/vol_id来取得文件系统类型。

  ----------------11.4) 执行local-premount/ 下的脚本:

  -------------------------11.4.1) 文件resume: (没看太懂)

  ------------------------------a) 处理传递的resume参数,它指定的是一个分区,格式为resume=LABEL=/dev/sda1或resume=UUID=xxx, 用于suspend to disk

  ----------------11.5) 根据文件系统类型加载相应的模块,例如如果根文件系统是ext2类型的,就加载ext2(如果没编译进内核)。

  ----------------11.6)mount根文件系统到/root上

  ----------------11.7) 执行local-bottom/下的脚本(这里没有脚本)。

  --------12) 执行init-bottom/下的脚本:

  ---------------12.1) 文件udev:

  ------------------------a) kill掉udevd

  ------------------------b) nuke /dev/.udev/queue/ (不知啥意思)

  ------------------------c) 执行/etc/udev/udev.conf 设置变量tmpfs_size=10M

  ------------------------d) mkdir /dev/.static/dev (注意,这个目录不是在硬盘上创建的)

  ------------------------e) mount -n -o bind /root/dev /dev/.static/dev 把真实文件系统的/dev目录下的node(在硬盘上) bind到/dev/.static/dev/下

  ------------------------f) mount -n -o move /dev /root/dev 把tmpfs类型的udev移到真实的文件系统的/dev下,(注意前面一开始就在/dev上mount了udev), 这时真实文件系统的/dev上mount了udev,而原来在硬盘的/dev目录下的node到了/dev/.static/dev下,实际上在硬盘上没有/dev/.static这个目录. (这个不太好理解)

  ------------------------g) nuke /dev (不知啥意思)

  ------------------------h) ln -s /root/dev /dev 前面mount -o move之后,目录/dev下什么也没了,这时/root还没真正成为根。这一步使得,如果其它脚本要使用/dev/下的设备文件时不至于找不到。

  --------13) mount -n -o move /sys /root/sys

  --------14) mount -n -o move /proc /root/proc

  --------15) exec run-init /root /sbin/init "$@" /root/dev/console 这一步应该是使真实文件系统成为根,并执行它的/sbin/init(没看懂)

  注:加载aic94xx时,需要从目录/usr/lib/hotplug/firmware或者/lib/udev/firmware下读入firmware数据,所以还要建立目录usr/lib/hotplug/firmware或者lib/udev/firmware (在initrd的根目录下,即/boot/myinit) ,然后,把aic94xx-seq.fw拷到任何一个目录中。 可以看出,如果把aic94xx编译进内核,就应把firmware数据也放进内核,但这个功能还没实现。参见内核文档Documentation/firmware_class/README的末尾。

顶(0)
踩(0)

您可能还会对下面的文章感兴趣:

最新评论