aboutsummaryrefslogtreecommitdiffstats
path: root/module/zfs
diff options
context:
space:
mode:
authorDon Brady <[email protected]>2017-08-14 18:17:15 -0400
committerBrian Behlendorf <[email protected]>2017-08-14 15:17:15 -0700
commitd977122da92e870a6a8990437ced845a04c39cfc (patch)
tree7b4b35bcba2f4a459a1004b80adea63ff970bf4f /module/zfs
parent42a76fc8d757ab82fc1ce8e5e1f2079e07a5b9d4 (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/zfs')
-rw-r--r--module/zfs/zio.c4
-rw-r--r--module/zfs/zio_inject.c52
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.