天天看點

linux檔案系統初始化過程(4)---加載initrd(中)一、目的 二、函數調用過程 三、initcall簡介 四、加載initrd檔案 五、總結

    上文詳細介紹了CPIO格式的initrd檔案,本文從源代碼角度分析加載并解析initrd檔案的過程。

    initrd檔案和linux核心一般存儲在磁盤空間中,在系統啟動階段由bootload負責把磁盤上的核心和initrd加載到指定的記憶體空間中;然後,再由核心讀取和解析initrd檔案,在VFS(目前隻有rootfs的根目錄)中建立目錄、正常檔案、符号連結檔案以及特殊檔案;這樣VFS就從根目錄"/"成長為一棵枝繁葉茂的大樹了。

    initrd詳細的加載過程在init/initramfs.c中實作的,為了更好的了解加載過程,我們給出了關鍵函數的調用關系圖1。這裡需要注意下,由于使用roofs_initcall()宏在initcallroofs段中注冊了populate_rootfs()函數,是以在執行do_initcalls()函數時會隐示調用populate_rootfs()。

linux檔案系統初始化過程(4)---加載initrd(中)一、目的 二、函數調用過程 三、initcall簡介 四、加載initrd檔案 五、總結

                                圖1

    linux在代碼段中定義了一個特殊的段initcall,該段中存放的都是函數指針;linux初始化階段調用do_initcalls()依次執行該段的函數。關于該段的詳細資訊可以參見vmlinux.lds.S連結腳本。

    使用者可以調用以下一組宏在initcall段中注冊函數指針;initcall段分為initcall0-initcall7這8個等級,initcall0段的優先級最高,initcall7段的優先級最低,優先級高的段最先被執行;initcallrootfs段優先級介于5和6之間。

  使用者使用不同優先級的initcall宏可以很友善的在linux代碼中注冊函數指針;将這些函數指針存儲在相應的initcall段中;最終,由do_initcalls()按照優先級依次執行段中的函數,具體的代碼實作如下:

回到加載initrd這個話題中,在init/initram.c的最後使用rootfs_initcall宏注冊了populate_rootfs()函數;基于以上分析,我們知道這裡就是加載initrd檔案的入口,下面就開始分析該函數的功能。

    系統啟動階段,bootload将initrd加載到記憶體起始位址為initrd_start,結束位址為initrd_end的記憶體中。

    populate_rootfs()調用unpack_to_rootfs()從記憶體中讀取并解析initrd檔案;根據CPIO的格式我們知道initrd檔案是由很多個段組成,且段中又是由檔案頭、檔案名和檔案體組成,是以該解析程式可以使用了狀态機原理處理initrd檔案。

    解析程式定義了以下8種狀态:Start(初始狀态)、Collect(擷取符号連結檔案資訊狀态)、GotHeader(擷取檔案頭資訊狀态)、SkipIt(跳過該段狀态)、GotName(擷取檔案名并建立檔案狀态)、CopyFile(寫檔案狀态)、GotSymlink(建立符号連結檔案狀态)、Reset(終止狀态)。

    為了直覺了解initrd檔案的解析過程,下面給出狀态機跳轉圖2。

    從圖中可以看出将檔案分為符号連結和非符号連結兩種情況處理,這是因為符号連結檔案是一種特殊的檔案,隻有第一個符号連結檔案的inode存儲的是真實資料,而其他符号連結檔案inode中存儲的是第一個符号連結檔案的路徑名,是以需要把第一個符号連結檔案的路徑名緩存起來,緩存的資料結構是hash表,是以在處理符号連結檔案時多了一些hash表的操作,是以分為了符号連結檔案和非符号連結檔案這兩種情況來處理。

    initrd檔案的詳細解析過程如下:

    1、S0:初始狀态,初始化一些全局變量;

    2、S1:擷取符号連結檔案的檔案頭和檔案體;

    3、S2:根據CPIO格式的定義,擷取檔案頭資訊;

    4、S3:跳過目前CPIO格式的段,繼續處理下一個段;

    5、S4:擷取檔案名,并在VFS中建立檔案;

    6、S5:将檔案内容寫入到建立檔案中;

    7、S6:建立符号連結檔案;

    8、S7:處理完目前CPIO格式的段,繼續一個段的處理。

    從圖中還可以看出,由于目錄檔案和特殊檔案沒有檔案内容,是以跳過了S5狀态,直接進入S3狀态。

linux檔案系統初始化過程(4)---加載initrd(中)一、目的 二、函數調用過程 三、initcall簡介 四、加載initrd檔案 五、總結

                                                                     圖2

    通過以上分析,程式就可以成功解析initrd檔案,并使用sys_dir()、sys_open()、sys_mknod()、sys_symlink()等系統調用建立目錄、正常檔案、特殊檔案和符号連結檔案了。此時,VFS從隻有根目錄"/"成長為了一棵内容豐富的大樹。

繼續閱讀