]> git.proxmox.com Git - mirror_zfs.git/blobdiff - module/zfs/zio.c
OpenZFS 7614, 9064 - zfs device evacuation/removal
[mirror_zfs.git] / module / zfs / zio.c
index 92e5a8dd8303ddbc9b170c925f7d513aa748dd84..5259a0c6f01df9b5bf5d698730d3f6835e3f6cf7 100644 (file)
@@ -402,6 +402,8 @@ zio_decrypt(zio_t *zio, abd_t *data, uint64_t size)
        int ret;
        void *tmp;
        blkptr_t *bp = zio->io_bp;
+       spa_t *spa = zio->io_spa;
+       uint64_t dsobj = zio->io_bookmark.zb_objset;
        uint64_t lsize = BP_GET_LSIZE(bp);
        dmu_object_type_t ot = BP_GET_TYPE(bp);
        uint8_t salt[ZIO_DATA_SALT_LEN];
@@ -460,13 +462,12 @@ zio_decrypt(zio_t *zio, abd_t *data, uint64_t size)
         */
        if (BP_IS_AUTHENTICATED(bp)) {
                if (ot == DMU_OT_OBJSET) {
-                       ret = spa_do_crypt_objset_mac_abd(B_FALSE, zio->io_spa,
-                           zio->io_bookmark.zb_objset, zio->io_abd, size,
-                           BP_SHOULD_BYTESWAP(bp));
+                       ret = spa_do_crypt_objset_mac_abd(B_FALSE, spa,
+                           dsobj, zio->io_abd, size, BP_SHOULD_BYTESWAP(bp));
                } else {
                        zio_crypt_decode_mac_bp(bp, mac);
-                       ret = spa_do_crypt_mac_abd(B_FALSE, zio->io_spa,
-                           zio->io_bookmark.zb_objset, zio->io_abd, size, mac);
+                       ret = spa_do_crypt_mac_abd(B_FALSE, spa, dsobj,
+                           zio->io_abd, size, mac);
                }
                abd_copy(data, zio->io_abd, size);
 
@@ -486,9 +487,8 @@ zio_decrypt(zio_t *zio, abd_t *data, uint64_t size)
                zio_crypt_decode_mac_bp(bp, mac);
        }
 
-       ret = spa_do_crypt_abd(B_FALSE, zio->io_spa, zio->io_bookmark.zb_objset,
-           bp, bp->blk_birth, size, data, zio->io_abd, iv, mac, salt,
-           &no_crypt);
+       ret = spa_do_crypt_abd(B_FALSE, spa, dsobj, bp, bp->blk_birth,
+           size, data, zio->io_abd, iv, mac, salt, &no_crypt);
        if (no_crypt)
                abd_copy(data, zio->io_abd, size);
 
