usr/src/uts/common/fs/zfs/dsl_dataset.c
changeset 10342 108f0058f837
parent 10298 a0d52501437c
child 10373 bcf97ee54990
--- a/usr/src/uts/common/fs/zfs/dsl_dataset.c	Tue Aug 18 20:06:58 2009 -0700
+++ b/usr/src/uts/common/fs/zfs/dsl_dataset.c	Wed Aug 19 11:15:14 2009 -0600
@@ -1000,6 +1000,11 @@
 			return (error);
 		dsda->rm_origin = origin;
 		dsl_dataset_make_exclusive(origin, tag);
+
+		if (origin->ds_objset != NULL) {
+			dmu_objset_evict(origin->ds_objset);
+			origin->ds_objset = NULL;
+		}
 	}
 
 	return (0);
@@ -1721,6 +1726,11 @@
 		ASSERT3U(err, ==, 0);
 		ASSERT(!DS_UNIQUE_IS_ACCURATE(ds) ||
 		    ds->ds_phys->ds_unique_bytes == 0);
+
+		if (ds->ds_prev != NULL) {
+			dsl_dataset_rele(ds->ds_prev, ds);
+			ds->ds_prev = ds_prev = NULL;
+		}
 	}
 
 	err = zio_wait(zio);
@@ -1782,19 +1792,9 @@
 		/*
 		 * Remove the origin of the clone we just destroyed.
 		 */
-		dsl_dataset_t *origin = ds->ds_prev;
 		struct dsl_ds_destroyarg ndsda = {0};
 
-		ASSERT3P(origin, ==, dsda->rm_origin);
-		if (origin->ds_objset) {
-			dmu_objset_evict(origin->ds_objset);
-			origin->ds_objset = NULL;
-		}
-
-		dsl_dataset_rele(ds->ds_prev, ds);
-		ds->ds_prev = NULL;
-
-		ndsda.ds = origin;
+		ndsda.ds = dsda->rm_origin;
 		dsl_dataset_destroy_sync(&ndsda, tag, cr, tx);
 	}
 }
@@ -3210,11 +3210,22 @@
 	return (err);
 }
 
