6972862 rollback can leak log blocks
authorMark Maybee <Mark.Maybee@Sun.COM>
Fri, 30 Jul 2010 09:40:31 -0600
changeset 12982 5d7f2db1e620
parent 12981 9fda0aeb1cb6
child 12983 dc4ded083034
6972862 rollback can leak log blocks 6971273 zfs: allocating allocated segment
usr/src/uts/common/fs/zfs/dmu_objset.c
usr/src/uts/common/fs/zfs/dmu_send.c
usr/src/uts/common/fs/zfs/dsl_dataset.c
--- a/usr/src/uts/common/fs/zfs/dmu_objset.c	Fri Jul 30 14:57:39 2010 +0100
+++ b/usr/src/uts/common/fs/zfs/dmu_objset.c	Fri Jul 30 09:40:31 2010 -0600
@@ -422,7 +422,7 @@
 	*osp = ds->ds_objset;
 	if (*osp == NULL) {
 		err = dmu_objset_open_impl(dsl_dataset_get_spa(ds),
-		    ds, &ds->ds_phys->ds_bp, osp);
+		    ds, dsl_dataset_get_blkptr(ds), osp);
 	}
 	mutex_exit(&ds->ds_opening_lock);
 	return (err);
@@ -602,11 +602,11 @@
 	dnode_t *mdn;
 
 	ASSERT(dmu_tx_is_syncing(tx));
