百科生活 投稿
关于【xyn是什么意思】:深入剖析Linux文件系统之文件系统挂载(二)(超详细~),建筑h代表什么意思(建筑图xy代表什么意思),今天小编给您分享一下,如果对您有所帮助别忘了关注本站哦。
- 内容导航:
- 1、建筑h代表什么意思(建筑图xy代表什么意思)
- 2、深入剖析Linux文件系统之文件系统挂载(二)(超详细~)
1、建筑h代表什么意思(建筑图xy代表什么意思)
1测量学的概念:测量学是研究地球的形状和大小以及确定地面点位的科学。
分为测定和测设两部分内容。

2地球的物理表面——水准面;地球的数学表面——旋转椭球体面
重力的方向线称为铅垂线—基准线;
水准面:任何一点都与重力方向相垂直的面。或水在静止时的表面。
水平面:与水准面相切的平面。
大地水准面:与平均海水面相吻合并向大陆岛屿延伸而形成的封闭曲面称为大地水准面——测量基准面;所包围的形体称为大地体。
地球椭球体:椭圆绕其短轴旋转而成的旋转椭球体,又称地球椭球体。
3测量坐标系与数学坐标系的区别:坐标轴不同,象限旋转顺序不同
4地面点的高程:(1)绝对高程:地面点到大地水准面的铅垂距离,称为该点的绝对高程,简称高程,用H 表示。(2)相对高程:地面点到假定水准面的铅垂距离,称为该点的相对高程或假定高程。(3)高差:地面两点间的高程之差,称为高差,用h 表示。高差有方向和正负。
5测量工作的原则:1、在布局上遵循“由整体到局部”的原则,在精度遵循“由高级到低级”的原则,在程序上遵循“先控制后碎部”的原则;2、在测量过程中,遵循“随时检查,杜绝错误”的原则;
测量的基本工作:1测距离、角度、高差是测量的基本工作;2距离、水平角、高差称测量三要素;3观测、计算、绘图是测量工作的基本技能
6水准测量:高差等于后视读数减去前视读数。
计算未知点高程:1.高差法;2.视线高法
7DS3微倾式水准仪的构造:望远镜;水准器;基座
视准轴CC :十字丝交点与物镜光心的连线
水准管轴LL :过零点与内表面相切的直线CC ∥LL ———构造满足的主要条件
圆水准器轴L ′L ′:过零点的球面法线; L ′L ′∥VV 。
水准仪的操作:1、安置仪器2、粗略整平3、瞄准水准尺4、精确整平5、读数
8视差:眼睛在目镜端上下移动,有时可看见十字丝的中丝与水准尺影像之间相对移动的现象。
产生的原因:水准尺的尺像与十字丝平面不重合。
消除的方法:仔细地转动物镜对光螺旋,直至尺像与十字丝平面重合。
9水准点:用水准测量的方法测定的高程控制点,称为水准点。
水准路线:在水准点间进行水准测量所经过的路线,称为水准路线。相邻两水准点间的路线称为测段。
在一般的工程测量中,水准路线布设形式主要有以下三种形式:1.附合水准路线2.闭合水准路线3.支水准路线
10普通水准测量方法: ∑∑-=理测h h f h z Kl Kl D 22sin cos ==α
水准测量成果整理:高差闭合差的计算:fh= ∑h 观 -∑h ;
高差改正数: 了解p25表2-2
11:DS3型水准仪的检验与校正:
水准仪应满足的几何条件:(1)L ′L ′∥VV ;(2)十字丝的中丝VV ;(3)LL ∥CC 。
12:角度测量:
水平角测量原理:水平角:地面上某点到两目标的方向线铅垂投影在水平面上所成的角度。 用β表示,0˚~360˚。
竖直角测量原理:竖直角α :在同一竖直面内,地面某点至目标方向线与水平视线间的夹角,又称倾角。0˚~±90˚。
13DJ6光学经纬仪及其操作:
DJ6型光学经纬仪的构造:照准部;基座;水平读盘;
DJ6光学经纬仪的基本操作:安置仪器,瞄准目标,读数;
安置仪器:(1)对中目的:仪器中心与测站点位于同一铅垂线上。方法:垂球:误差<3m 光学:误差<1mm;(2)整平目的:使仪器竖轴处于铅垂位置,水平度盘处于水平位置。方法:升降脚架使圆气泡大致居中;转脚螺旋,使长气泡居中。
14水平角的观测:1.测回法的观测方法:(1)在测站点O 安置经纬仪(2)盘左位置:顺时针转动照准部观测(3)盘右位置:逆时针转动照准部观测
2.方向观测法的观测方法:(1)在测站点O 安置经纬仪(2)盘左位置:顺时针转动照准部观测(3)盘右位置:逆时针转动照准部观测
了解书本p44,45表3-1,3-2
15竖直角观测
盘左位置: 盘右位置: 一测回竖直角: 竖盘指标偏离正确位置的差值x 角,称为竖盘指标差。 竖直角观测:(1)在测站点O 安置经纬仪(2)盘左位置:(3)盘右位置: 书本p50表3-3
16经纬仪的轴线及各轴线间应满足的几何条件:
经纬仪的主要轴线有:竖轴VV 、横轴HH 、视准轴CC 、水准管轴LL 。
经纬仪各轴线之间应满足以下几何条件:(1)LL VV ;(2)十字丝竖丝HH ;(3)CC HH ;(4)HH VV ;(5)竖盘指标指在正确的位置
17角度测量误差与注意事项
仪器误差:http://1.CC 不HH 横轴(视准轴误差);盘左、盘右观测取平均值;2.HH 不VV (横轴误差)盘左、盘右观测取平均值;3.水平度盘的偏心差;盘左、盘右观测取平均值
4.水平度盘刻划不均匀误差;多测回观测,按180º/ n 变换水平度盘位置;
5.仪器竖轴倾斜误差;无法采用一定的观测方法加以消除。在经纬仪使用之前应严格检校仪器竖轴与水准管轴的垂直关系。 i h i n n f v ∑-=i h i L L f v ∑
-=L L -︒=90α︒
-=270R R α)(21R L ααα+=)360(2
1)(21-+=-=R L x L R αα
观测误差: 1.仪器对中误差2.目标偏心误差
18距离测量
距离:两点间的水平长度
直线定线:在两点的连线上标定出若干个点,这项工作称为直线定线。
按精度要求的不同,直线定线分为:目估定线;经纬仪定线
相对误差K 应化为分子为1的分数形式。 19视距测量:视线倾斜时水平距离的计算公式为:
视线倾斜时高差的计算公式为:
20测量误差的基本知识
测量误差的来源:仪器,观测者,外界环境;观测条件相同称等精度观测;观测条件不相同称非等精度观测
测量误差的分类:系统误差,偶然误差
1.系统误差:定义:在相同观测条件下,对某量进行一系列观测,如果误差出现的符号和大小均相同,或按一定的规律变化,这种误差称为系统误差。特性:累积性。消除或削减措施: (1)进行计算改正 (2)选择适当的观测方法
2.偶然误差:在相同的观测条件下,对某量进行一系列的观测,如果观测误差的符号和大小都不一致,表面上没有任何规律性,这种误差称为偶然误差。
偶然误差的统计特性:(1)在一定的观测条件下,偶然误差的绝对值有一定的限值(范围)
(2)绝对值较小的误差比绝对值较大的误差出现的概率大(大小)
(3)绝对值相等的正、负误差出现的概率相同(符号)
(4)同一量的等精度观测,其偶然误差的算术平均值,随观测次数n 的无限增加而趋于零(抵偿性)
返往平均平均
返往D D D D D D K -=-=1v i Kl h -+=α2sin 21
#建筑##工程#

2、深入剖析Linux文件系统之文件系统挂载(二)(超详细~)
本文为文件系统挂载专题文章的第二篇,主要介绍如何通过挂载实例关联挂载点和超级块并添加到全局文件系统树。
深入剖析Linux文件系统之文件系统挂载(一)(超详细~)
4. 添加到全局文件系统树
4.1 do_new_mount_fc
do_new_mount //fs/namespace.c->do_new_mount_fc -> struct vfsmount *mnt; -> struct mountpoint *mp; -> struct super_block *sb = fc->root->d_sb; //获得vfs的超级块 (之前已经构建好) > mnt = vfs_create_mount(fc); //为一个已配置的超级块 分配mount实例 -> mp = lock_mount(mountpoint); //寻找挂载点 如果挂载目录是挂载点(已经有文件系统挂载其上),则将最后一次挂载的文件系统根目录作为挂载点 -> do_add_mount(real_mount(mnt), mp, mountpoint, mnt_flags); //关联挂载点 加入全局文件系统树
4.2 vfs_create_mount源码分析
vfs_create_mount -> mnt = alloc_vfsmnt(fc->source ?: "none"); //分配mount实例 -> mnt->mnt.mnt_sb = fc->root->d_sb; //mount关联超级块 (使用vfsmount关联) -> mnt->mnt.mnt_root = dget(fc->root); //mount关联根dentry (使用vfsmount关联) -> mnt->mnt_mountpoint = mnt->mnt.mnt_root; // mount关联挂载点 (临时指向根dentry,后面会指向真正的挂载点,以至于对用户可见) -> mnt->mnt_parent = mnt; //父挂载指向自己 (临时指向 后面会设置) -> return &mnt->mnt; //返回内嵌的vfsmount
- 注:老内核使用的是vfsmount来描述文件系统的一次挂载,现在内核都使用mount来描述,而vfsmount被内嵌到mount中,主要来描述文件系统的超级块和跟dentry。
vfs_create_mount之后vfs对象数据结构之间关系图如下:
更多linux内核视频教程文档资料免费领取后台私信【内核】自行获取.
4.3 lock_mount源码分析
lock_mount是最不好理解的函数,下面详细讲解:
-> mp = lock_mount(mountpoint);
//不只是加锁, 通过传来的 挂载点的 path(vfsmout, dentry二元组),来查找最后一次挂载的文件系统的根dentry作为即将挂载文件系统的挂载点
我们看下这个函数
-> 这个函数主要从挂载点的path(即是挂载目录的path结构,如挂载到/mnt下, path为mnt的path) 来找到真正的挂载点 两种情况:
1.如果挂载点的path 是正常的目录,原来不是挂载点,则直接返回这个目录的dentry作为挂载点(mountpoint的m_dentry会指向挂载点的dentry)
2.如果挂载点的path不是正常的目录,原来就是挂载点,说明这个目录已经有其他的文件系统挂载,那么它会查找最后一个挂载到这个目录的文件系统的根dentry,作为真正的挂载点。
我们打开这个黑匣子看一下:首先传递来的path 是一个表示要解析的挂载目录[vfsmount,dentry]二元组,如我们要挂载到 /mnt (path即为
//include/linux/path.h 描述一个路径struct path { struct vfsmount *mnt; struct dentry *dentry;} __randomize_layout; //fs/mount.h 描述一个挂载点struct mountpoint { struct hlist_node m_hash; struct dentry *m_dentry; struct hlist_head m_list; int m_count; }; static struct mountpoint *lock_mount(struct path *path) { struct vfsmount *mnt; struct dentry *dentry = path->dentry; //获得挂载目录的dentry retry: inode_lock(dentry->d_inode); //写方式申请 inode的读写信号量 if (unlikely(cant_mount(dentry))) { //判断挂载目录能否被挂载 inode_unlock(dentry->d_inode); return ERR_PTR(-ENOENT); } namespace_lock(); //写方式申请 命名空间读写信号量 mnt = lookup_mnt(path); //查找挂载在path上的第一个子mount //!!!重点函数,后面分析 !!! if (likely(!mnt)) { // mnt为空 说明没有文件系统挂载在这个path上 是我们要找的目标 //1.如果dentry之前是挂载点 则从mountpoint hash表 查找mountpoint (dentry计算hash) // 2. 如果dentry之前不是挂载点 分配mountpoint 加入mountpoint hash表(dentry计算hash),设置dentry为挂载点 struct mountpoint *mp = get_mountpoint(dentry); //!!!重点函数,后面会分析 !!! if (IS_ERR(mp)) { namespace_unlock(); inode_unlock(dentry->d_inode); return mp; } return mp; //返回找到的挂载点实例 (这个挂载点的dentry之前没有被挂载) } namespace_unlock(); //释放命名空间读写信号量 inode_unlock(path->dentry->d_inode); //释放 inode的读写信号量 path_put(path); path->mnt = mnt; // path->mnt指向找到的vfsmount dentry = path->dentry = dget(mnt->mnt_root); //path->dentry指向找到的vfsmount的根dentry! goto retry; //继续查找下一个挂载}
1)get_mountpoint源码分析
static struct mountpoint *get_mountpoint(struct dentry *dentry) { struct mountpoint *mp, *new = NULL; int ret; if (d_mountpoint(dentry)) { //dentry为挂载点 (当dentry为挂载点时 会设置dentry->d_flags 的DCACHE_MOUNTED标志) if (d_unlinked(dentry)) return ERR_PTR(-ENOENT); mountpoint: read_seqlock_excl(&mount_lock); mp = lookup_mountpoint(dentry); // 从mountpoint hash表 查找mountpoint (dentry计算hash) read_sequnlock_excl(&mount_lock); if (mp) goto done; //找到直接返回mountpoint实例 } if (!new) //mountpoint哈希表中没有找到 则分配 new = kmalloc(sizeof(struct mountpoint), GFP_KERNEL); if (!new) return ERR_PTR(-ENOMEM); ret = d_set_mounted(dentry); //设置dentry为挂载点 ->dentry->d_flags |= DCACHE_MOUNTED; //设置挂载点标志很重要 路径名查找时发现为挂载点则会步进到相关文件系统的跟dentry if (ret == -EBUSY) goto mountpoint; mp = ERR_PTR(ret); if (ret) goto done; read_seqlock_excl(&mount_lock); new->m_dentry = dget(dentry); //设置mountpoint实例 的m_dentry 指向dentry new->m_count = 1; hlist_add_head(&new->m_hash, mp_hash(dentry)); // mountpoint实例添加到 mountpoint_hashtable INIT_HLIST_HEAD(&new->m_list); //初始化 挂载链表 mount实例会加入到这个链表 read_sequnlock_excl(&mount_lock); mp = new; //指向挂载点 new = NULL; done: kfree(new); return mp; //返回挂载点 }
2)lookup_mnt源码分析
它在文件系统挂载和路径名查找都会使用到,作用为查找挂载在这个path下的第一个子vfsmount实例。
->文件系统挂载场景中,使用它查找合适的vfsmount实例作为父vfsmount。
->路径名查找场景中,使用它查找一个合适的vfsmount实例作为下一级路径名解析起点的vfsmount。
//fs/namespace.clookup_mnt(const struct path *path)-> struct mount *child_mnt; struct vfsmount *m; child_mnt = __lookup_mnt(path->mnt, path->dentry); //委托__lookup_mnt m = child_mnt ? &child_mnt->mnt : NULL; //返回mount实例的vfsmount实例 或NULL return m;->struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry) { struct hlist_head *head = m_hash(mnt, dentry); // 根据 父vfsmount实例 和 挂载点的dentry查找 mount_hashtable的一个哈希表项 struct mount *p; hlist_for_each_entry_rcu(p, head, mnt_hash) //从哈希表项对应的链表中查找 遍历链表的每个节点 if (&p->mnt_parent->mnt == mnt && p->mnt_mountpoint == dentry) //节点的mount实例的父mount为mnt 且mount实例的挂载点为 dentry return p; //找到返回mount实例 return NULL; //没找到返回NULL}
3)lock_mount情景分析
1)lock_mount传递的path 之前不是挂载点:
调用链为:
lock_mount ->mnt = lookup_mnt(path) //没有子mount 返回NULL ->mp = get_mountpoint(dentry) //分配mountpoint 加入mountpoint hash表(dentry计算hash),设置dentry为挂载点 ->return mp //返回找到的挂载点实例
2)lock_mount传递的path 之前是挂载点:我们现在执行 mount -t ext2 /dev/sda4 /mnt
之前 /mnt的挂载情况
mount /dev/sda1 /mnt (1) mount /dev/sda2 /mnt (2) mount /dev/sda3 /mnt (3)
调用链为:
lock_mount ->mnt = lookup_mnt(path) //返回(1)的mount实例 ->path->mnt = mnt //下一次查找的 path->mnt赋值(1)的mount实例 ->dentry = path->dentry = dget(mnt->mnt_root) // //下一次查找path->dentry 赋值(1)的根dentry
->mnt = lookup_mnt(path) //返回(2)的mount实例 ->path->mnt = mnt //下一次查找的 path->mnt赋值(2)的mount实例 ->dentry = path->dentry = dget(mnt->mnt_root) // //下一次查找path->dentry 赋值(2)的根dentry ->mnt = lookup_mnt(path) //返回(3)的mount实例
->path->mnt = mnt //下一次查找的 path->mnt赋值(3)的mount实例 ->dentry = path->dentry = dget(mnt->mnt_root) // //下一次查找path->dentry 赋值(3)的根dentry -> mnt = lookup_mnt(path) //没有子mount 返回NULL ->mp = get_mountpoint(dentry) //分配mountpoint 加入mountpoint hash表(dentry计算hash),设置dentry为挂载点((3)的根dentry作为挂载点)
->return mp //返回找到的挂载点实例(也就是最后一次挂载(3) 文件系统的根dentry)
4.4 do_add_mount源码分析
准备好了挂载点之后,接下来子mount实例关联挂载点以及添加子mount实例到全局的文件系统挂载树中。
do_add_mount //添加mount到全局的文件系统挂载树中->struct mount *parent = real_mount(path->mnt); //获得父挂载点的挂载实例->graft_tree(newmnt, parent, mp) -> mnt_set_mountpoint(dest_mnt, dest_mp, source_mnt) -> child_mnt->mnt_mountpoint = mp->m_dentry; //关联子mount到挂载点的dentry child_mnt->mnt_parent = mnt; //子mount->mnt_parent指向父mount child_mnt->mnt_mp = mp; //子mount->mnt_mp指向挂载点 hlist_add_head(&child_mnt->mnt_mp_list, &mp->m_list); //mount添加到挂载点链表 ->commit_tree //提交挂载树 ->__attach_mnt(mnt, parent) -> hlist_add_head_rcu(&mnt->mnt_hash, ¦ m_hash(&parent->mnt, mnt->mnt_mountpoint)); //添加到mount hash表 ,通过父挂载点的vfsmount和挂载点的dentry作为索引(如上面示例中的<(3)的vfsmount , (3)的根dentry>) list_add_tail(&mnt->mnt_child, &parent->mnt_mounts); //添加到父mount链表
上面说了一大堆,主要为了实现:
将mount实例与挂载点联系起来(会将mount实例加入到mount 哈希表,父文件系统的vfsmount和真正的挂载点的dentry组成的二元组为索引,路径名查找时便于查找),以及mount实例与文件系统的跟dentry联系起来(路径名查找的时候便于沿着跟dentry来访问这个文件系统的所有文件)。
do_add_mount 之后vfs对象数据结构之间关系图(/mnt之前不是挂载点情况)如下:
5. mount的应用
- 上面几章我们分析了文件系统挂载的主要流程,创建并关联了各个vfs的对象,为了打开文件等路径名查找时做准备。
5.1 路径名查找到挂载点源码分析
//fs/namei.c 查找一个路径分量walk_component ->step_into ->handle_mounts ->traverse_mounts ->flags = smp_load_acquire(&path->dentry->d_flags); //获得dentry标志 ->__traverse_mounts(path, flags, jumped, count, lookup_flags); //查找挂载点 返回不再是挂载点的path -> { while (flags & DCACHE_MANAGED_DENTRY) { //找到的dentry是挂载点 则继续查找 ,不是则退出循环 ... if (flags & DCACHE_MOUNTED) { // something's mounted alt="xyn是什么意思,建筑h代表什么意思(建筑H表示什么)" src="https://p3.toutiaoimg.com/tos-cn-i-qvj2lq49k0/84fd18fcb99e47438e0653eb84a6c920~tplv-tt-large.image" />
解释:mount实例、super_block实例、file_system_type实例三种层级逐渐升高,即一个file_system_type实例会包含多个super_block实例,一个super_block实例会包含多个mount实例。一种file_system_type必须先被注册到系统中来宣誓这种文件系统存在,主要提供此类文件系统的挂载和卸载方法等,注册即是加入全局的file_systems链表,等到有块设备上的文件系统要挂载时就会根据挂载时传递的文件系统类型名查找file_system_type实例,如果查找到,就会调用它的挂载方法进行挂载。首先,在file_systems实例的super_block链表中查找有没有super_block实例已经被创建,如果有就不需要从磁盘读取(这就是一个块设备上的文件系统挂载到多个目录上只有一个super_block实例的原因),如果没有从磁盘读取并加入对应的file_systems实例的super_block链表。而每次挂载都会创建一个mount实例来联系挂载点和super_block实例,并以(父vfsmount,挂载点dentry)为索引加入到全局mount哈希表,便于后面访问这个挂载点的文件系统时的路径名查找。
2)父子文件系统挂载关系图解
解释:图中/dev/sda1中的子文件系统挂载到父文件系统的/mnt目录下。当挂载的时候会创建mount、super_block、跟inode、跟dentry四大数据结构并建立相互关系,将子文件系统的mount加入到(Vp, Dp3)二元组为索引的mount哈希表中,通过设置mnt的目录项(Dp3)的DCACHE_MOUNTED来将其标记为挂载点,并与父文件系统建立亲缘关系挂载就完成了。
当需要访问子文件系统中的某个文件时,就会通过路径名各个分量解析到mnt目录,发现其为挂载点,就会通过(Vp, Dp3)二元组在mount哈希表中找到子文件系统的mount实例(Mc),然后就会从子文件系统的跟dentry(Dc1)开始往下继续查找,最终访问到子文件系统上的文件。
3)单个文件系统多挂载点关系图解
解释:图中将/dev/sda1中的文件系统分别挂载到父文件系统的/mnt/a和/mnt/b目录下。当第一次挂载到/mnt/a时,会创建mount、super_block、跟inode、跟dentry四大数据结构(分别对应与Mc1、Sc、Dc1、Ic)并建立相互关系,将子文件系统的Mc1加入到(Vp, Dp3)二元组为索引的mount哈希表中,通过设置/mnt/a的目录项的DCACHE_MOUNTED来将其标记为挂载点,并与父文件系统建立亲缘关系挂载就完成了。然后挂载到/mnt/b时, Sc、Dc1、Ic已经创建好不需要再创建,内存中只会有一份,会创建Mc2来关联super_block和第二次的挂载点,建立这几个数据结构关系,将子文件系统的Mc2加入到(Vp, Dp4)二元组为索引的mount哈希表中,通过设置/mnt/b的目录项的DCACHE_MOUNTED来将其标记为挂载点,并与父文件系统建立亲缘关系挂载就完成了。
当需要访问子文件系统中的某个文件时,就会通过路径名各个分量解析到/mnt/a目录,发现其为挂载点,就会通过(Vp, Dp3)在mount哈希表中找到子文件系统的Mc1,然后就会从子文件系统的Dc1开始往下继续查找,最终访问到子文件系统上的文件。同样,如果解析到/mnt/b目录,发现其为挂载点,就会通过(Vp, Dp4)在mount哈希表中找到子文件系统的Mc2,然后就会从子文件系统的Dc1开始往下继续查找,最终访问到子文件系统上的文件。可以发现,同一个块设备上的文件系统挂载到不同的目录上,相关联的super_block和跟dentry是一样的,这保证了无论从哪个挂载点开始路径名查找都访问到的是同一个文件系统上的文件。
3)多文件系统单挂载点关系图解
解释:最后我们来看多文件系统单挂载点的情况,图中先将块设备/dev/sda1中的子文件系统1挂载到/mnt目录,然后再将块设备/dev/sdb1中的子文件系统2挂载到/mnt目录上。
当子文件系统1挂载的时候,会创建mount、super_block、跟inode、跟dentry四大数据结构(分别对应与Mc1、Sc1、Dc1、Ic1)并建立相互关系,将子文件系统的Mc1加入到(Vp, Dp3)二元组为索引的mount哈希表中,通过设置/mnt的目录项的DCACHE_MOUNTED来将其标记为挂载点,并与父文件系统建立亲缘关系挂载就完成了。
当子文件系统2挂载的时候,会创建mount、super_block、跟inode、跟dentry四大数据结构(分别对应与Mc2、Sc2、Dc4、Ic2)并建立相互关系,这个时候会发现/mnt目录是挂载点,则会将子文件系统1的根目录(Dc1)作为文件系统2的挂载点,将子文件系统的Mc2加入到(Vc1, Dc1)二元组为索引的mount哈希表中,通过设置Dc1的DCACHE_MOUNTED来将其标记为挂载点,并与父文件系统建立亲缘关系挂载就完成了。
这个时候,子文件系统1已经被子文件系统2隐藏起来了,当路径名查找到/mnt目录时,发现其为挂载点,则通过(Vp, Dp3)二元组为索引在mount哈希表中找到Mc1,会转向文件系统1的跟目录(Dc1)开始往下继续查找,发现Dc1也是挂载点,则(通过Vc1, Dc1)二元组为索引在mount哈希表中找到Mc2, 会转向文件系统1的跟目录(Dc4)开始往下继续查找,于是就访问到了文件系统2中的文件。除非,文件系统2被卸载,文件系统1的跟dentry(Dc1)不再是挂载点,这个时候文件系统1中的文件才能再次被访问到。
7. 总结
Linux中,块设备上的文件系统只有挂载到内存的目录树中的一个目录下,用户进程才能访问,而挂载是创建数据结构关联块设备上的文件系统和挂载点,使得路径名查找的时候能够通过挂载点目录访问到挂载在其下的文件系统。
7.1 挂载主要步骤
1.vfs_get_tree 调用具体文件系统的获取填充超级块方法(fs_context_operations.get_tree或者file_system_type.mount), 在内存构建super_block,然后构建根inode和根dentry(磁盘文件系统可能需要从磁盘读取磁盘超级块构建内存的super_block,从磁盘读取根inode构建内存的inode)。2.do_new_mount_fc 对于每次挂载都会分配mount实例,用于关联挂载点到文件系统。当一个要挂载的目录不是挂载点,会设置这个目录的dentry为挂载点,然后mount实例记录这个挂载点。当一个要挂载的目录是挂载点(之前已经有文件系统被挂载到这个目录),那么新挂载的文件系统将挂载到这个目录最后一次挂载的文件系统的根dentry,之前挂载的文件系统的文件都被隐藏(当子挂载被卸载,原来的文件系统的文件才可见)。
7.2 文件系统的用户可见性
只对内核内部可见:不需要将文件系统关联到一个挂载点,内核通过文件系统的super_block等结构即可访问到文件系统的文件(如bdev,sockfs)。
对于用户可见:需要将文件系统关联到一个挂载点,就需要通过给定的挂载点目录名找到真正的挂载点,然后进行挂载操作, 挂载的实质是:通过mount实例的mnt_mountpoint关联真正的挂载点dentry,然后建立父mount关系,mount实例加入到全局的mount hash table(通过父vfsmount和真正的挂载点dentry作为hash索引),然后用户打开文件的时候通过路径名查找解析各个目录分量,当发现一个目录是挂载点时,就会步进到最后一次挂载到这个目录的文件系统的根dentry中继续查找,知道根dentry就可以继续查找到这个文件系统的任何文件。
7.3 几条重要规律
1)文件系统被挂载后都会有以下几大vfs对象被创建:
super_block mount
根inode
根dentry
注:其中mount为纯软件构造的对象(内嵌vfsmount对象),其他对象视文件系统类型,可能涉及到磁盘操作。
super_block 超级块实例,描述一个文件系统的信息,有的需要磁盘读取在内存中填充来构建(如磁盘文件系统),有的直接内存中填充来构建。
mount 挂载实例,描述一个文件系统的一次挂载,主要关联一个文件系统到挂载点,为路径名查找做重要准备工作。
根inode 每个文件系统都会有根inode,有的需要磁盘读取在内存中填充来构建(如磁盘文件系统,根inode号已知),有的直接内存中填充来构建。
根dentry 每个文件系统都会有根dentry,根据根inode来构建,路径名查找时会步进到文件系统的根dentry来访问这个文件系统的文件。
2)一个目录可以被多个文件系统挂载。第一次挂载是直接挂载这个目录上,新挂载的文件系统实际上是挂载在上一个文件系统的根dentry上。
3)一个目录被多个文件系统挂载时,新挂载导致之前的挂载被隐藏。
4)一个目录被文件系统挂载时,原来目录中包含的其他子目录或文件被隐藏。
5)每次挂载都会有一个mount实例描述本次挂载。
6)一个快设备上的文件系统可以被挂载到多个目录,有多个mount实例,但是只会有一个super_block、根dentry 和根inode。
7)mount实例用于关联挂载点dentry和文件系统,起到路径名查找时“路由”的作用。
8)挂载一个文件系统必须保证所要挂载的文件系统类型已经被注册。
9)挂载时会查询文件系统类型的fs_type->fs_supers链表,检查是否已经有super_block被加入链表,如果没有才会分配并读磁盘超级块填充。
10)对象层次:一个fs_type->fs_supers链表可以挂接属于同一个文件系统的被挂载的超级块,超级块链表可以挂接属于同一个超级块的mount实例 fs_type -> super_block -> mount 从高到低的包含层次。
本文关键词:建筑里h是什么意思,建筑里面h是什么意思,建筑H表示什么,建筑hn表示什么,hn是什么意思。这就是关于《xyn是什么意思,建筑h代表什么意思(建筑H表示什么)》的所有内容,希望对您能有所帮助!
- 最近发表