热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

LinuxVFS之mount系统调用(kernel3.4)

linuxversion:3.4.67kernel代码fsnamespace.c,mount.hstructvfsmount{structdentry*mnt_root;*挂载

linux version: 3.4.67


kernel 代码

fs/namespace.c ,  mount.h

struct vfsmount {
struct dentry *mnt_root;/*挂载点根目录的dentry */
struct super_block *mnt_sb;/* 挂载点批向superblock的指针*/
int mnt_flags;        //挂载标识
};


struct mount {
struct list_head mnt_hash;
struct mount *mnt_parent;
struct dentry *mnt_mountpoint;
struct vfsmount mnt;
........
};

mount命令调用关系

mount- > /fs/namespace.c/SYSCALL_DEFINE5(mount,....); -> do_mount -> do_new_mount->
    ->do_kern_mount->vfs_kern_mount->mount_fs->
     ->/fs/super.c (struct file_system_type *)type->mount(具体文件系统的mount方法)

根据调用关系对各函数注解

1、 do_mount  做一些标识判断、查找目标挂载路径,最后调用do_new_mount 

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;

//查询路径,存储在namidata结构体对象,存放了挂载点目录项对象和挂载点对象
retval = kern_path(dir_name, LOOKUP_FOLLOW, &path);
if (retval)
  return retval;
。。。。。。
/* Separate the per-mountpoint flags */
if (flags & MS_NOSUID)
  mnt_flags |= MNT_NOSUID;
if (flags & MS_NODEV)
  mnt_flags |= MNT_NODEV;   // 该文件系统类型不访问块设备

//注:根据这个标识最后具体文件系统的mount方法会调用super.c的mount_nodev或者mount_bdev。
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) //重新挂载,通常改变文件挂载的标志,如将只读的文件系统变为可写,一般不改变挂载点 ,比如:adb remount
  retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags,   data_page)

 //将文件系统的某个目录挂载到另一个目录,这样两个目录可以共同访问同一个目标设备或目录。

//比如: sprintf( emulatedPoint, "/mnt/shell/emulated/%d", uid);

//mount(emulatedPoint, "/storage/sdcard0/", "", MS_BIND, NULL);

//通过这种mount bind后,"/mnt/shell/emulated/0"和"/storage/sdcard0/" 都可以访问内置sdcard

else if (flags & MS_BIND)
  retval = do_loopback(&path, dev_name, flags & MS_REC);

//改变mount点的type,实际有这种需求吗?没用过!
else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
 retval = do_change_type(&path, flags);

//移动mo unt点,不清楚用于什么场景,没实际使用过!
else if (flags & MS_MOVE)  
  retval = do_move_mount(&path, dev_name);
else  //通常情况下调用这个函数,mount一个新的挂载点
  retval = do_new_mount(&path, type_page, flags, mnt_flags,
     dev_name, data_page);


dput_out:
path_put(&path);
return retval;
}


2、do_new_mount 创建一个新的挂载点vfsmount对象并加入到一个全局mount 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;

/* we need capabilities... */
if (!capable(CAP_SYS_ADMIN))  //mount的权限检查,只有root用户才有权mount
{
   return -EPERM;
}
//创建一个新的挂载点vfsmount对象,包括建立一个超级块对象和根目录项
mnt = do_kern_mount(type, flags, name, data);
if (IS_ERR(mnt))

  return PTR_ERR(mnt);
}
//将挂载点添加到挂载目录树,这个tree是全局的(不清楚具体算法),后面使用就在这边找吧。
err = do_add_mount(real_mount(mnt), path, mnt_flags);
if (err)
{
  mntput(mnt);
}
  return err;
}

3、do_kern_mount调用vfs_kern_mount

static struct vfsmount *
do_kern_mount(const char *fstype, int flags, const char *name, void *data)
{

  //根据type从全局file_systems链表(filesystems.c)查找已经注册的文件系统类型。比如ext4, fuse , 
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);  //创建挂载点,并返回vfsmount挂载点对象。
if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) &&
   !mnt->mnt_sb->s_subtype)
{
xlog_printk(ANDROID_LOG_DEBUG, "MNT_TAG", "do_kern_mount, fs_set_subtype\n"); 
mnt = fs_set_subtype(mnt, fstype);  //更新superblock fstype变量
}
put_filesystem(type);
return mnt;
}


