Linux系統內存磁盤初始化技術詳細解析

 

Linux內存初始化技術(initrd)用於支持兩階段的系統引導過程,是在系統啓動過程中被掛載的臨時root文件系統(譯者注:這裏的root文件系統是指的根文件系統)。initrd包含很多可執行程序和驅動,並允許在臨時的內存磁盤根文件系統被卸載,內存被釋放後掛載真實的root文件系統。在許多嵌入式Linux文件系統中,initrd是最終的根文件系統。這篇文章主要講解了linux2.6內核的initrd技術,包括在內核中的創建及使用。
1 什麼是內存磁盤初始化?
initrd掛載優先級高於真實根文件系統,它被邦定在內核上,做爲內核啓動過程的一部分被加載(load)。然後,做爲兩階段引導過程的第一部分,內核掛載(mount)initrd,用於獲得並加載真實有效的文件系統。
爲了達到這個目的,initrd包含有最起碼的目錄與程序,例如insmod,來安裝內核模塊到內核中。
對於桌面或服務器linux,initrd是臨時文件系統,它的生存週期很短,僅僅是做爲到達真實根文件系統的橋樑。但對於沒有存儲設備的嵌入式系統來說,它纔是永久性的根文件系統。本篇文章對這兩方面均有涉及。
2 深入分析initrdL
initrd包含有必須的程序和系統文件,用於支持系統的啓動的第二階段過程。創建初始化內存的方法,是隨着你所使用的系統版本而改變的。從Fedora Core3以後,initrd就由回送設備(loop device)建立。什麼是回送設備?它是一個設備驅動,允許你將一個文件掛載爲塊設備,並對其文件系統做出描述。也許loop device並不存在與你的內核中,但是你能夠通過內核的配置工具(make menuconfig)打開它。路徑是:Device Drivers-》Block Devices-》LoopBack Device support。下面爲檢查命令:

# mkdir temp ; cd temp 

# cp /boot/initrd.img.gz . 

# gunzip initrd.img.gz 

# mount -t ext -o loop initrd.img /mnt/initrd 

# ls -la /mnt/initrd 

#

現在,你可以通過查看/mnt/initrd的子目錄來查看initrd的內容。需要注意的是,即使你的initrd鏡像文件並不是以.gz做爲後綴名,但是你同樣可以通過增加此後綴名來讓gunzip打開它。
從Fedora Core3開始,默認的initrd鏡像就是一個壓縮的gpio歸檔文件。除了用掛載文件的方式以外,你同樣可以通過cpio歸檔的方式來將其掛載成使用了回送設備的壓縮鏡像。你可以通過以下的指令來檢查這個cpio歸檔文件的內容:

# mkdir temp ; cd temp 

# cp /boot/initrd-2.6.14.2.img initrd-2.6.14.2.img.gz 

# gunzip initrd-2.6.14.2.img.gz 

# cpio -i --make-DirectorIEs < initrd-2.6.14.2.img

你看到的結果將是一個小型根文件系統,如下所示:

# ls -la 

# 

drwxr-xr-x 10 root root 4096 May 7 02:48 . 

drwxr-x--- 15 root root 4096 May 7 00:54 .. 

drwxr-xr-x 2 root root 4096 May 7 02:48 bin 

drwxr-xr-x 2 root root 4096 May 7 02:48 dev 

drwxr-xr-x 4 root root 4096 May 7 02:48 etc 

-rwxr-xr-x 1 root root 812 May 7 02:48 init 

-rw-r--r-- 1 root root 1723392 May 7 02:45 initrd-2.6.14.2.img 

drwxr-xr-x 2 root root 4096 May 7 02:48 lib 

drwxr-xr-x 2 root root 4096 May 7 02:48 loopfs 

drwxr-xr-x 2 root root 4096 May 7 02:48 proc 

lrwxrwxrwx 1 root root 3 May 7 02:48 sbin -> bin 

drwxr-xr-x 2 root root 4096 May 7 02:48 sys 

drwxr-xr-x 2 root root 4096 May 7 02:48 sysroot 

#

一些小的,但是很有必要的程序組合能在./bin目錄下得到,包括nash(它不是一個shell,而是一個腳本解釋工具),用於加載內核模塊的insmod,以及lvm等。
上面所示目錄中,相對比較有趣的是root目錄下的初始化文件。這些文件,和傳統的linux啓動過程中一樣,是在initrd鏡像被解壓縮到RAM中時生成的。待會我們將繼續探討這個問題。
3 創建initrd的工具。
現在,讓我們回到一開始的討論:initrd的鏡像是如何被創建的?在傳統的linux系統中,initrd是在linux build的時候被創建的。像mkinitrd這樣的許許多多的工具,都能夠用於通過必須的庫和模塊來自動構建一個用於過渡到真實根文件系統的initrd。事實上,mkinitrd工具是一個腳本文件,因此,我們能夠很清楚得看到,這個過程是如何進行的。同樣的,YAIRD (Yet Another Mkinitrd)工具,也允許我們自定製每一個initrd被構建的階段。
4 自己動手,打造自定義的初始化內存盤
由於很多基於linux的嵌入式系統都沒有硬盤驅動器,initrd也可以做爲永久性的根文件系統。下面我就將告訴你們,如何創建一個initrd鏡像。我使用的是標準linux桌面系統,因此大家即使沒有嵌入式目標設備也可以照着做。除了交叉編譯以外,嵌入式目標文件的構建過程是相同的。

