上節講到了Linux啟動大體流程,及grub的作用,本節主要扯扯initramfs的那些事,并且通過簡單修改initramfs,將整體操作系統運行到了內存中。
3 initramfs3.1 簡述在2.4內核中initrd為boot loader initialized RAM Disk,linux啟動前boot loader先將initrd文件解壓,并加載到內存中。boot loader加載內核后,會先運行initrd,再switch_root到真正root fs。
在2.6內核中將initrd升級為initramfs,與initrd相比其作用相同,但是initramfs流程更加簡潔,即解壓initramfs后,運行init腳本,所以任務交由init腳本來完成。
更多initrd與initramfs的說明可參見文獻[3]。
[3]:Linux2.6內核的Initrd機制解析http://www.ibm.com/developerworks/cn/linux/l-k26initrd/
3.2 init基本流程initramfs的真正作用加載硬件模塊和文件系統模塊,用于切換到root device上的真正的root fs上。當然由于root fs應該支持存在于md或者dm設備上,所以在initramfs期間也會加載md和dm模塊,如果md編譯進行了內核的話,從加載的模塊中是查看不到的。
以下是通過在initramfs中的init文件中添加log,分析一個大概的開機流程,非細節。
1) 解壓并加載initramfs到內存后,當前root fs就是initramfs,所以/下所有文件都來源于initramfs。
2) 通過掛載/PRoc和/sys;mknod創建基本的設備/dev/console、/dev/null等。
3) udev規則對硬件進行掃描,加載對應模塊,創建對應設備,對于grub.conf中設置的root設備,若創建成功,則會在/dev/下創建/dev/root的鏈接指向對應真實設備。
4) 與此同時,無限循環判斷/dev/root是否已存在,若不存在,再次執行所有udev規則,嘗試是否有新硬件已準備就緒,判斷40次后(約20秒),仍未找到,則報出“no root device fonud, sleep forever”
5) 通過root device掛載真正的root fs。
6) 判斷/proc目錄是否存在,作為root fs已掛載成功的標準(此時的/proc僅僅是個空目錄)。
7) 判斷真正的root fs的init腳本是否存在,一般是/sbin/init
8) root fs已掛載到/sysroot目錄后,執行switch_root /sysroot /sbin/init。
9) switch_root命令執行后,initramfs的任務全部完成,切換到真正的root fs,開始執行/sbin/init
3.3 initramfs過程中的模塊加載情況begin init:
Opening /proc/modules: No such file or directory
pre udev:
Module Size Used by
after udev:
Module Size Used by
sd_mod 37157 0
crc_t10dif 1507 1 sd_mod
sr_mod 16162 0
cdrom 39769 1 sr_mod
mptspi 16537 0
mptscsih 35302 1 mptspi
mptbase 91106 2 mptspi,mptscsih
scsi_transport_spi 26117 1 mptspi
pata_acpi 3667 0
ata_generic 3611 0
ata_piix 22588 0
dm_mod 76856 0
after mount root fs, before switch root:
Module Size Used by
ext4 353883 1
mbcache 7918 1 ext4
jbd2 88969 1 ext4
sd_mod 37157 2
crc_t10dif 1507 1 sd_mod
sr_mod 16162 0
cdrom 39769 1 sr_mod
mptspi 16537 1
mptscsih 35302 1 mptspi
mptbase 91106 2 mptspi,mptscsih
scsi_transport_spi 26117 1 mptspi
pata_acpi 3667 0
ata_generic 3611 0
ata_piix 22588 0
dm_mod 76856 0
3.4 initramfs的解壓&&壓縮1、 解壓:
-bash-4.1# file initramfs-2.6.32-71.el6.5.vsds.x86_64.img
initramfs-2.6.32-71.el6.5.vsds.x86_64.img: gzip compressed data, from Unix, last modified: Tue Dec 18 17:25:14 2012, max compression
# gzip文件格式,所以需要先mv為gz文件
-bash-4.1# mv initramfs-2.6.32-71.el6.5.vsds.x86_64.img initramfs-2.6.32-71.el6.5.vsds.x86_64.img.gz
-bash-4.1# file initramfs-2.6.32-71.el6.5.vsds.x86_64.img
initramfs-2.6.32-71.el6.5.vsds.x86_64.img: ASCII cpio archive (SVR4 with no CRC)
-bash-4.1# gunzip initramfs-2.6.32-71.el6.5.vsds.x86_64.img.gz
initramfs-2.6.32-71.el6.5.vsds.x86_64.img
#此時為cpio格式
-bash-4.1# mkdir initramfs
-bash-4.1# cd initramfs
-bash-4.1# cpio -id ../initramfs
initramfs/ initramfs-2.6.32-71.el6.5.vsds.x86_64.img
-bash-4.1# cpio -id < ../initramfs-2.6.32-71.el6.5.vsds.x86_64.img
72953 blocks
2、 壓縮:
-bash-4.1# find . | cpio -c -o > ../initramfs-2.6.32-71.el6.5.vsds.x86_64.img
72953 blocks
-bash-4.1# gzip ../initramfs-2.6.32-71.el6.5.vsds.x86_64.img
-bash-4.1# cp ../initramfs-2.6.32-71.el6.5.vsds.x86_64.img.gz /boot
3.5 實例---將整個操作系統運行在內存以下使用方案并未真正應用,以下純屬個人理解,供參考。
3.5.1 優點 && 缺點1、優點:
1) 運行速度更快。開機后,由于系統運行在內存,運行速度要更快。
2) 文件系統不會損壞。系統異常斷電,或者其它破壞操作,不會引起操作系統損壞。
3) 節省存儲介質空間。操作系統可以進行壓縮后存放在可存儲介質中(壓縮率約80%),甚至可以存放在網絡環境上,開機后,解壓再到內存。
4) 便于多臺系統統一升級升級。若系統壓縮文件存放在網絡環境上,那么文件升級,使用這個文件的任意臺設備升級過程就僅僅是重啟就可以做到。
2、缺點:
1) 開機速度略慢。由于啟動過程需要將操作系統解壓到內存,會略慢一點,約10 ~ 20秒不明顯。
2) root fs無法存儲數據。由于系統運行在內存,重啟后新存儲的丟失。因此,一般需要存儲數據的分區單獨掛載一個非易失的介質上。
3) 內存要求更大。由于內存固定部分會劃分一個ram disk,用于運行操作系統。對于操作系統就需要900M空間的應用,內存2G就不足以支撐整個系統。
4) 更新系統較麻煩。對于需要頻率更改系統的環境,若要生效,需要重新制作壓縮文件,較麻煩。
3.5.2 應用場景目前嵌入式系統大多使用此方案,應該是基于其較小的存儲空間,及無用戶寫入數據要求而決定的。(本人不是做嵌入式的,純屬個人猜測哈)
3.5.3 實現思路思路一:就是把整體系統做成initramfs。(未測試)
initramfs就是一個小文件系統,也是開機第一個加載的文件系統,所以把整體系統都做成initramfs,那么系統啟動只需要2個文件即可,一是內核vmlinux;二是initramfs。
也就是說在initramfs最后要切換到真正的root fs時,不切換到了,直接運行系統中的/sbin/init。
但是initramfs可能會達到300M(root fs900M左右),boot loader會不會需要加載很長時間?
思路二:在initramfs運行過程中,將壓縮的系統解壓并復制到內存中運行
在上節已說明initramfs其實就是執行一個init腳本,簡單修改腳本流程。當尋到到root device設備后,將掛載root device掛載到/sysroot修改為,掛載root device到其它掛載點,再從root device中找到之前制作的壓縮的系統文件,將文件解壓到ramdisk中,掛載ramdisk到/sysroot,再切換到真正的root fs。
3.5.4 實現代碼以下僅根據思路二為基本,完成的一個簡單模型。
將系統文件解壓并復制到內存,那么先得將真正的root fs制作為一個系統文件,再通過initramfs的過程將其加載到內存。
1、 root fs文件ramlinux.img.gz的制作。
開始只將參考資料[2]中文件制作為了ramlinux.img.gz(壓縮后約80M,解壓后給不到200M),開機系統就panic,想必是應該缺少文件導致,所以,就將整個/下所有文件都制作到ramdisk.img.gz中,系統正常運行。
制作ramdisk.img.gz的腳本為mkrootfs.sh如下:
#!/bin/sh
rootfs="/mnt/ram"
umount $rootfs
rm -rf $rootfs
# make ram disk and mount
dd if=/dev/zero of=/dev/ram bs=1M count=900
echo y | mkfs.ext2 /dev/ram
mkdir $rootfs
mount -o loop /dev/ram $rootfs
# cp file to ram disk
pre_dir="/"
#pre_dir="/mnt/sdf1/"
# all file in dir cp to ram disk
cpdir=(bin boot cgroup etc home lib lib64 media opt sbin selinux srv usr var)
for dir_i in ${cpdir[@]}
do
echo "cp -av $pre_dir$dir_i $rootfs"
cp -av $pre_dir$dir_i $rootfs
done
# just mkdir, not cp file
mkdir=(proc sys tmp mnt root)
for dir_j in ${mkdir[@]}
do
echo "mkdir $rootfs/$dir_j"
mkdir $rootfs/$dir_j
done
# create dev device
mkdir $rootfs/dev
dev=`find /dev`
for dev_i in ${dev[@]}
do
if [ $dev_i = "/dev/ram" -o $dev_i = "/dev" ]
then
echo "find $dev_i pass........................................... "
continue
fi
echo "cp -R $dev_i $rootfs/dev"
cp -R $dev_i $rootfs/dev
done
# do ramlinux.img from ram disk
umount $rootfs
dd if=/dev/ram of=/mnt/bigspace/ramlinux.img bs=1M
gzip /mnt/bigspace/ramlinux.img
2、 initramfs加載root fs文件ramlinux.img.gz。
initramfs掛載真正的root fs,是通過執行initramfs的mount目錄下的*.sh來完成的,在mount目錄下加入98mount-ramdisk.sh,移除99mount-root.sh(原掛載root device到/sysroot的腳本)。由98mount-ramdisk.sh來完成系統文件的解壓,及掛載。
98mount-ramdisk.sh如下:
#!/bin/sh
echo "Mount root device for get img file"
mount -o defaults --rw /dev/root /mnt
echo "zcat img file to ram"
/bin/zcat /mnt/root/ramlinux.img.gz > /dev/ram
umount /mnt
echo "mount -o loop /dev/ram /sysroot"
mount -o loop /dev/ram /sysroot
echo "ls /sysroot"
/bin/ls /sysroot/
[ -d "/sysroot/proc" ] || echo "proc not exist 5555555555555555555........"
3、 完成以上步驟后,將initramfs解壓,拷貝98mount-ramdisk.sh到mount目錄下,刪除99mount-root.sh,重新生成initramfs,覆蓋/boot下的原文件,重啟即生效。
4、 其它注意。由于解壓ramlinux.img需要zcat命令,但此命令initramfs中未加入,因此,還需要從系統中拷貝zcat命令到initramfs的bin目錄下。(拷貝命令前,需要通過ldd /bin/zcat查看該命令是否有對應動態鏈接庫,如果有要一并cp-R到initramfs的對應目錄下,否則僅拷貝命令,命令是無法執行的)
5、 重啟后的系統環境:
a) 重啟后,系統從掛載信息即可看出當前系統已運行在內存中,并且touch的新文件,重啟無未保存,掛載信息如下:
-bash-4.1# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 886M 886M 0 100% /
tmpfs 2.0G 52M 1.9G 3% /dev/shm
/dev/sda2 146M 32M 106M 24% /var/log
(/的掛載設備應該不是/dev/sda1,應該是df命令在當前模型下顯示的問題,應該是/dev/ram,由于只是簡單模型搭建,很多配置未修改成導致。)
b) /dev/sda1是grub.conf中設置的root device,也是ramlinux.img文件真正存儲的介質。
-bash-4.1# cat /boot/grub/grub.conf
# grub.conf generated by anaconda
#
# Note that you do not have to rerun grub after making changes to this file
# NOTICE: You do not have a /boot partition. This means that
# all kernel and initrd paths are relative to /, eg.
# root (hd0,0)
# kernel /boot/vmlinuz-version ro root=/dev/sda1
# initrd /boot/initrd-[generic-]version.img
#boot=/dev/sda
default=0
timeout=5
splashimage=(hd0,0)/boot/grub/splash.xpm.gz
hiddenmenu
title SkySAN Storage System (2.6.32-71.el6.5.vsds.x86_64)
root (hd0,0)
kernel /boot/vmlinuz-2.6.32-71.el6.5.vsds.x86_64 ro root=UUID=212c95a4-56d0-44fc-93ce-73b5f3e8cf2a rd_NO_LUKS rd_NO_LVM rd_NO_MD rd_NO_DM LANG=en_US.UTF-8 SYSFONT=latarcyrheb-sun16 KEYBOARDTYPE=pc KEYTABLE=us
initrd /boot/initramfs-2.6.32-71.el6.5.vsds.x86_64.img
3.6 init腳本中加入log信息在理解init腳本過程中,為了更深入的理解init的作用,及當前環境狀態,往往需要打印一些我們自己需要的信息,在打印到屏幕的同時,如果可能保存文件,便于多次閱讀更好。
方法如下:
logfile="/tmp/logfile"
# tee用于將輸出到屏幕的信息,同時保存文件,-a:不覆蓋文件原內容,相當于>>
echo "begin init -------------------------------------------------------" 2>&1 | tee -a $logfile
lsmod 2>&1 | tee -a $logfile
sleep 5
……
#在swith_root前,將文件拷貝到/dev/目錄下,切換到root fs后,可以保留。
cp $logfile /dev/
exec switch_root "$NEWROOT" "$INIT" $initargs
……
新聞熱點
疑難解答