dm-dust

此目标模拟了任意位置的坏扇区行为,并能够在任意时间启用故障模拟。

此目标行为类似于线性目标。在给定时间,用户可以向目标发送消息,以开始在特定块上使读取请求失败(以模拟带有坏扇区的硬盘驱动器的行为)。

当启用故障行为时(即:“dmsetup status”的输出显示“fail_read_on_bad_block”时),“坏块列表”中的块读取将以 EIO(“输入/输出错误”)失败。

对“坏块列表”中的块进行写入将导致以下结果:

  1. 将块从“坏块列表”中移除。

  2. 成功完成写入。

这模拟了带有坏扇区的驱动器的“重映射扇区”行为。

通常,遇到坏扇区的驱动器很可能会在未知时间或位置遇到更多坏扇区。使用 dm-dust,用户可以使用“addbadblock”和“removebadblock”消息在新的位置添加任意坏块,并使用“enable”和“disable”消息来调整配置的“坏块”是否被视为坏块或被绕过。这允许在模拟坏扇区开始出现的“故障”事件之前预写入测试数据和元数据。

表参数

<device_path> <offset> <blksz>

强制参数
<device_path>

块设备的路径。

<offset>

从 device_path 开始到数据区域的偏移量

<blksz>

块大小(字节)

(最小 512,最大 1073741824,必须是 2 的幂)

使用说明

首先,找到要使用的设备的大小(以 512 字节扇区为单位)

$ sudo blockdev --getsz /dev/vdb1
33552384

创建 dm-dust 设备:(对于块大小为 512 字节的设备)

$ sudo dmsetup create dust1 --table '0 33552384 dust /dev/vdb1 0 512'

(对于块大小为 4096 字节的设备)

$ sudo dmsetup create dust1 --table '0 33552384 dust /dev/vdb1 0 4096'

检查读取行为的状态(“bypass”表示所有 I/O 都将传递给底层设备;“verbose”表示坏块的添加、移除和重映射将被详细记录)

$ sudo dmsetup status dust1
0 33552384 dust 252:17 bypass verbose

$ sudo dd if=/dev/mapper/dust1 of=/dev/null bs=512 count=128 iflag=direct
128+0 records in
128+0 records out

$ sudo dd if=/dev/zero of=/dev/mapper/dust1 bs=512 count=128 oflag=direct
128+0 records in
128+0 records out

添加和移除坏块

在任何时候(即:无论设备是否启用或禁用“坏块”模拟),都可以通过“addbadblock”和“removebadblock”消息向设备添加或从设备中移除坏块

$ sudo dmsetup message dust1 0 addbadblock 60
kernel: device-mapper: dust: badblock added at block 60

$ sudo dmsetup message dust1 0 addbadblock 67
kernel: device-mapper: dust: badblock added at block 67

$ sudo dmsetup message dust1 0 addbadblock 72
kernel: device-mapper: dust: badblock added at block 72

这些坏块将存储在“坏块列表”中。当设备处于“bypass”模式时,读写操作将成功。

$ sudo dmsetup status dust1
0 33552384 dust 252:17 bypass

启用块读取失败

要启用“坏块读取失败”行为,请发送“enable”消息

$ sudo dmsetup message dust1 0 enable
kernel: device-mapper: dust: enabling read failures on bad sectors

$ sudo dmsetup status dust1
0 33552384 dust 252:17 fail_read_on_bad_block

当设备处于“坏块读取失败”模式时,尝试读取块将遇到“输入/输出错误”

$ sudo dd if=/dev/mapper/dust1 of=/dev/null bs=512 count=1 skip=67 iflag=direct
dd: error reading '/dev/mapper/dust1': Input/output error
0+0 records in
0+0 records out
0 bytes copied, 0.00040651 s, 0.0 kB/s

...并且写入坏块将从列表中移除这些块,从而模拟硬盘驱动器的“重映射”行为。

$ sudo dd if=/dev/zero of=/dev/mapper/dust1 bs=512 count=128 oflag=direct
128+0 records in
128+0 records out

kernel: device-mapper: dust: block 60 removed from badblocklist by write
kernel: device-mapper: dust: block 67 removed from badblocklist by write
kernel: device-mapper: dust: block 72 removed from badblocklist by write
kernel: device-mapper: dust: block 87 removed from badblocklist by write

坏块添加/移除错误处理

