解析linux根文件系統(tǒng)的掛載過程_第1頁
解析linux根文件系統(tǒng)的掛載過程_第2頁
解析linux根文件系統(tǒng)的掛載過程_第3頁
解析linux根文件系統(tǒng)的掛載過程_第4頁
解析linux根文件系統(tǒng)的掛載過程_第5頁
已閱讀5頁,還剩8頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)

文檔簡介

1、一:前言 前段時間在編譯 kernel的時候發(fā)現(xiàn)rootfs掛載不上。相同的root選項設(shè)置舊版的image卻可 以。為了徹底解決這個問題。研究了一下 rootfs的掛載過程。特總結(jié)如下,希望能給這部份 知識點比較迷茫的朋友一點幫助。二:roo一:前言 前段時間在編譯 kernel的時候發(fā)現(xiàn)rootfs掛載不上。相同的root選項設(shè)置舊版的image卻可 以。為了徹底解決這個問題。研究了一下 rootfs的掛載過程。特總結(jié)如下,希望能給這部份 知識點比較迷茫的朋友一點幫助。二:rootfs的種類總的來說,rootfs分為兩種:虛擬 rootfs和真實rootfs.現(xiàn)在kernel的發(fā)展趨勢是將

2、更多的功 能放到用戶空間完成。以保持內(nèi)核的精簡。虛擬 rootfs也是各linux發(fā)行廠商普遍采用的一 種方式??梢詫⒁徊糠莸某跏蓟ぷ鞣旁谔摂M的rootfs里完成。然后切換到真實的文件系統(tǒng).在虛擬rootfs的發(fā)展過程中。又有以下幾個版本:initramfs:Initramfs是在kernel 2.5中引入的技術(shù),實際上它的含義就是:在內(nèi)核鏡像中附加一個cpio包,這個cpio包中包含了一個小型的文件系統(tǒng),當(dāng)內(nèi)核啟動時,內(nèi)核將這個 cpio包解開, 并且將其中包含的文件系統(tǒng)釋放到rootfs中,內(nèi)核中的一部分初始化代碼會放到這個文件系統(tǒng)中,作為用戶層進程來執(zhí)行。這樣帶來的明顯的好處是精簡了內(nèi)

3、核的初始化代碼,而且使得內(nèi)核的初始化過程更容易定制。這種這種方式的rootfs是包含在kernel image之中的.cpio-initrd: cpio 格式的 rootfsimage-initrd:傳統(tǒng)格式的 rootfs關(guān)于這兩種虛擬文件系統(tǒng)的制作請自行參閱其它資料三:rootfs文件系統(tǒng)的掛載過程 這里說的rootfs不同于上面分析的rootfs。這里指的是系統(tǒng)初始化時的根結(jié)點。即/結(jié)點。它是其于內(nèi)存的rootfs文件系統(tǒng)。這部份之前在 << linux啟動過程分析 >>和文件系統(tǒng)中已經(jīng)分 析過。為了知識的連貫性這里再重復(fù)一次。Start_kernel() mnt

