diff usr/src/uts/common/fs/zfs/dsl_dataset.c @ 12839:1eab9192da8b

6844896 recursive snapshots take a long time 6825126 zfs snapshot can fail with EBUSY due to unplayed logs
author Matthew Ahrens <Matthew.Ahrens@Sun.COM>
date Wed, 14 Jul 2010 16:21:46 -0700
parents f6c8601080b4
children 93cb1ac933e7
line wrap: on
line diff
--- a/usr/src/uts/common/fs/zfs/dsl_dataset.c	Wed Jul 14 15:47:07 2010 -0700
+++ b/usr/src/uts/common/fs/zfs/dsl_dataset.c	Wed Jul 14 16:21:46 2010 -0700
@@ -1622,11 +1622,6 @@
 	cv_broadcast(&ds->ds_exclusive_cv);
 	mutex_exit(&ds->ds_lock);
 
-	if (ds->ds_objset) {
-		dmu_objset_evict(ds->ds_objset);
-		ds->ds_objset = NULL;
-	}
-
 	/* Remove our reservation */
 	if (ds->ds_reserved != 0) {
 		dsl_prop_setarg_t psa;
@@ -1852,6 +1847,15 @@
 		}
 	}
 
+	/*
+	 * This must be done after the dsl_traverse(), because it will
+	 * re-open the objset.
+	 */
+	if (ds->ds_objset) {
+		dmu_objset_evict(ds->ds_objset);
+		ds->ds_objset = NULL;
+	}
+
 	if (ds->ds_dir->dd_phys->dd_head_dataset_obj == ds->ds_object) {
 		/* Erase the link in the dir */
 		dmu_buf_will_dirty(ds->ds_dir->dd_dbuf, tx);
@@ -1930,7 +1934,7 @@
 	 */
 	ASSERT(ds->ds_reserved == 0 || DS_UNIQUE_IS_ACCURATE(ds));
 	asize = MIN(ds->ds_phys->ds_unique_bytes, ds->ds_reserved);
-	if (asize > dsl_dir_space_available(ds->ds_dir, NULL, 0, FALSE))
+	if (asize > dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE))
 		return (ENOSPC);
 
 	/*
@@ -2226,8 +2230,22 @@
 	if (ds->ds_prev == NULL)
 		return (B_FALSE);
 	if (ds->ds_phys->ds_bp.blk_birth >
-	    ds->ds_prev->ds_phys->ds_creation_txg)
-		return (B_TRUE);
+	    ds->ds_prev->ds_phys->ds_creation_txg) {
+		objset_t *os, *os_prev;
+		int err;
+		/*
+		 * It may be that only the ZIL differs, because it was
+		 * reset in the head.  Don't count that as being
+		 * modified.
+		 */
+		if (dmu_objset_from_ds(ds, &os) != 0)
+			return (B_TRUE);
+		if (dmu_objset_from_ds(ds->ds_prev, &os_prev) != 0)
+			return (B_TRUE);
+		return (bcmp(&os->os_phys->os_meta_dnode,
+		    &os_prev->os_phys->os_meta_dnode,
+		    sizeof (os->os_phys->os_meta_dnode)) != 0);
+	}
 	return (B_FALSE);
 }