編譯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-rc57, 建立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指令碼的例子:
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
相關文章
- 編譯linux kernel預裝工具list編譯Linux
- ubuntu編譯安裝kernel教程。Ubuntu編譯
- CentOS7 編譯安裝最新的Linux Kernel 6.0 rc3CentOS編譯Linux
- LINUX 的patch 製作,及打patchLinux
- 自編譯製作docker版本的onlyoffice映象編譯Docker
- CentOS8 Stream編譯安裝最新的Linux Kernel 6.0 rc3CentOS編譯Linux
- RK3568開發筆記(五):在虛擬機器上使用SDK編譯製作uboot、kernel和ubuntu映象筆記虛擬機編譯bootUbuntu
- RK3568開發筆記(四):在虛擬機器上使用SDK編譯製作uboot、kernel和buildroot映象筆記虛擬機編譯bootUI
- 如何製作一款線上編譯器編譯
- Linux kernel mapLinux
- Linux中程式包管理及程式的原始碼編譯Linux原始碼編譯
- 如何編譯 Linux 核心編譯Linux
- linux核心修改編譯Linux編譯
- linux-編譯koLinux編譯
- LINUX下編譯TriangleLinux編譯
- 程式碼線上編譯器(上)- 編輯及編譯編譯
- svg製作及使用SVG
- i.MX6ULL開發板-Buildroot製作交叉編譯器UI編譯
- [譯] 使用CSS製作球體CSS
- Linux核心模組編譯Linux編譯
- linux與windows交叉編譯LinuxWindows編譯
- Linux中gcc編譯工具LinuxGC編譯
- Linux 編譯安裝 PythonLinux編譯Python
- Linux編譯安裝NginxLinux編譯Nginx
- Linux 製作系統映象Linux
- Linux自己製作rpm包Linux
- [譯] 製作 Vue 3 的過程Vue
- Linux 編譯 安裝 PHP 7.3.1Linux編譯PHP
- APK編譯及安全防護APK編譯
- QT支援https及編譯OpenSSLQTHTTP編譯
- Linux程式及作業管理Linux
- 交叉編譯場景分析(arm-linux)(四)--編譯readline和ncurses編譯Linux
- Linux下nginx編譯安裝教程和編譯引數詳解LinuxNginx編譯
- 使用lmbench測試linux效能-編譯Linux編譯
- linux源瑪包編譯安裝Linux編譯
- Linux編譯核心 Ubuntu18.04 -2020.11.04Linux編譯Ubuntu
- 在linux下編譯hibernate筆記Linux編譯筆記
- 詳解Linux 程式編譯過程Linux編譯
- openssl原始碼編譯及配置方法原始碼編譯