4、_init(): void _init mnt_init(void)(init_rootfs();init_mount_tree();Init_rootfs的代碼如下: int _init init_rootfs(void)int err;err = bdi_init(&ramfs_backing_dev_info);if (err)return err;err = register_filesystem(&rootfs_fs_type);if (err)bdi_destroy(&ramfs_backing_dev_info);return err;這個函數(shù)很簡單。就是

5、注冊了rootfs的文件系統(tǒng).init_mount_tree()代碼如下:static void _init init_mount_tree(void)(struct vfsmount *mnt;struct mnt_namespace *ns;struct path root;mnt = do_kern_mount("rootfs”, 0, "rootfs", NULL);if (IS_ERR(mnt)panic("Can't create rootfs");ns = kmalloc(sizeof(*ns), GFP_KERNEL);

6、if (!ns)panic("Can't allocate initial namespace");atomic_set(&ns->count, 1);INIT_LIST_HEAD(&ns->list);init_waitqueue_head(&ns->poll);ns->event = 0;list_add(&mnt->mnt_list, &ns->list);ns->root = mnt;mnt->mnt_ns = ns;init_task.nsproxy->mnt_n

7、s = ns;get_mnt_ns(ns);root.mnt = ns->root;root.dentry = ns->root->mnt_root;set_fs_pwd(current->fs, &root); set_fs_root(current->fs, &root);在這里,將rootfs文件系統(tǒng)掛載。它的掛載點默認(rèn)為”/”.最后切換進程的根目錄和當(dāng)前目錄為” /”.這也就是根目錄的由來。不過這里只是初始化。等掛載完具體的文件系統(tǒng)之后,一般都會將根目錄切換到具體的文件系統(tǒng)。所以在系統(tǒng)啟動之后,用mount命令是看不到rootfs的掛載信息

8、的.四:虛擬文件系統(tǒng)的掛載根目錄已經(jīng)掛上去了,可以掛載具體的文件系統(tǒng)了在 start_kernel()(Test_init() ckernel_init():static int _init kernel_init(void * unused)do_basic_setup();if (!ramdisk_execute_command)ramdisk_execute_command = "/init"if (sys_access(const char _user *) ramdisk_execute_command, 0) != 0) ramdisk_execute_comm

9、and = NULL;prepare_namespace();/* Ok, we have completed the initial bootup, and* we're essentially up and running. Get rid of the* initmem segments and start the user-mode stuff.*/init_post();return 0;do_basic_setup()是一個很關(guān)鍵的函數(shù),所有直接編譯在 kernel中的模塊都是由它啟動的。代碼片段如下:static void _init do_basic_setup(voi

10、d)/* drivers will send hotplug events */ init_workqueues();usermodehelper_init();driver_init();init_irq_proc();do_initcalls();Do_initcalls()用來啟動所有在 _initcall_start和_initcall_end段的函數(shù),而靜態(tài)編譯進內(nèi)核的 modules也會將其入口放置在這段區(qū)間里。跟根文件系統(tǒng)相關(guān)的初始化函數(shù)都會由rootfs_initcall ()所引用。注意到有以下初始化函數(shù):rootfs_initcall(populate_rootfs);也就

11、是說會在系統(tǒng)初始化的時候會調(diào)用populate_rootfs進行初始化。代碼如下:static int _init populate_rootfs(void)char *err = unpack_to_rootfs(_initramfs_start,_initramfs_end - _initramfs_start, 0);if (err)panic(err);if (initrd_start) #ifdef CONFIG_BLK_DEV_RAMint fd;printk(KERN_INFO "checking if image is initramfs.");err =

12、unpack_to_rootfs(char *)initrd_start,initrd_end - initrd_start, 1);if (!err) printk(" it isn");unpack_to_rootfs(char *)initrd_start,initrd_end - initrd_start, 0); free_initrd();return 0;printk("it isn't (%s); looks like an initrdn", err);fd = sys_open("/initrd.image”, O_

13、WRONL Y|O_CREA T, 0700);if (fd >= 0) sys_write(fd, (char *)initrd_start,initrd_end - initrd_start); sys_close(fd);free_initrd();#elseprintk(KERN_INFO "Unp acking initramfs.");err = unpack_to_rootfs(char *)initrd_start,initrd_end - initrd_start, 0);if (err)panic(err);printk(" donen&

14、quot;);free_initrd();#endifreturn 0;unpack_to_rootfs :顧名思義就是解壓包,并將其釋放至rootfs。它實際上有兩個功能,一個是釋放包,一個是查看包,看其是否屬于cpio結(jié)構(gòu)的包。功能選擇是根據(jù)最后的一個參數(shù)來區(qū)分的.在這個函數(shù)里,對應(yīng)我們之前分析的三種虛擬根文件系統(tǒng)的情況。一種是跟kernel融為一體的initramfs.在編譯 kernel的 時候,通過 鏈接腳 本將其 存放在_initramfs_start 至 _initramfs_end的區(qū)域。這種情況下,直接調(diào)用unpack_to_rootfs將其釋放到根目錄.如果不是屬于這種形式

