1. 文件系统层次化

对 Linux 系统来说一切皆文件,Linux 使用树形的层次化结构来管理所有的文件对象。

完整的Linux文件系统,是由多种设备、多种文件系统组成的一个混合的树形结构。我们首先从一个单独的块设备来分析其树形结构的构造。

1.1 块设备的层次化(superblock/inode/dentry)

对一个块设备来说要想构造文件系统树形结构,最重要的两个全局因素是:块设备(block_device)和文件系统(file_system_type)。内核使用了一个数据结构 struct super_block 把这两者结合起来,用来标识一个块设备。

确定了 super_block 以后,就可以使用文件系统提供的方法来解析块设备的内容,形成一个块设备内部的树形结构,也就是我们熟悉的文件夹、文件的层次结构。

系统使用 struct inode 结构来标识块设备内部的一个文件夹或者文件,struct inode 结构中最重要的成员是 ->i_ino 这个记录了 inode 在块设备中的偏移。

系统为了辅助 struct inode 的使用还设计了一个 struct dentry 结构,通常情况下一个 struct dentry 对应一个 struct inode,也有少数情况下多个 struct dentry 对应一个 struct inode(如硬链接)。struct dentry 中 cache 了更多的文件信息,类如文件名、层次结构,成员 ->d_parent 指向同一块设备内的父节点 struct dentry ,成员 ->d_subdirs 链接了所有的子节点 struct dentry

1.2 多设备的层次化(mount/vfsmount)

上一节描述了单个块设备构建树形文件系统的方式,如果是多个设备怎么样组成一颗更复杂的树呢?

Linux使用父子树的形式来构造,父设备树中的一个文件夹 struct dentry 可以充当子设备树的挂载点 mountpoint

  • mount/vfsmount

为了组成复杂的父子树,系统定义了一个 struct mount 结构来负责对一个设备内子树的引用。

  • mount tree

可以看到通过一个 struct mount 结构负责引用一颗子设备树,把这颗子设备树挂载到父设备树的其中一个 dentry 节点上。

如果 dentry 成为了挂载点 mountpoint,会给其标识成 DCACHE_MOUNTED。我们在查找路径的时候同样会判断 dentryDCACHE_MOUNTED 标志,一旦置位就变成了 mountpoint,挂载点文件夹下原有的内容就不能访问了,转而访问子设备树根节点下的内容。

struct mount 结构之间也构成了树形结构。

我们通常使用 mount -t fstpye devname pathname 命令来进行挂载子设备的操作。Linux 拥有非常灵活的挂载规则:

规则1、一个设备可以被挂载多次:

可以看到同一个子设备树,同时被两个 struct mount 结构所引用,被挂载到父设备树的两处不同的 dentry 处。

特别说明:虽然子设备树被挂载两次并且通过两处路径都能访问,但子设备的 dentryinode 只保持一份。

规则2、一个挂载点可以挂载多个设备:

还可以对父设备树的同一个文件夹 dentry 进行多次挂载,最后路径查找时生效的是最后一次挂载的子设备树。

  • path

因为linux提供的灵活的挂载规则,所以我们如果要标识一个路径 struct path 的话需要两个元素:vfsmountdentry

可以看到两个路径 struct path 最后引用到了同一 inode,但是路径 path 是不一样的,因为 path 指向的 vfsmount 是不一样的。

  • chroot

Linux 还支持每个进程拥有不同的根目录,使用 chroot() 系统调用可以把当前进程的根目录设置为整棵文件系统树中的任何 path

1.3 多名空间的层次化(mnt_namespace)

之前的系统中只有一棵mount树,为了支持mnt_namespace,系统把mount树叶扩展成了多棵。每个mnt_namespace拥有一棵独立的mount树:

2. 关键代码

2.1 mount()

mount() 系统调用是理解文件系统层次化的核心,它主要包含3个关键步骤:

1、解析 mount() 系统调用中的参数挂载点路径 pathname ,返回对应的 struct path 结构:

SYSCALL_DEFINE5(mount) → do_mount() → user_path() → user_path_at_empty() → filename_lookup() → path_lookupat() → link_path_walk() → walk_component() → follow_managed()

