changeset 3668:dc5b9a9208ca

6513020 zio pipeline went out to lunch
author gw25295
date Fri, 16 Feb 2007 13:39:57 -0800
parents 089a83b5d0bc
children 4e8428f56972
files usr/src/cmd/ztest/ztest.c usr/src/lib/libzpool/common/llib-lzpool usr/src/uts/common/fs/zfs/zil.c usr/src/uts/common/fs/zfs/zio.c
diffstat 4 files changed, 59 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/ztest/ztest.c	Fri Feb 16 12:27:32 2007 -0800
+++ b/usr/src/cmd/ztest/ztest.c	Fri Feb 16 13:39:57 2007 -0800
@@ -234,6 +234,7 @@
 static int ztest_dump_core = 1;
 
 extern uint64_t zio_gang_bang;
+extern uint16_t zio_zil_fail_shift;
 
 #define	ZTEST_DIROBJ		1
 #define	ZTEST_MICROZAP_OBJ	2
@@ -359,6 +360,7 @@
 	    "\t[-E(xisting)] (use existing pool instead of creating new one)\n"
 	    "\t[-T time] total run time (default: %llu sec)\n"
 	    "\t[-P passtime] time per pass (default: %llu sec)\n"
+	    "\t[-z zil failure rate (default: fail every 2^%llu allocs)]\n"
 	    "",
 	    cmdname,
 	    (u_longlong_t)zopt_vdevs,		/* -v */
@@ -375,7 +377,8 @@
 	    zopt_pool,				/* -p */
 	    zopt_dir,				/* -f */
 	    (u_longlong_t)zopt_time,		/* -T */
-	    (u_longlong_t)zopt_passtime);	/* -P */
+	    (u_longlong_t)zopt_passtime,	/* -P */
+	    (u_longlong_t)zio_zil_fail_shift);	/* -z */
 	exit(1);
 }
 
@@ -409,8 +412,11 @@
 	/* By default, test gang blocks for blocks 32K and greater */
 	zio_gang_bang = 32 << 10;
 
+	/* Default value, fail every 32nd allocation */
+	zio_zil_fail_shift = 5;
+
 	while ((opt = getopt(argc, argv,
-	    "v:s:a:m:r:R:d:t:g:i:k:p:f:VET:P:")) != EOF) {
+	    "v:s:a:m:r:R:d:t:g:i:k:p:f:VET:P:z:")) != EOF) {
 		value = 0;
 		switch (opt) {
 		    case 'v':
@@ -426,6 +432,7 @@
 		    case 'k':
 		    case 'T':
 		    case 'P':
+		    case 'z':
 			value = nicenumtoull(optarg);
 		}
 		switch (opt) {
@@ -480,6 +487,9 @@
 		    case 'P':
 			zopt_passtime = MAX(1, value);
 			break;
+		    case 'z':
+			zio_zil_fail_shift = MIN(value, 16);
+			break;
 		    case '?':
 		    default:
 			usage();
--- a/usr/src/lib/libzpool/common/llib-lzpool	Fri Feb 16 12:27:32 2007 -0800
+++ b/usr/src/lib/libzpool/common/llib-lzpool	Fri Feb 16 13:39:57 2007 -0800
@@ -49,3 +49,4 @@
 #include <sys/zfs_znode.h>
 
 extern uint64_t zio_gang_bang;
+extern uint16_t zio_zil_fail_shift;
--- a/usr/src/uts/common/fs/zfs/zil.c	Fri Feb 16 12:27:32 2007 -0800
+++ b/usr/src/uts/common/fs/zfs/zil.c	Fri Feb 16 13:39:57 2007 -0800
@@ -36,6 +36,7 @@
 #include <sys/zil_impl.h>
 #include <sys/dsl_dataset.h>
 #include <sys/vdev.h>
+#include <sys/dmu_tx.h>
 
 /*
  * The zfs intent log (ZIL) saves transaction records of system calls
@@ -690,14 +691,29 @@
 	/* pass the old blkptr in order to spread log blocks across devs */
 	error = zio_alloc_blk(spa, zil_blksz, bp, &lwb->lwb_blk, txg);
 	if (error) {
+		dmu_tx_t *tx = dmu_tx_create_assigned(zilog->zl_dmu_pool, txg);
+
 		/*
-		 * Reinitialise the lwb.
+		 * We dirty the dataset to ensure that zil_sync() will
+		 * be called to remove this lwb from our zl_lwb_list.
+		 * Failing to do so, may leave an lwb with a NULL lwb_buf
+		 * hanging around on the zl_lwb_list.
+		 */
+		dsl_dataset_dirty(dmu_objset_ds(zilog->zl_os), tx);
+
+
+		/*
+		 * Since we've just experienced an allocation failure so we
+		 * terminate the current lwb and send it on its way.
+		 */
+		ztp->zit_pad = 0;
+		ztp->zit_nused = lwb->lwb_nused;
+		ztp->zit_bt.zbt_cksum = lwb->lwb_blk.blk_cksum;
+		zio_nowait(lwb->lwb_zio);
+
+		/*
 		 * By returning NULL the caller will call tx_wait_synced()
 		 */
-		mutex_enter(&zilog->zl_lock);
-		lwb->lwb_nused = 0;
-		mutex_exit(&zilog->zl_lock);
-		txg_rele_to_sync(&lwb->lwb_txgh);
 		return (NULL);
 	}
 
@@ -1116,6 +1132,15 @@
 		list_remove(&zilog->zl_lwb_list, lwb);
 		zio_free_blk(spa, &lwb->lwb_blk, txg);
 		kmem_cache_free(zil_lwb_cache, lwb);
+
+		/*
+		 * If we don't have anything left in the lwb list then
+		 * we've had an allocation failure and we need to zero
+		 * out the zil_header blkptr so that we don't end
+		 * up freeing the same block twice.
+		 */
+		if (list_head(&zilog->zl_lwb_list) == NULL)
+			BP_ZERO(&zh->zh_log);
 	}
 	mutex_exit(&zilog->zl_lock);
 }
--- a/usr/src/uts/common/fs/zfs/zio.c	Fri Feb 16 12:27:32 2007 -0800
+++ b/usr/src/uts/common/fs/zfs/zio.c	Fri Feb 16 13:39:57 2007 -0800
@@ -64,6 +64,9 @@
 /* At or above this size, force gang blocking - for testing */
 uint64_t zio_gang_bang = SPA_MAXBLOCKSIZE + 1;
 
+/* Force an allocation failure when non-zero */
+uint16_t zio_zil_fail_shift = 0;
+
 typedef struct zio_sync_pass {
 	int	zp_defer_free;		/* defer frees after this pass */
 	int	zp_dontcompress;	/* don't compress after this pass */
@@ -1751,6 +1754,14 @@
 	}
 }
 
+static boolean_t
+zio_alloc_should_fail(void)
+{
+	static uint16_t	allocs = 0;
+
+	return (P2PHASE(allocs++, 1U<<zio_zil_fail_shift) == 0);
+}
+
 /*
  * Try to allocate an intent log block.  Return 0 on success, errno on failure.
  */
@@ -1762,6 +1773,11 @@
 
 	spa_config_enter(spa, RW_READER, FTAG);
 
+	if (zio_zil_fail_shift && zio_alloc_should_fail()) {
+		spa_config_exit(spa, FTAG);
+		return (ENOSPC);
+	}
+
 	/*
 	 * We were passed the previous log blocks dva_t in bp->blk_dva[0].
 	 */