Chinaunix首页 | 论坛 | 博客
  • 博客访问: 537455
  • 博文数量: 105
  • 博客积分: 6010
  • 博客等级: 准将
  • 技术积分: 1132
  • 用 户 组: 普通用户
  • 注册时间: 2008-10-15 09:57
文章分类

全部博文(105)

文章存档

2011年(1)

2009年(41)

2008年(63)

我的朋友

分类: LINUX

2008-10-22 10:01:32


   在日常项目实施中,通常会对系统进行驱动的升级或添加新硬件,一般情况下,用mkinitrd命令。而该命令其实是一个脚本,是通过一系列的流程来生成系统启动需要的initrd.img文件。通过分析该文件,我们可以更清晰的知道系统启动时候加载驱动的顺序(用于调整HBA卡识别的设备符号),及修正或加入一些自定义的配置。

   在昨天的日志中,我已经对initrd的基本概念解释过,可以参照《2.6内核解压》。这里我就不做重复。那么,initrd这个文件既然有我们启动过程中所需要的信息,也能够引导启动,是否必须呢?可以说:initrd文件不是必须的,但是对于像redflag这样,需要具有适应在不同的硬件环境下使用,用initrd会比较方便。

   我们常在编译内核时,使用make menuconfig,其中对某些额外的驱动,可以选择编译成模块,也可以直接编译到内核中。例如:ext3文件系统驱动,如果核心需要放在该文件系统上 ,可以有两个方法:

 
第一:把其全部编译到内核中,则只是需要一个内核文件系统即可启动;第二:把其编译为模块,然后通过initrd虚拟的内存系统加载;

   也就是说,由于initrd会在内存虚拟一个文件系统,然后可以根据不同的硬件加载不同的驱动,而不需要重新编译整个内核;所以,大部分的发行版本都会通过这种方式对驱动进行加载。然而,又带来了一个问题,在编译内核上或是以某种内核环境来编译驱动模块时,会遇到是否是2.4内核还是2.6内核的问题,也就是内核版本问题。

   根据核心版本的不同,initrd文件有两种格式:image和cpio,2.4核心只使用image格式,而2.6核心可以同时支持两种格式。它们不单格式不一样,而且运作机制和流程也完全不同,甚至制作方法也不一样。
下面,针对redflag DC 4.1和redflag DC5.0上的initrd进行说明。(机器环境不同,配置信息有所不同;驱动模块也有所不同。)

2.4核心

   1,格式:2.4核心只能使用image格式,其一般是通过loop设备及gzip压缩生成(mkinitrd命令)。

   2,解压:以redflag DC4.1使用核心为例;

[root@samba test]# ls initrd-2.4.21-9.30AX.img

[root@samba test]# file initrd-2.4.21-9.30AX.img

initrd-2.4.21-9.30AX.img: gzip compressed data, from Unix, max compression

   
    可以看到,它是一个gzip压缩文件,需要先解压:

[root@samba test]# mv initrd-2.4.21-9.30AX.img initrd-2.4.21-9.30AX.img.gz

[root@samba test]# gunzip initrd-2.4.21-9.30AX.img.gz [root@samba test]# file initrd-2.4.21-9.30AX.img

initrd-2.4.21-9.30AX.img: Linux rev 1.0 ext2 filesystem data


   然后挂载:

[root@samba test]# mkdir /mnt/disk

[root@samba test]# mount -o loop initrd-2.4.21-9.30AX.img /mnt/disk/

  
   内容:
