1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > Linux系统的各个mount点以及文件系统挂载分析

Linux系统的各个mount点以及文件系统挂载分析

时间:2022-05-16 04:24:37

相关推荐

Linux系统的各个mount点以及文件系统挂载分析

分析代码,内核的do_sys_open加入检查点,过滤进程touch的目的是,这样可以简单的在用户态通过touch命令创建文件的方式触发进入此分支。

caozilong@caozilong-Vostro-3268:~/Workspace/linux-compile/linux-5.4.129$ git diffdiff --git a/fs/open.c b/fs/open.cindex dcbd01611..f23170ddb 100644--- a/fs/open.c+++ b/fs/open.c@@ -1081,6 +1081,10 @@ long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)struct open_flags op;int fd = build_open_flags(flags, mode, &op);struct filename *tmp;+ char buf[TASK_COMM_LEN];++ memset(buf, 0x00, TASK_COMM_LEN);+ get_task_comm(buf, current);if (fd)return fd;@@ -1098,6 +1102,28 @@ long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)} else {fsnotify_open(f);fd_install(fd, f);+ if(strcmp(buf, "touch") == 0)+ {+ struct path path;+ struct vfsmount *mnt;+ char *name1, *name2;+ char buf[64];+ char buf1[128];++ memset(buf, 0, sizeof(buf));+ memset(buf1, 0, sizeof(buf1));++ mnt = f->f_path.mnt;+ path.mnt = mnt;+ path.dentry = mnt->mnt_root;+ name1 = d_path(&path, buf, sizeof(buf));+ name2 = file_path(f, buf1, sizeof(buf1));+ if(mnt && strstr(name2, ".txt"))+ {+ printk("%s line %d, fstype = %s,mount-root=%s, mountpoint=%s, filepath=%s, vfsmount=0x%p.\n", \+__func__, __LINE__, mnt->mnt_sb->s_type->name, mnt->mnt_root->d_name.name, name1, name2, mnt);+ }+ }}}putname(tmp);

df命令查看文件系统挂载情况

caozilong@caozilong-Vostro-3268:~/Workspace/linux-compile/linux-5.4.129$ df文件系统 1K-块已用可用 已用% 挂载点udev 3804456 0 3804456 0% /devtmpfs 8058642044 803820 1% /run/dev/sda7150140200 95560684 46883152 68% /tmpfs 4029312 0 4029312 0% /dev/shmtmpfs5120 45116 1% /run/locktmpfs 4029312 0 4029312 0% /sys/fs/cgroup/dev/loop0 56832 56832 0 100% /snap/core18/2074/dev/loop225602560 0 100% /snap/gnome-calculator/884/dev/loop4 66688 66688 0 100% /snap/gtk-common-themes/1515/dev/loop310241024 0 100% /snap/gnome-logs/81/dev/loop5 384384 0 100% /snap/gnome-characters/708/dev/loop6 640640 0 100% /snap/gnome-logs/103/dev/loop7 768768 0 100% /snap/gnome-characters/723/dev/loop8 101760 101760 0 100% /snap/core/11316/dev/loop1 249856 249856 0 100% /snap/gnome-3-38-/39/dev/loop9 46080 46080 0 100% /snap/gtk-common-themes/1440/dev/loop10 224256 224256 0 100% /snap/gnome-3-34-1804/72/dev/loop11 43524352 0 100% /snap/gnome-calculator/544/dev/loop12 164096 164096 0 100% /snap/gnome-3-28-1804/116/dev/loop13 166784 166784 0 100% /snap/gnome-3-28-1804/145/dev/loop15 25602560 0 100% /snap/gnome-system-monitor/160/dev/loop14 63232 63232 0 100% /snap/core20/1026/dev/loop16 56064 56064 0 100% /snap/core18/1668/dev/loop17 91264 91264 0 100% /snap/core/8268/dev/loop18 23042304 0 100% /snap/gnome-system-monitor/157/dev/sdb2 3871400 605860 3049172 17% /boot/dev/sda297280 32433 64847 34% /boot/efitmpfs 805860 16 805844 1% /run/user/121tmpfs 805860 36 805824 1% /run/user/1000

创建脚本,分别在上述路径下创建一个.txt后缀名的文件

