編譯linux kernel及製做initrd ( by quqi99 )

編譯linux kernel及製做initrd ( by quqi99 )

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

 

   運行一個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_installlinux

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-rc5git

   sudo update-initramfs -u -k version github

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

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

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

   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.imgcentos

   grub> bootbash

 

 

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的文件系統 ext二、ext三、reiserfs、xfs、jfs和Windows的FAT、FAT3二、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 工具進行壓縮,這與以往版本是有區別的。

1、啓動鏡像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 便可。

2、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


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

# xz -dc initrd.img | cpio -id


壓縮:

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



3、補充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

相關文章
相關標籤/搜索