文章目录

  • 一、前世今生
  • 二、kernel_init线程入口
  • 三、重磅角色—prepare_namespace

一、前世今生

kernel_init线程函数中会调用kernel_init_freeable()函数,在kernel_init_freeable函数中将调用prepare_namespace()函数挂载指定的根文件系统。

【漫漫长路,挂载开始!!!】


二、kernel_init线程入口

kernel_init()函数如下所示(/init/main.c):

static int __ref kernel_init(void *unused)
{int ret;kernel_init_freeable();async_synchronize_full();free_initmem();mark_rodata_ro();system_state = SYSTEM_RUNNING;numa_default_policy();flush_delayed_fput();if (ramdisk_execute_command) {ret = run_init_process(ramdisk_execute_command);if (!ret)return 0;pr_err("Failed to execute %s (error %d)\n",ramdisk_execute_command, ret);}if (execute_command) {ret = run_init_process(execute_command);if (!ret)return 0;panic("Requested init %s failed (error %d).",execute_command, ret);}if (!try_to_run_init_process("/sbin/init") ||!try_to_run_init_process("/etc/init") ||!try_to_run_init_process("/bin/init") ||!try_to_run_init_process("/bin/sh"))return 0;panic("No working init found.  Try passing init= option to kernel. ""See Linux Documentation/init.txt for guidance.");
}

上述代码第5行执行完成时,根文件系统就挂载成功了。具体执行函数由prepare_namespace()实现。下文将分析该函数。

第7~8行代码用于释放初始化函数调用时分配的内存,async_synchronize_full()函数用于同步所有的异步函数调用。free_initmem()函数用于释放初始化时所使用的内存空间。

三、重磅角色—prepare_namespace

prepare_namespace函数定义在(/init/do_mounts.c)文件中,如下所示:

void __init prepare_namespace(void)
{int is_floppy;if (root_delay) {printk(KERN_INFO "Waiting %d sec before mounting root device...\n",root_delay);ssleep(root_delay);}//等待完成对已知设备的探测wait_for_device_probe();md_run_setup();if (saved_root_name[0]) {root_device_name = saved_root_name;if (!strncmp(root_device_name, "mtd", 3) ||!strncmp(root_device_name, "ubi", 3)) {mount_block_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;}/* 等待所有的异步扫描操作完成 */if ((ROOT_DEV == 0) && root_wait) {printk(KERN_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);async_synchronize_full();}is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;if (is_floppy && rd_doload && rd_load_disk(0))ROOT_DEV = Root_RAM0;mount_root();out:devtmpfs_mount("dev");sys_mount(".", "/", NULL, MS_MOVE, NULL);sys_chroot(".");
}

上述代码本质是三种程序运行方式:

(1)【方式一】:如果root_device_namemtd或者ubi类型的根设备,则调用mount_block_root()函数挂载文件系统。

(2)【方式二】:调用initrd_load()进行早期根文件系统的挂载,如果mount_initrd为true的情况下,将执行根文件系统挂载操作。在linux内核中包含两种挂载早期根文件系统的机制:初始化RAM磁盘(initrd)是一种老式的机制。而initramfs是新的用于挂载早期根文件系统的机制。设计initrdinitramfs机制的目的:用于执行早期的用户空间程序;在挂载真正(最后的)根文件系统之前加载一些必须的设备驱动程序

(3)【方式三】:调用mount_root()函数进行文件系统挂载。该种方式是linux内核中比较常用的方式,在这种方式下,又包含三种文件系统挂载操作:1、nfs方式。2、Floppy方式。3、block方式。在平时开发中,常使用nfs进行网络挂载根文件系统,以便进行开发和调试。

以上三种方式,在实际linux启动过程中,linux内核将选择其中一种作为挂载根文件系统的方式。


下文将继续分析这三种方式:

【方式一】mount_block_root()函数将调用do_mount_root()进行文件系统挂载。如下图所示:

【方式二】initrd方式的文件系统挂载。

【方式三】

对于方式三,会调用mount_root()函数进行根文件系统的挂载,该函数定义如下(/init/do_mounts.c):

void __init mount_root(void)
{#ifdef CONFIG_ROOT_NFSif (ROOT_DEV == Root_NFS) {if (mount_nfs_root())return;printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n");ROOT_DEV = Root_FD0;}
#endif
#ifdef CONFIG_BLK_DEV_FDif (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {/* rd_doload is 2 for a dual initrd/ramload setup */if (rd_doload==2) {if (rd_load_disk(1)) {ROOT_DEV = Root_RAM1;root_device_name = NULL;}} elsechange_floppy("root floppy");}
#endif
#ifdef CONFIG_BLOCKcreate_dev("/dev/root", ROOT_DEV);mount_block_root("/dev/root", root_mountflags);
#endif
}

从以上代码片段可知:在进行mount_root()操作时,同样存在三种方式:

(1)NFS方式

通过mount_nfs_root()函数完成。

(2)ramload方式

通过rd_load_disk()函数完成。

(3)BLOCK方式

通过create_dev()和mount_block_root()两个函数完成。

mount_nfs_root()mount_block_root()两个函数都调用一个核心功能函数:do_mount_root()

该函数定义如下:

static int __init do_mount_root(char *name, char *fs, int flags, void *data)
{struct super_block *s;int err = sys_mount(name, "/root", fs, flags, data);if (err)return err;sys_chdir("/root");s = current->fs->pwd.dentry->d_sb;ROOT_DEV = s->s_dev;printk(KERN_INFO"VFS: Mounted root (%s filesystem)%s on device %u:%u.\n",s->s_type->name,s->s_flags & MS_RDONLY ?  " readonly" : "",MAJOR(ROOT_DEV), MINOR(ROOT_DEV));return 0;
}

