mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 10:37:35 +03:00
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:
committed by
Brian Behlendorf
parent
42a76fc8d7
commit
d977122da9
+2
-2
@@ -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
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user