一、前言
近几天调研了一下fuse编写文件系统的方法,先尝试拿fuse写一套类似tmpfs的简易文件系统,文件信息都保留在内存中。文件系统需要一个数据结构来管理文件节点 inode,正好《c语言实现map-使用内核红黑树》一文将rbtree结构拿出来了可以用上。
目标:支持文件读写操作:echo、cat;支持目录操作ls、mkdir、cd。
二、知识准备
FUSE(Filesystem in Userspace)为Linux下用户态的文件系统接口,通常情况文件系统的操作在内核态处理,存在调试不方便,开发效率低的情况,使用FUSE可以在用户空间进行方便地开发、调试。
如图所示,用户层的 list 操作,通过内核VFS\FUSE中转,在用户层通过libfuse到自定义程序hello中进行处理、返回。这种操作是非常灵活的,即list操作的结果是由你的应用来决定的,也就是说你能实现list展示你的自定义列表、自定义数据项等信息。当然,灵活性所需要付出的代价:用户态实现的操作系统会引入“内核态/用户态切换”额外的开销,进而影响性能。
fuse安装比较简单:
1、内核需要开启fuse的支持(默认带)
2、准备安装包 fuse-2.9.7.tar.gz
3、源码安装./configure --prefix=/usr && make -j4 && make install(编译过程提示我缺库,util-linux-ng-2.17.1.tar.gz)
三、实现
编译过程中需要指定库文件:-lfuse -pthread
首先需要定义文件系统支持的操作函数,填在结构体 struct fuse_operations 中,其他的可以详见[附录]:
static struct fuse_operations memfs_oper = {
.getattr = memfs_getattr,
.access = memfs_access,
.readdir = memfs_readdir,
.open = memfs_open,
.read = memfs_read,
.write = memfs_write,
.release = memfs_release,
.mknod = memfs_mknod,
.unlink = memfs_unlink,
.mkdir = memfs_mkdir,
.rmdir = memfs_rmdir,
.statfs = memfs_statfs,
};
主要包含了一些基础操作:
1、新建目录:mkdir、getattr;删除目录:rmdir;遍历目录:readdir;进入目录:access;
2、新建文件:getattr、mknod、open、write、read、release;删除文件:unlink;
3、状态查看:statfs;
然后看下数据结构,memfs为全局变量(多个终端操作为多线程访问该变量),并定义、初始化了statvfs结构来维护系统状态信息,定义了文件块BlockSize大小为4096,块上限MaxBlocks为1048576个,文件数MaxInode为1048576个:
struct memfs {
struct rb_root root;
struct statvfs statvfs;
pthread_mutex_t lock;
pthread_mutex_t lock_write;
};
#define FUSE_SUPER_MAGIC 0x65735546
#define BLOCKSIZE (1024UL * 4)
#define MAX_NAME 255
#define MAX_INODE (1024UL * 1024)
#define MAX_BLOCKS (1024UL * 1024)
/* Set global instance */
static struct memfs memfs = {
.root = RB_ROOT,
.statvfs = {
.f_bsize = BLOCKSIZE, /* Filesystem block size */
.f_frsize = BLOCKSIZE, /* Fragment size */
.f_blocks = MAX_BLOCKS, /* Size of fs in f_frsize units */
.f_bfree = MAX_BLOCKS, /* Number of free blocks */
.f_bavail = MAX_BLOCKS, /* Number of free blocks for unprivileged users */
.f_files = MAX_INODE, /* Number of inodes */
.f_ffree = MAX_INODE, /* Number of free inodes */
.f_favail = MAX_INODE, /* Number of free inodes for unprivileged users */
.f_fsid = 0x0123456701234567, /* Filesystem ID */
// .f_flags = 0, /* Mount flags */
.f_namemax = MAX_NAME, /* Maximum filename length */
},
.lock = PTHREAD_MUTEX_INITIALIZER,
.lock_write = PTHREAD_MUTEX_INITIALIZER,
};
/* File inodes store in r