尝试添加已存在于列表中的坏块将导致“无效参数”错误,并显示一条有用的消息。

$ sudo dmsetup message dust1 0 addbadblock 88
device-mapper: message ioctl on dust1  failed: Invalid argument
kernel: device-mapper: dust: block 88 already in badblocklist

尝试移除列表中不存在的坏块将导致“无效参数”错误,并显示一条有用的消息。

$ sudo dmsetup message dust1 0 removebadblock 87
device-mapper: message ioctl on dust1  failed: Invalid argument
kernel: device-mapper: dust: block 87 not found in badblocklist

统计坏块列表中坏块的数量

要统计设备中配置的坏块数量,请运行以下消息命令:

$ sudo dmsetup message dust1 0 countbadblocks

将打印一条消息,显示当前设备上配置的坏块数量。

countbadblocks: 895 badblock(s) found

查询特定坏块

要查找特定块是否在坏块列表中,请运行以下消息命令:

$ sudo dmsetup message dust1 0 queryblock 72

如果块在列表中,将打印以下消息:

dust_query_block: block 72 found in badblocklist

如果块不在列表中,将打印以下消息:

dust_query_block: block 72 not found in badblocklist

“queryblock”消息命令在“启用”和“禁用”模式下均可工作,从而无需向设备发出 I/O 或“启用”坏块模拟即可验证块是否被视为“坏块”。

清除坏块列表

要清除坏块列表(无需为每个块单独运行“removebadblock”消息命令),请运行以下消息命令:

$ sudo dmsetup message dust1 0 clearbadblocks

清除坏块列表后,将出现以下消息:

dust_clear_badblocks: badblocks cleared

如果没有要清除的坏块,将出现以下消息:

dust_clear_badblocks: no badblocks found

列出坏块列表

要列出坏块列表中的所有坏块(使用一个坏块列表中包含块 1 和 2 的示例设备),请运行以下消息命令:

$ sudo dmsetup message dust1 0 listbadblocks
1
2

如果坏块列表中没有坏块,该命令将执行且不显示任何输出。

$ sudo dmsetup message dust1 0 listbadblocks

消息命令列表

以下是可以发送到 dm-dust 设备的消息列表:

块操作(需要 <blknum> 参数)

addbadblock <blknum>
queryblock <blknum>
removebadblock <blknum>

...其中 <blknum> 是设备范围内的块号(对应于设备的块大小)。

单参数消息命令

countbadblocks
clearbadblocks
listbadblocks
disable
enable
quiet

设备移除

完成后,通过“dmsetup remove”命令移除设备。

$ sudo dmsetup remove dust1

安静模式

在有许多坏块的测试运行中,可能希望避免过多的日志记录(来自添加、移除或“重映射”的坏块)。这可以通过以下消息启用“安静模式”来完成:

$ sudo dmsetup message dust1 0 quiet

这将抑制添加/移除/通过写入操作移除的日志消息。“countbadblocks”或“queryblock”消息命令的日志消息在安静模式下仍会打印。

可以通过运行“dmsetup status”查看安静模式的状态。

$ sudo dmsetup status dust1
0 33552384 dust 252:17 fail_read_on_bad_block quiet

要禁用安静模式,请再次发送“quiet”消息。

$ sudo dmsetup message dust1 0 quiet

$ sudo dmsetup status dust1
0 33552384 dust 252:17 fail_read_on_bad_block verbose

(出现“verbose”表示正常日志记录。)

“为什么不……?”

scsi_debug 有一个“介质错误”模式,可以在一个指定的扇区(扇区 0x1234,在源代码中硬编码)上使读取失败,但它使用 RAM 进行持久存储,这大大减小了潜在的设备大小。

dm-flakey 在指定的时间频率下使所有块位置的所有 I/O 失败,而不是在给定时间点。

当硬盘驱动器上出现坏扇区时,设备将使对该扇区的读取失败,通常导致错误代码为 EIO(“I/O 错误”)或 ENODATA(“无可用数据”)。但是,对该扇区的写入可能会成功,并且在设备控制器不再遇到读取该扇区错误(或扇区重新分配后)后,该扇区变得可读。然而,设备上未来可能会在不同且不可预测的位置出现坏扇区。

此目标旨在提供一个设备,该设备可以在已知扇区位置、已知时间,基于大型存储设备(至少几十 GB,不占用系统内存)表现出坏扇区的行为。