[root@samba test]# cd /mnt/disk/
[root@samba disk]# ls -lR
.:
total 8
drwxr-xr-x    2 root     root         1024 Jan 10  2006 bin
drwxr-xr-x    2 root     root         1024 Jan 10  2006 dev
drwxr-xr-x    2 root     root         1024 Jan 10  2006 etc
drwxr-xr-x    2 root     root         1024 Jan 10  2006 lib
-rwxr-xr-x    1 root     root          436 Jan 10  2006 linuxrc  <== 一个nash脚本
drwxr-xr-x    2 root     root         1024 Jan 10  2006 loopfs
drwxr-xr-x    2 root     root         1024 Jan 10  2006 proc
lrwxrwxrwx    1 root     root            3 Jan 10  2006 sbin -> bin
drwxr-xr-x    2 root     root         1024 Jan 10  2006 sysroot
./bin:
total 151
-rwxr-xr-x    1 root     root       122464 Jan 10  2006 insmod  <== 插入模块
lrwxrwxrwx    1 root     root           10 Jan 10  2006 modprobe -> /sbin/nash
-rwxr-xr-x    1 root     root        29524 Jan 10  2006 nash  <== 一个小型解释器
./dev:  <== 一些必要的设备文件
total 0
crw-r--r--    1 root     root       5,   1 Jan 10  2006 console
crw-r--r--    1 root     root       1,   3 Jan 10  2006 null
brw-r--r--    1 root     root       1,   1 Jan 10  2006 ram
crw-r--r--    1 root     root       4,   0 Jan 10  2006 systty
crw-r--r--    1 root     root       4,   1 Jan 10  2006 tty1
crw-r--r--    1 root     root       4,   2 Jan 10  2006 tty2
crw-r--r--    1 root     root       4,   3 Jan 10  2006 tty3
crw-r--r--    1 root     root       4,   4 Jan 10  2006 tty4
./etc:
total 0
./lib:   <== 启动时加载的模块
total 173
-rwxr--r--    1 root     root       108320 May 27  2004 ext3.o
-rwxr--r--    1 root     root        65888 May 27  2004 jbd.o
./loopfs:
total 0
./proc:
total 0
./sysroot:
total 0

   3,执行脚本,解压出来之后有一堆文件,其中需要了解的就是linuxrc文件:

[root@samba disk]# cat linuxrc
#!/bin/nash
echo "Loading jbd.o module"
insmod /lib/jbd.o
echo "Loading ext3.o module"
insmod /lib/ext3.o
echo Mounting /proc filesystem
mount -t proc /proc /proc
echo Creating block devices
mkdevices /dev
echo Creating root device
mkrootdev /dev/root
echo 0x0100 > /proc/sys/kernel/real-root-dev
echo Mounting root filesystem
mount -o defaults --ro -t ext3 /dev/root /sysroot
pivot_root /sysroot /sysroot/initrd
umount /initrd/proc

   现在看得很清楚,内容就是在挂载对应的驱动和目录,看上去的命令和普通的linux命令是一样的。

   4,执行流程:

1)boot loader把内核以及/dev/initrd的内容加载到内存,/dev/initrd是由bootloader初始化的设备,存储着initrd。

2)在内核初始化过程中,内核把 /dev/initrd 设备的内容解压缩并拷贝到 /dev/ram0 设备上。

3)内核以可读写的方式把 /dev/ram0 设备挂载为原始的根文件系统。

4)如果 /dev/ram0 被指定为真正的根文件系统,那么内核跳至最后一步正常启动。

5)执行 initrd 上的 /linuxrc 文件,linuxrc 通常是一个脚本文件,负责加载内核访问根文件系统必须的驱动, 以及加载根文件系统。

6)/linuxrc 执行完毕,真正的根文件系统被挂载。

7)如果真正的根文件系统存在 /initrd 目录,那么 /dev/ram0 将从 / 移到 /initrd。否则如果 /initrd 目录不存在, /dev/ram0 将被卸载。

8)在真正的根文件系统上进行正常启动过程,执行 /sbin/init。 linux 2.4内核initrd的执行是作为内核启动的一个中间阶段,也就是initrd的 /linuxrc执行以后,内核会继续执行初始化代码。而我们可以把自己要添加的驱动执行脚本添加到linuxrc,并把驱动放到/lib目录,如:qla2300等。

 
   5,生成新initrd:
   由于默认的initrd不大,只有8M(由mkinitrd脚本决定);