@@ -506,10 +506,10 @@ error:
         * the io_error. If this was not a speculative zio, create an ereport.
         */
        if (ret == ECKSUM) {
-               ret = SET_ERROR(EIO);
+               zio->io_error = SET_ERROR(EIO);
                if ((zio->io_flags & ZIO_FLAG_SPECULATIVE) == 0) {
                        zfs_ereport_post(FM_EREPORT_ZFS_AUTHENTICATION,
-                           zio->io_spa, NULL, &zio->io_bookmark, zio, 0, 0);
+                           spa, NULL, &zio->io_bookmark, zio, 0, 0);
                }
        } else {
                zio->io_error = ret;
@@ -539,6 +539,8 @@ zio_walk_children(zio_t *pio, zio_link_t **zl)
 {
        list_t *cl = &pio->io_child_list;
 
+       ASSERT(MUTEX_HELD(&pio->io_lock));
+
        *zl = (*zl == NULL) ? list_head(cl) : list_next(cl, *zl);
        if (*zl == NULL)
                return (NULL);
@@ -573,8 +575,8 @@ zio_add_child(zio_t *pio, zio_t *cio)
        zl->zl_parent = pio;
        zl->zl_child = cio;
 
-       mutex_enter(&cio->io_lock);
        mutex_enter(&pio->io_lock);
+       mutex_enter(&cio->io_lock);
 
        ASSERT(pio->io_state[ZIO_WAIT_DONE] == 0);
 
@@ -587,8 +589,8 @@ zio_add_child(zio_t *pio, zio_t *cio)
        pio->io_child_count++;
        cio->io_parent_count++;
 
-       mutex_exit(&pio->io_lock);
        mutex_exit(&cio->io_lock);
+       mutex_exit(&pio->io_lock);
 }
 
 static void
@@ -597,8 +599,8 @@ zio_remove_child(zio_t *pio, zio_t *cio, zio_link_t *zl)
        ASSERT(zl->zl_parent == pio);
        ASSERT(zl->zl_child == cio);
 
-       mutex_enter(&cio->io_lock);
        mutex_enter(&pio->io_lock);
+       mutex_enter(&cio->io_lock);
 
        list_remove(&pio->io_child_list, zl);
        list_remove(&cio->io_parent_list, zl);
@@ -606,27 +608,32 @@ zio_remove_child(zio_t *pio, zio_t *cio, zio_link_t *zl)
        pio->io_child_count--;
        cio->io_parent_count--;
 
-       mutex_exit(&pio->io_lock);
        mutex_exit(&cio->io_lock);
+       mutex_exit(&pio->io_lock);
        kmem_cache_free(zio_link_cache, zl);
 }
 
 static boolean_t
