df 根据文件名找到挂载点原理
一、shell命令查看特定文件挂载点
#根据文件名找到对应的挂载点
rlk@rlk:vfs$ df ./stat.c
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda5 1029518584 18451556 958700644 2% /
#遍历当前系统所有的挂载点相关的信息
rlk@rlk:vfs$ df -h
Filesystem Size Used Avail Use% Mounted on
udev 1.9G 0 1.9G 0% /dev
tmpfs 391M 41M 350M 11% /run
/dev/sda5 982G 18G 915G 2% /
tmpfs 2.0G 0 2.0G 0% /dev/shm
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
tmpfs 2.0G 0 2.0G 0% /sys/fs/cgroup
/dev/loop0 219M 219M 0 100% /snap/gnome-3-34-1804/66
/dev/loop2 56M 56M 0 100% /snap/core18/2074
/dev/loop3 219M 219M 0 100% /snap/gnome-3-34-1804/72
/dev/loop1 56M 56M 0 100% /snap/core18/2128
/dev/loop4 66M 66M 0 100% /snap/gtk-common-themes/1515
/dev/loop5 33M 33M 0 100% /snap/snapd/12883
/dev/loop6 51M 51M 0 100% /snap/snap-store/547
/dev/loop7 33M 33M 0 100% /snap/snapd/12704
/dev/loop8 51M 51M 0 100% /snap/snap-store/542
/dev/sda1 511M 4.0K 511M 1% /boot/efi
tmpfs 391M 32K 391M 1% /run/user/1000
二、原理剖析
先strace查看系统调用,看看有没有什么线索。
rlk@rlk:vfs$ strace df ./stat.c
execve("/usr/bin/df", ["df", "./stat.c"], 0x7ffd63a88918 /* 62 vars */) = 0
brk(NULL) = 0x5638a5c79000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffcd9b3ba80) = -1 EINVAL (Invalid argument)
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=72115, ...}) = 0
mmap(NULL, 72115, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f5917bd2000
close(3) = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\360q\2\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
pread64(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32, 848) = 32
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\t\233\222%\274\260\320\31\331\326\10\204\276X>\263"..., 68, 880) = 68
fstat(3, {st_mode=S_IFREG|0755, st_size=2029224, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5917bd0000
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
pread64(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32, 848) = 32
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\t\233\222%\274\260\320\31\331\326\10\204\276X>\263"..., 68, 880) = 68
mmap(NULL, 2036952, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f59179de000
mprotect(0x7f5917a03000, 1847296, PROT_NONE) = 0
mmap(0x7f5917a03000, 1540096, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x25000) = 0x7f5917a03000
mmap(0x7f5917b7b000, 303104, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x19d000) = 0x7f5917b7b000
mmap(0x7f5917bc6000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7f5917bc6000
mmap(0x7f5917bcc000, 13528, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f5917bcc000
close(3) = 0
arch_prctl(ARCH_SET_FS, 0x7f5917bd1580) = 0
mprotect(0x7f5917bc6000, 12288, PROT_READ) = 0
mprotect(0x5638a5bce000, 4096, PROT_READ) = 0
mprotect(0x7f5917c11000, 4096, PROT_READ) = 0
munmap(0x7f5917bd2000, 72115) = 0
brk(NULL) = 0x5638a5c79000
brk(0x5638a5c9a000) = 0x5638a5c9a000
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=14537584, ...}) = 0
mmap(NULL, 14537584, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f5916c00000
close(3) = 0
openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=2996, ...}) = 0
read(3, "# Locale name alias data base.\n#"..., 4096) = 2996
read(3, "", 4096) = 0
close(3) = 0
openat(AT_FDCWD, "/usr/share/locale/en_US.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/en_US.utf8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/en_US/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/en.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/en.utf8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/en/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale-langpack/en_US.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale-langpack/en_US.utf8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale-langpack/en_US/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale-langpack/en.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale-langpack/en.utf8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale-langpack/en/LC_MESSAGES/coreutils.mo", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=613, ...}) = 0
mmap(NULL, 613, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f5917c10000
close(3) = 0
#这里获取了文件的struct stat相关信息
stat("./stat.c", {st_mode=S_IFREG|0664, st_size=452, ...}) = 0
openat(AT_FDCWD, "./stat.c", O_RDONLY|O_NOCTTY) = 3
close(3) = 0
#这里可以看到df命令打开了/proc/self/mountinfo文件,这个是可以查看所有挂在点的文件
openat(AT_FDCWD, "/proc/self/mountinfo", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
read(3, "24 29 0:22 / /sys rw,nosuid,node"..., 1024) = 1024
read(3, " rw,nosuid,nodev,noexec,relatime"..., 1024) = 1024
read(3, "/fs/cgroup/perf_event rw,nosuid,"..., 1024) = 1024
read(3, "ore18/2074 ro,nodev,relatime sha"..., 1024) = 1024
read(3, "54 29 8:1 / /boot/efi rw,relatim"..., 1024) = 636
read(3, "", 1024) = 0
lseek(3, 0, SEEK_CUR) = 4732
close(3) = 0
getcwd("/home/rlk/Desktop/vfs", 4096) = 22
lstat("/home/rlk/Desktop/vfs/stat.c", {st_mode=S_IFREG|0664, st_size=452, ...}) = 0
stat("/", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
uname({sysname="Linux", nodename="rlk", ...}) = 0
statfs("./stat.c", {f_type=EXT2_SUPER_MAGIC, f_bsize=4096, f_blocks=257379646, f_bfree=252766819, f_bavail=239675223, f_files=65437696, f_ffree=65033177, f_fsid={val=[3296162858, 246115465]}, f_namelen=255, f_frsize=4096, f_flags=ST_VALID|ST_RELATIME}) = 0
openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=27002, ...}) = 0
mmap(NULL, 27002, PROT_READ, MAP_SHARED, 3, 0) = 0x7f5917bdd000
close(3) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}) = 0
write(1, "Filesystem 1K-blocks Us"..., 61Filesystem 1K-blocks Used Available Use% Mounted on
) = 61
write(1, "/dev/sda5 1029518584 184513"..., 52/dev/sda5 1029518584 18451308 958700892 2% /
) = 52
close(1) = 0
close(2) = 0
exit_group(0) = ?
+++ exited with 0 +++
三、/proc/self/mountinfo和struct stat
关于mountinfo各个字段信息解释
rlk@rlk:vfs$ cat /proc/self/mountinfo
24 29 0:22 / /sys rw,nosuid,nodev,noexec,relatime shared:7 - sysfs sysfs rw
25 29 0:5 / /proc rw,nosuid,nodev,noexec,relatime shared:14 - proc proc rw
26 29 0:6 / /dev rw,nosuid,noexec,relatime shared:2 - devtmpfs udev rw,size=1973000k,nr_inodes=493250,mode=755
27 26 0:23 / /dev/pts rw,nosuid,noexec,relatime shared:3 - devpts devpts rw,gid=5,mode=620,ptmxmode=000
28 29 0:24 / /run rw,nosuid,nodev,noexec,relatime shared:5 - tmpfs tmpfs rw,size=400228k,mode=755
29 1 8:5 / / rw,relatime shared:1 - ext4 /dev/sda5 rw,errors=remount-ro
30 24 0:7 / /sys/kernel/security rw,nosuid,nodev,noexec,relatime shared:8 - securityfs securityfs rw
31 26 0:25 / /dev/shm rw,nosuid,nodev shared:4 - tmpfs tmpfs rw
32 28 0:26 / /run/lock rw,nosuid,nodev,noexec,relatime shared:6 - tmpfs tmpfs rw,size=5120k
33 24 0:27 / /sys/fs/cgroup ro,nosuid,nodev,noexec shared:9 - tmpfs tmpfs ro,mode=755
34 33 0:28 / /sys/fs/cgroup/unified rw,nosuid,nodev,noexec,relatime shared:10 - cgroup2 cgroup2 rw,nsdelegate
35 33 0:29 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime shared:11 - cgroup cgroup rw,xattr,name=systemd
36 24 0:30 / /sys/fs/pstore rw,nosuid,nodev,noexec,relatime shared:12 - pstore pstore rw
37 24 0:31 / /sys/fs/bpf rw,nosuid,nodev,noexec,relatime shared:13 - bpf none rw,mode=700
38 33 0:32 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime shared:15 - cgroup cgroup rw,blkio
39 33 0:33 / /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,cpu,cpuacct
40 33 0:34 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:17 - cgroup cgroup rw,memory
41 33 0:35 / /sys/fs/cgroup/net_cls,net_prio rw,nosuid,nodev,noexec,relatime shared:18 - cgroup cgroup rw,net_cls,net_prio
42 33 0:36 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:19 - cgroup cgroup rw,cpuset
43 33 0:37 / /sys/fs/cgroup/hugetlb rw,nosuid,nodev,noexec,relatime shared:20 - cgroup cgroup rw,hugetlb
44 33 0:38 / /sys/fs/cgroup/rdma rw,nosuid,nodev,noexec,relatime shared:21 - cgroup cgroup rw,rdma
45 33 0:39 / /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime shared:22 - cgroup cgroup rw,perf_event
46 33 0:40 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime shared:23 - cgroup cgroup rw,devices
47 33 0:41 / /sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime shared:24 - cgroup cgroup rw,pids
48 33 0:42 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime shared:25 - cgroup cgroup rw,freezer
49 25 0:43 / /proc/sys/fs/binfmt_misc rw,relatime shared:26 - autofs systemd-1 rw,fd=28,pgrp=1,timeout=0,minproto=5,maxproto=5,direct,pipe_ino=26316
50 26 0:20 / /dev/mqueue rw,nosuid,nodev,noexec,relatime shared:27 - mqueue mqueue rw
51 26 0:44 / /dev/hugepages rw,relatime shared:28 - hugetlbfs hugetlbfs rw,pagesize=2M
52 24 0:8 / /sys/kernel/debug rw,nosuid,nodev,noexec,relatime shared:29 - debugfs debugfs rw
53 24 0:12 / /sys/kernel/tracing rw,nosuid,nodev,noexec,relatime shared:30 - tracefs tracefs rw
55 29 7:0 / /snap/gnome-3-34-1804/66 ro,nodev,relatime shared:31 - squashfs /dev/loop0 ro
121 29 7:2 / /snap/core18/2074 ro,nodev,relatime shared:65 - squashfs /dev/loop2 ro
124 24 0:46 / /sys/fs/fuse/connections rw,nosuid,nodev,noexec,relatime shared:67 - fusectl fusectl rw
127 24 0:21 / /sys/kernel/config rw,nosuid,nodev,noexec,relatime shared:69 - configfs configfs rw
130 29 7:3 / /snap/gnome-3-34-1804/72 ro,nodev,relatime shared:71 - squashfs /dev/loop3 ro
133 29 7:1 / /snap/core18/2128 ro,nodev,relatime shared:73 - squashfs /dev/loop1 ro
136 29 7:4 / /snap/gtk-common-themes/1515 ro,nodev,relatime shared:75 - squashfs /dev/loop4 ro
139 28 0:47 / /run/vmblock-fuse rw,relatime shared:77 - fuse.vmware-vmblock vmware-vmblock rw,user_id=0,group_id=0,default_permissions,allow_other
142 29 7:5 / /snap/snapd/12883 ro,nodev,relatime shared:79 - squashfs /dev/loop5 ro
145 29 7:6 / /snap/snap-store/547 ro,nodev,relatime shared:81 - squashfs /dev/loop6 ro
148 29 7:7 / /snap/snapd/12704 ro,nodev,relatime shared:83 - squashfs /dev/loop7 ro
151 29 7:8 / /snap/snap-store/542 ro,nodev,relatime shared:85 - squashfs /dev/loop8 ro
154 29 8:1 / /boot/efi rw,relatime shared:87 - vfat /dev/sda1 rw,fmask=0077,dmask=0077,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro
157 49 0:49 / /proc/sys/fs/binfmt_misc rw,nosuid,nodev,noexec,relatime shared:89 - binfmt_misc binfmt_misc rw
1643 28 0:56 / /run/user/1000 rw,nosuid,nodev,relatime shared:912 - tmpfs tmpfs rw,size=400224k,mode=700,uid=1000,gid=1000
1675 1643 0:57 / /run/user/1000/gvfs rw,nosuid,nodev,relatime shared:929 - fuse.gvfsd-fuse gvfsd-fuse rw,user_id=1000,group_id=1000
574 1643 0:52 / /run/user/1000/doc rw,nosuid,nodev,relatime shared:532 - fuse /dev/fuse rw,user_id=1000,group_id=1000
/proc/[pid]/mountinfo (since Linux 2.6.26)
This file contains information about mounts in the
process's mount namespace (see mount_namespaces(7)). It
supplies various information (e.g., propagation state,
root of mount for bind mounts, identifier for each mount
and its parent) that is missing from the (older)
/proc/[pid]/mounts file, and fixes various other problems
with that file (e.g., nonextensibility, failure to
distinguish per-mount versus per-superblock options).
The file contains lines of the form:
36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
(1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11)
The numbers in parentheses are labels for the descriptions
below:
(1) mount ID: a unique ID for the mount (may be reused
after umount(2)).
(2) parent ID: the ID of the parent mount (or of self for
the root of this mount namespace's mount tree).
If a new mount is stacked on top of a previous
existing mount (so that it hides the existing mount)
at pathname P, then the parent of the new mount is
the previous mount at that location. Thus, when
looking at all the mounts stacked at a particular
location, the top-most mount is the one that is not
the parent of any other mount at the same location.
(Note, however, that this top-most mount will be
accessible only if the longest path subprefix of P
that is a mount point is not itself hidden by a
stacked mount.)
If the parent mount lies outside the process's root
directory (see chroot(2)), the ID shown here won't
have a corresponding record in mountinfo whose mount
ID (field 1) matches this parent mount ID (because
mounts that lie outside the process's root directory
are not shown in mountinfo). As a special case of
this point, the process's root mount may have a
parent mount (for the initramfs filesystem) that lies
outside the process's root directory, and an entry
for that mount will not appear in mountinfo.
(3) major:minor: the value of st_dev for files on this
filesystem (see stat(2)).
(4) root: the pathname of the directory in the filesystem
which forms the root of this mount.
(5) mount point: the pathname of the mount point relative
to the process's root directory.
(6) mount options: per-mount options (see mount(2)).
(7) optional fields: zero or more fields of the form
"tag[:value]"; see below.
(8) separator: the end of the optional fields is marked
by a single hyphen.
(9) filesystem type: the filesystem type in the form
"type[.subtype]".
(10) mount source: filesystem-specific information or
"none".
(11) super options: per-superblock options (see mount(2)).
Currently, the possible optional fields are shared,
master, propagate_from, and unbindable. See
mount_namespaces(7) for a description of these fields.
Parsers should ignore all unrecognized optional fields.
For more information on mount propagation see:
Documentation/filesystems/sharedsubtree.txt in the Linux
kernel source tree.
stat查看特定文件的stat信息
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/sysmacros.h>
int main(int argc, char *argv[])
{
struct stat fstat;
int ret = 0;
if (argc != 2) {
printf("Usage: %s <file path>\n", argv[0]);
return -1;
}
ret = stat(argv[1], &fstat);
if (ret < 0) {
perror("stat()");
return -1;
}
printf("st_dev = %ld\n", fstat.st_dev);
printf("%d %d\n", major(fstat.st_dev), minor(fstat.st_dev));
return 0;
}
#struct stat
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* Inode number */
mode_t st_mode; /* File type and mode */
nlink_t st_nlink; /* Number of hard links */
uid_t st_uid; /* User ID of owner */
gid_t st_gid; /* Group ID of owner */
dev_t st_rdev; /* Device ID (if special file) */
off_t st_size; /* Total size, in bytes */
blksize_t st_blksize; /* Block size for filesystem I/O */
blkcnt_t st_blocks; /* Number of 512B blocks allocated */
/* Since Linux 2.6, the kernel supports nanosecond
precision for the following timestamp fields.
For the details before Linux 2.6, see NOTES. */
struct timespec st_atim; /* Time of last access */
struct timespec st_mtim; /* Time of last modification */
struct timespec st_ctim; /* Time of last status change */
#define st_atime st_atim.tv_sec /* Backward compatibility */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};
测试结果
rlk@rlk:vfs$ ./a.out stat.c
st_dev = 2053
8 5
从stat中我们可以解析出,st_dev存的是文件本身存储设备的设备号,也就是硬盘的设备号,然后在moutinfo中去匹配,从而找到文件的挂在点;