本小节主要介绍文件系统类型的注册,以及文件系统挂载相关的内容(本节分析的内核源码版本为3.10)。并在本文结尾定义了一个测试文件系统stestfs,从而能较好的理解文件系统类型相关的代码、mount的过程、以及文件以及目录的创建与删除过程以及inode、dentry、superblock结构体相关的关联。
文件系统类型相关的处理
在上一节中,已经介绍过文件系统类型相关的结构体struce file_system_type,在linux内核中,定义了全局指针变量static struct file_system_type *file_systems;并为该全局变量定义了读写锁file_systems_lock。
static DEFINE_RWLOCK(file_systems_lock);,针对变量file_systems的操作,均需要使用读写锁file_systems_lock
在linux中所有注册的文件系统类型,都会通过next指针链接在一起。文件系统类型相关的变量以及每一个文件系统类型的超级块的链表连接如下图所示。
文件系统类型的注册接口 register_filesystem,该接口主要实现以下功能:
- 判断该文件系统是否已注册,若已注册,则返回失败;
- 若该文件系统未注册,则将该文件系统指针加入到register_filesystem变量对应链表的尾部。
int register_filesystem(struct file_system_type * fs)
{
int res = 0;
struct file_system_type ** p;
BUG_ON(strchr(fs->name, '.'));
if (fs->next)
return -EBUSY;
write_lock(&file_systems_lock);
p = find_filesystem(fs->name, strlen(fs->name));
if (*p)
res = -EBUSY;
else
*p = fs;
write_unlock(&file_systems_lock);
return res;
}
接口 find_filesystem用于根据文件系统名查找文件系统,若查找到则返回文件系统对应的指针,
若查找失败,则返回NULL;
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 (strlen((*p)->name) == len &&
strncmp((*p)->name, name, len) == 0)
break;
return p;
}
文件系统类型的注销接口为 unregister_filesystem,该接口实现的功能如下:
1.查找file_systems对应的链表中是否存在该文件系统类型,若存在,则删除该文件系统。
int unregister_filesystem(struct file_system_type * fs)
{
struct file_system_type ** tmp;
write_lock(&file_systems_lock);
tmp = &file_systems;
while (*tmp) {
if (fs == *tmp) {
*tmp = fs->next;
fs->next = NULL;
write_unlock(&file_systems_lock);
synchronize_rcu();
return 0;
}
tmp = &(*tmp)->next;
}
write_unlock(&file_systems_lock);
return -EINVAL;
}
文件系统挂载
针对文件系统的挂载,在应用层可通过接口mount实现挂载操作,而在linux内核下,则是sys_mount接口,针对mount接口调用流程图如下。mount的作用即调用文件系统类型中的mount接口,用于创建superblock、根root、根dentry等内容。关于mount的系统调用如下,在mount_fs接口中,则通过type->mount调用注册文件系统的mount接口,实现创建superblock、根root、根dentry。
如在下面编写的stestfs测试文件系统而言,即为调用stest_fs_mount,并调用stestfs_fill_super最终实现根dentry、根inode的创建。
文件系统类型的例子
为了能较好的理解文件系统类型的注册以及文件系统挂载、文件创建、目录创建、inode、dentry、superblock等变量之间的关系,下面创建一个新的文件系统类型,名称为stestfs。该文件系统可创建文件、创建目录、删除文件、删除目录等功能,但却不能对文件进行读写操作(这是因为该文件系统类型创建inode节点的函数stestfs_new_inode中针对文件inode节点的i_fop指针没有赋值,因此不能对该文件进行open、read、write、close等接口,因此不能对文件进行读写操作)。
该文件系统没有和真实的存储设备关联,只是在内存中创建的文件系统,因此在挂载时,执行如下命令即可
mount -t stestfs none mount_path.
该代码在ubuntu16.04(linux kernel 4.4.0)环境下可正常挂载,且可以正常进行文件/目录的创建、删除等操作
测试程序如下:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define STESTFS_MAGIC 0x123456FF
const struct inode_operations stestfs_file_inode_operations = {
.getattr = simple_getattr,
};
static const struct inode_operations stestfs_dir_inode_operations;
/*创建inode,包括文件、目录的创建*/
static struct inode *stestfs_new_inode(struct super_block *sb, struct inode * dir, umode_t mode, dev_t dev)
{
struct inode *inode = new_inode(sb);
if (inode) {
inode->i_ino = get_next_ino();
inode_init_owner(inode, dir, mode);
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
switch (mode & S_IFMT) {
default:
init_special_inode(inode, mode, dev);
break;
case S_IFREG:
printk("%s:%d create inode for file