
- 简 介
- 是Linux下的一个命令
- 外文名
- mount
- 用 途
- 用在虚拟光驱类软件上
- 中文名
- 挂载
-
2022-04-05 11:57:11
mount系统调用剖析
开篇
对于
mount
系统调用,在linux内核代码中同样也会使用到,特别是在linux内核的启动部分的源码中,她换了一种形式:在linux内核4.1.15版本下,内核的mount操作与用户空间的mount系统调用操作接口函数是一致的:都由sys_mount()
函数完成。在linux内核4.19.4
版本下,linux内核中mount调用的接口则分离成ksys_mount()
。文本以
4.1.15
版本的linux内核作为分析对象展开。mount系统调用在linux内核中的定义如下(/fs/namespace.c):
SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, char __user *, type, unsigned long, flags, void __user *, data) { int ret; char *kernel_type; char *kernel_dev; unsigned long data_page; kernel_type = copy_mount_string(type); ret = PTR_ERR(kernel_type); if (IS_ERR(kernel_type)) goto out_type; kernel_dev = copy_mount_string(dev_name); ret = PTR_ERR(kernel_dev); if (IS_ERR(kernel_dev)) goto out_dev; ret = copy_mount_options(data, &data_page); if (ret < 0) goto out_data; ret = do_mount(kernel_dev, dir_name, kernel_type, flags, (void *) data_page); free_page(data_page); out_data: kfree(kernel_dev); out_dev: kfree(kernel_type); out_type: return ret; }
上述第9-12、14-17行代码,使用
copy_mount_string()
函数从用户空间复制已经存在的字符串:挂载类型、挂载设备名称。第19-21行代码,使用
copy_mount_options()
函数复制挂载选项参数。如果代码执行异常,将通过goto语句跳转到对应的位置,从而结束mount系统调用流程。如果没有出现错误或异常,将调用
do_mount()
函数执行实际的挂载操作。该函数则是mount操作的核心函数,下文将分析该函数。
do_mount()
函数定义如下:long do_mount(const char *dev_name, const char __user *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; /* 执行基本的检查*/ if (data_page) ((char *)data_page)[PAGE_SIZE - 1] = 0; /*寻找挂载点 */ retval = user_path(dir_name, &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; if (!(flags & MS_NOATIME)) mnt_flags |= MNT_RELATIME; //分割每个挂载点的挂载标志 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; /* 设置默认的重新挂载时间是保存时间 */ 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); 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 retval = do_new_mount(&path, type_page, flags, mnt_flags, dev_name, data_page); dput_out: path_put(&path); return retval; }
从以上代码可见,在之前的59行的代码大部分用于flags标志位的判断和设置。在59-70行代码则是真正执行的挂载逻辑。从代码可知,在do_mount()函数中,将挂载分成了5种情况:
(1)如果是重新挂载:将调用
do_remount()
执行挂载操作。(2)如果是MS_BIND标志:则调用
do_loopback()
函数。(3)如果是MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE标志:则调用
do_change_type()
函数。(4)如果是MS_MOVE标志:则调用
do_move_mount()
函数。(5)如果都不是以上四种挂载情况,那么就会调用
do_new_mount()
函数创建新的挂载。在实际挂载中,小生假设运行逻辑中
do_new_mount()
函数将被执行,下文将分析该函数。
do_new_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; //根据fstype参数获取文件系统的类型,返回struct 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; } if (type->fs_flags & FS_USERNS_VISIBLE) { if (!fs_fully_visible(type, &mnt_flags)) return -EPERM; } } 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); err = do_add_mount(real_mount(mnt), path, mnt_flags); if (err) mntput(mnt); return err; }
从以上代码可知,
do_new_mount()
函数会调用vfs_kern_mount()
函数创建文件系统的挂载,然后再调用do_add_mount()
函数将创建的挂载添加到namespace的挂载树上。
vfs_kern_mount()
函数定义如下:struct vfsmount * vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data) { struct mount *mnt; struct dentry *root; if (!type) return ERR_PTR(-ENODEV); //分配mnt挂载描述符的内存空间 mnt = alloc_vfsmnt(name); if (!mnt) return ERR_PTR(-ENOMEM); if (flags & MS_KERNMOUNT) mnt->mnt.mnt_flags = MNT_INTERNAL; //在mount_fs()函数中,将调用对应文件系统类型注册的mount函数挂载文件系统,读取并且解析超级块并返回对应的struct dentry。 root = mount_fs(type, flags, name, data); if (IS_ERR(root)) { mnt_free_id(mnt); free_vfsmnt(mnt); return ERR_CAST(root); } //设置挂载树的根和超级快 mnt->mnt.mnt_root = root; mnt->mnt.mnt_sb = root->d_sb; mnt->mnt_mountpoint = mnt->mnt.mnt_root; mnt->mnt_parent = mnt; lock_mount_hash(); //把挂载描述符添加到超级块的挂载实例链表中。 list_add_tail(&mnt->mnt_instance, &root->d_sb->s_mounts); unlock_mount_hash(); return &mnt->mnt; }
do_add_mount()
函数定义如下:static int do_add_mount(struct mount *newmnt, struct path *path, int mnt_flags) { struct mountpoint *mp; struct mount *parent; int err; mnt_flags &= ~MNT_INTERNAL_FLAGS; mp = lock_mount(path); if (IS_ERR(mp)) return PTR_ERR(mp); parent = real_mount(path->mnt); err = -EINVAL; if (unlikely(!check_mnt(parent))) { /* that's acceptable only for automounts done in private ns */ if (!(mnt_flags & MNT_SHRINKABLE)) goto unlock; /* ... and for those we'd better have mountpoint still alive */ if (!parent->mnt_ns) goto unlock; } /* 拒绝在同一个挂载点上使用相同的文件系统 */ err = -EBUSY; if (path->mnt->mnt_sb == newmnt->mnt.mnt_sb && path->mnt->mnt_root == path->dentry) goto unlock; err = -EINVAL; if (d_is_symlink(newmnt->mnt.mnt_root)) goto unlock; newmnt->mnt.mnt_flags = mnt_flags; err = graft_tree(newmnt, parent, mp); unlock: unlock_mount(mp); return err; }
do_add_mount()
函数的核心操作是:1、把挂载描述符加入到散列表中。
2、将挂载描述符加入父亲的孩子链表中。如下代码片段(出自/fs/namespace.c文件中
commit_tree()
函数):list_add_tail(&head, &mnt->mnt_list); list_for_each_entry(m, &head, mnt_list) m->mnt_ns = n;
结尾
总结一下,mount系统调用主要执行的流程如下:
(1)调用
user_path()
函数,根据目录名称找到挂载描述符和dentry实例。(2)调用
get_fs_type()
函数,根据文件系统类型的名称查找对应的file_system_type
实例。(3)调用
alloc_vfsmount()
函数,分配挂载描述符内存空间,并填充相关参数。(4)在
mount_fs()
函数中,调用对应文件系统类型下注册的mount回调函数,执行文件系统挂载操作,读取并解析超级块。(该函数与具体文件系统相关)(5)把挂载描述符添加到超级块的挂载实例链表中。
(6)把挂载描述符加入父亲的孩子链表。
由于小生知识与精力有限,如果文章存在不妥的地方,欢迎批评指正或与我讨论,哈哈!
搜索关注【嵌入式小生】wx公众号获取更多精彩内容>>>>
更多相关内容 -
mountall:针对 Linux 上 ZFS 的 Mountall 增强功能
2021-06-23 13:54:39针对 Linux 上 ZFS 的 Mountall 增强功能这个 git 存储库的主页是: 位于的 ZoL PPA 中的 Mountall 包是使用 git-buildpackage 工具从此存储库构建的。休闲构建说明只需像这样快速构建: $ apt-get source --build ... -
linux如何mount挂载磁盘并设置开机自动mount的实现
2021-01-10 03:03:39知道大家时间都很宝贵,我直接把流程...mount /dev/vdb /u01 # mount 磁盘到/u01,保证/u01为空 blkid # 获取磁盘的uuid和属性,用uuid来进行开机mount vim /etc/fstab # 开机mount,模板是UUID=********** /u01 ext4 d -
linux mount挂载共享目录详解
2021-01-20 16:08:37sudo mount //192.168.10.22/FTPServer /windows -o username=user,password=abcdefg -t cifs 方式二:密码单独输入 sudo mount //192.168.10.22/FTPServer /windows -o username=user -t cifs password:... -
Linux Mount挂载设备使用说明
2021-01-09 16:17:57对于新手学习,mount 命令,一定会有很多疑问。其实我想疑问来源更多的是对linux系统本身特殊性了解问题。 linux是基于文件系统,所有的设备都会对应于:/dev/下面的设备。如: [chengmo@centos5 dev]$ ls | grep... -
vue中的.$mount(#app)手动挂载操作
2021-01-21 11:00:05在Vue构造函数时,需要配置一个el属性,如果没有没有el属性时,可以使用.$mount(‘#app’)进行挂载。 配置了el属性: new Vue({ el:#app, router }); 如果没有配置el属性,可以使用手动挂载$mount(“#app”) new... -
mount-iso:使用 udisksctl 挂载 ISO
2021-06-14 09:50:40安装iso 使用 udisksctl 挂载 ISO ... 还可以创建 Thunar 的自定义操作( mount-iso.sh复制到/usr/bin/mount-iso ): <icon>application-x-cd-image <name>Mount ISO <command>mount-iso %f *.iso;*.ISO <other> -
Linux mount命令用法详解
2021-01-09 21:21:02Linux mount命令 Linux mount命令是经常会使用到的命令,它用于挂载Linux系统外的文件。 语法 mount [-hV] mount -a [-fFnrsvw] [-t vfstype] mount [-fnrsvw] [-o options [,...]] device | dir mount [-fnrsvw] [-... -
每天学点Vue源码之vm.$mount挂载函数
2020-12-10 21:15:44在vue实例中,通过$mount()实现实例的挂载,下面来分析一下$mount()函数都实现了什么功能。 $mount函数执行位置 _init这个私有方法是在执行initMixin时候绑定到Vue原型上的。 $mount函数是如如何把组件挂在到... -
CentOS6挂载linux7samba服务时报错:mount error(22): Invalid argument Refer to the mount.cifs(8) ...
2021-01-03 20:55:32找了好久,百度上一直都是mount命令加各种参数,确认了用户跟密码都没有问题,目录权限也都给了,最后是使用下面的办法解决的。 在/etc/fstab的挂载配置里面添加参数sec=ntlmssp,如下: //hahaha.... -
linux mount报错:you must specify the filesystem type的解决方法
2021-01-10 18:16:04最近工作中遇到一个问题,在linux mount /dev/vdb 到 /home 分区时报错: # mount /dev/vdb /home mount: you must specify the filesystem type 先执行:mkfs.ext3 /dev/vdb # mkfs.ext3 /dev/vdb mke2fs 1.41.12... -
ipfs-api-mount:将IPFS目录挂载为本地FS
2021-02-03 20:01:34ipfs-api-mount 将IPFS目录挂载为本地FS。 go-ipfs守护程序具有此功能,但从0.4.22版本开始,它的速度很慢。 ipfs-api-mount旨在提高效率。 对于顺序访问随机数据,它比ipfs cat慢3倍ipfs cat但比go-ipfs挂载的cat... -
python获得linux下所有挂载点(mount points)的方法
2020-09-15 17:32:35主要介绍了python获得linux下所有挂载点(mount points)的方法,涉及Python操作Linux下挂载点的相关技巧,非常具有实用价值,需要的朋友可以参考下 -
mount.nfs: Connection timed out
2018-10-28 20:45:52mount.nfs: Connection timed out -
mountpoint命令 判断指定的目录是否是挂载点
2021-01-20 15:01:27mountpoint命令用来判断指定的目录是否是加载点,如果是挂载点返回0,如果不是就返回非0。设备总是挂载在某个指定的目录下,所以就可以使用mountpoint这条命令来确认某个目录是否“临时性”的被文件系统占用。 语法... -
tianma-mount:将管道挂载到给定的主机名或路径名
2021-06-17 08:44:04tianma-mount 在给定域名或路径上使用中间件。 安装 $ npm install tianma-mount 使用 挂载域名 可以为不同的域名使用不同的中间件。域名可以精确到二级或者三级,也可以模糊到一级甚至是零级。 var tianma = ... -
Linux 命令之mount
2020-12-02 16:02:27Linux 命令之mount mount [-t vfstype] [-o options] device dir -t vfstype 指定文件系统的类型 iso9660 光盘或光盘镜像 msdos DOS fat 16文件系统 vfat windows 9x fat32 文件系统 ntfs Windows nt ntfs ... -
linux中mount命令 linux的mount命令使用方法参数说明.doc
2020-09-17 21:53:43linux中mount命令 linux的mount命令使用方法参数说明 --入党程序 Linux系统下mount命令是常用的命令之一它主要用于挂载linux系统外的文件主要用法有显示程序信息挂载档案等具体怎么操作呢?下面由为大家了linux的... -
tf_efs_mount:提供EFS文件系统,挂载目标和安全组的Terraform模块
2021-04-29 05:12:56TF_EFS_MOUNT 提供一个EFS文件系统,挂载目标和安全组。 用法 module " efs_mount " { source = " github.com/manheim/tf_efs_mount " name = " my-efs-mount " subnets = " subnet-abcd1234,subnet-efgh5678 " ... -
mount命令剖析.doc
2020-01-11 15:48:19系统调用mount在内核中的实现函数的深度剖析,分析了sys_mount,do_mount,do_new_mount,do_kern_mount,vfs_kern_mount,get_sb等一些接口。 -
每天学点Vue源码之vm.$mount挂载函数.pdf
2020-11-22 21:37:30每每天天学学点点Vue源源码码之之vm$mount挂挂载载函函数数 这篇文章主要介绍了vm$mount挂载函数文中通过示例代码介绍的非常详细对大家的学习或者工作具有一定 的参 学习价值需要的朋友们下面随着小编来一起学习学习... -
luks-mount:使用luks加密的外部驱动器使轻而易举的简单脚本
2021-04-14 21:16:30卢克山一个简单的脚本,使... 只需克隆存储库,将其插入cd,然后sudo ./luks-mount-install.sh执行sudo chmod a+x luks-mount-install.sh然后执行sudo ./luks-mount-install.sh 进行sudo luks-mount help以查看使用案例 -
torrent-mount:使用 torrent-stream 和 fuse 实时安装 torrent(或磁力链接)作为文件系统。 又名疯狂科学...
2021-06-15 19:12:22洪流装载使用和 fuse 实时安装 torrent(或磁力链接)作为文件系统。... [options]source .torrent file or magnet link to openOptions:-m PATH, --mount PATH Mount location path [directory] [.]-l, --lazy Dow -
cgroupfs-mount.rar
2021-08-06 10:08:30cgroupfs-mount.rar -
auto-mount.zip
2020-04-16 22:12:491,auto-mount运行起来是会定期(30s)扫描是否有USB存储设备插入。 2,当有USB存储设备插入树莓派时auto-mount可以检测出来并识别该设备的名称也就是lable,然后会创建/home/mnt/{设备lable}目录并将该设备挂载到... -
【IT十八掌徐培成】Linux基础-04.xargs-mount-umount.zip
2021-08-13 12:57:48【IT十八掌徐培成】Linux基础-04.xargs-mount-umount.zip