-zio_wait_for_children(zio_t *zio, enum zio_child child, enum zio_wait_type wait)
+zio_wait_for_children(zio_t *zio, uint8_t childbits, enum zio_wait_type wait)
 {
-       uint64_t *countp = &zio->io_children[child][wait];
        boolean_t waiting = B_FALSE;
 
        mutex_enter(&zio->io_lock);
        ASSERT(zio->io_stall == NULL);
-       if (*countp != 0) {
-               zio->io_stage >>= 1;
-               ASSERT3U(zio->io_stage, !=, ZIO_STAGE_OPEN);
-               zio->io_stall = countp;
-               waiting = B_TRUE;
+       for (int c = 0; c < ZIO_CHILD_TYPES; c++) {
+               if (!(ZIO_CHILD_BIT_IS_SET(childbits, c)))
+                       continue;
+
+               uint64_t *countp = &zio->io_children[c][wait];
+               if (*countp != 0) {
+                       zio->io_stage >>= 1;
+                       ASSERT3U(zio->io_stage, !=, ZIO_STAGE_OPEN);
+                       zio->io_stall = countp;
+                       waiting = B_TRUE;
+                       break;
+               }
        }
        mutex_exit(&zio->io_lock);
-
        return (waiting);
 }
 
@@ -1011,6 +1018,8 @@ void
 zio_free(spa_t *spa, uint64_t txg, const blkptr_t *bp)
 {
 
+       zfs_blkptr_verify(spa, bp);
+
        /*
         * The check for EMBEDDED is a performance optimization.  We
         * process the free here (by ignoring it) rather than
@@ -1074,7 +1083,7 @@ zio_claim(zio_t *pio, spa_t *spa, uint64_t txg, const blkptr_t *bp,
 {
        zio_t *zio;
 
-       dprintf_bp(bp, "claiming in txg %llu", txg);
+       zfs_blkptr_verify(spa, bp);
 
        if (BP_IS_EMBEDDED(bp))
                return (zio_null(pio, spa, NULL, NULL, NULL, 0));
@@ -1193,8 +1202,26 @@ zio_vdev_child_io(zio_t *pio, blkptr_t *bp, vdev_t *vd, uint64_t offset,
        enum zio_stage pipeline = ZIO_VDEV_CHILD_PIPELINE;
        zio_t *zio;
 
-       ASSERT(vd->vdev_parent ==
-           (pio->io_vd ? pio->io_vd : pio->io_spa->spa_root_vdev));
+       /*
+        * vdev child I/Os do not propagate their error to the parent.
+        * Therefore, for correct operation the caller *must* check for
+        * and handle the error in the child i/o's done callback.
+        * The only exceptions are i/os that we don't care about
+        * (OPTIONAL or REPAIR).
+        */
+       ASSERT((flags & ZIO_FLAG_OPTIONAL) || (flags & ZIO_FLAG_IO_REPAIR) ||
+           done != NULL);
+
+       /*
+        * In the common case, where the parent zio was to a normal vdev,
+        * the child zio must be to a child vdev of that vdev.  Otherwise,
+        * the child zio must be to a top-level vdev.
+        */
+       if (pio->io_vd != NULL && pio->io_vd->vdev_ops != &vdev_indirect_ops) {
+               ASSERT3P(vd->vdev_parent, ==, pio->io_vd);
+       } else {
+               ASSERT3P(vd, ==, vd->vdev_top);
+       }
 
        if (type == ZIO_TYPE_READ && bp != NULL) {
                /*
@@ -1207,10 +1234,12 @@ zio_vdev_child_io(zio_t *pio, blkptr_t *bp, vdev_t *vd, uint64_t offset,
                pio->io_pipeline &= ~ZIO_STAGE_CHECKSUM_VERIFY;
        }
 
-       if (vd->vdev_children == 0)
+       if (vd->vdev_ops->vdev_op_leaf) {
+               ASSERT0(vd->vdev_children);
                offset += VDEV_LABEL_START_SIZE;
+       }
 
-       flags |= ZIO_VDEV_CHILD_FLAGS(pio) | ZIO_FLAG_DONT_PROPAGATE;
+       flags |= ZIO_VDEV_CHILD_FLAGS(pio);
 
        /*
         * If we've decided to do a repair, the write is not speculative --
@@ -1311,6 +1340,8 @@ zio_read_bp_init(zio_t *zio)
        uint64_t psize =
            BP_IS_EMBEDDED(bp) ? BPE_GET_PSIZE(bp) : BP_GET_PSIZE(bp);
 
+       ASSERT3P(zio->io_bp, ==, &zio->io_bp_copy);
+
        if (BP_GET_COMPRESS(bp) != ZIO_COMPRESS_OFF &&
            zio->io_child_type == ZIO_CHILD_LOGICAL &&
            !(zio->io_flags & ZIO_FLAG_RAW_COMPRESS)) {
@@ -1334,6 +1365,7 @@ zio_read_bp_init(zio_t *zio)
                abd_return_buf_copy(zio->io_abd, data, psize);
        } else {
                ASSERT(!BP_IS_EMBEDDED(bp));
+               ASSERT3P(zio->io_bp, ==, &zio->io_bp_copy);
        }
 
        if (!DMU_OT_IS_METADATA(BP_GET_TYPE(bp)) && BP_GET_LEVEL(bp) == 0)
@@ -1423,9 +1455,10 @@ zio_write_compress(zio_t *zio)
         * If our children haven't all reached the ready stage,
         * wait for them and then repeat this pipeline stage.
         */
-       if (zio_wait_for_children(zio, ZIO_CHILD_GANG, ZIO_WAIT_READY) ||
-           zio_wait_for_children(zio, ZIO_CHILD_LOGICAL, ZIO_WAIT_READY))
+       if (zio_wait_for_children(zio, ZIO_CHILD_LOGICAL_BIT |
+           ZIO_CHILD_GANG_BIT, ZIO_WAIT_READY)) {
                return (ZIO_PIPELINE_STOP);
+       }
 
        if (!IO_IS_ALLOCATING(zio))
                return (ZIO_PIPELINE_CONTINUE);
@@ -1524,9 +1557,21 @@ zio_write_compress(zio_t *zio)
                *bp = zio->io_bp_orig;
                zio->io_pipeline = zio->io_orig_pipeline;
 
+       } else if ((zio->io_flags & ZIO_FLAG_RAW_ENCRYPT) != 0 &&
+           zp->zp_type == DMU_OT_DNODE) {
+               /*
+                * The DMU actually relies on the zio layer's compression
+                * to free metadnode blocks that have had all contained
+                * dnodes freed. As a result, even when doing a raw
+                * receive, we must check whether the block can be compressed
+                * to a hole.
+                */
+               psize = zio_compress_data(ZIO_COMPRESS_EMPTY,
+                   zio->io_abd, NULL, lsize);
+               if (psize == 0)
+                       compress = ZIO_COMPRESS_OFF;
        } else {
                ASSERT3U(psize, !=, 0);
-
        }
 
        /*
@@ -1594,6 +1639,8 @@ zio_free_bp_init(zio_t *zio)
                        zio->io_pipeline = ZIO_DDT_FREE_PIPELINE;
        }
 
+       ASSERT3P(zio->io_bp, ==, &zio->io_bp_copy);
+
        return (ZIO_PIPELINE_CONTINUE);
 }
 
@@ -1746,6 +1793,80 @@ zio_delay_interrupt(zio_t *zio)
        zio_interrupt(zio);
 }
 
+static void
+zio_deadman_impl(zio_t *pio)
+{
+       zio_t *cio, *cio_next;
+       zio_link_t *zl = NULL;
+       vdev_t *vd = pio->io_vd;
+
+       if (vd != NULL && vd->vdev_ops->vdev_op_leaf) {
+               vdev_queue_t *vq = &vd->vdev_queue;
+               zbookmark_phys_t *zb = &pio->io_bookmark;
+               uint64_t delta = gethrtime() - pio->io_timestamp;
+               uint64_t failmode = spa_get_deadman_failmode(pio->io_spa);
+
+               zfs_dbgmsg("slow zio: zio=%p timestamp=%llu "
+                   "delta=%llu queued=%llu io=%llu "
+                   "path=%s last=%llu "
+                   "type=%d priority=%d flags=0x%x "
+                   "stage=0x%x pipeline=0x%x pipeline-trace=0x%x "
+                   "objset=%llu object=%llu level=%llu blkid=%llu "
+                   "offset=%llu size=%llu error=%d",
+                   pio, pio->io_timestamp,
+                   delta, pio->io_delta, pio->io_delay,
+                   vd->vdev_path, vq->vq_io_complete_ts,
+                   pio->io_type, pio->io_priority, pio->io_flags,
+                   pio->io_state, pio->io_pipeline, pio->io_pipeline_trace,
+                   zb->zb_objset, zb->zb_object, zb->zb_level, zb->zb_blkid,
+                   pio->io_offset, pio->io_size, pio->io_error);
+               zfs_ereport_post(FM_EREPORT_ZFS_DEADMAN,
+                   pio->io_spa, vd, zb, pio, 0, 0);
+
+               if (failmode == ZIO_FAILURE_MODE_CONTINUE &&
+                   taskq_empty_ent(&pio->io_tqent)) {
+                       zio_interrupt(pio);
+               }
+       }
+
+       mutex_enter(&pio->io_lock);
+       for (cio = zio_walk_children(pio, &zl); cio != NULL; cio = cio_next) {
+               cio_next = zio_walk_children(pio, &zl);
+               zio_deadman_impl(cio);
+       }
+       mutex_exit(&pio->io_lock);
+}
+
+/*
+ * Log the critical information describing this zio and all of its children
+ * using the zfs_dbgmsg() interface then post deadman event for the ZED.
+ */
+void
+zio_deadman(zio_t *pio, char *tag)
+{
+       spa_t *spa = pio->io_spa;
+       char *name = spa_name(spa);
+
+       if (!zfs_deadman_enabled || spa_suspended(spa))
+               return;
+
+       zio_deadman_impl(pio);
+
+       switch (spa_get_deadman_failmode(spa)) {
+       case ZIO_FAILURE_MODE_WAIT:
+               zfs_dbgmsg("%s waiting for hung I/O to pool '%s'", tag, name);
+               break;
+
+       case ZIO_FAILURE_MODE_CONTINUE:
+               zfs_dbgmsg("%s restarting hung I/O for pool '%s'", tag, name);
+               break;
+
+       case ZIO_FAILURE_MODE_PANIC:
+               fm_panic("%s determined I/O to pool '%s' is hung.", tag, name);
+               break;
+       }
+}
+
 /*
  * Execute the I/O pipeline until one of the following occurs:
  * (1) the I/O completes; (2) the pipeline stalls waiting for
@@ -1875,6 +1996,7 @@ __zio_execute(zio_t *zio)
 int
 zio_wait(zio_t *zio)
 {
+       long timeout = MSEC_TO_TICK(zfs_deadman_ziotime_ms);
        int error;
 
        ASSERT3S(zio->io_stage, ==, ZIO_STAGE_OPEN);
@@ -1887,8 +2009,19 @@ zio_wait(zio_t *zio)
        __zio_execute(zio);
 
        mutex_enter(&zio->io_lock);
-       while (zio->io_executor != NULL)
-               cv_wait_io(&zio->io_cv, &zio->io_lock);
+       while (zio->io_executor != NULL) {
+               error = cv_timedwait_io(&zio->io_cv, &zio->io_lock,
+                   ddi_get_lbolt() + timeout);
+
+               if (zfs_deadman_enabled && error == -1 &&
+                   gethrtime() - zio->io_queued_timestamp >
+                   spa_deadman_ziotime(zio->io_spa)) {
+                       mutex_exit(&zio->io_lock);
+                       timeout = MSEC_TO_TICK(zfs_deadman_checktime_ms);
+                       zio_deadman(zio, FTAG);
+                       mutex_enter(&zio->io_lock);
+               }
+       }
        mutex_exit(&zio->io_lock);
 
        error = zio->io_error;
@@ -1963,14 +2096,16 @@ zio_reexecute(zio_t *pio)
         * cannot be affected by any side effects of reexecuting 'cio'.
         */
        zio_link_t *zl = NULL;
+       mutex_enter(&pio->io_lock);
        for (cio = zio_walk_children(pio, &zl); cio != NULL; cio = cio_next) {
                cio_next = zio_walk_children(pio, &zl);
-               mutex_enter(&pio->io_lock);
                for (int w = 0; w < ZIO_WAIT_TYPES; w++)
                        pio->io_children[cio->io_child_type][w]++;
                mutex_exit(&pio->io_lock);
                zio_reexecute(cio);
+               mutex_enter(&pio->io_lock);
        }
+       mutex_exit(&pio->io_lock);
 
        /*
         * Now that all children have been reexecuted, execute the parent.
@@ -1984,21 +2119,7 @@ zio_reexecute(zio_t *pio)
 }
 
 void
-zio_cancel(zio_t *zio)
-{
-       /*
-        * Disallow cancellation of a zio that's already been issued.
-        */
-       VERIFY3P(zio->io_executor, ==, NULL);
-
-       zio->io_pipeline = ZIO_INTERLOCK_PIPELINE;
-       zio->io_done = NULL;
-
-       zio_nowait(zio);
-}
-
-void
-zio_suspend(spa_t *spa, zio_t *zio)
+zio_suspend(spa_t *spa, zio_t *zio, zio_suspend_reason_t reason)
 {
        if (spa_get_failmode(spa) == ZIO_FAILURE_MODE_PANIC)
                fm_panic("Pool '%s' has encountered an uncorrectable I/O "
@@ -2018,7 +2139,7 @@ zio_suspend(spa_t *spa, zio_t *zio)
                    ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE |
                    ZIO_FLAG_GODFATHER);
 
-       spa->spa_suspended = B_TRUE;
+       spa->spa_suspended = reason;
 
        if (zio != NULL) {
                ASSERT(!(zio->io_flags & ZIO_FLAG_GODFATHER));
@@ -2041,7 +2162,7 @@ zio_resume(spa_t *spa)
         * Reexecute all previously suspended i/o.
         */
        mutex_enter(&spa->spa_suspend_lock);
-       spa->spa_suspended = B_FALSE;
+       spa->spa_suspended = ZIO_SUSPEND_NONE;
        cv_broadcast(&spa->spa_suspend_cv);
        pio = spa->spa_suspend_zio_root;
        spa->spa_suspend_zio_root = NULL;
@@ -2366,8 +2487,9 @@ zio_gang_issue(zio_t *zio)
 {
        blkptr_t *bp = zio->io_bp;
 
-       if (zio_wait_for_children(zio, ZIO_CHILD_GANG, ZIO_WAIT_DONE))
+       if (zio_wait_for_children(zio, ZIO_CHILD_GANG_BIT, ZIO_WAIT_DONE)) {
                return (ZIO_PIPELINE_STOP);
+       }
 
        ASSERT(BP_IS_GANG(bp) && zio->io_gang_leader == zio);
        ASSERT(zio->io_child_type > ZIO_CHILD_GANG);
@@ -2708,8 +2830,9 @@ zio_ddt_read_done(zio_t *zio)
 {
        blkptr_t *bp = zio->io_bp;
 
-       if (zio_wait_for_children(zio, ZIO_CHILD_DDT, ZIO_WAIT_DONE))
+       if (zio_wait_for_children(zio, ZIO_CHILD_DDT_BIT, ZIO_WAIT_DONE)) {
                return (ZIO_PIPELINE_STOP);
+       }
 
        ASSERT(BP_GET_DEDUP(bp));
        ASSERT(BP_GET_PSIZE(bp) == zio->io_size);
@@ -3351,6 +3474,15 @@ zio_vdev_io_start(zio_t *zio)
        }
 
        ASSERT3P(zio->io_logical, !=, zio);
+       if (zio->io_type == ZIO_TYPE_WRITE && zio->io_vd->vdev_removing) {
+               /*
+                * Note: the code can handle other kinds of writes,
+                * but we don't expect them.
+                */
+               ASSERT(zio->io_flags &
+                   (ZIO_FLAG_PHYSICAL | ZIO_FLAG_SELF_HEAL |
+                   ZIO_FLAG_INDUCE_DAMAGE));
+       }
 
        align = 1ULL << vd->vdev_top->vdev_ashift;
 
@@ -3435,8 +3567,9 @@ zio_vdev_io_done(zio_t *zio)
        vdev_ops_t *ops = vd ? vd->vdev_ops : &vdev_mirror_ops;
        boolean_t unexpected_error = B_FALSE;
 
-       if (zio_wait_for_children(zio, ZIO_CHILD_VDEV, ZIO_WAIT_DONE))
+       if (zio_wait_for_children(zio, ZIO_CHILD_VDEV_BIT, ZIO_WAIT_DONE)) {
                return (ZIO_PIPELINE_STOP);
+       }
 
        ASSERT(zio->io_type == ZIO_TYPE_READ || zio->io_type == ZIO_TYPE_WRITE);
 
@@ -3474,6 +3607,35 @@ zio_vdev_io_done(zio_t *zio)
        return (ZIO_PIPELINE_CONTINUE);
 }
 
+/*
+ * This function is used to change the priority of an existing zio that is
+ * currently in-flight. This is used by the arc to upgrade priority in the
+ * event that a demand read is made for a block that is currently queued
+ * as a scrub or async read IO. Otherwise, the high priority read request
+ * would end up having to wait for the lower priority IO.
+ */
+void
+zio_change_priority(zio_t *pio, zio_priority_t priority)
+{
+       zio_t *cio, *cio_next;
+       zio_link_t *zl = NULL;
+
+       ASSERT3U(priority, <, ZIO_PRIORITY_NUM_QUEUEABLE);
+
+       if (pio->io_vd != NULL && pio->io_vd->vdev_ops->vdev_op_leaf) {
+               vdev_queue_change_io_priority(pio, priority);
+       } else {
+               pio->io_priority = priority;
+       }
+
+       mutex_enter(&pio->io_lock);
+       for (cio = zio_walk_children(pio, &zl); cio != NULL; cio = cio_next) {
+               cio_next = zio_walk_children(pio, &zl);
+               zio_change_priority(cio, priority);
+       }
+       mutex_exit(&pio->io_lock);
+}
+
 /*
  * For non-raidz ZIOs, we can just copy aside the bad data read from the
  * disk, and use that to finish the checksum ereport later.
@@ -3505,8 +3667,9 @@ zio_vdev_io_assess(zio_t *zio)
 {
        vdev_t *vd = zio->io_vd;
 
-       if (zio_wait_for_children(zio, ZIO_CHILD_VDEV, ZIO_WAIT_DONE))
+       if (zio_wait_for_children(zio, ZIO_CHILD_VDEV_BIT, ZIO_WAIT_DONE)) {
                return (ZIO_PIPELINE_STOP);
+       }
 
        if (vd == NULL && !(zio->io_flags & ZIO_FLAG_CONFIG_WRITER))
                spa_config_exit(zio->io_spa, SCL_ZIO, zio);
@@ -3624,6 +3787,7 @@ zio_encrypt(zio_t *zio)
        spa_t *spa = zio->io_spa;
        blkptr_t *bp = zio->io_bp;
        uint64_t psize = BP_GET_PSIZE(bp);
+       uint64_t dsobj = zio->io_bookmark.zb_objset;
        dmu_object_type_t ot = BP_GET_TYPE(bp);
        void *enc_buf = NULL;
        abd_t *eabd = NULL;
@@ -3647,10 +3811,27 @@ zio_encrypt(zio_t *zio)
 
        /* if we are doing raw encryption set the provided encryption params */
        if (zio->io_flags & ZIO_FLAG_RAW_ENCRYPT) {
+               ASSERT0(BP_GET_LEVEL(bp));
                BP_SET_CRYPT(bp, B_TRUE);
                BP_SET_BYTEORDER(bp, zp->zp_byteorder);
                if (ot != DMU_OT_OBJSET)
                        zio_crypt_encode_mac_bp(bp, zp->zp_mac);
+
+               /* dnode blocks must be written out in the provided byteorder */
+               if (zp->zp_byteorder != ZFS_HOST_BYTEORDER &&
+                   ot == DMU_OT_DNODE) {
+                       void *bswap_buf = zio_buf_alloc(psize);
+                       abd_t *babd = abd_get_from_buf(bswap_buf, psize);
+
+                       ASSERT3U(BP_GET_COMPRESS(bp), ==, ZIO_COMPRESS_OFF);
+                       abd_copy_to_buf(bswap_buf, zio->io_abd, psize);
+                       dmu_ot_byteswap[DMU_OT_BYTESWAP(ot)].ob_func(bswap_buf,
+                           psize);
+
+                       abd_take_ownership_of_buf(babd, B_TRUE);
+                       zio_push_transform(zio, babd, psize, psize, NULL);
+               }
+
                if (DMU_OT_IS_ENCRYPTED(ot))
                        zio_crypt_encode_params_bp(bp, zp->zp_salt, zp->zp_iv);
                return (ZIO_PIPELINE_CONTINUE);
@@ -3674,17 +3855,16 @@ zio_encrypt(zio_t *zio)
                ASSERT0(DMU_OT_IS_ENCRYPTED(ot));
                ASSERT3U(BP_GET_COMPRESS(bp), ==, ZIO_COMPRESS_OFF);
                BP_SET_CRYPT(bp, B_TRUE);
-               VERIFY0(spa_do_crypt_objset_mac_abd(B_TRUE, spa,
-                   zio->io_bookmark.zb_objset, zio->io_abd, psize,
-                   BP_SHOULD_BYTESWAP(bp)));
+               VERIFY0(spa_do_crypt_objset_mac_abd(B_TRUE, spa, dsobj,
+                   zio->io_abd, psize, BP_SHOULD_BYTESWAP(bp)));
                return (ZIO_PIPELINE_CONTINUE);
        }
 
        /* unencrypted object types are only authenticated with a MAC */
        if (!DMU_OT_IS_ENCRYPTED(ot)) {
                BP_SET_CRYPT(bp, B_TRUE);
-               VERIFY0(spa_do_crypt_mac_abd(B_TRUE, spa,
-                   zio->io_bookmark.zb_objset, zio->io_abd, psize, mac));
+               VERIFY0(spa_do_crypt_mac_abd(B_TRUE, spa, dsobj,
+                   zio->io_abd, psize, mac));
                zio_crypt_encode_mac_bp(bp, mac);
                return (ZIO_PIPELINE_CONTINUE);
        }
@@ -3718,8 +3898,8 @@ zio_encrypt(zio_t *zio)
        }
 
        /* Perform the encryption. This should not fail */
-       VERIFY0(spa_do_crypt_abd(B_TRUE, spa, zio->io_bookmark.zb_objset, bp,
-           zio->io_txg, psize, zio->io_abd, eabd, iv, mac, salt, &no_crypt));
+       VERIFY0(spa_do_crypt_abd(B_TRUE, spa, dsobj, bp, zio->io_txg,
+           psize, zio->io_abd, eabd, iv, mac, salt, &no_crypt));
 
        /* encode encryption metadata into the bp */
        if (ot == DMU_OT_INTENT_LOG) {
@@ -3861,9 +4041,10 @@ zio_ready(zio_t *zio)
        zio_t *pio, *pio_next;
        zio_link_t *zl = NULL;
 
-       if (zio_wait_for_children(zio, ZIO_CHILD_GANG, ZIO_WAIT_READY) ||
-           zio_wait_for_children(zio, ZIO_CHILD_DDT, ZIO_WAIT_READY))
+       if (zio_wait_for_children(zio, ZIO_CHILD_GANG_BIT | ZIO_CHILD_DDT_BIT,
+           ZIO_WAIT_READY)) {
                return (ZIO_PIPELINE_STOP);
+       }
 
        if (zio->io_ready) {
                ASSERT(IO_IS_ALLOCATING(zio));
@@ -4003,11 +4184,9 @@ zio_done(zio_t *zio)
         * If our children haven't all completed,
         * wait for them and then repeat this pipeline stage.
         */
-       if (zio_wait_for_children(zio, ZIO_CHILD_VDEV, ZIO_WAIT_DONE) ||
-           zio_wait_for_children(zio, ZIO_CHILD_GANG, ZIO_WAIT_DONE) ||
-           zio_wait_for_children(zio, ZIO_CHILD_DDT, ZIO_WAIT_DONE) ||
-           zio_wait_for_children(zio, ZIO_CHILD_LOGICAL, ZIO_WAIT_DONE))
+       if (zio_wait_for_children(zio, ZIO_CHILD_ALL_BITS, ZIO_WAIT_DONE)) {
                return (ZIO_PIPELINE_STOP);
+       }
 
        /*
         * If the allocation throttle is enabled, then update the accounting.
@@ -4049,7 +4228,6 @@ zio_done(zio_t *zio)
                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(zio->io_bp));
                        ASSERT3U(zio->io_prop.zp_copies, <=,
                            BP_GET_NDVAS(zio->io_bp));
                        ASSERT(BP_COUNT_GANG(zio->io_bp) == 0 ||
@@ -4248,7 +4426,7 @@ 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(zio->io_spa, zio);
+                       zio_suspend(zio->io_spa, zio, ZIO_SUSPEND_IOERR);
                } else {
                        /*
                         * Reexecution is potentially a huge amount of work.