[root@samba disk]# df -h /mnt/disk
Filesystem            Size  Used Avail Use% Mounted on
/root/test/initrd-2.4.21-9.30AX.img
                     7.6M  333K  6.9M   5% /mnt/disk

所以,要加入的东西不要过多。
保存的过程:
[root@samba test]# umount /mnt/disk/
[root@samba test]# mv initrd-2.4.21-9.30AX.img initrd-2.4.21-9.30AX.new.img
[root@samba test]# gzip -9 initrd-2.4.21-9.30AX.new.img
[root@samba test]# mv initrd-2.4.21-9.30AX.new.img.gz initrd-2.4.21-9.30AX.new.img
[root@samba test]# cp initrd-2.4.21-9.30AX.new.img /boot/
最后,修改grub即可。

如果是要新做一个initrd文件,可以这样:
[root@samba test]# dd if=/dev/zero of=./new.img bs=1024k count=8
[root@samba test]# mkfs.ext2 -F -m0 new.img
[root@samba test]# mkdir /mnt/new
[root@samba test]# mount -o loop new.img /mnt/new/  <==创建一个新挂载点
[root@samba test]# cd /mnt/new/
[root@samba new]# cp -a /mnt/disk/* ./

然后加入自定义的驱动或脚本
[root@samba test]# umount /mnt/new/
[root@samba test]# gzip -9 new.img
[root@samba test]# mv new.img.gz new.img
 
2.6核心

   1,格式:2.6核心可以支持image格式,但更多的时候还是使用cpio格式。其核心文件不再是linuxrc,而是/init。

   2,解压:以redflag DC5.0使用的核心为例:
[root@printserver test]# ls
initrd-2.6.9-11.19AX.img
[root@printserver test]# file initrd-2.6.9-11.19AX.img
initrd-2.6.9-11.19AX.img: gzip compressed data, from Unix, max compression

   可以这样来识别格式:
[root@printserver test]# gzip -dc initrd-2.6.9-11.19AX.img > new.img
[root@printserver test]# file new.img
new.img: ASCII cpio archive (SVR4 with no CRC)

   创建一个新目录,然后解压出来:
[root@printserver test]# mkdir new
[root@printserver test]# cd new/
[root@printserver new]# gzip -dc ../initrd-2.6.9-11.19AX.img | cpio -idvm

也可以用这样一个命令zcat,格式参考gzip,或是参考《2.6内核解压》。
内容:
[root@printserver new]# ll -R
.:
total 36
drwxr-xr-x  2 root root 4096 Sep 30 16:55 bin
drwxr-xr-x  2 root root 4096 Sep 30 16:55 dev
drwxr-xr-x  3 root root 4096 Sep 30 16:55 etc
-rwxr-xr-x  1 root root  725 Jun 29 17:35 init  <== 一个nash脚本
drwxr-xr-x  2 root root 4096 Sep 30 16:55 lib
drwxr-xr-x  2 root root 4096 Jun 29 17:35 loopfs
drwxr-xr-x  2 root root 4096 Jun 29 17:35 proc
lrwxrwxrwx  1 root root    3 Sep 30 16:54 sbin -> bin
drwxr-xr-x  2 root root 4096 Jun 29 17:35 sys
drwxr-xr-x  2 root root 4096 Jun 29 17:35 sysroot
./bin:
total 592
lrwxrwxrwx  1 root root     10 Sep 30 16:55 hotplug -> /sbin/nash
-rwxr-xr-x  1 root root  12904 Jun 29 17:35 insmod  <== 插入模块
lrwxrwxrwx  1 root root     10 Sep 30 16:55 modprobe -> /sbin/nash
-rwxr-xr-x  1 root root  38184 Jun 29 17:35 nash  <== 一个小型解释器
-rwxr-xr-x  1 root root 541716 Jun 29 17:35 udev
lrwxrwxrwx  1 root root      4 Sep 30 16:54 udevstart -> udev
./dev:  <== 一些必要的设备文件
total 0
crw-r--r--  1 root root 5, 1 Jun 29 17:35 console
crw-r--r--  1 root root 1, 3 Jun 29 17:35 null
brw-r--r--  1 root root 1, 1 Jun 29 17:35 ram
crw-r--r--  1 root root 4, 0 Jun 29 17:35 systty
crw-r--r--  1 root root 4, 1 Jun 29 17:35 tty1
crw-r--r--  1 root root 4, 2 Jun 29 17:35 tty2
crw-r--r--  1 root root 4, 3 Jun 29 17:35 tty3
crw-r--r--  1 root root 4, 4 Jun 29 17:35 tty4
./etc:
total 4
drwxr-xr-x  2 root root 4096 Sep 30 16:55 udev
./etc/udev:  <== udev配置文件
total 4
-rw-r--r--  1 root root 1128 Jun 29 17:35 udev.conf
./lib:  <== 启动时加载的模块
total 236
-rwxr--r--  1 root root 139452 Aug  5  2005 ext3.ko
-rwxr--r--  1 root root  89648 Aug  5  2005 jbd.ko
./loopfs:
total 0
./proc:
total 0
./sys:
total 0
./sysroot:
total 0
 

   3,执行脚本
