編譯linux kernel及制作initrd ( by quqi99 )


編譯linux kernel及制作initrd ( by quqi99 )

作者:張華  發表於:2013-01-27    ( http://blog.csdn.net/quqi99 )

 

   運行一個linux系統需要三項內容:
   1,kernel, 內核,一些核心的代碼塊,如進程管理,它要求體積很小。
   2,initrd, 進入系統所需預告加載的硬件驅動module的一個最小集。當GRUB加載kernel時,kernel會在內存中將initrd文件mount到rootfs上激活,然后kernel照着initrd中的init一步一步地加載驅動。在initrd文件中所放入的模塊,必須是與操作系統同一版本kernel所編譯的模塊。init腳本的工作流程是:
      initrd的參考文檔可見:
      1) Linux initial RAM disk (initrd) overview, http://www.ibm.com/developerworks/linux/library/l-initrd/index.html
      2)  NTTdocomo-openstack / baremetal-initrd-builder, https://github.com/NTTdocomo-openstack/baremetal-initrd-builder
      2.1, nash指令(一個文件小,內置了一些實用的指令)
      2,2 掛載主要的文件系統, 並建立設備文件所需的文件系統
         mount -t proc /proc /proc
         mount -t sysfs /sys /sys
            2.2.1,procfs映射着內存中的一個虛擬目錄,用於提供硬件、進程的實時信息,會隨時變動。linux為保證穩定性,不允許訪問/proc下的文件,root用戶也不例外。
            2.2.2, sysfs也映射着內存中的一個虛擬目錄,用於硬件信息的分類, sys目錄的每一個文件都只有一個字符為內容來做開關的。
            2.2.3, tmpfs也映射着內存中的一個虛擬目錄,內存中的文件系統。想要速度快時,可以選擇在內存建立tmpfs類型的文件系統,因為它都將建在內存中。
                   例如在內存中建立了一個tmpfs分區並掛載到/mnt/tmpfs目錄 :mount -t tmpfs -o size=50M tmpfs /mnt/tmpfs/
                        [root@zhanghua proc]# df -h
                        Filesystem      Size  Used Avail Use% Mounted on
                        tmpfs            50M     0   50M   0% /mnt/tmpfs
            2.2.4, /dev/shm,它是tmpfs的一種變種,tmpfs所有的內容所放在內存中,而/dev/shm在內存與文件系統有個映射,硬盤和內存中都會有這內容。
                  速度快,能存大於內存的文件,但重啟之后,內容會消失。
                  下面顯示在/dev/shm中建立文件與在普通ext4文件系統建文件的速度比較:
                        [root@zhanghua proc]# time dd if=/dev/zero of=/dev/shm/test.file bs=1M count=100
            100+0 records in
            100+0 records out
            104857600 bytes (105 MB) copied, 0.0395221 s, 2.7 GB/s

            real    0m0.075s
            user    0m0.001s
            sys    0m0.041s
            [root@zhanghua proc]# time dd if=/dev/zero of=/bak/test.file bs=1M count=100
            100+0 records in
            100+0 records out
            104857600 bytes (105 MB) copied, 0.0647526 s, 1.6 GB/s

            real    0m0.090s
            user    0m0.001s
            sys    0m0.066s
            2.2.5,devfs, 所有的device都會在/dev目錄建立一個對應的設備文件.
                   缺點是例如即使打印機沒連在計算機上,/dev/printer文件也會存在,這樣會造成在intrd階段的設備過多,所以devfs正在被udev所取代
                   例如要用光驅時,需先在linux與光驅之間通過 mount /dev/cdrom /mnt/命令做關聯
            2.2.6, udev, udev可以放在/sys目錄下,不需要將所有未使用的文件建立設備文件,不再需要major number和minor number,當硬件被加載時可執行用戶設置的script。
                   例如,如果/dev/cdrom是被udev建立的,而非devfs,那么當光驅被撥除時,/dev/cdrom文件就會消失。
            2.2.7,/proc/PID文件,第一個進程都會對應這要閏個文件
            2.2.8,/proc/partitions用來表示檢測到的硬盤信息, major字段表示SCSI controller的slot ID,minor字段表示分區ID。
                  #[root@zhanghua proc]# cat /proc/partitions  
           major minor  #blocks  name
               8        0  488386584 sda
               8        1   82051956 sda1
            2.2.9, /sys/block,塊設備
                  #[root@zhanghua proc]# cat /sys/block/
                    loop0/ loop1/  sda/   sr0/
            2.2.10, /dev/pts ( pseudo terminal slave) 副虛擬終端,其目錄的文件都是由ptmx(主虛擬終端)產生的,它們是父子關系。當用ssh聯機到localhost本地端之后,就會在
                   /dev/pts目錄下產生一個叫做"0"的文件,當別的console也利用ssh聯到這台機器時,就會出現“1“.
                  [root@zhanghua proc]# ps -ef|grep ssh
                   hua      11186  3068  0 16:01 pts/0    00:00:00 ssh hua@localhost  
                   hua      11195 11187  0 16:01 ?        00:00:00 sshd: hua@pts/3
                   如上,當一個用戶以ssh登錄之后,該用戶就分到一個ptmx所賦予的pts資源(pts/3),所以說ssh使用的是虛擬終端,不是真正的tty接口。telnet用的則是真正的tty接口。
            2.2.11, /dev/mapper,如果使用LVM后,linux要和硬盤打交道時不再直接使用/proc/partitions下的硬盤設備,而是使用/dev/mapper下的設備再去中轉。
                    # ls -l /dev/mapper/*
                      brw-rw---- 1 root disk 253, 0 jan 27 16.16  /dev/mapper/vg0-lv0
                    # cat /proc/partitions
                      major minor #blocks name
                       8     0     17528  sda
                       253   0     1111   dm-0
      3,建立最初所需使用的設備文件
         設備文件使用mknod指令建立,mknod指令用來建立字符(character)或塊(block)文件。
         例:mknod /dev/tty1c41, 建立一個名為tty1的設備文件,c表示是字符文件,major=4, minor=1
      4,加載相關模塊
      5,切入image所指示的硬盤中實體操作系統. (rescue mode是直接通過kernel加載initrd進入單純的內存開機的虛擬操作系統)
         5.1, mkrootdev -t ext4 -o defaults.ro hda1, 即nash指令會將GRUB中所設備的root=xxx中的xxx路徑先建立好
         5.2, mount /sysroot, 將GRUB中的root路徑mount到initrd中的/sysroot下。
         5.3, switchroot這個nash指令將initrd中的/sysroot文件系統切換成/rootfs,從而切換到了硬盤中的文件系統。
   3,image, 操作系統的image文件系統,當initrd被加載后,必須為用戶與文件系統牽線。
   4, init進程,在切入到用戶操作系統之后,首先執行linux的init進程(pid=1), init進程再去加載/etc/rc.d/init.d/functions從而啟動服務。
      關於啟動級別與init進程的事兒,也可參見我的另一博文件,Linux的運行級別與解決開機故障一例 ( by quqi99 ), http://blog.csdn.net/quqi99/article/details/7436926
   5, 系統管理
      5.1, 查看CPU信息 cat /proc/cpuinfo
      5.2, 查看內存, cat /proc/meminfo 或者 free -m
      5.3, 查看usb, lsusb
      5.4, 查看PCI, lspci
      5.5, 查看開機日志, dmesg |grep -i error


   本文講的是如何編譯kernel,接下來也會研究如何制作initrd與image.
   最好使用普通用戶執行下面所有操作。