+struct dsl_ds_holdarg {
+	dsl_sync_task_group_t *dstg;
+	char *htag;
+	char *snapname;
+	boolean_t recursive;
+	boolean_t gotone;
+	boolean_t temphold;
+	char failed[MAXPATHLEN];
+};
+
 static int
 dsl_dataset_user_hold_check(void *arg1, void *arg2, dmu_tx_t *tx)
 {
 	dsl_dataset_t *ds = arg1;
-	char *htag = arg2;
+	struct dsl_ds_holdarg *ha = arg2;
+	char *htag = ha->htag;
 	objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
 	int error = 0;
 
@@ -3224,9 +3235,6 @@
 	if (!dsl_dataset_is_snapshot(ds))
 		return (EINVAL);
 
-	if (strlen(htag) >= ZAP_MAXNAMELEN)
-		return (ENAMETOOLONG);
-
 	/* tags must be unique */
 	mutex_enter(&ds->ds_lock);
 	if (ds->ds_phys->ds_userrefs_obj) {
@@ -3246,8 +3254,10 @@
 dsl_dataset_user_hold_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
 {
 	dsl_dataset_t *ds = arg1;
-	char *htag = arg2;
-	objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
+	struct dsl_ds_holdarg *ha = arg2;
+	char *htag = ha->htag;
+	dsl_pool_t *dp = ds->ds_dir->dd_pool;
+	objset_t *mos = dp->dp_meta_objset;
 	time_t now = gethrestime_sec();
 	uint64_t zapobj;
 
@@ -3268,20 +3278,16 @@
 
 	VERIFY(0 == zap_add(mos, zapobj, htag, 8, 1, &now, tx));
 
+	if (ha->temphold) {
+		VERIFY(0 == dsl_pool_user_hold(dp, ds->ds_object,
+		    htag, &now, tx));
+	}
+
 	spa_history_internal_log(LOG_DS_USER_HOLD,
-	    ds->ds_dir->dd_pool->dp_spa, tx, cr, "<%s> dataset = %llu",
-	    htag, ds->ds_object);
+	    dp->dp_spa, tx, cr, "<%s> temp = %d dataset = %llu", htag,
+	    (int)ha->temphold, ds->ds_object);
 }
 
-struct dsl_ds_holdarg {
-	dsl_sync_task_group_t *dstg;
-	char *htag;
-	char *snapname;
-	boolean_t recursive;
-	boolean_t gotone;
-	char failed[MAXPATHLEN];
-};
-
 static int
 dsl_dataset_user_hold_one(char *dsname, void *arg)
 {
@@ -3297,7 +3303,7 @@
 	if (error == 0) {
 		ha->gotone = B_TRUE;
 		dsl_sync_task_create(ha->dstg, dsl_dataset_user_hold_check,
-		    dsl_dataset_user_hold_sync, ds, ha->htag, 0);
+		    dsl_dataset_user_hold_sync, ds, ha, 0);
 	} else if (error == ENOENT && ha->recursive) {
 		error = 0;
 	} else {
@@ -3308,7 +3314,7 @@
 
 int
 dsl_dataset_user_hold(char *dsname, char *snapname, char *htag,
-    boolean_t recursive)
+    boolean_t recursive, boolean_t temphold)
 {
 	struct dsl_ds_holdarg *ha;
 	dsl_sync_task_t *dst;
@@ -3329,6 +3335,7 @@
 	ha->htag = htag;
 	ha->snapname = snapname;
 	ha->recursive = recursive;
+	ha->temphold = temphold;
 	if (recursive) {
 		error = dmu_objset_find(dsname, dsl_dataset_user_hold_one,
 		    ha, DS_FIND_CHILDREN);
@@ -3446,16 +3453,19 @@
 {
 	struct dsl_ds_releasearg *ra = arg1;
 	dsl_dataset_t *ds = ra->ds;
-	spa_t *spa = ds->ds_dir->dd_pool->dp_spa;
-	objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
+	dsl_pool_t *dp = ds->ds_dir->dd_pool;
+	objset_t *mos = dp->dp_meta_objset;
 	uint64_t zapobj;
 	uint64_t dsobj = ds->ds_object;
 	uint64_t refs;
+	int error;
 
 	mutex_enter(&ds->ds_lock);
 	ds->ds_userrefs--;
 	refs = ds->ds_userrefs;
 	mutex_exit(&ds->ds_lock);
+	error = dsl_pool_user_release(dp, ds->ds_object, ra->htag, tx);
+	VERIFY(error == 0 || error == ENOENT);
 	zapobj = ds->ds_phys->ds_userrefs_obj;
 	VERIFY(0 == zap_remove(mos, zapobj, ra->htag, tx));
 	if (ds->ds_userrefs == 0 && ds->ds_phys->ds_num_children == 1 &&
@@ -3470,7 +3480,7 @@
 	}
 
 	spa_history_internal_log(LOG_DS_USER_RELEASE,
-	    spa, tx, cr, "<%s> %lld dataset = %llu",
+	    dp->dp_spa, tx, cr, "<%s> %lld dataset = %llu",
 	    ra->htag, (longlong_t)refs, dsobj);
 }
 
@@ -3486,9 +3496,6 @@
 	boolean_t own = B_FALSE;
 	boolean_t might_destroy;
 
-	if (strlen(ha->htag) >= ZAP_MAXNAMELEN)
-		return (ENAMETOOLONG);
-
 	/* alloc a buffer to hold dsname@snapname, plus the terminating NULL */
 	name = kmem_asprintf("%s@%s", dsname, ha->snapname);
 	error = dsl_dataset_hold(name, dtag, &ds);
@@ -3601,6 +3608,34 @@
 	return (error);
 }
 
+/*
+ * Called at spa_load time to release a stale temporary user hold.
+ */
+int
+dsl_dataset_user_release_tmp(dsl_pool_t *dp, uint64_t dsobj, char *htag)
+{
+	dsl_dataset_t *ds;
+	char *snap;
+	char *name;
+	int namelen;
+	int error;
+
+	rw_enter(&dp->dp_config_rwlock, RW_READER);
+	error = dsl_dataset_hold_obj(dp, dsobj, FTAG, &ds);
+	rw_exit(&dp->dp_config_rwlock);
+	if (error)
+		return (error);
+	namelen = dsl_dataset_namelen(ds)+1;
+	name = kmem_alloc(namelen, KM_SLEEP);
+	dsl_dataset_name(ds, name);
+	dsl_dataset_rele(ds, FTAG);
+
+	snap = strchr(name, '@');
+	*snap = '\0';
+	++snap;
+	return (dsl_dataset_user_release(name, snap, htag, B_FALSE));
+}
+
 int
 dsl_dataset_get_holds(const char *dsname, nvlist_t **nvp)
 {