mount过程分析之三(do_mount -> do_new_mount)

来源:互联网 发布:mariadb mysql 对比 编辑:程序博客网 时间:2024/06/05 19:45
上文我们说到了mount系统调用(简称sys_mount),下面我们就从sys_mount开始往下分析mount的过程

sys_mount - > do_mount


do_mount函数也在namespace.c里可以找到,如下:

long do_mount(const char *dev_name, const char *dir_name,                const char *type_page, unsigned long flags, void *data_page){        struct path path;        int retval = 0;        int mnt_flags = 0;        /* Discard magic */        if ((flags & MS_MGC_MSK) == MS_MGC_VAL)                flags &= ~MS_MGC_MSK;        /* Basic sanity checks */        if (!dir_name || !*dir_name || !memchr(dir_name, 0, PAGE_SIZE))                return -EINVAL;        if (data_page)                ((char *)data_page)[PAGE_SIZE - 1] = 0;        // 把mountpoint解释成path内核结构,这里是路径名解析的过程        // 调用do_path_lookup。关于路径名解析我们后面再说        /* ... and get the mountpoint */        retval = kern_path(dir_name, LOOKUP_FOLLOW, &path);        if (retval)                return retval;        retval = security_sb_mount(dev_name, &path,                                   type_page, flags, data_page);        if (!retval && !may_mount())                retval = -EPERM;        if (retval)                goto dput_out;        // 从这里开始就是一系列的对flags的解析,把通用option提出来        // 并且找出我们要mount做哪种操作,如bind, remount, newmount等        /* Default to relatime unless overriden */        if (!(flags & MS_NOATIME))                mnt_flags |= MNT_RELATIME;        /* Separate the per-mountpoint flags */        if (flags & MS_NOSUID)                mnt_flags |= MNT_NOSUID;        if (flags & MS_NODEV)                mnt_flags |= MNT_NODEV;        if (flags & MS_NOEXEC)                mnt_flags |= MNT_NOEXEC;        if (flags & MS_NOATIME)                mnt_flags |= MNT_NOATIME;        if (flags & MS_NODIRATIME)                mnt_flags |= MNT_NODIRATIME;        if (flags & MS_STRICTATIME)                mnt_flags &= ~(MNT_RELATIME | MNT_NOATIME);        if (flags & MS_RDONLY)                mnt_flags |= MNT_READONLY;        /* The default atime for remount is preservation */        if ((flags & MS_REMOUNT) &&            ((flags & (MS_NOATIME | MS_NODIRATIME | MS_RELATIME |                       MS_STRICTATIME)) == 0)) {                mnt_flags &= ~MNT_ATIME_MASK;                mnt_flags |= path.mnt->mnt_flags & MNT_ATIME_MASK;        }        flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | MS_BORN |                   MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT |                   MS_STRICTATIME);        // 根据flags的指示,决定做哪种mount操作        if (flags & MS_REMOUNT)                retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags,                                    data_page);        else if (flags & MS_BIND)                retval = do_loopback(&path, dev_name, flags & MS_REC);        else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))                retval = do_change_type(&path, flags);        else if (flags & MS_MOVE)                retval = do_move_mount(&path, dev_name);        else                // 我们这里以new mount为入手点,继续向下分析                retval = do_new_mount(&path, type_page, flags, mnt_flags,                                      dev_name, data_page);dput_out:        path_put(&path);        return retval;}


综上所述,我们得出do_mount主要干这么几个事:

1. 解析mountpoint路径名,把字符串路径名变成内核dentry或者说path结构

2. 解析flags,把通用option分出来。

3. 根据flags中指明mount操作的标志,决定做哪一种mount操作。

4. 执行remount/bind/shared/move/new mount操作。


到此mount就可能做5种mount操作(remount, bind, chang type, move和new mount)之一。我们以do_new_mount为例继续分析,do_new_mount属于最常见的情况,挂载一个新的文件系统。

sys_mount - > do_mount -> do_new_mount

do_new_mount函数也在namespace.c里可以找到,它主要做三件事:
1.根据fstype从全局文件系统类型(file_system_type)链表中找到对应的文件系统类型结构
2. 用上一步得到的特定文件系统类型结构中的mount回调函数执行下面的挂载操作,最终构建一个mount结构体,其中包含vfsmount信息。
3.将得到的mount结构体加入全局文件系统树中


来看一下详细代码:

static int do_new_mount(struct path *path, const char *fstype, int flags,                        int mnt_flags, const char *name, void *data){        struct file_system_type *type;        struct user_namespace *user_ns = current->nsproxy->mnt_ns->user_ns;        struct vfsmount *mnt;        int err;        if (!fstype)                return -EINVAL;        // 根据fs类型名(如xfs)在全局文件系统类型链表上找到其对应的file_system_type结构        type = get_fs_type(fstype);        if (!type)                return -ENODEV;        if (user_ns != &init_user_ns) {                if (!(type->fs_flags & FS_USERNS_MOUNT)) {                        put_filesystem(type);                        return -EPERM;                }                /* Only in special cases allow devices from mounts                 * created outside the initial user namespace.                 */                if (!(type->fs_flags & FS_USERNS_DEV_MOUNT)) {                        flags |= MS_NODEV;                        mnt_flags |= MNT_NODEV | MNT_LOCK_NODEV;                }        }        // 调用此函数准备进入每个文件系统的个别处理函数,构建一个vfsmnt结构        // 注意这里以文件系统类型、挂载标记、设备名和挂载选项信息为参数,并没有mountpoint参数。这里只是想用type中的mount回调函数读取设备的superblock信息,填充mnt结构,然后把flag和data解析后填充到mnt结构中。        mnt = vfs_kern_mount(type, flags, name, data);        if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) &&            !mnt->mnt_sb->s_subtype)                mnt = fs_set_subtype(mnt, fstype);        put_filesystem(type);        if (IS_ERR(mnt))                return PTR_ERR(mnt);        // 准备将得到的mnt结构加入全局文件系统树        // 注意path变量,也就是mountpoint在这里        err = do_add_mount(real_mount(mnt), path, mnt_flags);        if (err)                mntput(mnt);        return err;}


vfs_kern_mount和do_add_mount是接下来重要的两个步骤,vfs_kern_mount继续解析superblock并填充mnt结构,do_add_mount将创建好的mnt加入到全局文件系统树中。所以下面将分别按两条线对这两个函数的过程进行详述。




http://blog.csdn.net/zr_lang/article/details/40325241 (mount 七)

http://blog.csdn.net/zr_lang/article/details/40343899 (mount 六)

http://blog.csdn.net/zr_lang/article/details/40115013 (mount 五)

http://blog.csdn.net/zr_lang/article/details/40080979 (mount 四)

http://blog.csdn.net/zr_lang/article/details/40049305 (mount 三)

http://blog.csdn.net/zr_lang/article/details/40002285 (mount 二)

http://blog.csdn.net/zr_lang/article/details/39963253 (mount 一)
0 0
原创粉丝点击