touch /dev/zilong.txttouch /run/zilong.txttouch /zilong.txttouch /dev/shm/zilong.txttouch /run/lock/zilong.txttouch /sys/fs/cgroup/zilong.txttouch /snap/core18/2074/zilong.txttouch /snap/gnome-calculator/884/zilong.txttouch /snap/gtk-common-themes/1515/zilong.txttouch /snap/gnome-logs/81/zilong.txttouch /snap/gnome-characters/708/zilong.txttouch /snap/gnome-logs/103/zilong.txttouch /snap/gnome-characters/723/zilong.txttouch /snap/core/11316/zilong.txttouch /snap/gnome-3-38-/39/zilong.txttouch /snap/gtk-common-themes/1440/zilong.txttouch /snap/gnome-3-34-1804/72/zilong.txttouch /snap/gnome-calculator/544/zilong.txttouch /snap/gnome-3-28-1804/116/zilong.txttouch /snap/gnome-3-28-1804/145/zilong.txttouch /snap/gnome-system-monitor/160/zilong.txttouch /snap/core20/1026/zilong.txttouch /snap/core18/1668/zilong.txttouch /snap/core/8268/zilong.txttouch /snap/gnome-system-monitor/157/zilong.txttouch /boot/zilong.txttouch /boot/efi/zilong.txttouch /run/user/121/zilong.txttouch /run/user/1000/zilong.txttouch /tmp/zilong.txt

执行sudo bash ./a.sh, 可以看到有些文件无法写入,所以touch写的方式调试失效了,不过没关系,先看其它几个文件系统。

caozilong@caozilong-Vostro-3268:~/Workspace/linux-compile/opentest$ sudo bash ./a.shtouch: 无法创建'/sys/fs/cgroup/zilong.txt': 只读文件系统touch: 无法创建'/snap/core18/2074/zilong.txt': 只读文件系统touch: 无法创建'/snap/gnome-calculator/884/zilong.txt': 只读文件系统touch: 无法创建'/snap/gtk-common-themes/1515/zilong.txt': 只读文件系统touch: 无法创建'/snap/gnome-logs/81/zilong.txt': 只读文件系统touch: 无法创建'/snap/gnome-characters/708/zilong.txt': 只读文件系统touch: 无法创建'/snap/gnome-logs/103/zilong.txt': 只读文件系统touch: 无法创建'/snap/gnome-characters/723/zilong.txt': 只读文件系统touch: 无法创建'/snap/core/11316/zilong.txt': 只读文件系统touch: 无法创建'/snap/gnome-3-38-/39/zilong.txt': 只读文件系统touch: 无法创建'/snap/gtk-common-themes/1440/zilong.txt': 只读文件系统touch: 无法创建'/snap/gnome-3-34-1804/72/zilong.txt': 只读文件系统touch: 无法创建'/snap/gnome-calculator/544/zilong.txt': 只读文件系统touch: 无法创建'/snap/gnome-3-28-1804/116/zilong.txt': 只读文件系统touch: 无法创建'/snap/gnome-3-28-1804/145/zilong.txt': 只读文件系统touch: 无法创建'/snap/gnome-system-monitor/160/zilong.txt': 只读文件系统touch: 无法创建'/snap/core20/1026/zilong.txt': 只读文件系统touch: 无法创建'/snap/core18/1668/zilong.txt': 只读文件系统touch: 无法创建'/snap/core/8268/zilong.txt': 只读文件系统touch: 无法创建'/snap/gnome-system-monitor/157/zilong.txt': 只读文件系统caozilong@caozilong-Vostro-3268:~/Workspace/linux-compile/opentest$

dmesg查看内核打印输出

