作者简介: 黄伟亮(Huang weller),毕业于苏州大学,就职于苏州博世汽车部件汽车多媒体事业部,从事汽车多媒体娱乐系统的平台开发工作六年有余, 接触Linux 系统近10年。感兴趣的方向有Linux系统性能优化,多媒体框架, 文件系统和存储器件, USB以及虚拟化等。
前言
我们的学习习惯基本都是由浅入深的, 比如我们先学习如何使用fdisk工具来给磁盘分区, 之后才想到去看看fdisk到底对磁盘做了什么, 许久以后看到除了fdisk还有别的分区工具可以给磁盘分区. 通常我们只需要知道怎么用就可以了, 也有很多原因促使我们去思考它的背后到底发生了什么,这些原因可能是你碰到了具体问题, 不得不让你往下去看, 去看你认为肯定不会出问题的那一部分, 也有可能是你觉得现在的自己技术太浮于表面, 想深入一些, 也可能是受周围人的影响, 一起学习.
佛家讲究因果, 使用者往往接触的是果, 因为使用者在乎的是可用性, 开发者或者说设计者则要考虑因, 因为什么样的因就会导致什么样的果, 因为这样的设计, 所以就有那样的bug, 就像黑客帝国中的Neo 要找到architecture!
本文由来于心中的两个疑问,即平凡的存储器件是怎么从分区变成一个个块设备的, 根是怎么被mount的.
Romcode 说
通常,在processor上电后, 最早执行的代码是固化在CPU ROM中的程序, 它其实就是最早被执行的bootloader, 它的终极目的是从存储介质(包含uart, USB)加载另外一个bootloader, 比如u-boot. 拿启动介质是eMMC或者SD的例子来说, romcode一般会从offset = sector_size * 1的位置开始读取程序, 这么做的原因其实是为了跳开分区表.
当然笔者也见过一个奇葩的例子, 海思的一款ARM9的芯片, ROMCODE直接从eMMC data partition offset 0的位置开始读取程序, 这就导致当你从emmc 上的u-boot启动, 兴冲冲的进到ramdisk对eMMC进行分区, 格式化, 烧写系统之后, 发现系统再也起不来了, 那是因为分区表已经覆盖了第一个分区,破坏了bootloader. 整个系统没有使用分区工具来划分分区, 而是通过u-boot的boot arguments描述分区信息. 不管怎样, 本文描述的是前者,而非这个特例.
从分区表到块设备: 我不是表, 我是块设备
Linux 下Storage device 通常是作为块设备被访问的,例如mtdblock, mmcblock 和宇宙第一强的nandblk 块设备(实在太崇拜该设备了,将NAND发挥到了极致). Storage device的设备驱动作为底层支撑, 负责注册块设备并且直接和存储器件打交道, 接受, 执行和响应块设备层的过来的访问请求. 比如说, 一次文件读取的操作会变成文件系统提交到块设备的块读取请求, 该块设备的读访问请求, 在块设备驱动和Host controller driver会把它被转化为MMC协议的CMD17或者CMD18指令给到EMMC物理设备.
Storage device的设备驱动注册到块设备层,并且扫描分区表, 识别分区表, 然后解析分区表, 把磁盘上的分区注册为块设备. 所以, 当你奇怪为什么没有mmcblkp0这个设备时, 其实不是没有mmcblk0p0,而是p0被定义为就是mmcblk0. 代表了整个磁盘. 下面从代码上来看一下一个块设备驱动的初始化过程:
根: 木叶的根
我们知道u-boot的boot argument 会把root device的设备名称带给内核, 例如通过参数root=/dev/mmcblk0p2来告知内核, 根目录所在的分区. 事情真的那么简单吗?
原来这里面有一点点小弯弯:
原来在天地混沌的时候, 内核已经为了自己的未来初始化了一个ramfs, 并在ramfs中创建了一些必要的目录和设备节点, 例如/dev , /dev/console, /root.
然后, 为了mount mmcblk0p2, 它又根据设备文件名/dev/mmcblk0p2查找设备变量, 在ramfs下创建设备节点/dev/root, 这个设备文件指向的就是设备mmcblk0p2. 然后把ramfs下的设备/dev/mmcblk0p2挂载到ramfs的/root下. 切换当前路径到ramfs的/root下. 至此已经完成了设备mmcblk0p2的挂载工作, 但是此时它还不是根.
接着, 内核挂载devtmpfs到dev目录, 然后调用sys_chroot(“.”)把change root 到当前路径, 也就是ramfs的/root.
反映到代码上:
因此在系统起来后, cat /proc/mounts, 我们可以看到以下信息:
可以看到有一个文件系统的类型是rootfs, 它被mount到了“/”.
这个文件系统在init/do_mount.c中被定义, 它就是ramfs的一个实例,
该类型的文件系统在init_rootfs()中被注册.
从mount命令的输出上, 我们可以看到/dev/mmcblk0p2被挂载在了”/”, 殊不知这里的根已经不是原来的根.
结束语
本文没有对代码的细节作过多的分析, 一方面本文不是为了做代码分析的, 另一方面网络上有很多朋友也做过块设备的代码分析, 本文罗列了代码的脉络是为了来更好的表达分析的结果. Block layer是个很复杂的子系统, 有很多关于它的内容,比如IO-schecduler, buffer cache等, 相信自己可以越来越深入的研究这个子系统.
-
Linux
+关注
关注
87文章
11230浏览量
208937
原文标题:黄伟亮: 探秘Linux的块设备和根
文章出处:【微信号:LinuxDev,微信公众号:Linux阅码场】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论