无论如何,在 Linux 中,是否有办法故意使块设备报告 I/O 错误,或者可能为了测试目的模拟一个错误?
答案1
是的,使用设备映射器有一个非常合理的方法可以做到这一点。
设备映射器可以将块设备重新组合成您选择的新映射/顺序。LVM 可以做到这一点。它还支持其他目标(其中一些相当新颖),例如“flakey”用于模拟故障磁盘和“error”用于模拟磁盘故障区域。
人们可以构建一个故意设置 IO 黑洞的设备,当越过黑洞时,它会报告 IO 错误。
首先,创建一些虚拟卷作为目标并使其可作为块设备寻址。
dd if=/dev/zero of=/var/lib/virtualblock.img bs=512 count=1048576
losetup /dev/loop0 /var/lib/virtualblock.img
因此,首先创建一个 512M 文件,它是我们虚拟块设备的基础,我们将在其中打一个“洞”。不过现在还没有洞。如果你这样做,mkfs.ext4 /dev/loop0
你将获得一个完全有效的文件系统。
因此,让我们使用 dmsetup,使用这个块设备——将创建一个有一些漏洞的新设备。下面是一个例子
dmsetup create errdev0
0 261144 linear /dev/loop0 0
261144 5 error
261149 787427 linear /dev/loop0 261139
这将创建一个名为“errdev0”的设备(通常在 /dev/mapper 中)。当您输入时,dmsetup create errdev0
它将等待 stdin,并在输入 ^D 时完成。
在上面的例子中,我们在循环设备的扇区 261144 处创建了一个 5 扇区空洞(2.5kb)。然后我们继续正常地遍历循环设备。
该脚本将尝试为您生成一个表,该表将洞放置在大约 16Mb 的随机位置(尽管它非常随机)。
#!/bin/bash
start_sector=0
good_sector_size=0
for sector in {0..1048576}; do
if [[ ${RANDOM} == 0 ]]; then
echo "${start_sector} ${good_sector_size} linear /dev/loop0 ${start_sector}"
echo "${sector} 1 error"
start_sector=$((${sector}+1))
good_sector_size=0
else
good_sector_size=$((${good_sector_size}+1))
fi
done
echo "${start_sector} $((${good_sector_size}-1)) linear /dev/loop0 ${start_sector}"
该脚本假定您还创建了一个 512Mb 的设备,并且您的虚拟块设备已打开/dev/loop0
。
您可以将此数据作为表格输出到文本文件,然后将其输入到dmsetup create errdev0
。
创建设备后,您就可以像使用普通块设备一样开始使用它,首先对其进行格式化,然后在其上放置文件。在某个时候,您应该会遇到一些 IO 问题,即您遇到的扇区实际上是虚拟设备中的 IO 漏洞。
使用完毕后,dmsetup remove errdev0
请移除设备。
如果您想让 IO 错误更可能发生,您可以更频繁地添加孔或更改您创建的孔的大小。请注意,在某些部分中放置错误很可能会从一开始就导致问题,IE 大小为 32mb,您无法写入 ext 通常会尝试执行的超级块,因此格式将无法工作。
为了增加乐趣——您实际上可以立即losetup
用mkfs.ext4 /dev/loop0
数据填充它。一旦您有一个运行良好的文件系统,只需卸载文件系统并使用 dmsetup 添加一些漏洞并重新安装它!
答案2
为了在输出失败时检查程序的稳健性,您可以使用伪设备/dev/full
,该设备在写入时始终返回“ENOSPACE”。
$ dd if=/dev/zero of=/dev/full
dd: writing to `/dev/full': No space left on device
1+0 records in
0+0 records out
答案3
取决于您要测试的内容。使用LD_PRELOAD
ed 库,您可以诱使应用程序思考诸如“所有写入均失败ENOSPC
或EIO
”之类的事情。
答案4
也许您可以更改分区表,使分区比实际更大。这可能会导致 I/O 错误。或者,如果您的磁盘是热插拔的,您可以拔出一个。