]> git.proxmox.com Git - mirror_zfs.git/blobdiff - module/zfs/zio_inject.c
Add libzutil for libzfs or libzpool consumers
[mirror_zfs.git] / module / zfs / zio_inject.c
index 87d32a11556ba87ad8f9e8456a89c6a93b795a2b..7a7401ecda5702ba40debdd95234823ee30a464c 100644 (file)
@@ -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