Initrd原始碼分析

2021-07-23 19:11:33 字數 3390 閱讀 4957

initrd的作用有三:

1.提高系統的可移植性

把更多的核心功能條目編譯成模組,不僅僅是為了減小核心體積,更重要的是面對各種不同的硬體架構,可以使用initrd中的linuxrc按需進行模組載入以驅動硬體,甚至對於cpu型別或者多處理機也可以進行手工選擇核心(配合syslinux這類boot loader)

2.livecd(光碟上的linux)必備的部件

現在的可啟動光碟都沿用2023年制定的el torito標準,它的啟動原理在於模擬軟盤啟動映像,這個映像的大小一般被限制在2800kb,也就是兩張軟盤的大小,它包含了syslinux(也可以用isolinux,它對映像的大小要求更寬鬆),syslinux的配置檔案,initrd.img以及核心。這時候核心的大小就必須要有約束了(當然,也有來自1mb實模式記憶體空間的約束),把更多的模組壓縮進initrd.img中去,可以縮小啟動映像的體積。

最重要的是,linuxrc指令碼對於硬碟,光碟機模組的載入至關重要,因為livecd要適應盡量多的硬體架構,所以它必須能按需載入模組,這時候 initrd就派上用場了。比如說,我們在vmware裡執行knoppix,knoppix的linuxrc就自動載入buslogic.o模組(通過輪換insmod來實現)。

3.在linuxrc指令碼中可以很方便地啟用個性化bootsplash

給出initrd的原理圖例(請參看附件)以及相關原始碼分析:

/*init/do_mounts.c中的prepare_namespace函式 -- 確定系統的根檔案系統*/

void __init prepare_namespace(void)

is_floppy = major(root_dev) == floppy_major;

/*[2]嘗試處理initrd,見下*/

if (initrd_load())

goto out;

/*initrd_load()返回0,沒有處理initrd,存在以下兩種可能*/

/*或許已載入initrd但由於根裝置是ramdisk而沒有進行initrd處理,

則rd_doload==1,

呼叫rd_load_disk使用/dev/root取代上次rd_load_image中的/dev/root.old,root_dev=root_ram0*/

/*或許是沒有initrd以致,則rd_doload==0,root_dev!=root_ram0*/

/*rd_doload由arch/i386/kernel/setup.c中的setup_arch函式根據boot loader的命令列引數來決定*/

if (is_floppy && rd_doload && rd_load_disk(0))

root_dev = root_ram0;

/*根據root_dev掛載檔案系統*/

/*注意橙紅色標示的兩個mount_root()*/

mount_root();

/*無論有無經過initrd處理,最終為核心作最後chroot處理,確定系統的最終根檔案系統*/

out:

umount_devfs("/dev");

sys_mount(".", "/", null, ms_move, null);

sys_chroot(".");

security_sb_post_mountroot();

mount_devfs_fs ();

}

/*init/do_mounts_initrd.c*/

/*根據boot loader的命令列引數來判斷是否有initrd,如果沒有mount_initrd=0,否則為1*/

static int __initdata mount_initrd = 1;

static int __init no_initrd(char *str)

__setup("noinitrd", no_initrd);

...int __init initrd_load(void)

} sys_unlink("/initrd.image");

return 0;

}

/*init/do_mounts_initrd.c*/[/b]

/*執行linuxrc(通常是指令碼,由靜態鏈結的sh來執行)*/

/*linuxrc指令碼的作用通常有以下這些:*/

/*載入所需模組(比如在虛擬機器中從livecd啟動就應該要載入scsi模組buslogic.o)*/

/*改變/proc/sys/kernel/real-root-dev來改變隨後的正常根檔案系統(見handle_initrd函式)*/

static int __init do_linuxrc(void * shell)

; extern char * envp_init;

sys_close(old_fd);sys_close(root_fd);

sys_close(0);sys_close(1);sys_close(2);

sys_setsid();

(void) sys_open("/dev/console",o_rdwr,0);

(void) sys_dup(0);

(void) sys_dup(0);

return execve(shell, argv, envp_init);

}/*[1]核心函式handle_initrd--負責initrd的處理*/

static void __init handle_initrd(void)

/* move initrd to rootfs' /old */

sys_fchdir(old_fd);

sys_mount("/", ".", null, ms_move, null);

/* switch root and cwd back to / of rootfs */

sys_fchdir(root_fd);

sys_chroot(".");

sys_close(old_fd);

sys_close(root_fd);

umount_devfs("/old/dev");

if (new_decode_dev(real_root_dev) == root_ram0)

root_dev = new_decode_dev(real_root_dev);

mount_root();

printk(kern_notice "trying to move old root to /initrd ... ");

error = sys_mount("/old", "/root/initrd", null, ms_move, null);

if (!error)

printk("okay\n");

else else

printk(!error ? "okay\n" : "failed\n");

}}

spring原始碼分析 spring原始碼分析

1.spring 執行原理 spring 啟動時讀取應用程式提供的 bean 配置資訊,並在 spring 容器中生成乙份相應的 bean 配置登錄檔,然後根據這張登錄檔例項化 bean,裝配好 bean 之間的依賴關係,為上 層應用提供準備就緒的執行環境。二 spring 原始碼分析 1.1spr...

思科VPP原始碼分析(dpo機制原始碼分析)

vpp的dpo機制跟路由緊密結合在一起。路由表查詢 ip4 lookup 的最後結果是乙個load balance t結構。該結構可以看做是乙個hash表,裡面包含了很多dpo,指向為下一步處理動作。每個dpo都是新增路由時的乙個path的結果。dpo標準型別有 dpo drop,dpo ip nu...

redux原始碼分析(三) 原始碼部分

下面是每個部分的一些解讀 createstore apicreatestore reducer,initialstate enhancer 曾經非常好奇這個函式的第二個引數到底是initialstate還是enhancer,因為見過兩種寫法都有的,以為是版本問題。看了原始碼才發現,都可以的。如果你不...