15、的。 也就是_initramfs_start和_initramfs_end的值相等,長度為零。 不會做 任何處理。退出.對應(yīng)后兩種情況。 從代碼中看至叭 必須要配制 CONFIG_BLK_DEV_RAM 才會支持 image-initrd。否則全當(dāng)成 cpio-initrd的形式處理。對于是cpio-initrd的情況。直接將其釋放到根目錄。對于是 image-initrd的情況。將其釋放 到/initrd.image.最后將initrd內(nèi)存區(qū)域歸入伙伴系統(tǒng)。這段內(nèi)存就可以由操作系統(tǒng)來做其它 的用途了。接下來,內(nèi)核對這幾種情況又是怎么處理的呢?不要著急。往下看:回到kernel_init()這

16、個函數(shù):static int _init kernel_init(void * unused)do_basic_setup();/* check if there is an early userspace init. If yes, let it do all* the work*/ramdisk_execute_command = "/init"if (sys_access(const char _user *) ramdisk_execute_command, 0) != 0) ramdisk_execute_command = NULL;prepare_namesp

17、ace();/* Ok, we have completed the initial bootup, and* we're essentially up and running. Get rid of the* initmem segments and start the user-mode stuff.*/init_post();return 0;ramdisk_execute_command:在kernel解析引導(dǎo)參數(shù)的時候使用。如果用戶指定了 init文件路徑,即使用了 init= ",就會將這個參數(shù)值存放到這里。如果沒有指定init文件路徑。默認(rèn)為/init對應(yīng)于前面

