diff options
author | Don Brady <[email protected]> | 2017-08-14 18:17:15 -0400 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2017-08-14 15:17:15 -0700 |
commit | d977122da92e870a6a8990437ced845a04c39cfc (patch) | |
tree | 7b4b35bcba2f4a459a1004b80adea63ff970bf4f /module | |
parent | 42a76fc8d757ab82fc1ce8e5e1f2079e07a5b9d4 (diff) |
Add corruption failure option to zinject(8)
Added a 'corrupt' error option that will flip a bit in the data
after a read operation. This is useful for generating checksum
errors at the device layer (in a mirror config for example). It
is also used to validate the diagnosis of checksum errors from
the zfs diagnosis engine.
Reviewed-by: Brian Behlendorf <[email protected]>
Signed-off-by: Don Brady <[email protected]>
Closes #6345
Diffstat (limited to 'module')
-rw-r--r-- | module/zfs/zio.c | 4 | ||||
-rw-r--r-- | module/zfs/zio_inject.c | 52 |
2 files changed, 49 insertions, 7 deletions
diff --git a/module/zfs/zio.c b/module/zfs/zio.c index 959b9a5a8..057a1405f 100644 --- a/module/zfs/zio.c +++ b/module/zfs/zio.c @@ -3472,8 +3472,8 @@ zio_vdev_io_done(zio_t *zio) vdev_cache_write(zio); if (zio_injection_enabled && zio->io_error == 0) - zio->io_error = zio_handle_device_injection(vd, - zio, EIO); + zio->io_error = zio_handle_device_injections(vd, zio, + EIO, EILSEQ); if (zio_injection_enabled && zio->io_error == 0) zio->io_error = zio_handle_label_injection(zio, EIO); diff --git a/module/zfs/zio_inject.c b/module/zfs/zio_inject.c index 4a4d431e3..e1ea825d7 100644 --- a/module/zfs/zio_inject.c +++ b/module/zfs/zio_inject.c @@ -271,9 +271,24 @@ zio_handle_label_injection(zio_t *zio, int error) return (ret); } +/*ARGSUSED*/ +static int +zio_inject_bitflip_cb(void *data, size_t len, void *private) +{ + ASSERTV(zio_t *zio = private); + uint8_t *buffer = data; + uint_t byte = spa_get_random(len); -int -zio_handle_device_injection(vdev_t *vd, zio_t *zio, int error) + ASSERT(zio->io_type == ZIO_TYPE_READ); + + /* flip a single random bit in an abd data buffer */ + buffer[byte] ^= 1 << spa_get_random(8); + + return (1); /* stop after first flip */ +} + +static int +zio_handle_device_injection_impl(vdev_t *vd, zio_t *zio, int err1, int err2) { inject_handler_t *handler; int ret = 0; @@ -311,7 +326,8 @@ zio_handle_device_injection(vdev_t *vd, zio_t *zio, int error) handler->zi_record.zi_iotype != zio->io_type) continue; - if (handler->zi_record.zi_error == error) { + if (handler->zi_record.zi_error == err1 || + handler->zi_record.zi_error == err2) { /* * limit error injection if requested */ @@ -322,7 +338,7 @@ zio_handle_device_injection(vdev_t *vd, zio_t *zio, int error) * For a failed open, pretend like the device * has gone away. */ - if (error == ENXIO) + if (err1 == ENXIO) vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; @@ -335,7 +351,21 @@ zio_handle_device_injection(vdev_t *vd, zio_t *zio, int error) zio != NULL) zio->io_flags |= ZIO_FLAG_IO_RETRY; - ret = error; + /* + * EILSEQ means flip a bit after a read + */ + if (handler->zi_record.zi_error == EILSEQ) { + if (zio == NULL) + break; + + /* locate buffer data and flip a bit */ + (void) abd_iterate_func(zio->io_abd, 0, + zio->io_size, zio_inject_bitflip_cb, + zio); + break; + } + + ret = handler->zi_record.zi_error; break; } if (handler->zi_record.zi_error == ENXIO) { @@ -350,6 +380,18 @@ zio_handle_device_injection(vdev_t *vd, zio_t *zio, int error) return (ret); } +int +zio_handle_device_injection(vdev_t *vd, zio_t *zio, int error) +{ + return (zio_handle_device_injection_impl(vd, zio, error, INT_MAX)); +} + +int +zio_handle_device_injections(vdev_t *vd, zio_t *zio, int err1, int err2) +{ + return (zio_handle_device_injection_impl(vd, zio, err1, err2)); +} + /* * Simulate hardware that ignores cache flushes. For requested number * of seconds nix the actual writing to disk. |