xref: /onnv-gate/usr/src/uts/common/fs/zfs/dsl_dataset.c (revision 4603:c7840c367d00)
1789Sahrens /*
2789Sahrens  * CDDL HEADER START
3789Sahrens  *
4789Sahrens  * The contents of this file are subject to the terms of the
51544Seschrock  * Common Development and Distribution License (the "License").
61544Seschrock  * You may not use this file except in compliance with the License.
7789Sahrens  *
8789Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9789Sahrens  * or http://www.opensolaris.org/os/licensing.
10789Sahrens  * See the License for the specific language governing permissions
11789Sahrens  * and limitations under the License.
12789Sahrens  *
13789Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
14789Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15789Sahrens  * If applicable, add the following below this CDDL HEADER, with the
16789Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
17789Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
18789Sahrens  *
19789Sahrens  * CDDL HEADER END
20789Sahrens  */
21789Sahrens /*
223444Sek110237  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23789Sahrens  * Use is subject to license terms.
24789Sahrens  */
25789Sahrens 
26789Sahrens #pragma ident	"%Z%%M%	%I%	%E% SMI"
27789Sahrens 
28789Sahrens #include <sys/dmu_objset.h>
29789Sahrens #include <sys/dsl_dataset.h>
30789Sahrens #include <sys/dsl_dir.h>
312082Seschrock #include <sys/dsl_prop.h>
322199Sahrens #include <sys/dsl_synctask.h>
33789Sahrens #include <sys/dmu_traverse.h>
34789Sahrens #include <sys/dmu_tx.h>
35789Sahrens #include <sys/arc.h>
36789Sahrens #include <sys/zio.h>
37789Sahrens #include <sys/zap.h>
38789Sahrens #include <sys/unique.h>
39789Sahrens #include <sys/zfs_context.h>
404007Smmusante #include <sys/zfs_ioctl.h>
414543Smarks #include <sys/spa.h>
424543Smarks #include <sys/sunddi.h>
43789Sahrens 
442199Sahrens static dsl_checkfunc_t dsl_dataset_destroy_begin_check;
452199Sahrens static dsl_syncfunc_t dsl_dataset_destroy_begin_sync;
462199Sahrens static dsl_checkfunc_t dsl_dataset_rollback_check;
472199Sahrens static dsl_syncfunc_t dsl_dataset_rollback_sync;
482199Sahrens static dsl_checkfunc_t dsl_dataset_destroy_check;
492199Sahrens static dsl_syncfunc_t dsl_dataset_destroy_sync;
501731Sbonwick 
513444Sek110237 #define	DS_REF_MAX	(1ULL << 62)
52789Sahrens 
53789Sahrens #define	DSL_DEADLIST_BLOCKSIZE	SPA_MAXBLOCKSIZE
54789Sahrens 
55789Sahrens /*
56789Sahrens  * We use weighted reference counts to express the various forms of exclusion
57789Sahrens  * between different open modes.  A STANDARD open is 1 point, an EXCLUSIVE open
583444Sek110237  * is DS_REF_MAX, and a PRIMARY open is little more than half of an EXCLUSIVE.
59789Sahrens  * This makes the exclusion logic simple: the total refcnt for all opens cannot
603444Sek110237  * exceed DS_REF_MAX.  For example, EXCLUSIVE opens are exclusive because their
613444Sek110237  * weight (DS_REF_MAX) consumes the entire refcnt space.  PRIMARY opens consume
62789Sahrens  * just over half of the refcnt space, so there can't be more than one, but it
63789Sahrens  * can peacefully coexist with any number of STANDARD opens.
64789Sahrens  */
65789Sahrens static uint64_t ds_refcnt_weight[DS_MODE_LEVELS] = {
663444Sek110237 	0,			/* DS_MODE_NONE - invalid		*/
673444Sek110237 	1,			/* DS_MODE_STANDARD - unlimited number	*/
683444Sek110237 	(DS_REF_MAX >> 1) + 1,	/* DS_MODE_PRIMARY - only one of these	*/
693444Sek110237 	DS_REF_MAX		/* DS_MODE_EXCLUSIVE - no other opens	*/
70789Sahrens };
71789Sahrens 
72789Sahrens 
73789Sahrens void
74789Sahrens dsl_dataset_block_born(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx)
75789Sahrens {
762082Seschrock 	int used = bp_get_dasize(tx->tx_pool->dp_spa, bp);
77789Sahrens 	int compressed = BP_GET_PSIZE(bp);
78789Sahrens 	int uncompressed = BP_GET_UCSIZE(bp);
79789Sahrens 
80789Sahrens 	dprintf_bp(bp, "born, ds=%p\n", ds);
81789Sahrens 
82789Sahrens 	ASSERT(dmu_tx_is_syncing(tx));
83789Sahrens 	/* It could have been compressed away to nothing */
84789Sahrens 	if (BP_IS_HOLE(bp))
85789Sahrens 		return;
86789Sahrens 	ASSERT(BP_GET_TYPE(bp) != DMU_OT_NONE);
87789Sahrens 	ASSERT3U(BP_GET_TYPE(bp), <, DMU_OT_NUMTYPES);
88789Sahrens 	if (ds == NULL) {
89789Sahrens 		/*
90789Sahrens 		 * Account for the meta-objset space in its placeholder
91789Sahrens 		 * dsl_dir.
92789Sahrens 		 */
93789Sahrens 		ASSERT3U(compressed, ==, uncompressed); /* it's all metadata */
94789Sahrens 		dsl_dir_diduse_space(tx->tx_pool->dp_mos_dir,
95789Sahrens 		    used, compressed, uncompressed, tx);
96789Sahrens 		dsl_dir_dirty(tx->tx_pool->dp_mos_dir, tx);
97789Sahrens 		return;
98789Sahrens 	}
99789Sahrens 	dmu_buf_will_dirty(ds->ds_dbuf, tx);
100789Sahrens 	mutex_enter(&ds->ds_lock);
101789Sahrens 	ds->ds_phys->ds_used_bytes += used;
102789Sahrens 	ds->ds_phys->ds_compressed_bytes += compressed;
103789Sahrens 	ds->ds_phys->ds_uncompressed_bytes += uncompressed;
104789Sahrens 	ds->ds_phys->ds_unique_bytes += used;
105789Sahrens 	mutex_exit(&ds->ds_lock);
106789Sahrens 	dsl_dir_diduse_space(ds->ds_dir,
107789Sahrens 	    used, compressed, uncompressed, tx);
108789Sahrens }
109789Sahrens 
110789Sahrens void
1113547Smaybee dsl_dataset_block_kill(dsl_dataset_t *ds, blkptr_t *bp, zio_t *pio,
1123547Smaybee     dmu_tx_t *tx)
113789Sahrens {
1142082Seschrock 	int used = bp_get_dasize(tx->tx_pool->dp_spa, bp);
115789Sahrens 	int compressed = BP_GET_PSIZE(bp);
116789Sahrens 	int uncompressed = BP_GET_UCSIZE(bp);
117789Sahrens 
118789Sahrens 	ASSERT(dmu_tx_is_syncing(tx));
1193547Smaybee 	/* No block pointer => nothing to free */
120789Sahrens 	if (BP_IS_HOLE(bp))
121789Sahrens 		return;
122789Sahrens 
123789Sahrens 	ASSERT(used > 0);
124789Sahrens 	if (ds == NULL) {
1253547Smaybee 		int err;
126789Sahrens 		/*
127789Sahrens 		 * Account for the meta-objset space in its placeholder
128789Sahrens 		 * dataset.
129789Sahrens 		 */
1303547Smaybee 		err = arc_free(pio, tx->tx_pool->dp_spa,
1313547Smaybee 		    tx->tx_txg, bp, NULL, NULL, pio ? ARC_NOWAIT: ARC_WAIT);
1323547Smaybee 		ASSERT(err == 0);
133789Sahrens 
134789Sahrens 		dsl_dir_diduse_space(tx->tx_pool->dp_mos_dir,
135789Sahrens 		    -used, -compressed, -uncompressed, tx);
136789Sahrens 		dsl_dir_dirty(tx->tx_pool->dp_mos_dir, tx);
137789Sahrens 		return;
138789Sahrens 	}
139789Sahrens 	ASSERT3P(tx->tx_pool, ==, ds->ds_dir->dd_pool);
140789Sahrens 
141789Sahrens 	dmu_buf_will_dirty(ds->ds_dbuf, tx);
142789Sahrens 
143789Sahrens 	if (bp->blk_birth > ds->ds_phys->ds_prev_snap_txg) {
1443547Smaybee 		int err;
1453547Smaybee 
146789Sahrens 		dprintf_bp(bp, "freeing: %s", "");
1473547Smaybee 		err = arc_free(pio, tx->tx_pool->dp_spa,
1483547Smaybee 		    tx->tx_txg, bp, NULL, NULL, pio ? ARC_NOWAIT: ARC_WAIT);
1493547Smaybee 		ASSERT(err == 0);
150789Sahrens 
151789Sahrens 		mutex_enter(&ds->ds_lock);
152789Sahrens 		/* XXX unique_bytes is not accurate for head datasets */
153789Sahrens 		/* ASSERT3U(ds->ds_phys->ds_unique_bytes, >=, used); */
154789Sahrens 		ds->ds_phys->ds_unique_bytes -= used;
155789Sahrens 		mutex_exit(&ds->ds_lock);
156789Sahrens 		dsl_dir_diduse_space(ds->ds_dir,
157789Sahrens 		    -used, -compressed, -uncompressed, tx);
158789Sahrens 	} else {
159789Sahrens 		dprintf_bp(bp, "putting on dead list: %s", "");
1601544Seschrock 		VERIFY(0 == bplist_enqueue(&ds->ds_deadlist, bp, tx));
161789Sahrens 		/* if (bp->blk_birth > prev prev snap txg) prev unique += bs */
162789Sahrens 		if (ds->ds_phys->ds_prev_snap_obj != 0) {
163789Sahrens 			ASSERT3U(ds->ds_prev->ds_object, ==,
164789Sahrens 			    ds->ds_phys->ds_prev_snap_obj);
165789Sahrens 			ASSERT(ds->ds_prev->ds_phys->ds_num_children > 0);
166789Sahrens 			if (ds->ds_prev->ds_phys->ds_next_snap_obj ==
1672082Seschrock 			    ds->ds_object && bp->blk_birth >
168789Sahrens 			    ds->ds_prev->ds_phys->ds_prev_snap_txg) {
169789Sahrens 				dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx);
170789Sahrens 				mutex_enter(&ds->ds_prev->ds_lock);
171789Sahrens 				ds->ds_prev->ds_phys->ds_unique_bytes +=
172789Sahrens 				    used;
173789Sahrens 				mutex_exit(&ds->ds_prev->ds_lock);
174789Sahrens 			}
175789Sahrens 		}
176789Sahrens 	}
177789Sahrens 	mutex_enter(&ds->ds_lock);
178789Sahrens 	ASSERT3U(ds->ds_phys->ds_used_bytes, >=, used);
179789Sahrens 	ds->ds_phys->ds_used_bytes -= used;
180789Sahrens 	ASSERT3U(ds->ds_phys->ds_compressed_bytes, >=, compressed);
181789Sahrens 	ds->ds_phys->ds_compressed_bytes -= compressed;
182789Sahrens 	ASSERT3U(ds->ds_phys->ds_uncompressed_bytes, >=, uncompressed);
183789Sahrens 	ds->ds_phys->ds_uncompressed_bytes -= uncompressed;
184789Sahrens 	mutex_exit(&ds->ds_lock);
185789Sahrens }
186789Sahrens 
1871544Seschrock uint64_t
1881544Seschrock dsl_dataset_prev_snap_txg(dsl_dataset_t *ds)
189789Sahrens {
1902885Sahrens 	uint64_t trysnap = 0;
1912885Sahrens 
192789Sahrens 	if (ds == NULL)
1931544Seschrock 		return (0);
194789Sahrens 	/*
195789Sahrens 	 * The snapshot creation could fail, but that would cause an
196789Sahrens 	 * incorrect FALSE return, which would only result in an
197789Sahrens 	 * overestimation of the amount of space that an operation would
198789Sahrens 	 * consume, which is OK.
199789Sahrens 	 *
200789Sahrens 	 * There's also a small window where we could miss a pending
201789Sahrens 	 * snapshot, because we could set the sync task in the quiescing
202789Sahrens 	 * phase.  So this should only be used as a guess.
203789Sahrens 	 */
2042885Sahrens 	if (ds->ds_trysnap_txg >
2052885Sahrens 	    spa_last_synced_txg(ds->ds_dir->dd_pool->dp_spa))
2062885Sahrens 		trysnap = ds->ds_trysnap_txg;
2072885Sahrens 	return (MAX(ds->ds_phys->ds_prev_snap_txg, trysnap));
2081544Seschrock }
2091544Seschrock 
2101544Seschrock int
2111544Seschrock dsl_dataset_block_freeable(dsl_dataset_t *ds, uint64_t blk_birth)
2121544Seschrock {
2131544Seschrock 	return (blk_birth > dsl_dataset_prev_snap_txg(ds));
214789Sahrens }
215789Sahrens 
216789Sahrens /* ARGSUSED */
217789Sahrens static void
218789Sahrens dsl_dataset_evict(dmu_buf_t *db, void *dsv)
219789Sahrens {
220789Sahrens 	dsl_dataset_t *ds = dsv;
221789Sahrens 	dsl_pool_t *dp = ds->ds_dir->dd_pool;
222789Sahrens 
2233444Sek110237 	/* open_refcount == DS_REF_MAX when deleting */
224789Sahrens 	ASSERT(ds->ds_open_refcount == 0 ||
2253444Sek110237 	    ds->ds_open_refcount == DS_REF_MAX);
226789Sahrens 
227789Sahrens 	dprintf_ds(ds, "evicting %s\n", "");
228789Sahrens 
229789Sahrens 	unique_remove(ds->ds_phys->ds_fsid_guid);
230789Sahrens 
231789Sahrens 	if (ds->ds_user_ptr != NULL)
232789Sahrens 		ds->ds_user_evict_func(ds, ds->ds_user_ptr);
233789Sahrens 
234789Sahrens 	if (ds->ds_prev) {
235789Sahrens 		dsl_dataset_close(ds->ds_prev, DS_MODE_NONE, ds);
236789Sahrens 		ds->ds_prev = NULL;
237789Sahrens 	}
238789Sahrens 
239789Sahrens 	bplist_close(&ds->ds_deadlist);
240789Sahrens 	dsl_dir_close(ds->ds_dir, ds);
241789Sahrens 
242789Sahrens 	if (list_link_active(&ds->ds_synced_link))
243789Sahrens 		list_remove(&dp->dp_synced_objsets, ds);
244789Sahrens 
2452856Snd150628 	mutex_destroy(&ds->ds_lock);
2462856Snd150628 	mutex_destroy(&ds->ds_deadlist.bpl_lock);
2472856Snd150628 
248789Sahrens 	kmem_free(ds, sizeof (dsl_dataset_t));
249789Sahrens }
250789Sahrens 
2511544Seschrock static int
252789Sahrens dsl_dataset_get_snapname(dsl_dataset_t *ds)
253789Sahrens {
254789Sahrens 	dsl_dataset_phys_t *headphys;
255789Sahrens 	int err;
256789Sahrens 	dmu_buf_t *headdbuf;
257789Sahrens 	dsl_pool_t *dp = ds->ds_dir->dd_pool;
258789Sahrens 	objset_t *mos = dp->dp_meta_objset;
259789Sahrens 
260789Sahrens 	if (ds->ds_snapname[0])
2611544Seschrock 		return (0);
262789Sahrens 	if (ds->ds_phys->ds_next_snap_obj == 0)
2631544Seschrock 		return (0);
264789Sahrens 
2651544Seschrock 	err = dmu_bonus_hold(mos, ds->ds_dir->dd_phys->dd_head_dataset_obj,
2661544Seschrock 	    FTAG, &headdbuf);
2671544Seschrock 	if (err)
2681544Seschrock 		return (err);
269789Sahrens 	headphys = headdbuf->db_data;
270789Sahrens 	err = zap_value_search(dp->dp_meta_objset,
2714577Sahrens 	    headphys->ds_snapnames_zapobj, ds->ds_object, 0, ds->ds_snapname);
2721544Seschrock 	dmu_buf_rele(headdbuf, FTAG);
2731544Seschrock 	return (err);
274789Sahrens }
275789Sahrens 
2761544Seschrock int
277789Sahrens dsl_dataset_open_obj(dsl_pool_t *dp, uint64_t dsobj, const char *snapname,
2781544Seschrock     int mode, void *tag, dsl_dataset_t **dsp)
279789Sahrens {
280789Sahrens 	uint64_t weight = ds_refcnt_weight[DS_MODE_LEVEL(mode)];
281789Sahrens 	objset_t *mos = dp->dp_meta_objset;
282789Sahrens 	dmu_buf_t *dbuf;
283789Sahrens 	dsl_dataset_t *ds;
2841544Seschrock 	int err;
285789Sahrens 
286789Sahrens 	ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock) ||
287789Sahrens 	    dsl_pool_sync_context(dp));
288789Sahrens 
2891544Seschrock 	err = dmu_bonus_hold(mos, dsobj, tag, &dbuf);
2901544Seschrock 	if (err)
2911544Seschrock 		return (err);
292789Sahrens 	ds = dmu_buf_get_user(dbuf);
293789Sahrens 	if (ds == NULL) {
294789Sahrens 		dsl_dataset_t *winner;
295789Sahrens 
296789Sahrens 		ds = kmem_zalloc(sizeof (dsl_dataset_t), KM_SLEEP);
297789Sahrens 		ds->ds_dbuf = dbuf;
298789Sahrens 		ds->ds_object = dsobj;
299789Sahrens 		ds->ds_phys = dbuf->db_data;
300789Sahrens 
3012856Snd150628 		mutex_init(&ds->ds_lock, NULL, MUTEX_DEFAULT, NULL);
3022856Snd150628 		mutex_init(&ds->ds_deadlist.bpl_lock, NULL, MUTEX_DEFAULT,
3032856Snd150628 		    NULL);
3042856Snd150628 
3051544Seschrock 		err = bplist_open(&ds->ds_deadlist,
306789Sahrens 		    mos, ds->ds_phys->ds_deadlist_obj);
3071544Seschrock 		if (err == 0) {
3081544Seschrock 			err = dsl_dir_open_obj(dp,
3091544Seschrock 			    ds->ds_phys->ds_dir_obj, NULL, ds, &ds->ds_dir);
3101544Seschrock 		}
3111544Seschrock 		if (err) {
3121544Seschrock 			/*
3131544Seschrock 			 * we don't really need to close the blist if we
3141544Seschrock 			 * just opened it.
3151544Seschrock 			 */
3162856Snd150628 			mutex_destroy(&ds->ds_lock);
3172856Snd150628 			mutex_destroy(&ds->ds_deadlist.bpl_lock);
3181544Seschrock 			kmem_free(ds, sizeof (dsl_dataset_t));
3191544Seschrock 			dmu_buf_rele(dbuf, tag);
3201544Seschrock 			return (err);
3211544Seschrock 		}
322789Sahrens 
323789Sahrens 		if (ds->ds_dir->dd_phys->dd_head_dataset_obj == dsobj) {
324789Sahrens 			ds->ds_snapname[0] = '\0';
325789Sahrens 			if (ds->ds_phys->ds_prev_snap_obj) {
3261544Seschrock 				err = dsl_dataset_open_obj(dp,
327789Sahrens 				    ds->ds_phys->ds_prev_snap_obj, NULL,
3281544Seschrock 				    DS_MODE_NONE, ds, &ds->ds_prev);
329789Sahrens 			}
330789Sahrens 		} else {
331789Sahrens 			if (snapname) {
332789Sahrens #ifdef ZFS_DEBUG
333789Sahrens 				dsl_dataset_phys_t *headphys;
3341544Seschrock 				dmu_buf_t *headdbuf;
3351544Seschrock 				err = dmu_bonus_hold(mos,
3361544Seschrock 				    ds->ds_dir->dd_phys->dd_head_dataset_obj,
3371544Seschrock 				    FTAG, &headdbuf);
3381544Seschrock 				if (err == 0) {
3391544Seschrock 					headphys = headdbuf->db_data;
3401544Seschrock 					uint64_t foundobj;
3411544Seschrock 					err = zap_lookup(dp->dp_meta_objset,
3421544Seschrock 					    headphys->ds_snapnames_zapobj,
3431544Seschrock 					    snapname, sizeof (foundobj), 1,
3441544Seschrock 					    &foundobj);
3451544Seschrock 					ASSERT3U(foundobj, ==, dsobj);
3461544Seschrock 					dmu_buf_rele(headdbuf, FTAG);
3471544Seschrock 				}
348789Sahrens #endif
349789Sahrens 				(void) strcat(ds->ds_snapname, snapname);
350789Sahrens 			} else if (zfs_flags & ZFS_DEBUG_SNAPNAMES) {
3511544Seschrock 				err = dsl_dataset_get_snapname(ds);
352789Sahrens 			}
353789Sahrens 		}
354789Sahrens 
3551544Seschrock 		if (err == 0) {
3561544Seschrock 			winner = dmu_buf_set_user_ie(dbuf, ds, &ds->ds_phys,
3571544Seschrock 			    dsl_dataset_evict);
3581544Seschrock 		}
3591544Seschrock 		if (err || winner) {
360789Sahrens 			bplist_close(&ds->ds_deadlist);
361789Sahrens 			if (ds->ds_prev) {
362789Sahrens 				dsl_dataset_close(ds->ds_prev,
363789Sahrens 				    DS_MODE_NONE, ds);
364789Sahrens 			}
365789Sahrens 			dsl_dir_close(ds->ds_dir, ds);
3662856Snd150628 			mutex_destroy(&ds->ds_lock);
3672856Snd150628 			mutex_destroy(&ds->ds_deadlist.bpl_lock);
368789Sahrens 			kmem_free(ds, sizeof (dsl_dataset_t));
3691544Seschrock 			if (err) {
3701544Seschrock 				dmu_buf_rele(dbuf, tag);
3711544Seschrock 				return (err);
3721544Seschrock 			}
373789Sahrens 			ds = winner;
374789Sahrens 		} else {
375789Sahrens 			uint64_t new =
376789Sahrens 			    unique_insert(ds->ds_phys->ds_fsid_guid);
377789Sahrens 			if (new != ds->ds_phys->ds_fsid_guid) {
378789Sahrens 				/* XXX it won't necessarily be synced... */
379789Sahrens 				ds->ds_phys->ds_fsid_guid = new;
380789Sahrens 			}
381789Sahrens 		}
382789Sahrens 	}
383789Sahrens 	ASSERT3P(ds->ds_dbuf, ==, dbuf);
384789Sahrens 	ASSERT3P(ds->ds_phys, ==, dbuf->db_data);
385789Sahrens 
386789Sahrens 	mutex_enter(&ds->ds_lock);
387789Sahrens 	if ((DS_MODE_LEVEL(mode) == DS_MODE_PRIMARY &&
3882082Seschrock 	    (ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT) &&
3892082Seschrock 	    !DS_MODE_IS_INCONSISTENT(mode)) ||
3903444Sek110237 	    (ds->ds_open_refcount + weight > DS_REF_MAX)) {
391789Sahrens 		mutex_exit(&ds->ds_lock);
392789Sahrens 		dsl_dataset_close(ds, DS_MODE_NONE, tag);
3931544Seschrock 		return (EBUSY);
394789Sahrens 	}
395789Sahrens 	ds->ds_open_refcount += weight;
396789Sahrens 	mutex_exit(&ds->ds_lock);
397789Sahrens 
3981544Seschrock 	*dsp = ds;
3991544Seschrock 	return (0);
400789Sahrens }
401789Sahrens 
402789Sahrens int
403789Sahrens dsl_dataset_open_spa(spa_t *spa, const char *name, int mode,
404789Sahrens     void *tag, dsl_dataset_t **dsp)
405789Sahrens {
406789Sahrens 	dsl_dir_t *dd;
407789Sahrens 	dsl_pool_t *dp;
408789Sahrens 	const char *tail;
409789Sahrens 	uint64_t obj;
410789Sahrens 	dsl_dataset_t *ds = NULL;
411789Sahrens 	int err = 0;
412789Sahrens 
4131544Seschrock 	err = dsl_dir_open_spa(spa, name, FTAG, &dd, &tail);
4141544Seschrock 	if (err)
4151544Seschrock 		return (err);
416789Sahrens 
417789Sahrens 	dp = dd->dd_pool;
418789Sahrens 	obj = dd->dd_phys->dd_head_dataset_obj;
419789Sahrens 	rw_enter(&dp->dp_config_rwlock, RW_READER);
420789Sahrens 	if (obj == 0) {
421789Sahrens 		/* A dataset with no associated objset */
422789Sahrens 		err = ENOENT;
423789Sahrens 		goto out;
424789Sahrens 	}
425789Sahrens 
426789Sahrens 	if (tail != NULL) {
427789Sahrens 		objset_t *mos = dp->dp_meta_objset;
428789Sahrens 
4291544Seschrock 		err = dsl_dataset_open_obj(dp, obj, NULL,
4301544Seschrock 		    DS_MODE_NONE, tag, &ds);
4311544Seschrock 		if (err)
4321544Seschrock 			goto out;
433789Sahrens 		obj = ds->ds_phys->ds_snapnames_zapobj;
434789Sahrens 		dsl_dataset_close(ds, DS_MODE_NONE, tag);
435789Sahrens 		ds = NULL;
436789Sahrens 
437789Sahrens 		if (tail[0] != '@') {
438789Sahrens 			err = ENOENT;
439789Sahrens 			goto out;
440789Sahrens 		}
441789Sahrens 		tail++;
442789Sahrens 
443789Sahrens 		/* Look for a snapshot */
444789Sahrens 		if (!DS_MODE_IS_READONLY(mode)) {
445789Sahrens 			err = EROFS;
446789Sahrens 			goto out;
447789Sahrens 		}
448789Sahrens 		dprintf("looking for snapshot '%s'\n", tail);
449789Sahrens 		err = zap_lookup(mos, obj, tail, 8, 1, &obj);
450789Sahrens 		if (err)
451789Sahrens 			goto out;
452789Sahrens 	}
4531544Seschrock 	err = dsl_dataset_open_obj(dp, obj, tail, mode, tag, &ds);
454789Sahrens 
455789Sahrens out:
456789Sahrens 	rw_exit(&dp->dp_config_rwlock);
457789Sahrens 	dsl_dir_close(dd, FTAG);
458789Sahrens 
459789Sahrens 	ASSERT3U((err == 0), ==, (ds != NULL));
460789Sahrens 	/* ASSERT(ds == NULL || strcmp(name, ds->ds_name) == 0); */
461789Sahrens 
462789Sahrens 	*dsp = ds;
463789Sahrens 	return (err);
464789Sahrens }
465789Sahrens 
466789Sahrens int
467789Sahrens dsl_dataset_open(const char *name, int mode, void *tag, dsl_dataset_t **dsp)
468789Sahrens {
469789Sahrens 	return (dsl_dataset_open_spa(NULL, name, mode, tag, dsp));
470789Sahrens }
471789Sahrens 
472789Sahrens void
473789Sahrens dsl_dataset_name(dsl_dataset_t *ds, char *name)
474789Sahrens {
475789Sahrens 	if (ds == NULL) {
476789Sahrens 		(void) strcpy(name, "mos");
477789Sahrens 	} else {
478789Sahrens 		dsl_dir_name(ds->ds_dir, name);
4791544Seschrock 		VERIFY(0 == dsl_dataset_get_snapname(ds));
480789Sahrens 		if (ds->ds_snapname[0]) {
481789Sahrens 			(void) strcat(name, "@");
482789Sahrens 			if (!MUTEX_HELD(&ds->ds_lock)) {
483789Sahrens 				/*
484789Sahrens 				 * We use a "recursive" mutex so that we
485789Sahrens 				 * can call dprintf_ds() with ds_lock held.
486789Sahrens 				 */
487789Sahrens 				mutex_enter(&ds->ds_lock);
488789Sahrens 				(void) strcat(name, ds->ds_snapname);
489789Sahrens 				mutex_exit(&ds->ds_lock);
490789Sahrens 			} else {
491789Sahrens 				(void) strcat(name, ds->ds_snapname);
492789Sahrens 			}
493789Sahrens 		}
494789Sahrens 	}
495789Sahrens }
496789Sahrens 
4973978Smmusante static int
4983978Smmusante dsl_dataset_namelen(dsl_dataset_t *ds)
4993978Smmusante {
5003978Smmusante 	int result;
5013978Smmusante 
5023978Smmusante 	if (ds == NULL) {
5033978Smmusante 		result = 3;	/* "mos" */
5043978Smmusante 	} else {
5053978Smmusante 		result = dsl_dir_namelen(ds->ds_dir);
5063978Smmusante 		VERIFY(0 == dsl_dataset_get_snapname(ds));
5073978Smmusante 		if (ds->ds_snapname[0]) {
5083978Smmusante 			++result;	/* adding one for the @-sign */
5093978Smmusante 			if (!MUTEX_HELD(&ds->ds_lock)) {
5103978Smmusante 				/* see dsl_datset_name */
5113978Smmusante 				mutex_enter(&ds->ds_lock);
5123978Smmusante 				result += strlen(ds->ds_snapname);
5133978Smmusante 				mutex_exit(&ds->ds_lock);
5143978Smmusante 			} else {
5153978Smmusante 				result += strlen(ds->ds_snapname);
5163978Smmusante 			}
5173978Smmusante 		}
5183978Smmusante 	}
5193978Smmusante 
5203978Smmusante 	return (result);
5213978Smmusante }
5223978Smmusante 
523789Sahrens void
524789Sahrens dsl_dataset_close(dsl_dataset_t *ds, int mode, void *tag)
525789Sahrens {
526789Sahrens 	uint64_t weight = ds_refcnt_weight[DS_MODE_LEVEL(mode)];
527789Sahrens 	mutex_enter(&ds->ds_lock);
528789Sahrens 	ASSERT3U(ds->ds_open_refcount, >=, weight);
529789Sahrens 	ds->ds_open_refcount -= weight;
530789Sahrens 	dprintf_ds(ds, "closing mode %u refcount now 0x%llx\n",
531789Sahrens 	    mode, ds->ds_open_refcount);
532789Sahrens 	mutex_exit(&ds->ds_lock);
533789Sahrens 
5341544Seschrock 	dmu_buf_rele(ds->ds_dbuf, tag);
535789Sahrens }
536789Sahrens 
537789Sahrens void
538789Sahrens dsl_dataset_create_root(dsl_pool_t *dp, uint64_t *ddobjp, dmu_tx_t *tx)
539789Sahrens {
540789Sahrens 	objset_t *mos = dp->dp_meta_objset;
541789Sahrens 	dmu_buf_t *dbuf;
542789Sahrens 	dsl_dataset_phys_t *dsphys;
543789Sahrens 	dsl_dataset_t *ds;
544789Sahrens 	uint64_t dsobj;
545789Sahrens 	dsl_dir_t *dd;
546789Sahrens 
547789Sahrens 	dsl_dir_create_root(mos, ddobjp, tx);
5481544Seschrock 	VERIFY(0 == dsl_dir_open_obj(dp, *ddobjp, NULL, FTAG, &dd));
549789Sahrens 
550928Stabriz 	dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0,
551928Stabriz 	    DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx);
5521544Seschrock 	VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf));
553789Sahrens 	dmu_buf_will_dirty(dbuf, tx);
554789Sahrens 	dsphys = dbuf->db_data;
555789Sahrens 	dsphys->ds_dir_obj = dd->dd_object;
556789Sahrens 	dsphys->ds_fsid_guid = unique_create();
5571544Seschrock 	unique_remove(dsphys->ds_fsid_guid); /* it isn't open yet */
558789Sahrens 	(void) random_get_pseudo_bytes((void*)&dsphys->ds_guid,
559789Sahrens 	    sizeof (dsphys->ds_guid));
560789Sahrens 	dsphys->ds_snapnames_zapobj =
561885Sahrens 	    zap_create(mos, DMU_OT_DSL_DS_SNAP_MAP, DMU_OT_NONE, 0, tx);
562789Sahrens 	dsphys->ds_creation_time = gethrestime_sec();
563789Sahrens 	dsphys->ds_creation_txg = tx->tx_txg;
564789Sahrens 	dsphys->ds_deadlist_obj =
565789Sahrens 	    bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx);
5661544Seschrock 	dmu_buf_rele(dbuf, FTAG);
567789Sahrens 
568789Sahrens 	dmu_buf_will_dirty(dd->dd_dbuf, tx);
569789Sahrens 	dd->dd_phys->dd_head_dataset_obj = dsobj;
570789Sahrens 	dsl_dir_close(dd, FTAG);
571789Sahrens 
5721544Seschrock 	VERIFY(0 ==
5731544Seschrock 	    dsl_dataset_open_obj(dp, dsobj, NULL, DS_MODE_NONE, FTAG, &ds));
5743547Smaybee 	(void) dmu_objset_create_impl(dp->dp_spa, ds,
5753547Smaybee 	    &ds->ds_phys->ds_bp, DMU_OST_ZFS, tx);
576789Sahrens 	dsl_dataset_close(ds, DS_MODE_NONE, FTAG);
577789Sahrens }
578789Sahrens 
5792199Sahrens uint64_t
5802199Sahrens dsl_dataset_create_sync(dsl_dir_t *pdd,
581789Sahrens     const char *lastname, dsl_dataset_t *clone_parent, dmu_tx_t *tx)
582789Sahrens {
5832199Sahrens 	dsl_pool_t *dp = pdd->dd_pool;
584789Sahrens 	dmu_buf_t *dbuf;
585789Sahrens 	dsl_dataset_phys_t *dsphys;
5862199Sahrens 	uint64_t dsobj, ddobj;
587789Sahrens 	objset_t *mos = dp->dp_meta_objset;
588789Sahrens 	dsl_dir_t *dd;
589789Sahrens 
5902199Sahrens 	ASSERT(clone_parent == NULL || clone_parent->ds_dir->dd_pool == dp);
5912199Sahrens 	ASSERT(clone_parent == NULL ||
5922199Sahrens 	    clone_parent->ds_phys->ds_num_children > 0);
593789Sahrens 	ASSERT(lastname[0] != '@');
594789Sahrens 	ASSERT(dmu_tx_is_syncing(tx));
595789Sahrens 
5962199Sahrens 	ddobj = dsl_dir_create_sync(pdd, lastname, tx);
5972199Sahrens 	VERIFY(0 == dsl_dir_open_obj(dp, ddobj, lastname, FTAG, &dd));
598789Sahrens 
599928Stabriz 	dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0,
600928Stabriz 	    DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx);
6011544Seschrock 	VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf));
602789Sahrens 	dmu_buf_will_dirty(dbuf, tx);
603789Sahrens 	dsphys = dbuf->db_data;
604789Sahrens 	dsphys->ds_dir_obj = dd->dd_object;
605789Sahrens 	dsphys->ds_fsid_guid = unique_create();
606789Sahrens 	unique_remove(dsphys->ds_fsid_guid); /* it isn't open yet */
607789Sahrens 	(void) random_get_pseudo_bytes((void*)&dsphys->ds_guid,
608789Sahrens 	    sizeof (dsphys->ds_guid));
609789Sahrens 	dsphys->ds_snapnames_zapobj =
610885Sahrens 	    zap_create(mos, DMU_OT_DSL_DS_SNAP_MAP, DMU_OT_NONE, 0, tx);
611789Sahrens 	dsphys->ds_creation_time = gethrestime_sec();
612789Sahrens 	dsphys->ds_creation_txg = tx->tx_txg;
613789Sahrens 	dsphys->ds_deadlist_obj =
614789Sahrens 	    bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx);
615789Sahrens 	if (clone_parent) {
616789Sahrens 		dsphys->ds_prev_snap_obj = clone_parent->ds_object;
617789Sahrens 		dsphys->ds_prev_snap_txg =
618789Sahrens 		    clone_parent->ds_phys->ds_creation_txg;
619789Sahrens 		dsphys->ds_used_bytes =
620789Sahrens 		    clone_parent->ds_phys->ds_used_bytes;
621789Sahrens 		dsphys->ds_compressed_bytes =
622789Sahrens 		    clone_parent->ds_phys->ds_compressed_bytes;
623789Sahrens 		dsphys->ds_uncompressed_bytes =
624789Sahrens 		    clone_parent->ds_phys->ds_uncompressed_bytes;
625789Sahrens 		dsphys->ds_bp = clone_parent->ds_phys->ds_bp;
626789Sahrens 
627789Sahrens 		dmu_buf_will_dirty(clone_parent->ds_dbuf, tx);
628789Sahrens 		clone_parent->ds_phys->ds_num_children++;
629789Sahrens 
630789Sahrens 		dmu_buf_will_dirty(dd->dd_dbuf, tx);
631789Sahrens 		dd->dd_phys->dd_clone_parent_obj = clone_parent->ds_object;
632789Sahrens 	}
6331544Seschrock 	dmu_buf_rele(dbuf, FTAG);
634789Sahrens 
635789Sahrens 	dmu_buf_will_dirty(dd->dd_dbuf, tx);
636789Sahrens 	dd->dd_phys->dd_head_dataset_obj = dsobj;
637789Sahrens 	dsl_dir_close(dd, FTAG);
638789Sahrens 
6392199Sahrens 	return (dsobj);
6402199Sahrens }
6412199Sahrens 
6422199Sahrens struct destroyarg {
6432199Sahrens 	dsl_sync_task_group_t *dstg;
6442199Sahrens 	char *snapname;
6452199Sahrens 	char *failed;
6462199Sahrens };
6472199Sahrens 
6482199Sahrens static int
6492199Sahrens dsl_snapshot_destroy_one(char *name, void *arg)
6502199Sahrens {
6512199Sahrens 	struct destroyarg *da = arg;
6522199Sahrens 	dsl_dataset_t *ds;
6532199Sahrens 	char *cp;
6542199Sahrens 	int err;
6552199Sahrens 
6562199Sahrens 	(void) strcat(name, "@");
6572199Sahrens 	(void) strcat(name, da->snapname);
6582199Sahrens 	err = dsl_dataset_open(name,
6592199Sahrens 	    DS_MODE_EXCLUSIVE | DS_MODE_READONLY | DS_MODE_INCONSISTENT,
6604007Smmusante 	    da->dstg, &ds);
6612199Sahrens 	cp = strchr(name, '@');
6622199Sahrens 	*cp = '\0';
6632199Sahrens 	if (err == ENOENT)
6642199Sahrens 		return (0);
6652199Sahrens 	if (err) {
6662199Sahrens 		(void) strcpy(da->failed, name);
6672199Sahrens 		return (err);
6682199Sahrens 	}
6692199Sahrens 
6702199Sahrens 	dsl_sync_task_create(da->dstg, dsl_dataset_destroy_check,
6714007Smmusante 	    dsl_dataset_destroy_sync, ds, da->dstg, 0);
672789Sahrens 	return (0);
673789Sahrens }
674789Sahrens 
6752199Sahrens /*
6762199Sahrens  * Destroy 'snapname' in all descendants of 'fsname'.
6772199Sahrens  */
6782199Sahrens #pragma weak dmu_snapshots_destroy = dsl_snapshots_destroy
6792199Sahrens int
6802199Sahrens dsl_snapshots_destroy(char *fsname, char *snapname)
6812199Sahrens {
6822199Sahrens 	int err;
6832199Sahrens 	struct destroyarg da;
6842199Sahrens 	dsl_sync_task_t *dst;
6852199Sahrens 	spa_t *spa;
6862199Sahrens 
687*4603Sahrens 	err = spa_open(fsname, &spa, FTAG);
6882199Sahrens 	if (err)
6892199Sahrens 		return (err);
6902199Sahrens 	da.dstg = dsl_sync_task_group_create(spa_get_dsl(spa));
6912199Sahrens 	da.snapname = snapname;
6922199Sahrens 	da.failed = fsname;
6932199Sahrens 
6942199Sahrens 	err = dmu_objset_find(fsname,
6952417Sahrens 	    dsl_snapshot_destroy_one, &da, DS_FIND_CHILDREN);
6962199Sahrens 
6972199Sahrens 	if (err == 0)
6982199Sahrens 		err = dsl_sync_task_group_wait(da.dstg);
6992199Sahrens 
7002199Sahrens 	for (dst = list_head(&da.dstg->dstg_tasks); dst;
7012199Sahrens 	    dst = list_next(&da.dstg->dstg_tasks, dst)) {
7022199Sahrens 		dsl_dataset_t *ds = dst->dst_arg1;
7032199Sahrens 		if (dst->dst_err) {
7042199Sahrens 			dsl_dataset_name(ds, fsname);
705*4603Sahrens 			*strchr(fsname, '@') = '\0';
7062199Sahrens 		}
7072199Sahrens 		/*
7082199Sahrens 		 * If it was successful, destroy_sync would have
7092199Sahrens 		 * closed the ds
7102199Sahrens 		 */
7112199Sahrens 		if (err)
7124007Smmusante 			dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, da.dstg);
7132199Sahrens 	}
7142199Sahrens 
7152199Sahrens 	dsl_sync_task_group_destroy(da.dstg);
7162199Sahrens 	spa_close(spa, FTAG);
7172199Sahrens 	return (err);
7182199Sahrens }
7192199Sahrens 
720789Sahrens int
721789Sahrens dsl_dataset_destroy(const char *name)
722789Sahrens {
723789Sahrens 	int err;
7242199Sahrens 	dsl_sync_task_group_t *dstg;
7252199Sahrens 	objset_t *os;
7262199Sahrens 	dsl_dataset_t *ds;
727789Sahrens 	dsl_dir_t *dd;
7282199Sahrens 	uint64_t obj;
7292199Sahrens 
7302199Sahrens 	if (strchr(name, '@')) {
7312199Sahrens 		/* Destroying a snapshot is simpler */
7322199Sahrens 		err = dsl_dataset_open(name,
7332199Sahrens 		    DS_MODE_EXCLUSIVE | DS_MODE_READONLY | DS_MODE_INCONSISTENT,
7342199Sahrens 		    FTAG, &ds);
7352199Sahrens 		if (err)
7362199Sahrens 			return (err);
7372199Sahrens 		err = dsl_sync_task_do(ds->ds_dir->dd_pool,
7382199Sahrens 		    dsl_dataset_destroy_check, dsl_dataset_destroy_sync,
7392199Sahrens 		    ds, FTAG, 0);
7402199Sahrens 		if (err)
7412199Sahrens 			dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG);
7422199Sahrens 		return (err);
7432199Sahrens 	}
7442199Sahrens 
7452199Sahrens 	err = dmu_objset_open(name, DMU_OST_ANY,
7462199Sahrens 	    DS_MODE_EXCLUSIVE | DS_MODE_INCONSISTENT, &os);
7472199Sahrens 	if (err)
7482199Sahrens 		return (err);
7492199Sahrens 	ds = os->os->os_dsl_dataset;
7502199Sahrens 	dd = ds->ds_dir;
751789Sahrens 
7522199Sahrens 	/*
7532199Sahrens 	 * Check for errors and mark this ds as inconsistent, in
7542199Sahrens 	 * case we crash while freeing the objects.
7552199Sahrens 	 */
7562199Sahrens 	err = dsl_sync_task_do(dd->dd_pool, dsl_dataset_destroy_begin_check,
7572199Sahrens 	    dsl_dataset_destroy_begin_sync, ds, NULL, 0);
7582199Sahrens 	if (err) {
7592199Sahrens 		dmu_objset_close(os);
7602199Sahrens 		return (err);
7612199Sahrens 	}
7622199Sahrens 
7632199Sahrens 	/*
7642199Sahrens 	 * remove the objects in open context, so that we won't
7652199Sahrens 	 * have too much to do in syncing context.
7662199Sahrens 	 */
7673025Sahrens 	for (obj = 0; err == 0; err = dmu_object_next(os, &obj, FALSE,
7683025Sahrens 	    ds->ds_phys->ds_prev_snap_txg)) {
7692199Sahrens 		dmu_tx_t *tx = dmu_tx_create(os);
7702199Sahrens 		dmu_tx_hold_free(tx, obj, 0, DMU_OBJECT_END);
7712199Sahrens 		dmu_tx_hold_bonus(tx, obj);
7722199Sahrens 		err = dmu_tx_assign(tx, TXG_WAIT);
7732199Sahrens 		if (err) {
7742199Sahrens 			/*
7752199Sahrens 			 * Perhaps there is not enough disk
7762199Sahrens 			 * space.  Just deal with it from
7772199Sahrens 			 * dsl_dataset_destroy_sync().
7782199Sahrens 			 */
7792199Sahrens 			dmu_tx_abort(tx);
7802199Sahrens 			continue;
7812199Sahrens 		}
7822199Sahrens 		VERIFY(0 == dmu_object_free(os, obj, tx));
7832199Sahrens 		dmu_tx_commit(tx);
7842199Sahrens 	}
7852199Sahrens 	/* Make sure it's not dirty before we finish destroying it. */
7862199Sahrens 	txg_wait_synced(dd->dd_pool, 0);
7872199Sahrens 
7882199Sahrens 	dmu_objset_close(os);
7892199Sahrens 	if (err != ESRCH)
7902199Sahrens 		return (err);
7912199Sahrens 
7922199Sahrens 	err = dsl_dataset_open(name,
7932199Sahrens 	    DS_MODE_EXCLUSIVE | DS_MODE_READONLY | DS_MODE_INCONSISTENT,
7942199Sahrens 	    FTAG, &ds);
7951544Seschrock 	if (err)
7961544Seschrock 		return (err);
797789Sahrens 
7982199Sahrens 	err = dsl_dir_open(name, FTAG, &dd, NULL);
7992199Sahrens 	if (err) {
8002199Sahrens 		dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG);
8012199Sahrens 		return (err);
802789Sahrens 	}
803789Sahrens 
8042199Sahrens 	/*
8052199Sahrens 	 * Blow away the dsl_dir + head dataset.
8062199Sahrens 	 */
8072199Sahrens 	dstg = dsl_sync_task_group_create(ds->ds_dir->dd_pool);
8082199Sahrens 	dsl_sync_task_create(dstg, dsl_dataset_destroy_check,
8092199Sahrens 	    dsl_dataset_destroy_sync, ds, FTAG, 0);
8102199Sahrens 	dsl_sync_task_create(dstg, dsl_dir_destroy_check,
8112199Sahrens 	    dsl_dir_destroy_sync, dd, FTAG, 0);
8122199Sahrens 	err = dsl_sync_task_group_wait(dstg);
8132199Sahrens 	dsl_sync_task_group_destroy(dstg);
8142199Sahrens 	/* if it is successful, *destroy_sync will close the ds+dd */
8152199Sahrens 	if (err) {
8162199Sahrens 		dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG);
8172199Sahrens 		dsl_dir_close(dd, FTAG);
8182199Sahrens 	}
819789Sahrens 	return (err);
820789Sahrens }
821789Sahrens 
822789Sahrens int
8232199Sahrens dsl_dataset_rollback(dsl_dataset_t *ds)
824789Sahrens {
8253444Sek110237 	ASSERT3U(ds->ds_open_refcount, ==, DS_REF_MAX);
8262199Sahrens 	return (dsl_sync_task_do(ds->ds_dir->dd_pool,
8272199Sahrens 	    dsl_dataset_rollback_check, dsl_dataset_rollback_sync,
8282199Sahrens 	    ds, NULL, 0));
829789Sahrens }
830789Sahrens 
831789Sahrens void *
832789Sahrens dsl_dataset_set_user_ptr(dsl_dataset_t *ds,
833789Sahrens     void *p, dsl_dataset_evict_func_t func)
834789Sahrens {
835789Sahrens 	void *old;
836789Sahrens 
837789Sahrens 	mutex_enter(&ds->ds_lock);
838789Sahrens 	old = ds->ds_user_ptr;
839789Sahrens 	if (old == NULL) {
840789Sahrens 		ds->ds_user_ptr = p;
841789Sahrens 		ds->ds_user_evict_func = func;
842789Sahrens 	}
843789Sahrens 	mutex_exit(&ds->ds_lock);
844789Sahrens 	return (old);
845789Sahrens }
846789Sahrens 
847789Sahrens void *
848789Sahrens dsl_dataset_get_user_ptr(dsl_dataset_t *ds)
849789Sahrens {
850789Sahrens 	return (ds->ds_user_ptr);
851789Sahrens }
852789Sahrens 
853789Sahrens 
8543547Smaybee blkptr_t *
8553547Smaybee dsl_dataset_get_blkptr(dsl_dataset_t *ds)
856789Sahrens {
8573547Smaybee 	return (&ds->ds_phys->ds_bp);
858789Sahrens }
859789Sahrens 
860789Sahrens void
861789Sahrens dsl_dataset_set_blkptr(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx)
862789Sahrens {
863789Sahrens 	ASSERT(dmu_tx_is_syncing(tx));
864789Sahrens 	/* If it's the meta-objset, set dp_meta_rootbp */
865789Sahrens 	if (ds == NULL) {
866789Sahrens 		tx->tx_pool->dp_meta_rootbp = *bp;
867789Sahrens 	} else {
868789Sahrens 		dmu_buf_will_dirty(ds->ds_dbuf, tx);
869789Sahrens 		ds->ds_phys->ds_bp = *bp;
870789Sahrens 	}
871789Sahrens }
872789Sahrens 
873789Sahrens spa_t *
874789Sahrens dsl_dataset_get_spa(dsl_dataset_t *ds)
875789Sahrens {
876789Sahrens 	return (ds->ds_dir->dd_pool->dp_spa);
877789Sahrens }
878789Sahrens 
879789Sahrens void
880789Sahrens dsl_dataset_dirty(dsl_dataset_t *ds, dmu_tx_t *tx)
881789Sahrens {
882789Sahrens 	dsl_pool_t *dp;
883789Sahrens 
884789Sahrens 	if (ds == NULL) /* this is the meta-objset */
885789Sahrens 		return;
886789Sahrens 
887789Sahrens 	ASSERT(ds->ds_user_ptr != NULL);
8882885Sahrens 
8892885Sahrens 	if (ds->ds_phys->ds_next_snap_obj != 0)
8902885Sahrens 		panic("dirtying snapshot!");
891789Sahrens 
892789Sahrens 	dp = ds->ds_dir->dd_pool;
893789Sahrens 
894789Sahrens 	if (txg_list_add(&dp->dp_dirty_datasets, ds, tx->tx_txg) == 0) {
895789Sahrens 		/* up the hold count until we can be written out */
896789Sahrens 		dmu_buf_add_ref(ds->ds_dbuf, ds);
897789Sahrens 	}
898789Sahrens }
899789Sahrens 
900789Sahrens struct killarg {
901789Sahrens 	uint64_t *usedp;
902789Sahrens 	uint64_t *compressedp;
903789Sahrens 	uint64_t *uncompressedp;
904789Sahrens 	zio_t *zio;
905789Sahrens 	dmu_tx_t *tx;
906789Sahrens };
907789Sahrens 
908789Sahrens static int
909789Sahrens kill_blkptr(traverse_blk_cache_t *bc, spa_t *spa, void *arg)
910789Sahrens {
911789Sahrens 	struct killarg *ka = arg;
912789Sahrens 	blkptr_t *bp = &bc->bc_blkptr;
913789Sahrens 
914789Sahrens 	ASSERT3U(bc->bc_errno, ==, 0);
915789Sahrens 
916789Sahrens 	/*
917789Sahrens 	 * Since this callback is not called concurrently, no lock is
918789Sahrens 	 * needed on the accounting values.
919789Sahrens 	 */
9202082Seschrock 	*ka->usedp += bp_get_dasize(spa, bp);
921789Sahrens 	*ka->compressedp += BP_GET_PSIZE(bp);
922789Sahrens 	*ka->uncompressedp += BP_GET_UCSIZE(bp);
923789Sahrens 	/* XXX check for EIO? */
924789Sahrens 	(void) arc_free(ka->zio, spa, ka->tx->tx_txg, bp, NULL, NULL,
925789Sahrens 	    ARC_NOWAIT);
926789Sahrens 	return (0);
927789Sahrens }
928789Sahrens 
929789Sahrens /* ARGSUSED */
9302199Sahrens static int
9312199Sahrens dsl_dataset_rollback_check(void *arg1, void *arg2, dmu_tx_t *tx)
932789Sahrens {
9332199Sahrens 	dsl_dataset_t *ds = arg1;
934789Sahrens 
9352199Sahrens 	/*
9362199Sahrens 	 * There must be a previous snapshot.  I suppose we could roll
9372199Sahrens 	 * it back to being empty (and re-initialize the upper (ZPL)
9382199Sahrens 	 * layer).  But for now there's no way to do this via the user
9392199Sahrens 	 * interface.
9402199Sahrens 	 */
9412199Sahrens 	if (ds->ds_phys->ds_prev_snap_txg == 0)
942789Sahrens 		return (EINVAL);
943789Sahrens 
9442199Sahrens 	/*
9452199Sahrens 	 * This must not be a snapshot.
9462199Sahrens 	 */
9472199Sahrens 	if (ds->ds_phys->ds_next_snap_obj != 0)
9482199Sahrens 		return (EINVAL);
949789Sahrens 
950789Sahrens 	/*
951789Sahrens 	 * If we made changes this txg, traverse_dsl_dataset won't find
952789Sahrens 	 * them.  Try again.
953789Sahrens 	 */
9542199Sahrens 	if (ds->ds_phys->ds_bp.blk_birth >= tx->tx_txg)
955789Sahrens 		return (EAGAIN);
9562199Sahrens 
9572199Sahrens 	return (0);
9582199Sahrens }
959789Sahrens 
9602199Sahrens /* ARGSUSED */
9612199Sahrens static void
9624543Smarks dsl_dataset_rollback_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
9632199Sahrens {
9642199Sahrens 	dsl_dataset_t *ds = arg1;
9652199Sahrens 	objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
966789Sahrens 
967789Sahrens 	dmu_buf_will_dirty(ds->ds_dbuf, tx);
968789Sahrens 
969789Sahrens 	/* Zero out the deadlist. */
970789Sahrens 	bplist_close(&ds->ds_deadlist);
971789Sahrens 	bplist_destroy(mos, ds->ds_phys->ds_deadlist_obj, tx);
972789Sahrens 	ds->ds_phys->ds_deadlist_obj =
973789Sahrens 	    bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx);
9741544Seschrock 	VERIFY(0 == bplist_open(&ds->ds_deadlist, mos,
9751544Seschrock 	    ds->ds_phys->ds_deadlist_obj));
976789Sahrens 
977789Sahrens 	{
978789Sahrens 		/* Free blkptrs that we gave birth to */
979789Sahrens 		zio_t *zio;
980789Sahrens 		uint64_t used = 0, compressed = 0, uncompressed = 0;
981789Sahrens 		struct killarg ka;
982789Sahrens 
983789Sahrens 		zio = zio_root(tx->tx_pool->dp_spa, NULL, NULL,
984789Sahrens 		    ZIO_FLAG_MUSTSUCCEED);
985789Sahrens 		ka.usedp = &used;
986789Sahrens 		ka.compressedp = &compressed;
987789Sahrens 		ka.uncompressedp = &uncompressed;
988789Sahrens 		ka.zio = zio;
989789Sahrens 		ka.tx = tx;
990789Sahrens 		(void) traverse_dsl_dataset(ds, ds->ds_phys->ds_prev_snap_txg,
991789Sahrens 		    ADVANCE_POST, kill_blkptr, &ka);
992789Sahrens 		(void) zio_wait(zio);
993789Sahrens 
9942199Sahrens 		dsl_dir_diduse_space(ds->ds_dir,
995789Sahrens 		    -used, -compressed, -uncompressed, tx);
996789Sahrens 	}
997789Sahrens 
9982199Sahrens 	/* Change our contents to that of the prev snapshot */
999789Sahrens 	ASSERT3U(ds->ds_prev->ds_object, ==, ds->ds_phys->ds_prev_snap_obj);
1000789Sahrens 	ds->ds_phys->ds_bp = ds->ds_prev->ds_phys->ds_bp;
1001789Sahrens 	ds->ds_phys->ds_used_bytes = ds->ds_prev->ds_phys->ds_used_bytes;
1002789Sahrens 	ds->ds_phys->ds_compressed_bytes =
1003789Sahrens 	    ds->ds_prev->ds_phys->ds_compressed_bytes;
1004789Sahrens 	ds->ds_phys->ds_uncompressed_bytes =
1005789Sahrens 	    ds->ds_prev->ds_phys->ds_uncompressed_bytes;
10062082Seschrock 	ds->ds_phys->ds_flags = ds->ds_prev->ds_phys->ds_flags;
1007789Sahrens 	ds->ds_phys->ds_unique_bytes = 0;
1008789Sahrens 
10092532Sahrens 	if (ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) {
10102532Sahrens 		dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx);
10112532Sahrens 		ds->ds_prev->ds_phys->ds_unique_bytes = 0;
10122532Sahrens 	}
10134543Smarks 
10144543Smarks 	spa_history_internal_log(LOG_DS_ROLLBACK, ds->ds_dir->dd_pool->dp_spa,
10154543Smarks 	    tx, cr, "dataset = %llu", ds->ds_object);
1016789Sahrens }
1017789Sahrens 
10181731Sbonwick /* ARGSUSED */
10191731Sbonwick static int
10202199Sahrens dsl_dataset_destroy_begin_check(void *arg1, void *arg2, dmu_tx_t *tx)
10211731Sbonwick {
10222199Sahrens 	dsl_dataset_t *ds = arg1;
10231731Sbonwick 
10241731Sbonwick 	/*
10251731Sbonwick 	 * Can't delete a head dataset if there are snapshots of it.
10261731Sbonwick 	 * (Except if the only snapshots are from the branch we cloned
10271731Sbonwick 	 * from.)
10281731Sbonwick 	 */
10291731Sbonwick 	if (ds->ds_prev != NULL &&
10301731Sbonwick 	    ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object)
10311731Sbonwick 		return (EINVAL);
10321731Sbonwick 
10331731Sbonwick 	return (0);
10341731Sbonwick }
10351731Sbonwick 
10362199Sahrens /* ARGSUSED */
10372199Sahrens static void
10384543Smarks dsl_dataset_destroy_begin_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
1039789Sahrens {
10402199Sahrens 	dsl_dataset_t *ds = arg1;
10414543Smarks 	dsl_pool_t *dp = ds->ds_dir->dd_pool;
1042789Sahrens 
10432199Sahrens 	/* Mark it as inconsistent on-disk, in case we crash */
10442199Sahrens 	dmu_buf_will_dirty(ds->ds_dbuf, tx);
10452199Sahrens 	ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT;
10464543Smarks 
10474543Smarks 	spa_history_internal_log(LOG_DS_DESTROY_BEGIN, dp->dp_spa, tx,
10484543Smarks 	    cr, "dataset = %llu", ds->ds_object);
10492199Sahrens }
1050789Sahrens 
10512199Sahrens /* ARGSUSED */
10522199Sahrens static int
10532199Sahrens dsl_dataset_destroy_check(void *arg1, void *arg2, dmu_tx_t *tx)
10542199Sahrens {
10552199Sahrens 	dsl_dataset_t *ds = arg1;
1056789Sahrens 
1057789Sahrens 	/* Can't delete a branch point. */
10582199Sahrens 	if (ds->ds_phys->ds_num_children > 1)
10592199Sahrens 		return (EEXIST);
1060789Sahrens 
1061789Sahrens 	/*
1062789Sahrens 	 * Can't delete a head dataset if there are snapshots of it.
1063789Sahrens 	 * (Except if the only snapshots are from the branch we cloned
1064789Sahrens 	 * from.)
1065789Sahrens 	 */
1066789Sahrens 	if (ds->ds_prev != NULL &&
10672199Sahrens 	    ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object)
1068789Sahrens 		return (EINVAL);
1069789Sahrens 
1070789Sahrens 	/*
1071789Sahrens 	 * If we made changes this txg, traverse_dsl_dataset won't find
1072789Sahrens 	 * them.  Try again.
1073789Sahrens 	 */
10742199Sahrens 	if (ds->ds_phys->ds_bp.blk_birth >= tx->tx_txg)
1075789Sahrens 		return (EAGAIN);
10762199Sahrens 
10772199Sahrens 	/* XXX we should do some i/o error checking... */
10782199Sahrens 	return (0);
10792199Sahrens }
10802199Sahrens 
10812199Sahrens static void
10824543Smarks dsl_dataset_destroy_sync(void *arg1, void *tag, cred_t *cr, dmu_tx_t *tx)
10832199Sahrens {
10842199Sahrens 	dsl_dataset_t *ds = arg1;
10852199Sahrens 	uint64_t used = 0, compressed = 0, uncompressed = 0;
10862199Sahrens 	zio_t *zio;
10872199Sahrens 	int err;
10882199Sahrens 	int after_branch_point = FALSE;
10892199Sahrens 	dsl_pool_t *dp = ds->ds_dir->dd_pool;
10902199Sahrens 	objset_t *mos = dp->dp_meta_objset;
10912199Sahrens 	dsl_dataset_t *ds_prev = NULL;
10922199Sahrens 	uint64_t obj;
10932199Sahrens 
10943444Sek110237 	ASSERT3U(ds->ds_open_refcount, ==, DS_REF_MAX);
10952199Sahrens 	ASSERT3U(ds->ds_phys->ds_num_children, <=, 1);
10962199Sahrens 	ASSERT(ds->ds_prev == NULL ||
10972199Sahrens 	    ds->ds_prev->ds_phys->ds_next_snap_obj != ds->ds_object);
10982199Sahrens 	ASSERT3U(ds->ds_phys->ds_bp.blk_birth, <=, tx->tx_txg);
10992199Sahrens 
11002199Sahrens 	ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock));
11012199Sahrens 
11022199Sahrens 	obj = ds->ds_object;
1103789Sahrens 
1104789Sahrens 	if (ds->ds_phys->ds_prev_snap_obj != 0) {
1105789Sahrens 		if (ds->ds_prev) {
1106789Sahrens 			ds_prev = ds->ds_prev;
1107789Sahrens 		} else {
11082199Sahrens 			VERIFY(0 == dsl_dataset_open_obj(dp,
1109789Sahrens 			    ds->ds_phys->ds_prev_snap_obj, NULL,
11102199Sahrens 			    DS_MODE_NONE, FTAG, &ds_prev));
1111789Sahrens 		}
1112789Sahrens 		after_branch_point =
1113789Sahrens 		    (ds_prev->ds_phys->ds_next_snap_obj != obj);
1114789Sahrens 
1115789Sahrens 		dmu_buf_will_dirty(ds_prev->ds_dbuf, tx);
1116789Sahrens 		if (after_branch_point &&
1117789Sahrens 		    ds->ds_phys->ds_next_snap_obj == 0) {
1118789Sahrens 			/* This clone is toast. */
1119789Sahrens 			ASSERT(ds_prev->ds_phys->ds_num_children > 1);
1120789Sahrens 			ds_prev->ds_phys->ds_num_children--;
1121789Sahrens 		} else if (!after_branch_point) {
1122789Sahrens 			ds_prev->ds_phys->ds_next_snap_obj =
1123789Sahrens 			    ds->ds_phys->ds_next_snap_obj;
1124789Sahrens 		}
1125789Sahrens 	}
1126789Sahrens 
1127789Sahrens 	zio = zio_root(dp->dp_spa, NULL, NULL, ZIO_FLAG_MUSTSUCCEED);
1128789Sahrens 
1129789Sahrens 	if (ds->ds_phys->ds_next_snap_obj != 0) {
11302199Sahrens 		blkptr_t bp;
1131789Sahrens 		dsl_dataset_t *ds_next;
1132789Sahrens 		uint64_t itor = 0;
1133789Sahrens 
1134789Sahrens 		spa_scrub_restart(dp->dp_spa, tx->tx_txg);
1135789Sahrens 
11362199Sahrens 		VERIFY(0 == dsl_dataset_open_obj(dp,
11371544Seschrock 		    ds->ds_phys->ds_next_snap_obj, NULL,
11381544Seschrock 		    DS_MODE_NONE, FTAG, &ds_next));
1139789Sahrens 		ASSERT3U(ds_next->ds_phys->ds_prev_snap_obj, ==, obj);
1140789Sahrens 
1141789Sahrens 		dmu_buf_will_dirty(ds_next->ds_dbuf, tx);
1142789Sahrens 		ds_next->ds_phys->ds_prev_snap_obj =
1143789Sahrens 		    ds->ds_phys->ds_prev_snap_obj;
1144789Sahrens 		ds_next->ds_phys->ds_prev_snap_txg =
1145789Sahrens 		    ds->ds_phys->ds_prev_snap_txg;
1146789Sahrens 		ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==,
1147789Sahrens 		    ds_prev ? ds_prev->ds_phys->ds_creation_txg : 0);
1148789Sahrens 
1149789Sahrens 		/*
1150789Sahrens 		 * Transfer to our deadlist (which will become next's
1151789Sahrens 		 * new deadlist) any entries from next's current
1152789Sahrens 		 * deadlist which were born before prev, and free the
1153789Sahrens 		 * other entries.
1154789Sahrens 		 *
1155789Sahrens 		 * XXX we're doing this long task with the config lock held
1156789Sahrens 		 */
1157789Sahrens 		while (bplist_iterate(&ds_next->ds_deadlist, &itor,
1158789Sahrens 		    &bp) == 0) {
1159789Sahrens 			if (bp.blk_birth <= ds->ds_phys->ds_prev_snap_txg) {
11601544Seschrock 				VERIFY(0 == bplist_enqueue(&ds->ds_deadlist,
11611544Seschrock 				    &bp, tx));
1162789Sahrens 				if (ds_prev && !after_branch_point &&
1163789Sahrens 				    bp.blk_birth >
1164789Sahrens 				    ds_prev->ds_phys->ds_prev_snap_txg) {
1165789Sahrens 					ds_prev->ds_phys->ds_unique_bytes +=
11662082Seschrock 					    bp_get_dasize(dp->dp_spa, &bp);
1167789Sahrens 				}
1168789Sahrens 			} else {
11692082Seschrock 				used += bp_get_dasize(dp->dp_spa, &bp);
1170789Sahrens 				compressed += BP_GET_PSIZE(&bp);
1171789Sahrens 				uncompressed += BP_GET_UCSIZE(&bp);
1172789Sahrens 				/* XXX check return value? */
1173789Sahrens 				(void) arc_free(zio, dp->dp_spa, tx->tx_txg,
1174789Sahrens 				    &bp, NULL, NULL, ARC_NOWAIT);
1175789Sahrens 			}
1176789Sahrens 		}
1177789Sahrens 
1178789Sahrens 		/* free next's deadlist */
1179789Sahrens 		bplist_close(&ds_next->ds_deadlist);
1180789Sahrens 		bplist_destroy(mos, ds_next->ds_phys->ds_deadlist_obj, tx);
1181789Sahrens 
1182789Sahrens 		/* set next's deadlist to our deadlist */
1183789Sahrens 		ds_next->ds_phys->ds_deadlist_obj =
1184789Sahrens 		    ds->ds_phys->ds_deadlist_obj;
11851544Seschrock 		VERIFY(0 == bplist_open(&ds_next->ds_deadlist, mos,
11861544Seschrock 		    ds_next->ds_phys->ds_deadlist_obj));
1187789Sahrens 		ds->ds_phys->ds_deadlist_obj = 0;
1188789Sahrens 
1189789Sahrens 		if (ds_next->ds_phys->ds_next_snap_obj != 0) {
1190789Sahrens 			/*
1191789Sahrens 			 * Update next's unique to include blocks which
1192789Sahrens 			 * were previously shared by only this snapshot
1193789Sahrens 			 * and it.  Those blocks will be born after the
1194789Sahrens 			 * prev snap and before this snap, and will have
1195789Sahrens 			 * died after the next snap and before the one
1196789Sahrens 			 * after that (ie. be on the snap after next's
1197789Sahrens 			 * deadlist).
1198789Sahrens 			 *
1199789Sahrens 			 * XXX we're doing this long task with the
1200789Sahrens 			 * config lock held
1201789Sahrens 			 */
1202789Sahrens 			dsl_dataset_t *ds_after_next;
1203789Sahrens 
12042199Sahrens 			VERIFY(0 == dsl_dataset_open_obj(dp,
1205789Sahrens 			    ds_next->ds_phys->ds_next_snap_obj, NULL,
12061544Seschrock 			    DS_MODE_NONE, FTAG, &ds_after_next));
1207789Sahrens 			itor = 0;
1208789Sahrens 			while (bplist_iterate(&ds_after_next->ds_deadlist,
1209789Sahrens 			    &itor, &bp) == 0) {
1210789Sahrens 				if (bp.blk_birth >
1211789Sahrens 				    ds->ds_phys->ds_prev_snap_txg &&
1212789Sahrens 				    bp.blk_birth <=
1213789Sahrens 				    ds->ds_phys->ds_creation_txg) {
1214789Sahrens 					ds_next->ds_phys->ds_unique_bytes +=
12152082Seschrock 					    bp_get_dasize(dp->dp_spa, &bp);
1216789Sahrens 				}
1217789Sahrens 			}
1218789Sahrens 
1219789Sahrens 			dsl_dataset_close(ds_after_next, DS_MODE_NONE, FTAG);
1220789Sahrens 			ASSERT3P(ds_next->ds_prev, ==, NULL);
1221789Sahrens 		} else {
1222789Sahrens 			/*
1223789Sahrens 			 * It would be nice to update the head dataset's
1224789Sahrens 			 * unique.  To do so we would have to traverse
1225789Sahrens 			 * it for blocks born after ds_prev, which is
1226789Sahrens 			 * pretty expensive just to maintain something
1227789Sahrens 			 * for debugging purposes.
1228789Sahrens 			 */
1229789Sahrens 			ASSERT3P(ds_next->ds_prev, ==, ds);
1230789Sahrens 			dsl_dataset_close(ds_next->ds_prev, DS_MODE_NONE,
1231789Sahrens 			    ds_next);
1232789Sahrens 			if (ds_prev) {
12332199Sahrens 				VERIFY(0 == dsl_dataset_open_obj(dp,
12341544Seschrock 				    ds->ds_phys->ds_prev_snap_obj, NULL,
12351544Seschrock 				    DS_MODE_NONE, ds_next, &ds_next->ds_prev));
1236789Sahrens 			} else {
1237789Sahrens 				ds_next->ds_prev = NULL;
1238789Sahrens 			}
1239789Sahrens 		}
1240789Sahrens 		dsl_dataset_close(ds_next, DS_MODE_NONE, FTAG);
1241789Sahrens 
1242789Sahrens 		/*
1243789Sahrens 		 * NB: unique_bytes is not accurate for head objsets
1244789Sahrens 		 * because we don't update it when we delete the most
1245789Sahrens 		 * recent snapshot -- see above comment.
1246789Sahrens 		 */
1247789Sahrens 		ASSERT3U(used, ==, ds->ds_phys->ds_unique_bytes);
1248789Sahrens 	} else {
1249789Sahrens 		/*
1250789Sahrens 		 * There's no next snapshot, so this is a head dataset.
1251789Sahrens 		 * Destroy the deadlist.  Unless it's a clone, the
1252789Sahrens 		 * deadlist should be empty.  (If it's a clone, it's
1253789Sahrens 		 * safe to ignore the deadlist contents.)
1254789Sahrens 		 */
1255789Sahrens 		struct killarg ka;
1256789Sahrens 
1257789Sahrens 		ASSERT(after_branch_point || bplist_empty(&ds->ds_deadlist));
1258789Sahrens 		bplist_close(&ds->ds_deadlist);
1259789Sahrens 		bplist_destroy(mos, ds->ds_phys->ds_deadlist_obj, tx);
1260789Sahrens 		ds->ds_phys->ds_deadlist_obj = 0;
1261789Sahrens 
1262789Sahrens 		/*
1263789Sahrens 		 * Free everything that we point to (that's born after
1264789Sahrens 		 * the previous snapshot, if we are a clone)
1265789Sahrens 		 *
1266789Sahrens 		 * XXX we're doing this long task with the config lock held
1267789Sahrens 		 */
1268789Sahrens 		ka.usedp = &used;
1269789Sahrens 		ka.compressedp = &compressed;
1270789Sahrens 		ka.uncompressedp = &uncompressed;
1271789Sahrens 		ka.zio = zio;
1272789Sahrens 		ka.tx = tx;
1273789Sahrens 		err = traverse_dsl_dataset(ds, ds->ds_phys->ds_prev_snap_txg,
1274789Sahrens 		    ADVANCE_POST, kill_blkptr, &ka);
1275789Sahrens 		ASSERT3U(err, ==, 0);
1276789Sahrens 	}
1277789Sahrens 
1278789Sahrens 	err = zio_wait(zio);
1279789Sahrens 	ASSERT3U(err, ==, 0);
1280789Sahrens 
12812199Sahrens 	dsl_dir_diduse_space(ds->ds_dir, -used, -compressed, -uncompressed, tx);
1282789Sahrens 
1283789Sahrens 	if (ds->ds_phys->ds_snapnames_zapobj) {
1284789Sahrens 		err = zap_destroy(mos, ds->ds_phys->ds_snapnames_zapobj, tx);
1285789Sahrens 		ASSERT(err == 0);
1286789Sahrens 	}
1287789Sahrens 
12882199Sahrens 	if (ds->ds_dir->dd_phys->dd_head_dataset_obj == ds->ds_object) {
1289789Sahrens 		/* Erase the link in the dataset */
12902199Sahrens 		dmu_buf_will_dirty(ds->ds_dir->dd_dbuf, tx);
12912199Sahrens 		ds->ds_dir->dd_phys->dd_head_dataset_obj = 0;
1292789Sahrens 		/*
1293789Sahrens 		 * dsl_dir_sync_destroy() called us, they'll destroy
1294789Sahrens 		 * the dataset.
1295789Sahrens 		 */
1296789Sahrens 	} else {
1297789Sahrens 		/* remove from snapshot namespace */
1298789Sahrens 		dsl_dataset_t *ds_head;
12992199Sahrens 		VERIFY(0 == dsl_dataset_open_obj(dp,
13002199Sahrens 		    ds->ds_dir->dd_phys->dd_head_dataset_obj, NULL,
13011544Seschrock 		    DS_MODE_NONE, FTAG, &ds_head));
13022207Sahrens 		VERIFY(0 == dsl_dataset_get_snapname(ds));
1303789Sahrens #ifdef ZFS_DEBUG
1304789Sahrens 		{
1305789Sahrens 			uint64_t val;
1306789Sahrens 			err = zap_lookup(mos,
1307789Sahrens 			    ds_head->ds_phys->ds_snapnames_zapobj,
13082199Sahrens 			    ds->ds_snapname, 8, 1, &val);
1309789Sahrens 			ASSERT3U(err, ==, 0);
1310789Sahrens 			ASSERT3U(val, ==, obj);
1311789Sahrens 		}
1312789Sahrens #endif
1313789Sahrens 		err = zap_remove(mos, ds_head->ds_phys->ds_snapnames_zapobj,
13142199Sahrens 		    ds->ds_snapname, tx);
1315789Sahrens 		ASSERT(err == 0);
1316789Sahrens 		dsl_dataset_close(ds_head, DS_MODE_NONE, FTAG);
1317789Sahrens 	}
1318789Sahrens 
1319789Sahrens 	if (ds_prev && ds->ds_prev != ds_prev)
1320789Sahrens 		dsl_dataset_close(ds_prev, DS_MODE_NONE, FTAG);
1321789Sahrens 
13223912Slling 	spa_clear_bootfs(dp->dp_spa, ds->ds_object, tx);
13234543Smarks 	spa_history_internal_log(LOG_DS_DESTROY, dp->dp_spa, tx,
13244543Smarks 	    cr, "dataset = %llu", ds->ds_object);
13254543Smarks 
13262199Sahrens 	dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, tag);
13272199Sahrens 	VERIFY(0 == dmu_object_free(mos, obj, tx));
13283912Slling 
13292199Sahrens }
13302199Sahrens 
13312199Sahrens /* ARGSUSED */
13322199Sahrens int
13332199Sahrens dsl_dataset_snapshot_check(void *arg1, void *arg2, dmu_tx_t *tx)
13342199Sahrens {
13352199Sahrens 	objset_t *os = arg1;
13362199Sahrens 	dsl_dataset_t *ds = os->os->os_dsl_dataset;
13372199Sahrens 	const char *snapname = arg2;
13382199Sahrens 	objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
13392199Sahrens 	int err;
13402199Sahrens 	uint64_t value;
1341789Sahrens 
1342789Sahrens 	/*
13432199Sahrens 	 * We don't allow multiple snapshots of the same txg.  If there
13442199Sahrens 	 * is already one, try again.
13452199Sahrens 	 */
13462199Sahrens 	if (ds->ds_phys->ds_prev_snap_txg >= tx->tx_txg)
13472199Sahrens 		return (EAGAIN);
13482199Sahrens 
13492199Sahrens 	/*
13502199Sahrens 	 * Check for conflicting name snapshot name.
1351789Sahrens 	 */
13522199Sahrens 	err = zap_lookup(mos, ds->ds_phys->ds_snapnames_zapobj,
13532199Sahrens 	    snapname, 8, 1, &value);
13542199Sahrens 	if (err == 0)
13552199Sahrens 		return (EEXIST);
13562199Sahrens 	if (err != ENOENT)
13572199Sahrens 		return (err);
1358789Sahrens 
13593978Smmusante 	/*
13603978Smmusante 	 * Check that the dataset's name is not too long.  Name consists
13613978Smmusante 	 * of the dataset's length + 1 for the @-sign + snapshot name's length
13623978Smmusante 	 */
13633978Smmusante 	if (dsl_dataset_namelen(ds) + 1 + strlen(snapname) >= MAXNAMELEN)
13643978Smmusante 		return (ENAMETOOLONG);
13653978Smmusante 
13662199Sahrens 	ds->ds_trysnap_txg = tx->tx_txg;
1367789Sahrens 	return (0);
1368789Sahrens }
1369789Sahrens 
13702199Sahrens void
13714543Smarks dsl_dataset_snapshot_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
1372789Sahrens {
13732199Sahrens 	objset_t *os = arg1;
13742199Sahrens 	dsl_dataset_t *ds = os->os->os_dsl_dataset;
13752199Sahrens 	const char *snapname = arg2;
13762199Sahrens 	dsl_pool_t *dp = ds->ds_dir->dd_pool;
1377789Sahrens 	dmu_buf_t *dbuf;
1378789Sahrens 	dsl_dataset_phys_t *dsphys;
13792199Sahrens 	uint64_t dsobj;
1380789Sahrens 	objset_t *mos = dp->dp_meta_objset;
1381789Sahrens 	int err;
1382789Sahrens 
1383789Sahrens 	spa_scrub_restart(dp->dp_spa, tx->tx_txg);
13842199Sahrens 	ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock));
1385789Sahrens 
1386928Stabriz 	dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0,
1387928Stabriz 	    DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx);
13881544Seschrock 	VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf));
1389789Sahrens 	dmu_buf_will_dirty(dbuf, tx);
1390789Sahrens 	dsphys = dbuf->db_data;
13912199Sahrens 	dsphys->ds_dir_obj = ds->ds_dir->dd_object;
1392789Sahrens 	dsphys->ds_fsid_guid = unique_create();
1393789Sahrens 	unique_remove(dsphys->ds_fsid_guid); /* it isn't open yet */
1394789Sahrens 	(void) random_get_pseudo_bytes((void*)&dsphys->ds_guid,
1395789Sahrens 	    sizeof (dsphys->ds_guid));
1396789Sahrens 	dsphys->ds_prev_snap_obj = ds->ds_phys->ds_prev_snap_obj;
1397789Sahrens 	dsphys->ds_prev_snap_txg = ds->ds_phys->ds_prev_snap_txg;
1398789Sahrens 	dsphys->ds_next_snap_obj = ds->ds_object;
1399789Sahrens 	dsphys->ds_num_children = 1;
1400789Sahrens 	dsphys->ds_creation_time = gethrestime_sec();
1401789Sahrens 	dsphys->ds_creation_txg = tx->tx_txg;
1402789Sahrens 	dsphys->ds_deadlist_obj = ds->ds_phys->ds_deadlist_obj;
1403789Sahrens 	dsphys->ds_used_bytes = ds->ds_phys->ds_used_bytes;
1404789Sahrens 	dsphys->ds_compressed_bytes = ds->ds_phys->ds_compressed_bytes;
1405789Sahrens 	dsphys->ds_uncompressed_bytes = ds->ds_phys->ds_uncompressed_bytes;
14062082Seschrock 	dsphys->ds_flags = ds->ds_phys->ds_flags;
1407789Sahrens 	dsphys->ds_bp = ds->ds_phys->ds_bp;
14081544Seschrock 	dmu_buf_rele(dbuf, FTAG);
1409789Sahrens 
14102199Sahrens 	ASSERT3U(ds->ds_prev != 0, ==, ds->ds_phys->ds_prev_snap_obj != 0);
14112199Sahrens 	if (ds->ds_prev) {
14122199Sahrens 		ASSERT(ds->ds_prev->ds_phys->ds_next_snap_obj ==
1413789Sahrens 		    ds->ds_object ||
14142199Sahrens 		    ds->ds_prev->ds_phys->ds_num_children > 1);
14152199Sahrens 		if (ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) {
14162199Sahrens 			dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx);
1417789Sahrens 			ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==,
14182199Sahrens 			    ds->ds_prev->ds_phys->ds_creation_txg);
14192199Sahrens 			ds->ds_prev->ds_phys->ds_next_snap_obj = dsobj;
1420789Sahrens 		}
1421789Sahrens 	}
1422789Sahrens 
1423789Sahrens 	bplist_close(&ds->ds_deadlist);
1424789Sahrens 	dmu_buf_will_dirty(ds->ds_dbuf, tx);
1425789Sahrens 	ASSERT3U(ds->ds_phys->ds_prev_snap_txg, <, dsphys->ds_creation_txg);
1426789Sahrens 	ds->ds_phys->ds_prev_snap_obj = dsobj;
1427789Sahrens 	ds->ds_phys->ds_prev_snap_txg = dsphys->ds_creation_txg;
1428789Sahrens 	ds->ds_phys->ds_unique_bytes = 0;
1429789Sahrens 	ds->ds_phys->ds_deadlist_obj =
1430789Sahrens 	    bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx);
14311544Seschrock 	VERIFY(0 == bplist_open(&ds->ds_deadlist, mos,
14321544Seschrock 	    ds->ds_phys->ds_deadlist_obj));
1433789Sahrens 
1434789Sahrens 	dprintf("snap '%s' -> obj %llu\n", snapname, dsobj);
1435789Sahrens 	err = zap_add(mos, ds->ds_phys->ds_snapnames_zapobj,
1436789Sahrens 	    snapname, 8, 1, &dsobj, tx);
1437789Sahrens 	ASSERT(err == 0);
1438789Sahrens 
1439789Sahrens 	if (ds->ds_prev)
1440789Sahrens 		dsl_dataset_close(ds->ds_prev, DS_MODE_NONE, ds);
14411544Seschrock 	VERIFY(0 == dsl_dataset_open_obj(dp,
14421544Seschrock 	    ds->ds_phys->ds_prev_snap_obj, snapname,
14431544Seschrock 	    DS_MODE_NONE, ds, &ds->ds_prev));
14444543Smarks 
14454543Smarks 	spa_history_internal_log(LOG_DS_SNAPSHOT, dp->dp_spa, tx, cr,
1446*4603Sahrens 	    "dataset = %llu", dsobj);
1447789Sahrens }
1448789Sahrens 
1449789Sahrens void
14503547Smaybee dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx)
1451789Sahrens {
1452789Sahrens 	ASSERT(dmu_tx_is_syncing(tx));
1453789Sahrens 	ASSERT(ds->ds_user_ptr != NULL);
1454789Sahrens 	ASSERT(ds->ds_phys->ds_next_snap_obj == 0);
1455789Sahrens 
1456789Sahrens 	dsl_dir_dirty(ds->ds_dir, tx);
14573547Smaybee 	dmu_objset_sync(ds->ds_user_ptr, zio, tx);
14583547Smaybee 	/* Unneeded? bplist_close(&ds->ds_deadlist); */
1459789Sahrens }
1460789Sahrens 
1461789Sahrens void
14622885Sahrens dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv)
1463789Sahrens {
14642885Sahrens 	dsl_dir_stats(ds->ds_dir, nv);
1465789Sahrens 
14662885Sahrens 	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATION,
14672885Sahrens 	    ds->ds_phys->ds_creation_time);
14682885Sahrens 	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATETXG,
14692885Sahrens 	    ds->ds_phys->ds_creation_txg);
14702885Sahrens 	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFERENCED,
14712885Sahrens 	    ds->ds_phys->ds_used_bytes);
1472789Sahrens 
1473789Sahrens 	if (ds->ds_phys->ds_next_snap_obj) {
1474789Sahrens 		/*
1475789Sahrens 		 * This is a snapshot; override the dd's space used with
14762885Sahrens 		 * our unique space and compression ratio.
1477789Sahrens 		 */
14782885Sahrens 		dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED,
14792885Sahrens 		    ds->ds_phys->ds_unique_bytes);
14802885Sahrens 		dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO,
14812885Sahrens 		    ds->ds_phys->ds_compressed_bytes == 0 ? 100 :
14822885Sahrens 		    (ds->ds_phys->ds_uncompressed_bytes * 100 /
14832885Sahrens 		    ds->ds_phys->ds_compressed_bytes));
1484789Sahrens 	}
1485789Sahrens }
1486789Sahrens 
14872885Sahrens void
14882885Sahrens dsl_dataset_fast_stat(dsl_dataset_t *ds, dmu_objset_stats_t *stat)
1489789Sahrens {
14902885Sahrens 	stat->dds_creation_txg = ds->ds_phys->ds_creation_txg;
14912885Sahrens 	stat->dds_inconsistent = ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT;
14922885Sahrens 	if (ds->ds_phys->ds_next_snap_obj) {
14932885Sahrens 		stat->dds_is_snapshot = B_TRUE;
14942885Sahrens 		stat->dds_num_clones = ds->ds_phys->ds_num_children - 1;
14952885Sahrens 	}
14962885Sahrens 
14972885Sahrens 	/* clone origin is really a dsl_dir thing... */
14982885Sahrens 	if (ds->ds_dir->dd_phys->dd_clone_parent_obj) {
14992885Sahrens 		dsl_dataset_t *ods;
15002885Sahrens 
15012885Sahrens 		rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER);
15022885Sahrens 		VERIFY(0 == dsl_dataset_open_obj(ds->ds_dir->dd_pool,
15032885Sahrens 		    ds->ds_dir->dd_phys->dd_clone_parent_obj,
15042885Sahrens 		    NULL, DS_MODE_NONE, FTAG, &ods));
15052885Sahrens 		dsl_dataset_name(ods, stat->dds_clone_of);
15062885Sahrens 		dsl_dataset_close(ods, DS_MODE_NONE, FTAG);
15072885Sahrens 		rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock);
15082885Sahrens 	}
15092885Sahrens }
15102885Sahrens 
15112885Sahrens uint64_t
15122885Sahrens dsl_dataset_fsid_guid(dsl_dataset_t *ds)
15132885Sahrens {
15142885Sahrens 	return (ds->ds_phys->ds_fsid_guid);
15152885Sahrens }
15162885Sahrens 
15172885Sahrens void
15182885Sahrens dsl_dataset_space(dsl_dataset_t *ds,
15192885Sahrens     uint64_t *refdbytesp, uint64_t *availbytesp,
15202885Sahrens     uint64_t *usedobjsp, uint64_t *availobjsp)
15212885Sahrens {
15222885Sahrens 	*refdbytesp = ds->ds_phys->ds_used_bytes;
15232885Sahrens 	*availbytesp = dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE);
15242885Sahrens 	*usedobjsp = ds->ds_phys->ds_bp.blk_fill;
15252885Sahrens 	*availobjsp = DN_MAX_OBJECT - *usedobjsp;
1526789Sahrens }
1527789Sahrens 
15282199Sahrens /* ARGSUSED */
1529789Sahrens static int
15302199Sahrens dsl_dataset_snapshot_rename_check(void *arg1, void *arg2, dmu_tx_t *tx)
1531789Sahrens {
15322199Sahrens 	dsl_dataset_t *ds = arg1;
15332199Sahrens 	char *newsnapname = arg2;
15342199Sahrens 	dsl_dir_t *dd = ds->ds_dir;
1535789Sahrens 	objset_t *mos = dd->dd_pool->dp_meta_objset;
15362199Sahrens 	dsl_dataset_t *hds;
15372199Sahrens 	uint64_t val;
1538789Sahrens 	int err;
1539789Sahrens 
15402199Sahrens 	err = dsl_dataset_open_obj(dd->dd_pool,
15412199Sahrens 	    dd->dd_phys->dd_head_dataset_obj, NULL, DS_MODE_NONE, FTAG, &hds);
1542789Sahrens 	if (err)
1543789Sahrens 		return (err);
1544789Sahrens 
15452199Sahrens 	/* new name better not be in use */
15462199Sahrens 	err = zap_lookup(mos, hds->ds_phys->ds_snapnames_zapobj,
15472199Sahrens 	    newsnapname, 8, 1, &val);
15482199Sahrens 	dsl_dataset_close(hds, DS_MODE_NONE, FTAG);
1549789Sahrens 
15502199Sahrens 	if (err == 0)
15512199Sahrens 		err = EEXIST;
15522199Sahrens 	else if (err == ENOENT)
15532199Sahrens 		err = 0;
15544007Smmusante 
15554007Smmusante 	/* dataset name + 1 for the "@" + the new snapshot name must fit */
15564007Smmusante 	if (dsl_dir_namelen(ds->ds_dir) + 1 + strlen(newsnapname) >= MAXNAMELEN)
15574007Smmusante 		err = ENAMETOOLONG;
15584007Smmusante 
15592199Sahrens 	return (err);
15602199Sahrens }
1561789Sahrens 
15622199Sahrens static void
15634543Smarks dsl_dataset_snapshot_rename_sync(void *arg1, void *arg2,
15644543Smarks     cred_t *cr, dmu_tx_t *tx)
15652199Sahrens {
15662199Sahrens 	dsl_dataset_t *ds = arg1;
15674543Smarks 	const char *newsnapname = arg2;
15682199Sahrens 	dsl_dir_t *dd = ds->ds_dir;
15692199Sahrens 	objset_t *mos = dd->dd_pool->dp_meta_objset;
15702199Sahrens 	dsl_dataset_t *hds;
15712199Sahrens 	int err;
1572789Sahrens 
15732199Sahrens 	ASSERT(ds->ds_phys->ds_next_snap_obj != 0);
1574789Sahrens 
15752199Sahrens 	VERIFY(0 == dsl_dataset_open_obj(dd->dd_pool,
15762199Sahrens 	    dd->dd_phys->dd_head_dataset_obj, NULL, DS_MODE_NONE, FTAG, &hds));
1577789Sahrens 
15782199Sahrens 	VERIFY(0 == dsl_dataset_get_snapname(ds));
15792199Sahrens 	err = zap_remove(mos, hds->ds_phys->ds_snapnames_zapobj,
15802199Sahrens 	    ds->ds_snapname, tx);
1581789Sahrens 	ASSERT3U(err, ==, 0);
15822199Sahrens 	mutex_enter(&ds->ds_lock);
15832199Sahrens 	(void) strcpy(ds->ds_snapname, newsnapname);
15842199Sahrens 	mutex_exit(&ds->ds_lock);
15852199Sahrens 	err = zap_add(mos, hds->ds_phys->ds_snapnames_zapobj,
15862199Sahrens 	    ds->ds_snapname, 8, 1, &ds->ds_object, tx);
1587789Sahrens 	ASSERT3U(err, ==, 0);
1588789Sahrens 
15894543Smarks 	spa_history_internal_log(LOG_DS_RENAME, dd->dd_pool->dp_spa, tx,
15904543Smarks 	    cr, "dataset = %llu", ds->ds_object);
15912199Sahrens 	dsl_dataset_close(hds, DS_MODE_NONE, FTAG);
1592789Sahrens }
1593789Sahrens 
15944007Smmusante struct renamearg {
15954007Smmusante 	dsl_sync_task_group_t *dstg;
15964007Smmusante 	char failed[MAXPATHLEN];
15974007Smmusante 	char *oldsnap;
15984007Smmusante 	char *newsnap;
15994007Smmusante };
16004007Smmusante 
16014007Smmusante static int
16024007Smmusante dsl_snapshot_rename_one(char *name, void *arg)
16034007Smmusante {
16044007Smmusante 	struct renamearg *ra = arg;
16054007Smmusante 	dsl_dataset_t *ds = NULL;
16064007Smmusante 	char *cp;
16074007Smmusante 	int err;
16084007Smmusante 
16094007Smmusante 	cp = name + strlen(name);
16104007Smmusante 	*cp = '@';
16114007Smmusante 	(void) strcpy(cp + 1, ra->oldsnap);
16124543Smarks 
16134543Smarks 	/*
16144543Smarks 	 * For recursive snapshot renames the parent won't be changing
16154543Smarks 	 * so we just pass name for both the to/from argument.
16164543Smarks 	 */
16174543Smarks 	if (err = zfs_secpolicy_rename_perms(name, name, CRED())) {
16184543Smarks 		(void) strcpy(ra->failed, name);
16194543Smarks 		return (err);
16204543Smarks 	}
16214543Smarks 
16224007Smmusante 	err = dsl_dataset_open(name, DS_MODE_READONLY | DS_MODE_STANDARD,
16234007Smmusante 	    ra->dstg, &ds);
16244007Smmusante 	if (err == ENOENT) {
16254007Smmusante 		*cp = '\0';
16264007Smmusante 		return (0);
16274007Smmusante 	}
16284007Smmusante 	if (err) {
16294007Smmusante 		(void) strcpy(ra->failed, name);
16304007Smmusante 		*cp = '\0';
16314007Smmusante 		dsl_dataset_close(ds, DS_MODE_STANDARD, ra->dstg);
16324007Smmusante 		return (err);
16334007Smmusante 	}
16344007Smmusante 
16354007Smmusante #ifdef _KERNEL
16364007Smmusante 	/* for all filesystems undergoing rename, we'll need to unmount it */
16374007Smmusante 	(void) zfs_unmount_snap(name, NULL);
16384007Smmusante #endif
16394007Smmusante 
16404007Smmusante 	*cp = '\0';
16414007Smmusante 
16424007Smmusante 	dsl_sync_task_create(ra->dstg, dsl_dataset_snapshot_rename_check,
16434007Smmusante 	    dsl_dataset_snapshot_rename_sync, ds, ra->newsnap, 0);
16444007Smmusante 
16454007Smmusante 	return (0);
16464007Smmusante }
16474007Smmusante 
16484007Smmusante static int
16494007Smmusante dsl_recursive_rename(char *oldname, const char *newname)
16504007Smmusante {
16514007Smmusante 	int err;
16524007Smmusante 	struct renamearg *ra;
16534007Smmusante 	dsl_sync_task_t *dst;
16544007Smmusante 	spa_t *spa;
16554007Smmusante 	char *cp, *fsname = spa_strdup(oldname);
16564007Smmusante 	int len = strlen(oldname);
16574007Smmusante 
16584007Smmusante 	/* truncate the snapshot name to get the fsname */
16594007Smmusante 	cp = strchr(fsname, '@');
16604007Smmusante 	*cp = '\0';
16614007Smmusante 
1662*4603Sahrens 	err = spa_open(fsname, &spa, FTAG);
16634007Smmusante 	if (err) {
16644007Smmusante 		kmem_free(fsname, len + 1);
16654007Smmusante 		return (err);
16664007Smmusante 	}
16674007Smmusante 	ra = kmem_alloc(sizeof (struct renamearg), KM_SLEEP);
16684007Smmusante 	ra->dstg = dsl_sync_task_group_create(spa_get_dsl(spa));
16694007Smmusante 
16704007Smmusante 	ra->oldsnap = strchr(oldname, '@') + 1;
16714007Smmusante 	ra->newsnap = strchr(newname, '@') + 1;
16724007Smmusante 	*ra->failed = '\0';
16734007Smmusante 
16744007Smmusante 	err = dmu_objset_find(fsname, dsl_snapshot_rename_one, ra,
16754007Smmusante 	    DS_FIND_CHILDREN);
16764007Smmusante 	kmem_free(fsname, len + 1);
16774007Smmusante 
16784007Smmusante 	if (err == 0) {
16794007Smmusante 		err = dsl_sync_task_group_wait(ra->dstg);
16804007Smmusante 	}
16814007Smmusante 
16824007Smmusante 	for (dst = list_head(&ra->dstg->dstg_tasks); dst;
16834007Smmusante 	    dst = list_next(&ra->dstg->dstg_tasks, dst)) {
16844007Smmusante 		dsl_dataset_t *ds = dst->dst_arg1;
16854007Smmusante 		if (dst->dst_err) {
16864007Smmusante 			dsl_dir_name(ds->ds_dir, ra->failed);
16874009Smmusante 			(void) strcat(ra->failed, "@");
16884009Smmusante 			(void) strcat(ra->failed, ra->newsnap);
16894007Smmusante 		}
16904007Smmusante 		dsl_dataset_close(ds, DS_MODE_STANDARD, ra->dstg);
16914007Smmusante 	}
16924007Smmusante 
16934543Smarks 	if (err)
16944543Smarks 		(void) strcpy(oldname, ra->failed);
16954007Smmusante 
16964007Smmusante 	dsl_sync_task_group_destroy(ra->dstg);
16974007Smmusante 	kmem_free(ra, sizeof (struct renamearg));
16984007Smmusante 	spa_close(spa, FTAG);
16994007Smmusante 	return (err);
17004007Smmusante }
17014007Smmusante 
17024569Smmusante static int
17034569Smmusante dsl_valid_rename(char *oldname, void *arg)
17044569Smmusante {
17054569Smmusante 	int delta = *(int *)arg;
17064569Smmusante 
17074569Smmusante 	if (strlen(oldname) + delta >= MAXNAMELEN)
17084569Smmusante 		return (ENAMETOOLONG);
17094569Smmusante 
17104569Smmusante 	return (0);
17114569Smmusante }
17124569Smmusante 
1713789Sahrens #pragma weak dmu_objset_rename = dsl_dataset_rename
1714789Sahrens int
17154007Smmusante dsl_dataset_rename(char *oldname, const char *newname,
17164007Smmusante     boolean_t recursive)
1717789Sahrens {
1718789Sahrens 	dsl_dir_t *dd;
17192199Sahrens 	dsl_dataset_t *ds;
1720789Sahrens 	const char *tail;
1721789Sahrens 	int err;
1722789Sahrens 
17232199Sahrens 	err = dsl_dir_open(oldname, FTAG, &dd, &tail);
17241544Seschrock 	if (err)
17251544Seschrock 		return (err);
1726789Sahrens 	if (tail == NULL) {
17274569Smmusante 		int delta = strlen(newname) - strlen(oldname);
17284569Smmusante 
17294569Smmusante 		/* if we're growing, validate child size lengths */
17304569Smmusante 		if (delta > 0)
17314569Smmusante 			err = dmu_objset_find(oldname, dsl_valid_rename,
17324569Smmusante 			    &delta, DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS);
17334569Smmusante 
17344569Smmusante 		if (!err)
17354569Smmusante 			err = dsl_dir_rename(dd, newname);
1736789Sahrens 		dsl_dir_close(dd, FTAG);
1737789Sahrens 		return (err);
1738789Sahrens 	}
1739789Sahrens 	if (tail[0] != '@') {
1740789Sahrens 		/* the name ended in a nonexistant component */
1741789Sahrens 		dsl_dir_close(dd, FTAG);
1742789Sahrens 		return (ENOENT);
1743789Sahrens 	}
1744789Sahrens 
17452199Sahrens 	dsl_dir_close(dd, FTAG);
17462199Sahrens 
17472199Sahrens 	/* new name must be snapshot in same filesystem */
17482199Sahrens 	tail = strchr(newname, '@');
17492199Sahrens 	if (tail == NULL)
17502199Sahrens 		return (EINVAL);
17512199Sahrens 	tail++;
17522199Sahrens 	if (strncmp(oldname, newname, tail - newname) != 0)
17532199Sahrens 		return (EXDEV);
1754789Sahrens 
17554007Smmusante 	if (recursive) {
17564007Smmusante 		err = dsl_recursive_rename(oldname, newname);
17574007Smmusante 	} else {
17584007Smmusante 		err = dsl_dataset_open(oldname,
17594007Smmusante 		    DS_MODE_READONLY | DS_MODE_STANDARD, FTAG, &ds);
17604007Smmusante 		if (err)
17614007Smmusante 			return (err);
17622199Sahrens 
17634007Smmusante 		err = dsl_sync_task_do(ds->ds_dir->dd_pool,
17644007Smmusante 		    dsl_dataset_snapshot_rename_check,
17654007Smmusante 		    dsl_dataset_snapshot_rename_sync, ds, (char *)tail, 1);
17662199Sahrens 
17674007Smmusante 		dsl_dataset_close(ds, DS_MODE_STANDARD, FTAG);
17684007Smmusante 	}
17692199Sahrens 
1770789Sahrens 	return (err);
1771789Sahrens }
17722082Seschrock 
17732199Sahrens struct promotearg {
17742199Sahrens 	uint64_t used, comp, uncomp, unique;
17752199Sahrens 	uint64_t newnext_obj, snapnames_obj;
17762199Sahrens };
17772199Sahrens 
17784543Smarks /* ARGSUSED */
17792082Seschrock static int
17802199Sahrens dsl_dataset_promote_check(void *arg1, void *arg2, dmu_tx_t *tx)
17812082Seschrock {
17822199Sahrens 	dsl_dataset_t *hds = arg1;
17832199Sahrens 	struct promotearg *pa = arg2;
17842199Sahrens 	dsl_dir_t *dd = hds->ds_dir;
17852199Sahrens 	dsl_pool_t *dp = hds->ds_dir->dd_pool;
17862082Seschrock 	dsl_dir_t *pdd = NULL;
17872082Seschrock 	dsl_dataset_t *ds = NULL;
17882082Seschrock 	dsl_dataset_t *pivot_ds = NULL;
17892082Seschrock 	dsl_dataset_t *newnext_ds = NULL;
17902082Seschrock 	int err;
17912082Seschrock 	char *name = NULL;
17922199Sahrens 	uint64_t itor = 0;
17932082Seschrock 	blkptr_t bp;
17942082Seschrock 
17952199Sahrens 	bzero(pa, sizeof (*pa));
17962199Sahrens 
17972082Seschrock 	/* Check that it is a clone */
17982082Seschrock 	if (dd->dd_phys->dd_clone_parent_obj == 0)
17992082Seschrock 		return (EINVAL);
18002082Seschrock 
18012199Sahrens 	/* Since this is so expensive, don't do the preliminary check */
18022199Sahrens 	if (!dmu_tx_is_syncing(tx))
18032199Sahrens 		return (0);
18042199Sahrens 
18052199Sahrens 	if (err = dsl_dataset_open_obj(dp,
18062082Seschrock 	    dd->dd_phys->dd_clone_parent_obj,
18072082Seschrock 	    NULL, DS_MODE_EXCLUSIVE, FTAG, &pivot_ds))
18082082Seschrock 		goto out;
18092082Seschrock 	pdd = pivot_ds->ds_dir;
18102199Sahrens 
18112199Sahrens 	{
18122199Sahrens 		dsl_dataset_t *phds;
18132199Sahrens 		if (err = dsl_dataset_open_obj(dd->dd_pool,
18142199Sahrens 		    pdd->dd_phys->dd_head_dataset_obj,
18152199Sahrens 		    NULL, DS_MODE_NONE, FTAG, &phds))
18162199Sahrens 			goto out;
18172199Sahrens 		pa->snapnames_obj = phds->ds_phys->ds_snapnames_zapobj;
18182199Sahrens 		dsl_dataset_close(phds, DS_MODE_NONE, FTAG);
18192199Sahrens 	}
18202082Seschrock 
18212082Seschrock 	if (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE) {
18222082Seschrock 		err = EXDEV;
18232082Seschrock 		goto out;
18242082Seschrock 	}
18252082Seschrock 
18262082Seschrock 	/* find pivot point's new next ds */
18272082Seschrock 	VERIFY(0 == dsl_dataset_open_obj(dd->dd_pool, hds->ds_object,
18282082Seschrock 	    NULL, DS_MODE_NONE, FTAG, &newnext_ds));
18292082Seschrock 	while (newnext_ds->ds_phys->ds_prev_snap_obj != pivot_ds->ds_object) {
18302082Seschrock 		dsl_dataset_t *prev;
18312082Seschrock 
18322082Seschrock 		if (err = dsl_dataset_open_obj(dd->dd_pool,
18332199Sahrens 		    newnext_ds->ds_phys->ds_prev_snap_obj,
18342199Sahrens 		    NULL, DS_MODE_NONE, FTAG, &prev))
18352082Seschrock 			goto out;
18362082Seschrock 		dsl_dataset_close(newnext_ds, DS_MODE_NONE, FTAG);
18372082Seschrock 		newnext_ds = prev;
18382082Seschrock 	}
18392199Sahrens 	pa->newnext_obj = newnext_ds->ds_object;
18402082Seschrock 
18412082Seschrock 	/* compute pivot point's new unique space */
18422082Seschrock 	while ((err = bplist_iterate(&newnext_ds->ds_deadlist,
18432082Seschrock 	    &itor, &bp)) == 0) {
18442082Seschrock 		if (bp.blk_birth > pivot_ds->ds_phys->ds_prev_snap_txg)
18452199Sahrens 			pa->unique += bp_get_dasize(dd->dd_pool->dp_spa, &bp);
18462082Seschrock 	}
18472082Seschrock 	if (err != ENOENT)
18482082Seschrock 		goto out;
18492082Seschrock 
18502082Seschrock 	/* Walk the snapshots that we are moving */
18512082Seschrock 	name = kmem_alloc(MAXPATHLEN, KM_SLEEP);
18522082Seschrock 	ds = pivot_ds;
18532082Seschrock 	/* CONSTCOND */
18542082Seschrock 	while (TRUE) {
18552082Seschrock 		uint64_t val, dlused, dlcomp, dluncomp;
18562082Seschrock 		dsl_dataset_t *prev;
18572082Seschrock 
18582082Seschrock 		/* Check that the snapshot name does not conflict */
18592082Seschrock 		dsl_dataset_name(ds, name);
18602082Seschrock 		err = zap_lookup(dd->dd_pool->dp_meta_objset,
18612082Seschrock 		    hds->ds_phys->ds_snapnames_zapobj, ds->ds_snapname,
18622082Seschrock 		    8, 1, &val);
18632082Seschrock 		if (err != ENOENT) {
18642082Seschrock 			if (err == 0)
18652082Seschrock 				err = EEXIST;
18662082Seschrock 			goto out;
18672082Seschrock 		}
18682082Seschrock 
18692082Seschrock 		/*
18702082Seschrock 		 * compute space to transfer.  Each snapshot gave birth to:
18712082Seschrock 		 * (my used) - (prev's used) + (deadlist's used)
18722082Seschrock 		 */
18732199Sahrens 		pa->used += ds->ds_phys->ds_used_bytes;
18742199Sahrens 		pa->comp += ds->ds_phys->ds_compressed_bytes;
18752199Sahrens 		pa->uncomp += ds->ds_phys->ds_uncompressed_bytes;
18762082Seschrock 
18772082Seschrock 		/* If we reach the first snapshot, we're done. */
18782082Seschrock 		if (ds->ds_phys->ds_prev_snap_obj == 0)
18792082Seschrock 			break;
18802082Seschrock 
18812082Seschrock 		if (err = bplist_space(&ds->ds_deadlist,
18822082Seschrock 		    &dlused, &dlcomp, &dluncomp))
18832082Seschrock 			goto out;
18842082Seschrock 		if (err = dsl_dataset_open_obj(dd->dd_pool,
18852082Seschrock 		    ds->ds_phys->ds_prev_snap_obj, NULL, DS_MODE_EXCLUSIVE,
18862082Seschrock 		    FTAG, &prev))
18872082Seschrock 			goto out;
18882199Sahrens 		pa->used += dlused - prev->ds_phys->ds_used_bytes;
18892199Sahrens 		pa->comp += dlcomp - prev->ds_phys->ds_compressed_bytes;
18902199Sahrens 		pa->uncomp += dluncomp - prev->ds_phys->ds_uncompressed_bytes;
18912082Seschrock 
18922082Seschrock 		/*
18932082Seschrock 		 * We could be a clone of a clone.  If we reach our
18942082Seschrock 		 * parent's branch point, we're done.
18952082Seschrock 		 */
18962082Seschrock 		if (prev->ds_phys->ds_next_snap_obj != ds->ds_object) {
18972082Seschrock 			dsl_dataset_close(prev, DS_MODE_EXCLUSIVE, FTAG);
18982082Seschrock 			break;
18992082Seschrock 		}
19002082Seschrock 		if (ds != pivot_ds)
19012082Seschrock 			dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG);
19022082Seschrock 		ds = prev;
19032082Seschrock 	}
19042082Seschrock 
19052082Seschrock 	/* Check that there is enough space here */
19062199Sahrens 	err = dsl_dir_transfer_possible(pdd, dd, pa->used);
19072199Sahrens 
19082199Sahrens out:
19092199Sahrens 	if (ds && ds != pivot_ds)
19102199Sahrens 		dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG);
19112199Sahrens 	if (pivot_ds)
19122199Sahrens 		dsl_dataset_close(pivot_ds, DS_MODE_EXCLUSIVE, FTAG);
19132199Sahrens 	if (newnext_ds)
19142199Sahrens 		dsl_dataset_close(newnext_ds, DS_MODE_NONE, FTAG);
19152199Sahrens 	if (name)
19162199Sahrens 		kmem_free(name, MAXPATHLEN);
19172199Sahrens 	return (err);
19182199Sahrens }
19192082Seschrock 
19202199Sahrens static void
19214543Smarks dsl_dataset_promote_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
19222199Sahrens {
19232199Sahrens 	dsl_dataset_t *hds = arg1;
19242199Sahrens 	struct promotearg *pa = arg2;
19252199Sahrens 	dsl_dir_t *dd = hds->ds_dir;
19262199Sahrens 	dsl_pool_t *dp = hds->ds_dir->dd_pool;
19272199Sahrens 	dsl_dir_t *pdd = NULL;
19282199Sahrens 	dsl_dataset_t *ds, *pivot_ds;
19292199Sahrens 	char *name;
19302199Sahrens 
19312199Sahrens 	ASSERT(dd->dd_phys->dd_clone_parent_obj != 0);
19322199Sahrens 	ASSERT(0 == (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE));
19332199Sahrens 
19342199Sahrens 	VERIFY(0 == dsl_dataset_open_obj(dp,
19352199Sahrens 	    dd->dd_phys->dd_clone_parent_obj,
19362199Sahrens 	    NULL, DS_MODE_EXCLUSIVE, FTAG, &pivot_ds));
19372417Sahrens 	/*
19382417Sahrens 	 * We need to explicitly open pdd, since pivot_ds's pdd will be
19392417Sahrens 	 * changing.
19402417Sahrens 	 */
19412417Sahrens 	VERIFY(0 == dsl_dir_open_obj(dp, pivot_ds->ds_dir->dd_object,
19422417Sahrens 	    NULL, FTAG, &pdd));
19432082Seschrock 
19442082Seschrock 	/* move snapshots to this dir */
19452199Sahrens 	name = kmem_alloc(MAXPATHLEN, KM_SLEEP);
19462082Seschrock 	ds = pivot_ds;
19472082Seschrock 	/* CONSTCOND */
19482082Seschrock 	while (TRUE) {
19492082Seschrock 		dsl_dataset_t *prev;
19502082Seschrock 
19512082Seschrock 		/* move snap name entry */
19522082Seschrock 		dsl_dataset_name(ds, name);
19532199Sahrens 		VERIFY(0 == zap_remove(dp->dp_meta_objset,
19542199Sahrens 		    pa->snapnames_obj, ds->ds_snapname, tx));
19552199Sahrens 		VERIFY(0 == zap_add(dp->dp_meta_objset,
19562082Seschrock 		    hds->ds_phys->ds_snapnames_zapobj, ds->ds_snapname,
19572082Seschrock 		    8, 1, &ds->ds_object, tx));
19582082Seschrock 
19592082Seschrock 		/* change containing dsl_dir */
19602082Seschrock 		dmu_buf_will_dirty(ds->ds_dbuf, tx);
19612082Seschrock 		ASSERT3U(ds->ds_phys->ds_dir_obj, ==, pdd->dd_object);
19622082Seschrock 		ds->ds_phys->ds_dir_obj = dd->dd_object;
19632082Seschrock 		ASSERT3P(ds->ds_dir, ==, pdd);
19642082Seschrock 		dsl_dir_close(ds->ds_dir, ds);
19652199Sahrens 		VERIFY(0 == dsl_dir_open_obj(dp, dd->dd_object,
19662082Seschrock 		    NULL, ds, &ds->ds_dir));
19672082Seschrock 
19682082Seschrock 		ASSERT3U(dsl_prop_numcb(ds), ==, 0);
19692082Seschrock 
19702082Seschrock 		if (ds->ds_phys->ds_prev_snap_obj == 0)
19712082Seschrock 			break;
19722082Seschrock 
19732199Sahrens 		VERIFY(0 == dsl_dataset_open_obj(dp,
19742082Seschrock 		    ds->ds_phys->ds_prev_snap_obj, NULL, DS_MODE_EXCLUSIVE,
19752082Seschrock 		    FTAG, &prev));
19762082Seschrock 
19772082Seschrock 		if (prev->ds_phys->ds_next_snap_obj != ds->ds_object) {
19782082Seschrock 			dsl_dataset_close(prev, DS_MODE_EXCLUSIVE, FTAG);
19792082Seschrock 			break;
19802082Seschrock 		}
19812082Seschrock 		if (ds != pivot_ds)
19822082Seschrock 			dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG);
19832082Seschrock 		ds = prev;
19842082Seschrock 	}
19852199Sahrens 	if (ds != pivot_ds)
19862199Sahrens 		dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG);
19872082Seschrock 
19882082Seschrock 	/* change pivot point's next snap */
19892082Seschrock 	dmu_buf_will_dirty(pivot_ds->ds_dbuf, tx);
19902199Sahrens 	pivot_ds->ds_phys->ds_next_snap_obj = pa->newnext_obj;
19912082Seschrock 
19922082Seschrock 	/* change clone_parent-age */
19932082Seschrock 	dmu_buf_will_dirty(dd->dd_dbuf, tx);
19942082Seschrock 	ASSERT3U(dd->dd_phys->dd_clone_parent_obj, ==, pivot_ds->ds_object);
19952082Seschrock 	dd->dd_phys->dd_clone_parent_obj = pdd->dd_phys->dd_clone_parent_obj;
19962082Seschrock 	dmu_buf_will_dirty(pdd->dd_dbuf, tx);
19972082Seschrock 	pdd->dd_phys->dd_clone_parent_obj = pivot_ds->ds_object;
19982082Seschrock 
19992082Seschrock 	/* change space accounting */
20002199Sahrens 	dsl_dir_diduse_space(pdd, -pa->used, -pa->comp, -pa->uncomp, tx);
20012199Sahrens 	dsl_dir_diduse_space(dd, pa->used, pa->comp, pa->uncomp, tx);
20022199Sahrens 	pivot_ds->ds_phys->ds_unique_bytes = pa->unique;
20032082Seschrock 
20044543Smarks 	/* log history record */
20054543Smarks 	spa_history_internal_log(LOG_DS_PROMOTE, dd->dd_pool->dp_spa, tx,
20064543Smarks 	    cr, "dataset = %llu", ds->ds_object);
20074543Smarks 
20082417Sahrens 	dsl_dir_close(pdd, FTAG);
20092199Sahrens 	dsl_dataset_close(pivot_ds, DS_MODE_EXCLUSIVE, FTAG);
20102199Sahrens 	kmem_free(name, MAXPATHLEN);
20112082Seschrock }
20122082Seschrock 
20132082Seschrock int
20142082Seschrock dsl_dataset_promote(const char *name)
20152082Seschrock {
20162082Seschrock 	dsl_dataset_t *ds;
20172082Seschrock 	int err;
20182082Seschrock 	dmu_object_info_t doi;
20192199Sahrens 	struct promotearg pa;
20202082Seschrock 
20212082Seschrock 	err = dsl_dataset_open(name, DS_MODE_NONE, FTAG, &ds);
20222082Seschrock 	if (err)
20232082Seschrock 		return (err);
20242082Seschrock 
20252082Seschrock 	err = dmu_object_info(ds->ds_dir->dd_pool->dp_meta_objset,
20262082Seschrock 	    ds->ds_phys->ds_snapnames_zapobj, &doi);
20272082Seschrock 	if (err) {
20282082Seschrock 		dsl_dataset_close(ds, DS_MODE_NONE, FTAG);
20292082Seschrock 		return (err);
20302082Seschrock 	}
20312082Seschrock 
20322082Seschrock 	/*
20332082Seschrock 	 * Add in 128x the snapnames zapobj size, since we will be moving
20342082Seschrock 	 * a bunch of snapnames to the promoted ds, and dirtying their
20352082Seschrock 	 * bonus buffers.
20362082Seschrock 	 */
20372199Sahrens 	err = dsl_sync_task_do(ds->ds_dir->dd_pool,
20382199Sahrens 	    dsl_dataset_promote_check,
20392199Sahrens 	    dsl_dataset_promote_sync, ds, &pa, 2 + 2 * doi.doi_physical_blks);
20402082Seschrock 	dsl_dataset_close(ds, DS_MODE_NONE, FTAG);
20412082Seschrock 	return (err);
20422082Seschrock }
20433912Slling 
20443912Slling /*
20453912Slling  * Given a pool name and a dataset object number in that pool,
20463912Slling  * return the name of that dataset.
20473912Slling  */
20483912Slling int
20493912Slling dsl_dsobj_to_dsname(char *pname, uint64_t obj, char *buf)
20503912Slling {
20513912Slling 	spa_t *spa;
20523912Slling 	dsl_pool_t *dp;
20533912Slling 	dsl_dataset_t *ds = NULL;
20543912Slling 	int error;
20553912Slling 
20563912Slling 	if ((error = spa_open(pname, &spa, FTAG)) != 0)
20573912Slling 		return (error);
20583912Slling 	dp = spa_get_dsl(spa);
20593912Slling 	rw_enter(&dp->dp_config_rwlock, RW_READER);
20603912Slling 	if ((error = dsl_dataset_open_obj(dp, obj,
20613912Slling 	    NULL, DS_MODE_NONE, FTAG, &ds)) != 0) {
20623912Slling 		rw_exit(&dp->dp_config_rwlock);
20633912Slling 		spa_close(spa, FTAG);
20643912Slling 		return (error);
20653912Slling 	}
20663912Slling 	dsl_dataset_name(ds, buf);
20673912Slling 	dsl_dataset_close(ds, DS_MODE_NONE, FTAG);
20683912Slling 	rw_exit(&dp->dp_config_rwlock);
20693912Slling 	spa_close(spa, FTAG);
20703912Slling 
20713912Slling 	return (0);
20723912Slling }
2073