1,下載內核源碼
   git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
   用git tag查看版本,將並代碼切換到v3.8-rc5下, git checkout v3.8-rc5
2,配置內核(有點類似於./configure), 配置前先安裝一個依賴包, sudo yum install ncurses-devel,
   make menuconfig
   說明一下,內核的配置項是三選一,yes, no, 或module。yes, no意味着直接將該特性編譯或不編譯到內核中,module意味着以模塊形式編譯,模塊意味着你開機會可以通modprobe命令動態加載或卸載。
   我在這里選擇的默認配置,生成的配置位於根目錄下的.config文件之中。
   如果你在一個老的配置文件上更改配置的話,可以用make oldconfig命令比較與之前的配置文件的差異來驗證你配置的正確性。
3,執行make命令編譯,
   make
   說明一下,這條命令實際上已經包括了下面的命令:
   1)確定依賴性 make dep
   2)清理編譯中間文件,make clean
   3)編譯內核, make bzImage
   4)生成模塊, make modules
4, 安裝模塊,下列命令會將模塊自動安裝到/lib/modules/3.8.0-rc5/目錄下.
   sudo make modules_install

5, 安裝內核及initrd,人工將arch/x86/boot/bzImage的內核文件拷到/boot目錄即可。
   sudo cp arch/x86_64/boot/bzImage /boot/vmlinuz-3.8.0-rc5
   sudo chmod a+x vmlinuz-3.8.0-rc5

   sudo update-initramfs -u -k version 

  sudo update-grub -o /boot/grub/grub.cfg
   注意:以vmlinuz-<version>這樣命名它。

  上述三步等價於make install, 但make install在自動執行update grub命令時有時候會破壞你的grub文件,特別對於進行PGP加密過的硬盤。

6,「可選」,安裝符號表,只有調試時才需要用到。符號表System.map用以將內核符號和它們的起始地址對應起來,調試的時候,如果需要把內存地址翻譯成容易理解的函數名和以及變量名,就會很有用。

   sudo cp System.map /boot/System.map-3.8.0-rc5
