虚拟文件系统VFS---2
2016-05-26 16:22
330 查看
/* * Flags is a 32-bit value that allows up to 31 non-fs dependent flags to * be given to the mount() call (ie: read-only, no-dev, no-suid etc). * * data is a (void *) that can point to any structure up to * PAGE_SIZE-1 bytes, which can contain arbitrary fs-dependent * information (or be NULL). * * Pre-0.97 versions of mount() didn't have a flags word. * When the flags word was introduced its top half was required * to have the magic value 0xC0ED, and this remained so until 2.4.0-test9. * Therefore, if this magic number is present, it carries no information * and must be discarded. */ /* 以下几个函数将用户态参数拷贝至内核态,包括: ** 1. kernel_type:挂载文件系统类型,如ext3 ** 2. kernel_dir: 挂载点路径 ** 3. dev_name: 设备名称 ** 4. data_pages: 选项信息 */
/* 参数: ** dev_name : 挂载设备名称 ** dir_name : 挂载点名称 ** type_page: 保存挂载的文件系统类型,如"ext3" ** flags : 挂载标志 ** data_page: 大部分情况下为NULL */ long do_mount(char *dev_name, char *dir_name, 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; /* ... and get the mountpoint */ <span style="white-space:pre"> /* 调用kern_path(),根据挂载点名称查找其dentry等信息 ** 参数:@dir_name : 挂载点路径 ** :@LOOKUP_FOLLOW: 查找标志,遇到链接继续查找 ** :@path : 查找结果保存与此结构中 */ </span> 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) goto dput_out; /* 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; 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) <span style="white-space:pre"> </span> /*修改已经存在的文件系统参数,即改变超级块对象s_flags 字段的安装标志*/ 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 <span style="white-space:pre"> </span> /*handles normal mount operations. This is the default situation, so no special <span style="white-space:pre"> </span> flags are required*/ retval = do_new_mount(&path, type_page, flags, mnt_flags, dev_name, data_page); /*安装普通文件系统*/ dput_out: path_put(&path); return retval; }
对于 :kern_path(dir_name, LOOKUP_FOLLOW, &path);
其中:
/* 调用kern_path(),根据挂载点名称查找其dentry等信息
** 参数:@dir_name : 挂载点路径
** :@LOOKUP_FOLLOW: 查找标志,遇到链接继续查找
** :@path : 查找结果保存与此结构中
*/
根据挂载点的路径名在内核中查找其内存目录项结构(struct
dentry),保存在path中;
关于do_path_lookup()函数下节分析
int kern_path(const char *name, unsigned int flags, struct path *path) { struct nameidata nd; int res = do_path_lookup(AT_FDCWD, name, flags, &nd); if (!res) *path = nd.path; return res; }
对于do_new_mount(.......)分析;
/* * create a new mount for userspace and request it to be added into the * namespace's tree */ static int do_new_mount(struct path *path, char *type, int flags, int mnt_flags, char *name, void *data) { struct vfsmount *mnt; int err; if (!type) return -EINVAL; /* we need capabilities... */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; mnt = do_kern_mount(type, flags, name, data); if (IS_ERR(mnt)) return PTR_ERR(mnt); err = do_add_mount(real_mount(mnt), path, mnt_flags); if (err) mntput(mnt); return err; }
static struct vfsmount * do_kern_mount(const char *fstype, int flags, const char *name, void *data) { struct file_system_type *type = get_fs_type(fstype); struct vfsmount *mnt; if (!type) return ERR_PTR(-ENODEV); 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); return mnt; }
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 = alloc_vfsmnt(name); if (!mnt) return ERR_PTR(-ENOMEM); if (flags & MS_KERNMOUNT) mnt->mnt.mnt_flags = MNT_INTERNAL; root = mount_fs(type, flags, name, data); if (IS_ERR(root)) { 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; br_write_lock(&vfsmount_lock); list_add_tail(&mnt->mnt_instance, &root->d_sb->s_mounts); br_write_unlock(&vfsmount_lock); return &mnt->mnt;
/* * add a mount into a namespace's mount tree */ static int do_add_mount(struct mount *newmnt, struct path *path, int mnt_flags) { int err; mnt_flags &= ~(MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL); err = lock_mount(path); if (err) return err; err = -EINVAL; if (unlikely(!check_mnt(real_mount(path->mnt)))) { /* 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 (!real_mount(path->mnt)->mnt_ns) goto unlock; } /* Refuse the same filesystem on the same mount point */ err = -EBUSY; if (path->mnt->mnt_sb == newmnt->mnt.mnt_sb && path->mnt->mnt_root == path->dentry) goto unlock; err = -EINVAL; if (S_ISLNK(newmnt->mnt.mnt_root->d_inode->i_mode)) goto unlock; newmnt->mnt.mnt_flags = mnt_flags; err = graft_tree(newmnt, path); unlock: unlock_mount(path); return err;
相关文章推荐
- centos6.5 安装libevent
- python(三)字典,集合,可变与不可变对象(上)
- Linux启动/停止/重启Mysql数据库的方法
- org.hibernate.TransactionException: Transaction not successfully started
- Codeforces Round #354 (Div. 2) ABC
- as中.9图片的应用
- 实现PHP服务器+Android客户端(Retrofit+RxJava)第一天基础搭建
- MySQL存储引擎
- php中strstr、strrchr、substr、stristr四个函数用法区别:
- linux下Vim和Terminal配色
- 一起来学Android Studio:(三)导入项目
- Spring Security(20)——整合Cas
- 自定义滑动按钮
- 项目中使用spring和redis的整合
- 设置客户端连接PostgreSQL不需要密码
- PCL KinectFusion 编译安装教程
- C# SHA512 加密之我见
- 第12周项目1-复数类的运算符重载(4)-综合
- linux内核4.2.x实现自定义系统调用
- SpringMVC的Interceptor