`do_new_mount_fc()` 如何挂载像 ext4 这样的真实文件系统?
How does `do_new_mount_fc()` mount real file systems like ext4?
在相对较旧的 Linux 内核源代码中,do_new_mount()
将调用 vfs_kern_mount()
,最终会调用 mount_fs()
。而这个函数会像下面这样调用真实文件系统的函数
struct dentry *
mount_fs(struct file_system_type *type, int flags, const char *name, void *data)
{
struct dentry *root;
struct super_block *sb;
......
root = type->mount(type, flags, name, data);
......
sb = root->d_sb;
......
}
但是在相对较新的Linux内核源代码中,do_new_mount()
会调用do_new_mount_fc()
,我找不到这个函数如何像上面那样调用真实文件系统的挂载函数.
你能告诉我它现在是如何工作的吗?
由于最近过渡到 new Filesystem Mount API through "filesystem context". You can find more info in the relevant (quite massive) patchwork,您找不到“常规”函数调用。
我不打算解释整个事情,因为我在上面 link 编辑的内核文档应该已经给出了很好的解释(而且我也不是 Linux FS 内部专家) .
“文件系统上下文”基本上是一个包含有用信息的结构,这些信息会根据需要进行传递和更新。所以现在发生的是 vfs_get_tree()
function is responsible for creating the mountable root of the filesystem, and saving it in the fs_context
structure that is then passed to do_new_mount_fc()
并用于实际挂载。
(*) int vfs_get_tree(struct fs_context *fc);
Get or create the mountable root and superblock, using the parameters in
the filesystem context to select/configure the superblock. This invokes
the ->get_tree() method.
所以现在在 do_new_mount()
中,您会看到该函数在 之前 do_new_mount_fc()
:
fc = fs_context_for_mount(type, sb_flags);
put_filesystem(type);
if (IS_ERR(fc))
return PTR_ERR(fc);
if (subtype)
err = vfs_parse_fs_string(fc, "subtype",
subtype, strlen(subtype));
if (!err && name)
err = vfs_parse_fs_string(fc, "source", name, strlen(name));
if (!err)
err = parse_monolithic_mount_data(fc, data);
if (!err && !mount_capable(fc))
err = -EPERM;
if (!err)
err = vfs_get_tree(fc); // <<<<<<<<<<<<<<<<<<<<<<< HERE
if (!err)
err = do_new_mount_fc(fc, path, mnt_flags);
put_fs_context(fc);
return err;
}
vfs_get_tree()
函数调用 fc->ops->get_tree()
,这是负责创建 root
(如果它尚不存在)并将其分配给 fc->root
的方法。
error = fc->ops->get_tree(fc); // Here fc->root gets assigned.
if (error < 0)
return error;
对于所有文件系统,到这个新 API 的过渡仍然没有完成。对于仍然使用旧 API 的文件系统(例如 ext4),fs_context_for_mount()
函数(在 do_new_mount()
开头调用)通过 alloc_fs_context()
创建文件系统上下文,这检查文件系统是否支持新的 API,如果不支持 uses a default legacy version of the filesystem context operations(实际上,您还可以看到最后一个 link 中的注释 ” TODO:让所有文件系统无条件地支持这个).
对于 get_tree()
,旧版本是 legacy_get_tree()
,它确实完全符合您对 fc->fs_type->mount(...)
.
的期望
/*
* Get a mountable root with the legacy mount command.
*/
static int legacy_get_tree(struct fs_context *fc)
{
struct legacy_fs_context *ctx = fc->fs_private;
struct super_block *sb;
struct dentry *root;
root = fc->fs_type->mount(fc->fs_type, fc->sb_flags,
fc->source, ctx->legacy_data);
if (IS_ERR(root))
return PTR_ERR(root);
sb = root->d_sb;
BUG_ON(!sb);
fc->root = root;
return 0;
}
迟早,所有文件系统都将更新为使用新的 API 和文件系统上下文,那些 legacy_*
函数将被完全删除,我们将在中看到一个 init_fs_context
方法ext4 file_system_type
.
在相对较旧的 Linux 内核源代码中,do_new_mount()
将调用 vfs_kern_mount()
,最终会调用 mount_fs()
。而这个函数会像下面这样调用真实文件系统的函数
struct dentry *
mount_fs(struct file_system_type *type, int flags, const char *name, void *data)
{
struct dentry *root;
struct super_block *sb;
......
root = type->mount(type, flags, name, data);
......
sb = root->d_sb;
......
}
但是在相对较新的Linux内核源代码中,do_new_mount()
会调用do_new_mount_fc()
,我找不到这个函数如何像上面那样调用真实文件系统的挂载函数.
你能告诉我它现在是如何工作的吗?
由于最近过渡到 new Filesystem Mount API through "filesystem context". You can find more info in the relevant (quite massive) patchwork,您找不到“常规”函数调用。
我不打算解释整个事情,因为我在上面 link 编辑的内核文档应该已经给出了很好的解释(而且我也不是 Linux FS 内部专家) .
“文件系统上下文”基本上是一个包含有用信息的结构,这些信息会根据需要进行传递和更新。所以现在发生的是 vfs_get_tree()
function is responsible for creating the mountable root of the filesystem, and saving it in the fs_context
structure that is then passed to do_new_mount_fc()
并用于实际挂载。
(*) int vfs_get_tree(struct fs_context *fc);
Get or create the mountable root and superblock, using the parameters in
the filesystem context to select/configure the superblock. This invokes
the ->get_tree() method.
所以现在在 do_new_mount()
中,您会看到该函数在 之前 do_new_mount_fc()
:
fc = fs_context_for_mount(type, sb_flags);
put_filesystem(type);
if (IS_ERR(fc))
return PTR_ERR(fc);
if (subtype)
err = vfs_parse_fs_string(fc, "subtype",
subtype, strlen(subtype));
if (!err && name)
err = vfs_parse_fs_string(fc, "source", name, strlen(name));
if (!err)
err = parse_monolithic_mount_data(fc, data);
if (!err && !mount_capable(fc))
err = -EPERM;
if (!err)
err = vfs_get_tree(fc); // <<<<<<<<<<<<<<<<<<<<<<< HERE
if (!err)
err = do_new_mount_fc(fc, path, mnt_flags);
put_fs_context(fc);
return err;
}
vfs_get_tree()
函数调用 fc->ops->get_tree()
,这是负责创建 root
(如果它尚不存在)并将其分配给 fc->root
的方法。
error = fc->ops->get_tree(fc); // Here fc->root gets assigned.
if (error < 0)
return error;
对于所有文件系统,到这个新 API 的过渡仍然没有完成。对于仍然使用旧 API 的文件系统(例如 ext4),fs_context_for_mount()
函数(在 do_new_mount()
开头调用)通过 alloc_fs_context()
创建文件系统上下文,这检查文件系统是否支持新的 API,如果不支持 uses a default legacy version of the filesystem context operations(实际上,您还可以看到最后一个 link 中的注释 ” TODO:让所有文件系统无条件地支持这个).
对于 get_tree()
,旧版本是 legacy_get_tree()
,它确实完全符合您对 fc->fs_type->mount(...)
.
/*
* Get a mountable root with the legacy mount command.
*/
static int legacy_get_tree(struct fs_context *fc)
{
struct legacy_fs_context *ctx = fc->fs_private;
struct super_block *sb;
struct dentry *root;
root = fc->fs_type->mount(fc->fs_type, fc->sb_flags,
fc->source, ctx->legacy_data);
if (IS_ERR(root))
return PTR_ERR(root);
sb = root->d_sb;
BUG_ON(!sb);
fc->root = root;
return 0;
}
迟早,所有文件系统都将更新为使用新的 API 和文件系统上下文,那些 legacy_*
函数将被完全删除,我们将在中看到一个 init_fs_context
方法ext4 file_system_type
.