diff options
Diffstat (limited to 'module/zfs/zio_inject.c')
-rw-r--r-- | module/zfs/zio_inject.c | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/module/zfs/zio_inject.c b/module/zfs/zio_inject.c index 87d32a115..7a7401ecd 100644 --- a/module/zfs/zio_inject.c +++ b/module/zfs/zio_inject.c @@ -46,6 +46,7 @@ #include <sys/zfs_ioctl.h> #include <sys/vdev_impl.h> #include <sys/dmu_objset.h> +#include <sys/dsl_dataset.h> #include <sys/fs/zfs.h> uint32_t zio_injection_enabled = 0; @@ -659,6 +660,63 @@ zio_handle_io_delay(zio_t *zio) return (min_target); } +static int +zio_calculate_range(const char *pool, zinject_record_t *record) +{ + dsl_pool_t *dp; + dsl_dataset_t *ds; + objset_t *os = NULL; + dnode_t *dn = NULL; + int error; + + /* + * Obtain the dnode for object using pool, objset, and object + */ + error = dsl_pool_hold(pool, FTAG, &dp); + if (error) + return (error); + + error = dsl_dataset_hold_obj(dp, record->zi_objset, FTAG, &ds); + dsl_pool_rele(dp, FTAG); + if (error) + return (error); + + error = dmu_objset_from_ds(ds, &os); + dsl_dataset_rele(ds, FTAG); + if (error) + return (error); + + error = dnode_hold(os, record->zi_object, FTAG, &dn); + if (error) + return (error); + + /* + * Translate the range into block IDs + */ + if (record->zi_start != 0 || record->zi_end != -1ULL) { + record->zi_start >>= dn->dn_datablkshift; + record->zi_end >>= dn->dn_datablkshift; + } + if (record->zi_level > 0) { + if (record->zi_level >= dn->dn_nlevels) { + dnode_rele(dn, FTAG); + return (SET_ERROR(EDOM)); + } + + if (record->zi_start != 0 || record->zi_end != 0) { + int shift = dn->dn_indblkshift - SPA_BLKPTRSHIFT; + + for (int level = record->zi_level; level > 0; level--) { + record->zi_start >>= shift; + record->zi_end >>= shift; + } + } + } + + dnode_rele(dn, FTAG); + return (0); +} + /* * Create a new handler for the given record. We add it to the list, adding * a reference to the spa_t in the process. We increment zio_injection_enabled, @@ -698,6 +756,15 @@ zio_inject_fault(char *name, int flags, int *id, zinject_record_t *record) return (SET_ERROR(EINVAL)); } + /* + * If the supplied range was in bytes -- calculate the actual blkid + */ + if (flags & ZINJECT_CALC_RANGE) { + error = zio_calculate_range(name, record); + if (error != 0) + return (error); + } + if (!(flags & ZINJECT_NULL)) { /* * spa_inject_ref() will add an injection reference, which will |