[root@printserver new]# cat init
#!/bin/nash
mount -t proc /proc /proc
setquiet
echo Mounted /proc filesystem
echo Mounting sysfs
mount -t sysfs none /sys
echo Creating /dev
mount -o mode=0755 -t tmpfs none /dev
mknod /dev/console c 5 1
mknod /dev/null c 1 3
mknod /dev/zero c 1 5
mkdir /dev/pts
mkdir /dev/shm
echo Starting udev
/sbin/udevstart
echo -n "/sbin/hotplug" > /proc/sys/kernel/hotplug
echo "Loading jbd.ko module"
insmod /lib/jbd.ko
echo "Loading ext3.ko module"
insmod /lib/ext3.ko
/sbin/udevstart
echo Creating root device
mkrootdev /dev/root
umount /sys
echo Mounting root filesystem
mount -o defaults --ro -t ext3 /dev/root /sysroot
mount -t tmpfs --bind /dev /sysroot/dev
echo Switching to new root
switchroot /sysroot
umount /initrd/dev

 很明显,与2.4核心最大的差别在于用init代替了linuxrc,并且加入了udev方式。

   4,执行流程
   由于采用cpio格式后,不需要再创建一个临时的设备用于挂载img文件,所以执行的流程也简单很多:

1)boot loader 把内核以及 initrd 文件加载到内存的特定位置。

2)内核判断initrd的文件格式,如果是cpio格式。

3)将initrd的内容释放到rootfs中。

4)执行initrd中的/init文件,执行到这一点,内核的工作全部结束,完全给/init文件处理。这个正是cpio格式带来的便利,我们要修改和增加自定义的脚本和驱动都变得简单很多,一般只需要对init脚本和/lib添加即可。

 
   5,生成新initrd文件

[root@printserver new]# find ./ | cpio -c -o > ../initrd-2.6.9-11.19AX.new.img
1617 blocks
[root@printserver new]# cd ..
[root@printserver test]# gzip -9 initrd-2.6.9-11.19AX.new.img
[root@printserver test]# mv initrd-2.6.9-11.19AX.new.img.gz initrd-2.6.9-11.19AX.new.img
[root@printserver test]# cp initrd-2.6.9-11.19AX.new.img /boot/
最后,修改grub即可。

   若在2.6核心上使用image的initrd文件,处理的流程只是在开始会增加一个判断步骤,后续是和在2.4上执行的过程一样的。

   上面介绍了2.4和2.6两个版本的initrd,那么,它们有何区别跟相同点,下面做简单的说明:
在这个过程中,可以看到,使用cpio格式的处理是非常方便和简洁的,很难对比两种格式处理有什么不同,可以说几乎是一样的。但就是因为制作cpio,以及启动对cpio的处理更直接,目前新发行版的initrd都以cpio格式为多。
阅读(1109) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~