下面是把你这一串讨论压缩、梳理后的版本,我会按“概念 → 各字段含义 → 虚拟 FS 的 dev_t 冲突问题”来整理。
一、统一认知:dev_t 是啥
dev_t本质:主设备号 + 次设备号- 原始用途:驱动用来唯一标识一个具体设备实例(某块盘、某个分区、某个串口等)。
- 后来:VFS / 用户态接口也“复用”这个统一的编号方式,在不同层面用它标识:
- 块设备上的文件系统实例;
- 虚拟文件系统实例;
- 设备文件代表的真实设备等。
类型始终是同一个 dev_t,关键是:当前这个号“在标识哪一层的对象”。
二、st_dev / s_dev VS st_rdev / i_rdev:两个层面的“设备号”
1. s_dev / st_dev:文件系统实例所在的“设备号”
-
super_block.s_dev:
这个文件系统实例(super_block)对应的 dev_t。 -
对不同类型 FS:
-
块设备上的文件系统(ext4/xfs 等)
s_dev= 底层块设备的 dev_t(比如/dev/sda1的8:1)。- 这就是你熟悉的“给驱动用来标识这块设备的号”。
-
虚拟/内存文件系统(tmpfs/procfs/sysfs 等)
- 没底层块设备,内核会给它分配一个匿名 dev_t。
- 这个 dev_t 只用来标识这个文件系统实例,对实际硬件无意义。
-
-
用户态
stat()的:st.st_dev // = inode->i_sb->s_dev表示:这个文件所在的文件系统实例是哪个(用 dev_t 表示)。
换句话说,
st_dev/s_dev是“文件所在文件系统的设备号”。
对有块设备的情况,可以直观理解成“所在块设备的设备号”。
2. i_rdev / st_rdev:设备文件所代表的“真实设备号”
-
inode.i_rdev:
对于设备文件(字符设备/块设备),存的是它所代表的真实设备的 dev_t。 -
stat()的:st.st_rdev // = inode->i_rdev -
含义:
- 对普通文件/目录:无意义,通常为 0;
- 只对
/dev/sda1、/dev/ttyS0这种设备节点有意义:st_rdev= 设备驱动用来识别这个设备的 dev_t。
简化记忆:
dev(st_dev):这个文件“在哪个文件系统 / 设备上”。rdev(st_rdev):这个文件如果是设备节点,“它代表哪一个真实设备”。
三、具体例子串一下
假设:
- 根
/:挂在/dev/sda1上,为 ext4; /dev:是 devtmpfs;- 存在设备文件
/dev/sda1。
1. 普通文件 /home/a.txt
-
所在文件系统:挂在
/dev/sda1上的 ext4。 -
super_block:
sb_root->s_dev = 8:1 // 来自底层块设备 /dev/sda1 -
inode:
inode->i_sb = sb_root inode->i_rdev = 0 // 普通文件,不是设备节点 -
stat("a.txt"):st_dev = 8:1← “在 /dev/sda1 这个文件系统上”st_rdev = 0← 不是设备文件
2. 设备文件 /dev/sda1
-
/dev的 super_block(devtmpfs):sb_dev->s_dev = 某个匿名 dev_t(虚拟号,比如 0:18) -
/dev/sda1的 inode:inode->i_sb = sb_dev inode->i_rdev = 8:1 // 指向真实块设备 /dev/sda1 -
stat("/dev/sda1"):st_dev = sb_dev->s_dev(虚拟 dev_t,表示“它在 devtmpfs 文件系统上”)st_rdev = 8:1(真正的块设备号,驱动用它识别设备)
可以看到:同一个 8:1,同时扮演两种角色:
- 对驱动 & 块层:这是真实设备号;
- 对 VFS:它也可以是某个文件系统实例的
s_dev(比如挂在这块盘上的 ext4)。
四、虚拟文件系统的 dev_t 会不会和真实的冲突?
问题核心:
tmpfs/procfs 这种虚拟文件系统,用的“匿名 dev_t”会不会和真实块设备号(如
8:1)撞在一起?
正常内核实现里:不会。
原因:
-
匿名 dev_t 从专门的号段里分配
- 内核有专门给“匿名 super_block / 虚拟 FS”保留的 dev_t 号段(特定 major)。
- 实际块设备驱动通过
register_blkdev()分配的 major 不会用到这段号。
-
匿名 dev_t 在所有 super_block 间保证唯一
- 分配时会检查已用 dev_t,不会给两个 super_block 分同一个 dev_t。
因此:
- tmpfs 的
st_dev不会等于某个真实块设备文件系统的st_dev(例如8:1)。 - 如果你看到两个不同的文件系统实例
st_dev都是8:1,那要么:- 它们其实是同一个块设备上的不同挂载点 / 同一实例的多挂载情况;
- 要么是那个系统的内核被修改过 dev_t 分配逻辑,已经偏离主线实现。
五、最后帮你用两句“记忆版”总结
st_dev / s_dev:标识“这个文件在哪个文件系统实例上”,背后用 dev_t 表示该实例所依托的设备(真实的或匿名的)。st_rdev / i_rdev:只在设备文件上有意义,用来指向它代表的真实设备的 dev_t,驱动就是靠它识别设备。
再加一句:
- 虚拟文件系统的 dev_t 来自单独号段,不和真实块设备 dev_t 混用,因此不会出现 tmpfs 的
st_dev = 8:1这种和真实盘冲突的情况。