块设备的mknod 还是会创建在 /dev 路径下面,这一点和字符设备一样。/dev 路径下面是 devtmpfs 文件系统。这是块设备遇到的第一个文件系统。我们会为这个块设备文件,分配一个特殊的 inode,这一点和字符设备也是一样的。只不过字符设备走 S_ISCHR 这个分支,对应 inode 的 file_operations 是 def_chr_fops;而块设备走 S_ISBLK 这个分支,对应的 inode 的 file_operations 是 def_blk_fops。
接下来,我们要调用 mount,将这个块设备文件挂载到一个文件夹下面。如果这个块设备原来被格式化为一种文件系统的格式,例如 ext4,那我们调用的就是 ext4 相应的 mount 操作。这是块设备遇到的第二个文件系统,也是向这个块设备读写文件,需要基于的主流文件系统。
在 bdget 中,我们遇到了第三个文件系统,bdev 伪文件系统。bdget 函数根据传进来的 dev_t,在 blockdev_superblock 这个文件系统里面找到 inode。这里注意,这个 inode 已经不是 devtmpfs 文件系统的 inode 了。blockdev_superblock 的初始化在整个系统初始化的时候,会调用 bdev_cache_init 进行初始化。
我们有一个磁盘 /dev/sda,我们既可以把它整个格式化成一个文件系统,也可以把它分成多个分区 /dev/sda1、 /dev/sda2,然后把每个分区格式化成不同的文件系统。如果我们访问某个分区的设备文件 /dev/sda2,我们应该能知道它是哪个磁盘设备的。按说它们的驱动应该是一样的。如果我们访问整个磁盘的设备文件 /dev/sda,我们也应该能知道它分了几个区域,所以就有了下图这个复杂的关系结构。
- 所有的块设备被一个 map 结构管理从 dev_t 到 gendisk 的映射;
- 所有的 block_device 表示的设备或者分区都在 bdev 文件系统的 inode 列表中;
- mknod 创建出来的块设备文件在 devtemfs 文件系统里面,特殊 inode 里面有块设备号;
- mount 一个块设备上的文件系统,调用这个文件系统的 mount 接口;
- 通过按照 /dev/xxx 在文件系统 devtmpfs 文件系统上搜索到特殊 inode,得到块设备号;
- 根据特殊 inode 里面的 dev_t 在 bdev 文件系统里面找到 inode;
- 根据 bdev 文件系统上的 inode 找到对应的 block_device,根据 dev_t 在 map 中找到 gendisk,将两者关联起来;
- 找到 block_device 后打开设备,调用和 block_device 关联的 gendisk 里面的 block_device_operations 打开设备;
- 创建被 mount 的文件系统的 super_block。
此文章为11月Day14学习笔记,内容来源于极客时间《趣谈Linux操作系统》,推荐该课程。