Linux内核文件系统-minix文件系统

建议点击这里查看个人主页上的最新原文

一般的Linux书籍都是先讲解进程和内存相关的知识,但我想先讲解文件系统。

第一,因为我就是做文件系统的,更擅长这一块,其他模块的内容我还要再去好好看看书,毕竟不能误人子弟嘛;第二,是

因为文件系统模块更接近于用户态,是相对比较好理解的内容(当然想深入还是要下大功夫的),由文件系统入手比较适合初学者。

使用

虚拟机启动时,不能使用4k盘,qemu启动命令logical_block_sizephysical_block_size参数要使用512:

-drive file=1,if=none,format=raw,cache=writeback,file.locking=off,id=dd_1 \
-device scsi-hd,drive=dd_1,id=disk_1,logical_block_size=512,physical_block_size=512 \

格式化磁盘,具体的选项使用man mkfs.minix查看:

mkfs.minix image # 默认版本1
mkfs.minix -3 /dev/sda # 指定版本3

mkfs.minix image的输出如下:

21856 inodes
65535 blocks
Firstdatazone=696 (696)
Zonesize=1024 # v1的zone大小
Maxsize=268966912

挂载文件系统:

mount -t minix /dev/sda /mnt

或者格式化文件,通过loop设备挂载,注意这时需要打开CONFIG_BLK_DEV_LOOP配置。

独立模块编译

如果我们要在minix文件系统的基础上再开发,为了方便开发测试,可以fs/minix复制出来,然后打上补丁0001-myminix.patch,这里我把文件系统类型名改为了myminix,挂载时要指定挂载选项,如通过loop设备挂载:

mount -t myminix -o loop image /mnt

util-linux

用户态工具源码包含在util-linux中,github仓库

编译参考Documentation/howto-compilation.txt

apt install -y autopoint gettext flex bison sqlite3 libsqlite3-dev
./autogen.sh && ./configure && make -j`nproc`
# make install # 默认安装到/usr/sbin/mkfs.minix

数据结构

  1. 超级块结构。
  • 磁盘超级块结构struct minix_super_blockstruct minix3_super_block
  • 内存超级块结构struct minix_sb_info,赋值给struct super_blocks_fs_info成员
  1. 超级块操作方法minix_sops
  2. 索引节点结构。
  • 磁盘索引节点结构struct minix_inodestruct minix2_inode
  • 内存索引节点结构struct minix_inode_info
  1. 各种类型文件的索引节点操作方法:
  • 常规文件minix_file_inode_operations
  • 目录minix_dir_inode_operations
  • 符号链接(路径名小于60字节)minix_symlink_inode_operations
  1. dentry操作方法,minix没有定义
  2. 各种类型文件的file操作方法:
  • 常规文件minix_file_operations
  • 目录minix_dir_operations
  • 其他类型查看init_special_inode()函数。
  1. 各种类型文件的address_space操作方法,常规文件、目录、符号链接都是minix_aops
  2. 文件系统类型minix_fs_type
  3. 模块加载卸载方法,init_minix_fsexit_minix_fs

其他重要的数据结构:

typedef struct {
        block_t *p; // key在内存中的地址
        block_t key; // 块号
        struct buffer_head *bh; // 缓冲头,内存中保存块的数据
} Indirect;

函数流程

写文件流程:

write
  ksys_write
    vfs_write
      new_sync_write
        generic_file_write_iter
          __generic_file_write_iter
            generic_perform_write
              minix_write_begin
                block_write_begin
                  __block_write_begin_int
                    minix_get_block
                      V1_minix_get_block
                        get_block // 这里的bh已经分配内存了
                          block_to_path
                            offsets[n++] = block // if (block < 7) 直接块
                          // depth=1时直接指向数据,depth=2时一次间接地址
                          // Zonesize=1024,v1版本DIRECT = 7,所以当写的文件大小超过7168字节时,depth=2
                          get_branch
                            i_data(inode)
                              return u.i1_data
                            add_chain(i1_data + *offsets)
                              Indirect->p = block_t *
                              Indirect->key = block_t
                              Indirect->bh = buffer_head *
                            sb_bread // 根据块号和块大小获取数据,返回buffer_head
                          alloc_branch // 如果块没找到
                            parent = minix_new_block // 获得新块,只是设置bitmap
                            // 间接块才往下走
                            nr = minix_new_block(inode)
                            bh = sb_getblk // 获取间接块对应的buffer_head
                          map_bh // 将buffer_head映射到块

支持长文件名

我们来看一个有趣的问题: 让minix文件系统(v3)支持最大长度4095字节的文件名。

当我们使用touch命令创建一个4095字节长度的文件时,会执行到minix_lookup函数。而当创建一个4096字节长度的文件时,不会执行到minix_lookup函数,说明在vfs已经拦截了。

相关代码流程如下:

openat
  do_sys_open
    do_sys_openat2
      getname
        getname_flags
          len = strncpy_from_user(kname, filename, EMBEDDED_NAME_MAX) = 4064 // EMBEDDED_NAME_MAX 为 4096-32
          // touch <4095字节文件名> 时 len = 4095, 会调用到 minix_lookup
          // touch <4096字节文件名> 时 len = 4096, 不会调用到 minix_lookup
          len = strncpy_from_user(kname, filename, PATH_MAX)
          if (unlikely(len == PATH_MAX))
          return ERR_PTR(-ENAMETOOLONG) // touch <4096字节文件名> 时
      do_filp_open
        path_openat
          open_last_lookups
            lookup_open
              minix_lookup
                // s_namelen 的值在 minix_fill_super 中设置,minix v3 为 60字节
                return ERR_PTR(-ENAMETOOLONG) // touch <4095字节文件名> 时

如果当路径中前面有其他路径时(如/mnt/<4095字节文件名>就有4100个字节),会被vfs拦截,所以当要支持4095字节长度时,要在vfs做修改。而大部分文件系统支持的最大文件名长度为255字节,所以我们可以这样设计: 当文件名(普通文件和文件夹)大于255字节时,在vfs对文件名做hash映射,当文件名(普通文件和文件夹)大于minix v3文件系统最大支持的60字节时,在minix文件系统对文件名做hash映射。

暂时只对最后一个路径名作hash映射,后续再补充支持对中间路径名进行hash映射,补丁为0001-minix-support-long-file-name.patch

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值