在上述代码中,调用了sys_mount()sys_chdir()系统调用函数。


又到linux的系统调用了,sys_mount系统调用可参考该篇文章:
https://blog.csdn.net/kai_ding/article/details/9050429


由于小生知识与精力有限,如若文章存在不妥的地方,欢迎批评,也可与小生一起讨论(iriczhao@163.com)。哈哈!

【linux kernel】linux内核如何挂载根文件系统相关推荐

  1. linux内核开文件系统,新手,Linux内核无法挂载根文件系统

    新手求助,Linux内核无法挂载根文件系统 一块开发板,厂商已经提供好了uboot,kernel,ramdisk文件系统跟安卓镜像 有:uboot.bin, zImage, ramdisk-uboot ...

  2. 用Qemu模拟vexpress-a9 (四) --- u-boot引导kernel,用nfs挂载根文件系统

    环境介绍 Win7 64 + Vmware 11 + ubuntu14.04 32 u-boot 版本:u-boot-2015-04 Linux kernel版本:linux-3.16.y busyb ...

  3. 【linux kernel】挂载根文件系统之rootfs

    挂载根文件系统之rootfs 文章目录 挂载根文件系统之rootfs 一.开篇 二.rootfs根文件系统 (2-1)初始化rootfs (2-2)挂载rootfs文件系统 (2-3)创建简单的roo ...

  4. AT91SAM9260——NFS挂载根文件系统

    NFS(Network File System)即网络文件系统,是FreeBSD支持的文件系统中的一种,它允许网络中的计算机之间通过TCP/IP网络共享资源.在NFS的应用中,本地NFS的客户端应用可 ...

  5. linux uboot nfs启动,嵌入式uboot,内核启动通过nfs挂载根文件系统

    概述 嵌入式移植学习第二个内容,通过nfs挂载根文件系统.也是自己第一次做,也遇到了一些问题,但最后还是都解决了.在此记录一下整个流程,也希望能够给别的初学者一个参考. 系统环境 PC端 linux ...

  6. linux 文件系统覆盖目录,Linux内核裁减及根文件系统定制

    一.内核编译 1.准备工作 (1)整理出系统需要支持的硬件.文件系统类型以及网络协议等内容. (2)建议用命令uname –r 查看一下系统的版本号,如果你的系统版本与将要编译的内核版本一致,建议将/ ...

  7. linux 内核移植和根文件系统的制作【转载】

    原文地址:http://www.cnblogs.com/hnrainll/archive/2011/06/09/2076214.html 1.1 Linux内核基础知识 在动手进行Linux内核移植之 ...

  8. Linux内核移植和根文件系统制作(详细步骤精讲)

    第一章移植内核 1.1 Linux内核基础知识 1.1.1 Linux版本 1.1.2 什么是标准内核 1.1.3 Linux操作系统的分类 1.1.4 linux内核的选择 1.2 Linux内核启 ...

  9. Linux通过nfs挂载根文件系统失败:VFS: Unable to mount root fs via NFS, trying floppy.

    简介: 本文主要介绍一种nfs挂载失败的情况,即在根文件系统中dev文件下没有设置console和null节点.如果你的文件系统中没有这种情况,这篇文章可能对你帮助不大.不过我也会将我在查找这个问题时 ...

最新文章

  1. 苹果2010新品发布会图文实录
  2. 网络编程 -- RPC实现原理 -- RPC -- 迭代版本V4 -- 远程方法调用 整合 Spring 自动注册...
  3. 一个数据仓库时代开始--Hive
  4. 项目使用了redis还需要mysql_【11-05】lnmp项目中Redis和Mysql配合使用应该注意哪些问题?...
  5. 《Google官方SEO指南》十一:以恰当的方式推广你的网站
  6. 【转】RabbitMQ六种队列模式-3.发布订阅模式
  7. 树莓派B+使用入门RPI库安装wringPi库安装
  8. linux 混杂模式 收包,Linux下使用混杂模式抓包(2)
  9. python自动化测试怎么提高效率_自动化测试更适合缺陷预防,而不是提高测试效率...
  10. 调洪演算双辅助线法计算程序(带石门坎水电站算例)
  11. 分享一个好用的网页pdf打印插件
  12. x,y直角坐标系转经纬度WGS-84坐标系
  13. python实现列主元消去法解线性方程组
  14. 计算机软件使用前验证校准,ISO对计量器具管理要求
  15. 北大邹磊:图数据库中的子图匹配算法
  16. 北极寒流带来《后天》享受(组图)零下50度美国城市成灾区出门都犯法
  17. php社区twig,twig模板简单实用介绍
  18. MUR60120PT-ASEMI整流二极管MUR60120PT
  19. 计算机应用基础3阶段在线作业,《计算机应用基础》第四阶段在线作业(自测)
  20. 腾讯云、阿里云和百度云的优劣势各是什么?

热门文章

  1. 信息熵与信息增益——python
  2. 计算机网络——子网划分(内含习题讲解)
  3. input和button之间的缝隙问题与高度对齐问题
  4. C 语言的编译,干货有点多!
  5. cocos2dx 植物大战僵尸 17 路障僵尸
  6. 2020中国程序员调查报告:平均年薪15万,45%单身
  7. c++多线程之_beginthreadex
  8. 往事岂堪回首(选自网络)
  9. 火狐插件油猴Greasemonkey系列一
  10. ​力扣解法汇总790. 多米诺和托米诺平铺