編譯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格式轉換。
-
create raw disk
sudo kvm-img create -f raw /bak/kvmimages/ubuntutemplate.img 8G
-
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
-
啟動虛機之后安裝一些如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
-
調整鏡像, 因為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命令的 -H 選項指定打包文件的具體格式,要生成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 壓縮:
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 壓縮:
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。
如下:
initrd.img: LZMA compressed data, streamed
※ 注意,若在低於RHEL 6.2 版本下執行file 命令,可能無法識別LZMA 壓縮格式:
initrd.img: data
這時,可把file 軟件包升級到5.04-13.el6 即可。
二、xz 工具簡介
xz 工具是LZMA 壓縮算法的一個實現。具體可見:Wikipedia
7-Zip supports xz since version 9.04 beta (stable since 9.20)
可見,Windows 下可使用7-Zip 打開.xz 文件。LZMA 算法比Gzip 算法壓縮率更高。幾個參數:
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 文件
解壓:
壓縮:
三、補充tar.lzma
由於LZMA 具有優秀的壓縮率及占用資源少的特點,越來越多的工具采用lzma進行打包,后綴名為:tar.lzma。
對於Fedora 11 及以后的版本,可以使用下面的命令操作:
壓縮
解壓:
如果是CentOS 5.3 等老版本,需要安裝獨立的lzma 工具或用xz 進行:
壓縮:
解壓(兩個方式都可以):
# 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