Linux 文件系统从磁盘到用户的路径

8次阅读

linux通过总线枚举磁盘并按探测顺序生成/dev/sda等节点;mkfs.ext4写入超级块等元数据使分区可识别为ext4;mount加载驱动、验证超级块、构建VFS对象并挂接;路径访问经dentry→inode→块映射→扇区I/O。

Linux 文件系统从磁盘到用户的路径

磁盘设备如何被识别为 /dev/sda 这类节点

Linux 启动时,内核通过 PCI/usb/SATA 等总线枚举存储控制器,再扫描其挂载的物理设备。每块磁盘会被分配一个主设备号和次设备号,最终在 /dev 下生成对应节点(如 /dev/sda)。顺序不取决于物理插槽,而取决于内核探测到设备的先后——热插拔或 bios 启动顺序变化都可能让 sda 变成 sdb

实际中别硬编码 /dev/sda,优先用 /dev/disk/by-uuid//dev/disk/by-label/ 下的稳定符号链接。

mkfs.ext4 怎么把裸设备变成可挂载的文件系统

执行 mkfs.ext4 /dev/sda1 并非“格式化磁盘”,而是向该分区起始区域写入 ext4 的超级块(superblock)、组描述符、inode 表、块位图等元数据结构。这些数据定义了“哪些扇区存文件内容、哪些存目录项、空闲空间怎么管理”。没有这一步,mount 会报错 Wrong fs type, bad option, bad superblock

常见疏漏:

  • 忘记先用 fdiskparted 创建分区表和分区(直接对 /dev/sda 格式化虽可行,但破坏 MBR/gpt,且多数工具默认不识别)
  • 误用 mkfs.xfs 后却尝试以 ext4 挂载
  • 在 LVM 逻辑卷上运行 mkfs 前没确认 lvscan 已识别该 LV

mount /dev/sda1 /mnt 发生了什么

内核收到 mount 系统调用后,会:加载 ext4 模块(若未加载)、读取 /dev/sda1 开头的超级块验证文件系统类型、构建内存中的 VFS 层对象(Struct super_block, struct dentry, struct inode),最后将该文件系统根目录的 dentry 挂接到 /mnt 对应的 dentry 上。

关键点:

  • 挂载点 /mnt 必须是已存在的空目录;若非空,挂载后原内容不可见(但卸载即恢复)
  • mount -o ro 会让内核拒绝所有写入路径,连 open(O_RDWR) 都会返回 EROFS
  • 使用 bind 挂载(mount --bind /src /dst)不涉及文件系统解析,只是 VFS 层的路径映射

用户访问 /mnt/file.txt 时,内核怎么定位到磁盘扇区

路径解析从 /mnt 的 dentry 开始,逐级查子目录项(dentry)→ 获取对应 inode → 根据 inode 中的 block map(直接/间接块指针)算出文件数据所在逻辑块号 → 通过块设备层映射为物理扇区地址 → 提交 I/O 请求给驱动。

这个过程里容易被忽略的环节:

  • ext4 默认启用 dir_index 特性,用 htree 加速目录查找;禁用后大目录 ls 会明显变慢
  • 如果文件被 chattr +e 设置为 extent 格式,inode 不再用传统间接块,而是直接存 extent 数组,减少元数据跳转
  • SSD 上开启 discard 挂载选项后,rm 文件会立即发 TRIM 命令,但可能拖慢删除速度;多数场景建议用定期 fstrim

磁盘到用户的每一跳都依赖前一跳的正确建立:设备节点错、文件系统未初始化、挂载点失效、路径组件权限不足,任一环断开,cat: /mnt/file.txt: No such file or Directory 就不是简单的“文件不存在”。

text=ZqhQzanResources