[ 444.029396] do_sys_open line 1124, fstype = devtmpfs,mount-root=/, mountpoint=/dev, filepath=/dev/zilong.txt, vfsmount=0x0000000094f582a3.[ 444.029897] do_sys_open line 1124, fstype = tmpfs,mount-root=/, mountpoint=/run, filepath=/run/zilong.txt, vfsmount=0x000000006412958f.[ 444.030829] do_sys_open line 1124, fstype = ext4,mount-root=/, mountpoint=/, filepath=/zilong.txt, vfsmount=0x0000000068fd3026.[ 444.031419] do_sys_open line 1124, fstype = tmpfs,mount-root=/, mountpoint=/dev/shm, filepath=/dev/shm/zilong.txt, vfsmount=0x000000000e2b123f.[ 444.031970] do_sys_open line 1124, fstype = tmpfs,mount-root=/, mountpoint=/run/lock, filepath=/run/lock/zilong.txt, vfsmount=0x000000007d4d921d.[ 444.048815] do_sys_open line 1124, fstype = ext4,mount-root=/, mountpoint=/boot, filepath=/boot/zilong.txt, vfsmount=0x000000003c744766.[ 444.049554] do_sys_open line 1124, fstype = vfat,mount-root=/, mountpoint=/boot/efi, filepath=/boot/efi/zilong.txt, vfsmount=0x0000000034dc4c99.[ 444.050638] do_sys_open line 1124, fstype = tmpfs,mount-root=/, mountpoint=/run/user/121, filepath=/run/user/121/zilong.txt, vfsmount=0x000000004e8529a4.[ 444.051385] do_sys_open line 1124, fstype = tmpfs,mount-root=/, mountpoint=/run/user/1000, filepath=/run/user/1000/zilong.txt, vfsmount=0x00000000799dbb6f.[ 444.052149] do_sys_open line 1124, fstype = ext4,mount-root=/, mountpoint=/, filepath=/tmp/zilong.txt, vfsmount=0x0000000068fd3026.

可以看到,系统中的挂载点有 /dev, /run, /, /dev/shm, /run/lock, /boot,/boot/efi, /run/user/121, /run/user/1000,图示表示如下:

让人感到意外的是/tmp文件系统这里没有新的挂载点,仅仅是/根文件系统的一个普通目录而已,之前一直认为/tmp文件系统是一个内存文件系统的挂载点的。

简单分析一下vfsmount结构:

对于某个文件系统实例,内存中 super_block 和 vfsmount 都是唯一的。比如,我们将某个挂载硬盘分区 mount -t vfat /dev/hda2 /mnt/d。实际上就是新建一个 vfsmount 结构作为连接件,vfsmount->mnt_sb = /dev/hda2 的超级块结构;vfsmount->mnt_root =/dev/hda2 的"根"目录的 dentry。

修改pattern,增加对mnt->mnt_root->d_parent和mnt->mnt_root的打印输出,观察它们是不是同一个

caozilong@caozilong-Vostro-3268:~/Workspace/linux-compile/linux-5.4.129$ git diffdiff --git a/fs/open.c b/fs/open.cindex dcbd01611..2cafc865d 100644--- a/fs/open.c+++ b/fs/open.c@@ -1081,6 +1081,10 @@ long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)struct open_flags op;int fd = build_open_flags(flags, mode, &op);struct filename *tmp;+ char buf[TASK_COMM_LEN];++ memset(buf, 0x00, TASK_COMM_LEN);+ get_task_comm(buf, current);if (fd)return fd;@@ -1098,6 +1102,30 @@ long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)} else {fsnotify_open(f);fd_install(fd, f);+ if(strcmp(buf, "touch") == 0)+ {+ struct path path;+ struct dentry *parent;+ struct vfsmount *mnt;+ char *name1, *name2;+ char buf[64];+ char buf1[128];++ memset(buf, 0, sizeof(buf));+ memset(buf1, 0, sizeof(buf1));++ mnt = f->f_path.mnt;+ path.mnt = mnt;+ path.dentry = mnt->mnt_root;+ parent = mnt->mnt_root->d_parent;+ name1 = d_path(&path, buf, sizeof(buf));+ name2 = file_path(f, buf1, sizeof(buf1));+ if(mnt && strstr(name2, ".txt"))+ {+ printk("%s line %d, fstype = %s,mount-root=%s, mountpoint=%s, filepath=%s, vfsmount=0x%p, parent=%s.parent=0x%p, mnt->mnt_root=0x%p\n", \+__func__, __LINE__, mnt->mnt_sb->s_type->name, mnt->mnt_root->d_name.name, name1, name2, mnt, parent->d_name.name, parent, mnt->mnt_root);+ }+ }}}putname(tmp);caozilong@caozilong-Vostro-3268:~/Workspace/linux-compile/linux-5.4.129$

执行sudo touch /tmp/zilong.txt后,查看dmesg. 根据输出结果,可以看出它们确实是相同的