7, 建立initrd文件
   sudo mkinitrd --with=ntfs -o /boot/initrd-linux3.8.0-rc5.img 3.8.0-rc5
   以上mkinitrd命令是參照現有系統的/etc/modprobe.conf和/etc/fstab文件創建一個全新的initrd, 用--with=ntfs會從/lib/modules/3.8.0-rc5目錄將ntfs模塊也做到initrd里去。

   那如何要從頭開始做一個initrd呢?
   1) 可以用 sudo zcat initrd-linux3.8.0-rc5.img | cpio -id 命令解壓 ( initrd文件是以ext2作為文件系統中,所以可以用mount -o loop initrd.img /mnt命令加載.)
   2) 然后將模塊ntfs.ko加到相應的目錄,如lib/modules/3.8.0-rc5/kernel/fs/ntfs目錄
   3) 將ntfs.ko模塊加到init腳本
   4) 重新壓縮,find | cpio -co | gzip -9 > initrd-new.img

8, 更新grub, 編譯/etc/grub/grub.conf文件,添加下面內容,注意千成不要用update grub命令來更新grub哦,這可能會導致你的雙系統無法用。
   menuentry 'Fedora,Linux 3.8.0' --class fedora --class gnu-linux --class gnu --class os {
        set root='(hd0,msdos9)'
        linux   /boot/vmlinuz-3.8.0-rc5 root=/dev/sda10 ro   quiet splash
        initrd /boot/initrd-linux3.8.0-rc5.img
   }

   也可以在開機時按e進入grub編輯模式,再按e一次進入kernel的設置界面:
   grub> root (hd0,msdos9)
   grub> kernel /boot/vmlinuz-3.8.0-rc5 ro root=/dev/sda9 acpi=off (注意,kernel在前的grub>光標后一定要空一行)
   grub> initrd /boot/initrd-linux3.8.0-rc5.img

   grub> boot

 

 

9, 下面講一下用於裸機的image的制作過程,需要將虛擬機磁盤系統(raw, qcow2, vhd等)往Linux識別的ext4格式轉換。

  1. create raw disk

    sudo kvm-img create -f raw /bak/kvmimages/ubuntutemplate.img 8G

  2. install kvm virtual machine

    sudo kvm -m 728 -cdrom/bak/kvmimages/ubuntu-11.04-desktop-i386.iso -drivefile=/bak/kvmimages/ubuntutemplate.img -boot d -nographic -vnc :0

    use vnc to see: vncviewer192.168.99.100:5900

  3. 啟動虛機之后安裝一些如SSH,cloud-init等軟件

    sudo apt-get install kvm-pxe

    sudo kvm -m 728 -drivefile=/bak/kvmimages/ubuntutemplate .img -boot c -nographic -vnc :0

    sudo apt-get install openssh-servercloud-init

    sudo rm -rf/etc/udev/rules.d/70-persistent-net.rules #刪它,防止添加其他網口

    sudo shutdown -h now

  4. 調整鏡像, 因為openstack只接受ext4文件系統格式,故需將raw格式轉化成ext4

    root@zhhua:/bak/kvmimages# sudo losetup -f  --show /bak/kvmimages/ubuntucapture.img

    root@zhhua:/bak/kvmimages# sudo losetup -a

    /dev/loop0: [0809]:5770371(/bak/kvmimages/nova.img)

    /dev/loop1: [0809]:5770373(/bak/kvmimages/ubuntucapture .img)

    root@zhhua:/bak/kvmimages# sudo fdisk-l /dev/loop1

    Disk /dev/loop1: 8589 MB, 8589934592bytes

    255 heads, 63 sectors/track, 1044cylinders, total 16777216 sectors

    Units = sectors of 1 * 512 = 512 bytes

    Sector size (logical/physical): 512bytes / 512 bytes

    I/O size (minimum/optimal): 512 bytes/ 512 bytes

    Disk identifier: 0x0009d391

    Device Boot Start End Blocks Id System

    /dev/loop1p1 * 2048 15286271 7642112 83 Linux

    /dev/loop1p2 15288318 16775167 743425 5 Extended

    /dev/loop1p5 15288320 16775167 743424 82 Linux swap

顯示分區是從扇區(sector)2048開始的,每個扇區是512個字節,所以是從2048 x 512 = 1048576個字節開始的。記住這個1048576,下面會用到

卸載loop后重新從1048576字節開始掛載:

sudo losetup -d /dev/loop1

sudo losetup -f -o 1048576 /bak/kvmimages/ubuntucapture.img

 

把這整個分區拷貝到一個新文件就是一個我們要的ext4文件系統鏡像

sudo dd if=/dev/loop1 of=/bak/kvmimages/ubuntutemplate.img

用完loop后記得卸載,sudo losetup -d /dev/loop1

 

掛載剛創建的ext4根文件系統,修改分區加載表(/etc/fstab),注釋或刪除以前的,加上“LABEL=my-rootfs / ext4 defaults 0 0”一行,

