系列目录传送门
mount系统调用简介
玩过linux的同学对mount系统调用都不会陌生, shell命令mount正是调用内核中的sys_mount函数完成文件系统的挂载. 比如下面的命令:
lqp@lqp-ThinkPad-T540p:~/mnt$ sudo mkfs.minix /dev/ram0
21856 inodes
65535 blocks
Firstdatazone=696 (696)
Zonesize=1024
Maxsize=268966912lqp@lqp-ThinkPad-T540p:~/mnt$ sudo mount -t minix /dev/ram0 ramdisk
在/dev/ram0中的Ram disk中创建minix文件系统, 并挂载到ramdisk目录下. 这样, 访问ramdisk目录时实际上访问的就是/dev/ram0设备中的minix文件系统, 该文件系统将数据存储在Ram Disk中. 用户通过文件系统的接口与物理磁盘设备交互.
接下来的内容中, 让我们来看一看mount系统调用是如何将文件系统和具体的设备关联起来的.
Minix文件系统示意图
图片取自网络
查看原图
从上可以看到, 磁盘块按功能分5部分:
1. Boot block - 用来存放boot loader, 方便操作系统加载的
2. Super block - 用来描述整个文件系统的属性的, 比如inode个数, 设备数据块总数量等
3. I-nodes bitmap和Zone bitmap - 用来管理分配inode和数据页的bitmap, 每一bit代表一个对应的inode或者zone(即数据块)对象
4. inode block - 用来存放inode数据, inode数据中存放了文件的属性, 如文件大小, 创建时间, 文件的数据块对应的块号等
5. 文件的数据块
每一个block对应1024字节, 对应2个扇区(sector, 512字节), 除此之外还有一个重要的概念, page, 对应虚拟内存的内存页面大小, 一般是4096个字节. 这几个概念会不断穿插在文件系统中. 这里简单归纳一下:
- page - 内存管理相关, 是MMU管理的对象, 可以直接映射到地址空间
- 文件系统block - 也叫逻辑块, 不同的文件系统可以定义不同的block size
- sector - 磁盘设备的读取单位, 传统设备的是512字节, 像ssd这种可以配置成一次读取4k. 不过在block io层, 面向设备接口sector对应的是512字节, 设备可以根据自身特性做适配. 在Ram Disk驱动的内部, 就是按4K的page来组织数据的.
约束关系: sector size <= 文件系统block size <= page size, 且成2的指数倍关系.
mount调用流程
如下图所示:
查看原图
其中关键调用点有:
- step 4: get_fs_type()
- step 8 : minix_mount()
- step 11: minix_fill_super()
接下来我们挨个来看一下.
1. get_fs_type()
struct file_system_type *get_fs_type(const char *name)
{
struct file_system_type *fs;
const char *dot = strchr(name, '.');
int len = dot ? dot - name : strlen(name);
fs = __get_fs_type(name, len);
if (!fs && (request_module("fs-%.*s", len, name) == 0))
fs = __get_fs_type(name, len);
if (dot && fs && !(fs->fs_flags & FS_HAS_SUBTYPE)) {
put_filesystem(fs);
fs = NULL;
}
return fs;
}
可以看到, 该函数接受的是字符串参数, 对minix而言, 则是字符串 “minix”, 然后调用内部函数__get_fs_type来查找内部注册的文件系统链表. 如果链表中没有找到, 那么还会主动加载对应文件系统的驱动来注册所需要的文件系统类型, 然后再查找一次.查找过程中调用了find_filesystem函数, 如下所示:
//lqp comment: 文件系统的查找是简单的根据名字查找文件系统链表
static struct file_system_type **find_filesystem(const char *name, unsigned len)
{
struct file_system_type **p;
for (p = &file_systems; *p; p = &(*p)->next)
if (strncmp(