这说明在挂载点构造的vfsmount结构并没有指向父文件系统的dentry结构,那么疑问就产生了,系统是如何找到挂载点的父文件系统的dentry结构的呢?

揭开文件系统根目录背后的“影子”的真面目

diff --git a/fs/open.c b/fs/open.cindex dcbd01611..43bb0a09a 100644--- a/fs/open.c+++ b/fs/open.c@@ -32,8 +32,8 @@#include <linux/ima.h>#include <linux/dnotify.h>#include <linux/compat.h>-#include "internal.h"+#include "mount.h"int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,struct file *filp)@@ -1081,6 +1081,10 @@ long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)struct open_flags op;int fd = build_open_flags(flags, mode, &op);struct filename *tmp;+char buf[TASK_COMM_LEN];++memset(buf, 0x00, TASK_COMM_LEN);+get_task_comm(buf, current);if (fd)return fd;@@ -1098,6 +1102,35 @@ long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)} else {fsnotify_open(f);fd_install(fd, f);+if(strcmp(buf, "touch") == 0)+{+struct path path;+struct dentry *parent;+struct vfsmount *mnt;+struct mount *realmnt;+struct mount *mnt_parent;+char *name1, *name2;+char buf[64];+char buf1[128];++memset(buf, 0, sizeof(buf));+memset(buf1, 0, sizeof(buf1));++mnt = f->f_path.mnt;+path.mnt = mnt;+path.dentry = mnt->mnt_root;+parent = mnt->mnt_root->d_parent;+name1 = d_path(&path, buf, sizeof(buf));+name2 = file_path(f, buf1, sizeof(buf1));+//realmnt = container_of(mnt, struct mount, mnt);+realmnt = real_mount(mnt);+mnt_parent = realmnt->mnt_parent;+if(mnt && strstr(name2, ".txt"))+{+printk("%s line %d, fstype = %s,mount-root=%s, mountpoint=%s, filepath=%s, vfsmount=0x%p, parent=%s.parent=0x%p, mnt->mnt_root=0x%p, realmnt->mnt_mountpoint=0x%p,mnt_parent->d_name.name=%s, mnt_parent->mnt_mountpoint->d_name.name=%s.mnt_parent->mnt_mountpoint=0x%p,mnt_parent->mnt.mnt_sb->s_type->name=%s.\n", \+__func__, __LINE__, mnt->mnt_sb->s_type->name, mnt->mnt_root->d_name.name, name1, name2, mnt, parent->d_name.name, parent, mnt->mnt_root, realmnt->mnt_mountpoint, mnt_parent->mnt.mnt_root->d_name.name,mnt_parent->mnt_mountpoint->d_name.name, mnt_parent->mnt_mountpoint, mnt_parent->mnt.mnt_sb->s_type->name);+}+}}}putname(tmp);

执行sudo touch /tmp/zilong.txt, dmesg后:

可以看到vfsmount内嵌于struct mount结构中,根据struct mount可以找到挂载树结构

由于tmp隶属于"/"文件系统,所以我们直接找到了"/" dentry. 但是令人意外的是,"/"的 mount parent不为空,并且根据strucdt mount找到的这个"\"背后的文件系统竟然是rootfs! 这里有一个问题,假设现在的根文件系统对应块设备/dev/sda1, 那么mount -t ext4 /dev/sda1 时,/目录还不存在,那么dev和sda1又从何来呢?内核在启动时mount一个临时的根目录,这个临时的根目录的文件系统类别就是rootfs,它不对应任何磁盘文件,也就是它属于一个内存文件系统。rootfs在ubuntu 系统中同样存在,可以通过cat /proc/filesystems查看.

sudo touch /dev/zilong.txt 的输出为

