| dm-dust | |
| ======= | |
| This target emulates the behavior of bad sectors at arbitrary | |
| locations, and the ability to enable the emulation of the failures | |
| at an arbitrary time. | |
| This target behaves similarly to a linear target. At a given time, | |
| the user can send a message to the target to start failing read | |
| requests on specific blocks (to emulate the behavior of a hard disk | |
| drive with bad sectors). | |
| When the failure behavior is enabled (i.e.: when the output of | |
| "dmsetup status" displays "fail_read_on_bad_block"), reads of blocks | |
| in the "bad block list" will fail with EIO ("Input/output error"). | |
| Writes of blocks in the "bad block list will result in the following: | |
| 1. Remove the block from the "bad block list". | |
| 2. Successfully complete the write. | |
| This emulates the "remapped sector" behavior of a drive with bad | |
| sectors. | |
| Normally, a drive that is encountering bad sectors will most likely | |
| encounter more bad sectors, at an unknown time or location. | |
| With dm-dust, the user can use the "addbadblock" and "removebadblock" | |
| messages to add arbitrary bad blocks at new locations, and the | |
| "enable" and "disable" messages to modulate the state of whether the | |
| configured "bad blocks" will be treated as bad, or bypassed. | |
| This allows the pre-writing of test data and metadata prior to | |
| simulating a "failure" event where bad sectors start to appear. | |
| Table parameters | |
| ---------------- | |
| <device_path> <offset> <blksz> | |
| Mandatory parameters: | |
| <device_path>: | |
| Path to the block device. | |
| <offset>: | |
| Offset to data area from start of device_path | |
| <blksz>: | |
| Block size in bytes | |
| (minimum 512, maximum 1073741824, must be a power of 2) | |
| Usage instructions | |
| ------------------ | |
| First, find the size (in 512-byte sectors) of the device to be used:: | |
| $ sudo blockdev --getsz /dev/vdb1 | |
| 33552384 | |
| Create the dm-dust device: | |
| (For a device with a block size of 512 bytes) | |
| :: | |
| $ sudo dmsetup create dust1 --table '0 33552384 dust /dev/vdb1 0 512' | |
| (For a device with a block size of 4096 bytes) | |
| :: | |
| $ sudo dmsetup create dust1 --table '0 33552384 dust /dev/vdb1 0 4096' | |
| Check the status of the read behavior ("bypass" indicates that all I/O | |
| will be passed through to the underlying device; "verbose" indicates that | |
| bad block additions, removals, and remaps will be verbosely logged):: | |
| $ 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 | |
| Adding and removing bad blocks | |
| ------------------------------ | |
| At any time (i.e.: whether the device has the "bad block" emulation | |
| enabled or disabled), bad blocks may be added or removed from the | |
| device via the "addbadblock" and "removebadblock" messages:: | |
| $ 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 | |
| These bad blocks will be stored in the "bad block list". | |
| While the device is in "bypass" mode, reads and writes will succeed:: | |
| $ sudo dmsetup status dust1 | |
| 0 33552384 dust 252:17 bypass | |
| Enabling block read failures | |
| ---------------------------- | |
| To enable the "fail read on bad block" behavior, send the "enable" message:: | |
| $ 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 | |
| With the device in "fail read on bad block" mode, attempting to read a | |
| block will encounter an "Input/output error":: | |
| $ 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 | |
| ...and writing to the bad blocks will remove the blocks from the list, | |
| therefore emulating the "remap" behavior of hard disk drives:: | |
| $ 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 | |
| Bad block add/remove error handling | |
| ----------------------------------- | |
| Attempting to add a bad block that already exists in the list will | |
| result in an "Invalid argument" error, as well as a helpful message:: | |
| $ 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 | |
| Attempting to remove a bad block that doesn't exist in the list will | |
| result in an "Invalid argument" error, as well as a helpful message:: | |
| $ 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 | |
| Counting the number of bad blocks in the bad block list | |
| ------------------------------------------------------- | |
| To count the number of bad blocks configured in the device, run the | |
| following message command:: | |
| $ sudo dmsetup message dust1 0 countbadblocks | |
| A message will print with the number of bad blocks currently | |
| configured on the device:: | |
| countbadblocks: 895 badblock(s) found | |
| Querying for specific bad blocks | |
| -------------------------------- | |
| To find out if a specific block is in the bad block list, run the | |
| following message command:: | |
| $ sudo dmsetup message dust1 0 queryblock 72 | |
| The following message will print if the block is in the list:: | |
| dust_query_block: block 72 found in badblocklist | |
| The following message will print if the block is not in the list:: | |
| dust_query_block: block 72 not found in badblocklist | |
| The "queryblock" message command will work in both the "enabled" | |
| and "disabled" modes, allowing the verification of whether a block | |
| will be treated as "bad" without having to issue I/O to the device, | |
| or having to "enable" the bad block emulation. | |
| Clearing the bad block list | |
| --------------------------- | |
| To clear the bad block list (without needing to individually run | |
| a "removebadblock" message command for every block), run the | |
| following message command:: | |
| $ sudo dmsetup message dust1 0 clearbadblocks | |
| After clearing the bad block list, the following message will appear:: | |
| dust_clear_badblocks: badblocks cleared | |
| If there were no bad blocks to clear, the following message will | |
| appear:: | |
| dust_clear_badblocks: no badblocks found | |
| Listing the bad block list | |
| -------------------------- | |
| To list all bad blocks in the bad block list (using an example device | |
| with blocks 1 and 2 in the bad block list), run the following message | |
| command:: | |
| $ sudo dmsetup message dust1 0 listbadblocks | |
| 1 | |
| 2 | |
| If there are no bad blocks in the bad block list, the command will | |
| execute with no output:: | |
| $ sudo dmsetup message dust1 0 listbadblocks | |
| Message commands list | |
| --------------------- | |
| Below is a list of the messages that can be sent to a dust device: | |
| Operations on blocks (requires a <blknum> argument):: | |
| addbadblock <blknum> | |
| queryblock <blknum> | |
| removebadblock <blknum> | |
| ...where <blknum> is a block number within range of the device | |
| (corresponding to the block size of the device.) | |
| Single argument message commands:: | |
| countbadblocks | |
| clearbadblocks | |
| listbadblocks | |
| disable | |
| enable | |
| quiet | |
| Device removal | |
| -------------- | |
| When finished, remove the device via the "dmsetup remove" command:: | |
| $ sudo dmsetup remove dust1 | |
| Quiet mode | |
| ---------- | |
| On test runs with many bad blocks, it may be desirable to avoid | |
| excessive logging (from bad blocks added, removed, or "remapped"). | |
| This can be done by enabling "quiet mode" via the following message:: | |
| $ sudo dmsetup message dust1 0 quiet | |
| This will suppress log messages from add / remove / removed by write | |
| operations. Log messages from "countbadblocks" or "queryblock" | |
| message commands will still print in quiet mode. | |
| The status of quiet mode can be seen by running "dmsetup status":: | |
| $ sudo dmsetup status dust1 | |
| 0 33552384 dust 252:17 fail_read_on_bad_block quiet | |
| To disable quiet mode, send the "quiet" message again:: | |
| $ sudo dmsetup message dust1 0 quiet | |
| $ sudo dmsetup status dust1 | |
| 0 33552384 dust 252:17 fail_read_on_bad_block verbose | |
| (The presence of "verbose" indicates normal logging.) | |
| "Why not...?" | |
| ------------- | |
| scsi_debug has a "medium error" mode that can fail reads on one | |
| specified sector (sector 0x1234, hardcoded in the source code), but | |
| it uses RAM for the persistent storage, which drastically decreases | |
| the potential device size. | |
| dm-flakey fails all I/O from all block locations at a specified time | |
| frequency, and not a given point in time. | |
| When a bad sector occurs on a hard disk drive, reads to that sector | |
| are failed by the device, usually resulting in an error code of EIO | |
| ("I/O error") or ENODATA ("No data available"). However, a write to | |
| the sector may succeed, and result in the sector becoming readable | |
| after the device controller no longer experiences errors reading the | |
| sector (or after a reallocation of the sector). However, there may | |
| be bad sectors that occur on the device in the future, in a different, | |
| unpredictable location. | |
| This target seeks to provide a device that can exhibit the behavior | |
| of a bad sector at a known sector location, at a known time, based | |
| on a large storage device (at least tens of gigabytes, not occupying | |
| system memory). |