Linux 有句老话:一切皆文件。看看 /dev 目录就明白这不是鸡汤:
$ ls -l /dev | head -5
brw-rw---- 1 root disk 8, 0 nvme0n1 ← 你的整块硬盘
crw-rw-rw- 1 root tty 4, 64 ttyS0 ← 串口终端
crw-rw---- 1 root kvm 10, 232 kvm ← 虚拟化接口
b 开头是块设备,c 开头是字符设备,8 和 0 是主次设备号。你在磁盘上 dd、对串口 cat、往声卡里写数据,用的全是同一套 open/read/write 系统调用。把千奇百怪的硬件统一成「文件」,是设备管理的核心思想;而统一背后,是本章要展开的层次:中断和 DMA(计组第 9 章讲过硬件侧,这里看内核怎么用它们)、设备驱动、磁盘调度算法、以及 SSD 时代的新格局。
从上到下,内核把设备分三层管理:
open/read/write/ioctl 的文件接口,应用只见文件不见硬件。一个实用知识点:块设备和字符设备的差别。块设备(磁盘)可以随机寻址、以块为单位读写、可挂文件系统;字符设备(串口、键盘)是字节流,来了就得收。鼠标是字符设备,SSD 是块设备,别看 SSD 没有磁头,抽象不变。
机械硬盘的物理结构:盘片、磁道、扇区(512B 或 4KB,最小读写单位),磁头移动靠机械臂。一次磁盘访问的耗时拆成三段:
典型值:寻道几毫秒(磁头臂要移动),旋转延迟平均半圈(7200rpm 的盘约 4ms),传输微秒级。寻道是大头,所以磁盘调度的全部目标就一句话:让磁头少跑路。
设磁头在 50 号磁道,请求队列 98, 183, 37, 122, 14, 124, 65, 67,把四个算法各算一遍(这是本章的必考手算题):
FCFS:按请求原序跑,总移动 = |98-50|+|183-98|+... = 48+85+146+85+108+110+59+2 = 640。磁头在盘面上反复横跳,公平但荒唐。
SSTF(最短寻道优先):每步挑最近的。50→65→67→37→14→98→122→124→183,总计 236。好很多,但有饥饿病:远端请求永远排不进「最近」,两头的老请求可能被无限晾着。
SCAN(电梯):磁头只朝一个方向扫,扫到头再折返,像电梯。50→37→14→0(到底)→65→67→98→122→124→183,总计 208。无饿死,但中间磁道待遇最好,刚被扫过的边缘要等整整一个来回。
C-SCAN(循环扫描):单向服务,扫到头直接空驶回起点再扫,把「服务」限定在单方向,等待时间分布最均匀。总移动约 382(多付了空驶),换来公平。
教材到这就算完了,但真实世界有两层后续值得知道。其一,现代磁盘自己有缓存和队列(NCQ),会偷偷重排 OS 下发的请求,OS 级调度的意义被稀释;其二,SSD 没有磁头,「寻道」不存在,这套算法在 SSD 上的意义归零——但它们的思想搬进了 SSD 内部的固件(FTL 层)和调度器(如 mq-deadline 保证读请求不被写请求憋死),电梯还是那部电梯,只是换了司机。
CPU 快、设备慢、各设备之间也互不匹配,缓冲(buffering)是标准药方:在内存里放缓冲区,快的一方写完就走,慢的一方慢慢消化。你写的每一行 printf 其实都进了 libc 的缓冲区,攒够了才 syscall;数据库的 WAL、日志系统的批量落盘,同源同理。缓冲还顺带解决「生产者和消费者速率抖动」问题,吸收瞬时洪峰。
SPOOLing(假脱机)是另一味药,专治「独占设备虚拟成共享」:打印机一次只能打一份,多个进程同时打印就会穿插出废纸。SPOOLing 把打印请求排队写进磁盘队列,打印机守护进程按序取活。打印机变成了「共享的」,每个进程感觉自己独占着一台。这招的思想(排队 + 守护进程 + 磁盘做中转)在打印、队列系统、消息中间件里到处都是。
留一个现代话题收尾。传统的「读文件发网络」要四次拷贝:磁盘→页缓存→用户缓冲区→socket 缓冲区→网卡。数据在内核和用户态之间反复横跳,CPU 当搬运工。Linux 的 sendfile(或 mmap)把中间两跳省掉,数据从页缓存直送网卡(DMA 配合),拷贝从四次降到两次、CPU 从全程参与变成旁观。Nginx 静态文件快、Kafka 吞吐高,这个系统调用功不可没。它提醒我们设备管理的终极目标和整门课一致:让 CPU 从搬运中解放,只做决策。
iostat 的 %util 当「磁盘满负荷」。SSD 并行度高,%util 100% 可能远没到瓶颈;看 IOPS、延迟、队列深度才是正路。98,183,37,122,14,124,65,67(教材经典原题),分别算 FCFS、SSTF、SCAN(向大号方向)、C-SCAN 的总移动距离。iostat -x 1 观察 NVMe 盘的 r/s、await、%util;跑 fio 或简单 dd 分别做顺序写和 4K 随机写,亲测性能差多少倍。