-	if (ds)
-		mutex_enter(&ds->ds_opening_lock);
-	VERIFY(0 == dmu_objset_open_impl(spa, ds, bp, &os));
-	if (ds)
-		mutex_exit(&ds->ds_opening_lock);
+	if (ds != NULL)
+		VERIFY(0 == dmu_objset_from_ds(ds, &os));
+	else
+		VERIFY(0 == dmu_objset_open_impl(spa, NULL, bp, &os));
+
 	mdn = DMU_META_DNODE(os);
 
 	dnode_allocate(mdn, DMU_OT_DNODE, 1 << DNODE_BLOCK_SHIFT,
@@ -695,38 +695,33 @@
 dmu_objset_create_sync(void *arg1, void *arg2, dmu_tx_t *tx)
 {
 	dsl_dir_t *dd = arg1;
+	spa_t *spa = dd->dd_pool->dp_spa;
 	struct oscarg *oa = arg2;
-	uint64_t dsobj;
-	dsl_dataset_t *ds;
-	objset_t *os;
+	uint64_t obj;
 
 	ASSERT(dmu_tx_is_syncing(tx));
 
-	dsobj = dsl_dataset_create_sync(dd, oa->lastname,
+	obj = dsl_dataset_create_sync(dd, oa->lastname,
 	    oa->clone_origin, oa->flags, oa->cr, tx);
 
-	VERIFY(0 == dsl_dataset_hold_obj(dd->dd_pool, dsobj, FTAG, &ds));
+	if (oa->clone_origin == NULL) {
+		dsl_pool_t *dp = dd->dd_pool;
+		dsl_dataset_t *ds;
+		blkptr_t *bp;
+		objset_t *os;
 
-	if (oa->clone_origin == NULL) {
-		blkptr_t *bp;
-
+		VERIFY3U(0, ==, dsl_dataset_hold_obj(dp, obj, FTAG, &ds));
 		bp = dsl_dataset_get_blkptr(ds);
 		ASSERT(BP_IS_HOLE(bp));
 
-		os = dmu_objset_create_impl(dsl_dataset_get_spa(ds),
-		    ds, bp, oa->type, tx);
+		os = dmu_objset_create_impl(spa, ds, bp, oa->type, tx);
 
 		if (oa->userfunc)
 			oa->userfunc(os, oa->userarg, oa->cr, tx);
-	} else {
-		VERIFY3U(0, ==, dmu_objset_from_ds(ds, &os));
-		bzero(&os->os_zil_header, sizeof (os->os_zil_header));
-		dsl_dataset_dirty(ds, tx);
+		dsl_dataset_rele(ds, FTAG);
 	}
-	dsl_dataset_rele(ds, FTAG);
 
-	spa_history_log_internal(LOG_DS_CREATE, dd->dd_pool->dp_spa,
-	    tx, "dataset = %llu", dsobj);
+	spa_history_log_internal(LOG_DS_CREATE, spa, tx, "dataset = %llu", obj);
 }
 
 int
@@ -794,18 +789,8 @@
 	dsl_dataset_t *ds;
 	int error;
 
-	/*
-	 * dsl_dataset_destroy() can free any claimed-but-unplayed
-	 * intent log, but if there is an active log, it has blocks that
-	 * are allocated, but may not yet be reflected in the on-disk
-	 * structure.  Only the ZIL knows how to free them, so we have
-	 * to call into it here.
-	 */
 	error = dsl_dataset_own(name, B_TRUE, FTAG, &ds);
 	if (error == 0) {
-		objset_t *os;
-		if (dmu_objset_from_ds(ds, &os) == 0)
-			zil_destroy(dmu_objset_zil(os), B_FALSE);
 		error = dsl_dataset_destroy(ds, FTAG, defer);
 		/* dsl_dataset_destroy() closes the ds. */
 	}
--- a/usr/src/uts/common/fs/zfs/dmu_send.c	Fri Jul 30 14:57:39 2010 +0100
+++ b/usr/src/uts/common/fs/zfs/dmu_send.c	Fri Jul 30 09:40:31 2010 -0600
@@ -574,6 +574,14 @@
 	if (!rbsa->force && dsl_dataset_modified_since_lastsnap(ds))
 		return (ETXTBSY);
 
+	/* new snapshot name must not exist */
+	err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset,
+	    ds->ds_phys->ds_snapnames_zapobj, rbsa->tosnap, 8, 1, &val);
+	if (err == 0)
+		return (EEXIST);
+	if (err != ENOENT)
+		return (err);
+
 	if (rbsa->fromguid) {
 		/* if incremental, most recent snapshot must match fromguid */
 		if (ds->ds_prev == NULL)
@@ -621,13 +629,6 @@
 	if (err != ENOENT)
 		return (err);
 
-	/* new snapshot name must not exist */
-	err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset,
-	    ds->ds_phys->ds_snapnames_zapobj, rbsa->tosnap, 8, 1, &val);
-	if (err == 0)
-		return (EEXIST);
-	if (err != ENOENT)
-		return (err);
 	return (0);
 }
 
--- a/usr/src/uts/common/fs/zfs/dsl_dataset.c	Fri Jul 30 14:57:39 2010 +0100
+++ b/usr/src/uts/common/fs/zfs/dsl_dataset.c	Fri Jul 30 09:40:31 2010 -0600
@@ -883,6 +883,21 @@
 
 	dsl_dir_close(dd, FTAG);
 
+	/*
+	 * If we are creating a clone, make sure we zero out any stale
+	 * data from the origin snapshots zil header.
+	 */
+	if (origin != NULL) {
+		dsl_dataset_t *ds;
+		objset_t *os;
+
+		VERIFY3U(0, ==, dsl_dataset_hold_obj(dp, dsobj, FTAG, &ds));
+		VERIFY3U(0, ==, dmu_objset_from_ds(ds, &os));
+		bzero(&os->os_zil_header, sizeof (os->os_zil_header));
+		dsl_dataset_dirty(ds, tx);
+		dsl_dataset_rele(ds, FTAG);
+	}
+
 	return (dsobj);
 }
 
@@ -1083,11 +1098,16 @@
 		 */
 		(void) dmu_free_object(os, obj);
 	}
+	if (err != ESRCH)
+		goto out;
 
 	/*
-	 * We need to sync out all in-flight IO before we try to evict
-	 * (the dataset evict func is trying to clear the cached entries
-	 * for this dataset in the ARC).
+	 * Only the ZIL knows how to free log blocks.
+	 */
+	zil_destroy(dmu_objset_zil(os), B_FALSE);
+
+	/*
+	 * Sync out all in-flight IO.
 	 */
 	txg_wait_synced(dd->dd_pool, 0);
 
@@ -1105,9 +1125,6 @@
 		    count == 0);
 	}
 
-	if (err != ESRCH)
-		goto out;
-
 	rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER);
 	err = dsl_dir_open_obj(dd->dd_pool, dd->dd_object, NULL, FTAG, &dd);
 	rw_exit(&dd->dd_pool->dp_config_rwlock);