当注册新的文件系统时,会调用register_filesystem函数,这个函数会检查是否已经存在相同的名字,如果不存在则将该文件系统挂到全局的filesystem链表上
/**
* register_filesystem - register a new filesystem
* @fs: the file system structure
*
* Adds the file system passed to the list of file systems the kernel
* is aware of for mount and other syscalls. Returns 0 on success,
* or a negative errno code on an error.
*
* The &struct file_system_type that is passed is linked into the kernel
* structures and must not be freed until the file system has been
* unregistered.
*/
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;
}
EXPORT_SYMBOL(register_filesystem);
fuse 模块初始化
static int __init fuse_init(void)
{
int res;
printk(KERN_INFO "fuse init (API version %i.%i)\n",
FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
INIT_LIST_HEAD(&fuse_conn_list);
res = fuse_fs_init();
if (res)
goto err;
res = fuse_dev_init();
if (res)
goto err_fs_cleanup;
res = fuse_sysfs_init();
if (res)
goto err_dev_cleanup;
res = fuse_ctl_init();
if (res)
goto err_sysfs_cleanup;
sanitize_global_limit(&max_user_bgreq);
sanitize_global_limit(&max_user_congthresh);
return 0;
err_sysfs_cleanup:
fuse_sysfs_cleanup();
err_dev_cleanup:
fuse_dev_cleanup();
err_fs_cleanup:
fuse_fs_cleanup();
err:
return res;
}
fuse_fs_init 初始化注册fuse文件系统
fuse_sysfs_init 注册到 /sys/fs/fuse/connections sysfs,这是一个kobject
static int fuse_sysfs_init(void)
{
int err;
fuse_kobj = kobject_create_and_add("fuse", fs_kobj);
if (!fuse_kobj) {
err = -ENOMEM;
goto out_err;
}
err = sysfs_create_mount_point(fuse_kobj, "connections");
if (err)
goto out_fuse_unregister;
return 0;
out_fuse_unregister:
kobject_put(fuse_kobj);
out_err:
return err;
}
kobject_create_and_add(“fuse”, fs_kobj) 就是将 fuse加到 /sys/fs sysfs文件系统
kobject_put 为回收内存
最后是fuse_ctl_init,注册了fusectl 文件系统
static struct dentry *fuse_mount(struct file_system_type *fs_type,
int flags, const char *dev_name,
void *raw_data)
{
return mount_nodev(fs_type, flags, raw_data, fuse_fill_super);
}
fuse在mount的时候调用的是mount_nodev,
mount_nodev: mount a filesystem that is not backed by a device
在fuse_mount的时候就会调用 fuse_fill_super 来填充fuse的super_block
fuse_fill_super的过程除了填充superblock,还会初始化fuse_connection, fusedev, 初始化bdi
static int fuse_bdi_init(struct fuse_conn *fc, struct super_block *sb)
{
int err;
char *suffix = "";
if (sb->s_bdev) {
suffix = "-fuseblk";
/*
* sb->s_bdi points to blkdev's bdi however we want to redirect
* it to our private bdi...
*/
bdi_put(sb->s_bdi);
sb->s_bdi = &noop_backing_dev_info;
}
err = super_setup_bdi_name(sb, "%u:%u%s", MAJOR(fc->dev),
MINOR(fc->dev), suffix);
if (err)
return err;
sb->s_bdi->ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_SIZE;
/* fuse does it's own writeback accounting */
sb->s_bdi->capabilities = BDI_CAP_NO_ACCT_WB | BDI_CAP_STRICTLIMIT;
/*
* For a single fuse filesystem use max 1% of dirty +
* writeback threshold.
*
* This gives about 1M of write buffer for memory maps on a
* machine with 1G and 10% dirty_ratio, which should be more
* than enough.
*
* Privileged users can raise it by writing to
*
* /sys/class/bdi/<bdi>/max_ratio
*/
bdi_set_max_ratio(sb->s_bdi, 1);
return 0;
}
初始化root dentry
因为root节点没有 revalidate,所以,这里专门搞了一个root_dentry_operations
const struct dentry_operations fuse_dentry_operations = {
.d_revalidate = fuse_dentry_revalidate,
.d_init = fuse_dentry_init,
.d_release = fuse_dentry_release,
};
const struct dentry_operations fuse_root_dentry_operations = {
.d_init = fuse_dentry_init,
.d_release = fuse_dentry_release,
};
root = fuse_get_root_inode(sb, d.rootmode);
sb->s_d_op = &fuse_root_dentry_operations;
root_dentry = d_make_root(root);
if (!root_dentry)
goto err_dev_free;
/* Root dentry doesn't have .d_revalidate */
sb->s_d_op = &fuse_dentry_operations;
在创建好root_dentry后,再将s_d_op改为 fuse_dentry_operations
然后初始化init_req
将fc添加到 fuse_ctl connections