博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
VFS分析(一)挂载(持续更新)
阅读量:4963 次
发布时间:2019-06-12

本文共 3274 字,大约阅读时间需要 10 分钟。

基础知识在<深入linux内核架构>第8章,自行脑补.

看下几个关键的过程:

do_add_mount里有重要函数lock_mount, lock_mount函数的输入是struct path, 输出是struct mountpoint:

struct path {        struct vfsmount *mnt;        struct dentry *dentry;    };
struct mountpoint {        struct hlist_node m_hash;        struct dentry *m_dentry;        struct hlist_head m_list;        int m_count;    };
struct vfsmount {    struct dentry *mnt_root;    /* root of the mounted tree */    struct super_block *mnt_sb; /* pointer to superblock */    int mnt_flags;};

path 由 filename_lookup 得到, 其中vfsmount是当前文件系统的挂载信息, dentry是通过文件名得出的最后一级目录的dentry(比如,/mnt/dir1/dir2/,那么此时dentry对应的就是dir2的dentry.

函数: m_hash(struct vfsmount *mnt, struct dentry *dentry)

二元组<mnt, dentry>可以确定什么东西? 这个二元组可以唯一确定当前目录树中的一个目录[感觉直接用一个dentry也可以得到啊! 但是用两个参数可能散列效果更好?] ,这样可以直接得到一个下标(下标是mount_hashtable的下标). mount_hashtable是个什么事情?

这个就是函数m_hash的输出了:mount_hashtable[tmp & m_hash_mask].

我们发现,原来所有mount结构体都是通过链接元素mnt_hash链接到mount_hashtable[**]中去的,所以当我们发现了这个链表之后,就可以通过这个链表得到在这个开链上的所有的mount结构体!这里就得到了一个很重要的信息[所有的mount信息都在一个散列表mount_hashtable上维护]

这样我们就可以找到一个挂载点的所有的挂载信息了!

lookup_mnt还算是比较复杂的, 涉及到一个挂载点上挂载了多个"磁盘", lookup会找到最早的挂载的磁盘, 这个可以以后看, 现在我们只需要知道lookup_mnt发到了vfsmount结构体就可以了!

另一个函数:lookup_mountpoint(struct dentry *dentry), 这个函数在是通过dentry项, 找到全局数组&mountpoint_hashtable中的一个开链:mountpoint_hashtable[tmp & mp_hash_mask];

这里也得到一个很重要的信息:

[所有的mountpoing信息都是在一个全局的散列表mountpoint_hashtable上维护]

mountpoint 和 vfsmount有什么区别?

struct mountpoint {    struct hlist_node m_hash;    struct dentry *m_dentry;    struct hlist_head m_list;    int m_count;};

mountoint只和dentry相关, 

所以说lock_mount到最后就是得到一个mountpoint, 

-------------------------

无关:

函数vfs_kern_mount(struct file_system_type *type, int flags,  const char *name, void *data)

首先根据文件名, 分配 mount 结构体, alloc_vfsmnt(name), 

然后调用mount_fs函数得到fs相对根目录dentry,

根据dentry,初始化mount结构体, 然后根据返回mount结构提中的vfsmount成员.

--------------------------

attach_recursive_mnt是最终把这些散乱的东西链接在一起的函数

static int attach_recursive_mnt(struct mount *source_mnt,

                struct mount *dest_mnt, 

                struct mountpoint *dest_mp,

                struct path *parent_path)

各参数中, source_mnt当前新的挂载信息, dest_mnt是父挂载信息, dest_mp是挂载点的信息, parent_path是路径的信息

内核代码中这个函数头的注释我也是醉了, 好大一长串, (其中涉及到mount的属性:shared, private, slave, unbindable 等等), 之所以这么复杂, 是因为考虑到namespace的东西,这个也是将来要看的,看下docker到底是个神马东西!

===========

mount这一块确实有看头哈,看下到底怎么通过挂载点把资源给隔离开!

主要看函数:mnt_set_mountpoint (struct mount *mnt, struct mountpoint *mp, struct mount *child_mnt)

首先,mountpoint是怎么来的? mountpoint通过dentry而来, 上来之后,先把

mp->m_count++; 然后设置子mount 的 mnt_parent 为 父mount , 子mount的mnt_mountpoint点设置成mp->m_dentry, mountpoint中有一个串联所有mount信息的一个链叫做m_list, 这个链里面会把该mountpoint下面所有的mount链接在一起.

===========

3.6 commit_tree()

1.将当前文件系统的名字空间设置为父名字空间,父vfsmount通过当前vfsmount中的mnt_parent获取;再将其连接到父名字空间链表中。

2.将当前vfsmount加入到对应哈希值的冲突链表当中,哈希值通过hash()计算。其中,mnt_hash作为链表元素。

3.将当前vfsmount加入到父vfsmount对应的子文件系统链表mnt_mounts中。其中,mnt_child作为链表元素。

从整个挂载的处理流程上看,挂载的本质就是将源文件系统的vfsmount结构连接到目的文件系统对应的vfsmount结构中,即具体涉及到两个vfsmount中字段的指向问题。两个vfsmount具体父子等级关系,这也对应着内核中目录树的父子等级关系。

 

关键函数:commit_tree(struct mount *mnt, struct mount *shadows)

1 将子文件系统的命名空间设置成父命名空间, 父vfsmount通过当前vfsmount中的mnt_parent获取; 再将其联街道父命名空间列表中去.

2 将当前vfsmount加入到对应哈希值的冲突链表中去,

3 将当前vfsmount加入到父vfsmount对应的子文件系统链表mnt_mounts中去,

 

转载于:https://www.cnblogs.com/honpey/p/5097389.html

你可能感兴趣的文章
设计模式学习--Builder
查看>>
C语言中Return用法
查看>>
Android接口测试-JUnit入门
查看>>
Caffe 源码阅读 (一) ---- Windows7 + VS2015 + Python2.7 安装 (CPU only)
查看>>
基于tiny4412的Linux内核移植 (device tree 操作实例2_涉及到u-boot和内核的一系列文章 )...
查看>>
force complete tenting on top 与 force complete tenting on bottom (过孔)
查看>>
python中的几种遍历列表的方法比较
查看>>
网站最常见的错误
查看>>
协方差矩阵计算方法
查看>>
获取Linux时间函数
查看>>
scala的type alias特性
查看>>
PCL 3维点云的模板匹配
查看>>
java XML解析成Map
查看>>
[bzoj1014][JSOI2008]火星人prefix
查看>>
1010 Radix:猥琐的测试数据
查看>>
JavaScript中函数和构造函数的区别
查看>>
数据结构学习(四) Java链表实现
查看>>
Hitachi Content Platform学习
查看>>
kubernetes1.3搭建dns服务
查看>>
【性能调优】一次关于慢查询及FGC频繁的调优经历
查看>>