2、解析 mount() 系统调用中的参数文件系统类型 -t type 和设备路径 devname ,建立起子设备的树形结构(如果之前已经创建过引用即可),建立起新的 struct mount 结构对其引用:

SYSCALL_DEFINE5(mount) → do_mount() → do_new_mount() → vfs_kern_mount() → mount_fs() → type->mount()

3、将新建立的 struct mount 结构挂载到查找到的 struct path 结构上:

SYSCALL_DEFINE5(mount) → do_mount() → do_new_mount() → do_add_mount() → graft_tree() → attach_recursive_mnt() → commit_tree()

2.2 chroot()

更改当前进程的根目录:

SYSCALL_DEFINE1(chroot, const char __user *, filename)
{
struct path path;
int error;
unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
retry:
/* (1) 解析指定的路径,返回对应的`struct path`结构 */
error = user_path_at(AT_FDCWD, filename, lookup_flags, &path);
if (error)
goto out; error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
if (error)
goto dput_and_out; error = -EPERM;
if (!ns_capable(current_user_ns(), CAP_SYS_CHROOT))
goto dput_and_out;
error = security_path_chroot(&path);
if (error)
goto dput_and_out; /* (2) 把`struct path`结构设置为当前进程的根目录 */
set_fs_root(current->fs, &path);
error = 0;
dput_and_out:
path_put(&path);
if (retry_estale(error, lookup_flags)) {
lookup_flags |= LOOKUP_REVAL;
goto retry;
}
out:
return error;
} ↓ void set_fs_root(struct fs_struct *fs, const struct path *path)
{
struct path old_root; path_get(path);
spin_lock(&fs->lock);
write_seqcount_begin(&fs->seq);
old_root = fs->root;
/* (2.1) 替换新的根目录 */
fs->root = *path;
write_seqcount_end(&fs->seq);
spin_unlock(&fs->lock);
if (old_root.dentry)
path_put(&old_root);
}

2.3 copy_mnt_ns()

在进程创建或者 unshare()/setns() 系统调用时,如果设置了 CLONE_NEWNS 标志会调用 copy_mnt_ns() 创建一个新的 mnt namespace。其中的核心是创建一颗新的 struct mount 树,首先把旧的 struct mount 树复制过来:

SYSCALL_DEFINE1(unshare) → unshare_nsproxy_namespaces() → create_new_namespaces() → copy_mnt_ns() → copy_tree() → clone_mnt()

随后如果有新的 mount() 动作,两棵树的内容就会不同。

参考文档:

1.Linux Namespace
2.Linux文件系统
3.在CentOS7上使用LXC管理容器
4.docker基础:从chroot理解namespace的隔离
5.Docker基础: Linux内核命名空间之(1)mnt namespace
6.Docker基础:文件系统之AUFS
7.docker image是什么,存储在什么位置
8.Docker镜像存储-overlayfs
9.linux文件系统之mount流程分析
10.dentry和inode的关系

