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 5. IPC Namespace 详解

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

  2. linux服务器怎么查看cpu配置信息,linux服务器cpu信息查看详解

    在linux系统中,提供了/proc目录下文件,显示系统的软硬件信息.如果想了解系统中CPU的提供商和相关配置信息,则可以查/proc/cpuinfo.但是此文件输出项较多,不易理解.例如我们想获取, ...

  3. Linux文件系统的目录结构详解(转)

    Linux文件系统的目录结构详解(转) 原文链接https://www.cnblogs.com/cyjaysun/p/4462325.html 一.前 言 文章对Linux下所有目录一一说明,对比较重 ...

  4. LINUX经常使用的命令详解

    LINUX经常使用的命令详解 源地址:http://blog.itpub.net/29065182/viewspace-1189162/ 1.man 对你熟悉或不熟悉的命令提供帮助解释  eg:man ...

  5. Linux初始化内存盘黑屏,详解linux内存磁盘初始化技术.doc

    详解linux内存磁盘初始化技术 详解linux内存磁盘初始化技术 /5502266.html 关键词: HYPERLINK "/tag/initrd" \n _blankinit ...

  6. Ubuntu (Linux) 系统 find 命令详解

    Ubuntu (Linux) 系统 find 命令详解 在Ubuntu (Linux)系统的终端上,虽然没有像 windows 上那样简介易用的图形界面 搜索工具,但只要你使用足够熟练, 有一个强大命 ...

  7. linux内核管道pipe实现详解

    linux内核管道pipe实现详解 (文件系统暂时不是很了解,文件系统部分暂时不做解释,此文仅解释关键流程,系统调用部分请参考前面已经发布的文章,这里不做展开) 1.管道系统调用(SyS_pipe) ...

  8. linux find 命令通配符,linux find命令查找文件详解

    首页 > Linux教程 > 常用命令 > find 查找文件 linux find命令查找文件详解 linux中find命令用来在指定目录下查找文件,如果使用该命令时,不设置任何参 ...

  9. 【linux】Valgrind工具集详解(八):Memcheck命令行参数详解

    [linux]Valgrind工具集详解(五):命令行详解中不够全,在此专门针对Memcheck工具中的命令行参数做一次详细的解释. Memcheck命令行选项 –leak-check=<no| ...

最新文章

  1. Hadoop数据收集与入库系统Flume与Sqoop
  2. Scala学习笔记-5
  3. BCH实用场景增加,Bitwage推出BCH工资单
  4. 点云的无序性_PU-Net:解决3D点云数据的上采样问题
  5. anki怎么设置学习计划_打篮球怎么训练弹跳力?NBA经典训练计划值得学习
  6. 大话中文文本分类之Transformers
  7. 网络编程相关概念学习笔记
  8. C# DirectX 开发2 - 定义一个矩阵和赋值
  9. hdu_1861_游船出租_201402282130
  10. php 对象赋值后改变成员变量影响赋值对象
  11. 线性条件随机场代码解读
  12. 【API进阶之路6】一个技术盲点,差点让整个项目翻车
  13. linux中存放着内核和引导程序的是,Linux操作系统 考试题库
  14. 停掉暴风影音stormliv.exe进程
  15. apk 反编译 - 最新版图文教程
  16. keil5代码可以下载但无法进行串口通信
  17. mac过热_如何阻止Mac过热
  18. 关于数据埋点的认识以及在流量分析系统中的实际使用
  19. python图片中文汉字标注乱码,变成方框
  20. 解决org.apache.zookeeper.KeeperException$UnimplementedException:KeeperErrorCode = Unimplemented for /S

热门文章

  1. u盘数据乱码怎么恢复?恢复U盘,图文教程在这里
  2. 企业邮箱邮件如何备份?公司邮件如何转发?
  3. 自助建站有什么优势?什么是自助建站
  4. Leetcode 第121,122,136,141,144,145,155,160,167,168题(Java解法)
  5. JAVA PDF文件下载
  6. android 国密签名,关于国密 (sm2,sm3,sm4)在Linux、python、Android、java、ios中的...
  7. 离职后,想去原来的公司上班怎么办?
  8. typeorm-统计数据,格式化时间
  9. 特斯拉向更多车主开放FSD测试,并推出安全评分系统,马斯克终于兑现承诺了吗?
  10. matlab范德瓦尔斯,范德瓦尔斯等温线的计算机描绘