`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.