#!/bin/bash 

# Housekeeping... 

rm -f /tmp/ramdisk.img 

rm -f /tmp/ramdisk.img.gz 

# Ramdisk Constants 

RDSIZE=4000 

BLKSIZE=1024 

# Create an empty ramdisk image 

dd if=/dev/zero of=/tmp/ramdisk.img bs=$BLKSIZE count=$RDSIZE 

# Make it an ext2 mountable file system 

/sbin/mke2fs -F -m 0 -b $BLKSIZE /tmp/ramdisk.img $RDSIZE 

# Mount it so that we can populate 

mount /tmp/ramdisk.img /mnt/initrd -t ext2 -o loop=/dev/loop0 

# Populate the filesystem (subDirectorIEs) 

mkdir /mnt/initrd/bin 

mkdir /mnt/initrd/sys 

mkdir /mnt/initrd/dev 

mkdir /mnt/initrd/proc 

# Grab busybox and create the symbolic links 

pushd /mnt/initrd/bin 

cp /usr/local/src/busybox-1.1.1/busybox . 

ln -s busybox ash 

ln -s busybox mount 

ln -s busybox echo 

ln -s busybox ls 

ln -s busybox cat 

ln -s busybox ps 

ln -s busybox dmesg 

ln -s busybox sysctl 

popd 

# Grab the necessary dev files 

cp -a /dev/console /mnt/initrd/dev 

cp -a /dev/ramdisk /mnt/initrd/dev 

cp -a /dev/ram0 /mnt/initrd/dev 

cp -a /dev/null /mnt/initrd/dev 

cp -a /dev/tty1 /mnt/initrd/dev 

cp -a /dev/tty2 /mnt/initrd/dev 

# Equate sbin with bin 

pushd /mnt/initrd 

ln -s bin sbin 

popd 

# Create the init file 

cat >> /mnt/initrd/linuxrc << EOF 

#!/bin/ash 

echo 

echo "Simple initrd is active" 

echo 

mount -t proc /proc /proc 

mount -t sysfs none /sys 

/bin/ash --login 

EOF 

chmod +x /mnt/initrd/linuxrc 

# Finish up... 

umount /mnt/initrd 

gzip -9 /tmp/ramdisk.img 

cp /tmp/ramdisk.img.gz /boot/ramdisk.img.gz

想創建initrd的話,你需要首先創建一個空文件,將/dev/zero(0字符流)做爲ramdisk.img的輸入。得到的文件大小大約是4MB(有4000個1K的塊組成)。接下來,用mke2fs命令來創建一個使用這個空文件的ext2文件系統。現在,這個文件就是一個ext2文件系統。ok,接下來,以迴路設備的形式掛載這個文件到/mnt/initrd,現在,你就在掛載點擁有一個代表着ext2文件系統的目錄,並用與存放你的initrd。其他大多數的腳本語句都是用於實現這個功能。
下一步,就是創建一些必須的子目錄,用於生成你的根文件系統: /bin, /sys, /dev, 和 /pro。這裏只需要少數幾個目錄,例如,沒有/lib。但是它們已經包含了大部分功能。
如果想讓你的根文件系統發揮更大的作用,請使用 BusyBox。這個工具是一個包含了許多獨立工具的鏡像,這些獨立的工具你都能在linux中找到( ash, a等等wk, sed, insmod)。BusyBox的優勢在於,它把它們集合在了一起,並分享了公用的部分,從而極大縮小了鏡像的體積。這對於嵌入式系統來講,是非常理想的。請將BustBox鏡像從它的源目錄中複製出來,到你的/bin目錄下,這樣,很多指向BusyBox工具集的符號鏈接將被創建,BusyBox能確定哪一個工具將被使用,並自動引用它。這個/bin目錄下被創建的鏈接的小型集合將用於對啓動腳本的支持。
再下一步,就是一小部分特殊設備文件的創建。我從我的/dev文件夾中直接拷貝了出來,別忘了加上-a選項來保持它們原有的屬性。
倒數第二步,就是生成linuxrc文件。在內核掛載了內存盤之後,它將搜索並執行相關的啓動文件,如果沒有找到,內核就將linuxrc文件做爲其啓動腳本。你最好在這個文件中對環境變量做一些基本設置,例如掛載/proc文件系統等。除了/proc外,我還掛載了/sys文件系統,將消息發送給終端。最後,我調用ash並通過它和根文件系統交互。最後記住,用chmod把linuxrc文件的屬性改爲可執行。
最後,你的根文件系統算是ok了。現在它並沒有被掛載,用gzip將它壓縮,並將壓縮後的文件ramdisk.img.gz拷貝到/boot目錄下,這樣它就能被GRUB調用。
想要構建你的初始化ram盤的話,你只需要調用mkird,鏡像就將自動創建並拷貝到/boot目錄下。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章