RamDisk (Initrd)小結

RamDisk(Initrd)小結:


名稱:
  initrd -- boot loader initialized RAM disk,就是由啓動加載器進行初始化的RAM DISK;
描述
   /dev/initrd這個特殊文件是一個只讀的塊設備文件。/dev/initrd設備文件是一個在內核被啓動之前由啓動加載器進行初始化的RAM disk。

   隨後,內核利用/dev/initrd設備文件的內容進行兩個階段的(系統)自舉。

   boot loader 會將存儲介質中的內核文件及 initrd文件(initrd會解壓縮後再釋放)加載到內存,然後內核進行初始化,內核啓動時會在訪問真正的根文件系統前先訪問該內存中的 initrd 文件系統。

   在(系統)自舉的第一個階段,掛載/dev/initrd中精簡的根文件系統。這個根文件系統包含必備的liunx目錄和程序,甚至也有一個init腳本(或程序linuxrc;在RedHat5中是init),必需的一些驅動模塊;然後執行init腳本,完成加載驅動及模塊的任務;腳本執行後期,會藉助剛纔加載的驅動及模塊掛載上真正的根文件系統,並且切換根文件系統從精簡的initrd根文件系統到根文件系統;


  在第二個階段,根文件系統已經被掛載,系統會運行真正根文件系統中的/sbin/init繼續完成系統其它的初始化工作;

  (在桌面或服務器 Linux 系統中,initrd 是一個臨時的文件系統。其生存週期很短,只會用作到真實文件系統的一個橋樑。在很多沒有存儲設備的嵌入式系統中,initrd 是永久的根文件系統;)
   
 補充:
  在真正的運行環境中,對內核需求是短小而精悍,不應該靜態包含進太多驅動模塊;所以其採用模塊化設計,大部分設備模塊是在需要使用時才加載相應驅動的。但是Linux內核啓動最後一步,需要掛載根文件系統,然後運行/sbin/init創建init內核線程來引導初始化系統。而根文件系統可能在硬盤、磁盤陣列、nfs、flash上,同時根文件系統的格式也是五花八門。此時,要是實在不想包含這麼多驅動到內核的話,可以使用initrd作爲一個過渡。另外,內核在編譯的時候,是可以選擇是否支持initrd,如果使用initrd,則系統自居是兩段式的。如果不使用initrd,需要編譯進去各種驅動(沒做過相關實驗,不發表見解:網上編譯內核教程一堆堆的,但是貌似很多問題,你要感覺那是理所當然的...就引導了o(╯□╰)o);並且如果換新的文件系統,但是恰好內核又沒有更換,這是胡恐怕只有重新編譯內核了而不是僅僅的只mkinitrd就完事大吉了。


下面是2.6內核對模塊選擇路徑:
Linux Kernel Configuration
  -> Device Drivers
   ->Block devices
    ->RAM block device support
     ->Default number of RAM disks  (設定Ramdisk的個數,默認是16)
     ->Default RAM disk size (kbytes) (設定Ramdisk的大小,默認4096k)
Linux Kernel Configuration
  ->General setup
   ->Inital RAM filesystem and RAM disk(initramfs/initrd) support
 

  如果對Ramdisk的支持已經編譯進內核,我們就可以使用它了,當然對於我RedHat5.4來說默認是使用該項的;

RamDisk文件系統中腳本init作用:
    init文件是RamDisk的核心文件,其中的其他文件都是爲該腳本服務的;臨時Mount虛擬root,並自動運行該文件系統中的init腳本 文件 ,這個文件將實際加載真實物理root所需要的設備驅動模塊(如raid或scsi驅動),和文件系統驅動模塊,所有必需的驅動調入後,這個腳本將物理root Mount上,並卸下Ramdisk虛擬根文件系統,此時根文件系統就已經爲真實根文件系統了,然後系統進入正常引導,加載各service ,啓動應用程序;


