]> git.proxmox.com Git - mirror_zfs.git/blobdiff - module/zfs/zio.c
Add linux kernel module support
[mirror_zfs.git] / module / zfs / zio.c
index 88d80af4e99ff2ccd8a3e812234933a8be16bd4b..70d3addf5cadcbfded19a17c0586d986f0fab342 100644 (file)
@@ -74,6 +74,7 @@ kmem_cache_t *zio_cache;
 kmem_cache_t *zio_link_cache;
 kmem_cache_t *zio_buf_cache[SPA_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT];
 kmem_cache_t *zio_data_buf_cache[SPA_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT];
+int zio_bulk_flags = 0;
 
 #ifdef _KERNEL
 extern vmem_t *zio_alloc_arena;
@@ -93,6 +94,8 @@ int zio_buf_debug_limit = 16384;
 int zio_buf_debug_limit = 0;
 #endif
 
+static inline void __zio_execute(zio_t *zio);
+
 void
 zio_init(void)
 {
@@ -134,12 +137,14 @@ zio_init(void)
                        (void) sprintf(name, "zio_buf_%lu", (ulong_t)size);
                        zio_buf_cache[c] = kmem_cache_create(name, size,
                            align, NULL, NULL, NULL, NULL, NULL,
-                           size > zio_buf_debug_limit ? KMC_NODEBUG : 0);
+                           (size > zio_buf_debug_limit ? KMC_NODEBUG : 0) |
+                           zio_bulk_flags);
 
                        (void) sprintf(name, "zio_data_buf_%lu", (ulong_t)size);
                        zio_data_buf_cache[c] = kmem_cache_create(name, size,
                            align, NULL, NULL, NULL, NULL, data_alloc_arena,
-                           size > zio_buf_debug_limit ? KMC_NODEBUG : 0);
+                           (size > zio_buf_debug_limit ? KMC_NODEBUG : 0) |
+                           zio_bulk_flags);
                }
        }
 