Linux ns 3. Mnt Namespace 详解的更多相关文章

  1. Linux ns 4. UTS Namespace 详解

    目录 1. 使用简介 1.1 hostname 1.2 domainname 1.3 uname 2. 代码分析 2.1 copy_utsname() 2.2 sethostname() 2.3 ge ...

  2. Linux ns 6. Network Namespace 详解

    文章目录 1. 简介 1.1 Docker Network 桥接模式配置 2. 代码解析 2.1 copy_net_ns() 2.2 pernet_list 2.2.1 loopback_net_op ...

  3. Linux ns 5. IPC Namespace 详解

    文章目录 1. 简介 2. 源码分析 2.1 copy_ipcs() 2.2 ipcget() 2.3 ipc_check_perms() 2.4 相关系统调用 参考文档: 1. 简介 进程间通讯的机 ...

  4. Linux下的文件目录结构详解

    Linux下的文件目录结构详解 / Linux文件系统的上层根目录 /bin 存放用户可执行的程序 /boot 操作系统启动时所需要的文件 /dev 接口设备文件目录,例如:had表示硬盘 /etc ...

  5. Linux文件系统的目录结构详解

    Linux文件系统的目录结构详解   一.前 言 文章对Linux下所有目录一一说明,对比较重要的目录加以重点解说,以帮助初学者熟练掌握Linux的目录结构. 二.目 录 1.什么是文件系统 2.文件 ...

  6. Linux文件权限与属性详解 之 ACL

    Linux文件权限与属性详解 之 一般权限 Linux文件权限与属性详解 之 ACL Linux文件权限与属性详解 之 SUID.SGID & SBIT Linux文件权限与属性详解 之 ch ...

  7. Linux下DNS服务器搭建详解

    Linux下DNS服务器搭建详解 DNS  即Domain Name System(域名系统)的缩写,它是一种将ip地址转换成对应的主机名或将主机名转换成与之相对应ip地址的一种机制.其中通过域名解析 ...

  8. Linux自带神器logrotate详解

    Linux自带神器logrotate详解 散尽浮华 运维 3天前   作者:散尽浮华 链接:https://www.cnblogs.com/kevingrace/p/6307298.html 对于 L ...

  9. Linux上的free命令详解、swap机制

    Linux上的free命令详解   解释一下Linux上free命令的输出. 下面是free的运行结果,一共有4行.为了方便说明,我加上了列号.这样可以把free的输出看成一个二维数组FO(Free ...

随机推荐

  1. Python自动化测试发送邮件太麻烦?!一起聊一聊 Python 发送邮件的3种方式

    1. 前言 发送邮件,我们在平时工作中经用到,做为测试人员,在自动化测试中用的也比较多,需要发送邮件给某领导 SMTP是Python默认的邮件模块,可以发送纯文本.富文本.HTML 等格式的邮件 今天 ...

  2. Vue插槽slot理解与初体验 ~

    一.插槽的理解 1.官网介绍 Vue 实现了一套内容分发的 API,将 <slot> 元素作为承载分发内容的出口. 2.为什么使用插槽 Vue 中有一个重要的概念-组件,可以在开发中将子组 ...

  3. Unity——FSM有限状态机

    FSM有限状态机 一.设计思路 1.共同的状态父类,提供可重写的进入,保持,退出该状态的生命周期方法: 2.状态机,管理所有状态(增删查改),状态机运行方法(Run): 3.在角色控制器中,实例化状态 ...

  4. Spatial Analyst 工具-数学分析

    数学分析 # Process: Abs arcpy.gp.Abs_sa("", 输出栅格) # Process: Exp arcpy.gp.Exp_sa("", ...

  5. css3新增属性-background背景

    css3新增属性 边框属性 背景属性 文字属性 颜色属性 背景属性 属性 说明 background-image 添加背景图片 background-size 指定背景图像的大小 background ...

  6. Linux命令查看内存、整体负载、端口查看、进程查看、vim编辑器(3)

    一.资源占用命令   1.查看内存(free) free命令默认是以kb为单位显示的. free -m用Mb单位来显示. free -h显示单位 . free -h -s 3 ,每隔三秒刷新一次,如果 ...

  7. 电脑日常使用bug记录

    1.由于电脑太卡了,于是决定关一点服务,一不小心,电脑无线无法使用了.启动无线服务时提示"windows无法启动wlan autoconfig服务错误1068依赖服务" 启动 Ex ...

  8. 【UE4 设计模式】享元模式 Flyweight Pattern

    概述 描述 运用共享技术有效地支持大量细粒度对象的复用.系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用. 由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻 ...

  9. 简明教程 | Docker篇 · 其一:基础入门

    了解Docker Docker是什么 Docker是指容器化技术,用于支持创建和使用 Linux 容器,同时Docker也是软件容器平台. 什么是容器(container) 容器是主机上与其他进程隔离 ...

  10. 2021.10.27考试总结[冲刺NOIP模拟17]

    T1 宝藏 发现每个数成为中位数的长度是关于权值单调的.线段树二分判断是否合法,单调指针扫即可. 考场上写了二分,平添\(\log\). \(code:\) T1 #include<bits/s ...