Как do_new_mount_f c () монтирует реальные файловые системы, такие как ext4? - PullRequest
2 голосов
/ 21 июня 2020

В относительно старых исходных кодах ядра 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(), и Я не могу найти, как эта функция вызывает функцию монтирования реальной файловой системы, как указано выше.

Вы можете сказать мне, как это работает сейчас?

1 Ответ

1 голос
/ 21 июня 2020

Вы не найдете «обычных» вызовов функций из-за недавнего перехода на новый API монтирования файловой системы через «контекст файловой системы». Вы можете найти больше информации в соответствующем (довольно массивном) patchwork .

Я не собираюсь объяснять все это, поскольку документация ядра, на которую я ссылался выше, уже должна дать довольно хорошее объяснение (и я также не являюсь экспертом по внутреннему устройству Linux FS).

«Контекст файловой системы» - это в основном структура, содержащая полезную информацию, которая передается и обновляется постепенно по мере необходимости. Теперь происходит следующее: функция vfs_get_tree() отвечает за создание монтируемого root файловой системы и сохранение его в структуре fs_context, которая затем передается в 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. , а если нет, то использует устаревшую версию контекстных операций файловой системы по умолчанию (на самом деле, вы также можете увидеть комментарий в этой последней ссылке, в котором говорится: «ЗАДАЧИ: Сделайте так, чтобы все файловые системы поддерживали это безоговорочно» ).

Для 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 .

...