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,不佔用系統記憶體)表現出壞扇區的行為。