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

本文深入探讨Linux文件系统,分析挂载点如/dev, /tmp, /var, /dev/pts等,重点研究vfsmount结构、rootfs、devtmpfs以及如何查看和理解挂载信息。通过代码分析,揭示了文件系统挂载的内在工作原理,包括mount点的查找、文件系统的类型以及挂载点的完整路径获取。同时,讨论了如何将普通文件挂载为文件系统。" 127336752,14259628,Docker基础操作指南:镜像与容器管理,"['docker', '容器', '镜像管理']
摘要由CSDN通过智能技术生成

Linux文件系统的层次结构:

思考:作为与文件平级的磁盘设备文件与作为文件系统底层的磁盘设备之间有什么区别呢?

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

caozilong@caozilong-Vostro-3268:~/Workspace/linux-compile/linux-5.4.129$ git diff
diff --git a/fs/open.c b/fs/open.c
index 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% /dev
tmpfs             805864     2044   803820    1% /run
/dev/sda7      150140200 95560684 46883152   68% /
tmpfs            4029312        0  4029312    0% /dev/shm
tmpfs               5120        4     5116    1% /run/lock
tmpfs            4029312        0  4029312    0% /sys/fs/cgroup
/dev/loop0         56832    56832        0  100% /snap/core18/2074
/dev/loop2          2560     2560        0  100% /snap/gnome-calculator/884
/dev/loop4         66688    66688        0  100% /snap/gtk-common-themes/1515
/dev/loop3          1024     1024        0  100% /snap/gnome-logs/81
/dev/loop5           384      384        0  100% /snap/gnome-characters/708
/dev/loop6           640      640        0  100% /snap/gnome-logs/103
/dev/loop7           768      768        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-2004/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         4352     4352        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         2560     2560        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         2304     2304        0  100% /snap/gnome-system-monitor/157
/dev/sdb2        3871400   605860  3049172   17% /boot
/dev/sda2          97280    32433    64847   34% /boot/efi
tmpfs             805860       16   805844    1% /run/user/121
tmpfs             805860       36   805824    1% /run/user/1000

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

touch /dev/zilong.txt
touch /run/zilong.txt
touch /zilong.txt
touch /dev/shm/zilong.txt
touch /run/lock/zilong.txt
touch /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-2004/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
touch /boot/zilong.txt
touch /boot/efi/zilong.txt
touch /run/user/121/zilong.txt
touch /run/user/1000/zilong.txt
touch /tmp/zilong.txt

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

caozilong@caozilong-Vostro-3268:~/Workspace/linux-compile/opentest$ sudo bash ./a.sh
touch: 无法创建'/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-2004/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 diff
diff --git a/fs/open.c b/fs/open.c
index 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.c
index 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.c
index 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脚本,内容中即包括挂在devtmpfs.

mount -t devpts devpts /dev/pts

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

papaofdoudou

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值