18、一段的分析,我們知道,對于 initramdisk和cpio-initrd的情況,都會將虛擬根文 件系統(tǒng)釋放到根目錄。如果這些虛擬文件系統(tǒng)里有/init這個文件。就會轉(zhuǎn)入到 init_post()。Init_post()代碼如下:static int noinline init_post(void)free_initmem();unlock_kernel();mark_rodata_ro();system_state = SYSTEM_RUNNING;numa_default_policy();if (sys_open(const char _user *) "/dev/consol

19、e", O_RDWR, 0) < 0)printk(KERN_W ARNING "Warning: unable to open an initial console.n");(void) sys_dup(0);(void) sys_dup(0);if (ramdisk_execute_command) (run_init_process(ramdisk_execute_command);printk(KERN_W ARNING "Failed to execute %sn",ramdisk_execute_command);/* We

20、try each of these until one succeeds.* The Bourne shell can be used instead of init if we are* trying to recover a really broken machine.*/if (execute_command) (run_init_process(execute_command);printk(KERN_W ARNING "Failed to execute %s. Attempting ""defaults.n”, execute_command);run

21、_init_process("/sbin/init");run_init_process("/etc/init");run_init_process("/bin/init");run_init_process("/bin/sh");panic("No init found. Try passing init= option to kernel.");從代碼中可以看中,會依次執(zhí)行指定的init文件,如果失敗,就會執(zhí)行/sbin/init, /etc/init,/bin/init,/bin/sh注意

22、的是,run_init_process在調(diào)用相應(yīng)程序運行的時候,用的是kernel_execve。也就是說調(diào)用進程會替換當(dāng)前進程。 只要上述任意一個文件調(diào)用成功,就不會返回到這個函數(shù)。 如果上面幾個文件都無法執(zhí)行。打印出沒有找到init文件的錯誤。對于image-hdr或者是虛擬文件系統(tǒng)中沒有包含/init的情況,會由prepare_namespace(處理。代碼如下:void _init prepare_namespace(void)(int is_floppy;if (root_delay) (printk(KERN_INFO "Waiting %dsec before moun

23、ting root device.n", root_delay);ssleep(root_delay);/* wait for the known devices to complete their probing */while (driver_probe_done() != 0) msleep(100);/mtd的處理md_run_setup();if (saved_root_name0) root_device_name = saved_root_name;if (!strncmp(root_device_name, "mtd", 3) mount_bloc

24、k_root(root_device_name, root_mountflags);goto out;ROOT_DEV = name_to_dev_t(root_device_name);if (strncmp(root_device_name, "/dev/", 5) = 0)root_device_name += 5;if (initrd_load() goto out;/* wait for any asynchronous scanning to complete */if (ROOT_DEV = 0) && root_wait) printk(KE

25、RN_INFO "Waiting for root device %s.n”,saved_root_name);while (driver_probe_done() != 0 |(ROOT_DEV = name_to_dev_t(saved_root_name) = 0) msleep(100);is_floppy = MAJOR(ROOT_DEV) = FLOPPY_MAJOR;if (is_floppy && rd_doload && rd_load_disk(0) ROOT_DEV = Root_RAM0;mount_root();out:sys

26、_mount(".”, ”/”, NULL, MS_MOVE, NULL);sys_chroot(".”);這里有幾個比較有意思的處理,首先用戶可以用root=來指定根文件系統(tǒng)。它的值保存在saved_root_name中。如果用戶指定了以 mtd開始的字串做為它的根文件系統(tǒng)。就會直接去 掛載。這個文件是 mtdblock的設(shè)備文件。否則將設(shè)備結(jié)點文件轉(zhuǎn)換為ROOT_DEV即設(shè)備節(jié)點號然后,轉(zhuǎn)向initrd_load()執(zhí)行initrd預(yù)處理后,再將具體的根文件系統(tǒng)掛載。注意到,在這個函數(shù)末尾。會調(diào)用sys_mount()來移動當(dāng)前文件系統(tǒng)掛載點到”/”目錄下。然后將根目錄

27、切換到當(dāng)前目錄。這樣,根文件系統(tǒng)的掛載點就成為了我們在用戶空間所看到的” /” 了 .對于其它根文件系統(tǒng)的情況,會先經(jīng)過initrd的處理。即int _init initrd_load(void)(if (mount_initrd) (create_dev("/dev/ram", Root_RAM0);/* Load the initrd data into /dev/ram0. Execute it as initrd* unless /dev/ram0 is supposed to be our actual root device,* in that case the

28、 ram disk is just set up here, and gets* mounted in the normal path.*/if (rd_load_image("/initrd.image") && ROOT_DEV != Root_RAM0) (sys_unlink("/initrd.image");handle_initrd();return 1;sys_unlink("/initrd.image");return 0;建立一個 ROOT_RAM)的設(shè)備節(jié)點,并將 /initrd/.image 釋放

29、到這個節(jié)點中,/initrd.image 的 內(nèi)容,就是我們之前分析的image-initrd。如果根文件設(shè)備號不是ROOT_RAM0(用戶指定的根文件系統(tǒng)不是/dev/ram0就會轉(zhuǎn)入到handle_initrd()如果當(dāng)前根文件系統(tǒng)是/dev/ram0.將其直接掛載就好了。handle_initrd ()代碼如下:static void _init handle_initrd(void)int error;int pid;real_root_dev = new_encode_dev(ROOT_DEV);create_dev("/dev/root.old”, Root_RAM0);

30、/* mount initrd on rootfs' /root */mount_block_root("/dev/root.old", root_mountflags & MS_RDONL Y);sys_mkdir("/old", 0700);root_fd = sys_open("/", 0, 0);old_fd = sys_open("/old", 0, 0);/* move initrd over / and chdir/chroot in initrd root */sys_chdir(&

31、quot;/root");sys_mount(".", "/", NULL, MS_MOVE, NULL);sys_chroot(".”);/* In case that a resume from disk is carried out by linuxrc or one of* its children, we need to tell the freezer not to wait for us.*/current->flags |= PF_FREEZER_SKIP;pid = kernel_thread(do_linux

32、rc, "/linuxrc", SIGCHLD);if (pid > 0)while (pid != sys_wait4(-1, NULL, 0, NULL)yield();current->flags &= PF_FREEZER_SKIP;/* 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(".”);sy

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論