"我的"文件系统

由于工作需要,写了一个功能最简单的文件系统,想着再完善一下,当成公开课素材,一来觉得挺好玩,二来觉得可以自己的简历也需要这么一个项目。

这个”我的”(my)文件系统不是为了生产目的,目前只用于学习目的,欢迎更多的朋友来完善,可以参考其他文件系统的代码(当然不能整段copy),但请标明出处。

点击这里访问代码仓库

1 参考

2 编译

2.1 独立模块编译

修改Makefile文件中的KDIR变量对应Linux内核仓库的路径,然后在myfs代码仓库执行以下命令:

make # 生成 myfs.ko
# make clean # 清理编译生成的文件

2.2 作为内核一部分编译

整个代码仓库目录myfs复制到Linux内核仓库的fs目录下。然后到内核仓库中执行以下命令:

git am fs/myfs/0001-add-support-for-myfs.patch
mv fs/myfs/Makefile.kernel fs/myfs/Makefile
make O=x86_64-build menuconfig
make O=x86_64-build bzImage -j`nproc`
make O=x86_64-build modules -j`nproc`

2.3 todo

本来想和ksmbd/Makefile中一样用ifneq ($(KERNELRELEASE),)隔离开独立模块和作为内核一部分,但好像没什么卵用,对makefile熟悉的朋友可以告诉我要怎么写。

3 使用

3.1 调试日志

参考fs/smb/server/server.c写了一个日志开关功能,使用请参考《smb调试方法》

控制命令如下:

cat /sys/class/myfs-ctrl/debug # 查看日志开关,打开的日志类型有中括号
echo all > /sys/class/myfs-ctrl/debug # 全部切换
echo main > /sys/class/myfs-ctrl/debug # 只切换main

3.2 挂载

用以下命令挂载:

mount -t myfs /dev/sda /mnt
mount
lsblk
df
umount /mnt

如果编译内核打开了CONFIG_BLK_DEV_LOOP配置,可以挂载文件:

mount -t myfs -o loop /dev/sda /mnt

3.3 文件操作

#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/limits.h>

int main()
{
        int res = syscall(__NR_openat, AT_FDCWD, "/mnt", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY);
        printf("result: %d\n", res);

        return 0;
}

4 开发过程

文件系统的模块加载函数是init_myfs(),模块卸载函数是exit_myfs()。可作为独立模块编译,也可作为内核一部分编译,内核配置选项是CONFIG_MYFS

引入struct file_system_type myfs_fs_type,实现.mount.kill_sb方法,但测试发现mount时会panic,用scripts/faddr2line脚本解析栈信息,发现在legacy_get_tree()中得到的struct dentry *root为空,所以是还没能得到rootdentryinode

为了方便调试,引入调试日志函数接口myfs_debug()。接着在myfs_fill_super()函数中获取root inode,但mount时却报错: mount: /mnt: mount(2) system call failed: Not a directory.。查看代码发现是root inode不是目录类型,所以将root inodei_mode设置成目录类型,这时就能挂载成功。

但这时df -Th命令还不能输出myfs相关的信息,引入struct super_operations myfs_sops且实现.statfs方法,df -Th命令就可输出相关信息。

引入myfs_dir_operationsmyfs_file_operations,但是ls /mnt还是报错ls: cannot open directory '/mnt': Not a directory,具体原因待定位。