--- 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);