diff options
author | smh <smh@FreeBSD.org> | 2014-04-28 09:00:00 +0000 |
---|---|---|
committer | smh <smh@FreeBSD.org> | 2014-04-28 09:00:00 +0000 |
commit | 764830753767f22850b41620e71c06c0def1c6ee (patch) | |
tree | dabf2ad120847ea26c3a0fc79f5ad885046709ba | |
parent | 4cfedd16e9cac655b2b8b2f3d125419c9259bd8e (diff) | |
download | FreeBSD-src-764830753767f22850b41620e71c06c0def1c6ee.zip FreeBSD-src-764830753767f22850b41620e71c06c0def1c6ee.tar.gz |
Fix ZIO reordering done by vdev_queue_io causing panics when zio_vdev_io_start
returns ZIO_PIPELINE_CONTINUE from vdev_op_io_start to zio_execute resulting
in the wrong ZIO continuing its pipeline.
This is a serious issue which could cause data loss / corruption but appears
to be limited to error handling such as when vdev_readable(vd) returns false.
MFC after: 2 days
-rw-r--r-- | sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h | 2 | ||||
-rw-r--r-- | sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c | 68 |
2 files changed, 47 insertions, 23 deletions
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h index 41960b5..8b4e834 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h @@ -349,7 +349,7 @@ typedef struct zio_transform { struct zio_transform *zt_next; } zio_transform_t; -typedef int zio_pipe_stage_t(zio_t *zio); +typedef int zio_pipe_stage_t(zio_t **ziop); /* * The io_reexecute flags are distinct from io_flags because the child must diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c index ea81b43..95f6bbd 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c @@ -1012,8 +1012,9 @@ zio_shrink(zio_t *zio, uint64_t size) */ static int -zio_read_bp_init(zio_t *zio) +zio_read_bp_init(zio_t **ziop) { + zio_t *zio = *ziop; blkptr_t *bp = zio->io_bp; if (BP_GET_COMPRESS(bp) != ZIO_COMPRESS_OFF && @@ -1038,8 +1039,9 @@ zio_read_bp_init(zio_t *zio) } static int -zio_write_bp_init(zio_t *zio) +zio_write_bp_init(zio_t **ziop) { + zio_t *zio = *ziop; spa_t *spa = zio->io_spa; zio_prop_t *zp = &zio->io_prop; enum zio_compress compress = zp->zp_compress; @@ -1189,8 +1191,9 @@ zio_write_bp_init(zio_t *zio) } static int -zio_free_bp_init(zio_t *zio) +zio_free_bp_init(zio_t **ziop) { + zio_t *zio = *ziop; blkptr_t *bp = zio->io_bp; if (zio->io_child_type == ZIO_CHILD_LOGICAL) { @@ -1273,8 +1276,10 @@ zio_taskq_member(zio_t *zio, zio_taskq_type_t q) } static int -zio_issue_async(zio_t *zio) +zio_issue_async(zio_t **ziop) { + zio_t *zio = *ziop; + zio_taskq_dispatch(zio, ZIO_TASKQ_ISSUE, B_FALSE); return (ZIO_PIPELINE_STOP); @@ -1342,7 +1347,7 @@ zio_execute(zio_t *zio) } zio->io_stage = stage; - rv = zio_pipeline[highbit64(stage) - 1](zio); + rv = zio_pipeline[highbit64(stage) - 1](&zio); if (rv == ZIO_PIPELINE_STOP) return; @@ -1776,8 +1781,9 @@ zio_gang_tree_issue(zio_t *pio, zio_gang_node_t *gn, blkptr_t *bp, void *data) } static int -zio_gang_assemble(zio_t *zio) +zio_gang_assemble(zio_t **ziop) { + zio_t *zio = *ziop; blkptr_t *bp = zio->io_bp; ASSERT(BP_IS_GANG(bp) && zio->io_gang_leader == NULL); @@ -1791,8 +1797,9 @@ zio_gang_assemble(zio_t *zio) } static int -zio_gang_issue(zio_t *zio) +zio_gang_issue(zio_t **ziop) { + zio_t *zio = *ziop; blkptr_t *bp = zio->io_bp; if (zio_wait_for_children(zio, ZIO_CHILD_GANG, ZIO_WAIT_DONE)) @@ -1926,8 +1933,9 @@ zio_write_gang_block(zio_t *pio) * writes) and as a result is mutually exclusive with dedup. */ static int -zio_nop_write(zio_t *zio) +zio_nop_write(zio_t **ziop) { + zio_t *zio = *ziop; blkptr_t *bp = zio->io_bp; blkptr_t *bp_orig = &zio->io_bp_orig; zio_prop_t *zp = &zio->io_prop; @@ -1998,8 +2006,9 @@ zio_ddt_child_read_done(zio_t *zio) } static int -zio_ddt_read_start(zio_t *zio) +zio_ddt_read_start(zio_t **ziop) { + zio_t *zio = *ziop; blkptr_t *bp = zio->io_bp; ASSERT(BP_GET_DEDUP(bp)); @@ -2041,8 +2050,9 @@ zio_ddt_read_start(zio_t *zio) } static int -zio_ddt_read_done(zio_t *zio) +zio_ddt_read_done(zio_t **ziop) { + zio_t *zio = *ziop; blkptr_t *bp = zio->io_bp; if (zio_wait_for_children(zio, ZIO_CHILD_DDT, ZIO_WAIT_DONE)) @@ -2210,8 +2220,9 @@ zio_ddt_ditto_write_done(zio_t *zio) } static int -zio_ddt_write(zio_t *zio) +zio_ddt_write(zio_t **ziop) { + zio_t *zio = *ziop; spa_t *spa = zio->io_spa; blkptr_t *bp = zio->io_bp; uint64_t txg = zio->io_txg; @@ -2322,8 +2333,9 @@ zio_ddt_write(zio_t *zio) ddt_entry_t *freedde; /* for debugging */ static int -zio_ddt_free(zio_t *zio) +zio_ddt_free(zio_t **ziop) { + zio_t *zio = *ziop; spa_t *spa = zio->io_spa; blkptr_t *bp = zio->io_bp; ddt_t *ddt = ddt_select(spa, bp); @@ -2348,8 +2360,9 @@ zio_ddt_free(zio_t *zio) * ========================================================================== */ static int -zio_dva_allocate(zio_t *zio) +zio_dva_allocate(zio_t **ziop) { + zio_t *zio = *ziop; spa_t *spa = zio->io_spa; metaslab_class_t *mc = spa_normal_class(spa); blkptr_t *bp = zio->io_bp; @@ -2391,16 +2404,19 @@ zio_dva_allocate(zio_t *zio) } static int -zio_dva_free(zio_t *zio) +zio_dva_free(zio_t **ziop) { + zio_t *zio = *ziop; + metaslab_free(zio->io_spa, zio->io_bp, zio->io_txg, B_FALSE); return (ZIO_PIPELINE_CONTINUE); } static int -zio_dva_claim(zio_t *zio) +zio_dva_claim(zio_t **ziop) { + zio_t *zio = *ziop; int error; error = metaslab_claim(zio->io_spa, zio->io_bp, zio->io_txg); @@ -2494,8 +2510,9 @@ zio_free_zil(spa_t *spa, uint64_t txg, blkptr_t *bp) * ========================================================================== */ static int -zio_vdev_io_start(zio_t *zio) +zio_vdev_io_start(zio_t **ziop) { + zio_t *zio = *ziop; vdev_t *vd = zio->io_vd; uint64_t align; spa_t *spa = zio->io_spa; @@ -2589,6 +2606,7 @@ zio_vdev_io_start(zio_t *zio) if ((zio = vdev_queue_io(zio)) == NULL) return (ZIO_PIPELINE_STOP); + *ziop = zio; if (!vdev_accessible(vd, zio)) { zio->io_error = SET_ERROR(ENXIO); @@ -2612,8 +2630,9 @@ zio_vdev_io_start(zio_t *zio) } static int -zio_vdev_io_done(zio_t *zio) +zio_vdev_io_done(zio_t **ziop) { + zio_t *zio = *ziop; vdev_t *vd = zio->io_vd; vdev_ops_t *ops = vd ? vd->vdev_ops : &vdev_mirror_ops; boolean_t unexpected_error = B_FALSE; @@ -2687,8 +2706,9 @@ zio_vsd_default_cksum_report(zio_t *zio, zio_cksum_report_t *zcr, void *ignored) } static int -zio_vdev_io_assess(zio_t *zio) +zio_vdev_io_assess(zio_t **ziop) { + zio_t *zio = *ziop; vdev_t *vd = zio->io_vd; if (zio_wait_for_children(zio, ZIO_CHILD_VDEV, ZIO_WAIT_DONE)) @@ -2801,8 +2821,9 @@ zio_vdev_io_bypass(zio_t *zio) * ========================================================================== */ static int -zio_checksum_generate(zio_t *zio) +zio_checksum_generate(zio_t **ziop) { + zio_t *zio = *ziop; blkptr_t *bp = zio->io_bp; enum zio_checksum checksum; @@ -2832,8 +2853,9 @@ zio_checksum_generate(zio_t *zio) } static int -zio_checksum_verify(zio_t *zio) +zio_checksum_verify(zio_t **ziop) { + zio_t *zio = *ziop; zio_bad_cksum_t info; blkptr_t *bp = zio->io_bp; int error; @@ -2904,8 +2926,9 @@ zio_worst_error(int e1, int e2) * ========================================================================== */ static int -zio_ready(zio_t *zio) +zio_ready(zio_t **ziop) { + zio_t *zio = *ziop; blkptr_t *bp = zio->io_bp; zio_t *pio, *pio_next; @@ -2962,8 +2985,9 @@ zio_ready(zio_t *zio) } static int -zio_done(zio_t *zio) +zio_done(zio_t **ziop) { + zio_t *zio = *ziop; spa_t *spa = zio->io_spa; zio_t *lio = zio->io_logical; blkptr_t *bp = zio->io_bp; |