最后,別忘了運行下列命令將塊設備的卷標修改成我們上面設置的my-rootfs, sudo tune2fs -L my-rootfs /bak/kvmimages/ubuntutemplate.img:

sudo mount -o loop /bak/kvmimages/ubuntutemplate.img /mnt

sudo vi /mnt/etc/fstab

#UUID=98a4bc39-82a9-4d20-abf8-4aef654c1268 / ext4 errors=remount-ro 0 1

UUID=my-rootfs / ext4 defaults 0 0

# swapwas on /dev/sda5 during installation

UUID=3afdd9f7-7e1e-4172-ae32-7407b0559c51none swap sw 0 0

 

 

把內核(vmlinuz)和initrd文件拷貝出來以便后面和虛擬機鏡像一起發布到OpenStack雲里。使用完虛擬機鏡像后記得卸載(unmount):

sudo cp /mnt/boot/vmlinuz-2.6.38-8-generic /bak/kvmimages/boot/

sudo cp /mnt/boot/initrd.img-2.6.38-8-generic /bak/kvmimages/boot/

sudo umount  /mnt

 

整個過程是,initrc或者initramfs都是一個運行在內存的小根文件系統,它有一個叫init的腳本,做完一些准備工作之后,如加載硬件的驅動,然后會切換到鏡像所在的新根文件系統上,下面就是一個intramfs中init腳本的例子:

 

 

#!/bin/sh
mount -vt proc proc /proc              #很多工具都讀proc的數據,故先加載
mount -vt sysfs sysfs /sys            #加載內核文件系統
insmod scsi_mod                         #要切換到鏡像的新根文件系統,當然要先加載硬件用的scsi驅動模塊
insmod libata
insmod ata_piix
insmod sd_mod
mdev -s  或者echo /sbin/mdev > /proc/sys/kernel/hotplug   #可以使用busybox的mdev生成動態的udev文件,也可以使用hotplug技術在加載模塊的時候再加載相應的設備
mount /dev/sda /mnt                      #加載硬盤,或者直接加到根目錄/中
exec switch_root /mnt /sbin/init   #通過exec會讓鏡像中的init進程完全替換initramfs中的init進程的空間來切換根文件分區

/bin/sh                                              #如果上述切換根文件分區失敗,還可以使用initramfs的sh進程,否則會panic

所以說,這個鏡像應該是linux內核直接可以認的文件系統格式,如ext4, 直虛機使用的文件格式像raw, qrow2等須像如上方式轉換到ext4等格式。這樣也就可以直接通過dd命令將鏡像拷到/dev/sda硬盤中了(gunzip -c /mnt/sda1/hda.img.gz | dd of=/dev/hda conv=sync,noerror bs=64K)

想把整個硬盤備份到外部存儲移動硬盤中的話:
1,加載移動硬盤,mount -t vfat /dev/sda1 /mnt/sda1
2,dd備份,dd if=/dev/hda conv=sync,noerror bs=64K | gzip -c  > /mnt/sda1/hda.img.gz
3, 恢復,gunzip -c /mnt/sda1/hda.img.gz | dd of=/dev/hda conv=sync,noerror bs=64K
顯然, dd的缺點是備份整個硬盤分區,不管它是不是真用了。有個叫再生龍的工具(Clonezilla)就是來克服這個缺點的。下面是它的介紹:
Clonezilla是一個很好的系統克隆工具,它基於Partimage,吸取了Norton Ghost和Partition Image的優點。即不僅支持對整個系統進行克隆,而且也可以克隆單個的分區,這種靈活性可能更能適應備份者的需要.支持GNU/Linux的文件系統 ext2、ext3、reiserfs、xfs、jfs和Windows的FAT、FAT32、NTFS文件系統.Clonezilla支持使用 PXEBoot來進行Multicast克隆.這對於需要克隆大量系統的用戶極為有用. Clonezilla 比起Ghost For Linux(簡稱G4L)有一個很顯著的優勢就是Clonezilla支持的文件系統格式比G4L多以外Clonezilla只備份數據,而G4L卻將整個分區都備份了(即包含空數據),所以G4L將比Clonezilla占用更多的用於存放備份鏡像的空間。

 

 

或者我們使用另一種方式制作OpenStack鏡像(即根文件系統),例如linux-0.2.img是一個采用kvm虛機安裝的raw格式的鏡像,現在將它轉成linux內核認識的ext4格式的根文件系統。
1, sudo mkdir -p /mnt/{raw,ext4} && sudo mount -o loop linux-0.2.img /mnt/raw
2, dd if=/dev/zero of=linux-0.2.ext4 bs=1M count=22
   mkfs.ext4 linux-0.2.ext4
   sudo mount -o loop linux-0.2.ext4 /mnt/ext4
