usr/src/uts/common/fs/zfs/zio.c
changeset 6523 c1d2a7f04573
parent 6245 1a2a7cfb9f26
child 6976 cae5f06df471
--- 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);