我有一个旧的 64MB CF 卡,我在带有 CardBus 适配器的笔记本电脑(内核 2.6.38)中使用它。如果我在这张CF卡上写入一个64MB的图片,那么写入速度超过200MB/s:
T42 ~ # fdisk -lu
Disk /dev/sda: 40.0 GB, 40007761920 bytes
255 heads, 63 sectors/track, 4864 cylinders, total 78140160 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00043afc
Device Boot Start End Blocks Id System
/dev/sda1 * 2048 73947135 36972544 83 Linux
/dev/sda2 73949182 78139391 2095105 5 Extended
/dev/sda5 73949184 78139391 2095104 82 Linux swap / Solaris
Disk /dev/sdb: 64 MB, 64225280 bytes
8 heads, 32 sectors/track, 490 cylinders, total 125440 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000
Device Boot Start End Blocks Id System
/dev/sdb1 * 32 125300 62634+ 4 FAT16 <32M
Partition 1 has different physical/logical endings:
phys=(488, 7, 32) logical=(489, 3, 21)
T42 ~ # mount | grep -i sdb
T42 ~ # time dd if=64MB of=/dev/sdb bs=10M
6+1 records in
6+1 records out
64225280 bytes (64 MB) copied, 0.320419 s, 200 MB/s
real 0m0.624s
user 0m0.000s
sys 0m0.304s
T42 ~ #
Run Code Online (Sandbox Code Playgroud)
在 0.32 秒内达到 64MB,对于 10 年旧的 CF 卡显然是不现实的,如果我在dd if=64MB of=/dev/sdb bs=10M完成后立即从笔记本电脑中取出卡,我会看到很多输出<timestamp> end_request: I/O error, dev sdb, sector <sector number>错误dmesg。什么可能导致这种行为?
块设备写入由内核缓冲。这在挂载文件系统时清晰可见(卸载时,必须刷新缓冲区,有时会导致umount返回前有很长的延迟)。随着可用 RAM 越来越大,这种延迟似乎越来越严重。您甚至可以在内核初始化数据传输之前立即写入半 GB。在您看到传输完成后,内核可能会在几分钟内透明地写入设备。
出于多种原因,此功能非常好。它允许更快地读取和写入设备的响应,也可以透明地读取数据从写入之后的缓冲区中,甚至在实际物理写入完成之前。对于长期安装的硬盘驱动器,内核会在有时间的时候安排写入,同时从用户的角度使设备响应更快。尤其是对于磁性硬盘,顺序写入大块也比在整个驱动器的几个地方写入小块更快:块可以在推送到物理设备之前进行排序和分组(尽管硬盘驱动器也做了一些缓冲和数据排序在硬件内部)。简而言之,您不会注意到设备的运行缓慢,也不会注意到初始延迟(在网络安装驱动器或硬盘驱动器必须从休眠状态启动的情况下)。
对于块设备的直接访问,缓冲有点不幸,因为你没有调用umount,也没有真正注意到传输何时完成。无论如何你应该打电话sync。