diff -r 26439431f254 -r c1d2a7f04573 usr/src/uts/common/fs/zfs/zio.c --- a/usr/src/uts/common/fs/zfs/zio.c Wed Apr 30 11:30:34 2008 -0700 +++ b/usr/src/uts/common/fs/zfs/zio.c Wed Apr 30 12:37:56 2008 -0700 @@ -796,6 +796,20 @@ * Initiate I/O, either sync or async * ========================================================================== */ +static void +zio_destroy(zio_t *zio) +{ + mutex_destroy(&zio->io_lock); + cv_destroy(&zio->io_cv); + if (zio->io_failed_vds != NULL) { + kmem_free(zio->io_failed_vds, + zio->io_failed_vds_count * sizeof (vdev_t *)); + zio->io_failed_vds = NULL; + zio->io_failed_vds_count = 0; + } + kmem_cache_free(zio_cache, zio); +} + int zio_wait(zio_t *zio) { @@ -813,9 +827,7 @@ mutex_exit(&zio->io_lock); error = zio->io_error; - mutex_destroy(&zio->io_lock); - cv_destroy(&zio->io_cv); - kmem_cache_free(zio_cache, zio); + zio_destroy(zio); return (error); } @@ -864,13 +876,44 @@ } static void +zio_add_failed_vdev(zio_t *pio, zio_t *zio) +{ + uint64_t oldcount = pio->io_failed_vds_count; + vdev_t **new_vds; + int i; + + ASSERT(MUTEX_HELD(&pio->io_lock)); + + if (zio->io_vd == NULL) + return; + + for (i = 0; i < oldcount; i++) { + if (pio->io_failed_vds[i] == zio->io_vd) + return; + } + + new_vds = kmem_zalloc((oldcount + 1) * sizeof (vdev_t *), KM_SLEEP); + if (pio->io_failed_vds != NULL) { + bcopy(pio->io_failed_vds, new_vds, + oldcount * sizeof (vdev_t *)); + kmem_free(pio->io_failed_vds, oldcount * sizeof (vdev_t *)); + } + pio->io_failed_vds = new_vds; + pio->io_failed_vds[oldcount] = zio->io_vd; + pio->io_failed_vds_count++; +} + +static void zio_notify_parent(zio_t *zio, uint32_t stage, uint64_t *countp) { zio_t *pio = zio->io_parent; mutex_enter(&pio->io_lock); - if (pio->io_error == 0 && !(zio->io_flags & ZIO_FLAG_DONT_PROPAGATE)) + if (pio->io_error == 0 && !(zio->io_flags & ZIO_FLAG_DONT_PROPAGATE)) { pio->io_error = zio->io_error; + if (zio->io_error && zio->io_error != ENOTSUP) + zio_add_failed_vdev(pio, zio); + } ASSERT3U(*countp, >, 0); if (--*countp == 0 && pio->io_stalled == stage) { pio->io_stalled = 0; @@ -1083,6 +1126,38 @@ return (ZIO_PIPELINE_STOP); } +static void +zio_handle_io_failure(zio_t *zio, vdev_t *vd) +{ + spa_t *spa = zio->io_spa; + blkptr_t *bp = zio->io_bp; + char *blkbuf; + +#ifdef ZFS_DEBUG + blkbuf = kmem_alloc(BP_SPRINTF_LEN, KM_NOSLEEP); + if (blkbuf) { + sprintf_blkptr(blkbuf, BP_SPRINTF_LEN, + bp ? bp : &zio->io_bp_copy); + } + cmn_err(CE_WARN, "ZFS: %s (%s on %s off %llx: zio %p %s): error %d", + zio->io_error == ECKSUM ? "bad checksum" : "I/O failure", + zio_type_name[zio->io_type], vdev_description(vd), + (u_longlong_t)zio->io_offset, (void *)zio, + blkbuf ? blkbuf : "", zio->io_error); + if (blkbuf) + kmem_free(blkbuf, BP_SPRINTF_LEN); +#endif + + if (spa_get_failmode(spa) == ZIO_FAILURE_MODE_PANIC) { + fm_panic("Pool '%s' has encountered an uncorrectable I/O " + "failure and the failure mode property for this pool " + "is set to panic.", spa_name(spa)); + } + zfs_ereport_post(FM_EREPORT_ZFS_IO_FAILURE, spa, NULL, NULL, 0, 0); + vdev_set_state(vd, vd == spa->spa_root_vdev ? B_TRUE : B_FALSE, + VDEV_STATE_FAULTED, VDEV_AUX_IO_FAILURE); +} + static int zio_assess(zio_t *zio) { @@ -1164,32 +1239,23 @@ * a result of vdev failures vs. a full pool. */ if (!(zio->io_flags & ZIO_FLAG_CANFAIL)) { - char *blkbuf; + int i; -#ifdef ZFS_DEBUG - blkbuf = kmem_alloc(BP_SPRINTF_LEN, KM_NOSLEEP); - if (blkbuf) { - sprintf_blkptr(blkbuf, BP_SPRINTF_LEN, - bp ? bp : &zio->io_bp_copy); + for (i = 0; i < zio->io_failed_vds_count; i++) { + zio_handle_io_failure(zio, + zio->io_failed_vds[i]); } - cmn_err(CE_WARN, "ZFS: %s (%s on %s off %llx: zio %p " - "%s): error %d", zio->io_error == ECKSUM ? - "bad checksum" : "I/O failure", - zio_type_name[zio->io_type], - vdev_description(vd), - (u_longlong_t)zio->io_offset, - (void *)zio, blkbuf ? blkbuf : "", zio->io_error); -#endif - - if (spa_get_failmode(spa) == ZIO_FAILURE_MODE_PANIC) { - fm_panic("Pool '%s' has encountered an " - "uncorrectable I/O failure and the " - "failure mode property for this pool " - "is set to panic.", spa_name(spa)); + if (zio->io_failed_vds_count == 0) { + zio_handle_io_failure(zio, + vd ? vd : spa->spa_root_vdev); } - cmn_err(CE_WARN, "Pool '%s' has encountered " - "an uncorrectable I/O error. " - "Manual intervention is required.", spa_name(spa)); + if (zio->io_failed_vds != NULL) { + kmem_free(zio->io_failed_vds, + zio->io_failed_vds_count * + sizeof (vdev_t *)); + zio->io_failed_vds = NULL; + zio->io_failed_vds_count = 0; + } return (zio_vdev_suspend_io(zio)); } } @@ -1248,9 +1314,7 @@ cv_broadcast(&zio->io_cv); mutex_exit(&zio->io_lock); } else { - mutex_destroy(&zio->io_lock); - cv_destroy(&zio->io_cv); - kmem_cache_free(zio_cache, zio); + zio_destroy(zio); } return (ZIO_PIPELINE_STOP);