init腳本的格式:

  1. #!/bin/nash 
  2. mount -t proc /proc /proc 
  3. setquiet 
  4. echo Mounting proc filesystem 
  5. echo Mounting sysfs filesystem 
  6. mount -t sysfs /sys /sys 
  7. echo Creating /dev 
  8. mount -o mode=0755 -t tmpfs /dev /dev 
  9. mkdir /dev/pts 
  10. mount -t devpts -o gid=5,mode=620 /dev/pts /dev/pts 
  11. mkdir /dev/shm 
  12. mkdir /dev/mapper 
  13. echo Creating initial device nodes 
  14. mknod /dev/null c 1 3 
  15. mknod /dev/zero c 1 5 
  16. mknod /dev/systty c 4 0 
  17. mknod /dev/tty c 5 0 
  18. mknod /dev/console c 5 1 
  19. mknod /dev/ptmx c 5 2 
  20. mknod /dev/rtc c 10 135 
  21. mknod /dev/tty0 c 4 0 
  22. mknod /dev/tty1 c 4 1 
  23. mknod /dev/tty2 c 4 2 
  24. mknod /dev/tty3 c 4 3 
  25. mknod /dev/tty4 c 4 4 
  26. mknod /dev/tty5 c 4 5 
  27. mknod /dev/tty6 c 4 6 
  28. mknod /dev/tty7 c 4 7 
  29. mknod /dev/tty8 c 4 8 
  30. mknod /dev/tty9 c 4 9 
  31. mknod /dev/tty10 c 4 10 
  32. mknod /dev/tty11 c 4 11 
  33. mknod /dev/tty12 c 4 12 
  34. mknod /dev/ttyS0 c 4 64 
  35. mknod /dev/ttyS1 c 4 65 
  36. mknod /dev/ttyS2 c 4 66 
  37. mknod /dev/ttyS3 c 4 67 
  38. echo Setting up hotplug. 
  39. hotplug 
  40. echo Creating block device nodes. 
  41. mkblkdevs 
  42. echo "Loading uhci-hcd.ko module" 
  43. insmod /lib/uhci-hcd.ko  
  44. echo "Loading ohci-hcd.ko module" 
  45. insmod /lib/ohci-hcd.ko  
  46. echo "Loading ehci-hcd.ko module" 
  47. insmod /lib/ehci-hcd.ko  
  48. mount -t usbfs /proc/bus/usb /proc/bus/usb 
  49. echo "Loading jbd.ko module" 
  50. insmod /lib/jbd.ko  
  51. echo "Loading ext3.ko module" 
  52. insmod /lib/ext3.ko  
  53. echo "Loading scsi_mod.ko module" 
  54. insmod /lib/scsi_mod.ko  
  55. echo "Loading sd_mod.ko module" 
  56. insmod /lib/sd_mod.ko  
  57. echo "Loading scsi_transport_spi.ko module" 
  58. insmod /lib/scsi_transport_spi.ko  
  59. echo "Loading mptbase.ko module" 
  60. insmod /lib/mptbase.ko  
  61. echo "Loading mptscsih.ko module" 
  62. insmod /lib/mptscsih.ko  
  63. echo "Loading mptspi.ko module" 
  64. insmod /lib/mptspi.ko  
  65. echo "Loading dm-mod.ko module" 
  66. insmod /lib/dm-mod.ko  
  67. echo "Loading dm-mirror.ko module" 
  68. insmod /lib/dm-mirror.ko  
  69. echo "Loading dm-zero.ko module" 
  70. insmod /lib/dm-zero.ko  
  71. echo "Loading dm-snapshot.ko module" 
  72. insmod /lib/dm-snapshot.ko  
  73. echo Waiting for driver initialization. 
  74. stabilized --hash --interval 250 /proc/scsi/scsi 
  75. echo Making device-mapper control node 
  76. mkdmnod 
  77. mkblkdevs 
  78. echo Scanning logical volumes 
  79. lvm vgscan --ignorelockingfailure 
  80. echo Activating logical volumes 
  81. lvm vgchange -ay --ignorelockingfailure   VolGroup00 
  82. resume /dev/VolGroup00/LogVol01 
  83. echo Creating root device. 
  84. mkrootdev -t ext3 -o defaults,ro /dev/VolGroup00/LogVol00 
  85. echo Mounting root filesystem. 
  86. mount /sysroot 
  87. echo Setting up other filesystems. 
  88. setuproot 
  89. echo Switching to new root and running init. 
  90. switchroot 
  91.  


  腳本執行過程分析:
  第一行#!/bin/nash是一個redhat自己的微型解釋器。只包含精簡的命令,能做基本的mount、insmod、mkdev等,主要是爲了減小iitrd體積;
   
  mount命令掛載上了initrd釋放出來的各種內核文件系統/proc、/sys、/dev到相應的位置;

  mknod生成各種設備節點;hotplug開始監聽系統總線熱插拔的磁盤等uevent事件。mkblkdevs將這些熱插拔的磁盤節點創建到/dev下。

  接着insmod開始安裝usb,block設備,scsi設備,ide設備,device-mapper的設備驅動,隨後系統總線就會收到這些事件,mkblkdevs又會把他們的節點創建到/dev下。我們的硬盤多數是在這個階段被找到並創建了相應的設備節點。然後是加載啓動邏輯卷管理,使我們的設備能使用邏輯卷名稱。這一步可以不要的

    然後是加載啓動邏輯卷管理,使我們的設備能使用邏輯卷名稱;(該步驟非必要)

  (重要)下面mkrootdev:該命令可以創建根文件系統的設備節點;查找內核參數當中的“root=”項;然後解析mkrootdev後面的-t 和-o參數,如果-t是nfs,而且,-o中包含dhcp,那麼root的相關信息從dhcp主機取得,如果-o選項不包含dhcp或者-t不是nfs, 則從root=內核參數取真正root文件系統的位置,如果沒有root=參數,使用mkrootdev後面的設備作爲root設備。如果是-t nfs那麼直接添加入口到/etc/fstab文件,包括-t的文件系統類型和-o的選項。如果-t指定的文件系統不是nfs,那麼它創建名稱爲/dev/root的節點,它的Major,Minor設備號使用root=參數的設備號(如果有),或mkrootdev後面的設備的設備號。;它不僅能夠根據root=/dev/xxx來生成對應的設備節點,還能夠在碰到root=LABEL=/ 的情況下探測所有的硬盤分區,以便找到對應着卷標爲/的分區。

  所以,mkrootdev -t ext3 -o defaults,ro /dev/VolGroup00/LogVol00這行,會將一條入口信息寫入內存中的/etc/fstab,如: /dev/root /sysroot ext3 defaults,ro 0 0 ;注意此時設備是/dev/root.而不是/dev/VolGroup00/LogVol00,但他們的設備號是一樣的。 
 
  緊接着後面的mount  /sysroot;就會讀取/etc/fstab並加載剛剛mkrootdev寫入的這條入口信息所指定的設備,這就是加載/dev/root 到/sysroot下。這時我們的真正的root才被加載到了系統中。nash在mount時,如果只有一個參數,以它作爲root加載點,且它必須是 /sysroot(會同fstab中的做比較)。如果有加載點和設備參數,-t -o必須也被提供,mount丟棄/etc/fstab中的入口的內容,而使用參數提供的信息加載root設備。若如本例,至此/sysroot下是真正物理系統的root分區。/是initrd的內存盤。 
 
  setuproot 並不接受任何參數,而以上面的/sysroot作爲我們的root。安裝所有的子分區到/sysroot下。也就是建立我們的根文件系統樹,如果我們的root 不是由單個分區組成的話。這些信息從/sysroot/etc/fstab.sys中讀取。如果它不存在,就從initrd的/etc /fstab.sys中讀取。如果仍然不存在,就建立默認的文件系統樹: 
 
  掛載(Bind掛載方式)/proc 到/sysroot/proc ,/sys到/sysroot/sys 
 
  最後switchroot卸載/dev,/proc,/sys文件系統,掛載(移動掛載方式)/sysroot到/下面.,然後卸載initrd的/。打開 /dev/console到描述符3,將stdin,stdout,stderr全部定向到3(console),分析內核參數,尋找init=,如果有,以它作爲init程序執行,否則,執行默認:搜尋第一個找到的/sbin/init;/etc/init;/bin/init;/bin/sh執行,這就 是所有進程的父進程0 
 

文章參考:

關於Linux-gate.so.1的含義: http://www.linuxidc.com/Linux/2007-07/6221.htm

Linux boot process (initrd part):http://bbs.kylin-linux.com/htm_data/9/1003/209.html
http://www.mike.org.cn/articles/linux-xiangjie-linux-initrd/
拓展參考: http://www.ibm.com/developerworks/cn/linux/l-initrd.html(IBM上面用busybox實現了一個精簡的initrd)

 整理過程,難免出錯,希望共同探討;

 

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