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 <behlendorf1@llnl.gov>
Signed-off-by: Don Brady <don.brady@intel.com>
Closes #6345
This commit is contained in:
Don Brady
2017-08-14 18:17:15 -04:00
committed by Brian Behlendorf
parent 42a76fc8d7
commit d977122da9
5 changed files with 76 additions and 17 deletions
+2 -2
View File
@@ -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);
+47 -5
View File
@@ -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.