diff --git a/fs/open.c b/fs/open.cindex dcbd01611..a0c79fe60 100644--- a/fs/open.c+++ b/fs/open.c@@ -32,8 +32,8 @@#include <linux/ima.h>#include <linux/dnotify.h>#include <linux/compat.h>-#include "internal.h"+#include "mount.h"int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,struct file *filp)@@ -1081,6 +1081,10 @@ long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)struct open_flags op;int fd = build_open_flags(flags, mode, &op);struct filename *tmp;+char buf[TASK_COMM_LEN];++memset(buf, 0x00, TASK_COMM_LEN);+get_task_comm(buf, current);if (fd)return fd;@@ -1098,6 +1102,35 @@ long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)} else {fsnotify_open(f);fd_install(fd, f);+if(strcmp(buf, "touch") == 0)+{+struct path path;+struct dentry *parent;+struct vfsmount *mnt;+struct mount *realmnt;+struct mount *mnt_parent;+char *name1, *name2;+char buf[64];+char buf1[128];++memset(buf, 0, sizeof(buf));+memset(buf1, 0, sizeof(buf1));++mnt = f->f_path.mnt;+path.mnt = mnt;+path.dentry = mnt->mnt_root;+parent = mnt->mnt_root->d_parent;+name1 = d_path(&path, buf, sizeof(buf));+name2 = file_path(f, buf1, sizeof(buf1));+//realmnt = container_of(mnt, struct mount, mnt);+realmnt = real_mount(mnt);+mnt_parent = realmnt->mnt_parent;+if(mnt && strstr(name2, ".txt"))+{+printk("%s line %d, fstype = %s,mount-root=%s, mountpoint=%s, filepath=%s, vfsmount=0x%p, parent=%s.parent=0x%p, mnt->mnt_root=0x%p, realmnt->mnt_mountpoint=0x%p,mnt_parent->d_name.name=%s, mnt_parent->mnt_mountpoint->d_name.name=%s.mnt_parent->mnt_mountpoint=0x%p,mnt_parent->mnt.mnt_sb->s_type->name=%s realmnt->mnt_mountpoint->d_name.name=%s.\n", \+__func__, __LINE__, mnt->mnt_sb->s_type->name, mnt->mnt_root->d_name.name, name1, name2, mnt, parent->d_name.name, parent, mnt->mnt_root, realmnt->mnt_mountpoint, mnt_parent->mnt.mnt_root->d_name.name,mnt_parent->mnt_mountpoint->d_name.name, mnt_parent->mnt_mountpoint, mnt_parent->mnt.mnt_sb->s_type->name, realmnt->mnt_mountpoint->d_name.name);+}+}}}putname(tmp);

[ 34.621278] do_sys_open line 1131, fstype = devtmpfs,mount-root=/, mountpoint=/dev, filepath=/dev/zilong.txt, vfsmount=0x00000000e67b240c, parent=/.parent=0x000000008c557a3d, mnt->mnt_root=0x000000008c557a3d, realmnt->mnt_mountpoint=0x0000000092f6d290,mnt_parent->d_name.name=/, mnt_parent->mnt_mountpoint->d_name.name=/.mnt_parent->mnt_mountpoint=0x0000000009bdf69c,mnt_parent->mnt.mnt_sb->s_type->name=ext4 realmnt->mnt_mountpoint->d_name.name=dev.

可以看到挂载点的dev目录的dentry.

devtmpfs文件系统:

前面分析我们知道了,/dev目录下挂载的是设备文件系统,它的类型就是devtmpfs.它本质上是一个内存文件系统.

"/"是临时挂载点,最后的挂载点在/dev目录,由下面的流程完成:

devtmpfs的挂载发起是在用户态的启动过程中,以busybox启动为例,在rootfs阶段,将会执行/etc/init.d/rcS脚本,内容中即包括挂在devtmpsf.

mount -t devpts devpts /dev/pts

参考博客

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_vexpress-a9有几个核_papaofdoudou的博客-CSDN博客

vfsmount point

vfs_create_mount之后vfs对象数据结构之间关系图如下:

do_add_mount 之后vfs对象数据结构之间关系图(/mnt之前不是挂载点情况)如下:

mount、super_block、file_system_type三者关系图解

解释: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哈希表,便于后面访问这个挂载点的文件系统时的路径名查找。

父子文件系统挂载关系图解

单个文件系统多挂载点关系图解

多文件系统单挂载点关系图解

如何查看系统MOUNT点

使用mount命令

使用 /proc/self/mountinfo

使用cat /proc/mounts

各类fs类型

debug_fs_type

其它文件系统都是通过struct inode_operations 去创建,删除文件,而debugfs直接暴露创建/删除接口给到用户.

debugfs的读写都通过显示的内核接口:

debugfs_create_dir和__debugfs_create_file

结束!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。