使用初始 RAM 磁碟 (initrd)¶
由 Werner Almesberger <werner.almesberger@epfl.ch> 和 Hans Lermen <lermen@fgan.de> 於 1996,2000 年編寫
initrd 提供了一種功能,可以透過引導載入程式載入 RAM 磁碟。然後可以將此 RAM 磁碟掛載為根檔案系統,並可以從中執行程式。之後,可以從不同的裝置掛載新的根檔案系統。然後將先前的根(來自 initrd)移動到目錄,並隨後可以解除安裝。
initrd 的主要設計目的是允許系統啟動分兩個階段進行,其中核心啟動時包含最小的一組編譯到核心中的驅動程式,並且從 initrd 載入其他模組。
本文件簡要概述了 initrd 的使用。有關引導過程的更詳細討論,請參見 [1]。
操作¶
使用 initrd 時,系統通常按以下方式啟動
引導載入程式載入核心和初始 RAM 磁碟
核心將 initrd 轉換為“普通” RAM 磁碟,並釋放 initrd 使用的記憶體
如果根裝置不是
/dev/ram0,則遵循舊的(已棄用)change_root 過程。請參見下面的“過時的根更改機制”部分。掛載根裝置。 如果它是
/dev/ram0,則將 initrd 映像掛載為根執行 /sbin/init(可以是任何有效的可執行檔案,包括 shell 指令碼;它以 uid 0 執行,並且基本上可以執行 init 可以執行的所有操作)。
init 掛載“真實”根檔案系統
init 使用 pivot_root 系統呼叫將根檔案系統放置在根目錄中
init 在新的根檔案系統上執行
/sbin/init,執行通常的啟動順序刪除 initrd 檔案系統
請注意,更改根目錄不涉及解除安裝它。 因此,可以在該過程中使程序在 initrd 上繼續執行。 另請注意,掛載在 initrd 下的檔案系統仍可訪問。
引導命令列選項¶
initrd 新增以下新選項
initrd=<path> (e.g. LOADLIN)
Loads the specified file as the initial RAM disk. When using LILO, you
have to specify the RAM disk image file in /etc/lilo.conf, using the
INITRD configuration variable.
noinitrd
initrd data is preserved but it is not converted to a RAM disk and
the "normal" root file system is mounted. initrd data can be read
from /dev/initrd. Note that the data in initrd can have any structure
in this case and doesn't necessarily have to be a file system image.
This option is used mainly for debugging.
Note: /dev/initrd is read-only and it can only be used once. As soon
as the last process has closed it, all data is freed and /dev/initrd
can't be opened anymore.
root=/dev/ram0
initrd is mounted as root, and the normal boot procedure is followed,
with the RAM disk mounted as root.
壓縮的 cpio 影像¶
最近的核心支援從壓縮的 cpio 存檔填充 ramdisk。 在這種系統上,ramdisk 映像的建立不需要特殊的塊裝置或環回; 您只需在磁碟上建立一個具有所需 initrd 內容的目錄,cd 到該目錄,然後執行(例如)
find . | cpio --quiet -H newc -o | gzip -9 -n > /boot/imagefile.img
檢查現有影像檔案的內容同樣簡單
mkdir /tmp/imagefile
cd /tmp/imagefile
gzip -cd /boot/imagefile.img | cpio -imd --quiet
安裝¶
首先,必須在“普通”根檔案系統上建立 initrd 檔案系統的目錄,例如
# mkdir /initrd
名稱不相關。 有關更多詳細資訊,請參見 pivot_root(2) 手冊頁。
如果在引導過程中建立了根檔案系統(即,如果您正在構建安裝軟盤),則根檔案系統建立過程應建立 /initrd 目錄。
如果 initrd 在某些情況下不會被掛載,如果建立了以下裝置,仍然可以訪問其內容
# mknod /dev/initrd b 1 250
# chmod 400 /dev/initrd
其次,必須編譯核心,啟用 RAM 磁碟支援和初始 RAM 磁碟支援。 此外,至少必須將執行 initrd 中的程式所需的所有元件(例如,可執行檔案格式和檔案系統)編譯到核心中。
第三,必須建立 RAM 磁碟映像。 這是透過在塊裝置上建立檔案系統,根據需要將檔案複製到其中,然後將塊裝置的內容複製到 initrd 檔案來完成的。 對於最近的核心,至少有三種類型的裝置適合該方法
軟盤(隨處可用,但速度很慢)
RAM 磁碟(速度快,但分配物理記憶體)
環回裝置(最優雅的解決方案)
我們將描述環回裝置方法
確保環回塊裝置已配置到核心中
建立適當大小的空檔案系統,例如
# dd if=/dev/zero of=initrd bs=300k count=1 # mke2fs -F -m0 initrd(如果空間至關重要,則可能需要使用 Minix FS 代替 Ext2)
掛載檔案系統,例如
# mount -t ext2 -o loop initrd /mnt建立控制檯裝置
# mkdir /mnt/dev # mknod /mnt/dev/console c 5 1複製正確使用 initrd 環境所需的所有檔案。 不要忘記最重要的檔案
/sbin/init注意
/sbin/init許可權必須包括“x”(執行)。即使不使用命令重新啟動,也可以經常測試initrd環境的正確操作
# chroot /mnt /sbin/init當然,這僅限於不干擾常規系統狀態(例如,重新配置網路介面,覆蓋已掛載的裝置,嘗試啟動已在執行的守護程式等)的initrd。 但是請注意,通常可以在這種chroot'ed initrd環境中使用pivot_root。)
解除安裝檔案系統
# umount /mntinitrd 現在位於檔案“initrd”中。 可選擇對其進行壓縮
# gzip -9 initrd
為了嘗試 initrd,您可能需要使用救援軟盤,並且僅將從 /sbin/init 到 /bin/sh 的符號連結新增到其中。 或者,您可以嘗試實驗性的 newlib 環境 [2] 來建立一個小的 initrd。
最後,您必須啟動核心並載入 initrd。 幾乎所有 Linux 引導載入程式都支援 initrd。 由於引導過程仍然與較舊的機制相容,因此必須給出以下引導命令列引數
root=/dev/ram0 rw
(僅當寫入 initrd 檔案系統時才需要 rw。)
使用 LOADLIN,您只需執行
LOADLIN <kernel> initrd=<disk_image>
例如
LOADLIN C:\LINUX\BZIMAGE initrd=C:\LINUX\INITRD.GZ root=/dev/ram0 rw
使用 LILO,您可以將選項 INITRD=<path> 新增到全域性部分或 /etc/lilo.conf 中相應核心的部分,並使用 APPEND 傳遞選項,例如
image = /bzImage
initrd = /boot/initrd.gz
append = "root=/dev/ram0 rw"
並執行 /sbin/lilo
有關其他引導載入程式,請參考相應的文件。
現在您可以啟動並享受使用 initrd 的樂趣了。
更改根裝置¶
完成其職責後,init 通常會更改根裝置,並繼續在“真實”根裝置上啟動 Linux 系統。
- 該過程包括以下步驟
掛載新的根檔案系統
將其變成根檔案系統
刪除對舊(initrd)根檔案系統的所有訪問
解除安裝 initrd 檔案系統並釋放 RAM 磁碟
掛載新的根檔案系統很容易:只需將其掛載在當前根下的目錄中即可。 例子
# mkdir /new-root
# mount -o ro /dev/hda1 /new-root
根更改透過 pivot_root 系統呼叫完成,該呼叫也可透過 pivot_root 實用程式獲得(請參見 pivot_root(8) 手冊頁;pivot_root 隨 util-linux 版本 2.10h 或更高版本一起分發 [3])。 pivot_root 將當前根移動到新根下的目錄,並將新根放在其位置。 用於舊根的目錄必須在呼叫 pivot_root 之前存在。 例子
# cd /new-root
# mkdir initrd
# pivot_root . initrd
現在,init 程序可能仍然透過其可執行檔案、共享庫、標準輸入/輸出/錯誤及其當前根目錄訪問舊根。 所有這些引用都透過以下命令刪除
# exec chroot . what-follows <dev/console >dev/console 2>&1
其中 what-follows 是新根下的程式,例如 /sbin/init。 如果新根檔案系統將與 udev 一起使用,並且沒有有效的 /dev 目錄,則必須先初始化 udev,然後才能呼叫 chroot,以提供 /dev/console。
注意:pivot_root 的實現細節可能會隨著時間的推移而變化。 為了確保相容性,應注意以下幾點
在呼叫 pivot_root 之前,呼叫程序的當前目錄應指向新的根目錄
使用 . 作為第一個引數,並使用舊根目錄的_相對_路徑作為第二個引數
chroot 程式必須在舊根和新根下都可用
之後 chroot 到新根
在 exec 命令中使用 dev/console 的相對路徑
現在,可以解除安裝 initrd,並且可以釋放 RAM 磁碟分配的記憶體
# umount /initrd
# blockdev --flushbufs /dev/ram0
也可以將 initrd 與 NFS 掛載的根一起使用,有關詳細資訊,請參見 pivot_root(8) 手冊頁。
使用場景¶
實現 initrd 的主要動機是允許在系統安裝時進行模組化核心配置。 該過程將按以下方式工作
系統從軟盤或其他介質啟動,該介質具有最小的核心(例如,對 RAM 磁碟、initrd、a.out 和 Ext2 FS 的支援)並載入 initrd
/sbin/init確定需要什麼來 (1) 掛載“真實”根 FS(即裝置型別、裝置驅動程式、檔案系統)和 (2) 分發介質(例如 CD-ROM、網路、磁帶等)。 這可以透過詢問使用者、自動探測或使用混合方法來完成。
/sbin/init載入必要的核心模組
/sbin/init建立並填充根檔案系統(這不必是一個非常可用的系統)
/sbin/init呼叫pivot_root以更改根檔案系統,並透過 chroot 執行一個繼續安裝的程式安裝引導載入程式
引導載入程式被配置為載入一個 initrd,其中包含用於啟動系統的模組集(例如,可以修改
/initrd,然後將其解除安裝,最後將映像從/dev/ram0或/dev/rd/0寫入到檔案中)現在系統可以啟動,並且可以執行其他安裝任務
initrd 在這裡的關鍵作用是在正常系統操作期間重新使用配置資料,而無需使用臃腫的“通用”核心或重新編譯或重新連結核心。
第二種情況是,Linux 在單個管理域中具有不同硬體配置的系統上執行的安裝。 在這種情況下,希望只生成一小部分核心(理想情況下只有一個),並儘可能保持系統特定配置資訊的大小。 在這種情況下,可以生成一個包含所有必要模組的通用 initrd。 然後,只有 /sbin/init 或它讀取的檔案必須不同。
第三種情況是更方便的恢復磁碟,因為不必在啟動時提供諸如根 FS 分割槽位置之類的資訊,而是可以從 initrd 載入的系統可以呼叫使用者友好的對話方塊,並且還可以執行一些健全性檢查(甚至某種形式的自動檢測)。
最後,CD-ROM 發行商可以使用它來更好地從 CD 進行安裝,例如,透過使用啟動軟盤並透過 initrd 從 CD 引導更大的 RAM 磁碟; 或者透過像 LOADLIN 這樣的載入程式或直接從 CD-ROM 啟動,並從 CD 載入 RAM 磁碟而無需軟盤。
過時的根更改機制¶
在引入 pivot_root 之前使用了以下機制。 當前的核心仍然支援它,但是您_不_應該依賴於它的持續可用性。
它的工作方式是,當 linuxrc 退出時,將“真實”根裝置(即核心映像中使用 rdev 設定的或引導命令列中使用 root=... 設定的裝置)掛載為根檔案系統。 然後解除安裝 initrd 檔案系統,或者,如果它仍然繁忙,則如果新根檔案系統上存在這樣的目錄,則將其移動到目錄 /initrd。
為了使用此機制,您不必指定引導命令選項 root、init 或 rw。(如果指定,它們將影響真實根檔案系統,而不是 initrd 環境。)
如果掛載了 /proc,則可以透過將新根 FS 裝置的編號寫入特殊檔案 /proc/sys/kernel/real-root-dev,從 linuxrc 中更改“真實”根裝置,例如
# echo 0x301 >/proc/sys/kernel/real-root-dev
請注意,該機制與 NFS 和類似的檔案系統不相容。
這種舊的、已棄用的機制通常稱為 change_root,而新的、受支援的機制稱為 pivot_root。
混合 change_root 和 pivot_root 機制¶
如果您不想使用 root=/dev/ram0 來觸發 pivot_root 機制,則可以在 initrd 映像中同時建立 /linuxrc 和 /sbin/init。
/linuxrc 將僅包含以下內容
#! /bin/sh
mount -n -t proc proc /proc
echo 0x0100 >/proc/sys/kernel/real-root-dev
umount -n /proc
一旦 linuxrc 退出,核心將再次將您的 initrd 掛載為根,這次執行 /sbin/init。 同樣,此 init 的職責是在最終執行真實 /sbin/init 之前,構建正確的環境(可能使用在 cmdline 上傳遞的 root= 裝置)。