每个mount过程都会存在一个超级块与之对应,超级块中包含了相关的信息。在写代码之前,首先搞清楚mount过程是很有必要的。

以下部分参考《深入Linux内核架构》第八章。

vfsmount和super\_block结构初步

在day1中,我们完成了文件系统的注册,也就是说我们将samplefs的信息通知内核,让内核知道有这么个东西,所以在注册过程中只需要向file\_systems链表添加一个对象就可以。但是mount过程相对来说比较复杂,下面我们详细了解。

Unix采用了一种单一的文件系统结构,新的文件系统可以嵌套其中。文件系统mount的目录叫做装载点,在将文件系统mount到一个目录时,装载点的内容被替换为即将装载的文件系统的相对根目录的位置。每个装载的文件系统都对应了一个vfsmount实例。


struct vfsmount {
      struct dentry *mnt_root;
      struct super_block *mnt_sb;
      int mnt_flags;
}

mnt\_root中保存了当前文件系统根目录的dentry,mnt\_sb中保存了当前文件系统对应的超级块。在早期内核中,vfsmount中还存在很多链表元素,目前这些成员都被转移到struct mount中,暂不对其进行更深入的分析。

在装载文件系统前,首先需要创建超级块,之后对超级块进行读取,装载工作才算正式开始,struct super_block的结构是这样的:

struct super_block {

    [...snipped...]

    unsigned char        s_blocksize_bits;
    unsigned long        s_blocksize;
    loff_t            s_maxbytes;    /* Max file size */
    struct file_system_type    *s_type;
    const struct super_operations    *s_op;

    [...snipped...]

    unsigned long        s_magic;
    struct dentry        *s_root;

    [...snipped...]

    void             *s_fs_info;    /* Filesystem private info */

    [...snipped...]

    /* Granularity of c/m/atime in ns.
       Cannot be worse than a second */
    u32           s_time_gran;

    [...snipped...]
};

s\_blocksize 和 s\_blocksize\_bits指定了文件系统的块长度。
s\_type指向file\_syetem\_type的实例,保存了与文件系统有关的一般类型的信息。
s\_root将超级块与全局根目录的dentry关联起来,而根目录的dentry又可以指向根目录的inode。一般用s\_root检查文件系统是否已经装载,如果是NULL,则该文件系统只在内核内部可见,否则在用户空间中可见。
s\_fs\_info指向文件系统的私有信息。
s\_op指向一个包含了函数指针的结构,提供了处理超级块的一般接口。具体的struct super_operations暂时不做介绍。

mount系统调用

mount系统调用在fs/namespace.c中实现:

SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
        char __user *, type, unsigned long, flags, void __user *, data)
{
    return ksys_mount(dev_name, dir_name, type, flags, data);
}

因此在5.4.89内核中,mount一个新文件系统的路径如下:

mount -> ksys_mount -> do_mount -> do_new_mount -> do_new_mount_fc -> vfs_create_mount, do_add_mount

我们发现在5.4.89内核中,在do\_new\_mount过程中,调用do\_new\_mount\_fc,发现使用了一个fs\_context新结构。

struct fs_context {
    const struct fs_context_operations *ops;
    struct mutex        uapi_mutex;    /* Userspace access mutex */
    struct file_system_type    *fs_type;
    void            *fs_private;    /* The filesystem's context */
    void            *sget_key;
    struct dentry        *root;        /* The root and superblock */
    struct user_namespace    *user_ns;    /* The user namespace for this mount */
    struct net        *net_ns;    /* The network namespace for this mount */
    const struct cred    *cred;        /* The mounter's credentials */
    struct fc_log        *log;        /* Logging buffer */
    const char        *source;    /* The source name (eg. dev path) */
    void            *security;    /* Linux S&M options */
    void            *s_fs_info;    /* Proposed s_fs_info */
    unsigned int        sb_flags;    /* Proposed superblock flags (SB_*) */
    unsigned int        sb_flags_mask;    /* Superblock flags that were changed */
    unsigned int        s_iflags;    /* OR'd with sb->s_iflags */
    unsigned int        lsm_flags;    /* Information flags from the fs to the LSM */
    enum fs_context_purpose    purpose:8;
    enum fs_context_phase    phase:8;    /* The phase the context is in */
    bool            need_free:1;    /* Need to call ops->free() */
    bool            global:1;    /* Goes into &init_user_ns */
};

我们发现,vfs\_create\_mount中原来回调fill\_super函数的位置现在变成了一个dget(fc->root),所以我个人觉得调用fill\_super的位置应该在vfs\_get\_tree中,但是目前这个函数的具体实现并未找到,明天再说。。。

写了一下午,发现自己还完全没有追内核的能力。。。只能看看大佬的文章学习了。

参考资料

Linux中的VFS实现 [二]
mount系统调用初探

明天把上面这两篇专栏系统看一看。

标签: linux, mount, 文件系统, struct, flags, fs

相关文章推荐

添加新评论,含*的栏目为必填