3, sudo cp -r /mnt/raw/* /mnt/ext4/

 

直接用raw格式的做鏡像也是可以的,那樣就不需要轉換了,glance add name="CentOS-6.4-x86_64" is_public=true container_format=ovf disk_format=raw < CentOS-6.4-x86_64.img

 

 

最后,現看一下如何掛載raw和qcow2格式的KVM硬盤鏡像

raw格式
對於未分區鏡像文件直接使用loop:
mount -o loop image.img /mnt/image
已分區的鏡像文件:
如果已知分區的起始位置
mount -o loop,offset=32256 image.img /mnt/image
或者使用losetup + kpartx
losetup /dev/loop0 image.img
kpartx -a /dev/loop0
mount /dev/mapper/loop0p1 /mnt/image
kpartx命令的作用,是讓Linux內核讀取一個設備上的分區表,然后生成代表相應分區的設備。
kpartx -l imagefile 可以查看一個映像文件中的分區,使用 kpartx -a imagefile 命令后,就可以通過 /dev/mapper/loop0pX (其中X是 分區號)來訪問映像。

qcow2格式
對於qcow2格式需要使用qemu-nbd這個工具
modprobe nbd max_part=63
qemu-nbd -c /dev/nbd0 image.img
mount /dev/nbd0p1 /mnt/image
如果是LVM格式的鏡像:
vgscan
vgchange -ay
mount /dev/VolGroupName/LogVolName /mnt/image
最后使用結束需釋放資源:
umount /mnt/image
vgchange -an VolGroupName
killall qemu-nbd
kpartx -d /dev/loop0
losetup -d /dev/loop0

 

initrd的制作和解壓

initrd 的英文含義是 boot loader initialized RAM disk,就是由 boot loader 初始化的內存盤。在 linux內核啟動前,boot loader 會將存儲介質中的 initrd 文件加載到內存,內核啟動時會在訪問真正的根文件系統前先訪問該內存中的 initrd 文件系統。在 boot loader 配置了 initrd 的情況下,內核啟動被分成了兩個階段,第一階段先執行 initrd 文件系統中的"init or linuxrc",完成加載驅動模塊等任務,第二階段才會執行真正的根文件系統中的 /sbin/init, Linux2.6既支持cpio-initrd,也支持image-initrd,但是cpio-initrd有着更大的優勢,在使用中我們應該優先 考慮使用cpio格式的initrd.

Initrd 的主要用途

linux 發行版必須適應各種不同的硬件架構,將所有的驅動編譯進內核是不現實的,initrd 技術是解決該問題的關鍵技術。Linux 發行版在內核中只編譯了基本的硬件驅動,在安裝過程中通過檢測系統硬件,生成包含安裝系統硬件驅動的 initrd,是一種即可行又靈活的解決方案。

1.解壓 initrd
 # file initrd.`uname –r`.img (察看格式,不同的linux操作系統,這個文件格式也有不同,這個文件格式可能是cpio 也可能是ext2)
 如果是cpio格式 :

# mkdir /mnt/tmp
# cd /mnt/tmp
# cpio -idmv </tmp/initrd.`uname -r`.img

 

2 壓縮initrd

2.1 mkinitrd 

#cd /lib/modules/`uname -r`
#mkinitrd /tmp/initrd.`uname -r`.img `uname -r`
#cd /tmp
#mv initrd.`uname –r`.img initrd.`uname –r`.img.gz
(initrd使用gzip壓縮,如果不改名字的話,后面無法解壓縮) #gunzip initrd.`uname -r`.img.gz

2.2 cpio

#假設當前目錄位於准備好的initrd文件系統的根目錄下

第一種方式,老的-c選項,用的是ascii碼備份方式. 

# find . | cpio -c -o > ../initrd.img
# gzip ../initrd.img

 

第二種方式,新的.已經測試可用的方式.

#cd /root/busybox-1.15.3/rootfs9260
#find . | cpio -H newc -o > ../initrd_cpio.img
#cd ../
#cp initrd_cpio.img initrd_cpio_bk.img -f
#gzip initrd_cpio.img -f
#/home/u-boot-1.1.5/tools/mkimage -A arm -T ramdisk -C none -O linux -a 0x600000 -e 0x600000 -d initrd_cpio.img.gz /home/ramdisk.uboot
#ls /home/ramdisk.uboot -al

上面cpio命令的 -選項指定打包文件的具體格式,要生成initramfs,只能用newc 格式,如果使用其他格式,

內核會打出這樣的出錯信息:Unpacking initramfs...<0> kernel panic - not syncing: no cpio magic

或者出現:Unpacking initramfs...<0>Kernel panic - not syncing: bad gzip magic numbers。 如果采用了-c舊的ascii碼備份方式,則內核會按照ramdisk的方式加載根文件系統。

如果你在編譯內核時選上了RAM block device support (在device drivers -> block devices里),

也可以啟動成功,但這就失去了cpio-initrd的意義了!。

再就是注意cpio-initrd的初始進程是 “/init”,ramdisk方式初始進程是"/linuxrc"

另外如果采用cramfs格式的根文件系統,也需在編譯內核時選上RAM block device support


2.3  gen_init_cpio
獲取 gen_init_cpio,工具 ,gen_init_cpio是編譯內核時得到的,
在內核源代碼的 usr 目錄下,我們可以通過 以下步驟獲取它,進入內核源代碼 執行 :
# make menuconfig
# make usr/
這樣即編譯好gen_init_cpio,
gen_initramfs_list.sh 在內核源代碼的 script 目錄下,
將這兩個 文件 copy 到 /tmp 目錄下,/tmp/initrd 為 解壓好的 initrd 目錄,執行以下命令 制作initrd :

 
        

#制作initrd : 

# gen_initramfs_list.sh initrd/ > filelist
# gen_init_cpio filelist >initrd.img
# gzip initrd.img
# mv initrd.img initrd-'uname –r’.img

只有用這個方式壓縮的initrd ,在Linux系統重啟的時候才能 一正確的文件格式 boot 起來,也可以用
這種方式修改安裝光盤的initrd文件 然后 進行系統安裝。

3. 如何在 initrd 中添加新的驅動,以 ahci.ko 為例

 
        

3.1 gen_init_cpio 

# cp initrd-‘uname –r‘.img /tmp/initrd;cd /tmp/initrd
# cpio –ivdum < initrd-‘uname –r’.img;
# mv initrd-‘uname –r’.img ../
# cd /tmp/initrd
# vim init加上一行 insmod /lib/ahci.ko
# cp ahci.ko lib/
# cd /tmp
# gen_initramfs_list.sh initrd/ > filelist
# gen_init_cpio filelist >initrd.img
# gzip initrd.img
# mv initrd.img initrd-‘uname –r’.img

至此,新的initrd文件initrd-‘uname –r’.img中就包含了ahci的驅動程序了 ,這種方式是最簡單有效的。

 3.2 mkinitrd
(1) Add “alias scsi_hostadapter ahci” at /etc/modprobe.conf
(2) copy ahci.ko to “/lib/module/$(kernel-version)”/kernel/drivers/scsi”
(3) mkinitrd initrd.img ‘uname -r’
至此,新的initrd文件initrd-‘uname –r’.img中就包含了ahci的驅動程序了 .


#釋放cpio格式的initrd:       

mv initrd.img imitrd.img.gz
gunzip initrd.img.gz
cpio -i --make-directories < initrd.img

#釋放centos6.2系統的initramfs.img

1."gunzip initrd.img-2.6.27-7-generic.gz",得到一個未壓縮的initrd.img-2.6.27-7-generic 

2. cpio -iv <initrd.img-2.6.27-7-generic",提取成功

#制作cpio格式的initrd(新2012年使用過的)

# cd /root/busybox-1.15.3/rootfs9260 # find . | cpio -H newc -o > ../initrd_cpio.img

#制作cpio格式的initrd(2009年制作的LFS的方式):
dd if=/dev/zero of=/tmp/rootfs bs=1k count=35000
losetup /dev/loop0 /tmp/rootfs
mkfs.ext2 –F –i 2000 /tmp/rootfs
mkdir /tmp/loop
mount –o loop /tmp/rootfs /tmp/loop
#然后將剛才建立的基本系統拷貝到/tmp/loop
cp /lfs/* /tmp/loop –arfp
find . | cpio –o –H newc | gzip –c > /tmp/initrd.img

 

centos7的initrd.img解壓縮

紅帽(Red Hat)從Enterprise Server 6.2 開始,啟動鏡像文件initrd.img 開始改用xz 工具進行壓縮,這與以往版本是有區別的。

一、啟動鏡像initrd.img 文件
類RedHat 系統從vmlinuz 核心引導后,會讀取initrd.img 啟動鏡像。該文件中包含驅動模塊等信息,是非常重要的文件。不同版本使用的格式不同。
1.RHEL 4.0 版本
采用ext2 文件格式鏡像,再通過gzip 壓縮:

引用
# file initrd.img
initrd.img: gzip compressed data, from Unix, max compression
# mv initrd.img initrd.img.gz
# gunzip initrd.img.gz
# file initrd.img
initrd.img: Linux rev 1.0 ext2 filesystem data


2.RHEL 5.0 版本
采用cpio 打包鏡像,再通過gzip 壓縮:

引用
# file initrd.img
initrd.img: gzip compressed data, from Unix, max compression
# mv initrd.img initrd.img.gz
# gunzip initrd.img.gz
# file initrd.img
initrd.img: ASCII cpio archive (SVR4 with no CRC)


3.RHEL 6.2 版本
RHEL 6.0 - 6.2 都采用與RHEL 5.0 相同的格式進行打包,但從6.2版本開始,改用LZMA 進行壓縮。詳見:Release Notes for Red Hat Enterprise Linux 6.2 Edition 2
如下:

引用
# file initrd.img
initrd.img: LZMA compressed data, streamed


※ 注意,若在低於RHEL 6.2 版本下執行file 命令,可能無法識別LZMA 壓縮格式:

引用
# file initrd.img
initrd.img: data


這時,可把file 軟件包升級到5.04-13.el6 即可。

二、xz 工具簡介
xz 工具是LZMA 壓縮算法的一個實現。具體可見:Wikipedia

引用
xz is a lossless data compression file format incorporating the LZMA2 compression algorithm. While xz can only support one file the convention is to bundle a file that is an archive itself, such as those created by the tar or cpio Unix programs. The original 7zip program implementing LZMA2 compression achieved small files (at the cost of speed compared to gzip or bzip2), but also created its own unique archive format which was Windows-centric and did not support Unix functionality; xz is essentially a stripped down 7zip with little archive format functionality, that compresses a single file (as opposed to 7zip's more complex capabilities like concatenating & compressing entire directories).
7-Zip supports xz since version 9.04 beta (stable since 9.20)


可見,Windows 下可使用7-Zip 打開.xz 文件。LZMA 算法比Gzip 算法壓縮率更高。幾個參數:

引用
# xz --help
Usage: xz [OPTION]... [FILE]...
Compress or decompress FILEs in the .xz format.

Mandatory arguments to long options are mandatory for short options too.

  -z, --compress      force compression
  -d, --decompress    force decompression
  -t, --test          test compressed file integrity
  -l, --list          list information about files
  -k, --keep          keep (don't delete) input files
  -f, --force         force overwrite of output file and (de)compress links
  -c, --stdout        write to standard output and don't delete input files
  -0 .. -9            compression preset; 0-2 fast compression, 3-5 good
                      compression, 6-9 excellent compression; default is 6
  -e, --extreme       use more CPU time when encoding to increase compression
                      ratio without increasing memory usage of the decoder


三、手動修改initrd.img 文件
解壓:

# xz -dc initrd.img | cpio -id


壓縮:

# find . | cpio -c -o | xz -9 --format=lzma > initrd.img



三、補充tar.lzma
由於LZMA 具有優秀的壓縮率及占用資源少的特點,越來越多的工具采用lzma進行打包,后綴名為:tar.lzma。
對於Fedora 11 及以后的版本,可以使用下面的命令操作:
壓縮

# tar cfv backup.tar.lzma a/dir --lzma


解壓:

# tar xfv backup.tar.lzma --lzma



如果是CentOS 5.3 等老版本,需要安裝獨立的lzma 工具或用xz 進行: 
壓縮:

# tar cv a/dir | lzma -c -z > backup.tar.lzma


解壓(兩個方式都可以):

# cat backup.tar.lzma | lzma -d | tar xv 
# xz -dc backup.tar.lzma | tar xvf -

 

光盤中的initrd.img

位置isolinux/initrd.img

1 解壓縮

file后發現是xz文件

將initrd.img改名,改名為Initrd.img.xz

為什么要改名?因為不改名xz會叫喚,說你胡塞給我什么文件啊?我不解壓縮

file initrd.img

mv initrd.img initrd.img.xz

unxz initrd.img.xz

解壓縮完成。

結果:生成一個initrd.img,和原始文件比,這個文件是個cpio后的文件

2 cpio解出來

file initrd.img(第一步解壓縮出來的名字)

發現是cpio

cpio -i -d < initrd.img

結果:生成所有文件系統,主要是usr, etc, lib等目錄

 

2.6內核中的initrd.img采用cpio壓縮,不再是2.4內核使用的ext2格式,無法使用mount -o loop 掛載。需要使用gunzip解壓縮,然后再使用cpio解包
cp /boot/initrd-***.img initrd.img.gz
gunzip initrd.img.gz
mkdir initrd
mv initrd.img initrd
cd initrd
cpio -ivmd  ../initrd.new.img
gzip ../initrd.new.img
再將其改名拷貝至/boot目錄,重啟就可以觀察修改后的效果。重啟后無法成功引導。這是因為生成的initrd.img不對。解決如下:
生成initrd
find . | cpio -o -H newc | gzip > /mnt/sda1/boot/initrd.img-2.6.18-4-686
(注:-H newc 是必須的,否則內核會認為是ramdisk,而不是initramfs)

 

解壓並重新打包 initrd.img

Extract
gunzip < /boot/initrd.img | cpio -i –make-directories

Repack
find ./ | cpio -H newc -o > initrd.cpio
gzip initrd.cpio
mv initrd.cpio.gz initrd.img

 

Uncompress:

mkdir initrd
cd initrd zcat ../initrd.img | cpio -idmv

Compress:

find . | cpio -o -c | gzip -9 > ../initrd.img

 

initrd.img解壓:

[root@CentOS5 ~]# mkdir /usr/src/initrd

[root@CentOS5 ~]# cp /boot/initrd-2.6.18-308.el5.img /usr/src/initrd

[root@CentOS5 ~]# cd /usr/src/initrd

[root@CentOS5 initrd]# ls

initrd-2.6.18-308.el5.img

[root@CentOS5 initrd]# mv initrd-2.6.18-308.el5.img initrd-2.6.18-308.el5.img.gz

[root@CentOS5 initrd]# gunzip initrd-2.6.18-308.el5.img.gz

[root@CentOS5 initrd]# cpio -i -d <  initrd-2.6.18-308.el5.img

[root@CentOS5 initrd]# rm -rf  initrd-2.6.18-308.el5.img 

[root@CentOS5 initrd]# ls

bin  dev  etc  init  lib  proc  sbin  sys  sysroot

 

initrd.img打包:

[root@CentOS5 initrd]# find . -print|cpio -o -H newc > ../initrd-2.6.18-308.el5.img

[root@CentOS5 initrd]# cd ..

[root@CentOS5 src]# gzip -9 initrd-2.6.18-308.el5.img 

[root@CentOS5 src]# mv  initrd-2.6.18-308.el5.img.gz  initrd-2.6.18-308.el5.img

[root@CentOS5 src]# ls

initrd-2.6.18-308.el5.img

 

*initrd.img打包也可采用如下命令:

[root@CentOS5 initrd]# find . | cpio --quiet -H newc -o | gzip -9 -n > ../initrd-2.6.18-308.el5.img.gz

 

[root@CentOS5 src]# mv  initrd-2.6.18-308.el5.img.gz  initrd-2.6.18-308.el5.img

[root@CentOS5 src]# ls

initrd-2.6.18-308.el5.img

 

解壓Ubuntu的initrd.img的方法

Ubuntu的initrd.img可以在/boot中找到,通常文件名后面還跟有很長的一串版本號。

  為了保險起見,不直接操作原文件,而是把它復制到自己的家目(home)錄中。如果你是用root帳號登錄的,家目錄就在/root中,如果是用wsxx登錄的,家目錄一般就在/home/wsxx中,通常登錄之后自動就到了家目中。我們把initrd.img復制但家目中進行解壓:

  cp /boot/initrd.img-2.6.15-ubuntu-r6 ./initrd.img.gz

  上面這個命令把/boot區中的文件復制到當前目錄,並更名為initrd.img.gz。一方面改成短文件名好一點好操作,另一方面加上gz的后綴更清楚表明它原本就是一個gzip壓縮出來的文件。http://www.ccthere.com/article/825480

  然后解壓:

  gunzip initrd.img.gz

  也可以:http://www.ccthere.com/article/825480

  gzip -d initrd.img.gz

  兩者結果是相同的,都是在當前目錄得到一個解壓后的initrd.img,原來的initrd.img.gz被刪除掉了(這也許是linux整潔的優點)。

  現在這個更大的initrd.img要用cpio解開,成為一系列目錄和文件。為了不與當前目錄中現有的文件搞混,我們有必要新建一個目錄,把initrd.img解壓到新目錄中去。將來把里面的文件修改好之后,還要把所有的目錄文件再打包起來:http://www.ccthere.com/article/825480

  mkdir initrd #建立目錄

  cd initrd  #進入目錄

  cpio -i -d < ../initrd.img #解開上層目錄中的initrd.img http://www.ccthere.com/article/825480

  因為已經進入到initrd中,../initrd.img表示上層目錄中的initrd.img。

  現在就可以看到initrd中各目錄中有很多新的目錄和文件了。在這里我們可以窺視到ubuntu是如何裝配起來的。可以對其中的內容進行修改了。

  http://www.ccthere.com/article/825480

  修改文本文件沒有什么好多說的了。

  修改之后,就是壓縮回去,用它來啟動,檢驗是否可以正常啟動,是否達到預期的修改目的。先用cpio打包:

  http://www.ccthere.com/article/825480

  find . | cpio -o -H newc > ../myinitrd.img #打包當前目錄中的所有目錄和文件,到上層目錄中的myinitrd.img

  cd .. #回到上層目錄

  gzip -9 myinitrd.img #gzip的最高級壓縮http://www.ccthere.com/article/825480

  得到的myinitrd.img.gz就是新的Ubuntu啟動文件了。

  做到這里,要有必要停下來看看一看,比較一下重新壓縮之后的文件,是否和原來的initrd.img.gz差不多大小?都應該是4M多的文件。如果文件大小相差太多,可能就有問題。我用Ubuntu文件解壓后在壓縮回來,用不同的文件名,最后比較,大小完全一致,心里就踏實了。

  http://www.ccthere.com/article/825480

  再用Gentoo的initramfs文件進行同樣方法的操作,2M多的文件解壓再壓縮回來,只剩下不到1K了,自己也不相信這是對的。

 

==================== End

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM