我有一张旧的 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 ~ #
对于使用 10 年的 CF 卡,0.32 秒内传输 64MB 显然是不现实的,如果我在完成后立即从笔记本电脑中取出该卡,我会在输出中dd if=64MB of=/dev/sdb bs=10M
看到很多<timestamp> end_request: I/O error, dev sdb, sector <sector number>
错误。dmesg
什么可能导致这种行为?
答案1
块设备写入由内核缓冲。当安装文件系统时,这一点清晰可见(当您卸载时,必须刷新缓冲区,导致有时在返回之前有很长的延迟umount
)。随着可用 RAM 越来越大,这种延迟似乎变得越来越严重。您甚至可以在内核初始化数据传输之前立即写入半 GB。在您看到传输完成后,内核可能会透明地写入设备几分钟。
这个功能非常好,原因有很多。它允许更快地响应设备的读写,数据也可以透明地传输读在写入之后、实际物理写入完成之前从缓冲区中读取。对于长期安装的硬盘驱动器,内核会安排在有时间时进行写入,同时从用户的角度来看使设备响应更快。特别是对于磁性硬盘驱动器,顺序写入大块也比在整个驱动器的多个位置写入小块更快:在推送到物理设备之前可以对块进行排序和分组(尽管硬盘驱动器也进行一些缓冲和数据排序)硬件内部)。简而言之,您不会注意到设备的速度有多慢,也不会注意到初始延迟(如果网络安装的驱动器或硬盘驱动器必须从休眠状态启动)。
对于直接访问块设备,缓冲有点不幸,因为您不调用umount
,也没有真正注意到传输何时完成。sync
无论如何你都应该打电话。
答案2
操作系统正在缓存数据dd
(以及其他命令),您应该sync
在删除 CF 之前执行以下操作:等待同步完成。
出于性能原因,缓存/缓冲非常重要,并且还允许内核/驱动程序重新排列对底层硬件的写入,以便例如对 HD 上单个磁道的所有写入一次性以正确的顺序完成(更少的磁头移动)。