@@ -366,6 +371,7 @@ void
 zio_add_child(zio_t *pio, zio_t *cio)
 {
        zio_link_t *zl = kmem_cache_alloc(zio_link_cache, KM_SLEEP);
+       int w;
 
        /*
         * Logical I/Os can have logical, gang, or vdev children.
@@ -383,7 +389,7 @@ zio_add_child(zio_t *pio, zio_t *cio)
 
        ASSERT(pio->io_state[ZIO_WAIT_DONE] == 0);
 
-       for (int w = 0; w < ZIO_WAIT_TYPES; w++)
+       for (w = 0; w < ZIO_WAIT_TYPES; w++)
                pio->io_children[cio->io_child_type][w] += !cio->io_state[w];
 
        list_insert_head(&pio->io_child_list, zl);
@@ -435,7 +441,8 @@ zio_wait_for_children(zio_t *zio, enum zio_child child, enum zio_wait_type wait)
        return (waiting);
 }
 
-static void
+__attribute__((always_inline))
+static inline void
 zio_notify_parent(zio_t *pio, zio_t *zio, enum zio_wait_type wait)
 {
        uint64_t *countp = &pio->io_children[zio->io_child_type][wait];
@@ -449,7 +456,7 @@ zio_notify_parent(zio_t *pio, zio_t *zio, enum zio_wait_type wait)
        if (--*countp == 0 && pio->io_stall == countp) {
                pio->io_stall = NULL;
                mutex_exit(&pio->io_lock);
-               zio_execute(pio);
+               __zio_execute(pio);
        } else {
                mutex_exit(&pio->io_lock);
        }
@@ -993,8 +1000,8 @@ zio_write_bp_init(zio_t *zio)
         */
        if (bp->blk_birth == zio->io_txg && BP_GET_PSIZE(bp) == psize &&
            pass > SYNC_PASS_REWRITE) {
-               ASSERT(psize != 0);
                enum zio_stage gang_stages = zio->io_pipeline & ZIO_GANG_STAGES;
+               ASSERT(psize != 0);
                zio->io_pipeline = ZIO_REWRITE_PIPELINE | gang_stages;
                zio->io_flags |= ZIO_FLAG_IO_REWRITE;
        } else {
@@ -1048,7 +1055,7 @@ zio_taskq_dispatch(zio_t *zio, enum zio_taskq_type q, boolean_t cutinline)
 {
        spa_t *spa = zio->io_spa;
        zio_type_t t = zio->io_type;
-       int flags = TQ_SLEEP | (cutinline ? TQ_FRONT : 0);
+       int flags = TQ_NOSLEEP | (cutinline ? TQ_FRONT : 0);
 
        /*
         * If we're a config writer or a probe, the normal issue and
@@ -1072,8 +1079,9 @@ zio_taskq_dispatch(zio_t *zio, enum zio_taskq_type q, boolean_t cutinline)
                q++;
 
        ASSERT3U(q, <, ZIO_TASKQ_TYPES);
-       (void) taskq_dispatch(spa->spa_zio_taskq[t][q],
-           (task_func_t *)zio_execute, zio, flags);
+
+       while (taskq_dispatch(spa->spa_zio_taskq[t][q],
+           (task_func_t *)zio_execute, zio, flags) == 0); /* do nothing */
 }
 
 static boolean_t
@@ -1081,8 +1089,9 @@ zio_taskq_member(zio_t *zio, enum zio_taskq_type q)
 {
        kthread_t *executor = zio->io_executor;
        spa_t *spa = zio->io_spa;
+       zio_type_t t;
 
-       for (zio_type_t t = 0; t < ZIO_TYPES; t++)
+       for (t = 0; t < ZIO_TYPES; t++)
                if (taskq_member(spa->spa_zio_taskq[t][q], executor))
                        return (B_TRUE);
 
@@ -1118,8 +1127,23 @@ zio_interrupt(zio_t *zio)
  */
 static zio_pipe_stage_t *zio_pipeline[];
 
+/*
+ * zio_execute() is a wrapper around the static function
+ * __zio_execute() so that we can force  __zio_execute() to be
+ * inlined.  This reduces stack overhead which is important
+ * because __zio_execute() is called recursively in several zio
+ * code paths.  zio_execute() itself cannot be inlined because
+ * it is externally visible.
+ */
 void
 zio_execute(zio_t *zio)
+{
+       __zio_execute(zio);
+}
+
+__attribute__((always_inline))
+static inline void
+__zio_execute(zio_t *zio)
 {
        zio->io_executor = curthread;
 
@@ -1165,6 +1189,7 @@ zio_execute(zio_t *zio)
        }
 }
 
+
 /*
  * ==========================================================================
  * Initiate I/O, either sync or async
@@ -1180,7 +1205,7 @@ zio_wait(zio_t *zio)
 
        zio->io_waiter = curthread;
 
-       zio_execute(zio);
+       __zio_execute(zio);
 
        mutex_enter(&zio->io_lock);
        while (zio->io_executor != NULL)
@@ -1210,7 +1235,7 @@ zio_nowait(zio_t *zio)
                zio_add_child(spa->spa_async_zio_root, zio);
        }
 
-       zio_execute(zio);
+       __zio_execute(zio);
 }
 
 /*
@@ -1223,6 +1248,7 @@ static void
 zio_reexecute(zio_t *pio)
 {
        zio_t *cio, *cio_next;
+       int c, w;
 
        ASSERT(pio->io_child_type == ZIO_CHILD_LOGICAL);
        ASSERT(pio->io_orig_stage == ZIO_STAGE_OPEN);
@@ -1234,9 +1260,9 @@ zio_reexecute(zio_t *pio)
        pio->io_pipeline = pio->io_orig_pipeline;
        pio->io_reexecute = 0;
        pio->io_error = 0;
-       for (int w = 0; w < ZIO_WAIT_TYPES; w++)
+       for (w = 0; w < ZIO_WAIT_TYPES; w++)
                pio->io_state[w] = 0;
-       for (int c = 0; c < ZIO_CHILD_TYPES; c++)
+       for (c = 0; c < ZIO_CHILD_TYPES; c++)
                pio->io_child_error[c] = 0;
 
        if (IO_IS_ALLOCATING(pio))
@@ -1252,7 +1278,7 @@ zio_reexecute(zio_t *pio)
        for (cio = zio_walk_children(pio); cio != NULL; cio = cio_next) {
                cio_next = zio_walk_children(pio);
                mutex_enter(&pio->io_lock);
-               for (int w = 0; w < ZIO_WAIT_TYPES; w++)
+               for (w = 0; w < ZIO_WAIT_TYPES; w++)
                        pio->io_children[cio->io_child_type][w]++;
                mutex_exit(&pio->io_lock);
                zio_reexecute(cio);
@@ -1264,7 +1290,7 @@ zio_reexecute(zio_t *pio)
         * responsibility of the caller to wait on him.
         */
        if (!(pio->io_flags & ZIO_FLAG_GODFATHER))
-               zio_execute(pio);
+               __zio_execute(pio);
 }
 
 void
@@ -1488,8 +1514,9 @@ static void
 zio_gang_node_free(zio_gang_node_t **gnpp)
 {
        zio_gang_node_t *gn = *gnpp;
+       int g;
 
-       for (int g = 0; g < SPA_GBH_NBLKPTRS; g++)
+       for (g = 0; g < SPA_GBH_NBLKPTRS; g++)
                ASSERT(gn->gn_child[g] == NULL);
 
        zio_buf_free(gn->gn_gbh, SPA_GANGBLOCKSIZE);
@@ -1501,11 +1528,12 @@ static void
 zio_gang_tree_free(zio_gang_node_t **gnpp)
 {
        zio_gang_node_t *gn = *gnpp;
+       int g;
 
        if (gn == NULL)
                return;
 
-       for (int g = 0; g < SPA_GBH_NBLKPTRS; g++)
+       for (g = 0; g < SPA_GBH_NBLKPTRS; g++)
                zio_gang_tree_free(&gn->gn_child[g]);
 
        zio_gang_node_free(gnpp);
@@ -1530,6 +1558,7 @@ zio_gang_tree_assemble_done(zio_t *zio)
        zio_t *gio = zio->io_gang_leader;
        zio_gang_node_t *gn = zio->io_private;
        blkptr_t *bp = zio->io_bp;
+       int g;
 
        ASSERT(gio == zio_unique_parent(zio));
        ASSERT(zio->io_child_count == 0);
@@ -1544,7 +1573,7 @@ zio_gang_tree_assemble_done(zio_t *zio)
        ASSERT(zio->io_size == SPA_GANGBLOCKSIZE);
        ASSERT(gn->gn_gbh->zg_tail.zec_magic == ZEC_MAGIC);
 
-       for (int g = 0; g < SPA_GBH_NBLKPTRS; g++) {
+       for (g = 0; g < SPA_GBH_NBLKPTRS; g++) {
                blkptr_t *gbp = &gn->gn_gbh->zg_blkptr[g];
                if (!BP_IS_GANG(gbp))
                        continue;
@@ -1557,6 +1586,7 @@ zio_gang_tree_issue(zio_t *pio, zio_gang_node_t *gn, blkptr_t *bp, void *data)
 {
        zio_t *gio = pio->io_gang_leader;
        zio_t *zio;
+       int g;
 
        ASSERT(BP_IS_GANG(bp) == !!gn);
        ASSERT(BP_GET_CHECKSUM(bp) == BP_GET_CHECKSUM(gio->io_bp));
@@ -1571,7 +1601,7 @@ zio_gang_tree_issue(zio_t *pio, zio_gang_node_t *gn, blkptr_t *bp, void *data)
        if (gn != NULL) {
                ASSERT(gn->gn_gbh->zg_tail.zec_magic == ZEC_MAGIC);
 
-               for (int g = 0; g < SPA_GBH_NBLKPTRS; g++) {
+               for (g = 0; g < SPA_GBH_NBLKPTRS; g++) {
                        blkptr_t *gbp = &gn->gn_gbh->zg_blkptr[g];
                        if (BP_IS_HOLE(gbp))
                                continue;
@@ -1627,10 +1657,11 @@ static void
 zio_write_gang_member_ready(zio_t *zio)
 {
        zio_t *pio = zio_unique_parent(zio);
-       zio_t *gio = zio->io_gang_leader;
+       ASSERTV(zio_t *gio = zio->io_gang_leader;)
        dva_t *cdva = zio->io_bp->blk_dva;
        dva_t *pdva = pio->io_bp->blk_dva;
        uint64_t asize;
+       int d;
 
        if (BP_IS_HOLE(zio->io_bp))
                return;
@@ -1644,7 +1675,7 @@ zio_write_gang_member_ready(zio_t *zio)
        ASSERT3U(BP_GET_NDVAS(zio->io_bp), <=, BP_GET_NDVAS(pio->io_bp));
 
        mutex_enter(&pio->io_lock);
-       for (int d = 0; d < BP_GET_NDVAS(zio->io_bp); d++) {
+       for (d = 0; d < BP_GET_NDVAS(zio->io_bp); d++) {
                ASSERT(DVA_GET_GANG(&pdva[d]));
                asize = DVA_GET_ASIZE(&pdva[d]);
                asize += DVA_GET_ASIZE(&cdva[d]);
@@ -1668,7 +1699,7 @@ zio_write_gang_block(zio_t *pio)
        int copies = gio->io_prop.zp_copies;
        int gbh_copies = MIN(copies + 1, spa_max_replication(spa));
        zio_prop_t zp;
-       int error;
+       int g, error;
 
        error = metaslab_alloc(spa, spa_normal_class(spa), SPA_GANGBLOCKSIZE,
            bp, gbh_copies, txg, pio == gio ? NULL : gio->io_bp,
@@ -1698,7 +1729,7 @@ zio_write_gang_block(zio_t *pio)
        /*
         * Create and nowait the gang children.
         */
-       for (int g = 0; resid != 0; resid -= lsize, g++) {
+       for (g = 0; resid != 0; resid -= lsize, g++) {
                lsize = P2ROUNDUP(resid / (SPA_GBH_NBLKPTRS - g),
                    SPA_MINBLOCKSIZE);
                ASSERT(lsize >= SPA_MINBLOCKSIZE && lsize <= resid);
@@ -1756,6 +1787,7 @@ static int
 zio_ddt_read_start(zio_t *zio)
 {
        blkptr_t *bp = zio->io_bp;
+       int p;
 
        ASSERT(BP_GET_DEDUP(bp));
        ASSERT(BP_GET_PSIZE(bp) == zio->io_size);
@@ -1774,7 +1806,7 @@ zio_ddt_read_start(zio_t *zio)
                if (ddp_self == NULL)
                        return (ZIO_PIPELINE_CONTINUE);
 
-               for (int p = 0; p < DDT_PHYS_TYPES; p++, ddp++) {
+               for (p = 0; p < DDT_PHYS_TYPES; p++, ddp++) {
                        if (ddp->ddp_phys_birth == 0 || ddp == ddp_self)
                                continue;
                        ddt_bp_create(ddt->ddt_checksum, &dde->dde_key, ddp,
@@ -1836,6 +1868,7 @@ static boolean_t
 zio_ddt_collision(zio_t *zio, ddt_t *ddt, ddt_entry_t *dde)
 {
        spa_t *spa = zio->io_spa;
+       int p;
 
        /*
         * Note: we compare the original data, not the transformed data,
@@ -1843,7 +1876,7 @@ zio_ddt_collision(zio_t *zio, ddt_t *ddt, ddt_entry_t *dde)
         * pushed the I/O transforms.  That's an important optimization
         * because otherwise we'd compress/encrypt all dmu_sync() data twice.
         */
-       for (int p = DDT_PHYS_SINGLE; p <= DDT_PHYS_TRIPLE; p++) {
+       for (p = DDT_PHYS_SINGLE; p <= DDT_PHYS_TRIPLE; p++) {
                zio_t *lio = dde->dde_lead_zio[p];
 
                if (lio != NULL) {
@@ -1853,7 +1886,7 @@ zio_ddt_collision(zio_t *zio, ddt_t *ddt, ddt_entry_t *dde)
                }
        }
 
-       for (int p = DDT_PHYS_SINGLE; p <= DDT_PHYS_TRIPLE; p++) {
+       for (p = DDT_PHYS_SINGLE; p <= DDT_PHYS_TRIPLE; p++) {
                ddt_phys_t *ddp = &dde->dde_phys[p];
 
                if (ddp->ddp_phys_birth != 0) {
@@ -1939,12 +1972,12 @@ static void
 zio_ddt_ditto_write_done(zio_t *zio)
 {
        int p = DDT_PHYS_DITTO;
-       zio_prop_t *zp = &zio->io_prop;
        blkptr_t *bp = zio->io_bp;
        ddt_t *ddt = ddt_select(zio->io_spa, bp);
        ddt_entry_t *dde = zio->io_private;
        ddt_phys_t *ddp = &dde->dde_phys[p];
        ddt_key_t *ddk = &dde->dde_key;
+       ASSERTV(zio_prop_t *zp = &zio->io_prop);
 
        ddt_enter(ddt);
 
@@ -2161,6 +2194,8 @@ zio_dva_claim(zio_t *zio)
 static void
 zio_dva_unallocate(zio_t *zio, zio_gang_node_t *gn, blkptr_t *bp)
 {
+       int g;
+
        ASSERT(bp->blk_birth == zio->io_txg || BP_IS_HOLE(bp));
        ASSERT(zio->io_bp_override == NULL);
 
@@ -2168,7 +2203,7 @@ zio_dva_unallocate(zio_t *zio, zio_gang_node_t *gn, blkptr_t *bp)
                metaslab_free(zio->io_spa, bp, bp->blk_birth, B_TRUE);
 
        if (gn != NULL) {
-               for (int g = 0; g < SPA_GBH_NBLKPTRS; g++) {
+               for (g = 0; g < SPA_GBH_NBLKPTRS; g++) {
                        zio_dva_unallocate(zio, gn->gn_child[g],
                            &gn->gn_gbh->zg_blkptr[g]);
                }
@@ -2247,6 +2282,26 @@ zio_vdev_io_start(zio_t *zio)
                return (vdev_mirror_ops.vdev_op_io_start(zio));
        }
 
+       /*
+        * We keep track of time-sensitive I/Os so that the scan thread
+        * can quickly react to certain workloads.  In particular, we care
+        * about non-scrubbing, top-level reads and writes with the following
+        * characteristics:
+        *      - synchronous writes of user data to non-slog devices
+        *      - any reads of user data
+        * When these conditions are met, adjust the timestamp of spa_last_io
+        * which allows the scan thread to adjust its workload accordingly.
+        */
+       if (!(zio->io_flags & ZIO_FLAG_SCAN_THREAD) && zio->io_bp != NULL &&
+           vd == vd->vdev_top && !vd->vdev_islog &&
+           zio->io_bookmark.zb_objset != DMU_META_OBJSET &&
+           zio->io_txg != spa_syncing_txg(spa)) {
+               uint64_t old = spa->spa_last_io;
+               uint64_t new = ddi_get_lbolt64();
+               if (old != new)
+                       (void) atomic_cas_64(&spa->spa_last_io, old, new);
+       }
+
        align = 1ULL << vd->vdev_top->vdev_ashift;
 
        if (P2PHASE(zio->io_size, align) != 0) {
@@ -2262,7 +2317,7 @@ zio_vdev_io_start(zio_t *zio)
 
        ASSERT(P2PHASE(zio->io_offset, align) == 0);
        ASSERT(P2PHASE(zio->io_size, align) == 0);
-       ASSERT(zio->io_type != ZIO_TYPE_WRITE || spa_writeable(spa));
+       VERIFY(zio->io_type != ZIO_TYPE_WRITE || spa_writeable(spa));
 
        /*
         * If this is a repair I/O, and there's no self-healing involved --
@@ -2629,12 +2684,8 @@ zio_ready(zio_t *zio)
 static int
 zio_done(zio_t *zio)
 {
-       spa_t *spa = zio->io_spa;
-       zio_t *lio = zio->io_logical;
-       blkptr_t *bp = zio->io_bp;
-       vdev_t *vd = zio->io_vd;
-       uint64_t psize = zio->io_size;
        zio_t *pio, *pio_next;
+       int c, w;
 
        /*
         * If our children haven't all completed,
@@ -2646,22 +2697,22 @@ zio_done(zio_t *zio)
            zio_wait_for_children(zio, ZIO_CHILD_LOGICAL, ZIO_WAIT_DONE))
                return (ZIO_PIPELINE_STOP);
 
-       for (int c = 0; c < ZIO_CHILD_TYPES; c++)
-               for (int w = 0; w < ZIO_WAIT_TYPES; w++)
+       for (c = 0; c < ZIO_CHILD_TYPES; c++)
+               for (w = 0; w < ZIO_WAIT_TYPES; w++)
                        ASSERT(zio->io_children[c][w] == 0);
 
-       if (bp != NULL) {
-               ASSERT(bp->blk_pad[0] == 0);
-               ASSERT(bp->blk_pad[1] == 0);
-               ASSERT(bcmp(bp, &zio->io_bp_copy, sizeof (blkptr_t)) == 0 ||
-                   (bp == zio_unique_parent(zio)->io_bp));
-               if (zio->io_type == ZIO_TYPE_WRITE && !BP_IS_HOLE(bp) &&
+       if (zio->io_bp != NULL) {
+               ASSERT(zio->io_bp->blk_pad[0] == 0);
+               ASSERT(zio->io_bp->blk_pad[1] == 0);
+               ASSERT(bcmp(zio->io_bp, &zio->io_bp_copy, sizeof (blkptr_t)) == 0 ||
+                   (zio->io_bp == zio_unique_parent(zio)->io_bp));
+               if (zio->io_type == ZIO_TYPE_WRITE && !BP_IS_HOLE(zio->io_bp) &&
                    zio->io_bp_override == NULL &&
                    !(zio->io_flags & ZIO_FLAG_IO_REPAIR)) {
-                       ASSERT(!BP_SHOULD_BYTESWAP(bp));
-                       ASSERT3U(zio->io_prop.zp_copies, <=, BP_GET_NDVAS(bp));
-                       ASSERT(BP_COUNT_GANG(bp) == 0 ||
-                           (BP_COUNT_GANG(bp) == BP_GET_NDVAS(bp)));
+                       ASSERT(!BP_SHOULD_BYTESWAP(zio->io_bp));
+                       ASSERT3U(zio->io_prop.zp_copies, <=, BP_GET_NDVAS(zio->io_bp));
+                       ASSERT(BP_COUNT_GANG(zio->io_bp) == 0 ||
+                           (BP_COUNT_GANG(zio->io_bp) == BP_GET_NDVAS(zio->io_bp)));
                }
        }
 
@@ -2680,13 +2731,13 @@ zio_done(zio_t *zio)
                while (zio->io_cksum_report != NULL) {
                        zio_cksum_report_t *zcr = zio->io_cksum_report;
                        uint64_t align = zcr->zcr_align;
-                       uint64_t asize = P2ROUNDUP(psize, align);
+                       uint64_t asize = P2ROUNDUP(zio->io_size, align);
                        char *abuf = zio->io_data;
 
-                       if (asize != psize) {
+                       if (asize != zio->io_size) {
                                abuf = zio_buf_alloc(asize);
-                               bcopy(zio->io_data, abuf, psize);
-                               bzero(abuf + psize, asize - psize);
+                               bcopy(zio->io_data, abuf, zio->io_size);
+                               bzero(abuf + zio->io_size, asize - zio->io_size);
                        }
 
                        zio->io_cksum_report = zcr->zcr_next;
@@ -2694,14 +2745,14 @@ zio_done(zio_t *zio)
                        zcr->zcr_finish(zcr, abuf);
                        zfs_ereport_free_checksum(zcr);
 
-                       if (asize != psize)
+                       if (asize != zio->io_size)
                                zio_buf_free(abuf, asize);
                }
        }
 
        zio_pop_transforms(zio);        /* note: may set zio->io_error */
 
-       vdev_stat_update(zio, psize);
+       vdev_stat_update(zio, zio->io_size);
 
        if (zio->io_error) {
                /*
@@ -2710,28 +2761,30 @@ zio_done(zio_t *zio)
                 * at the block level.  We ignore these errors if the
                 * device is currently unavailable.
                 */
-               if (zio->io_error != ECKSUM && vd != NULL && !vdev_is_dead(vd))
-                       zfs_ereport_post(FM_EREPORT_ZFS_IO, spa, vd, zio, 0, 0);
+               if (zio->io_error != ECKSUM && zio->io_vd != NULL &&
+                       !vdev_is_dead(zio->io_vd))
+                       zfs_ereport_post(FM_EREPORT_ZFS_IO, zio->io_spa,
+                                               zio->io_vd, zio, 0, 0);
 
                if ((zio->io_error == EIO || !(zio->io_flags &
                    (ZIO_FLAG_SPECULATIVE | ZIO_FLAG_DONT_PROPAGATE))) &&
-                   zio == lio) {
+                   zio == zio->io_logical) {
                        /*
                         * For logical I/O requests, tell the SPA to log the
                         * error and generate a logical data ereport.
                         */
-                       spa_log_error(spa, zio);
-                       zfs_ereport_post(FM_EREPORT_ZFS_DATA, spa, NULL, zio,
+                       spa_log_error(zio->io_spa, zio);
+                       zfs_ereport_post(FM_EREPORT_ZFS_DATA, zio->io_spa, NULL, zio,
                            0, 0);
                }
        }
 
-       if (zio->io_error && zio == lio) {
+       if (zio->io_error && zio == zio->io_logical) {
                /*
                 * Determine whether zio should be reexecuted.  This will
                 * propagate all the way to the root via zio_notify_parent().
                 */
-               ASSERT(vd == NULL && bp != NULL);
+               ASSERT(zio->io_vd == NULL && zio->io_bp != NULL);
                ASSERT(zio->io_child_type == ZIO_CHILD_LOGICAL);
 
                if (IO_IS_ALLOCATING(zio) &&
@@ -2744,9 +2797,10 @@ zio_done(zio_t *zio)
 
                if ((zio->io_type == ZIO_TYPE_READ ||
                    zio->io_type == ZIO_TYPE_FREE) &&
+                   !(zio->io_flags & ZIO_FLAG_SCAN_THREAD) &&
                    zio->io_error == ENXIO &&
-                   spa_load_state(spa) == SPA_LOAD_NONE &&
-                   spa_get_failmode(spa) != ZIO_FAILURE_MODE_CONTINUE)
+                   spa_load_state(zio->io_spa) == SPA_LOAD_NONE &&
+                   spa_get_failmode(zio->io_spa) != ZIO_FAILURE_MODE_CONTINUE)
                        zio->io_reexecute |= ZIO_REEXECUTE_SUSPEND;
 
                if (!(zio->io_flags & ZIO_FLAG_CANFAIL) && !zio->io_reexecute)
@@ -2772,7 +2826,7 @@ zio_done(zio_t *zio)
        if ((zio->io_error || zio->io_reexecute) &&
            IO_IS_ALLOCATING(zio) && zio->io_gang_leader == zio &&
            !(zio->io_flags & ZIO_FLAG_IO_REWRITE))
-               zio_dva_unallocate(zio, zio->io_gang_tree, bp);
+               zio_dva_unallocate(zio, zio->io_gang_tree, zio->io_bp);
 
        zio_gang_tree_free(&zio->io_gang_tree);
 
@@ -2837,14 +2891,14 @@ zio_done(zio_t *zio)
                         * We'd fail again if we reexecuted now, so suspend
                         * until conditions improve (e.g. device comes online).
                         */
-                       zio_suspend(spa, zio);
+                       zio_suspend(zio->io_spa, zio);
                } else {
                        /*
                         * Reexecution is potentially a huge amount of work.
                         * Hand it off to the otherwise-unused claim taskq.
                         */
                        (void) taskq_dispatch(
-                           spa->spa_zio_taskq[ZIO_TYPE_CLAIM][ZIO_TASKQ_ISSUE],
+                           zio->io_spa->spa_zio_taskq[ZIO_TYPE_CLAIM][ZIO_TASKQ_ISSUE],
                            (task_func_t *)zio_reexecute, zio, TQ_SLEEP);
                }
                return (ZIO_PIPELINE_STOP);
@@ -2924,3 +2978,19 @@ static zio_pipe_stage_t *zio_pipeline[] = {
        zio_checksum_verify,
        zio_done
 };
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+/* Fault injection */
+EXPORT_SYMBOL(zio_injection_enabled);
+EXPORT_SYMBOL(zio_inject_fault);
+EXPORT_SYMBOL(zio_inject_list_next);
+EXPORT_SYMBOL(zio_clear_fault);
+EXPORT_SYMBOL(zio_handle_fault_injection);
+EXPORT_SYMBOL(zio_handle_device_injection);
+EXPORT_SYMBOL(zio_handle_label_injection);
+EXPORT_SYMBOL(zio_priority_table);
+EXPORT_SYMBOL(zio_type_name);
+
+module_param(zio_bulk_flags, int, 0644);
+MODULE_PARM_DESC(zio_bulk_flags, "Additional flags to pass to bulk buffers");
+#endif