4、vfs_kern_mount  申请vfsmount结构,并调用mount_fs函数

struct vfsmount *
vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
{
struct mount *mnt;
struct dentry *root;

mnt = alloc_vfsmnt(name);  //申请vfsmount结构内存,并初始化
if (!mnt)
{
return ERR_PTR(-ENOMEM);
}

if (flags & MS_KERNMOUNT)
mnt->mnt.mnt_flags = MNT_INTERNAL;

root = mount_fs(type, flags, name, data);  //调用具体的fs来mount,并得到根目的dentry和文件系统superblock等。 
if (IS_ERR(root)) {
free_vfsmnt(mnt);
return ERR_CAST(root);
}

mnt->mnt.mnt_root = root;    //根目的dentry和文件系统superblock初始化vfsmount挂载点对象
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;
}

5、mount_fs调用到具体文件系统的mount函数

struct dentry *
mount_fs(struct file_system_type *type, int flags, const char *name, void *data)
{
struct dentry *root;
struct super_block *sb;
char *secdata = NULL;
int error = -ENOMEM;

。。。。。。
root = type->mount(type, flags, name, data); // 调用具体文件系系统由register_filesystem注册的file_system_type->mount方法。

//如前面提到,从fs/super.c 中可以看到根据不同文件系统的类型mount方法最后会调用两个通用函数:访问块设备mount_bdev,和不访问块设备主mount_nodev。

sb = root->d_sb;
BUG_ON(!sb);
WARN_ON(!sb->s_bdi);
WARN_ON(sb->s_bdi == &default_backing_dev_info);
sb->s_flags |= MS_BORN;

。。。。。。。
WARN((sb->s_maxbytes <0), "%s set sb->s_maxbytes to "
"negative value (%lld)\n", type->name, sb->s_maxbytes);

return root;

}


推荐阅读
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 深入解析Linux下的I/O多路转接epoll技术
    本文深入解析了Linux下的I/O多路转接epoll技术,介绍了select和poll函数的问题,以及epoll函数的设计和优点。同时讲解了epoll函数的使用方法,包括epoll_create和epoll_ctl两个系统调用。 ... [详细]
  • Linux服务器密码过期策略、登录次数限制、私钥登录等配置方法
    本文介绍了在Linux服务器上进行密码过期策略、登录次数限制、私钥登录等配置的方法。通过修改配置文件中的参数,可以设置密码的有效期、最小间隔时间、最小长度,并在密码过期前进行提示。同时还介绍了如何进行公钥登录和修改默认账户用户名的操作。详细步骤和注意事项可参考本文内容。 ... [详细]
  • 树莓派Linux基础(一):查看文件系统的命令行操作
    本文介绍了在树莓派上通过SSH服务使用命令行查看文件系统的操作,包括cd命令用于变更目录、pwd命令用于显示当前目录位置、ls命令用于显示文件和目录列表。详细讲解了这些命令的使用方法和注意事项。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
  • 本文介绍了一种图的存储和遍历方法——链式前向星法,该方法在存储带边权的图时时间效率比vector略高且节省空间。然而,链式前向星法存图的最大问题是对一个点的出边进行排序去重不容易,但在平行边无所谓的情况下选择这个方法是非常明智的。文章还提及了图中搜索树的父子关系一般不是很重要,同时给出了相应的代码示例。 ... [详细]
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • 解决Cydia数据库错误:could not open file /var/lib/dpkg/status 的方法
    本文介绍了解决iOS系统中Cydia数据库错误的方法。通过使用苹果电脑上的Impactor工具和NewTerm软件,以及ifunbox工具和终端命令,可以解决该问题。具体步骤包括下载所需工具、连接手机到电脑、安装NewTerm、下载ifunbox并注册Dropbox账号、下载并解压lib.zip文件、将lib文件夹拖入Books文件夹中,并将lib文件夹拷贝到/var/目录下。以上方法适用于已经越狱且出现Cydia数据库错误的iPhone手机。 ... [详细]
  • 本文介绍了在go语言中利用(*interface{})(nil)传递参数类型的原理及应用。通过分析Martini框架中的injector类型的声明,解释了values映射表的作用以及parent Injector的含义。同时,讨论了该技术在实际开发中的应用场景。 ... [详细]
author-avatar
久福网_382
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有