1fa9e4066Sahrens /*
2fa9e4066Sahrens  * CDDL HEADER START
3fa9e4066Sahrens  *
4fa9e4066Sahrens  * The contents of this file are subject to the terms of the
5ea8dc4b6Seschrock  * Common Development and Distribution License (the "License").
6ea8dc4b6Seschrock  * You may not use this file except in compliance with the License.
7fa9e4066Sahrens  *
8fa9e4066Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fa9e4066Sahrens  * or http://www.opensolaris.org/os/licensing.
10fa9e4066Sahrens  * See the License for the specific language governing permissions
11fa9e4066Sahrens  * and limitations under the License.
12fa9e4066Sahrens  *
13fa9e4066Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
14fa9e4066Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fa9e4066Sahrens  * If applicable, add the following below this CDDL HEADER, with the
16fa9e4066Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
17fa9e4066Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
18fa9e4066Sahrens  *
19fa9e4066Sahrens  * CDDL HEADER END
20fa9e4066Sahrens  */
21fa9e4066Sahrens /*
225afc78aaSChris Kirby  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23ad135b5dSChristopher Siden  * Copyright (c) 2012 by Delphix. All rights reserved.
244e3c9f44SBill Pijewski  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
25fa9e4066Sahrens  */
26fa9e4066Sahrens 
27fa9e4066Sahrens #include <sys/dmu_objset.h>
28fa9e4066Sahrens #include <sys/dsl_dataset.h>
29fa9e4066Sahrens #include <sys/dsl_dir.h>
3099653d4eSeschrock #include <sys/dsl_prop.h>
311d452cf5Sahrens #include <sys/dsl_synctask.h>
32fa9e4066Sahrens #include <sys/dmu_traverse.h>
334e3c9f44SBill Pijewski #include <sys/dmu_impl.h>
34fa9e4066Sahrens #include <sys/dmu_tx.h>
35fa9e4066Sahrens #include <sys/arc.h>
36fa9e4066Sahrens #include <sys/zio.h>
37fa9e4066Sahrens #include <sys/zap.h>
38ad135b5dSChristopher Siden #include <sys/zfeature.h>
39fa9e4066Sahrens #include <sys/unique.h>
40fa9e4066Sahrens #include <sys/zfs_context.h>
41cdf5b4caSmmusante #include <sys/zfs_ioctl.h>
42ecd6cf80Smarks #include <sys/spa.h>
43088f3894Sahrens #include <sys/zfs_znode.h>
44c99e4bdcSChris Kirby #include <sys/zfs_onexit.h>
45842727c2SChris Kirby #include <sys/zvol.h>
463f9d6ad7SLin Ling #include <sys/dsl_scan.h>
47cde58dbcSMatthew Ahrens #include <sys/dsl_deadlist.h>
48fa9e4066Sahrens 
49745cd3c5Smaybee static char *dsl_reaper = "the grim reaper";
50745cd3c5Smaybee 
511d452cf5Sahrens static dsl_checkfunc_t dsl_dataset_destroy_begin_check;
521d452cf5Sahrens static dsl_syncfunc_t dsl_dataset_destroy_begin_sync;
53a9799022Sck static dsl_syncfunc_t dsl_dataset_set_reservation_sync;
54e1930233Sbonwick 
55cde58dbcSMatthew Ahrens #define	SWITCH64(x, y) \
56cde58dbcSMatthew Ahrens 	{ \
57cde58dbcSMatthew Ahrens 		uint64_t __tmp = (x); \
58cde58dbcSMatthew Ahrens 		(x) = (y); \
59cde58dbcSMatthew Ahrens 		(y) = __tmp; \
60cde58dbcSMatthew Ahrens 	}
61cde58dbcSMatthew Ahrens 
6255434c77Sek #define	DS_REF_MAX	(1ULL << 62)
63fa9e4066Sahrens 
64fa9e4066Sahrens #define	DSL_DEADLIST_BLOCKSIZE	SPA_MAXBLOCKSIZE
65fa9e4066Sahrens 
66745cd3c5Smaybee #define	DSL_DATASET_IS_DESTROYED(ds)	((ds)->ds_owner == dsl_reaper)
67745cd3c5Smaybee 
68fa9e4066Sahrens 
69a9799022Sck /*
70a9799022Sck  * Figure out how much of this delta should be propogated to the dsl_dir
71a9799022Sck  * layer.  If there's a refreservation, that space has already been
72a9799022Sck  * partially accounted for in our ancestors.
73a9799022Sck  */
74a9799022Sck static int64_t
75a9799022Sck parent_delta(dsl_dataset_t *ds, int64_t delta)
76a9799022Sck {
77a9799022Sck 	uint64_t old_bytes, new_bytes;
78a9799022Sck 
79a9799022Sck 	if (ds->ds_reserved == 0)
80a9799022Sck 		return (delta);
81a9799022Sck 
82a9799022Sck 	old_bytes = MAX(ds->ds_phys->ds_unique_bytes, ds->ds_reserved);
83a9799022Sck 	new_bytes = MAX(ds->ds_phys->ds_unique_bytes + delta, ds->ds_reserved);
84a9799022Sck 
85a9799022Sck 	ASSERT3U(ABS((int64_t)(new_bytes - old_bytes)), <=, ABS(delta));
86a9799022Sck 	return (new_bytes - old_bytes);
87a9799022Sck }
88fa9e4066Sahrens 
89fa9e4066Sahrens void
90b24ab676SJeff Bonwick dsl_dataset_block_born(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx)
91fa9e4066Sahrens {
92b24ab676SJeff Bonwick 	int used = bp_get_dsize_sync(tx->tx_pool->dp_spa, bp);
93fa9e4066Sahrens 	int compressed = BP_GET_PSIZE(bp);
94fa9e4066Sahrens 	int uncompressed = BP_GET_UCSIZE(bp);
95a9799022Sck 	int64_t delta;
96fa9e4066Sahrens 
973f9d6ad7SLin Ling 	dprintf_bp(bp, "ds=%p", ds);
98fa9e4066Sahrens 
99fa9e4066Sahrens 	ASSERT(dmu_tx_is_syncing(tx));
100fa9e4066Sahrens 	/* It could have been compressed away to nothing */
101fa9e4066Sahrens 	if (BP_IS_HOLE(bp))
102fa9e4066Sahrens 		return;
103fa9e4066Sahrens 	ASSERT(BP_GET_TYPE(bp) != DMU_OT_NONE);
104ad135b5dSChristopher Siden 	ASSERT(DMU_OT_IS_VALID(BP_GET_TYPE(bp)));
105fa9e4066Sahrens 	if (ds == NULL) {
106*ce636f8bSMatthew Ahrens 		dsl_pool_mos_diduse_space(tx->tx_pool,
107*ce636f8bSMatthew Ahrens 		    used, compressed, uncompressed);
108fa9e4066Sahrens 		return;
109fa9e4066Sahrens 	}
110fa9e4066Sahrens 	dmu_buf_will_dirty(ds->ds_dbuf, tx);
1113f9d6ad7SLin Ling 
11202c8f3f0SMatthew Ahrens 	mutex_enter(&ds->ds_dir->dd_lock);
113fa9e4066Sahrens 	mutex_enter(&ds->ds_lock);
114a9799022Sck 	delta = parent_delta(ds, used);
115ad135b5dSChristopher Siden 	ds->ds_phys->ds_referenced_bytes += used;
116fa9e4066Sahrens 	ds->ds_phys->ds_compressed_bytes += compressed;
117fa9e4066Sahrens 	ds->ds_phys->ds_uncompressed_bytes += uncompressed;
118fa9e4066Sahrens 	ds->ds_phys->ds_unique_bytes += used;
119fa9e4066Sahrens 	mutex_exit(&ds->ds_lock);
12074e7dc98SMatthew Ahrens 	dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, delta,
12174e7dc98SMatthew Ahrens 	    compressed, uncompressed, tx);
12274e7dc98SMatthew Ahrens 	dsl_dir_transfer_space(ds->ds_dir, used - delta,
12374e7dc98SMatthew Ahrens 	    DD_USED_REFRSRV, DD_USED_HEAD, tx);
12402c8f3f0SMatthew Ahrens 	mutex_exit(&ds->ds_dir->dd_lock);
125fa9e4066Sahrens }
126fa9e4066Sahrens 
127cdb0ab79Smaybee int
128b24ab676SJeff Bonwick dsl_dataset_block_kill(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx,
129b24ab676SJeff Bonwick     boolean_t async)
130fa9e4066Sahrens {
131fa9e4066Sahrens 	if (BP_IS_HOLE(bp))
132cdb0ab79Smaybee 		return (0);
133fa9e4066Sahrens 
134b24ab676SJeff Bonwick 	ASSERT(dmu_tx_is_syncing(tx));
135b24ab676SJeff Bonwick 	ASSERT(bp->blk_birth <= tx->tx_txg);
136b24ab676SJeff Bonwick 
137b24ab676SJeff Bonwick 	int used = bp_get_dsize_sync(tx->tx_pool->dp_spa, bp);
138b24ab676SJeff Bonwick 	int compressed = BP_GET_PSIZE(bp);
139b24ab676SJeff Bonwick 	int uncompressed = BP_GET_UCSIZE(bp);
140b24ab676SJeff Bonwick 
141fa9e4066Sahrens 	ASSERT(used > 0);
142fa9e4066Sahrens 	if (ds == NULL) {
143b24ab676SJeff Bonwick 		dsl_free(tx->tx_pool, tx->tx_txg, bp);
144*ce636f8bSMatthew Ahrens 		dsl_pool_mos_diduse_space(tx->tx_pool,
145*ce636f8bSMatthew Ahrens 		    -used, -compressed, -uncompressed);
146cdb0ab79Smaybee 		return (used);
147fa9e4066Sahrens 	}
148fa9e4066Sahrens 	ASSERT3P(tx->tx_pool, ==, ds->ds_dir->dd_pool);
149fa9e4066Sahrens 
15074e7dc98SMatthew Ahrens 	ASSERT(!dsl_dataset_is_snapshot(ds));
151fa9e4066Sahrens 	dmu_buf_will_dirty(ds->ds_dbuf, tx);
152fa9e4066Sahrens 
153fa9e4066Sahrens 	if (bp->blk_birth > ds->ds_phys->ds_prev_snap_txg) {
154a9799022Sck 		int64_t delta;
155c717a561Smaybee 
1563f9d6ad7SLin Ling 		dprintf_bp(bp, "freeing ds=%llu", ds->ds_object);
157b24ab676SJeff Bonwick 		dsl_free(tx->tx_pool, tx->tx_txg, bp);
158fa9e4066Sahrens 
15902c8f3f0SMatthew Ahrens 		mutex_enter(&ds->ds_dir->dd_lock);
160fa9e4066Sahrens 		mutex_enter(&ds->ds_lock);
161a9799022Sck 		ASSERT(ds->ds_phys->ds_unique_bytes >= used ||
162a9799022Sck 		    !DS_UNIQUE_IS_ACCURATE(ds));
163a9799022Sck 		delta = parent_delta(ds, -used);
164fa9e4066Sahrens 		ds->ds_phys->ds_unique_bytes -= used;
165fa9e4066Sahrens 		mutex_exit(&ds->ds_lock);
16674e7dc98SMatthew Ahrens 		dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD,
167a9799022Sck 		    delta, -compressed, -uncompressed, tx);
16874e7dc98SMatthew Ahrens 		dsl_dir_transfer_space(ds->ds_dir, -used - delta,
16974e7dc98SMatthew Ahrens 		    DD_USED_REFRSRV, DD_USED_HEAD, tx);
17002c8f3f0SMatthew Ahrens 		mutex_exit(&ds->ds_dir->dd_lock);
171fa9e4066Sahrens 	} else {
172fa9e4066Sahrens 		dprintf_bp(bp, "putting on dead list: %s", "");
173b24ab676SJeff Bonwick 		if (async) {
174b24ab676SJeff Bonwick 			/*
175b24ab676SJeff Bonwick 			 * We are here as part of zio's write done callback,
176b24ab676SJeff Bonwick 			 * which means we're a zio interrupt thread.  We can't
177cde58dbcSMatthew Ahrens 			 * call dsl_deadlist_insert() now because it may block
178b24ab676SJeff Bonwick 			 * waiting for I/O.  Instead, put bp on the deferred
179b24ab676SJeff Bonwick 			 * queue and let dsl_pool_sync() finish the job.
180b24ab676SJeff Bonwick 			 */
181cde58dbcSMatthew Ahrens 			bplist_append(&ds->ds_pending_deadlist, bp);
182b24ab676SJeff Bonwick 		} else {
183cde58dbcSMatthew Ahrens 			dsl_deadlist_insert(&ds->ds_deadlist, bp, tx);
184b24ab676SJeff Bonwick 		}
185a4611edeSahrens 		ASSERT3U(ds->ds_prev->ds_object, ==,
186a4611edeSahrens 		    ds->ds_phys->ds_prev_snap_obj);
187a4611edeSahrens 		ASSERT(ds->ds_prev->ds_phys->ds_num_children > 0);
188fa9e4066Sahrens 		/* if (bp->blk_birth > prev prev snap txg) prev unique += bs */
189a4611edeSahrens 		if (ds->ds_prev->ds_phys->ds_next_snap_obj ==
190a4611edeSahrens 		    ds->ds_object && bp->blk_birth >
191a4611edeSahrens 		    ds->ds_prev->ds_phys->ds_prev_snap_txg) {
192a4611edeSahrens 			dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx);
193a4611edeSahrens 			mutex_enter(&ds->ds_prev->ds_lock);
194a4611edeSahrens 			ds->ds_prev->ds_phys->ds_unique_bytes += used;
195a4611edeSahrens 			mutex_exit(&ds->ds_prev->ds_lock);
196fa9e4066Sahrens 		}
1973f9d6ad7SLin Ling 		if (bp->blk_birth > ds->ds_dir->dd_origin_txg) {
19874e7dc98SMatthew Ahrens 			dsl_dir_transfer_space(ds->ds_dir, used,
19974e7dc98SMatthew Ahrens 			    DD_USED_HEAD, DD_USED_SNAP, tx);
20074e7dc98SMatthew Ahrens 		}
201fa9e4066Sahrens 	}
202fa9e4066Sahrens 	mutex_enter(&ds->ds_lock);
203ad135b5dSChristopher Siden 	ASSERT3U(ds->ds_phys->ds_referenced_bytes, >=, used);
204ad135b5dSChristopher Siden 	ds->ds_phys->ds_referenced_bytes -= used;
205fa9e4066Sahrens 	ASSERT3U(ds->ds_phys->ds_compressed_bytes, >=, compressed);
206fa9e4066Sahrens 	ds->ds_phys->ds_compressed_bytes -= compressed;
207fa9e4066Sahrens 	ASSERT3U(ds->ds_phys->ds_uncompressed_bytes, >=, uncompressed);
208fa9e4066Sahrens 	ds->ds_phys->ds_uncompressed_bytes -= uncompressed;
209fa9e4066Sahrens 	mutex_exit(&ds->ds_lock);
210cdb0ab79Smaybee 
211cdb0ab79Smaybee 	return (used);
212fa9e4066Sahrens }
213fa9e4066Sahrens 
214ea8dc4b6Seschrock uint64_t
215ea8dc4b6Seschrock dsl_dataset_prev_snap_txg(dsl_dataset_t *ds)
216fa9e4066Sahrens {
217a2eea2e1Sahrens 	uint64_t trysnap = 0;
218a2eea2e1Sahrens 
219fa9e4066Sahrens 	if (ds == NULL)
220ea8dc4b6Seschrock 		return (0);
221fa9e4066Sahrens 	/*
222fa9e4066Sahrens 	 * The snapshot creation could fail, but that would cause an
223fa9e4066Sahrens 	 * incorrect FALSE return, which would only result in an
224fa9e4066Sahrens 	 * overestimation of the amount of space that an operation would
225fa9e4066Sahrens 	 * consume, which is OK.
226fa9e4066Sahrens 	 *
227fa9e4066Sahrens 	 * There's also a small window where we could miss a pending
228fa9e4066Sahrens 	 * snapshot, because we could set the sync task in the quiescing
229fa9e4066Sahrens 	 * phase.  So this should only be used as a guess.
230fa9e4066Sahrens 	 */
231a2eea2e1Sahrens 	if (ds->ds_trysnap_txg >
232a2eea2e1Sahrens 	    spa_last_synced_txg(ds->ds_dir->dd_pool->dp_spa))
233a2eea2e1Sahrens 		trysnap = ds->ds_trysnap_txg;
234a2eea2e1Sahrens 	return (MAX(ds->ds_phys->ds_prev_snap_txg, trysnap));
235ea8dc4b6Seschrock }
236ea8dc4b6Seschrock 
2373d692628SSanjeev Bagewadi boolean_t
238c7cd2421SGeorge Wilson dsl_dataset_block_freeable(dsl_dataset_t *ds, const blkptr_t *bp,
239c7cd2421SGeorge Wilson     uint64_t blk_birth)
240ea8dc4b6Seschrock {
241c7cd2421SGeorge Wilson 	if (blk_birth <= dsl_dataset_prev_snap_txg(ds))
242c7cd2421SGeorge Wilson 		return (B_FALSE);
243c7cd2421SGeorge Wilson 
244837b568bSGeorge Wilson 	ddt_prefetch(dsl_dataset_get_spa(ds), bp);
245c7cd2421SGeorge Wilson 
246c7cd2421SGeorge Wilson 	return (B_TRUE);
247fa9e4066Sahrens }
248fa9e4066Sahrens 
249fa9e4066Sahrens /* ARGSUSED */
250fa9e4066Sahrens static void
251fa9e4066Sahrens dsl_dataset_evict(dmu_buf_t *db, void *dsv)
252fa9e4066Sahrens {
253fa9e4066Sahrens 	dsl_dataset_t *ds = dsv;
254fa9e4066Sahrens 
255745cd3c5Smaybee 	ASSERT(ds->ds_owner == NULL || DSL_DATASET_IS_DESTROYED(ds));
256fa9e4066Sahrens 
25791ebeef5Sahrens 	unique_remove(ds->ds_fsid_guid);
258fa9e4066Sahrens 
259503ad85cSMatthew Ahrens 	if (ds->ds_objset != NULL)
260503ad85cSMatthew Ahrens 		dmu_objset_evict(ds->ds_objset);
261fa9e4066Sahrens 
262fa9e4066Sahrens 	if (ds->ds_prev) {
263745cd3c5Smaybee 		dsl_dataset_drop_ref(ds->ds_prev, ds);
264fa9e4066Sahrens 		ds->ds_prev = NULL;
265fa9e4066Sahrens 	}
266fa9e4066Sahrens 
267cde58dbcSMatthew Ahrens 	bplist_destroy(&ds->ds_pending_deadlist);
268cde58dbcSMatthew Ahrens 	if (db != NULL) {
269cde58dbcSMatthew Ahrens 		dsl_deadlist_close(&ds->ds_deadlist);
270cde58dbcSMatthew Ahrens 	} else {
271cde58dbcSMatthew Ahrens 		ASSERT(ds->ds_deadlist.dl_dbuf == NULL);
272cde58dbcSMatthew Ahrens 		ASSERT(!ds->ds_deadlist.dl_oldfmt);
273cde58dbcSMatthew Ahrens 	}
274745cd3c5Smaybee 	if (ds->ds_dir)
275745cd3c5Smaybee 		dsl_dir_close(ds->ds_dir, ds);
276fa9e4066Sahrens 
27791ebeef5Sahrens 	ASSERT(!list_link_active(&ds->ds_synced_link));
278fa9e4066Sahrens 
2795ad82045Snd 	mutex_destroy(&ds->ds_lock);
280f4b94bdeSMatthew Ahrens 	mutex_destroy(&ds->ds_recvlock);
28191ebeef5Sahrens 	mutex_destroy(&ds->ds_opening_lock);
282745cd3c5Smaybee 	rw_destroy(&ds->ds_rwlock);
283745cd3c5Smaybee 	cv_destroy(&ds->ds_exclusive_cv);
2845ad82045Snd 
285fa9e4066Sahrens 	kmem_free(ds, sizeof (dsl_dataset_t));
286fa9e4066Sahrens }
287fa9e4066Sahrens 
288ea8dc4b6Seschrock static int
289fa9e4066Sahrens dsl_dataset_get_snapname(dsl_dataset_t *ds)
290fa9e4066Sahrens {
291fa9e4066Sahrens 	dsl_dataset_phys_t *headphys;
292fa9e4066Sahrens 	int err;
293fa9e4066Sahrens 	dmu_buf_t *headdbuf;
294fa9e4066Sahrens 	dsl_pool_t *dp = ds->ds_dir->dd_pool;
295fa9e4066Sahrens 	objset_t *mos = dp->dp_meta_objset;
296fa9e4066Sahrens 
297fa9e4066Sahrens 	if (ds->ds_snapname[0])
298ea8dc4b6Seschrock 		return (0);
299fa9e4066Sahrens 	if (ds->ds_phys->ds_next_snap_obj == 0)
300ea8dc4b6Seschrock 		return (0);
301fa9e4066Sahrens 
302ea8dc4b6Seschrock 	err = dmu_bonus_hold(mos, ds->ds_dir->dd_phys->dd_head_dataset_obj,
303ea8dc4b6Seschrock 	    FTAG, &headdbuf);
304ea8dc4b6Seschrock 	if (err)
305ea8dc4b6Seschrock 		return (err);
306fa9e4066Sahrens 	headphys = headdbuf->db_data;
307fa9e4066Sahrens 	err = zap_value_search(dp->dp_meta_objset,
308e7437265Sahrens 	    headphys->ds_snapnames_zapobj, ds->ds_object, 0, ds->ds_snapname);
309ea8dc4b6Seschrock 	dmu_buf_rele(headdbuf, FTAG);
310ea8dc4b6Seschrock 	return (err);
311fa9e4066Sahrens }
312fa9e4066Sahrens 
313ab04eb8eStimh static int
314745cd3c5Smaybee dsl_dataset_snap_lookup(dsl_dataset_t *ds, const char *name, uint64_t *value)
315ab04eb8eStimh {
316745cd3c5Smaybee 	objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
317745cd3c5Smaybee 	uint64_t snapobj = ds->ds_phys->ds_snapnames_zapobj;
318ab04eb8eStimh 	matchtype_t mt;
319ab04eb8eStimh 	int err;
320ab04eb8eStimh 
321745cd3c5Smaybee 	if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET)
322ab04eb8eStimh 		mt = MT_FIRST;
323ab04eb8eStimh 	else
324ab04eb8eStimh 		mt = MT_EXACT;
325ab04eb8eStimh 
326745cd3c5Smaybee 	err = zap_lookup_norm(mos, snapobj, name, 8, 1,
327ab04eb8eStimh 	    value, mt, NULL, 0, NULL);
328ab04eb8eStimh 	if (err == ENOTSUP && mt == MT_FIRST)
329745cd3c5Smaybee 		err = zap_lookup(mos, snapobj, name, 8, 1, value);
330ab04eb8eStimh 	return (err);
331ab04eb8eStimh }
332ab04eb8eStimh 
333ab04eb8eStimh static int
334745cd3c5Smaybee dsl_dataset_snap_remove(dsl_dataset_t *ds, char *name, dmu_tx_t *tx)
335ab04eb8eStimh {
336745cd3c5Smaybee 	objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
337745cd3c5Smaybee 	uint64_t snapobj = ds->ds_phys->ds_snapnames_zapobj;
338ab04eb8eStimh 	matchtype_t mt;
339ab04eb8eStimh 	int err;
340ab04eb8eStimh 
34171eb0538SChris Kirby 	dsl_dir_snap_cmtime_update(ds->ds_dir);
34271eb0538SChris Kirby 
343745cd3c5Smaybee 	if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET)
344ab04eb8eStimh 		mt = MT_FIRST;
345ab04eb8eStimh 	else
346ab04eb8eStimh 		mt = MT_EXACT;
347ab04eb8eStimh 
348745cd3c5Smaybee 	err = zap_remove_norm(mos, snapobj, name, mt, tx);
349ab04eb8eStimh 	if (err == ENOTSUP && mt == MT_FIRST)
350745cd3c5Smaybee 		err = zap_remove(mos, snapobj, name, tx);
351ab04eb8eStimh 	return (err);
352ab04eb8eStimh }
353ab04eb8eStimh 
354745cd3c5Smaybee static int
355745cd3c5Smaybee dsl_dataset_get_ref(dsl_pool_t *dp, uint64_t dsobj, void *tag,
356745cd3c5Smaybee     dsl_dataset_t **dsp)
357fa9e4066Sahrens {
358fa9e4066Sahrens 	objset_t *mos = dp->dp_meta_objset;
359fa9e4066Sahrens 	dmu_buf_t *dbuf;
360fa9e4066Sahrens 	dsl_dataset_t *ds;
361ea8dc4b6Seschrock 	int err;
362a7f53a56SChris Kirby 	dmu_object_info_t doi;
363fa9e4066Sahrens 
364fa9e4066Sahrens 	ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock) ||
365fa9e4066Sahrens 	    dsl_pool_sync_context(dp));
366fa9e4066Sahrens 
367ea8dc4b6Seschrock 	err = dmu_bonus_hold(mos, dsobj, tag, &dbuf);
368ea8dc4b6Seschrock 	if (err)
369ea8dc4b6Seschrock 		return (err);
370a7f53a56SChris Kirby 
371a7f53a56SChris Kirby 	/* Make sure dsobj has the correct object type. */
372a7f53a56SChris Kirby 	dmu_object_info_from_db(dbuf, &doi);
373a7f53a56SChris Kirby 	if (doi.doi_type != DMU_OT_DSL_DATASET)
374a7f53a56SChris Kirby 		return (EINVAL);
375a7f53a56SChris Kirby 
376fa9e4066Sahrens 	ds = dmu_buf_get_user(dbuf);
377fa9e4066Sahrens 	if (ds == NULL) {
378fa9e4066Sahrens 		dsl_dataset_t *winner;
379fa9e4066Sahrens 
380fa9e4066Sahrens 		ds = kmem_zalloc(sizeof (dsl_dataset_t), KM_SLEEP);
381fa9e4066Sahrens 		ds->ds_dbuf = dbuf;
382fa9e4066Sahrens 		ds->ds_object = dsobj;
383fa9e4066Sahrens 		ds->ds_phys = dbuf->db_data;
384fa9e4066Sahrens 
3855ad82045Snd 		mutex_init(&ds->ds_lock, NULL, MUTEX_DEFAULT, NULL);
386f4b94bdeSMatthew Ahrens 		mutex_init(&ds->ds_recvlock, NULL, MUTEX_DEFAULT, NULL);
38791ebeef5Sahrens 		mutex_init(&ds->ds_opening_lock, NULL, MUTEX_DEFAULT, NULL);
3884e3c9f44SBill Pijewski 		mutex_init(&ds->ds_sendstream_lock, NULL, MUTEX_DEFAULT, NULL);
3894e3c9f44SBill Pijewski 
390745cd3c5Smaybee 		rw_init(&ds->ds_rwlock, 0, 0, 0);
391745cd3c5Smaybee 		cv_init(&ds->ds_exclusive_cv, NULL, CV_DEFAULT, NULL);
3925ad82045Snd 
393cde58dbcSMatthew Ahrens 		bplist_create(&ds->ds_pending_deadlist);
394cde58dbcSMatthew Ahrens 		dsl_deadlist_open(&ds->ds_deadlist,
395fa9e4066Sahrens 		    mos, ds->ds_phys->ds_deadlist_obj);
396cde58dbcSMatthew Ahrens 
3974e3c9f44SBill Pijewski 		list_create(&ds->ds_sendstreams, sizeof (dmu_sendarg_t),
3984e3c9f44SBill Pijewski 		    offsetof(dmu_sendarg_t, dsa_link));
3994e3c9f44SBill Pijewski 
400ea8dc4b6Seschrock 		if (err == 0) {
401ea8dc4b6Seschrock 			err = dsl_dir_open_obj(dp,
402ea8dc4b6Seschrock 			    ds->ds_phys->ds_dir_obj, NULL, ds, &ds->ds_dir);
403ea8dc4b6Seschrock 		}
404ea8dc4b6Seschrock 		if (err) {
4055ad82045Snd 			mutex_destroy(&ds->ds_lock);
406f4b94bdeSMatthew Ahrens 			mutex_destroy(&ds->ds_recvlock);
40791ebeef5Sahrens 			mutex_destroy(&ds->ds_opening_lock);
408745cd3c5Smaybee 			rw_destroy(&ds->ds_rwlock);
409745cd3c5Smaybee 			cv_destroy(&ds->ds_exclusive_cv);
410cde58dbcSMatthew Ahrens 			bplist_destroy(&ds->ds_pending_deadlist);
411cde58dbcSMatthew Ahrens 			dsl_deadlist_close(&ds->ds_deadlist);
412ea8dc4b6Seschrock 			kmem_free(ds, sizeof (dsl_dataset_t));
413ea8dc4b6Seschrock 			dmu_buf_rele(dbuf, tag);
414ea8dc4b6Seschrock 			return (err);
415ea8dc4b6Seschrock 		}
416fa9e4066Sahrens 
41774e7dc98SMatthew Ahrens 		if (!dsl_dataset_is_snapshot(ds)) {
418fa9e4066Sahrens 			ds->ds_snapname[0] = '\0';
419fa9e4066Sahrens 			if (ds->ds_phys->ds_prev_snap_obj) {
420745cd3c5Smaybee 				err = dsl_dataset_get_ref(dp,
421745cd3c5Smaybee 				    ds->ds_phys->ds_prev_snap_obj,
422745cd3c5Smaybee 				    ds, &ds->ds_prev);
423fa9e4066Sahrens 			}
424842727c2SChris Kirby 		} else {
425842727c2SChris Kirby 			if (zfs_flags & ZFS_DEBUG_SNAPNAMES)
426842727c2SChris Kirby 				err = dsl_dataset_get_snapname(ds);
427842727c2SChris Kirby 			if (err == 0 && ds->ds_phys->ds_userrefs_obj != 0) {
428842727c2SChris Kirby 				err = zap_count(
429842727c2SChris Kirby 				    ds->ds_dir->dd_pool->dp_meta_objset,
430842727c2SChris Kirby 				    ds->ds_phys->ds_userrefs_obj,
431842727c2SChris Kirby 				    &ds->ds_userrefs);
432842727c2SChris Kirby 			}
433fa9e4066Sahrens 		}
434fa9e4066Sahrens 
43574e7dc98SMatthew Ahrens 		if (err == 0 && !dsl_dataset_is_snapshot(ds)) {
43627345066Sck 			/*
43727345066Sck 			 * In sync context, we're called with either no lock
43827345066Sck 			 * or with the write lock.  If we're not syncing,
43927345066Sck 			 * we're always called with the read lock held.
44027345066Sck 			 */
441cb625fb5Sck 			boolean_t need_lock =
44227345066Sck 			    !RW_WRITE_HELD(&dp->dp_config_rwlock) &&
44327345066Sck 			    dsl_pool_sync_context(dp);
444cb625fb5Sck 
445cb625fb5Sck 			if (need_lock)
446cb625fb5Sck 				rw_enter(&dp->dp_config_rwlock, RW_READER);
447cb625fb5Sck 
448bb0ade09Sahrens 			err = dsl_prop_get_ds(ds,
449cb625fb5Sck 			    "refreservation", sizeof (uint64_t), 1,
450cb625fb5Sck 			    &ds->ds_reserved, NULL);
451cb625fb5Sck 			if (err == 0) {
452bb0ade09Sahrens 				err = dsl_prop_get_ds(ds,
453cb625fb5Sck 				    "refquota", sizeof (uint64_t), 1,
454cb625fb5Sck 				    &ds->ds_quota, NULL);
455cb625fb5Sck 			}
456cb625fb5Sck 
457cb625fb5Sck 			if (need_lock)
458cb625fb5Sck 				rw_exit(&dp->dp_config_rwlock);
459cb625fb5Sck 		} else {
460cb625fb5Sck 			ds->ds_reserved = ds->ds_quota = 0;
461cb625fb5Sck 		}
462cb625fb5Sck 
463ea8dc4b6Seschrock 		if (err == 0) {
464ea8dc4b6Seschrock 			winner = dmu_buf_set_user_ie(dbuf, ds, &ds->ds_phys,
465ea8dc4b6Seschrock 			    dsl_dataset_evict);
466ea8dc4b6Seschrock 		}
467ea8dc4b6Seschrock 		if (err || winner) {
468cde58dbcSMatthew Ahrens 			bplist_destroy(&ds->ds_pending_deadlist);
469cde58dbcSMatthew Ahrens 			dsl_deadlist_close(&ds->ds_deadlist);
470745cd3c5Smaybee 			if (ds->ds_prev)
471745cd3c5Smaybee 				dsl_dataset_drop_ref(ds->ds_prev, ds);
472fa9e4066Sahrens 			dsl_dir_close(ds->ds_dir, ds);
4735ad82045Snd 			mutex_destroy(&ds->ds_lock);
474f4b94bdeSMatthew Ahrens 			mutex_destroy(&ds->ds_recvlock);
47591ebeef5Sahrens 			mutex_destroy(&ds->ds_opening_lock);
476745cd3c5Smaybee 			rw_destroy(&ds->ds_rwlock);
477745cd3c5Smaybee 			cv_destroy(&ds->ds_exclusive_cv);
478fa9e4066Sahrens 			kmem_free(ds, sizeof (dsl_dataset_t));
479ea8dc4b6Seschrock 			if (err) {
480ea8dc4b6Seschrock 				dmu_buf_rele(dbuf, tag);
481ea8dc4b6Seschrock 				return (err);
482ea8dc4b6Seschrock 			}
483fa9e4066Sahrens 			ds = winner;
484fa9e4066Sahrens 		} else {
48591ebeef5Sahrens 			ds->ds_fsid_guid =
486fa9e4066Sahrens 			    unique_insert(ds->ds_phys->ds_fsid_guid);
487fa9e4066Sahrens 		}
488fa9e4066Sahrens 	}
489fa9e4066Sahrens 	ASSERT3P(ds->ds_dbuf, ==, dbuf);
490fa9e4066Sahrens 	ASSERT3P(ds->ds_phys, ==, dbuf->db_data);
491088f3894Sahrens 	ASSERT(ds->ds_phys->ds_prev_snap_obj != 0 ||
492afc6333aSahrens 	    spa_version(dp->dp_spa) < SPA_VERSION_ORIGIN ||
49384db2a68Sahrens 	    dp->dp_origin_snap == NULL || ds == dp->dp_origin_snap);
494fa9e4066Sahrens 	mutex_enter(&ds->ds_lock);
495745cd3c5Smaybee 	if (!dsl_pool_sync_context(dp) && DSL_DATASET_IS_DESTROYED(ds)) {
496fa9e4066Sahrens 		mutex_exit(&ds->ds_lock);
497745cd3c5Smaybee 		dmu_buf_rele(ds->ds_dbuf, tag);
498745cd3c5Smaybee 		return (ENOENT);
499fa9e4066Sahrens 	}
500fa9e4066Sahrens 	mutex_exit(&ds->ds_lock);
501ea8dc4b6Seschrock 	*dsp = ds;
502ea8dc4b6Seschrock 	return (0);
503fa9e4066Sahrens }
504fa9e4066Sahrens 
505745cd3c5Smaybee static int
506745cd3c5Smaybee dsl_dataset_hold_ref(dsl_dataset_t *ds, void *tag)
507745cd3c5Smaybee {
508745cd3c5Smaybee 	dsl_pool_t *dp = ds->ds_dir->dd_pool;
509745cd3c5Smaybee 
510745cd3c5Smaybee 	/*
511745cd3c5Smaybee 	 * In syncing context we don't want the rwlock lock: there
512745cd3c5Smaybee 	 * may be an existing writer waiting for sync phase to
513745cd3c5Smaybee 	 * finish.  We don't need to worry about such writers, since
514745cd3c5Smaybee 	 * sync phase is single-threaded, so the writer can't be
515745cd3c5Smaybee 	 * doing anything while we are active.
516745cd3c5Smaybee 	 */
517745cd3c5Smaybee 	if (dsl_pool_sync_context(dp)) {
518745cd3c5Smaybee 		ASSERT(!DSL_DATASET_IS_DESTROYED(ds));
519745cd3c5Smaybee 		return (0);
520745cd3c5Smaybee 	}
521745cd3c5Smaybee 
522745cd3c5Smaybee 	/*
523745cd3c5Smaybee 	 * Normal users will hold the ds_rwlock as a READER until they
524745cd3c5Smaybee 	 * are finished (i.e., call dsl_dataset_rele()).  "Owners" will
525745cd3c5Smaybee 	 * drop their READER lock after they set the ds_owner field.
526745cd3c5Smaybee 	 *
527745cd3c5Smaybee 	 * If the dataset is being destroyed, the destroy thread will
528745cd3c5Smaybee 	 * obtain a WRITER lock for exclusive access after it's done its
529745cd3c5Smaybee 	 * open-context work and then change the ds_owner to
530745cd3c5Smaybee 	 * dsl_reaper once destruction is assured.  So threads
531745cd3c5Smaybee 	 * may block here temporarily, until the "destructability" of
532745cd3c5Smaybee 	 * the dataset is determined.
533745cd3c5Smaybee 	 */
534745cd3c5Smaybee 	ASSERT(!RW_WRITE_HELD(&dp->dp_config_rwlock));
535745cd3c5Smaybee 	mutex_enter(&ds->ds_lock);
536745cd3c5Smaybee 	while (!rw_tryenter(&ds->ds_rwlock, RW_READER)) {
537745cd3c5Smaybee 		rw_exit(&dp->dp_config_rwlock);
538745cd3c5Smaybee 		cv_wait(&ds->ds_exclusive_cv, &ds->ds_lock);
539745cd3c5Smaybee 		if (DSL_DATASET_IS_DESTROYED(ds)) {
540745cd3c5Smaybee 			mutex_exit(&ds->ds_lock);
541745cd3c5Smaybee 			dsl_dataset_drop_ref(ds, tag);
542745cd3c5Smaybee 			rw_enter(&dp->dp_config_rwlock, RW_READER);
543745cd3c5Smaybee 			return (ENOENT);
544745cd3c5Smaybee 		}
545620252bcSChris Kirby 		/*
546620252bcSChris Kirby 		 * The dp_config_rwlock lives above the ds_lock. And
547620252bcSChris Kirby 		 * we need to check DSL_DATASET_IS_DESTROYED() while
548620252bcSChris Kirby 		 * holding the ds_lock, so we have to drop and reacquire
549620252bcSChris Kirby 		 * the ds_lock here.
550620252bcSChris Kirby 		 */
551620252bcSChris Kirby 		mutex_exit(&ds->ds_lock);
552745cd3c5Smaybee 		rw_enter(&dp->dp_config_rwlock, RW_READER);
553620252bcSChris Kirby 		mutex_enter(&ds->ds_lock);
554745cd3c5Smaybee 	}
555745cd3c5Smaybee 	mutex_exit(&ds->ds_lock);
556745cd3c5Smaybee 	return (0);
557745cd3c5Smaybee }
558745cd3c5Smaybee 
559745cd3c5Smaybee int
560745cd3c5Smaybee dsl_dataset_hold_obj(dsl_pool_t *dp, uint64_t dsobj, void *tag,
561745cd3c5Smaybee     dsl_dataset_t **dsp)
562745cd3c5Smaybee {
563745cd3c5Smaybee 	int err = dsl_dataset_get_ref(dp, dsobj, tag, dsp);
564745cd3c5Smaybee 
565745cd3c5Smaybee 	if (err)
566745cd3c5Smaybee 		return (err);
567745cd3c5Smaybee 	return (dsl_dataset_hold_ref(*dsp, tag));
568745cd3c5Smaybee }
569745cd3c5Smaybee 
570745cd3c5Smaybee int
571503ad85cSMatthew Ahrens dsl_dataset_own_obj(dsl_pool_t *dp, uint64_t dsobj, boolean_t inconsistentok,
572503ad85cSMatthew Ahrens     void *tag, dsl_dataset_t **dsp)
573745cd3c5Smaybee {
574503ad85cSMatthew Ahrens 	int err = dsl_dataset_hold_obj(dp, dsobj, tag, dsp);
575745cd3c5Smaybee 	if (err)
576745cd3c5Smaybee 		return (err);
577503ad85cSMatthew Ahrens 	if (!dsl_dataset_tryown(*dsp, inconsistentok, tag)) {
578503ad85cSMatthew Ahrens 		dsl_dataset_rele(*dsp, tag);
5794f5064b7SMark J Musante 		*dsp = NULL;
580745cd3c5Smaybee 		return (EBUSY);
581745cd3c5Smaybee 	}
582745cd3c5Smaybee 	return (0);
583745cd3c5Smaybee }
584745cd3c5Smaybee 
585fa9e4066Sahrens int
586745cd3c5Smaybee dsl_dataset_hold(const char *name, void *tag, dsl_dataset_t **dsp)
587fa9e4066Sahrens {
588fa9e4066Sahrens 	dsl_dir_t *dd;
589fa9e4066Sahrens 	dsl_pool_t *dp;
590745cd3c5Smaybee 	const char *snapname;
591fa9e4066Sahrens 	uint64_t obj;
592fa9e4066Sahrens 	int err = 0;
593fa9e4066Sahrens 
594745cd3c5Smaybee 	err = dsl_dir_open_spa(NULL, name, FTAG, &dd, &snapname);
595ea8dc4b6Seschrock 	if (err)
596ea8dc4b6Seschrock 		return (err);
597fa9e4066Sahrens 
598fa9e4066Sahrens 	dp = dd->dd_pool;
599fa9e4066Sahrens 	obj = dd->dd_phys->dd_head_dataset_obj;
600fa9e4066Sahrens 	rw_enter(&dp->dp_config_rwlock, RW_READER);
601745cd3c5Smaybee 	if (obj)
602745cd3c5Smaybee 		err = dsl_dataset_get_ref(dp, obj, tag, dsp);
603745cd3c5Smaybee 	else
604fa9e4066Sahrens 		err = ENOENT;
605745cd3c5Smaybee 	if (err)
606fa9e4066Sahrens 		goto out;
607fa9e4066Sahrens 
608745cd3c5Smaybee 	err = dsl_dataset_hold_ref(*dsp, tag);
609fa9e4066Sahrens 
610745cd3c5Smaybee 	/* we may be looking for a snapshot */
611745cd3c5Smaybee 	if (err == 0 && snapname != NULL) {
612745cd3c5Smaybee 		dsl_dataset_t *ds = NULL;
613fa9e4066Sahrens 
614745cd3c5Smaybee 		if (*snapname++ != '@') {
615745cd3c5Smaybee 			dsl_dataset_rele(*dsp, tag);
616fa9e4066Sahrens 			err = ENOENT;
617fa9e4066Sahrens 			goto out;
618fa9e4066Sahrens 		}
619fa9e4066Sahrens 
620745cd3c5Smaybee 		dprintf("looking for snapshot '%s'\n", snapname);
621745cd3c5Smaybee 		err = dsl_dataset_snap_lookup(*dsp, snapname, &obj);
622745cd3c5Smaybee 		if (err == 0)
623745cd3c5Smaybee 			err = dsl_dataset_get_ref(dp, obj, tag, &ds);
624745cd3c5Smaybee 		dsl_dataset_rele(*dsp, tag);
625745cd3c5Smaybee 
626745cd3c5Smaybee 		ASSERT3U((err == 0), ==, (ds != NULL));
627745cd3c5Smaybee 
628745cd3c5Smaybee 		if (ds) {
629745cd3c5Smaybee 			mutex_enter(&ds->ds_lock);
630745cd3c5Smaybee 			if (ds->ds_snapname[0] == 0)
631745cd3c5Smaybee 				(void) strlcpy(ds->ds_snapname, snapname,
632745cd3c5Smaybee 				    sizeof (ds->ds_snapname));
633745cd3c5Smaybee 			mutex_exit(&ds->ds_lock);
634745cd3c5Smaybee 			err = dsl_dataset_hold_ref(ds, tag);
635745cd3c5Smaybee 			*dsp = err ? NULL : ds;
636fa9e4066Sahrens 		}
637fa9e4066Sahrens 	}
638fa9e4066Sahrens out:
639fa9e4066Sahrens 	rw_exit(&dp->dp_config_rwlock);
640fa9e4066Sahrens 	dsl_dir_close(dd, FTAG);
641fa9e4066Sahrens 	return (err);
642fa9e4066Sahrens }
643fa9e4066Sahrens 
644fa9e4066Sahrens int
645503ad85cSMatthew Ahrens dsl_dataset_own(const char *name, boolean_t inconsistentok,
646503ad85cSMatthew Ahrens     void *tag, dsl_dataset_t **dsp)
647fa9e4066Sahrens {
648503ad85cSMatthew Ahrens 	int err = dsl_dataset_hold(name, tag, dsp);
649745cd3c5Smaybee 	if (err)
650745cd3c5Smaybee 		return (err);
651503ad85cSMatthew Ahrens 	if (!dsl_dataset_tryown(*dsp, inconsistentok, tag)) {
652503ad85cSMatthew Ahrens 		dsl_dataset_rele(*dsp, tag);
653745cd3c5Smaybee 		return (EBUSY);
654745cd3c5Smaybee 	}
655745cd3c5Smaybee 	return (0);
656fa9e4066Sahrens }
657fa9e4066Sahrens 
658fa9e4066Sahrens void
659fa9e4066Sahrens dsl_dataset_name(dsl_dataset_t *ds, char *name)
660fa9e4066Sahrens {
661fa9e4066Sahrens 	if (ds == NULL) {
662fa9e4066Sahrens 		(void) strcpy(name, "mos");
663fa9e4066Sahrens 	} else {
664fa9e4066Sahrens 		dsl_dir_name(ds->ds_dir, name);
665ea8dc4b6Seschrock 		VERIFY(0 == dsl_dataset_get_snapname(ds));
666fa9e4066Sahrens 		if (ds->ds_snapname[0]) {
667fa9e4066Sahrens 			(void) strcat(name, "@");
668745cd3c5Smaybee 			/*
669745cd3c5Smaybee 			 * We use a "recursive" mutex so that we
670745cd3c5Smaybee 			 * can call dprintf_ds() with ds_lock held.
671745cd3c5Smaybee 			 */
672fa9e4066Sahrens 			if (!MUTEX_HELD(&ds->ds_lock)) {
673fa9e4066Sahrens 				mutex_enter(&ds->ds_lock);
674fa9e4066Sahrens 				(void) strcat(name, ds->ds_snapname);
675fa9e4066Sahrens 				mutex_exit(&ds->ds_lock);
676fa9e4066Sahrens 			} else {
677fa9e4066Sahrens 				(void) strcat(name, ds->ds_snapname);
678fa9e4066Sahrens 			}
679fa9e4066Sahrens 		}
680fa9e4066Sahrens 	}
681fa9e4066Sahrens }
682fa9e4066Sahrens 
683b7661cccSmmusante static int
684b7661cccSmmusante dsl_dataset_namelen(dsl_dataset_t *ds)
685b7661cccSmmusante {
686b7661cccSmmusante 	int result;
687b7661cccSmmusante 
688b7661cccSmmusante 	if (ds == NULL) {
689b7661cccSmmusante 		result = 3;	/* "mos" */
690b7661cccSmmusante 	} else {
691b7661cccSmmusante 		result = dsl_dir_namelen(ds->ds_dir);
692b7661cccSmmusante 		VERIFY(0 == dsl_dataset_get_snapname(ds));
693b7661cccSmmusante 		if (ds->ds_snapname[0]) {
694b7661cccSmmusante 			++result;	/* adding one for the @-sign */
695b7661cccSmmusante 			if (!MUTEX_HELD(&ds->ds_lock)) {
696b7661cccSmmusante 				mutex_enter(&ds->ds_lock);
697b7661cccSmmusante 				result += strlen(ds->ds_snapname);
698b7661cccSmmusante 				mutex_exit(&ds->ds_lock);
699b7661cccSmmusante 			} else {
700b7661cccSmmusante 				result += strlen(ds->ds_snapname);
701b7661cccSmmusante 			}
702b7661cccSmmusante 		}
703b7661cccSmmusante 	}
704b7661cccSmmusante 
705b7661cccSmmusante 	return (result);
706b7661cccSmmusante }
707b7661cccSmmusante 
708088f3894Sahrens void
709745cd3c5Smaybee dsl_dataset_drop_ref(dsl_dataset_t *ds, void *tag)
710fa9e4066Sahrens {
711ea8dc4b6Seschrock 	dmu_buf_rele(ds->ds_dbuf, tag);
712fa9e4066Sahrens }
713fa9e4066Sahrens 
7143cb34c60Sahrens void
715745cd3c5Smaybee dsl_dataset_rele(dsl_dataset_t *ds, void *tag)
7163cb34c60Sahrens {
717745cd3c5Smaybee 	if (!dsl_pool_sync_context(ds->ds_dir->dd_pool)) {
718745cd3c5Smaybee 		rw_exit(&ds->ds_rwlock);
719745cd3c5Smaybee 	}
720745cd3c5Smaybee 	dsl_dataset_drop_ref(ds, tag);
721745cd3c5Smaybee }
722745cd3c5Smaybee 
723745cd3c5Smaybee void
724503ad85cSMatthew Ahrens dsl_dataset_disown(dsl_dataset_t *ds, void *tag)
725745cd3c5Smaybee {
726503ad85cSMatthew Ahrens 	ASSERT((ds->ds_owner == tag && ds->ds_dbuf) ||
727745cd3c5Smaybee 	    (DSL_DATASET_IS_DESTROYED(ds) && ds->ds_dbuf == NULL));
728745cd3c5Smaybee 
7293cb34c60Sahrens 	mutex_enter(&ds->ds_lock);
730745cd3c5Smaybee 	ds->ds_owner = NULL;
731745cd3c5Smaybee 	if (RW_WRITE_HELD(&ds->ds_rwlock)) {
732745cd3c5Smaybee 		rw_exit(&ds->ds_rwlock);
733745cd3c5Smaybee 		cv_broadcast(&ds->ds_exclusive_cv);
734745cd3c5Smaybee 	}
7353cb34c60Sahrens 	mutex_exit(&ds->ds_lock);
736745cd3c5Smaybee 	if (ds->ds_dbuf)
737503ad85cSMatthew Ahrens 		dsl_dataset_drop_ref(ds, tag);
738745cd3c5Smaybee 	else
739cde58dbcSMatthew Ahrens 		dsl_dataset_evict(NULL, ds);
7403cb34c60Sahrens }
7413cb34c60Sahrens 
7423cb34c60Sahrens boolean_t
743503ad85cSMatthew Ahrens dsl_dataset_tryown(dsl_dataset_t *ds, boolean_t inconsistentok, void *tag)
7443cb34c60Sahrens {
745745cd3c5Smaybee 	boolean_t gotit = FALSE;
746745cd3c5Smaybee 
7473cb34c60Sahrens 	mutex_enter(&ds->ds_lock);
748745cd3c5Smaybee 	if (ds->ds_owner == NULL &&
749745cd3c5Smaybee 	    (!DS_IS_INCONSISTENT(ds) || inconsistentok)) {
750503ad85cSMatthew Ahrens 		ds->ds_owner = tag;
751745cd3c5Smaybee 		if (!dsl_pool_sync_context(ds->ds_dir->dd_pool))
752745cd3c5Smaybee 			rw_exit(&ds->ds_rwlock);
753745cd3c5Smaybee 		gotit = TRUE;
7543cb34c60Sahrens 	}
7553cb34c60Sahrens 	mutex_exit(&ds->ds_lock);
756745cd3c5Smaybee 	return (gotit);
757745cd3c5Smaybee }
758745cd3c5Smaybee 
759745cd3c5Smaybee void
760745cd3c5Smaybee dsl_dataset_make_exclusive(dsl_dataset_t *ds, void *owner)
761745cd3c5Smaybee {
762745cd3c5Smaybee 	ASSERT3P(owner, ==, ds->ds_owner);
763745cd3c5Smaybee 	if (!RW_WRITE_HELD(&ds->ds_rwlock))
764745cd3c5Smaybee 		rw_enter(&ds->ds_rwlock, RW_WRITER);
7653cb34c60Sahrens }
7663cb34c60Sahrens 
7671d452cf5Sahrens uint64_t
768088f3894Sahrens dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin,
769ab04eb8eStimh     uint64_t flags, dmu_tx_t *tx)
770fa9e4066Sahrens {
7713cb34c60Sahrens 	dsl_pool_t *dp = dd->dd_pool;
772fa9e4066Sahrens 	dmu_buf_t *dbuf;
773fa9e4066Sahrens 	dsl_dataset_phys_t *dsphys;
7743cb34c60Sahrens 	uint64_t dsobj;
775fa9e4066Sahrens 	objset_t *mos = dp->dp_meta_objset;
776fa9e4066Sahrens 
777088f3894Sahrens 	if (origin == NULL)
778088f3894Sahrens 		origin = dp->dp_origin_snap;
779088f3894Sahrens 
7803cb34c60Sahrens 	ASSERT(origin == NULL || origin->ds_dir->dd_pool == dp);
7813cb34c60Sahrens 	ASSERT(origin == NULL || origin->ds_phys->ds_num_children > 0);
782fa9e4066Sahrens 	ASSERT(dmu_tx_is_syncing(tx));
7833cb34c60Sahrens 	ASSERT(dd->dd_phys->dd_head_dataset_obj == 0);
784fa9e4066Sahrens 
7851649cd4bStabriz 	dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0,
7861649cd4bStabriz 	    DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx);
787ea8dc4b6Seschrock 	VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf));
788fa9e4066Sahrens 	dmu_buf_will_dirty(dbuf, tx);
789fa9e4066Sahrens 	dsphys = dbuf->db_data;
790745cd3c5Smaybee 	bzero(dsphys, sizeof (dsl_dataset_phys_t));
791fa9e4066Sahrens 	dsphys->ds_dir_obj = dd->dd_object;
792ab04eb8eStimh 	dsphys->ds_flags = flags;
793fa9e4066Sahrens 	dsphys->ds_fsid_guid = unique_create();
794fa9e4066Sahrens 	(void) random_get_pseudo_bytes((void*)&dsphys->ds_guid,
795fa9e4066Sahrens 	    sizeof (dsphys->ds_guid));
796fa9e4066Sahrens 	dsphys->ds_snapnames_zapobj =
797ab04eb8eStimh 	    zap_create_norm(mos, U8_TEXTPREP_TOUPPER, DMU_OT_DSL_DS_SNAP_MAP,
798ab04eb8eStimh 	    DMU_OT_NONE, 0, tx);
799fa9e4066Sahrens 	dsphys->ds_creation_time = gethrestime_sec();
800088f3894Sahrens 	dsphys->ds_creation_txg = tx->tx_txg == TXG_INITIAL ? 1 : tx->tx_txg;
801a9799022Sck 
802cde58dbcSMatthew Ahrens 	if (origin == NULL) {
803cde58dbcSMatthew Ahrens 		dsphys->ds_deadlist_obj = dsl_deadlist_alloc(mos, tx);
804cde58dbcSMatthew Ahrens 	} else {
805cde58dbcSMatthew Ahrens 		dsl_dataset_t *ohds;
806cde58dbcSMatthew Ahrens 
8073cb34c60Sahrens 		dsphys->ds_prev_snap_obj = origin->ds_object;
808fa9e4066Sahrens 		dsphys->ds_prev_snap_txg =
8093cb34c60Sahrens 		    origin->ds_phys->ds_creation_txg;
810ad135b5dSChristopher Siden 		dsphys->ds_referenced_bytes =
811ad135b5dSChristopher Siden 		    origin->ds_phys->ds_referenced_bytes;
812fa9e4066Sahrens 		dsphys->ds_compressed_bytes =
8133cb34c60Sahrens 		    origin->ds_phys->ds_compressed_bytes;
814fa9e4066Sahrens 		dsphys->ds_uncompressed_bytes =
8153cb34c60Sahrens 		    origin->ds_phys->ds_uncompressed_bytes;
8163cb34c60Sahrens 		dsphys->ds_bp = origin->ds_phys->ds_bp;
817579ae4d5Stimh 		dsphys->ds_flags |= origin->ds_phys->ds_flags;
818fa9e4066Sahrens 
8193cb34c60Sahrens 		dmu_buf_will_dirty(origin->ds_dbuf, tx);
8203cb34c60Sahrens 		origin->ds_phys->ds_num_children++;
821fa9e4066Sahrens 
822b420f3adSRichard Lowe 		VERIFY3U(0, ==, dsl_dataset_hold_obj(dp,
823cde58dbcSMatthew Ahrens 		    origin->ds_dir->dd_phys->dd_head_dataset_obj, FTAG, &ohds));
824cde58dbcSMatthew Ahrens 		dsphys->ds_deadlist_obj = dsl_deadlist_clone(&ohds->ds_deadlist,
825cde58dbcSMatthew Ahrens 		    dsphys->ds_prev_snap_txg, dsphys->ds_prev_snap_obj, tx);
826cde58dbcSMatthew Ahrens 		dsl_dataset_rele(ohds, FTAG);
827cde58dbcSMatthew Ahrens 
828088f3894Sahrens 		if (spa_version(dp->dp_spa) >= SPA_VERSION_NEXT_CLONES) {
829088f3894Sahrens 			if (origin->ds_phys->ds_next_clones_obj == 0) {
830088f3894Sahrens 				origin->ds_phys->ds_next_clones_obj =
831088f3894Sahrens 				    zap_create(mos,
832088f3894Sahrens 				    DMU_OT_NEXT_CLONES, DMU_OT_NONE, 0, tx);
833088f3894Sahrens 			}
834088f3894Sahrens 			VERIFY(0 == zap_add_int(mos,
835088f3894Sahrens 			    origin->ds_phys->ds_next_clones_obj,
836088f3894Sahrens 			    dsobj, tx));
837088f3894Sahrens 		}
838088f3894Sahrens 
839fa9e4066Sahrens 		dmu_buf_will_dirty(dd->dd_dbuf, tx);
8403cb34c60Sahrens 		dd->dd_phys->dd_origin_obj = origin->ds_object;
841cde58dbcSMatthew Ahrens 		if (spa_version(dp->dp_spa) >= SPA_VERSION_DIR_CLONES) {
842cde58dbcSMatthew Ahrens 			if (origin->ds_dir->dd_phys->dd_clones == 0) {
843cde58dbcSMatthew Ahrens 				dmu_buf_will_dirty(origin->ds_dir->dd_dbuf, tx);
844cde58dbcSMatthew Ahrens 				origin->ds_dir->dd_phys->dd_clones =
845cde58dbcSMatthew Ahrens 				    zap_create(mos,
846cde58dbcSMatthew Ahrens 				    DMU_OT_DSL_CLONES, DMU_OT_NONE, 0, tx);
847cde58dbcSMatthew Ahrens 			}
848b420f3adSRichard Lowe 			VERIFY3U(0, ==, zap_add_int(mos,
849cde58dbcSMatthew Ahrens 			    origin->ds_dir->dd_phys->dd_clones, dsobj, tx));
850cde58dbcSMatthew Ahrens 		}
851fa9e4066Sahrens 	}
852ab04eb8eStimh 
853ab04eb8eStimh 	if (spa_version(dp->dp_spa) >= SPA_VERSION_UNIQUE_ACCURATE)
854ab04eb8eStimh 		dsphys->ds_flags |= DS_FLAG_UNIQUE_ACCURATE;
855ab04eb8eStimh 
856ea8dc4b6Seschrock 	dmu_buf_rele(dbuf, FTAG);
857fa9e4066Sahrens 
858fa9e4066Sahrens 	dmu_buf_will_dirty(dd->dd_dbuf, tx);
859fa9e4066Sahrens 	dd->dd_phys->dd_head_dataset_obj = dsobj;
8603cb34c60Sahrens 
8613cb34c60Sahrens 	return (dsobj);
8623cb34c60Sahrens }
8633cb34c60Sahrens 
8643cb34c60Sahrens uint64_t
865ab04eb8eStimh dsl_dataset_create_sync(dsl_dir_t *pdd, const char *lastname,
866ab04eb8eStimh     dsl_dataset_t *origin, uint64_t flags, cred_t *cr, dmu_tx_t *tx)
8673cb34c60Sahrens {
8683cb34c60Sahrens 	dsl_pool_t *dp = pdd->dd_pool;
8693cb34c60Sahrens 	uint64_t dsobj, ddobj;
8703cb34c60Sahrens 	dsl_dir_t *dd;
8713cb34c60Sahrens 
8723cb34c60Sahrens 	ASSERT(lastname[0] != '@');
8733cb34c60Sahrens 
874088f3894Sahrens 	ddobj = dsl_dir_create_sync(dp, pdd, lastname, tx);
8753cb34c60Sahrens 	VERIFY(0 == dsl_dir_open_obj(dp, ddobj, lastname, FTAG, &dd));
8763cb34c60Sahrens 
877088f3894Sahrens 	dsobj = dsl_dataset_create_sync_dd(dd, origin, flags, tx);
8783cb34c60Sahrens 
8793cb34c60Sahrens 	dsl_deleg_set_create_perms(dd, tx, cr);
8803cb34c60Sahrens 
881fa9e4066Sahrens 	dsl_dir_close(dd, FTAG);
882fa9e4066Sahrens 
883feaa74e4SMark Maybee 	/*
884feaa74e4SMark Maybee 	 * If we are creating a clone, make sure we zero out any stale
885feaa74e4SMark Maybee 	 * data from the origin snapshots zil header.
886feaa74e4SMark Maybee 	 */
887feaa74e4SMark Maybee 	if (origin != NULL) {
888feaa74e4SMark Maybee 		dsl_dataset_t *ds;
889feaa74e4SMark Maybee 		objset_t *os;
890feaa74e4SMark Maybee 
891b420f3adSRichard Lowe 		VERIFY3U(0, ==, dsl_dataset_hold_obj(dp, dsobj, FTAG, &ds));
892b420f3adSRichard Lowe 		VERIFY3U(0, ==, dmu_objset_from_ds(ds, &os));
893feaa74e4SMark Maybee 		bzero(&os->os_zil_header, sizeof (os->os_zil_header));
894feaa74e4SMark Maybee 		dsl_dataset_dirty(ds, tx);
895feaa74e4SMark Maybee 		dsl_dataset_rele(ds, FTAG);
896feaa74e4SMark Maybee 	}
897feaa74e4SMark Maybee 
8981d452cf5Sahrens 	return (dsobj);
899fa9e4066Sahrens }
900fa9e4066Sahrens 
9011d452cf5Sahrens /*
90219b94df9SMatthew Ahrens  * The snapshots must all be in the same pool.
9031d452cf5Sahrens  */
9041d452cf5Sahrens int
9054445fffbSMatthew Ahrens dmu_snapshots_destroy_nvl(nvlist_t *snaps, boolean_t defer,
9064445fffbSMatthew Ahrens     nvlist_t *errlist)
9071d452cf5Sahrens {
9081d452cf5Sahrens 	int err;
9091d452cf5Sahrens 	dsl_sync_task_t *dst;
9101d452cf5Sahrens 	spa_t *spa;
91119b94df9SMatthew Ahrens 	nvpair_t *pair;
91219b94df9SMatthew Ahrens 	dsl_sync_task_group_t *dstg;
913e5351341SMatthew Ahrens 
91419b94df9SMatthew Ahrens 	pair = nvlist_next_nvpair(snaps, NULL);
91519b94df9SMatthew Ahrens 	if (pair == NULL)
91619b94df9SMatthew Ahrens 		return (0);
91719b94df9SMatthew Ahrens 
91819b94df9SMatthew Ahrens 	err = spa_open(nvpair_name(pair), &spa, FTAG);
9191d452cf5Sahrens 	if (err)
9201d452cf5Sahrens 		return (err);
92119b94df9SMatthew Ahrens 	dstg = dsl_sync_task_group_create(spa_get_dsl(spa));
9221d452cf5Sahrens 
92319b94df9SMatthew Ahrens 	for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
92419b94df9SMatthew Ahrens 	    pair = nvlist_next_nvpair(snaps, pair)) {
92519b94df9SMatthew Ahrens 		dsl_dataset_t *ds;
92619b94df9SMatthew Ahrens 
92719b94df9SMatthew Ahrens 		err = dsl_dataset_own(nvpair_name(pair), B_TRUE, dstg, &ds);
92819b94df9SMatthew Ahrens 		if (err == 0) {
92919b94df9SMatthew Ahrens 			struct dsl_ds_destroyarg *dsda;
93019b94df9SMatthew Ahrens 
93119b94df9SMatthew Ahrens 			dsl_dataset_make_exclusive(ds, dstg);
93219b94df9SMatthew Ahrens 			dsda = kmem_zalloc(sizeof (struct dsl_ds_destroyarg),
93319b94df9SMatthew Ahrens 			    KM_SLEEP);
93419b94df9SMatthew Ahrens 			dsda->ds = ds;
93519b94df9SMatthew Ahrens 			dsda->defer = defer;
93619b94df9SMatthew Ahrens 			dsl_sync_task_create(dstg, dsl_dataset_destroy_check,
93719b94df9SMatthew Ahrens 			    dsl_dataset_destroy_sync, dsda, dstg, 0);
93819b94df9SMatthew Ahrens 		} else if (err == ENOENT) {
93919b94df9SMatthew Ahrens 			err = 0;
94019b94df9SMatthew Ahrens 		} else {
9414445fffbSMatthew Ahrens 			fnvlist_add_int32(errlist, nvpair_name(pair), err);
94219b94df9SMatthew Ahrens 			break;
94319b94df9SMatthew Ahrens 		}
94419b94df9SMatthew Ahrens 	}
9451d452cf5Sahrens 
9461d452cf5Sahrens 	if (err == 0)
94719b94df9SMatthew Ahrens 		err = dsl_sync_task_group_wait(dstg);
9481d452cf5Sahrens 
94919b94df9SMatthew Ahrens 	for (dst = list_head(&dstg->dstg_tasks); dst;
95019b94df9SMatthew Ahrens 	    dst = list_next(&dstg->dstg_tasks, dst)) {
951842727c2SChris Kirby 		struct dsl_ds_destroyarg *dsda = dst->dst_arg1;
952842727c2SChris Kirby 		dsl_dataset_t *ds = dsda->ds;
953842727c2SChris Kirby 
954745cd3c5Smaybee 		/*
9554445fffbSMatthew Ahrens 		 * Return the snapshots that triggered the error.
956745cd3c5Smaybee 		 */
9574445fffbSMatthew Ahrens 		if (dst->dst_err != 0) {
9584445fffbSMatthew Ahrens 			char name[ZFS_MAXNAMELEN];
9594445fffbSMatthew Ahrens 			dsl_dataset_name(ds, name);
9604445fffbSMatthew Ahrens 			fnvlist_add_int32(errlist, name, dst->dst_err);
961e1930233Sbonwick 		}
962842727c2SChris Kirby 		ASSERT3P(dsda->rm_origin, ==, NULL);
96319b94df9SMatthew Ahrens 		dsl_dataset_disown(ds, dstg);
964842727c2SChris Kirby 		kmem_free(dsda, sizeof (struct dsl_ds_destroyarg));
965fa9e4066Sahrens 	}
966fa9e4066Sahrens 
96719b94df9SMatthew Ahrens 	dsl_sync_task_group_destroy(dstg);
9681d452cf5Sahrens 	spa_close(spa, FTAG);
969fa9e4066Sahrens 	return (err);
97019b94df9SMatthew Ahrens 
971fa9e4066Sahrens }
972fa9e4066Sahrens 
973842727c2SChris Kirby static boolean_t
974842727c2SChris Kirby dsl_dataset_might_destroy_origin(dsl_dataset_t *ds)
975842727c2SChris Kirby {
976842727c2SChris Kirby 	boolean_t might_destroy = B_FALSE;
977842727c2SChris Kirby 
978842727c2SChris Kirby 	mutex_enter(&ds->ds_lock);
979842727c2SChris Kirby 	if (ds->ds_phys->ds_num_children == 2 && ds->ds_userrefs == 0 &&
980842727c2SChris Kirby 	    DS_IS_DEFER_DESTROY(ds))
981842727c2SChris Kirby 		might_destroy = B_TRUE;
982842727c2SChris Kirby 	mutex_exit(&ds->ds_lock);
983842727c2SChris Kirby 
984842727c2SChris Kirby 	return (might_destroy);
985842727c2SChris Kirby }
986842727c2SChris Kirby 
987842727c2SChris Kirby /*
988842727c2SChris Kirby  * If we're removing a clone, and these three conditions are true:
989842727c2SChris Kirby  *	1) the clone's origin has no other children
990842727c2SChris Kirby  *	2) the clone's origin has no user references
991842727c2SChris Kirby  *	3) the clone's origin has been marked for deferred destruction
992842727c2SChris Kirby  * Then, prepare to remove the origin as part of this sync task group.
993842727c2SChris Kirby  */
994842727c2SChris Kirby static int
995842727c2SChris Kirby dsl_dataset_origin_rm_prep(struct dsl_ds_destroyarg *dsda, void *tag)
996842727c2SChris Kirby {
997842727c2SChris Kirby 	dsl_dataset_t *ds = dsda->ds;
998842727c2SChris Kirby 	dsl_dataset_t *origin = ds->ds_prev;
999842727c2SChris Kirby 
1000842727c2SChris Kirby 	if (dsl_dataset_might_destroy_origin(origin)) {
1001842727c2SChris Kirby 		char *name;
1002842727c2SChris Kirby 		int namelen;
1003842727c2SChris Kirby 		int error;
1004842727c2SChris Kirby 
1005842727c2SChris Kirby 		namelen = dsl_dataset_namelen(origin) + 1;
1006842727c2SChris Kirby 		name = kmem_alloc(namelen, KM_SLEEP);
1007842727c2SChris Kirby 		dsl_dataset_name(origin, name);
1008842727c2SChris Kirby #ifdef _KERNEL
1009842727c2SChris Kirby 		error = zfs_unmount_snap(name, NULL);
1010842727c2SChris Kirby 		if (error) {
1011842727c2SChris Kirby 			kmem_free(name, namelen);
1012842727c2SChris Kirby 			return (error);
1013842727c2SChris Kirby 		}
1014842727c2SChris Kirby #endif
1015503ad85cSMatthew Ahrens 		error = dsl_dataset_own(name, B_TRUE, tag, &origin);
1016842727c2SChris Kirby 		kmem_free(name, namelen);
1017842727c2SChris Kirby 		if (error)
1018842727c2SChris Kirby 			return (error);
1019842727c2SChris Kirby 		dsda->rm_origin = origin;
1020842727c2SChris Kirby 		dsl_dataset_make_exclusive(origin, tag);
1021842727c2SChris Kirby 	}
1022842727c2SChris Kirby 
1023842727c2SChris Kirby 	return (0);
1024842727c2SChris Kirby }
1025842727c2SChris Kirby 
10263cb34c60Sahrens /*
1027745cd3c5Smaybee  * ds must be opened as OWNER.  On return (whether successful or not),
1028745cd3c5Smaybee  * ds will be closed and caller can no longer dereference it.
10293cb34c60Sahrens  */
1030fa9e4066Sahrens int
1031842727c2SChris Kirby dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer)
1032fa9e4066Sahrens {
1033fa9e4066Sahrens 	int err;
10341d452cf5Sahrens 	dsl_sync_task_group_t *dstg;
10351d452cf5Sahrens 	objset_t *os;
1036fa9e4066Sahrens 	dsl_dir_t *dd;
10371d452cf5Sahrens 	uint64_t obj;
103892241e0bSTom Erickson 	struct dsl_ds_destroyarg dsda = { 0 };
1039842727c2SChris Kirby 
1040842727c2SChris Kirby 	dsda.ds = ds;
10411d452cf5Sahrens 
10423cb34c60Sahrens 	if (dsl_dataset_is_snapshot(ds)) {
10431d452cf5Sahrens 		/* Destroying a snapshot is simpler */
1044745cd3c5Smaybee 		dsl_dataset_make_exclusive(ds, tag);
10453baa08fcSek 
1046842727c2SChris Kirby 		dsda.defer = defer;
10471d452cf5Sahrens 		err = dsl_sync_task_do(ds->ds_dir->dd_pool,
10481d452cf5Sahrens 		    dsl_dataset_destroy_check, dsl_dataset_destroy_sync,
1049842727c2SChris Kirby 		    &dsda, tag, 0);
1050842727c2SChris Kirby 		ASSERT3P(dsda.rm_origin, ==, NULL);
10513cb34c60Sahrens 		goto out;
1052922d9a97SChris Kirby 	} else if (defer) {
1053922d9a97SChris Kirby 		err = EINVAL;
1054922d9a97SChris Kirby 		goto out;
10551d452cf5Sahrens 	}
1056fa9e4066Sahrens 
10571d452cf5Sahrens 	dd = ds->ds_dir;
1058fa9e4066Sahrens 
1059ad135b5dSChristopher Siden 	if (!spa_feature_is_enabled(dsl_dataset_get_spa(ds),
1060ad135b5dSChristopher Siden 	    &spa_feature_table[SPA_FEATURE_ASYNC_DESTROY])) {
1061*ce636f8bSMatthew Ahrens 		/*
1062*ce636f8bSMatthew Ahrens 		 * Check for errors and mark this ds as inconsistent, in
1063*ce636f8bSMatthew Ahrens 		 * case we crash while freeing the objects.
1064*ce636f8bSMatthew Ahrens 		 */
1065*ce636f8bSMatthew Ahrens 		err = dsl_sync_task_do(dd->dd_pool,
1066*ce636f8bSMatthew Ahrens 		    dsl_dataset_destroy_begin_check,
1067*ce636f8bSMatthew Ahrens 		    dsl_dataset_destroy_begin_sync, ds, NULL, 0);
1068*ce636f8bSMatthew Ahrens 		if (err)
1069*ce636f8bSMatthew Ahrens 			goto out;
1070*ce636f8bSMatthew Ahrens 
1071*ce636f8bSMatthew Ahrens 		err = dmu_objset_from_ds(ds, &os);
1072*ce636f8bSMatthew Ahrens 		if (err)
1073*ce636f8bSMatthew Ahrens 			goto out;
1074*ce636f8bSMatthew Ahrens 
1075*ce636f8bSMatthew Ahrens 		/*
1076*ce636f8bSMatthew Ahrens 		 * Remove all objects while in the open context so that
1077*ce636f8bSMatthew Ahrens 		 * there is less work to do in the syncing context.
1078*ce636f8bSMatthew Ahrens 		 */
1079ad135b5dSChristopher Siden 		for (obj = 0; err == 0; err = dmu_object_next(os, &obj, FALSE,
1080ad135b5dSChristopher Siden 		    ds->ds_phys->ds_prev_snap_txg)) {
1081ad135b5dSChristopher Siden 			/*
1082ad135b5dSChristopher Siden 			 * Ignore errors, if there is not enough disk space
1083ad135b5dSChristopher Siden 			 * we will deal with it in dsl_dataset_destroy_sync().
1084ad135b5dSChristopher Siden 			 */
1085ad135b5dSChristopher Siden 			(void) dmu_free_object(os, obj);
1086ad135b5dSChristopher Siden 		}
1087ad135b5dSChristopher Siden 		if (err != ESRCH)
1088ad135b5dSChristopher Siden 			goto out;
1089feaa74e4SMark Maybee 
1090*ce636f8bSMatthew Ahrens 		/*
1091*ce636f8bSMatthew Ahrens 		 * Sync out all in-flight IO.
1092*ce636f8bSMatthew Ahrens 		 */
1093*ce636f8bSMatthew Ahrens 		txg_wait_synced(dd->dd_pool, 0);
109414843421SMatthew Ahrens 
1095*ce636f8bSMatthew Ahrens 		/*
1096*ce636f8bSMatthew Ahrens 		 * If we managed to free all the objects in open
1097*ce636f8bSMatthew Ahrens 		 * context, the user space accounting should be zero.
1098*ce636f8bSMatthew Ahrens 		 */
1099*ce636f8bSMatthew Ahrens 		if (ds->ds_phys->ds_bp.blk_fill == 0 &&
1100*ce636f8bSMatthew Ahrens 		    dmu_objset_userused_enabled(os)) {
1101*ce636f8bSMatthew Ahrens 			uint64_t count;
1102*ce636f8bSMatthew Ahrens 
1103*ce636f8bSMatthew Ahrens 			ASSERT(zap_count(os, DMU_USERUSED_OBJECT,
1104*ce636f8bSMatthew Ahrens 			    &count) != 0 || count == 0);
1105*ce636f8bSMatthew Ahrens 			ASSERT(zap_count(os, DMU_GROUPUSED_OBJECT,
1106*ce636f8bSMatthew Ahrens 			    &count) != 0 || count == 0);
1107*ce636f8bSMatthew Ahrens 		}
110814843421SMatthew Ahrens 	}
110914843421SMatthew Ahrens 
111068038c2cSmaybee 	rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER);
111168038c2cSmaybee 	err = dsl_dir_open_obj(dd->dd_pool, dd->dd_object, NULL, FTAG, &dd);
111268038c2cSmaybee 	rw_exit(&dd->dd_pool->dp_config_rwlock);
111368038c2cSmaybee 
111468038c2cSmaybee 	if (err)
111568038c2cSmaybee 		goto out;
111668038c2cSmaybee 
11171d452cf5Sahrens 	/*
11181d452cf5Sahrens 	 * Blow away the dsl_dir + head dataset.
11191d452cf5Sahrens 	 */
1120745cd3c5Smaybee 	dsl_dataset_make_exclusive(ds, tag);
1121842727c2SChris Kirby 	/*
1122842727c2SChris Kirby 	 * If we're removing a clone, we might also need to remove its
1123842727c2SChris Kirby 	 * origin.
1124842727c2SChris Kirby 	 */
1125842727c2SChris Kirby 	do {
1126842727c2SChris Kirby 		dsda.need_prep = B_FALSE;
1127842727c2SChris Kirby 		if (dsl_dir_is_clone(dd)) {
1128842727c2SChris Kirby 			err = dsl_dataset_origin_rm_prep(&dsda, tag);
1129842727c2SChris Kirby 			if (err) {
1130842727c2SChris Kirby 				dsl_dir_close(dd, FTAG);
1131842727c2SChris Kirby 				goto out;
1132842727c2SChris Kirby 			}
1133842727c2SChris Kirby 		}
1134842727c2SChris Kirby 
1135842727c2SChris Kirby 		dstg = dsl_sync_task_group_create(ds->ds_dir->dd_pool);
1136842727c2SChris Kirby 		dsl_sync_task_create(dstg, dsl_dataset_destroy_check,
1137842727c2SChris Kirby 		    dsl_dataset_destroy_sync, &dsda, tag, 0);
1138842727c2SChris Kirby 		dsl_sync_task_create(dstg, dsl_dir_destroy_check,
11394445fffbSMatthew Ahrens 		    dsl_dir_destroy_sync, dd, FTAG, 0);
1140842727c2SChris Kirby 		err = dsl_sync_task_group_wait(dstg);
1141842727c2SChris Kirby 		dsl_sync_task_group_destroy(dstg);
1142842727c2SChris Kirby 
1143842727c2SChris Kirby 		/*
1144842727c2SChris Kirby 		 * We could be racing against 'zfs release' or 'zfs destroy -d'
1145842727c2SChris Kirby 		 * on the origin snap, in which case we can get EBUSY if we
1146842727c2SChris Kirby 		 * needed to destroy the origin snap but were not ready to
1147842727c2SChris Kirby 		 * do so.
1148842727c2SChris Kirby 		 */
1149842727c2SChris Kirby 		if (dsda.need_prep) {
1150842727c2SChris Kirby 			ASSERT(err == EBUSY);
1151842727c2SChris Kirby 			ASSERT(dsl_dir_is_clone(dd));
1152842727c2SChris Kirby 			ASSERT(dsda.rm_origin == NULL);
1153842727c2SChris Kirby 		}
1154842727c2SChris Kirby 	} while (dsda.need_prep);
1155842727c2SChris Kirby 
1156842727c2SChris Kirby 	if (dsda.rm_origin != NULL)
1157842727c2SChris Kirby 		dsl_dataset_disown(dsda.rm_origin, tag);
1158842727c2SChris Kirby 
1159745cd3c5Smaybee 	/* if it is successful, dsl_dir_destroy_sync will close the dd */
11603cb34c60Sahrens 	if (err)
11611d452cf5Sahrens 		dsl_dir_close(dd, FTAG);
11623cb34c60Sahrens out:
1163745cd3c5Smaybee 	dsl_dataset_disown(ds, tag);
1164fa9e4066Sahrens 	return (err);
1165fa9e4066Sahrens }
1166fa9e4066Sahrens 
1167c717a561Smaybee blkptr_t *
1168c717a561Smaybee dsl_dataset_get_blkptr(dsl_dataset_t *ds)
1169fa9e4066Sahrens {
1170c717a561Smaybee 	return (&ds->ds_phys->ds_bp);
1171fa9e4066Sahrens }
1172fa9e4066Sahrens 
1173fa9e4066Sahrens void
1174fa9e4066Sahrens dsl_dataset_set_blkptr(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx)
1175fa9e4066Sahrens {
1176fa9e4066Sahrens 	ASSERT(dmu_tx_is_syncing(tx));
1177fa9e4066Sahrens 	/* If it's the meta-objset, set dp_meta_rootbp */
1178fa9e4066Sahrens 	if (ds == NULL) {
1179fa9e4066Sahrens 		tx->tx_pool->dp_meta_rootbp = *bp;
1180fa9e4066Sahrens 	} else {
1181fa9e4066Sahrens 		dmu_buf_will_dirty(ds->ds_dbuf, tx);
1182fa9e4066Sahrens 		ds->ds_phys->ds_bp = *bp;
1183fa9e4066Sahrens 	}
1184fa9e4066Sahrens }
1185fa9e4066Sahrens 
1186fa9e4066Sahrens spa_t *
1187fa9e4066Sahrens dsl_dataset_get_spa(dsl_dataset_t *ds)
1188fa9e4066Sahrens {
1189fa9e4066Sahrens 	return (ds->ds_dir->dd_pool->dp_spa);
1190fa9e4066Sahrens }
1191fa9e4066Sahrens 
1192fa9e4066Sahrens void
1193fa9e4066Sahrens dsl_dataset_dirty(dsl_dataset_t *ds, dmu_tx_t *tx)
1194fa9e4066Sahrens {
1195fa9e4066Sahrens 	dsl_pool_t *dp;
1196fa9e4066Sahrens 
1197fa9e4066Sahrens 	if (ds == NULL) /* this is the meta-objset */
1198fa9e4066Sahrens 		return;
1199fa9e4066Sahrens 
1200503ad85cSMatthew Ahrens 	ASSERT(ds->ds_objset != NULL);
1201a2eea2e1Sahrens 
1202a2eea2e1Sahrens 	if (ds->ds_phys->ds_next_snap_obj != 0)
1203a2eea2e1Sahrens 		panic("dirtying snapshot!");
1204fa9e4066Sahrens 
1205fa9e4066Sahrens 	dp = ds->ds_dir->dd_pool;
1206fa9e4066Sahrens 
1207fa9e4066Sahrens 	if (txg_list_add(&dp->dp_dirty_datasets, ds, tx->tx_txg) == 0) {
1208fa9e4066Sahrens 		/* up the hold count until we can be written out */
1209fa9e4066Sahrens 		dmu_buf_add_ref(ds->ds_dbuf, ds);
1210fa9e4066Sahrens 	}
1211fa9e4066Sahrens }
1212fa9e4066Sahrens 
1213a9799022Sck /*
1214a9799022Sck  * The unique space in the head dataset can be calculated by subtracting
1215a9799022Sck  * the space used in the most recent snapshot, that is still being used
1216a9799022Sck  * in this file system, from the space currently in use.  To figure out
1217a9799022Sck  * the space in the most recent snapshot still in use, we need to take
1218a9799022Sck  * the total space used in the snapshot and subtract out the space that
1219a9799022Sck  * has been freed up since the snapshot was taken.
1220a9799022Sck  */
1221a9799022Sck static void
1222a9799022Sck dsl_dataset_recalc_head_uniq(dsl_dataset_t *ds)
1223a9799022Sck {
1224a9799022Sck 	uint64_t mrs_used;
1225a9799022Sck 	uint64_t dlused, dlcomp, dluncomp;
1226a9799022Sck 
12273f9d6ad7SLin Ling 	ASSERT(!dsl_dataset_is_snapshot(ds));
1228a9799022Sck 
1229a9799022Sck 	if (ds->ds_phys->ds_prev_snap_obj != 0)
1230ad135b5dSChristopher Siden 		mrs_used = ds->ds_prev->ds_phys->ds_referenced_bytes;
1231a9799022Sck 	else
1232a9799022Sck 		mrs_used = 0;
1233a9799022Sck 
1234cde58dbcSMatthew Ahrens 	dsl_deadlist_space(&ds->ds_deadlist, &dlused, &dlcomp, &dluncomp);
1235a9799022Sck 
1236a9799022Sck 	ASSERT3U(dlused, <=, mrs_used);
1237a9799022Sck 	ds->ds_phys->ds_unique_bytes =
1238ad135b5dSChristopher Siden 	    ds->ds_phys->ds_referenced_bytes - (mrs_used - dlused);
1239a9799022Sck 
12403f9d6ad7SLin Ling 	if (spa_version(ds->ds_dir->dd_pool->dp_spa) >=
1241a9799022Sck 	    SPA_VERSION_UNIQUE_ACCURATE)
1242a9799022Sck 		ds->ds_phys->ds_flags |= DS_FLAG_UNIQUE_ACCURATE;
1243a9799022Sck }
1244a9799022Sck 
1245fa9e4066Sahrens struct killarg {
124674e7dc98SMatthew Ahrens 	dsl_dataset_t *ds;
1247fa9e4066Sahrens 	dmu_tx_t *tx;
1248fa9e4066Sahrens };
1249fa9e4066Sahrens 
125074e7dc98SMatthew Ahrens /* ARGSUSED */
1251fa9e4066Sahrens static int
12523f9d6ad7SLin Ling kill_blkptr(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, arc_buf_t *pbuf,
1253b24ab676SJeff Bonwick     const zbookmark_t *zb, const dnode_phys_t *dnp, void *arg)
1254fa9e4066Sahrens {
1255fa9e4066Sahrens 	struct killarg *ka = arg;
1256b24ab676SJeff Bonwick 	dmu_tx_t *tx = ka->tx;
1257fa9e4066Sahrens 
125888b7b0f2SMatthew Ahrens 	if (bp == NULL)
125988b7b0f2SMatthew Ahrens 		return (0);
1260fa9e4066Sahrens 
1261b24ab676SJeff Bonwick 	if (zb->zb_level == ZB_ZIL_LEVEL) {
1262b24ab676SJeff Bonwick 		ASSERT(zilog != NULL);
1263ab69d62fSMatthew Ahrens 		/*
1264ab69d62fSMatthew Ahrens 		 * It's a block in the intent log.  It has no
1265ab69d62fSMatthew Ahrens 		 * accounting, so just free it.
1266ab69d62fSMatthew Ahrens 		 */
1267b24ab676SJeff Bonwick 		dsl_free(ka->tx->tx_pool, ka->tx->tx_txg, bp);
1268ab69d62fSMatthew Ahrens 	} else {
1269b24ab676SJeff Bonwick 		ASSERT(zilog == NULL);
1270ab69d62fSMatthew Ahrens 		ASSERT3U(bp->blk_birth, >, ka->ds->ds_phys->ds_prev_snap_txg);
1271b24ab676SJeff Bonwick 		(void) dsl_dataset_block_kill(ka->ds, bp, tx, B_FALSE);
1272ab69d62fSMatthew Ahrens 	}
127374e7dc98SMatthew Ahrens 
1274fa9e4066Sahrens 	return (0);
1275fa9e4066Sahrens }
1276fa9e4066Sahrens 
1277e1930233Sbonwick /* ARGSUSED */
1278e1930233Sbonwick static int
12791d452cf5Sahrens dsl_dataset_destroy_begin_check(void *arg1, void *arg2, dmu_tx_t *tx)
1280e1930233Sbonwick {
12811d452cf5Sahrens 	dsl_dataset_t *ds = arg1;
12823cb34c60Sahrens 	objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
12833cb34c60Sahrens 	uint64_t count;
12843cb34c60Sahrens 	int err;
1285e1930233Sbonwick 
1286e1930233Sbonwick 	/*
1287e1930233Sbonwick 	 * Can't delete a head dataset if there are snapshots of it.
1288e1930233Sbonwick 	 * (Except if the only snapshots are from the branch we cloned
1289e1930233Sbonwick 	 * from.)
1290e1930233Sbonwick 	 */
1291e1930233Sbonwick 	if (ds->ds_prev != NULL &&
1292e1930233Sbonwick 	    ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object)
12934aed9999Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		return (EBUSY);
1294e1930233Sbonwick 
12953cb34c60Sahrens 	/*
12963cb34c60Sahrens 	 * This is really a dsl_dir thing, but check it here so that
12973cb34c60Sahrens 	 * we'll be less likely to leave this dataset inconsistent &
12983cb34c60Sahrens 	 * nearly destroyed.
12993cb34c60Sahrens 	 */
13003cb34c60Sahrens 	err = zap_count(mos, ds->ds_dir->dd_phys->dd_child_dir_zapobj, &count);
13013cb34c60Sahrens 	if (err)
13023cb34c60Sahrens 		return (err);
13033cb34c60Sahrens 	if (count != 0)
13043cb34c60Sahrens 		return (EEXIST);
13053cb34c60Sahrens 
1306e1930233Sbonwick 	return (0);
1307e1930233Sbonwick }
1308e1930233Sbonwick 
13091d452cf5Sahrens /* ARGSUSED */
13101d452cf5Sahrens static void
13113f9d6ad7SLin Ling dsl_dataset_destroy_begin_sync(void *arg1, void *arg2, dmu_tx_t *tx)
1312fa9e4066Sahrens {
13131d452cf5Sahrens 	dsl_dataset_t *ds = arg1;
1314fa9e4066Sahrens 
13151d452cf5Sahrens 	/* Mark it as inconsistent on-disk, in case we crash */
13161d452cf5Sahrens 	dmu_buf_will_dirty(ds->ds_dbuf, tx);
13171d452cf5Sahrens 	ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT;
1318ecd6cf80Smarks 
13194445fffbSMatthew Ahrens 	spa_history_log_internal_ds(ds, "destroy begin", tx, "");
13201d452cf5Sahrens }
1321fa9e4066Sahrens 
1322842727c2SChris Kirby static int
1323842727c2SChris Kirby dsl_dataset_origin_check(struct dsl_ds_destroyarg *dsda, void *tag,
1324842727c2SChris Kirby     dmu_tx_t *tx)
1325842727c2SChris Kirby {
1326842727c2SChris Kirby 	dsl_dataset_t *ds = dsda->ds;
1327842727c2SChris Kirby 	dsl_dataset_t *ds_prev = ds->ds_prev;
1328842727c2SChris Kirby 
1329842727c2SChris Kirby 	if (dsl_dataset_might_destroy_origin(ds_prev)) {
1330842727c2SChris Kirby 		struct dsl_ds_destroyarg ndsda = {0};
1331842727c2SChris Kirby 
1332842727c2SChris Kirby 		/*
1333842727c2SChris Kirby 		 * If we're not prepared to remove the origin, don't remove
1334842727c2SChris Kirby 		 * the clone either.
1335842727c2SChris Kirby 		 */
1336842727c2SChris Kirby 		if (dsda->rm_origin == NULL) {
1337842727c2SChris Kirby 			dsda->need_prep = B_TRUE;
1338842727c2SChris Kirby 			return (EBUSY);
1339842727c2SChris Kirby 		}
1340842727c2SChris Kirby 
1341842727c2SChris Kirby 		ndsda.ds = ds_prev;
1342842727c2SChris Kirby 		ndsda.is_origin_rm = B_TRUE;
1343842727c2SChris Kirby 		return (dsl_dataset_destroy_check(&ndsda, tag, tx));
1344842727c2SChris Kirby 	}
1345842727c2SChris Kirby 
1346842727c2SChris Kirby 	/*
1347842727c2SChris Kirby 	 * If we're not going to remove the origin after all,
1348842727c2SChris Kirby 	 * undo the open context setup.
1349842727c2SChris Kirby 	 */
1350842727c2SChris Kirby 	if (dsda->rm_origin != NULL) {
1351842727c2SChris Kirby 		dsl_dataset_disown(dsda->rm_origin, tag);
1352842727c2SChris Kirby 		dsda->rm_origin = NULL;
1353842727c2SChris Kirby 	}
1354842727c2SChris Kirby 
1355842727c2SChris Kirby 	return (0);
1356842727c2SChris Kirby }
1357842727c2SChris Kirby 
135899d5e173STim Haley /*
135999d5e173STim Haley  * If you add new checks here, you may need to add
136099d5e173STim Haley  * additional checks to the "temporary" case in
136199d5e173STim Haley  * snapshot_check() in dmu_objset.c.
136299d5e173STim Haley  */
13631d452cf5Sahrens /* ARGSUSED */
13643cb34c60Sahrens int
13651d452cf5Sahrens dsl_dataset_destroy_check(void *arg1, void *arg2, dmu_tx_t *tx)
13661d452cf5Sahrens {
1367842727c2SChris Kirby 	struct dsl_ds_destroyarg *dsda = arg1;
1368842727c2SChris Kirby 	dsl_dataset_t *ds = dsda->ds;
1369fa9e4066Sahrens 
1370745cd3c5Smaybee 	/* we have an owner hold, so noone else can destroy us */
1371745cd3c5Smaybee 	ASSERT(!DSL_DATASET_IS_DESTROYED(ds));
1372745cd3c5Smaybee 
1373842727c2SChris Kirby 	/*
1374842727c2SChris Kirby 	 * Only allow deferred destroy on pools that support it.
1375842727c2SChris Kirby 	 * NOTE: deferred destroy is only supported on snapshots.
1376842727c2SChris Kirby 	 */
1377842727c2SChris Kirby 	if (dsda->defer) {
1378842727c2SChris Kirby 		if (spa_version(ds->ds_dir->dd_pool->dp_spa) <
1379842727c2SChris Kirby 		    SPA_VERSION_USERREFS)
1380842727c2SChris Kirby 			return (ENOTSUP);
1381842727c2SChris Kirby 		ASSERT(dsl_dataset_is_snapshot(ds));
1382842727c2SChris Kirby 		return (0);
1383842727c2SChris Kirby 	}
1384fa9e4066Sahrens 
1385fa9e4066Sahrens 	/*
1386fa9e4066Sahrens 	 * Can't delete a head dataset if there are snapshots of it.
1387fa9e4066Sahrens 	 * (Except if the only snapshots are from the branch we cloned
1388fa9e4066Sahrens 	 * from.)
1389fa9e4066Sahrens 	 */
1390fa9e4066Sahrens 	if (ds->ds_prev != NULL &&
13911d452cf5Sahrens 	    ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object)
13924aed9999Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		return (EBUSY);
1393fa9e4066Sahrens 
1394fa9e4066Sahrens 	/*
1395fa9e4066Sahrens 	 * If we made changes this txg, traverse_dsl_dataset won't find
1396fa9e4066Sahrens 	 * them.  Try again.
1397fa9e4066Sahrens 	 */
13981d452cf5Sahrens 	if (ds->ds_phys->ds_bp.blk_birth >= tx->tx_txg)
1399fa9e4066Sahrens 		return (EAGAIN);
14001d452cf5Sahrens 
1401842727c2SChris Kirby 	if (dsl_dataset_is_snapshot(ds)) {
1402842727c2SChris Kirby 		/*
1403842727c2SChris Kirby 		 * If this snapshot has an elevated user reference count,
1404842727c2SChris Kirby 		 * we can't destroy it yet.
1405842727c2SChris Kirby 		 */
1406842727c2SChris Kirby 		if (ds->ds_userrefs > 0 && !dsda->releasing)
1407842727c2SChris Kirby 			return (EBUSY);
1408842727c2SChris Kirby 
1409842727c2SChris Kirby 		mutex_enter(&ds->ds_lock);
1410842727c2SChris Kirby 		/*
1411842727c2SChris Kirby 		 * Can't delete a branch point. However, if we're destroying
1412842727c2SChris Kirby 		 * a clone and removing its origin due to it having a user
1413842727c2SChris Kirby 		 * hold count of 0 and having been marked for deferred destroy,
1414842727c2SChris Kirby 		 * it's OK for the origin to have a single clone.
1415842727c2SChris Kirby 		 */
1416842727c2SChris Kirby 		if (ds->ds_phys->ds_num_children >
1417842727c2SChris Kirby 		    (dsda->is_origin_rm ? 2 : 1)) {
1418842727c2SChris Kirby 			mutex_exit(&ds->ds_lock);
1419842727c2SChris Kirby 			return (EEXIST);
1420842727c2SChris Kirby 		}
1421842727c2SChris Kirby 		mutex_exit(&ds->ds_lock);
1422842727c2SChris Kirby 	} else if (dsl_dir_is_clone(ds->ds_dir)) {
1423842727c2SChris Kirby 		return (dsl_dataset_origin_check(dsda, arg2, tx));
1424842727c2SChris Kirby 	}
1425842727c2SChris Kirby 
14261d452cf5Sahrens 	/* XXX we should do some i/o error checking... */
14271d452cf5Sahrens 	return (0);
14281d452cf5Sahrens }
14291d452cf5Sahrens 
1430745cd3c5Smaybee struct refsarg {
1431745cd3c5Smaybee 	kmutex_t lock;
1432745cd3c5Smaybee 	boolean_t gone;
1433745cd3c5Smaybee 	kcondvar_t cv;
1434745cd3c5Smaybee };
1435745cd3c5Smaybee 
1436745cd3c5Smaybee /* ARGSUSED */
1437745cd3c5Smaybee static void
1438745cd3c5Smaybee dsl_dataset_refs_gone(dmu_buf_t *db, void *argv)
1439745cd3c5Smaybee {
1440745cd3c5Smaybee 	struct refsarg *arg = argv;
1441745cd3c5Smaybee 
1442745cd3c5Smaybee 	mutex_enter(&arg->lock);
1443745cd3c5Smaybee 	arg->gone = TRUE;
1444745cd3c5Smaybee 	cv_signal(&arg->cv);
1445745cd3c5Smaybee 	mutex_exit(&arg->lock);
1446745cd3c5Smaybee }
1447745cd3c5Smaybee 
1448745cd3c5Smaybee static void
1449745cd3c5Smaybee dsl_dataset_drain_refs(dsl_dataset_t *ds, void *tag)
1450745cd3c5Smaybee {
1451745cd3c5Smaybee 	struct refsarg arg;
1452745cd3c5Smaybee 
1453745cd3c5Smaybee 	mutex_init(&arg.lock, NULL, MUTEX_DEFAULT, NULL);
1454745cd3c5Smaybee 	cv_init(&arg.cv, NULL, CV_DEFAULT, NULL);
1455745cd3c5Smaybee 	arg.gone = FALSE;
1456745cd3c5Smaybee 	(void) dmu_buf_update_user(ds->ds_dbuf, ds, &arg, &ds->ds_phys,
1457745cd3c5Smaybee 	    dsl_dataset_refs_gone);
1458745cd3c5Smaybee 	dmu_buf_rele(ds->ds_dbuf, tag);
1459745cd3c5Smaybee 	mutex_enter(&arg.lock);
1460745cd3c5Smaybee 	while (!arg.gone)
1461745cd3c5Smaybee 		cv_wait(&arg.cv, &arg.lock);
1462745cd3c5Smaybee 	ASSERT(arg.gone);
1463745cd3c5Smaybee 	mutex_exit(&arg.lock);
1464745cd3c5Smaybee 	ds->ds_dbuf = NULL;
1465745cd3c5Smaybee 	ds->ds_phys = NULL;
1466745cd3c5Smaybee 	mutex_destroy(&arg.lock);
1467745cd3c5Smaybee 	cv_destroy(&arg.cv);
1468745cd3c5Smaybee }
1469745cd3c5Smaybee 
1470c33e334fSMatthew Ahrens static void
1471c33e334fSMatthew Ahrens remove_from_next_clones(dsl_dataset_t *ds, uint64_t obj, dmu_tx_t *tx)
1472c33e334fSMatthew Ahrens {
1473c33e334fSMatthew Ahrens 	objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
1474c33e334fSMatthew Ahrens 	uint64_t count;
1475c33e334fSMatthew Ahrens 	int err;
1476c33e334fSMatthew Ahrens 
1477c33e334fSMatthew Ahrens 	ASSERT(ds->ds_phys->ds_num_children >= 2);
1478c33e334fSMatthew Ahrens 	err = zap_remove_int(mos, ds->ds_phys->ds_next_clones_obj, obj, tx);
1479c33e334fSMatthew Ahrens 	/*
1480c33e334fSMatthew Ahrens 	 * The err should not be ENOENT, but a bug in a previous version
1481c33e334fSMatthew Ahrens 	 * of the code could cause upgrade_clones_cb() to not set
1482c33e334fSMatthew Ahrens 	 * ds_next_snap_obj when it should, leading to a missing entry.
1483c33e334fSMatthew Ahrens 	 * If we knew that the pool was created after
1484c33e334fSMatthew Ahrens 	 * SPA_VERSION_NEXT_CLONES, we could assert that it isn't
1485c33e334fSMatthew Ahrens 	 * ENOENT.  However, at least we can check that we don't have
1486c33e334fSMatthew Ahrens 	 * too many entries in the next_clones_obj even after failing to
1487c33e334fSMatthew Ahrens 	 * remove this one.
1488c33e334fSMatthew Ahrens 	 */
1489c33e334fSMatthew Ahrens 	if (err != ENOENT) {
1490b420f3adSRichard Lowe 		VERIFY3U(err, ==, 0);
1491c33e334fSMatthew Ahrens 	}
1492b420f3adSRichard Lowe 	ASSERT3U(0, ==, zap_count(mos, ds->ds_phys->ds_next_clones_obj,
1493b420f3adSRichard Lowe 	    &count));
1494c33e334fSMatthew Ahrens 	ASSERT3U(count, <=, ds->ds_phys->ds_num_children - 2);
1495c33e334fSMatthew Ahrens }
1496c33e334fSMatthew Ahrens 
1497cde58dbcSMatthew Ahrens static void
1498cde58dbcSMatthew Ahrens dsl_dataset_remove_clones_key(dsl_dataset_t *ds, uint64_t mintxg, dmu_tx_t *tx)
1499cde58dbcSMatthew Ahrens {
1500cde58dbcSMatthew Ahrens 	objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
1501cde58dbcSMatthew Ahrens 	zap_cursor_t zc;
1502cde58dbcSMatthew Ahrens 	zap_attribute_t za;
1503cde58dbcSMatthew Ahrens 
1504cde58dbcSMatthew Ahrens 	/*
1505cde58dbcSMatthew Ahrens 	 * If it is the old version, dd_clones doesn't exist so we can't
1506cde58dbcSMatthew Ahrens 	 * find the clones, but deadlist_remove_key() is a no-op so it
1507cde58dbcSMatthew Ahrens 	 * doesn't matter.
1508cde58dbcSMatthew Ahrens 	 */
1509cde58dbcSMatthew Ahrens 	if (ds->ds_dir->dd_phys->dd_clones == 0)
1510cde58dbcSMatthew Ahrens 		return;
1511cde58dbcSMatthew Ahrens 
1512cde58dbcSMatthew Ahrens 	for (zap_cursor_init(&zc, mos, ds->ds_dir->dd_phys->dd_clones);
1513cde58dbcSMatthew Ahrens 	    zap_cursor_retrieve(&zc, &za) == 0;
1514cde58dbcSMatthew Ahrens 	    zap_cursor_advance(&zc)) {
1515cde58dbcSMatthew Ahrens 		dsl_dataset_t *clone;
1516cde58dbcSMatthew Ahrens 
1517b420f3adSRichard Lowe 		VERIFY3U(0, ==, dsl_dataset_hold_obj(ds->ds_dir->dd_pool,
1518cde58dbcSMatthew Ahrens 		    za.za_first_integer, FTAG, &clone));
1519cde58dbcSMatthew Ahrens 		if (clone->ds_dir->dd_origin_txg > mintxg) {
1520cde58dbcSMatthew Ahrens 			dsl_deadlist_remove_key(&clone->ds_deadlist,
1521cde58dbcSMatthew Ahrens 			    mintxg, tx);
1522cde58dbcSMatthew Ahrens 			dsl_dataset_remove_clones_key(clone, mintxg, tx);
1523cde58dbcSMatthew Ahrens 		}
1524cde58dbcSMatthew Ahrens 		dsl_dataset_rele(clone, FTAG);
1525cde58dbcSMatthew Ahrens 	}
1526cde58dbcSMatthew Ahrens 	zap_cursor_fini(&zc);
1527cde58dbcSMatthew Ahrens }
1528cde58dbcSMatthew Ahrens 
1529cde58dbcSMatthew Ahrens struct process_old_arg {
1530cde58dbcSMatthew Ahrens 	dsl_dataset_t *ds;
1531cde58dbcSMatthew Ahrens 	dsl_dataset_t *ds_prev;
1532cde58dbcSMatthew Ahrens 	boolean_t after_branch_point;
1533cde58dbcSMatthew Ahrens 	zio_t *pio;
1534cde58dbcSMatthew Ahrens 	uint64_t used, comp, uncomp;
1535cde58dbcSMatthew Ahrens };
1536cde58dbcSMatthew Ahrens 
1537cde58dbcSMatthew Ahrens static int
1538cde58dbcSMatthew Ahrens process_old_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx)
1539cde58dbcSMatthew Ahrens {
1540cde58dbcSMatthew Ahrens 	struct process_old_arg *poa = arg;
1541cde58dbcSMatthew Ahrens 	dsl_pool_t *dp = poa->ds->ds_dir->dd_pool;
1542cde58dbcSMatthew Ahrens 
1543cde58dbcSMatthew Ahrens 	if (bp->blk_birth <= poa->ds->ds_phys->ds_prev_snap_txg) {
1544cde58dbcSMatthew Ahrens 		dsl_deadlist_insert(&poa->ds->ds_deadlist, bp, tx);
1545cde58dbcSMatthew Ahrens 		if (poa->ds_prev && !poa->after_branch_point &&
1546cde58dbcSMatthew Ahrens 		    bp->blk_birth >
1547cde58dbcSMatthew Ahrens 		    poa->ds_prev->ds_phys->ds_prev_snap_txg) {
1548cde58dbcSMatthew Ahrens 			poa->ds_prev->ds_phys->ds_unique_bytes +=
1549cde58dbcSMatthew Ahrens 			    bp_get_dsize_sync(dp->dp_spa, bp);
1550cde58dbcSMatthew Ahrens 		}
1551cde58dbcSMatthew Ahrens 	} else {
1552cde58dbcSMatthew Ahrens 		poa->used += bp_get_dsize_sync(dp->dp_spa, bp);
1553cde58dbcSMatthew Ahrens 		poa->comp += BP_GET_PSIZE(bp);
1554cde58dbcSMatthew Ahrens 		poa->uncomp += BP_GET_UCSIZE(bp);
1555cde58dbcSMatthew Ahrens 		dsl_free_sync(poa->pio, dp, tx->tx_txg, bp);
1556cde58dbcSMatthew Ahrens 	}
1557cde58dbcSMatthew Ahrens 	return (0);
1558cde58dbcSMatthew Ahrens }
1559cde58dbcSMatthew Ahrens 
1560cde58dbcSMatthew Ahrens static void
1561cde58dbcSMatthew Ahrens process_old_deadlist(dsl_dataset_t *ds, dsl_dataset_t *ds_prev,
1562cde58dbcSMatthew Ahrens     dsl_dataset_t *ds_next, boolean_t after_branch_point, dmu_tx_t *tx)
1563cde58dbcSMatthew Ahrens {
1564cde58dbcSMatthew Ahrens 	struct process_old_arg poa = { 0 };
1565cde58dbcSMatthew Ahrens 	dsl_pool_t *dp = ds->ds_dir->dd_pool;
1566cde58dbcSMatthew Ahrens 	objset_t *mos = dp->dp_meta_objset;
1567cde58dbcSMatthew Ahrens 
1568cde58dbcSMatthew Ahrens 	ASSERT(ds->ds_deadlist.dl_oldfmt);
1569cde58dbcSMatthew Ahrens 	ASSERT(ds_next->ds_deadlist.dl_oldfmt);
1570cde58dbcSMatthew Ahrens 
1571cde58dbcSMatthew Ahrens 	poa.ds = ds;
1572cde58dbcSMatthew Ahrens 	poa.ds_prev = ds_prev;
1573cde58dbcSMatthew Ahrens 	poa.after_branch_point = after_branch_point;
1574cde58dbcSMatthew Ahrens 	poa.pio = zio_root(dp->dp_spa, NULL, NULL, ZIO_FLAG_MUSTSUCCEED);
1575b420f3adSRichard Lowe 	VERIFY3U(0, ==, bpobj_iterate(&ds_next->ds_deadlist.dl_bpobj,
1576cde58dbcSMatthew Ahrens 	    process_old_cb, &poa, tx));
1577b420f3adSRichard Lowe 	VERIFY3U(zio_wait(poa.pio), ==, 0);
1578cde58dbcSMatthew Ahrens 	ASSERT3U(poa.used, ==, ds->ds_phys->ds_unique_bytes);
1579cde58dbcSMatthew Ahrens 
1580cde58dbcSMatthew Ahrens 	/* change snapused */
1581cde58dbcSMatthew Ahrens 	dsl_dir_diduse_space(ds->ds_dir, DD_USED_SNAP,
1582cde58dbcSMatthew Ahrens 	    -poa.used, -poa.comp, -poa.uncomp, tx);
1583cde58dbcSMatthew Ahrens 
1584cde58dbcSMatthew Ahrens 	/* swap next's deadlist to our deadlist */
1585cde58dbcSMatthew Ahrens 	dsl_deadlist_close(&ds->ds_deadlist);
1586cde58dbcSMatthew Ahrens 	dsl_deadlist_close(&ds_next->ds_deadlist);
1587cde58dbcSMatthew Ahrens 	SWITCH64(ds_next->ds_phys->ds_deadlist_obj,
1588cde58dbcSMatthew Ahrens 	    ds->ds_phys->ds_deadlist_obj);
1589cde58dbcSMatthew Ahrens 	dsl_deadlist_open(&ds->ds_deadlist, mos, ds->ds_phys->ds_deadlist_obj);
1590cde58dbcSMatthew Ahrens 	dsl_deadlist_open(&ds_next->ds_deadlist, mos,
1591cde58dbcSMatthew Ahrens 	    ds_next->ds_phys->ds_deadlist_obj);
1592cde58dbcSMatthew Ahrens }
1593cde58dbcSMatthew Ahrens 
1594ad135b5dSChristopher Siden static int
1595ad135b5dSChristopher Siden old_synchronous_dataset_destroy(dsl_dataset_t *ds, dmu_tx_t *tx)
1596ad135b5dSChristopher Siden {
1597ad135b5dSChristopher Siden 	int err;
1598ad135b5dSChristopher Siden 	struct killarg ka;
1599ad135b5dSChristopher Siden 
1600ad135b5dSChristopher Siden 	/*
1601ad135b5dSChristopher Siden 	 * Free everything that we point to (that's born after
1602ad135b5dSChristopher Siden 	 * the previous snapshot, if we are a clone)
1603ad135b5dSChristopher Siden 	 *
1604ad135b5dSChristopher Siden 	 * NB: this should be very quick, because we already
1605ad135b5dSChristopher Siden 	 * freed all the objects in open context.
1606ad135b5dSChristopher Siden 	 */
1607ad135b5dSChristopher Siden 	ka.ds = ds;
1608ad135b5dSChristopher Siden 	ka.tx = tx;
1609ad135b5dSChristopher Siden 	err = traverse_dataset(ds,
1610ad135b5dSChristopher Siden 	    ds->ds_phys->ds_prev_snap_txg, TRAVERSE_POST,
1611ad135b5dSChristopher Siden 	    kill_blkptr, &ka);
1612b420f3adSRichard Lowe 	ASSERT3U(err, ==, 0);
1613ad135b5dSChristopher Siden 	ASSERT(!DS_UNIQUE_IS_ACCURATE(ds) || ds->ds_phys->ds_unique_bytes == 0);
1614ad135b5dSChristopher Siden 
1615ad135b5dSChristopher Siden 	return (err);
1616ad135b5dSChristopher Siden }
1617ad135b5dSChristopher Siden 
16183cb34c60Sahrens void
16193f9d6ad7SLin Ling dsl_dataset_destroy_sync(void *arg1, void *tag, dmu_tx_t *tx)
16201d452cf5Sahrens {
1621842727c2SChris Kirby 	struct dsl_ds_destroyarg *dsda = arg1;
1622842727c2SChris Kirby 	dsl_dataset_t *ds = dsda->ds;
16231d452cf5Sahrens 	int err;
16241d452cf5Sahrens 	int after_branch_point = FALSE;
16251d452cf5Sahrens 	dsl_pool_t *dp = ds->ds_dir->dd_pool;
16261d452cf5Sahrens 	objset_t *mos = dp->dp_meta_objset;
16271d452cf5Sahrens 	dsl_dataset_t *ds_prev = NULL;
162899d5e173STim Haley 	boolean_t wont_destroy;
16291d452cf5Sahrens 	uint64_t obj;
16301d452cf5Sahrens 
163199d5e173STim Haley 	wont_destroy = (dsda->defer &&
163299d5e173STim Haley 	    (ds->ds_userrefs > 0 || ds->ds_phys->ds_num_children > 1));
163399d5e173STim Haley 
163499d5e173STim Haley 	ASSERT(ds->ds_owner || wont_destroy);
1635842727c2SChris Kirby 	ASSERT(dsda->defer || ds->ds_phys->ds_num_children <= 1);
16361d452cf5Sahrens 	ASSERT(ds->ds_prev == NULL ||
16371d452cf5Sahrens 	    ds->ds_prev->ds_phys->ds_next_snap_obj != ds->ds_object);
16381d452cf5Sahrens 	ASSERT3U(ds->ds_phys->ds_bp.blk_birth, <=, tx->tx_txg);
16391d452cf5Sahrens 
164099d5e173STim Haley 	if (wont_destroy) {
1641842727c2SChris Kirby 		ASSERT(spa_version(dp->dp_spa) >= SPA_VERSION_USERREFS);
164299d5e173STim Haley 		dmu_buf_will_dirty(ds->ds_dbuf, tx);
164399d5e173STim Haley 		ds->ds_phys->ds_flags |= DS_FLAG_DEFER_DESTROY;
16444445fffbSMatthew Ahrens 		spa_history_log_internal_ds(ds, "defer_destroy", tx, "");
164599d5e173STim Haley 		return;
1646842727c2SChris Kirby 	}
1647842727c2SChris Kirby 
16484445fffbSMatthew Ahrens 	/* We need to log before removing it from the namespace. */
16494445fffbSMatthew Ahrens 	spa_history_log_internal_ds(ds, "destroy", tx, "");
16504445fffbSMatthew Ahrens 
1651745cd3c5Smaybee 	/* signal any waiters that this dataset is going away */
1652745cd3c5Smaybee 	mutex_enter(&ds->ds_lock);
1653745cd3c5Smaybee 	ds->ds_owner = dsl_reaper;
1654745cd3c5Smaybee 	cv_broadcast(&ds->ds_exclusive_cv);
1655745cd3c5Smaybee 	mutex_exit(&ds->ds_lock);
1656745cd3c5Smaybee 
1657a9799022Sck 	/* Remove our reservation */
1658a9799022Sck 	if (ds->ds_reserved != 0) {
165992241e0bSTom Erickson 		dsl_prop_setarg_t psa;
166092241e0bSTom Erickson 		uint64_t value = 0;
166192241e0bSTom Erickson 
166292241e0bSTom Erickson 		dsl_prop_setarg_init_uint64(&psa, "refreservation",
166392241e0bSTom Erickson 		    (ZPROP_SRC_NONE | ZPROP_SRC_LOCAL | ZPROP_SRC_RECEIVED),
166492241e0bSTom Erickson 		    &value);
166592241e0bSTom Erickson 		psa.psa_effective_value = 0;	/* predict default value */
166692241e0bSTom Erickson 
16673f9d6ad7SLin Ling 		dsl_dataset_set_reservation_sync(ds, &psa, tx);
1668b420f3adSRichard Lowe 		ASSERT3U(ds->ds_reserved, ==, 0);
1669a9799022Sck 	}
1670a9799022Sck 
16711d452cf5Sahrens 	ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock));
16721d452cf5Sahrens 
16733f9d6ad7SLin Ling 	dsl_scan_ds_destroyed(ds, tx);
1674088f3894Sahrens 
16751d452cf5Sahrens 	obj = ds->ds_object;
1676fa9e4066Sahrens 
1677fa9e4066Sahrens 	if (ds->ds_phys->ds_prev_snap_obj != 0) {
1678fa9e4066Sahrens 		if (ds->ds_prev) {
1679fa9e4066Sahrens 			ds_prev = ds->ds_prev;
1680fa9e4066Sahrens 		} else {
1681745cd3c5Smaybee 			VERIFY(0 == dsl_dataset_hold_obj(dp,
1682745cd3c5Smaybee 			    ds->ds_phys->ds_prev_snap_obj, FTAG, &ds_prev));
1683fa9e4066Sahrens 		}
1684fa9e4066Sahrens 		after_branch_point =
1685fa9e4066Sahrens 		    (ds_prev->ds_phys->ds_next_snap_obj != obj);
1686fa9e4066Sahrens 
1687fa9e4066Sahrens 		dmu_buf_will_dirty(ds_prev->ds_dbuf, tx);
1688088f3894Sahrens 		if (after_branch_point &&
1689088f3894Sahrens 		    ds_prev->ds_phys->ds_next_clones_obj != 0) {
1690c33e334fSMatthew Ahrens 			remove_from_next_clones(ds_prev, obj, tx);
1691088f3894Sahrens 			if (ds->ds_phys->ds_next_snap_obj != 0) {
1692088f3894Sahrens 				VERIFY(0 == zap_add_int(mos,
1693088f3894Sahrens 				    ds_prev->ds_phys->ds_next_clones_obj,
1694088f3894Sahrens 				    ds->ds_phys->ds_next_snap_obj, tx));
1695088f3894Sahrens 			}
1696088f3894Sahrens 		}
1697fa9e4066Sahrens 		if (after_branch_point &&
1698fa9e4066Sahrens 		    ds->ds_phys->ds_next_snap_obj == 0) {
1699fa9e4066Sahrens 			/* This clone is toast. */
1700fa9e4066Sahrens 			ASSERT(ds_prev->ds_phys->ds_num_children > 1);
1701fa9e4066Sahrens 			ds_prev->ds_phys->ds_num_children--;
1702842727c2SChris Kirby 
1703842727c2SChris Kirby 			/*
1704842727c2SChris Kirby 			 * If the clone's origin has no other clones, no
1705842727c2SChris Kirby 			 * user holds, and has been marked for deferred
1706842727c2SChris Kirby 			 * deletion, then we should have done the necessary
1707842727c2SChris Kirby 			 * destroy setup for it.
1708842727c2SChris Kirby 			 */
1709842727c2SChris Kirby 			if (ds_prev->ds_phys->ds_num_children == 1 &&
1710842727c2SChris Kirby 			    ds_prev->ds_userrefs == 0 &&
1711842727c2SChris Kirby 			    DS_IS_DEFER_DESTROY(ds_prev)) {
1712842727c2SChris Kirby 				ASSERT3P(dsda->rm_origin, !=, NULL);
1713842727c2SChris Kirby 			} else {
1714842727c2SChris Kirby 				ASSERT3P(dsda->rm_origin, ==, NULL);
1715842727c2SChris Kirby 			}
1716fa9e4066Sahrens 		} else if (!after_branch_point) {
1717fa9e4066Sahrens 			ds_prev->ds_phys->ds_next_snap_obj =
1718fa9e4066Sahrens 			    ds->ds_phys->ds_next_snap_obj;
1719fa9e4066Sahrens 		}
1720fa9e4066Sahrens 	}
1721fa9e4066Sahrens 
17223f9d6ad7SLin Ling 	if (dsl_dataset_is_snapshot(ds)) {
1723fa9e4066Sahrens 		dsl_dataset_t *ds_next;
1724a9799022Sck 		uint64_t old_unique;
1725cde58dbcSMatthew Ahrens 		uint64_t used = 0, comp = 0, uncomp = 0;
1726fa9e4066Sahrens 
1727745cd3c5Smaybee 		VERIFY(0 == dsl_dataset_hold_obj(dp,
1728745cd3c5Smaybee 		    ds->ds_phys->ds_next_snap_obj, FTAG, &ds_next));
1729fa9e4066Sahrens 		ASSERT3U(ds_next->ds_phys->ds_prev_snap_obj, ==, obj);
1730fa9e4066Sahrens 
17313f9d6ad7SLin Ling 		old_unique = ds_next->ds_phys->ds_unique_bytes;
1732a9799022Sck 
1733fa9e4066Sahrens 		dmu_buf_will_dirty(ds_next->ds_dbuf, tx);
1734fa9e4066Sahrens 		ds_next->ds_phys->ds_prev_snap_obj =
1735fa9e4066Sahrens 		    ds->ds_phys->ds_prev_snap_obj;
1736fa9e4066Sahrens 		ds_next->ds_phys->ds_prev_snap_txg =
1737fa9e4066Sahrens 		    ds->ds_phys->ds_prev_snap_txg;
1738fa9e4066Sahrens 		ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==,
1739fa9e4066Sahrens 		    ds_prev ? ds_prev->ds_phys->ds_creation_txg : 0);
1740fa9e4066Sahrens 
17413113f7ceSGeorge Wilson 
1742cde58dbcSMatthew Ahrens 		if (ds_next->ds_deadlist.dl_oldfmt) {
1743cde58dbcSMatthew Ahrens 			process_old_deadlist(ds, ds_prev, ds_next,
1744cde58dbcSMatthew Ahrens 			    after_branch_point, tx);
1745cde58dbcSMatthew Ahrens 		} else {
1746cde58dbcSMatthew Ahrens 			/* Adjust prev's unique space. */
1747cde58dbcSMatthew Ahrens 			if (ds_prev && !after_branch_point) {
1748cde58dbcSMatthew Ahrens 				dsl_deadlist_space_range(&ds_next->ds_deadlist,
1749cde58dbcSMatthew Ahrens 				    ds_prev->ds_phys->ds_prev_snap_txg,
1750cde58dbcSMatthew Ahrens 				    ds->ds_phys->ds_prev_snap_txg,
1751cde58dbcSMatthew Ahrens 				    &used, &comp, &uncomp);
1752cde58dbcSMatthew Ahrens 				ds_prev->ds_phys->ds_unique_bytes += used;
1753fa9e4066Sahrens 			}
175474e7dc98SMatthew Ahrens 
1755cde58dbcSMatthew Ahrens 			/* Adjust snapused. */
1756cde58dbcSMatthew Ahrens 			dsl_deadlist_space_range(&ds_next->ds_deadlist,
1757cde58dbcSMatthew Ahrens 			    ds->ds_phys->ds_prev_snap_txg, UINT64_MAX,
1758cde58dbcSMatthew Ahrens 			    &used, &comp, &uncomp);
1759cde58dbcSMatthew Ahrens 			dsl_dir_diduse_space(ds->ds_dir, DD_USED_SNAP,
1760cde58dbcSMatthew Ahrens 			    -used, -comp, -uncomp, tx);
1761cde58dbcSMatthew Ahrens 
1762cde58dbcSMatthew Ahrens 			/* Move blocks to be freed to pool's free list. */
1763cde58dbcSMatthew Ahrens 			dsl_deadlist_move_bpobj(&ds_next->ds_deadlist,
1764cde58dbcSMatthew Ahrens 			    &dp->dp_free_bpobj, ds->ds_phys->ds_prev_snap_txg,
1765cde58dbcSMatthew Ahrens 			    tx);
1766cde58dbcSMatthew Ahrens 			dsl_dir_diduse_space(tx->tx_pool->dp_free_dir,
1767cde58dbcSMatthew Ahrens 			    DD_USED_HEAD, used, comp, uncomp, tx);
1768cde58dbcSMatthew Ahrens 
1769cde58dbcSMatthew Ahrens 			/* Merge our deadlist into next's and free it. */
1770cde58dbcSMatthew Ahrens 			dsl_deadlist_merge(&ds_next->ds_deadlist,
1771cde58dbcSMatthew Ahrens 			    ds->ds_phys->ds_deadlist_obj, tx);
1772cde58dbcSMatthew Ahrens 		}
1773cde58dbcSMatthew Ahrens 		dsl_deadlist_close(&ds->ds_deadlist);
1774cde58dbcSMatthew Ahrens 		dsl_deadlist_free(mos, ds->ds_phys->ds_deadlist_obj, tx);
1775fa9e4066Sahrens 
1776cde58dbcSMatthew Ahrens 		/* Collapse range in clone heads */
1777cde58dbcSMatthew Ahrens 		dsl_dataset_remove_clones_key(ds,
1778cde58dbcSMatthew Ahrens 		    ds->ds_phys->ds_creation_txg, tx);
1779fa9e4066Sahrens 
17803f9d6ad7SLin Ling 		if (dsl_dataset_is_snapshot(ds_next)) {
1781cde58dbcSMatthew Ahrens 			dsl_dataset_t *ds_nextnext;
1782cde58dbcSMatthew Ahrens 
1783fa9e4066Sahrens 			/*
1784fa9e4066Sahrens 			 * Update next's unique to include blocks which
1785fa9e4066Sahrens 			 * were previously shared by only this snapshot
1786fa9e4066Sahrens 			 * and it.  Those blocks will be born after the
1787fa9e4066Sahrens 			 * prev snap and before this snap, and will have
1788fa9e4066Sahrens 			 * died after the next snap and before the one
1789fa9e4066Sahrens 			 * after that (ie. be on the snap after next's
1790fa9e4066Sahrens 			 * deadlist).
1791fa9e4066Sahrens 			 */
1792745cd3c5Smaybee 			VERIFY(0 == dsl_dataset_hold_obj(dp,
1793745cd3c5Smaybee 			    ds_next->ds_phys->ds_next_snap_obj,
1794cde58dbcSMatthew Ahrens 			    FTAG, &ds_nextnext));
1795cde58dbcSMatthew Ahrens 			dsl_deadlist_space_range(&ds_nextnext->ds_deadlist,
179674e7dc98SMatthew Ahrens 			    ds->ds_phys->ds_prev_snap_txg,
1797cde58dbcSMatthew Ahrens 			    ds->ds_phys->ds_creation_txg,
1798cde58dbcSMatthew Ahrens 			    &used, &comp, &uncomp);
1799cde58dbcSMatthew Ahrens 			ds_next->ds_phys->ds_unique_bytes += used;
1800cde58dbcSMatthew Ahrens 			dsl_dataset_rele(ds_nextnext, FTAG);
1801fa9e4066Sahrens 			ASSERT3P(ds_next->ds_prev, ==, NULL);
1802cde58dbcSMatthew Ahrens 
1803cde58dbcSMatthew Ahrens 			/* Collapse range in this head. */
1804cde58dbcSMatthew Ahrens 			dsl_dataset_t *hds;
1805b420f3adSRichard Lowe 			VERIFY3U(0, ==, dsl_dataset_hold_obj(dp,
1806cde58dbcSMatthew Ahrens 			    ds->ds_dir->dd_phys->dd_head_dataset_obj,
1807cde58dbcSMatthew Ahrens 			    FTAG, &hds));
1808cde58dbcSMatthew Ahrens 			dsl_deadlist_remove_key(&hds->ds_deadlist,
1809cde58dbcSMatthew Ahrens 			    ds->ds_phys->ds_creation_txg, tx);
1810cde58dbcSMatthew Ahrens 			dsl_dataset_rele(hds, FTAG);
1811cde58dbcSMatthew Ahrens 
1812fa9e4066Sahrens 		} else {
1813fa9e4066Sahrens 			ASSERT3P(ds_next->ds_prev, ==, ds);
1814745cd3c5Smaybee 			dsl_dataset_drop_ref(ds_next->ds_prev, ds_next);
1815745cd3c5Smaybee 			ds_next->ds_prev = NULL;
1816fa9e4066Sahrens 			if (ds_prev) {
1817745cd3c5Smaybee 				VERIFY(0 == dsl_dataset_get_ref(dp,
1818745cd3c5Smaybee 				    ds->ds_phys->ds_prev_snap_obj,
1819745cd3c5Smaybee 				    ds_next, &ds_next->ds_prev));
1820fa9e4066Sahrens 			}
1821a9799022Sck 
1822a9799022Sck 			dsl_dataset_recalc_head_uniq(ds_next);
1823a9799022Sck 
1824a9799022Sck 			/*
1825a9799022Sck 			 * Reduce the amount of our unconsmed refreservation
1826a9799022Sck 			 * being charged to our parent by the amount of
1827a9799022Sck 			 * new unique data we have gained.
1828a9799022Sck 			 */
1829a9799022Sck 			if (old_unique < ds_next->ds_reserved) {
1830a9799022Sck 				int64_t mrsdelta;
1831a9799022Sck 				uint64_t new_unique =
1832a9799022Sck 				    ds_next->ds_phys->ds_unique_bytes;
1833a9799022Sck 
1834a9799022Sck 				ASSERT(old_unique <= new_unique);
1835a9799022Sck 				mrsdelta = MIN(new_unique - old_unique,
1836a9799022Sck 				    ds_next->ds_reserved - old_unique);
183774e7dc98SMatthew Ahrens 				dsl_dir_diduse_space(ds->ds_dir,
183874e7dc98SMatthew Ahrens 				    DD_USED_REFRSRV, -mrsdelta, 0, 0, tx);
1839a9799022Sck 			}
1840fa9e4066Sahrens 		}
1841745cd3c5Smaybee 		dsl_dataset_rele(ds_next, FTAG);
1842fa9e4066Sahrens 	} else {
1843ad135b5dSChristopher Siden 		zfeature_info_t *async_destroy =
1844ad135b5dSChristopher Siden 		    &spa_feature_table[SPA_FEATURE_ASYNC_DESTROY];
1845*ce636f8bSMatthew Ahrens 		objset_t *os;
1846ad135b5dSChristopher Siden 
1847fa9e4066Sahrens 		/*
1848fa9e4066Sahrens 		 * There's no next snapshot, so this is a head dataset.
1849fa9e4066Sahrens 		 * Destroy the deadlist.  Unless it's a clone, the
1850fa9e4066Sahrens 		 * deadlist should be empty.  (If it's a clone, it's
1851fa9e4066Sahrens 		 * safe to ignore the deadlist contents.)
1852fa9e4066Sahrens 		 */
1853cde58dbcSMatthew Ahrens 		dsl_deadlist_close(&ds->ds_deadlist);
1854cde58dbcSMatthew Ahrens 		dsl_deadlist_free(mos, ds->ds_phys->ds_deadlist_obj, tx);
1855fa9e4066Sahrens 		ds->ds_phys->ds_deadlist_obj = 0;
1856fa9e4066Sahrens 
1857*ce636f8bSMatthew Ahrens 		VERIFY3U(0, ==, dmu_objset_from_ds(ds, &os));
1858*ce636f8bSMatthew Ahrens 
1859ad135b5dSChristopher Siden 		if (!spa_feature_is_enabled(dp->dp_spa, async_destroy)) {
1860ad135b5dSChristopher Siden 			err = old_synchronous_dataset_destroy(ds, tx);
1861ad135b5dSChristopher Siden 		} else {
1862ad135b5dSChristopher Siden 			/*
1863ad135b5dSChristopher Siden 			 * Move the bptree into the pool's list of trees to
1864ad135b5dSChristopher Siden 			 * clean up and update space accounting information.
1865ad135b5dSChristopher Siden 			 */
1866ad135b5dSChristopher Siden 			uint64_t used, comp, uncomp;
1867ad135b5dSChristopher Siden 
1868*ce636f8bSMatthew Ahrens 			zil_destroy_sync(dmu_objset_zil(os), tx);
1869*ce636f8bSMatthew Ahrens 
1870ad135b5dSChristopher Siden 			if (!spa_feature_is_active(dp->dp_spa, async_destroy)) {
1871ad135b5dSChristopher Siden 				spa_feature_incr(dp->dp_spa, async_destroy, tx);
1872*ce636f8bSMatthew Ahrens 				dp->dp_bptree_obj = bptree_alloc(mos, tx);
1873*ce636f8bSMatthew Ahrens 				VERIFY(zap_add(mos,
1874ad135b5dSChristopher Siden 				    DMU_POOL_DIRECTORY_OBJECT,
1875ad135b5dSChristopher Siden 				    DMU_POOL_BPTREE_OBJ, sizeof (uint64_t), 1,
1876ad135b5dSChristopher Siden 				    &dp->dp_bptree_obj, tx) == 0);
1877ad135b5dSChristopher Siden 			}
1878ad135b5dSChristopher Siden 
1879ad135b5dSChristopher Siden 			used = ds->ds_dir->dd_phys->dd_used_bytes;
1880ad135b5dSChristopher Siden 			comp = ds->ds_dir->dd_phys->dd_compressed_bytes;
1881ad135b5dSChristopher Siden 			uncomp = ds->ds_dir->dd_phys->dd_uncompressed_bytes;
1882ad135b5dSChristopher Siden 
1883ad135b5dSChristopher Siden 			ASSERT(!DS_UNIQUE_IS_ACCURATE(ds) ||
1884ad135b5dSChristopher Siden 			    ds->ds_phys->ds_unique_bytes == used);
1885ad135b5dSChristopher Siden 
1886*ce636f8bSMatthew Ahrens 			bptree_add(mos, dp->dp_bptree_obj,
1887ad135b5dSChristopher Siden 			    &ds->ds_phys->ds_bp, ds->ds_phys->ds_prev_snap_txg,
1888ad135b5dSChristopher Siden 			    used, comp, uncomp, tx);
1889ad135b5dSChristopher Siden 			dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD,
1890ad135b5dSChristopher Siden 			    -used, -comp, -uncomp, tx);
1891ad135b5dSChristopher Siden 			dsl_dir_diduse_space(dp->dp_free_dir, DD_USED_HEAD,
1892ad135b5dSChristopher Siden 			    used, comp, uncomp, tx);
1893ad135b5dSChristopher Siden 		}
1894ca45db41SChris Kirby 
1895ca45db41SChris Kirby 		if (ds->ds_prev != NULL) {
1896cde58dbcSMatthew Ahrens 			if (spa_version(dp->dp_spa) >= SPA_VERSION_DIR_CLONES) {
1897b420f3adSRichard Lowe 				VERIFY3U(0, ==, zap_remove_int(mos,
1898cde58dbcSMatthew Ahrens 				    ds->ds_prev->ds_dir->dd_phys->dd_clones,
1899cde58dbcSMatthew Ahrens 				    ds->ds_object, tx));
1900cde58dbcSMatthew Ahrens 			}
1901ca45db41SChris Kirby 			dsl_dataset_rele(ds->ds_prev, ds);
1902ca45db41SChris Kirby 			ds->ds_prev = ds_prev = NULL;
1903ca45db41SChris Kirby 		}
1904fa9e4066Sahrens 	}
1905fa9e4066Sahrens 
19066e0cbcaaSMatthew Ahrens 	/*
19076e0cbcaaSMatthew Ahrens 	 * This must be done after the dsl_traverse(), because it will
19086e0cbcaaSMatthew Ahrens 	 * re-open the objset.
19096e0cbcaaSMatthew Ahrens 	 */
19106e0cbcaaSMatthew Ahrens 	if (ds->ds_objset) {
19116e0cbcaaSMatthew Ahrens 		dmu_objset_evict(ds->ds_objset);
19126e0cbcaaSMatthew Ahrens 		ds->ds_objset = NULL;
19136e0cbcaaSMatthew Ahrens 	}
19146e0cbcaaSMatthew Ahrens 
19151d452cf5Sahrens 	if (ds->ds_dir->dd_phys->dd_head_dataset_obj == ds->ds_object) {
1916745cd3c5Smaybee 		/* Erase the link in the dir */
19171d452cf5Sahrens 		dmu_buf_will_dirty(ds->ds_dir->dd_dbuf, tx);
19181d452cf5Sahrens 		ds->ds_dir->dd_phys->dd_head_dataset_obj = 0;
1919745cd3c5Smaybee 		ASSERT(ds->ds_phys->ds_snapnames_zapobj != 0);
1920745cd3c5Smaybee 		err = zap_destroy(mos, ds->ds_phys->ds_snapnames_zapobj, tx);
1921745cd3c5Smaybee 		ASSERT(err == 0);
1922fa9e4066Sahrens 	} else {
1923fa9e4066Sahrens 		/* remove from snapshot namespace */
1924fa9e4066Sahrens 		dsl_dataset_t *ds_head;
1925745cd3c5Smaybee 		ASSERT(ds->ds_phys->ds_snapnames_zapobj == 0);
1926745cd3c5Smaybee 		VERIFY(0 == dsl_dataset_hold_obj(dp,
1927745cd3c5Smaybee 		    ds->ds_dir->dd_phys->dd_head_dataset_obj, FTAG, &ds_head));
19288660574dSahrens 		VERIFY(0 == dsl_dataset_get_snapname(ds));
1929fa9e4066Sahrens #ifdef ZFS_DEBUG
1930fa9e4066Sahrens 		{
1931fa9e4066Sahrens 			uint64_t val;
1932ab04eb8eStimh 
1933745cd3c5Smaybee 			err = dsl_dataset_snap_lookup(ds_head,
1934ab04eb8eStimh 			    ds->ds_snapname, &val);
1935b420f3adSRichard Lowe 			ASSERT3U(err, ==, 0);
1936fa9e4066Sahrens 			ASSERT3U(val, ==, obj);
1937fa9e4066Sahrens 		}
1938fa9e4066Sahrens #endif
1939745cd3c5Smaybee 		err = dsl_dataset_snap_remove(ds_head, ds->ds_snapname, tx);
1940fa9e4066Sahrens 		ASSERT(err == 0);
1941745cd3c5Smaybee 		dsl_dataset_rele(ds_head, FTAG);
1942fa9e4066Sahrens 	}
1943fa9e4066Sahrens 
1944fa9e4066Sahrens 	if (ds_prev && ds->ds_prev != ds_prev)
1945745cd3c5Smaybee 		dsl_dataset_rele(ds_prev, FTAG);
1946fa9e4066Sahrens 
1947990b4856Slling 	spa_prop_clear_bootfs(dp->dp_spa, ds->ds_object, tx);
1948ecd6cf80Smarks 
1949088f3894Sahrens 	if (ds->ds_phys->ds_next_clones_obj != 0) {
1950088f3894Sahrens 		uint64_t count;
1951088f3894Sahrens 		ASSERT(0 == zap_count(mos,
1952088f3894Sahrens 		    ds->ds_phys->ds_next_clones_obj, &count) && count == 0);
1953088f3894Sahrens 		VERIFY(0 == dmu_object_free(mos,
1954088f3894Sahrens 		    ds->ds_phys->ds_next_clones_obj, tx));
1955088f3894Sahrens 	}
195674e7dc98SMatthew Ahrens 	if (ds->ds_phys->ds_props_obj != 0)
195774e7dc98SMatthew Ahrens 		VERIFY(0 == zap_destroy(mos, ds->ds_phys->ds_props_obj, tx));
1958842727c2SChris Kirby 	if (ds->ds_phys->ds_userrefs_obj != 0)
1959842727c2SChris Kirby 		VERIFY(0 == zap_destroy(mos, ds->ds_phys->ds_userrefs_obj, tx));
1960745cd3c5Smaybee 	dsl_dir_close(ds->ds_dir, ds);
1961745cd3c5Smaybee 	ds->ds_dir = NULL;
1962745cd3c5Smaybee 	dsl_dataset_drain_refs(ds, tag);
19631d452cf5Sahrens 	VERIFY(0 == dmu_object_free(mos, obj, tx));
1964842727c2SChris Kirby 
1965842727c2SChris Kirby 	if (dsda->rm_origin) {
1966842727c2SChris Kirby 		/*
1967842727c2SChris Kirby 		 * Remove the origin of the clone we just destroyed.
1968842727c2SChris Kirby 		 */
1969842727c2SChris Kirby 		struct dsl_ds_destroyarg ndsda = {0};
1970842727c2SChris Kirby 
1971ca45db41SChris Kirby 		ndsda.ds = dsda->rm_origin;
19723f9d6ad7SLin Ling 		dsl_dataset_destroy_sync(&ndsda, tag, tx);
1973842727c2SChris Kirby 	}
1974fa9e4066Sahrens }
1975fa9e4066Sahrens 
1976a9799022Sck static int
1977a9799022Sck dsl_dataset_snapshot_reserve_space(dsl_dataset_t *ds, dmu_tx_t *tx)
1978a9799022Sck {
1979a9799022Sck 	uint64_t asize;
1980a9799022Sck 
1981a9799022Sck 	if (!dmu_tx_is_syncing(tx))
1982a9799022Sck 		return (0);
1983a9799022Sck 
1984a9799022Sck 	/*
1985a9799022Sck 	 * If there's an fs-only reservation, any blocks that might become
1986a9799022Sck 	 * owned by the snapshot dataset must be accommodated by space
1987a9799022Sck 	 * outside of the reservation.
1988a9799022Sck 	 */
19893f9d6ad7SLin Ling 	ASSERT(ds->ds_reserved == 0 || DS_UNIQUE_IS_ACCURATE(ds));
19903f9d6ad7SLin Ling 	asize = MIN(ds->ds_phys->ds_unique_bytes, ds->ds_reserved);
19916e0cbcaaSMatthew Ahrens 	if (asize > dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE))
1992a9799022Sck 		return (ENOSPC);
1993a9799022Sck 
1994a9799022Sck 	/*
19954445fffbSMatthew Ahrens 	 * Propagate any reserved space for this snapshot to other
1996a9799022Sck 	 * snapshot checks in this sync group.
1997a9799022Sck 	 */
1998a9799022Sck 	if (asize > 0)
1999a9799022Sck 		dsl_dir_willuse_space(ds->ds_dir, asize, tx);
2000a9799022Sck 
2001a9799022Sck 	return (0);
2002a9799022Sck }
2003a9799022Sck 
2004fa9e4066Sahrens int
20054445fffbSMatthew Ahrens dsl_dataset_snapshot_check(dsl_dataset_t *ds, const char *snapname,
20064445fffbSMatthew Ahrens     dmu_tx_t *tx)
2007fa9e4066Sahrens {
2008fa9e4066Sahrens 	int err;
20091d452cf5Sahrens 	uint64_t value;
2010fa9e4066Sahrens 
20111d452cf5Sahrens 	/*
20121d452cf5Sahrens 	 * We don't allow multiple snapshots of the same txg.  If there
20131d452cf5Sahrens 	 * is already one, try again.
20141d452cf5Sahrens 	 */
20151d452cf5Sahrens 	if (ds->ds_phys->ds_prev_snap_txg >= tx->tx_txg)
20161d452cf5Sahrens 		return (EAGAIN);
2017fa9e4066Sahrens 
20181d452cf5Sahrens 	/*
20194445fffbSMatthew Ahrens 	 * Check for conflicting snapshot name.
20201d452cf5Sahrens 	 */
2021745cd3c5Smaybee 	err = dsl_dataset_snap_lookup(ds, snapname, &value);
20221d452cf5Sahrens 	if (err == 0)
2023fa9e4066Sahrens 		return (EEXIST);
20241d452cf5Sahrens 	if (err != ENOENT)
20251d452cf5Sahrens 		return (err);
2026fa9e4066Sahrens 
2027b7661cccSmmusante 	/*
2028b7661cccSmmusante 	 * Check that the dataset's name is not too long.  Name consists
2029b7661cccSmmusante 	 * of the dataset's length + 1 for the @-sign + snapshot name's length
2030b7661cccSmmusante 	 */
2031b7661cccSmmusante 	if (dsl_dataset_namelen(ds) + 1 + strlen(snapname) >= MAXNAMELEN)
2032b7661cccSmmusante 		return (ENAMETOOLONG);
2033b7661cccSmmusante 
2034a9799022Sck 	err = dsl_dataset_snapshot_reserve_space(ds, tx);
2035a9799022Sck 	if (err)
2036a9799022Sck 		return (err);
2037a9799022Sck 
20381d452cf5Sahrens 	ds->ds_trysnap_txg = tx->tx_txg;
20391d452cf5Sahrens 	return (0);
20401d452cf5Sahrens }
2041fa9e4066Sahrens 
20421d452cf5Sahrens void
20434445fffbSMatthew Ahrens dsl_dataset_snapshot_sync(dsl_dataset_t *ds, const char *snapname,
20444445fffbSMatthew Ahrens     dmu_tx_t *tx)
20451d452cf5Sahrens {
20461d452cf5Sahrens 	dsl_pool_t *dp = ds->ds_dir->dd_pool;
20471d452cf5Sahrens 	dmu_buf_t *dbuf;
20481d452cf5Sahrens 	dsl_dataset_phys_t *dsphys;
2049088f3894Sahrens 	uint64_t dsobj, crtxg;
20501d452cf5Sahrens 	objset_t *mos = dp->dp_meta_objset;
20511d452cf5Sahrens 	int err;
2052fa9e4066Sahrens 
20531d452cf5Sahrens 	ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock));
2054fa9e4066Sahrens 
2055088f3894Sahrens 	/*
2056088f3894Sahrens 	 * The origin's ds_creation_txg has to be < TXG_INITIAL
2057088f3894Sahrens 	 */
2058088f3894Sahrens 	if (strcmp(snapname, ORIGIN_DIR_NAME) == 0)
2059088f3894Sahrens 		crtxg = 1;
2060088f3894Sahrens 	else
2061088f3894Sahrens 		crtxg = tx->tx_txg;
2062088f3894Sahrens 
20631649cd4bStabriz 	dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0,
20641649cd4bStabriz 	    DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx);
2065ea8dc4b6Seschrock 	VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf));
2066fa9e4066Sahrens 	dmu_buf_will_dirty(dbuf, tx);
2067fa9e4066Sahrens 	dsphys = dbuf->db_data;
2068745cd3c5Smaybee 	bzero(dsphys, sizeof (dsl_dataset_phys_t));
20691d452cf5Sahrens 	dsphys->ds_dir_obj = ds->ds_dir->dd_object;
2070fa9e4066Sahrens 	dsphys->ds_fsid_guid = unique_create();
2071fa9e4066Sahrens 	(void) random_get_pseudo_bytes((void*)&dsphys->ds_guid,
2072fa9e4066Sahrens 	    sizeof (dsphys->ds_guid));
2073fa9e4066Sahrens 	dsphys->ds_prev_snap_obj = ds->ds_phys->ds_prev_snap_obj;
2074fa9e4066Sahrens 	dsphys->ds_prev_snap_txg = ds->ds_phys->ds_prev_snap_txg;
2075fa9e4066Sahrens 	dsphys->ds_next_snap_obj = ds->ds_object;
2076fa9e4066Sahrens 	dsphys->ds_num_children = 1;
2077fa9e4066Sahrens 	dsphys->ds_creation_time = gethrestime_sec();
2078088f3894Sahrens 	dsphys->ds_creation_txg = crtxg;
2079fa9e4066Sahrens 	dsphys->ds_deadlist_obj = ds->ds_phys->ds_deadlist_obj;
2080ad135b5dSChristopher Siden 	dsphys->ds_referenced_bytes = ds->ds_phys->ds_referenced_bytes;
2081fa9e4066Sahrens 	dsphys->ds_compressed_bytes = ds->ds_phys->ds_compressed_bytes;
2082fa9e4066Sahrens 	dsphys->ds_uncompressed_bytes = ds->ds_phys->ds_uncompressed_bytes;
208399653d4eSeschrock 	dsphys->ds_flags = ds->ds_phys->ds_flags;
2084fa9e4066Sahrens 	dsphys->ds_bp = ds->ds_phys->ds_bp;
2085ea8dc4b6Seschrock 	dmu_buf_rele(dbuf, FTAG);
2086fa9e4066Sahrens 
20871d452cf5Sahrens 	ASSERT3U(ds->ds_prev != 0, ==, ds->ds_phys->ds_prev_snap_obj != 0);
20881d452cf5Sahrens 	if (ds->ds_prev) {
2089088f3894Sahrens 		uint64_t next_clones_obj =
2090088f3894Sahrens 		    ds->ds_prev->ds_phys->ds_next_clones_obj;
20911d452cf5Sahrens 		ASSERT(ds->ds_prev->ds_phys->ds_next_snap_obj ==
2092fa9e4066Sahrens 		    ds->ds_object ||
20931d452cf5Sahrens 		    ds->ds_prev->ds_phys->ds_num_children > 1);
20941d452cf5Sahrens 		if (ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) {
20951d452cf5Sahrens 			dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx);
2096fa9e4066Sahrens 			ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==,
20971d452cf5Sahrens 			    ds->ds_prev->ds_phys->ds_creation_txg);
20981d452cf5Sahrens 			ds->ds_prev->ds_phys->ds_next_snap_obj = dsobj;
2099088f3894Sahrens 		} else if (next_clones_obj != 0) {
2100c33e334fSMatthew Ahrens 			remove_from_next_clones(ds->ds_prev,
2101c33e334fSMatthew Ahrens 			    dsphys->ds_next_snap_obj, tx);
2102b420f3adSRichard Lowe 			VERIFY3U(0, ==, zap_add_int(mos,
2103088f3894Sahrens 			    next_clones_obj, dsobj, tx));
2104fa9e4066Sahrens 		}
2105fa9e4066Sahrens 	}
2106fa9e4066Sahrens 
2107a9799022Sck 	/*
2108a9799022Sck 	 * If we have a reference-reservation on this dataset, we will
2109a9799022Sck 	 * need to increase the amount of refreservation being charged
2110a9799022Sck 	 * since our unique space is going to zero.
2111a9799022Sck 	 */
2112a9799022Sck 	if (ds->ds_reserved) {
21133f9d6ad7SLin Ling 		int64_t delta;
21143f9d6ad7SLin Ling 		ASSERT(DS_UNIQUE_IS_ACCURATE(ds));
21153f9d6ad7SLin Ling 		delta = MIN(ds->ds_phys->ds_unique_bytes, ds->ds_reserved);
211674e7dc98SMatthew Ahrens 		dsl_dir_diduse_space(ds->ds_dir, DD_USED_REFRSRV,
21173f9d6ad7SLin Ling 		    delta, 0, 0, tx);
2118a9799022Sck 	}
2119a9799022Sck 
2120fa9e4066Sahrens 	dmu_buf_will_dirty(ds->ds_dbuf, tx);
2121cde58dbcSMatthew Ahrens 	zfs_dbgmsg("taking snapshot %s@%s/%llu; newkey=%llu",
2122cde58dbcSMatthew Ahrens 	    ds->ds_dir->dd_myname, snapname, dsobj,
2123cde58dbcSMatthew Ahrens 	    ds->ds_phys->ds_prev_snap_txg);
2124cde58dbcSMatthew Ahrens 	ds->ds_phys->ds_deadlist_obj = dsl_deadlist_clone(&ds->ds_deadlist,
2125cde58dbcSMatthew Ahrens 	    UINT64_MAX, ds->ds_phys->ds_prev_snap_obj, tx);
2126cde58dbcSMatthew Ahrens 	dsl_deadlist_close(&ds->ds_deadlist);
2127cde58dbcSMatthew Ahrens 	dsl_deadlist_open(&ds->ds_deadlist, mos, ds->ds_phys->ds_deadlist_obj);
2128cde58dbcSMatthew Ahrens 	dsl_deadlist_add_key(&ds->ds_deadlist,
2129cde58dbcSMatthew Ahrens 	    ds->ds_phys->ds_prev_snap_txg, tx);
2130cde58dbcSMatthew Ahrens 
2131a4611edeSahrens 	ASSERT3U(ds->ds_phys->ds_prev_snap_txg, <, tx->tx_txg);
2132fa9e4066Sahrens 	ds->ds_phys->ds_prev_snap_obj = dsobj;
2133088f3894Sahrens 	ds->ds_phys->ds_prev_snap_txg = crtxg;
2134fa9e4066Sahrens 	ds->ds_phys->ds_unique_bytes = 0;
2135a9799022Sck 	if (spa_version(dp->dp_spa) >= SPA_VERSION_UNIQUE_ACCURATE)
2136a9799022Sck 		ds->ds_phys->ds_flags |= DS_FLAG_UNIQUE_ACCURATE;
2137fa9e4066Sahrens 
2138fa9e4066Sahrens 	err = zap_add(mos, ds->ds_phys->ds_snapnames_zapobj,
2139fa9e4066Sahrens 	    snapname, 8, 1, &dsobj, tx);
2140fa9e4066Sahrens 	ASSERT(err == 0);
2141fa9e4066Sahrens 
2142fa9e4066Sahrens 	if (ds->ds_prev)
2143745cd3c5Smaybee 		dsl_dataset_drop_ref(ds->ds_prev, ds);
2144745cd3c5Smaybee 	VERIFY(0 == dsl_dataset_get_ref(dp,
2145745cd3c5Smaybee 	    ds->ds_phys->ds_prev_snap_obj, ds, &ds->ds_prev));
2146ecd6cf80Smarks 
21473f9d6ad7SLin Ling 	dsl_scan_ds_snapshotted(ds, tx);
2148088f3894Sahrens 
214971eb0538SChris Kirby 	dsl_dir_snap_cmtime_update(ds->ds_dir);
215071eb0538SChris Kirby 
21514445fffbSMatthew Ahrens 	spa_history_log_internal_ds(ds->ds_prev, "snapshot", tx, "");
2152fa9e4066Sahrens }
2153fa9e4066Sahrens 
2154fa9e4066Sahrens void
2155c717a561Smaybee dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx)
2156fa9e4066Sahrens {
2157fa9e4066Sahrens 	ASSERT(dmu_tx_is_syncing(tx));
2158503ad85cSMatthew Ahrens 	ASSERT(ds->ds_objset != NULL);
2159fa9e4066Sahrens 	ASSERT(ds->ds_phys->ds_next_snap_obj == 0);
2160fa9e4066Sahrens 
216191ebeef5Sahrens 	/*
216291ebeef5Sahrens 	 * in case we had to change ds_fsid_guid when we opened it,
216391ebeef5Sahrens 	 * sync it out now.
216491ebeef5Sahrens 	 */
216591ebeef5Sahrens 	dmu_buf_will_dirty(ds->ds_dbuf, tx);
216691ebeef5Sahrens 	ds->ds_phys->ds_fsid_guid = ds->ds_fsid_guid;
216791ebeef5Sahrens 
2168503ad85cSMatthew Ahrens 	dmu_objset_sync(ds->ds_objset, zio, tx);
2169fa9e4066Sahrens }
2170fa9e4066Sahrens 
217119b94df9SMatthew Ahrens static void
217219b94df9SMatthew Ahrens get_clones_stat(dsl_dataset_t *ds, nvlist_t *nv)
217319b94df9SMatthew Ahrens {
217419b94df9SMatthew Ahrens 	uint64_t count = 0;
217519b94df9SMatthew Ahrens 	objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
217619b94df9SMatthew Ahrens 	zap_cursor_t zc;
217719b94df9SMatthew Ahrens 	zap_attribute_t za;
217819b94df9SMatthew Ahrens 	nvlist_t *propval;
217919b94df9SMatthew Ahrens 	nvlist_t *val;
218019b94df9SMatthew Ahrens 
218119b94df9SMatthew Ahrens 	rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER);
218219b94df9SMatthew Ahrens 	VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
218319b94df9SMatthew Ahrens 	VERIFY(nvlist_alloc(&val, NV_UNIQUE_NAME, KM_SLEEP) == 0);
218419b94df9SMatthew Ahrens 
218519b94df9SMatthew Ahrens 	/*
218619b94df9SMatthew Ahrens 	 * There may me missing entries in ds_next_clones_obj
218719b94df9SMatthew Ahrens 	 * due to a bug in a previous version of the code.
218819b94df9SMatthew Ahrens 	 * Only trust it if it has the right number of entries.
218919b94df9SMatthew Ahrens 	 */
219019b94df9SMatthew Ahrens 	if (ds->ds_phys->ds_next_clones_obj != 0) {
2191b420f3adSRichard Lowe 		ASSERT3U(0, ==, zap_count(mos, ds->ds_phys->ds_next_clones_obj,
219219b94df9SMatthew Ahrens 		    &count));
219319b94df9SMatthew Ahrens 	}
219419b94df9SMatthew Ahrens 	if (count != ds->ds_phys->ds_num_children - 1) {
219519b94df9SMatthew Ahrens 		goto fail;
219619b94df9SMatthew Ahrens 	}
219719b94df9SMatthew Ahrens 	for (zap_cursor_init(&zc, mos, ds->ds_phys->ds_next_clones_obj);
219819b94df9SMatthew Ahrens 	    zap_cursor_retrieve(&zc, &za) == 0;
219919b94df9SMatthew Ahrens 	    zap_cursor_advance(&zc)) {
220019b94df9SMatthew Ahrens 		dsl_dataset_t *clone;
220119b94df9SMatthew Ahrens 		char buf[ZFS_MAXNAMELEN];
2202ad135b5dSChristopher Siden 		/*
2203ad135b5dSChristopher Siden 		 * Even though we hold the dp_config_rwlock, the dataset
2204ad135b5dSChristopher Siden 		 * may fail to open, returning ENOENT.  If there is a
2205ad135b5dSChristopher Siden 		 * thread concurrently attempting to destroy this
2206ad135b5dSChristopher Siden 		 * dataset, it will have the ds_rwlock held for
2207ad135b5dSChristopher Siden 		 * RW_WRITER.  Our call to dsl_dataset_hold_obj() ->
2208ad135b5dSChristopher Siden 		 * dsl_dataset_hold_ref() will fail its
2209ad135b5dSChristopher Siden 		 * rw_tryenter(&ds->ds_rwlock, RW_READER), drop the
2210ad135b5dSChristopher Siden 		 * dp_config_rwlock, and wait for the destroy progress
2211ad135b5dSChristopher Siden 		 * and signal ds_exclusive_cv.  If the destroy was
2212ad135b5dSChristopher Siden 		 * successful, we will see that
2213ad135b5dSChristopher Siden 		 * DSL_DATASET_IS_DESTROYED(), and return ENOENT.
2214ad135b5dSChristopher Siden 		 */
221519b94df9SMatthew Ahrens 		if (dsl_dataset_hold_obj(ds->ds_dir->dd_pool,
2216ad135b5dSChristopher Siden 		    za.za_first_integer, FTAG, &clone) != 0)
2217ad135b5dSChristopher Siden 			continue;
221819b94df9SMatthew Ahrens 		dsl_dir_name(clone->ds_dir, buf);
221919b94df9SMatthew Ahrens 		VERIFY(nvlist_add_boolean(val, buf) == 0);
222019b94df9SMatthew Ahrens 		dsl_dataset_rele(clone, FTAG);
222119b94df9SMatthew Ahrens 	}
222219b94df9SMatthew Ahrens 	zap_cursor_fini(&zc);
222319b94df9SMatthew Ahrens 	VERIFY(nvlist_add_nvlist(propval, ZPROP_VALUE, val) == 0);
222419b94df9SMatthew Ahrens 	VERIFY(nvlist_add_nvlist(nv, zfs_prop_to_name(ZFS_PROP_CLONES),
222519b94df9SMatthew Ahrens 	    propval) == 0);
222619b94df9SMatthew Ahrens fail:
222719b94df9SMatthew Ahrens 	nvlist_free(val);
222819b94df9SMatthew Ahrens 	nvlist_free(propval);
222919b94df9SMatthew Ahrens 	rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock);
223019b94df9SMatthew Ahrens }
223119b94df9SMatthew Ahrens 
2232fa9e4066Sahrens void
2233a2eea2e1Sahrens dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv)
2234fa9e4066Sahrens {
2235187d6ac0SMatt Ahrens 	uint64_t refd, avail, uobjs, aobjs, ratio;
2236a9799022Sck 
22374445fffbSMatthew Ahrens 	ratio = ds->ds_phys->ds_compressed_bytes == 0 ? 100 :
22384445fffbSMatthew Ahrens 	    (ds->ds_phys->ds_uncompressed_bytes * 100 /
22394445fffbSMatthew Ahrens 	    ds->ds_phys->ds_compressed_bytes);
22404445fffbSMatthew Ahrens 
22414445fffbSMatthew Ahrens 	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRATIO, ratio);
22424445fffbSMatthew Ahrens 
22434445fffbSMatthew Ahrens 	if (dsl_dataset_is_snapshot(ds)) {
22444445fffbSMatthew Ahrens 		dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO, ratio);
22454445fffbSMatthew Ahrens 		dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED,
22464445fffbSMatthew Ahrens 		    ds->ds_phys->ds_unique_bytes);
22474445fffbSMatthew Ahrens 		get_clones_stat(ds, nv);
22484445fffbSMatthew Ahrens 	} else {
22494445fffbSMatthew Ahrens 		dsl_dir_stats(ds->ds_dir, nv);
22504445fffbSMatthew Ahrens 	}
2251fa9e4066Sahrens 
2252a9799022Sck 	dsl_dataset_space(ds, &refd, &avail, &uobjs, &aobjs);
2253a9799022Sck 	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_AVAILABLE, avail);
2254a9799022Sck 	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFERENCED, refd);
2255a9799022Sck 
2256a2eea2e1Sahrens 	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATION,
2257a2eea2e1Sahrens 	    ds->ds_phys->ds_creation_time);
2258a2eea2e1Sahrens 	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATETXG,
2259a2eea2e1Sahrens 	    ds->ds_phys->ds_creation_txg);
2260a9799022Sck 	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFQUOTA,
2261a9799022Sck 	    ds->ds_quota);
2262a9799022Sck 	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRESERVATION,
2263a9799022Sck 	    ds->ds_reserved);
2264c5904d13Seschrock 	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_GUID,
2265c5904d13Seschrock 	    ds->ds_phys->ds_guid);
22661d713200SEric Schrock 	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_UNIQUE,
22673f9d6ad7SLin Ling 	    ds->ds_phys->ds_unique_bytes);
22681d713200SEric Schrock 	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_OBJSETID,
22691d713200SEric Schrock 	    ds->ds_object);
227092241e0bSTom Erickson 	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USERREFS,
227192241e0bSTom Erickson 	    ds->ds_userrefs);
2272842727c2SChris Kirby 	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_DEFER_DESTROY,
2273842727c2SChris Kirby 	    DS_IS_DEFER_DESTROY(ds) ? 1 : 0);
2274fa9e4066Sahrens 
227519b94df9SMatthew Ahrens 	if (ds->ds_phys->ds_prev_snap_obj != 0) {
227619b94df9SMatthew Ahrens 		uint64_t written, comp, uncomp;
227719b94df9SMatthew Ahrens 		dsl_pool_t *dp = ds->ds_dir->dd_pool;
227819b94df9SMatthew Ahrens 		dsl_dataset_t *prev;
227919b94df9SMatthew Ahrens 
228019b94df9SMatthew Ahrens 		rw_enter(&dp->dp_config_rwlock, RW_READER);
228119b94df9SMatthew Ahrens 		int err = dsl_dataset_hold_obj(dp,
228219b94df9SMatthew Ahrens 		    ds->ds_phys->ds_prev_snap_obj, FTAG, &prev);
228319b94df9SMatthew Ahrens 		rw_exit(&dp->dp_config_rwlock);
228419b94df9SMatthew Ahrens 		if (err == 0) {
228519b94df9SMatthew Ahrens 			err = dsl_dataset_space_written(prev, ds, &written,
228619b94df9SMatthew Ahrens 			    &comp, &uncomp);
228719b94df9SMatthew Ahrens 			dsl_dataset_rele(prev, FTAG);
228819b94df9SMatthew Ahrens 			if (err == 0) {
228919b94df9SMatthew Ahrens 				dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_WRITTEN,
229019b94df9SMatthew Ahrens 				    written);
229119b94df9SMatthew Ahrens 			}
229219b94df9SMatthew Ahrens 		}
229319b94df9SMatthew Ahrens 	}
229419b94df9SMatthew Ahrens 
2295fa9e4066Sahrens }
2296fa9e4066Sahrens 
2297a2eea2e1Sahrens void
2298a2eea2e1Sahrens dsl_dataset_fast_stat(dsl_dataset_t *ds, dmu_objset_stats_t *stat)
2299a2eea2e1Sahrens {
2300a2eea2e1Sahrens 	stat->dds_creation_txg = ds->ds_phys->ds_creation_txg;
2301a2eea2e1Sahrens 	stat->dds_inconsistent = ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT;
23023cb34c60Sahrens 	stat->dds_guid = ds->ds_phys->ds_guid;
23034445fffbSMatthew Ahrens 	stat->dds_origin[0] = '\0';
23044445fffbSMatthew Ahrens 	if (dsl_dataset_is_snapshot(ds)) {
2305a2eea2e1Sahrens 		stat->dds_is_snapshot = B_TRUE;
2306a2eea2e1Sahrens 		stat->dds_num_clones = ds->ds_phys->ds_num_children - 1;
2307ebedde84SEric Taylor 	} else {
2308ebedde84SEric Taylor 		stat->dds_is_snapshot = B_FALSE;
2309ebedde84SEric Taylor 		stat->dds_num_clones = 0;
2310a2eea2e1Sahrens 
23114445fffbSMatthew Ahrens 		rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER);
23124445fffbSMatthew Ahrens 		if (dsl_dir_is_clone(ds->ds_dir)) {
23134445fffbSMatthew Ahrens 			dsl_dataset_t *ods;
2314a2eea2e1Sahrens 
23154445fffbSMatthew Ahrens 			VERIFY(0 == dsl_dataset_get_ref(ds->ds_dir->dd_pool,
23164445fffbSMatthew Ahrens 			    ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &ods));
23174445fffbSMatthew Ahrens 			dsl_dataset_name(ods, stat->dds_origin);
23184445fffbSMatthew Ahrens 			dsl_dataset_drop_ref(ods, FTAG);
23194445fffbSMatthew Ahrens 		}
23204445fffbSMatthew Ahrens 		rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock);
2321a2eea2e1Sahrens 	}
2322a2eea2e1Sahrens }
2323a2eea2e1Sahrens 
2324a2eea2e1Sahrens uint64_t
2325a2eea2e1Sahrens dsl_dataset_fsid_guid(dsl_dataset_t *ds)
2326a2eea2e1Sahrens {
232791ebeef5Sahrens 	return (ds->ds_fsid_guid);
2328a2eea2e1Sahrens }
2329a2eea2e1Sahrens 
2330a2eea2e1Sahrens void
2331a2eea2e1Sahrens dsl_dataset_space(dsl_dataset_t *ds,
2332a2eea2e1Sahrens     uint64_t *refdbytesp, uint64_t *availbytesp,
2333a2eea2e1Sahrens     uint64_t *usedobjsp, uint64_t *availobjsp)
2334fa9e4066Sahrens {
2335ad135b5dSChristopher Siden 	*refdbytesp = ds->ds_phys->ds_referenced_bytes;
2336a2eea2e1Sahrens 	*availbytesp = dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE);
2337a9799022Sck 	if (ds->ds_reserved > ds->ds_phys->ds_unique_bytes)
2338a9799022Sck 		*availbytesp += ds->ds_reserved - ds->ds_phys->ds_unique_bytes;
2339a9799022Sck 	if (ds->ds_quota != 0) {
2340a9799022Sck 		/*
2341a9799022Sck 		 * Adjust available bytes according to refquota
2342a9799022Sck 		 */
2343a9799022Sck 		if (*refdbytesp < ds->ds_quota)
2344a9799022Sck 			*availbytesp = MIN(*availbytesp,
2345a9799022Sck 			    ds->ds_quota - *refdbytesp);
2346a9799022Sck 		else
2347a9799022Sck 			*availbytesp = 0;
2348a9799022Sck 	}
2349a2eea2e1Sahrens 	*usedobjsp = ds->ds_phys->ds_bp.blk_fill;
2350a2eea2e1Sahrens 	*availobjsp = DN_MAX_OBJECT - *usedobjsp;
2351fa9e4066Sahrens }
2352fa9e4066Sahrens 
2353f18faf3fSek boolean_t
2354f18faf3fSek dsl_dataset_modified_since_lastsnap(dsl_dataset_t *ds)
2355f18faf3fSek {
2356f18faf3fSek 	dsl_pool_t *dp = ds->ds_dir->dd_pool;
2357f18faf3fSek 
2358f18faf3fSek 	ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock) ||
2359f18faf3fSek 	    dsl_pool_sync_context(dp));
2360f18faf3fSek 	if (ds->ds_prev == NULL)
2361f18faf3fSek 		return (B_FALSE);
2362f18faf3fSek 	if (ds->ds_phys->ds_bp.blk_birth >
23636e0cbcaaSMatthew Ahrens 	    ds->ds_prev->ds_phys->ds_creation_txg) {
23646e0cbcaaSMatthew Ahrens 		objset_t *os, *os_prev;
23656e0cbcaaSMatthew Ahrens 		/*
23666e0cbcaaSMatthew Ahrens 		 * It may be that only the ZIL differs, because it was
23676e0cbcaaSMatthew Ahrens 		 * reset in the head.  Don't count that as being
23686e0cbcaaSMatthew Ahrens 		 * modified.
23696e0cbcaaSMatthew Ahrens 		 */
23706e0cbcaaSMatthew Ahrens 		if (dmu_objset_from_ds(ds, &os) != 0)
23716e0cbcaaSMatthew Ahrens 			return (B_TRUE);
23726e0cbcaaSMatthew Ahrens 		if (dmu_objset_from_ds(ds->ds_prev, &os_prev) != 0)
23736e0cbcaaSMatthew Ahrens 			return (B_TRUE);
23746e0cbcaaSMatthew Ahrens 		return (bcmp(&os->os_phys->os_meta_dnode,
23756e0cbcaaSMatthew Ahrens 		    &os_prev->os_phys->os_meta_dnode,
23766e0cbcaaSMatthew Ahrens 		    sizeof (os->os_phys->os_meta_dnode)) != 0);
23776e0cbcaaSMatthew Ahrens 	}
2378f18faf3fSek 	return (B_FALSE);
2379f18faf3fSek }
2380f18faf3fSek 
23811d452cf5Sahrens /* ARGSUSED */
2382fa9e4066Sahrens static int
23831d452cf5Sahrens dsl_dataset_snapshot_rename_check(void *arg1, void *arg2, dmu_tx_t *tx)
2384fa9e4066Sahrens {
23851d452cf5Sahrens 	dsl_dataset_t *ds = arg1;
23861d452cf5Sahrens 	char *newsnapname = arg2;
23871d452cf5Sahrens 	dsl_dir_t *dd = ds->ds_dir;
23881d452cf5Sahrens 	dsl_dataset_t *hds;
2389fa9e4066Sahrens 	uint64_t val;
23901d452cf5Sahrens 	int err;
2391fa9e4066Sahrens 
2392745cd3c5Smaybee 	err = dsl_dataset_hold_obj(dd->dd_pool,
2393745cd3c5Smaybee 	    dd->dd_phys->dd_head_dataset_obj, FTAG, &hds);
2394fa9e4066Sahrens 	if (err)
2395fa9e4066Sahrens 		return (err);
2396fa9e4066Sahrens 
23971d452cf5Sahrens 	/* new name better not be in use */
2398745cd3c5Smaybee 	err = dsl_dataset_snap_lookup(hds, newsnapname, &val);
2399745cd3c5Smaybee 	dsl_dataset_rele(hds, FTAG);
24001d452cf5Sahrens 
24011d452cf5Sahrens 	if (err == 0)
24021d452cf5Sahrens 		err = EEXIST;
24031d452cf5Sahrens 	else if (err == ENOENT)
24041d452cf5Sahrens 		err = 0;
2405cdf5b4caSmmusante 
2406cdf5b4caSmmusante 	/* dataset name + 1 for the "@" + the new snapshot name must fit */
2407cdf5b4caSmmusante 	if (dsl_dir_namelen(ds->ds_dir) + 1 + strlen(newsnapname) >= MAXNAMELEN)
2408cdf5b4caSmmusante 		err = ENAMETOOLONG;
2409cdf5b4caSmmusante 
24101d452cf5Sahrens 	return (err);
24111d452cf5Sahrens }
2412fa9e4066Sahrens 
24131d452cf5Sahrens static void
24143f9d6ad7SLin Ling dsl_dataset_snapshot_rename_sync(void *arg1, void *arg2, dmu_tx_t *tx)
24151d452cf5Sahrens {
24161d452cf5Sahrens 	dsl_dataset_t *ds = arg1;
2417ecd6cf80Smarks 	const char *newsnapname = arg2;
24181d452cf5Sahrens 	dsl_dir_t *dd = ds->ds_dir;
24191d452cf5Sahrens 	objset_t *mos = dd->dd_pool->dp_meta_objset;
24201d452cf5Sahrens 	dsl_dataset_t *hds;
24211d452cf5Sahrens 	int err;
2422fa9e4066Sahrens 
24231d452cf5Sahrens 	ASSERT(ds->ds_phys->ds_next_snap_obj != 0);
2424fa9e4066Sahrens 
2425745cd3c5Smaybee 	VERIFY(0 == dsl_dataset_hold_obj(dd->dd_pool,
2426745cd3c5Smaybee 	    dd->dd_phys->dd_head_dataset_obj, FTAG, &hds));
2427fa9e4066Sahrens 
24281d452cf5Sahrens 	VERIFY(0 == dsl_dataset_get_snapname(ds));
2429745cd3c5Smaybee 	err = dsl_dataset_snap_remove(hds, ds->ds_snapname, tx);
2430b420f3adSRichard Lowe 	ASSERT3U(err, ==, 0);
24311d452cf5Sahrens 	mutex_enter(&ds->ds_lock);
24321d452cf5Sahrens 	(void) strcpy(ds->ds_snapname, newsnapname);
24331d452cf5Sahrens 	mutex_exit(&ds->ds_lock);
24341d452cf5Sahrens 	err = zap_add(mos, hds->ds_phys->ds_snapnames_zapobj,
24351d452cf5Sahrens 	    ds->ds_snapname, 8, 1, &ds->ds_object, tx);
2436b420f3adSRichard Lowe 	ASSERT3U(err, ==, 0);
2437fa9e4066Sahrens 
24384445fffbSMatthew Ahrens 	spa_history_log_internal_ds(ds, "rename", tx,
24394445fffbSMatthew Ahrens 	    "-> @%s", newsnapname);
2440745cd3c5Smaybee 	dsl_dataset_rele(hds, FTAG);
2441fa9e4066Sahrens }
2442fa9e4066Sahrens 
2443f18faf3fSek struct renamesnaparg {
2444cdf5b4caSmmusante 	dsl_sync_task_group_t *dstg;
2445cdf5b4caSmmusante 	char failed[MAXPATHLEN];
2446cdf5b4caSmmusante 	char *oldsnap;
2447cdf5b4caSmmusante 	char *newsnap;
2448cdf5b4caSmmusante };
2449cdf5b4caSmmusante 
2450cdf5b4caSmmusante static int
2451fd136879SMatthew Ahrens dsl_snapshot_rename_one(const char *name, void *arg)
2452cdf5b4caSmmusante {
2453f18faf3fSek 	struct renamesnaparg *ra = arg;
2454cdf5b4caSmmusante 	dsl_dataset_t *ds = NULL;
2455fd136879SMatthew Ahrens 	char *snapname;
2456cdf5b4caSmmusante 	int err;
2457cdf5b4caSmmusante 
2458fd136879SMatthew Ahrens 	snapname = kmem_asprintf("%s@%s", name, ra->oldsnap);
2459fd136879SMatthew Ahrens 	(void) strlcpy(ra->failed, snapname, sizeof (ra->failed));
2460ecd6cf80Smarks 
2461ecd6cf80Smarks 	/*
2462ecd6cf80Smarks 	 * For recursive snapshot renames the parent won't be changing
2463ecd6cf80Smarks 	 * so we just pass name for both the to/from argument.
2464ecd6cf80Smarks 	 */
2465fd136879SMatthew Ahrens 	err = zfs_secpolicy_rename_perms(snapname, snapname, CRED());
2466fd136879SMatthew Ahrens 	if (err != 0) {
2467fd136879SMatthew Ahrens 		strfree(snapname);
2468fd136879SMatthew Ahrens 		return (err == ENOENT ? 0 : err);
2469ecd6cf80Smarks 	}
2470ecd6cf80Smarks 
2471745cd3c5Smaybee #ifdef _KERNEL
2472745cd3c5Smaybee 	/*
2473745cd3c5Smaybee 	 * For all filesystems undergoing rename, we'll need to unmount it.
2474745cd3c5Smaybee 	 */
2475fd136879SMatthew Ahrens 	(void) zfs_unmount_snap(snapname, NULL);
2476745cd3c5Smaybee #endif
2477fd136879SMatthew Ahrens 	err = dsl_dataset_hold(snapname, ra->dstg, &ds);
24783f1f8012SMatthew Ahrens 	strfree(snapname);
24793f1f8012SMatthew Ahrens 	if (err != 0)
2480fd136879SMatthew Ahrens 		return (err == ENOENT ? 0 : err);
2481cdf5b4caSmmusante 
2482cdf5b4caSmmusante 	dsl_sync_task_create(ra->dstg, dsl_dataset_snapshot_rename_check,
2483cdf5b4caSmmusante 	    dsl_dataset_snapshot_rename_sync, ds, ra->newsnap, 0);
2484cdf5b4caSmmusante 
2485cdf5b4caSmmusante 	return (0);
2486cdf5b4caSmmusante }
2487cdf5b4caSmmusante 
2488cdf5b4caSmmusante static int
2489cdf5b4caSmmusante dsl_recursive_rename(char *oldname, const char *newname)
2490cdf5b4caSmmusante {
2491cdf5b4caSmmusante 	int err;
2492f18faf3fSek 	struct renamesnaparg *ra;
2493cdf5b4caSmmusante 	dsl_sync_task_t *dst;
2494cdf5b4caSmmusante 	spa_t *spa;
2495cdf5b4caSmmusante 	char *cp, *fsname = spa_strdup(oldname);
2496fd136879SMatthew Ahrens 	int len = strlen(oldname) + 1;
2497cdf5b4caSmmusante 
2498cdf5b4caSmmusante 	/* truncate the snapshot name to get the fsname */
2499cdf5b4caSmmusante 	cp = strchr(fsname, '@');
2500cdf5b4caSmmusante 	*cp = '\0';
2501cdf5b4caSmmusante 
250240feaa91Sahrens 	err = spa_open(fsname, &spa, FTAG);
2503cdf5b4caSmmusante 	if (err) {
2504fd136879SMatthew Ahrens 		kmem_free(fsname, len);
2505cdf5b4caSmmusante 		return (err);
2506cdf5b4caSmmusante 	}
2507f18faf3fSek 	ra = kmem_alloc(sizeof (struct renamesnaparg), KM_SLEEP);
2508cdf5b4caSmmusante 	ra->dstg = dsl_sync_task_group_create(spa_get_dsl(spa));
2509cdf5b4caSmmusante 
2510cdf5b4caSmmusante 	ra->oldsnap = strchr(oldname, '@') + 1;
2511cdf5b4caSmmusante 	ra->newsnap = strchr(newname, '@') + 1;
2512cdf5b4caSmmusante 	*ra->failed = '\0';
2513cdf5b4caSmmusante 
2514cdf5b4caSmmusante 	err = dmu_objset_find(fsname, dsl_snapshot_rename_one, ra,
2515cdf5b4caSmmusante 	    DS_FIND_CHILDREN);
2516fd136879SMatthew Ahrens 	kmem_free(fsname, len);
2517cdf5b4caSmmusante 
2518cdf5b4caSmmusante 	if (err == 0) {
2519cdf5b4caSmmusante 		err = dsl_sync_task_group_wait(ra->dstg);
2520cdf5b4caSmmusante 	}
2521cdf5b4caSmmusante 
2522cdf5b4caSmmusante 	for (dst = list_head(&ra->dstg->dstg_tasks); dst;
2523cdf5b4caSmmusante 	    dst = list_next(&ra->dstg->dstg_tasks, dst)) {
2524cdf5b4caSmmusante 		dsl_dataset_t *ds = dst->dst_arg1;
2525cdf5b4caSmmusante 		if (dst->dst_err) {
2526cdf5b4caSmmusante 			dsl_dir_name(ds->ds_dir, ra->failed);
2527fd136879SMatthew Ahrens 			(void) strlcat(ra->failed, "@", sizeof (ra->failed));
2528fd136879SMatthew Ahrens 			(void) strlcat(ra->failed, ra->newsnap,
2529fd136879SMatthew Ahrens 			    sizeof (ra->failed));
2530cdf5b4caSmmusante 		}
2531745cd3c5Smaybee 		dsl_dataset_rele(ds, ra->dstg);
2532cdf5b4caSmmusante 	}
2533cdf5b4caSmmusante 
2534ecd6cf80Smarks 	if (err)
2535fd136879SMatthew Ahrens 		(void) strlcpy(oldname, ra->failed, sizeof (ra->failed));
2536cdf5b4caSmmusante 
2537cdf5b4caSmmusante 	dsl_sync_task_group_destroy(ra->dstg);
2538f18faf3fSek 	kmem_free(ra, sizeof (struct renamesnaparg));
2539cdf5b4caSmmusante 	spa_close(spa, FTAG);
2540cdf5b4caSmmusante 	return (err);
2541cdf5b4caSmmusante }
2542cdf5b4caSmmusante 
25433a5a36beSmmusante static int
2544fd136879SMatthew Ahrens dsl_valid_rename(const char *oldname, void *arg)
25453a5a36beSmmusante {
25463a5a36beSmmusante 	int delta = *(int *)arg;
25473a5a36beSmmusante 
25483a5a36beSmmusante 	if (strlen(oldname) + delta >= MAXNAMELEN)
25493a5a36beSmmusante 		return (ENAMETOOLONG);
25503a5a36beSmmusante 
25513a5a36beSmmusante 	return (0);
25523a5a36beSmmusante }
25533a5a36beSmmusante 
2554fa9e4066Sahrens #pragma weak dmu_objset_rename = dsl_dataset_rename
2555fa9e4066Sahrens int
2556745cd3c5Smaybee dsl_dataset_rename(char *oldname, const char *newname, boolean_t recursive)
2557fa9e4066Sahrens {
2558fa9e4066Sahrens 	dsl_dir_t *dd;
25591d452cf5Sahrens 	dsl_dataset_t *ds;
2560fa9e4066Sahrens 	const char *tail;
2561fa9e4066Sahrens 	int err;
2562fa9e4066Sahrens 
25631d452cf5Sahrens 	err = dsl_dir_open(oldname, FTAG, &dd, &tail);
2564ea8dc4b6Seschrock 	if (err)
2565ea8dc4b6Seschrock 		return (err);
2566370c1af0SSanjeev Bagewadi 
2567fa9e4066Sahrens 	if (tail == NULL) {
25683a5a36beSmmusante 		int delta = strlen(newname) - strlen(oldname);
25693a5a36beSmmusante 
2570088f3894Sahrens 		/* if we're growing, validate child name lengths */
25713a5a36beSmmusante 		if (delta > 0)
25723a5a36beSmmusante 			err = dmu_objset_find(oldname, dsl_valid_rename,
25733a5a36beSmmusante 			    &delta, DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS);
25743a5a36beSmmusante 
2575b91a2f0bSMatthew Ahrens 		if (err == 0)
25763a5a36beSmmusante 			err = dsl_dir_rename(dd, newname);
2577fa9e4066Sahrens 		dsl_dir_close(dd, FTAG);
2578fa9e4066Sahrens 		return (err);
2579fa9e4066Sahrens 	}
2580370c1af0SSanjeev Bagewadi 
2581fa9e4066Sahrens 	if (tail[0] != '@') {
2582681d9761SEric Taylor 		/* the name ended in a nonexistent component */
2583fa9e4066Sahrens 		dsl_dir_close(dd, FTAG);
2584fa9e4066Sahrens 		return (ENOENT);
2585fa9e4066Sahrens 	}
2586fa9e4066Sahrens 
2587fa9e4066Sahrens 	dsl_dir_close(dd, FTAG);
25881d452cf5Sahrens 
25891d452cf5Sahrens 	/* new name must be snapshot in same filesystem */
25901d452cf5Sahrens 	tail = strchr(newname, '@');
25911d452cf5Sahrens 	if (tail == NULL)
25921d452cf5Sahrens 		return (EINVAL);
25931d452cf5Sahrens 	tail++;
25941d452cf5Sahrens 	if (strncmp(oldname, newname, tail - newname) != 0)
25951d452cf5Sahrens 		return (EXDEV);
25961d452cf5Sahrens 
2597cdf5b4caSmmusante 	if (recursive) {
2598cdf5b4caSmmusante 		err = dsl_recursive_rename(oldname, newname);
2599cdf5b4caSmmusante 	} else {
2600745cd3c5Smaybee 		err = dsl_dataset_hold(oldname, FTAG, &ds);
2601cdf5b4caSmmusante 		if (err)
2602cdf5b4caSmmusante 			return (err);
26031d452cf5Sahrens 
2604cdf5b4caSmmusante 		err = dsl_sync_task_do(ds->ds_dir->dd_pool,
2605cdf5b4caSmmusante 		    dsl_dataset_snapshot_rename_check,
2606cdf5b4caSmmusante 		    dsl_dataset_snapshot_rename_sync, ds, (char *)tail, 1);
26071d452cf5Sahrens 
2608745cd3c5Smaybee 		dsl_dataset_rele(ds, FTAG);
2609cdf5b4caSmmusante 	}
26101d452cf5Sahrens 
2611fa9e4066Sahrens 	return (err);
2612fa9e4066Sahrens }
261399653d4eSeschrock 
2614088f3894Sahrens struct promotenode {
2615745cd3c5Smaybee 	list_node_t link;
2616745cd3c5Smaybee 	dsl_dataset_t *ds;
2617745cd3c5Smaybee };
2618745cd3c5Smaybee 
26191d452cf5Sahrens struct promotearg {
262074e7dc98SMatthew Ahrens 	list_t shared_snaps, origin_snaps, clone_snaps;
26213f9d6ad7SLin Ling 	dsl_dataset_t *origin_origin;
262274e7dc98SMatthew Ahrens 	uint64_t used, comp, uncomp, unique, cloneusedsnap, originusedsnap;
2623681d9761SEric Taylor 	char *err_ds;
26241d452cf5Sahrens };
26251d452cf5Sahrens 
262674e7dc98SMatthew Ahrens static int snaplist_space(list_t *l, uint64_t mintxg, uint64_t *spacep);
26273f9d6ad7SLin Ling static boolean_t snaplist_unstable(list_t *l);
262874e7dc98SMatthew Ahrens 
262999653d4eSeschrock static int
26301d452cf5Sahrens dsl_dataset_promote_check(void *arg1, void *arg2, dmu_tx_t *tx)
263199653d4eSeschrock {
26321d452cf5Sahrens 	dsl_dataset_t *hds = arg1;
26331d452cf5Sahrens 	struct promotearg *pa = arg2;
263474e7dc98SMatthew Ahrens 	struct promotenode *snap = list_head(&pa->shared_snaps);
2635745cd3c5Smaybee 	dsl_dataset_t *origin_ds = snap->ds;
2636745cd3c5Smaybee 	int err;
2637cde58dbcSMatthew Ahrens 	uint64_t unused;
26381d452cf5Sahrens 
2639088f3894Sahrens 	/* Check that it is a real clone */
2640088f3894Sahrens 	if (!dsl_dir_is_clone(hds->ds_dir))
264199653d4eSeschrock 		return (EINVAL);
264299653d4eSeschrock 
26431d452cf5Sahrens 	/* Since this is so expensive, don't do the preliminary check */
26441d452cf5Sahrens 	if (!dmu_tx_is_syncing(tx))
26451d452cf5Sahrens 		return (0);
26461d452cf5Sahrens 
2647745cd3c5Smaybee 	if (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE)
2648745cd3c5Smaybee 		return (EXDEV);
264999653d4eSeschrock 
26503cb34c60Sahrens 	/* compute origin's new unique space */
265174e7dc98SMatthew Ahrens 	snap = list_tail(&pa->clone_snaps);
265274e7dc98SMatthew Ahrens 	ASSERT3U(snap->ds->ds_phys->ds_prev_snap_obj, ==, origin_ds->ds_object);
2653cde58dbcSMatthew Ahrens 	dsl_deadlist_space_range(&snap->ds->ds_deadlist,
2654cde58dbcSMatthew Ahrens 	    origin_ds->ds_phys->ds_prev_snap_txg, UINT64_MAX,
2655cde58dbcSMatthew Ahrens 	    &pa->unique, &unused, &unused);
265699653d4eSeschrock 
2657745cd3c5Smaybee 	/*
2658745cd3c5Smaybee 	 * Walk the snapshots that we are moving
2659745cd3c5Smaybee 	 *
266074e7dc98SMatthew Ahrens 	 * Compute space to transfer.  Consider the incremental changes
266174e7dc98SMatthew Ahrens 	 * to used for each snapshot:
266274e7dc98SMatthew Ahrens 	 * (my used) = (prev's used) + (blocks born) - (blocks killed)
266374e7dc98SMatthew Ahrens 	 * So each snapshot gave birth to:
266474e7dc98SMatthew Ahrens 	 * (blocks born) = (my used) - (prev's used) + (blocks killed)
2665745cd3c5Smaybee 	 * So a sequence would look like:
266674e7dc98SMatthew Ahrens 	 * (uN - u(N-1) + kN) + ... + (u1 - u0 + k1) + (u0 - 0 + k0)
2667745cd3c5Smaybee 	 * Which simplifies to:
266874e7dc98SMatthew Ahrens 	 * uN + kN + kN-1 + ... + k1 + k0
2669745cd3c5Smaybee 	 * Note however, if we stop before we reach the ORIGIN we get:
267074e7dc98SMatthew Ahrens 	 * uN + kN + kN-1 + ... + kM - uM-1
2671745cd3c5Smaybee 	 */
2672ad135b5dSChristopher Siden 	pa->used = origin_ds->ds_phys->ds_referenced_bytes;
2673745cd3c5Smaybee 	pa->comp = origin_ds->ds_phys->ds_compressed_bytes;
2674745cd3c5Smaybee 	pa->uncomp = origin_ds->ds_phys->ds_uncompressed_bytes;
267574e7dc98SMatthew Ahrens 	for (snap = list_head(&pa->shared_snaps); snap;
267674e7dc98SMatthew Ahrens 	    snap = list_next(&pa->shared_snaps, snap)) {
267799653d4eSeschrock 		uint64_t val, dlused, dlcomp, dluncomp;
2678745cd3c5Smaybee 		dsl_dataset_t *ds = snap->ds;
267999653d4eSeschrock 
268099653d4eSeschrock 		/* Check that the snapshot name does not conflict */
268174e7dc98SMatthew Ahrens 		VERIFY(0 == dsl_dataset_get_snapname(ds));
2682745cd3c5Smaybee 		err = dsl_dataset_snap_lookup(hds, ds->ds_snapname, &val);
2683681d9761SEric Taylor 		if (err == 0) {
2684681d9761SEric Taylor 			err = EEXIST;
2685681d9761SEric Taylor 			goto out;
2686681d9761SEric Taylor 		}
2687745cd3c5Smaybee 		if (err != ENOENT)
2688681d9761SEric Taylor 			goto out;
268999653d4eSeschrock 
2690745cd3c5Smaybee 		/* The very first snapshot does not have a deadlist */
269174e7dc98SMatthew Ahrens 		if (ds->ds_phys->ds_prev_snap_obj == 0)
269274e7dc98SMatthew Ahrens 			continue;
269374e7dc98SMatthew Ahrens 
2694cde58dbcSMatthew Ahrens 		dsl_deadlist_space(&ds->ds_deadlist,
2695cde58dbcSMatthew Ahrens 		    &dlused, &dlcomp, &dluncomp);
269674e7dc98SMatthew Ahrens 		pa->used += dlused;
269774e7dc98SMatthew Ahrens 		pa->comp += dlcomp;
269874e7dc98SMatthew Ahrens 		pa->uncomp += dluncomp;
269974e7dc98SMatthew Ahrens 	}
2700745cd3c5Smaybee 
2701745cd3c5Smaybee 	/*
2702745cd3c5Smaybee 	 * If we are a clone of a clone then we never reached ORIGIN,
2703745cd3c5Smaybee 	 * so we need to subtract out the clone origin's used space.
2704745cd3c5Smaybee 	 */
270574e7dc98SMatthew Ahrens 	if (pa->origin_origin) {
2706ad135b5dSChristopher Siden 		pa->used -= pa->origin_origin->ds_phys->ds_referenced_bytes;
270774e7dc98SMatthew Ahrens 		pa->comp -= pa->origin_origin->ds_phys->ds_compressed_bytes;
270874e7dc98SMatthew Ahrens 		pa->uncomp -= pa->origin_origin->ds_phys->ds_uncompressed_bytes;
270999653d4eSeschrock 	}
271099653d4eSeschrock 
271199653d4eSeschrock 	/* Check that there is enough space here */
271274e7dc98SMatthew Ahrens 	err = dsl_dir_transfer_possible(origin_ds->ds_dir, hds->ds_dir,
271374e7dc98SMatthew Ahrens 	    pa->used);
271474e7dc98SMatthew Ahrens 	if (err)
271574e7dc98SMatthew Ahrens 		return (err);
271674e7dc98SMatthew Ahrens 
271774e7dc98SMatthew Ahrens 	/*
271874e7dc98SMatthew Ahrens 	 * Compute the amounts of space that will be used by snapshots
271974e7dc98SMatthew Ahrens 	 * after the promotion (for both origin and clone).  For each,
272074e7dc98SMatthew Ahrens 	 * it is the amount of space that will be on all of their
272174e7dc98SMatthew Ahrens 	 * deadlists (that was not born before their new origin).
272274e7dc98SMatthew Ahrens 	 */
272374e7dc98SMatthew Ahrens 	if (hds->ds_dir->dd_phys->dd_flags & DD_FLAG_USED_BREAKDOWN) {
272474e7dc98SMatthew Ahrens 		uint64_t space;
272574e7dc98SMatthew Ahrens 
272674e7dc98SMatthew Ahrens 		/*
272774e7dc98SMatthew Ahrens 		 * Note, typically this will not be a clone of a clone,
27283f9d6ad7SLin Ling 		 * so dd_origin_txg will be < TXG_INITIAL, so
2729cde58dbcSMatthew Ahrens 		 * these snaplist_space() -> dsl_deadlist_space_range()
273074e7dc98SMatthew Ahrens 		 * calls will be fast because they do not have to
273174e7dc98SMatthew Ahrens 		 * iterate over all bps.
273274e7dc98SMatthew Ahrens 		 */
273374e7dc98SMatthew Ahrens 		snap = list_head(&pa->origin_snaps);
273474e7dc98SMatthew Ahrens 		err = snaplist_space(&pa->shared_snaps,
27353f9d6ad7SLin Ling 		    snap->ds->ds_dir->dd_origin_txg, &pa->cloneusedsnap);
273674e7dc98SMatthew Ahrens 		if (err)
273774e7dc98SMatthew Ahrens 			return (err);
273874e7dc98SMatthew Ahrens 
273974e7dc98SMatthew Ahrens 		err = snaplist_space(&pa->clone_snaps,
27403f9d6ad7SLin Ling 		    snap->ds->ds_dir->dd_origin_txg, &space);
274174e7dc98SMatthew Ahrens 		if (err)
274274e7dc98SMatthew Ahrens 			return (err);
274374e7dc98SMatthew Ahrens 		pa->cloneusedsnap += space;
274474e7dc98SMatthew Ahrens 	}
274574e7dc98SMatthew Ahrens 	if (origin_ds->ds_dir->dd_phys->dd_flags & DD_FLAG_USED_BREAKDOWN) {
274674e7dc98SMatthew Ahrens 		err = snaplist_space(&pa->origin_snaps,
274774e7dc98SMatthew Ahrens 		    origin_ds->ds_phys->ds_creation_txg, &pa->originusedsnap);
274874e7dc98SMatthew Ahrens 		if (err)
274974e7dc98SMatthew Ahrens 			return (err);
2750745cd3c5Smaybee 	}
27511d452cf5Sahrens 
275274e7dc98SMatthew Ahrens 	return (0);
2753681d9761SEric Taylor out:
2754681d9761SEric Taylor 	pa->err_ds =  snap->ds->ds_snapname;
2755681d9761SEric Taylor 	return (err);
27561d452cf5Sahrens }
275799653d4eSeschrock 
27581d452cf5Sahrens static void
27593f9d6ad7SLin Ling dsl_dataset_promote_sync(void *arg1, void *arg2, dmu_tx_t *tx)
27601d452cf5Sahrens {
27611d452cf5Sahrens 	dsl_dataset_t *hds = arg1;
27621d452cf5Sahrens 	struct promotearg *pa = arg2;
276374e7dc98SMatthew Ahrens 	struct promotenode *snap = list_head(&pa->shared_snaps);
2764745cd3c5Smaybee 	dsl_dataset_t *origin_ds = snap->ds;
276574e7dc98SMatthew Ahrens 	dsl_dataset_t *origin_head;
27661d452cf5Sahrens 	dsl_dir_t *dd = hds->ds_dir;
27671d452cf5Sahrens 	dsl_pool_t *dp = hds->ds_dir->dd_pool;
27683cb34c60Sahrens 	dsl_dir_t *odd = NULL;
2769088f3894Sahrens 	uint64_t oldnext_obj;
277074e7dc98SMatthew Ahrens 	int64_t delta;
27711d452cf5Sahrens 
27721d452cf5Sahrens 	ASSERT(0 == (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE));
27731d452cf5Sahrens 
277474e7dc98SMatthew Ahrens 	snap = list_head(&pa->origin_snaps);
277574e7dc98SMatthew Ahrens 	origin_head = snap->ds;
277674e7dc98SMatthew Ahrens 
27770b69c2f0Sahrens 	/*
27783cb34c60Sahrens 	 * We need to explicitly open odd, since origin_ds's dd will be
27790b69c2f0Sahrens 	 * changing.
27800b69c2f0Sahrens 	 */
27813cb34c60Sahrens 	VERIFY(0 == dsl_dir_open_obj(dp, origin_ds->ds_dir->dd_object,
27823cb34c60Sahrens 	    NULL, FTAG, &odd));
278399653d4eSeschrock 
2784745cd3c5Smaybee 	/* change origin's next snap */
2785745cd3c5Smaybee 	dmu_buf_will_dirty(origin_ds->ds_dbuf, tx);
2786088f3894Sahrens 	oldnext_obj = origin_ds->ds_phys->ds_next_snap_obj;
278774e7dc98SMatthew Ahrens 	snap = list_tail(&pa->clone_snaps);
278874e7dc98SMatthew Ahrens 	ASSERT3U(snap->ds->ds_phys->ds_prev_snap_obj, ==, origin_ds->ds_object);
278974e7dc98SMatthew Ahrens 	origin_ds->ds_phys->ds_next_snap_obj = snap->ds->ds_object;
2790745cd3c5Smaybee 
2791088f3894Sahrens 	/* change the origin's next clone */
2792088f3894Sahrens 	if (origin_ds->ds_phys->ds_next_clones_obj) {
2793c33e334fSMatthew Ahrens 		remove_from_next_clones(origin_ds, snap->ds->ds_object, tx);
2794b420f3adSRichard Lowe 		VERIFY3U(0, ==, zap_add_int(dp->dp_meta_objset,
2795088f3894Sahrens 		    origin_ds->ds_phys->ds_next_clones_obj,
2796088f3894Sahrens 		    oldnext_obj, tx));
2797088f3894Sahrens 	}
2798088f3894Sahrens 
2799745cd3c5Smaybee 	/* change origin */
2800745cd3c5Smaybee 	dmu_buf_will_dirty(dd->dd_dbuf, tx);
2801745cd3c5Smaybee 	ASSERT3U(dd->dd_phys->dd_origin_obj, ==, origin_ds->ds_object);
2802745cd3c5Smaybee 	dd->dd_phys->dd_origin_obj = odd->dd_phys->dd_origin_obj;
28033f9d6ad7SLin Ling 	dd->dd_origin_txg = origin_head->ds_dir->dd_origin_txg;
2804745cd3c5Smaybee 	dmu_buf_will_dirty(odd->dd_dbuf, tx);
2805745cd3c5Smaybee 	odd->dd_phys->dd_origin_obj = origin_ds->ds_object;
28063f9d6ad7SLin Ling 	origin_head->ds_dir->dd_origin_txg =
28073f9d6ad7SLin Ling 	    origin_ds->ds_phys->ds_creation_txg;
2808745cd3c5Smaybee 
2809cde58dbcSMatthew Ahrens 	/* change dd_clone entries */
2810cde58dbcSMatthew Ahrens 	if (spa_version(dp->dp_spa) >= SPA_VERSION_DIR_CLONES) {
2811b420f3adSRichard Lowe 		VERIFY3U(0, ==, zap_remove_int(dp->dp_meta_objset,
2812cde58dbcSMatthew Ahrens 		    odd->dd_phys->dd_clones, hds->ds_object, tx));
2813b420f3adSRichard Lowe 		VERIFY3U(0, ==, zap_add_int(dp->dp_meta_objset,
2814cde58dbcSMatthew Ahrens 		    pa->origin_origin->ds_dir->dd_phys->dd_clones,
2815cde58dbcSMatthew Ahrens 		    hds->ds_object, tx));
2816cde58dbcSMatthew Ahrens 
2817b420f3adSRichard Lowe 		VERIFY3U(0, ==, zap_remove_int(dp->dp_meta_objset,
2818cde58dbcSMatthew Ahrens 		    pa->origin_origin->ds_dir->dd_phys->dd_clones,
2819cde58dbcSMatthew Ahrens 		    origin_head->ds_object, tx));
2820cde58dbcSMatthew Ahrens 		if (dd->dd_phys->dd_clones == 0) {
2821cde58dbcSMatthew Ahrens 			dd->dd_phys->dd_clones = zap_create(dp->dp_meta_objset,
2822cde58dbcSMatthew Ahrens 			    DMU_OT_DSL_CLONES, DMU_OT_NONE, 0, tx);
2823cde58dbcSMatthew Ahrens 		}
2824b420f3adSRichard Lowe 		VERIFY3U(0, ==, zap_add_int(dp->dp_meta_objset,
2825cde58dbcSMatthew Ahrens 		    dd->dd_phys->dd_clones, origin_head->ds_object, tx));
2826cde58dbcSMatthew Ahrens 
2827cde58dbcSMatthew Ahrens 	}
2828cde58dbcSMatthew Ahrens 
282999653d4eSeschrock 	/* move snapshots to this dir */
283074e7dc98SMatthew Ahrens 	for (snap = list_head(&pa->shared_snaps); snap;
283174e7dc98SMatthew Ahrens 	    snap = list_next(&pa->shared_snaps, snap)) {
2832745cd3c5Smaybee 		dsl_dataset_t *ds = snap->ds;
283399653d4eSeschrock 
28343baa08fcSek 		/* unregister props as dsl_dir is changing */
2835503ad85cSMatthew Ahrens 		if (ds->ds_objset) {
2836503ad85cSMatthew Ahrens 			dmu_objset_evict(ds->ds_objset);
2837503ad85cSMatthew Ahrens 			ds->ds_objset = NULL;
28383baa08fcSek 		}
283999653d4eSeschrock 		/* move snap name entry */
284074e7dc98SMatthew Ahrens 		VERIFY(0 == dsl_dataset_get_snapname(ds));
284174e7dc98SMatthew Ahrens 		VERIFY(0 == dsl_dataset_snap_remove(origin_head,
2842745cd3c5Smaybee 		    ds->ds_snapname, tx));
28431d452cf5Sahrens 		VERIFY(0 == zap_add(dp->dp_meta_objset,
284499653d4eSeschrock 		    hds->ds_phys->ds_snapnames_zapobj, ds->ds_snapname,
284599653d4eSeschrock 		    8, 1, &ds->ds_object, tx));
2846cde58dbcSMatthew Ahrens 
284799653d4eSeschrock 		/* change containing dsl_dir */
284899653d4eSeschrock 		dmu_buf_will_dirty(ds->ds_dbuf, tx);
28493cb34c60Sahrens 		ASSERT3U(ds->ds_phys->ds_dir_obj, ==, odd->dd_object);
285099653d4eSeschrock 		ds->ds_phys->ds_dir_obj = dd->dd_object;
28513cb34c60Sahrens 		ASSERT3P(ds->ds_dir, ==, odd);
285299653d4eSeschrock 		dsl_dir_close(ds->ds_dir, ds);
28531d452cf5Sahrens 		VERIFY(0 == dsl_dir_open_obj(dp, dd->dd_object,
285499653d4eSeschrock 		    NULL, ds, &ds->ds_dir));
285599653d4eSeschrock 
2856cde58dbcSMatthew Ahrens 		/* move any clone references */
2857cde58dbcSMatthew Ahrens 		if (ds->ds_phys->ds_next_clones_obj &&
2858cde58dbcSMatthew Ahrens 		    spa_version(dp->dp_spa) >= SPA_VERSION_DIR_CLONES) {
2859cde58dbcSMatthew Ahrens 			zap_cursor_t zc;
2860cde58dbcSMatthew Ahrens 			zap_attribute_t za;
2861cde58dbcSMatthew Ahrens 
2862cde58dbcSMatthew Ahrens 			for (zap_cursor_init(&zc, dp->dp_meta_objset,
2863cde58dbcSMatthew Ahrens 			    ds->ds_phys->ds_next_clones_obj);
2864cde58dbcSMatthew Ahrens 			    zap_cursor_retrieve(&zc, &za) == 0;
2865cde58dbcSMatthew Ahrens 			    zap_cursor_advance(&zc)) {
2866cde58dbcSMatthew Ahrens 				dsl_dataset_t *cnds;
2867cde58dbcSMatthew Ahrens 				uint64_t o;
2868cde58dbcSMatthew Ahrens 
2869cde58dbcSMatthew Ahrens 				if (za.za_first_integer == oldnext_obj) {
2870cde58dbcSMatthew Ahrens 					/*
2871cde58dbcSMatthew Ahrens 					 * We've already moved the
2872cde58dbcSMatthew Ahrens 					 * origin's reference.
2873cde58dbcSMatthew Ahrens 					 */
2874cde58dbcSMatthew Ahrens 					continue;
2875cde58dbcSMatthew Ahrens 				}
2876cde58dbcSMatthew Ahrens 
2877b420f3adSRichard Lowe 				VERIFY3U(0, ==, dsl_dataset_hold_obj(dp,
2878cde58dbcSMatthew Ahrens 				    za.za_first_integer, FTAG, &cnds));
2879cde58dbcSMatthew Ahrens 				o = cnds->ds_dir->dd_phys->dd_head_dataset_obj;
2880cde58dbcSMatthew Ahrens 
2881cde58dbcSMatthew Ahrens 				VERIFY3U(zap_remove_int(dp->dp_meta_objset,
2882cde58dbcSMatthew Ahrens 				    odd->dd_phys->dd_clones, o, tx), ==, 0);
2883cde58dbcSMatthew Ahrens 				VERIFY3U(zap_add_int(dp->dp_meta_objset,
2884cde58dbcSMatthew Ahrens 				    dd->dd_phys->dd_clones, o, tx), ==, 0);
2885cde58dbcSMatthew Ahrens 				dsl_dataset_rele(cnds, FTAG);
2886cde58dbcSMatthew Ahrens 			}
2887cde58dbcSMatthew Ahrens 			zap_cursor_fini(&zc);
2888cde58dbcSMatthew Ahrens 		}
2889cde58dbcSMatthew Ahrens 
2890b420f3adSRichard Lowe 		ASSERT3U(dsl_prop_numcb(ds), ==, 0);
289174e7dc98SMatthew Ahrens 	}
289274e7dc98SMatthew Ahrens 
289374e7dc98SMatthew Ahrens 	/*
289474e7dc98SMatthew Ahrens 	 * Change space accounting.
289574e7dc98SMatthew Ahrens 	 * Note, pa->*usedsnap and dd_used_breakdown[SNAP] will either
289674e7dc98SMatthew Ahrens 	 * both be valid, or both be 0 (resulting in delta == 0).  This
289774e7dc98SMatthew Ahrens 	 * is true for each of {clone,origin} independently.
289874e7dc98SMatthew Ahrens 	 */
289974e7dc98SMatthew Ahrens 
290074e7dc98SMatthew Ahrens 	delta = pa->cloneusedsnap -
290174e7dc98SMatthew Ahrens 	    dd->dd_phys->dd_used_breakdown[DD_USED_SNAP];
290274e7dc98SMatthew Ahrens 	ASSERT3S(delta, >=, 0);
290374e7dc98SMatthew Ahrens 	ASSERT3U(pa->used, >=, delta);
290474e7dc98SMatthew Ahrens 	dsl_dir_diduse_space(dd, DD_USED_SNAP, delta, 0, 0, tx);
290574e7dc98SMatthew Ahrens 	dsl_dir_diduse_space(dd, DD_USED_HEAD,
290674e7dc98SMatthew Ahrens 	    pa->used - delta, pa->comp, pa->uncomp, tx);
290774e7dc98SMatthew Ahrens 
290874e7dc98SMatthew Ahrens 	delta = pa->originusedsnap -
290974e7dc98SMatthew Ahrens 	    odd->dd_phys->dd_used_breakdown[DD_USED_SNAP];
291074e7dc98SMatthew Ahrens 	ASSERT3S(delta, <=, 0);
291174e7dc98SMatthew Ahrens 	ASSERT3U(pa->used, >=, -delta);
291274e7dc98SMatthew Ahrens 	dsl_dir_diduse_space(odd, DD_USED_SNAP, delta, 0, 0, tx);
291374e7dc98SMatthew Ahrens 	dsl_dir_diduse_space(odd, DD_USED_HEAD,
291474e7dc98SMatthew Ahrens 	    -pa->used - delta, -pa->comp, -pa->uncomp, tx);
291599653d4eSeschrock 
29163cb34c60Sahrens 	origin_ds->ds_phys->ds_unique_bytes = pa->unique;
291799653d4eSeschrock 
2918ecd6cf80Smarks 	/* log history record */
29194445fffbSMatthew Ahrens 	spa_history_log_internal_ds(hds, "promote", tx, "");
2920ecd6cf80Smarks 
29213cb34c60Sahrens 	dsl_dir_close(odd, FTAG);
292299653d4eSeschrock }
292399653d4eSeschrock 
292474e7dc98SMatthew Ahrens static char *snaplist_tag = "snaplist";
292574e7dc98SMatthew Ahrens /*
292674e7dc98SMatthew Ahrens  * Make a list of dsl_dataset_t's for the snapshots between first_obj
292774e7dc98SMatthew Ahrens  * (exclusive) and last_obj (inclusive).  The list will be in reverse
292874e7dc98SMatthew Ahrens  * order (last_obj will be the list_head()).  If first_obj == 0, do all
292974e7dc98SMatthew Ahrens  * snapshots back to this dataset's origin.
293074e7dc98SMatthew Ahrens  */
293174e7dc98SMatthew Ahrens static int
293274e7dc98SMatthew Ahrens snaplist_make(dsl_pool_t *dp, boolean_t own,
293374e7dc98SMatthew Ahrens     uint64_t first_obj, uint64_t last_obj, list_t *l)
293474e7dc98SMatthew Ahrens {
293574e7dc98SMatthew Ahrens 	uint64_t obj = last_obj;
293674e7dc98SMatthew Ahrens 
293774e7dc98SMatthew Ahrens 	ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock));
293874e7dc98SMatthew Ahrens 
293974e7dc98SMatthew Ahrens 	list_create(l, sizeof (struct promotenode),
294074e7dc98SMatthew Ahrens 	    offsetof(struct promotenode, link));
294174e7dc98SMatthew Ahrens 
294274e7dc98SMatthew Ahrens 	while (obj != first_obj) {
294374e7dc98SMatthew Ahrens 		dsl_dataset_t *ds;
294474e7dc98SMatthew Ahrens 		struct promotenode *snap;
294574e7dc98SMatthew Ahrens 		int err;
294674e7dc98SMatthew Ahrens 
294774e7dc98SMatthew Ahrens 		if (own) {
294874e7dc98SMatthew Ahrens 			err = dsl_dataset_own_obj(dp, obj,
294974e7dc98SMatthew Ahrens 			    0, snaplist_tag, &ds);
295074e7dc98SMatthew Ahrens 			if (err == 0)
295174e7dc98SMatthew Ahrens 				dsl_dataset_make_exclusive(ds, snaplist_tag);
295274e7dc98SMatthew Ahrens 		} else {
295374e7dc98SMatthew Ahrens 			err = dsl_dataset_hold_obj(dp, obj, snaplist_tag, &ds);
295474e7dc98SMatthew Ahrens 		}
295574e7dc98SMatthew Ahrens 		if (err == ENOENT) {
295674e7dc98SMatthew Ahrens 			/* lost race with snapshot destroy */
295774e7dc98SMatthew Ahrens 			struct promotenode *last = list_tail(l);
295874e7dc98SMatthew Ahrens 			ASSERT(obj != last->ds->ds_phys->ds_prev_snap_obj);
295974e7dc98SMatthew Ahrens 			obj = last->ds->ds_phys->ds_prev_snap_obj;
296074e7dc98SMatthew Ahrens 			continue;
296174e7dc98SMatthew Ahrens 		} else if (err) {
296274e7dc98SMatthew Ahrens 			return (err);
296374e7dc98SMatthew Ahrens 		}
296474e7dc98SMatthew Ahrens 
296574e7dc98SMatthew Ahrens 		if (first_obj == 0)
296674e7dc98SMatthew Ahrens 			first_obj = ds->ds_dir->dd_phys->dd_origin_obj;
296774e7dc98SMatthew Ahrens 
296874e7dc98SMatthew Ahrens 		snap = kmem_alloc(sizeof (struct promotenode), KM_SLEEP);
296974e7dc98SMatthew Ahrens 		snap->ds = ds;
297074e7dc98SMatthew Ahrens 		list_insert_tail(l, snap);
297174e7dc98SMatthew Ahrens 		obj = ds->ds_phys->ds_prev_snap_obj;
297274e7dc98SMatthew Ahrens 	}
297374e7dc98SMatthew Ahrens 
297474e7dc98SMatthew Ahrens 	return (0);
297574e7dc98SMatthew Ahrens }
297674e7dc98SMatthew Ahrens 
297774e7dc98SMatthew Ahrens static int
297874e7dc98SMatthew Ahrens snaplist_space(list_t *l, uint64_t mintxg, uint64_t *spacep)
297974e7dc98SMatthew Ahrens {
298074e7dc98SMatthew Ahrens 	struct promotenode *snap;
298174e7dc98SMatthew Ahrens 
298274e7dc98SMatthew Ahrens 	*spacep = 0;
298374e7dc98SMatthew Ahrens 	for (snap = list_head(l); snap; snap = list_next(l, snap)) {
2984cde58dbcSMatthew Ahrens 		uint64_t used, comp, uncomp;
2985cde58dbcSMatthew Ahrens 		dsl_deadlist_space_range(&snap->ds->ds_deadlist,
2986cde58dbcSMatthew Ahrens 		    mintxg, UINT64_MAX, &used, &comp, &uncomp);
298774e7dc98SMatthew Ahrens 		*spacep += used;
298874e7dc98SMatthew Ahrens 	}
298974e7dc98SMatthew Ahrens 	return (0);
299074e7dc98SMatthew Ahrens }
299174e7dc98SMatthew Ahrens 
299274e7dc98SMatthew Ahrens static void
299374e7dc98SMatthew Ahrens snaplist_destroy(list_t *l, boolean_t own)
299474e7dc98SMatthew Ahrens {
299574e7dc98SMatthew Ahrens 	struct promotenode *snap;
299674e7dc98SMatthew Ahrens 
29974f5064b7SMark J Musante 	if (!l || !list_link_active(&l->list_head))
299874e7dc98SMatthew Ahrens 		return;
299974e7dc98SMatthew Ahrens 
300074e7dc98SMatthew Ahrens 	while ((snap = list_tail(l)) != NULL) {
300174e7dc98SMatthew Ahrens 		list_remove(l, snap);
300274e7dc98SMatthew Ahrens 		if (own)
300374e7dc98SMatthew Ahrens 			dsl_dataset_disown(snap->ds, snaplist_tag);
300474e7dc98SMatthew Ahrens 		else
300574e7dc98SMatthew Ahrens 			dsl_dataset_rele(snap->ds, snaplist_tag);
300674e7dc98SMatthew Ahrens 		kmem_free(snap, sizeof (struct promotenode));
300774e7dc98SMatthew Ahrens 	}
300874e7dc98SMatthew Ahrens 	list_destroy(l);
300974e7dc98SMatthew Ahrens }
301074e7dc98SMatthew Ahrens 
301174e7dc98SMatthew Ahrens /*
301274e7dc98SMatthew Ahrens  * Promote a clone.  Nomenclature note:
301374e7dc98SMatthew Ahrens  * "clone" or "cds": the original clone which is being promoted
301474e7dc98SMatthew Ahrens  * "origin" or "ods": the snapshot which is originally clone's origin
301574e7dc98SMatthew Ahrens  * "origin head" or "ohds": the dataset which is the head
301674e7dc98SMatthew Ahrens  * (filesystem/volume) for the origin
301774e7dc98SMatthew Ahrens  * "origin origin": the origin of the origin's filesystem (typically
301874e7dc98SMatthew Ahrens  * NULL, indicating that the clone is not a clone of a clone).
301974e7dc98SMatthew Ahrens  */
302099653d4eSeschrock int
3021681d9761SEric Taylor dsl_dataset_promote(const char *name, char *conflsnap)
302299653d4eSeschrock {
302399653d4eSeschrock 	dsl_dataset_t *ds;
3024745cd3c5Smaybee 	dsl_dir_t *dd;
3025745cd3c5Smaybee 	dsl_pool_t *dp;
302699653d4eSeschrock 	dmu_object_info_t doi;
302774e7dc98SMatthew Ahrens 	struct promotearg pa = { 0 };
3028088f3894Sahrens 	struct promotenode *snap;
3029745cd3c5Smaybee 	int err;
303099653d4eSeschrock 
3031745cd3c5Smaybee 	err = dsl_dataset_hold(name, FTAG, &ds);
303299653d4eSeschrock 	if (err)
303399653d4eSeschrock 		return (err);
3034745cd3c5Smaybee 	dd = ds->ds_dir;
3035745cd3c5Smaybee 	dp = dd->dd_pool;
303699653d4eSeschrock 
3037745cd3c5Smaybee 	err = dmu_object_info(dp->dp_meta_objset,
303899653d4eSeschrock 	    ds->ds_phys->ds_snapnames_zapobj, &doi);
303999653d4eSeschrock 	if (err) {
3040745cd3c5Smaybee 		dsl_dataset_rele(ds, FTAG);
304199653d4eSeschrock 		return (err);
304299653d4eSeschrock 	}
304399653d4eSeschrock 
304474e7dc98SMatthew Ahrens 	if (dsl_dataset_is_snapshot(ds) || dd->dd_phys->dd_origin_obj == 0) {
304574e7dc98SMatthew Ahrens 		dsl_dataset_rele(ds, FTAG);
304674e7dc98SMatthew Ahrens 		return (EINVAL);
304774e7dc98SMatthew Ahrens 	}
304874e7dc98SMatthew Ahrens 
3049745cd3c5Smaybee 	/*
3050745cd3c5Smaybee 	 * We are going to inherit all the snapshots taken before our
3051745cd3c5Smaybee 	 * origin (i.e., our new origin will be our parent's origin).
3052745cd3c5Smaybee 	 * Take ownership of them so that we can rename them into our
3053745cd3c5Smaybee 	 * namespace.
3054745cd3c5Smaybee 	 */
3055745cd3c5Smaybee 	rw_enter(&dp->dp_config_rwlock, RW_READER);
3056088f3894Sahrens 
305774e7dc98SMatthew Ahrens 	err = snaplist_make(dp, B_TRUE, 0, dd->dd_phys->dd_origin_obj,
305874e7dc98SMatthew Ahrens 	    &pa.shared_snaps);
305974e7dc98SMatthew Ahrens 	if (err != 0)
306074e7dc98SMatthew Ahrens 		goto out;
3061088f3894Sahrens 
306274e7dc98SMatthew Ahrens 	err = snaplist_make(dp, B_FALSE, 0, ds->ds_object, &pa.clone_snaps);
306374e7dc98SMatthew Ahrens 	if (err != 0)
306474e7dc98SMatthew Ahrens 		goto out;
3065088f3894Sahrens 
306674e7dc98SMatthew Ahrens 	snap = list_head(&pa.shared_snaps);
306774e7dc98SMatthew Ahrens 	ASSERT3U(snap->ds->ds_object, ==, dd->dd_phys->dd_origin_obj);
306874e7dc98SMatthew Ahrens 	err = snaplist_make(dp, B_FALSE, dd->dd_phys->dd_origin_obj,
306974e7dc98SMatthew Ahrens 	    snap->ds->ds_dir->dd_phys->dd_head_dataset_obj, &pa.origin_snaps);
307074e7dc98SMatthew Ahrens 	if (err != 0)
307174e7dc98SMatthew Ahrens 		goto out;
3072088f3894Sahrens 
3073cde58dbcSMatthew Ahrens 	if (snap->ds->ds_dir->dd_phys->dd_origin_obj != 0) {
3074cde58dbcSMatthew Ahrens 		err = dsl_dataset_hold_obj(dp,
307574e7dc98SMatthew Ahrens 		    snap->ds->ds_dir->dd_phys->dd_origin_obj,
3076cde58dbcSMatthew Ahrens 		    FTAG, &pa.origin_origin);
307774e7dc98SMatthew Ahrens 		if (err != 0)
307874e7dc98SMatthew Ahrens 			goto out;
307974e7dc98SMatthew Ahrens 	}
3080745cd3c5Smaybee 
308174e7dc98SMatthew Ahrens out:
308274e7dc98SMatthew Ahrens 	rw_exit(&dp->dp_config_rwlock);
3083745cd3c5Smaybee 
308499653d4eSeschrock 	/*
308599653d4eSeschrock 	 * Add in 128x the snapnames zapobj size, since we will be moving
308699653d4eSeschrock 	 * a bunch of snapnames to the promoted ds, and dirtying their
308799653d4eSeschrock 	 * bonus buffers.
308899653d4eSeschrock 	 */
308974e7dc98SMatthew Ahrens 	if (err == 0) {
309074e7dc98SMatthew Ahrens 		err = dsl_sync_task_do(dp, dsl_dataset_promote_check,
309174e7dc98SMatthew Ahrens 		    dsl_dataset_promote_sync, ds, &pa,
3092b24ab676SJeff Bonwick 		    2 + 2 * doi.doi_physical_blocks_512);
3093681d9761SEric Taylor 		if (err && pa.err_ds && conflsnap)
3094681d9761SEric Taylor 			(void) strncpy(conflsnap, pa.err_ds, MAXNAMELEN);
3095745cd3c5Smaybee 	}
309674e7dc98SMatthew Ahrens 
309774e7dc98SMatthew Ahrens 	snaplist_destroy(&pa.shared_snaps, B_TRUE);
309874e7dc98SMatthew Ahrens 	snaplist_destroy(&pa.clone_snaps, B_FALSE);
309974e7dc98SMatthew Ahrens 	snaplist_destroy(&pa.origin_snaps, B_FALSE);
310074e7dc98SMatthew Ahrens 	if (pa.origin_origin)
3101cde58dbcSMatthew Ahrens 		dsl_dataset_rele(pa.origin_origin, FTAG);
3102745cd3c5Smaybee 	dsl_dataset_rele(ds, FTAG);
310399653d4eSeschrock 	return (err);
310499653d4eSeschrock }
3105b1b8ab34Slling 
31063cb34c60Sahrens struct cloneswaparg {
31073cb34c60Sahrens 	dsl_dataset_t *cds; /* clone dataset */
31083cb34c60Sahrens 	dsl_dataset_t *ohds; /* origin's head dataset */
31093cb34c60Sahrens 	boolean_t force;
3110a9b821a0Sck 	int64_t unused_refres_delta; /* change in unconsumed refreservation */
31113cb34c60Sahrens };
3112f18faf3fSek 
3113f18faf3fSek /* ARGSUSED */
3114f18faf3fSek static int
3115f18faf3fSek dsl_dataset_clone_swap_check(void *arg1, void *arg2, dmu_tx_t *tx)
3116f18faf3fSek {
31173cb34c60Sahrens 	struct cloneswaparg *csa = arg1;
3118f18faf3fSek 
31193cb34c60Sahrens 	/* they should both be heads */
31203cb34c60Sahrens 	if (dsl_dataset_is_snapshot(csa->cds) ||
31213cb34c60Sahrens 	    dsl_dataset_is_snapshot(csa->ohds))
3122f18faf3fSek 		return (EINVAL);
3123f18faf3fSek 
31243cb34c60Sahrens 	/* the branch point should be just before them */
31253cb34c60Sahrens 	if (csa->cds->ds_prev != csa->ohds->ds_prev)
3126f18faf3fSek 		return (EINVAL);
3127f18faf3fSek 
3128ae46e4c7SMatthew Ahrens 	/* cds should be the clone (unless they are unrelated) */
3129ae46e4c7SMatthew Ahrens 	if (csa->cds->ds_prev != NULL &&
3130ae46e4c7SMatthew Ahrens 	    csa->cds->ds_prev != csa->cds->ds_dir->dd_pool->dp_origin_snap &&
3131ae46e4c7SMatthew Ahrens 	    csa->ohds->ds_object !=
3132ae46e4c7SMatthew Ahrens 	    csa->cds->ds_prev->ds_phys->ds_next_snap_obj)
31333cb34c60Sahrens 		return (EINVAL);
3134f18faf3fSek 
31353cb34c60Sahrens 	/* the clone should be a child of the origin */
31363cb34c60Sahrens 	if (csa->cds->ds_dir->dd_parent != csa->ohds->ds_dir)
31373cb34c60Sahrens 		return (EINVAL);
3138f18faf3fSek 
31393cb34c60Sahrens 	/* ohds shouldn't be modified unless 'force' */
31403cb34c60Sahrens 	if (!csa->force && dsl_dataset_modified_since_lastsnap(csa->ohds))
31413cb34c60Sahrens 		return (ETXTBSY);
3142a9b821a0Sck 
3143a9b821a0Sck 	/* adjust amount of any unconsumed refreservation */
3144a9b821a0Sck 	csa->unused_refres_delta =
3145a9b821a0Sck 	    (int64_t)MIN(csa->ohds->ds_reserved,
3146a9b821a0Sck 	    csa->ohds->ds_phys->ds_unique_bytes) -
3147a9b821a0Sck 	    (int64_t)MIN(csa->ohds->ds_reserved,
3148a9b821a0Sck 	    csa->cds->ds_phys->ds_unique_bytes);
3149a9b821a0Sck 
3150a9b821a0Sck 	if (csa->unused_refres_delta > 0 &&
3151a9b821a0Sck 	    csa->unused_refres_delta >
3152a9b821a0Sck 	    dsl_dir_space_available(csa->ohds->ds_dir, NULL, 0, TRUE))
3153a9b821a0Sck 		return (ENOSPC);
3154a9b821a0Sck 
3155c4cbca4fSChris Kirby 	if (csa->ohds->ds_quota != 0 &&
3156c4cbca4fSChris Kirby 	    csa->cds->ds_phys->ds_unique_bytes > csa->ohds->ds_quota)
3157c4cbca4fSChris Kirby 		return (EDQUOT);
3158c4cbca4fSChris Kirby 
31593cb34c60Sahrens 	return (0);
3160f18faf3fSek }
3161f18faf3fSek 
3162f18faf3fSek /* ARGSUSED */
3163f18faf3fSek static void
31643f9d6ad7SLin Ling dsl_dataset_clone_swap_sync(void *arg1, void *arg2, dmu_tx_t *tx)
3165f18faf3fSek {
31663cb34c60Sahrens 	struct cloneswaparg *csa = arg1;
31673cb34c60Sahrens 	dsl_pool_t *dp = csa->cds->ds_dir->dd_pool;
3168f18faf3fSek 
3169a9b821a0Sck 	ASSERT(csa->cds->ds_reserved == 0);
3170c4cbca4fSChris Kirby 	ASSERT(csa->ohds->ds_quota == 0 ||
3171c4cbca4fSChris Kirby 	    csa->cds->ds_phys->ds_unique_bytes <= csa->ohds->ds_quota);
3172a9b821a0Sck 
31733cb34c60Sahrens 	dmu_buf_will_dirty(csa->cds->ds_dbuf, tx);
31743cb34c60Sahrens 	dmu_buf_will_dirty(csa->ohds->ds_dbuf, tx);
3175f18faf3fSek 
3176503ad85cSMatthew Ahrens 	if (csa->cds->ds_objset != NULL) {
3177503ad85cSMatthew Ahrens 		dmu_objset_evict(csa->cds->ds_objset);
3178503ad85cSMatthew Ahrens 		csa->cds->ds_objset = NULL;
31793cb34c60Sahrens 	}
3180f18faf3fSek 
3181503ad85cSMatthew Ahrens 	if (csa->ohds->ds_objset != NULL) {
3182503ad85cSMatthew Ahrens 		dmu_objset_evict(csa->ohds->ds_objset);
3183503ad85cSMatthew Ahrens 		csa->ohds->ds_objset = NULL;
31843cb34c60Sahrens 	}
3185f18faf3fSek 
3186ae46e4c7SMatthew Ahrens 	/*
3187ae46e4c7SMatthew Ahrens 	 * Reset origin's unique bytes, if it exists.
3188ae46e4c7SMatthew Ahrens 	 */
3189ae46e4c7SMatthew Ahrens 	if (csa->cds->ds_prev) {
3190ae46e4c7SMatthew Ahrens 		dsl_dataset_t *origin = csa->cds->ds_prev;
3191cde58dbcSMatthew Ahrens 		uint64_t comp, uncomp;
3192cde58dbcSMatthew Ahrens 
3193ae46e4c7SMatthew Ahrens 		dmu_buf_will_dirty(origin->ds_dbuf, tx);
3194cde58dbcSMatthew Ahrens 		dsl_deadlist_space_range(&csa->cds->ds_deadlist,
3195ae46e4c7SMatthew Ahrens 		    origin->ds_phys->ds_prev_snap_txg, UINT64_MAX,
3196cde58dbcSMatthew Ahrens 		    &origin->ds_phys->ds_unique_bytes, &comp, &uncomp);
3197ae46e4c7SMatthew Ahrens 	}
3198f18faf3fSek 
3199f18faf3fSek 	/* swap blkptrs */
3200f18faf3fSek 	{
3201f18faf3fSek 		blkptr_t tmp;
32023cb34c60Sahrens 		tmp = csa->ohds->ds_phys->ds_bp;
32033cb34c60Sahrens 		csa->ohds->ds_phys->ds_bp = csa->cds->ds_phys->ds_bp;
32043cb34c60Sahrens 		csa->cds->ds_phys->ds_bp = tmp;
3205f18faf3fSek 	}
3206f18faf3fSek 
3207f18faf3fSek 	/* set dd_*_bytes */
3208f18faf3fSek 	{
3209f18faf3fSek 		int64_t dused, dcomp, duncomp;
3210f18faf3fSek 		uint64_t cdl_used, cdl_comp, cdl_uncomp;
3211f18faf3fSek 		uint64_t odl_used, odl_comp, odl_uncomp;
3212f18faf3fSek 
321374e7dc98SMatthew Ahrens 		ASSERT3U(csa->cds->ds_dir->dd_phys->
321474e7dc98SMatthew Ahrens 		    dd_used_breakdown[DD_USED_SNAP], ==, 0);
321574e7dc98SMatthew Ahrens 
3216cde58dbcSMatthew Ahrens 		dsl_deadlist_space(&csa->cds->ds_deadlist,
3217cde58dbcSMatthew Ahrens 		    &cdl_used, &cdl_comp, &cdl_uncomp);
3218cde58dbcSMatthew Ahrens 		dsl_deadlist_space(&csa->ohds->ds_deadlist,
3219cde58dbcSMatthew Ahrens 		    &odl_used, &odl_comp, &odl_uncomp);
322074e7dc98SMatthew Ahrens 
3221ad135b5dSChristopher Siden 		dused = csa->cds->ds_phys->ds_referenced_bytes + cdl_used -
3222ad135b5dSChristopher Siden 		    (csa->ohds->ds_phys->ds_referenced_bytes + odl_used);
32233cb34c60Sahrens 		dcomp = csa->cds->ds_phys->ds_compressed_bytes + cdl_comp -
32243cb34c60Sahrens 		    (csa->ohds->ds_phys->ds_compressed_bytes + odl_comp);
32253cb34c60Sahrens 		duncomp = csa->cds->ds_phys->ds_uncompressed_bytes +
32263cb34c60Sahrens 		    cdl_uncomp -
32273cb34c60Sahrens 		    (csa->ohds->ds_phys->ds_uncompressed_bytes + odl_uncomp);
32283cb34c60Sahrens 
322974e7dc98SMatthew Ahrens 		dsl_dir_diduse_space(csa->ohds->ds_dir, DD_USED_HEAD,
32303cb34c60Sahrens 		    dused, dcomp, duncomp, tx);
323174e7dc98SMatthew Ahrens 		dsl_dir_diduse_space(csa->cds->ds_dir, DD_USED_HEAD,
32323cb34c60Sahrens 		    -dused, -dcomp, -duncomp, tx);
323374e7dc98SMatthew Ahrens 
323474e7dc98SMatthew Ahrens 		/*
323574e7dc98SMatthew Ahrens 		 * The difference in the space used by snapshots is the
323674e7dc98SMatthew Ahrens 		 * difference in snapshot space due to the head's
323774e7dc98SMatthew Ahrens 		 * deadlist (since that's the only thing that's
323874e7dc98SMatthew Ahrens 		 * changing that affects the snapused).
323974e7dc98SMatthew Ahrens 		 */
3240cde58dbcSMatthew Ahrens 		dsl_deadlist_space_range(&csa->cds->ds_deadlist,
3241cde58dbcSMatthew Ahrens 		    csa->ohds->ds_dir->dd_origin_txg, UINT64_MAX,
3242cde58dbcSMatthew Ahrens 		    &cdl_used, &cdl_comp, &cdl_uncomp);
3243cde58dbcSMatthew Ahrens 		dsl_deadlist_space_range(&csa->ohds->ds_deadlist,
3244cde58dbcSMatthew Ahrens 		    csa->ohds->ds_dir->dd_origin_txg, UINT64_MAX,
3245cde58dbcSMatthew Ahrens 		    &odl_used, &odl_comp, &odl_uncomp);
324674e7dc98SMatthew Ahrens 		dsl_dir_transfer_space(csa->ohds->ds_dir, cdl_used - odl_used,
324774e7dc98SMatthew Ahrens 		    DD_USED_HEAD, DD_USED_SNAP, tx);
32483cb34c60Sahrens 	}
32493cb34c60Sahrens 
3250f18faf3fSek 	/* swap ds_*_bytes */
3251ad135b5dSChristopher Siden 	SWITCH64(csa->ohds->ds_phys->ds_referenced_bytes,
3252ad135b5dSChristopher Siden 	    csa->cds->ds_phys->ds_referenced_bytes);
32533cb34c60Sahrens 	SWITCH64(csa->ohds->ds_phys->ds_compressed_bytes,
32543cb34c60Sahrens 	    csa->cds->ds_phys->ds_compressed_bytes);
32553cb34c60Sahrens 	SWITCH64(csa->ohds->ds_phys->ds_uncompressed_bytes,
32563cb34c60Sahrens 	    csa->cds->ds_phys->ds_uncompressed_bytes);
3257a9b821a0Sck 	SWITCH64(csa->ohds->ds_phys->ds_unique_bytes,
3258a9b821a0Sck 	    csa->cds->ds_phys->ds_unique_bytes);
3259a9b821a0Sck 
3260a9b821a0Sck 	/* apply any parent delta for change in unconsumed refreservation */
326174e7dc98SMatthew Ahrens 	dsl_dir_diduse_space(csa->ohds->ds_dir, DD_USED_REFRSRV,
326274e7dc98SMatthew Ahrens 	    csa->unused_refres_delta, 0, 0, tx);
3263f18faf3fSek 
3264cde58dbcSMatthew Ahrens 	/*
3265cde58dbcSMatthew Ahrens 	 * Swap deadlists.
3266cde58dbcSMatthew Ahrens 	 */
3267cde58dbcSMatthew Ahrens 	dsl_deadlist_close(&csa->cds->ds_deadlist);
3268cde58dbcSMatthew Ahrens 	dsl_deadlist_close(&csa->ohds->ds_deadlist);
32693cb34c60Sahrens 	SWITCH64(csa->ohds->ds_phys->ds_deadlist_obj,
32703cb34c60Sahrens 	    csa->cds->ds_phys->ds_deadlist_obj);
3271cde58dbcSMatthew Ahrens 	dsl_deadlist_open(&csa->cds->ds_deadlist, dp->dp_meta_objset,
3272cde58dbcSMatthew Ahrens 	    csa->cds->ds_phys->ds_deadlist_obj);
3273cde58dbcSMatthew Ahrens 	dsl_deadlist_open(&csa->ohds->ds_deadlist, dp->dp_meta_objset,
3274cde58dbcSMatthew Ahrens 	    csa->ohds->ds_phys->ds_deadlist_obj);
327588b7b0f2SMatthew Ahrens 
32763f9d6ad7SLin Ling 	dsl_scan_ds_clone_swapped(csa->ohds, csa->cds, tx);
32774445fffbSMatthew Ahrens 
32784445fffbSMatthew Ahrens 	spa_history_log_internal_ds(csa->cds, "clone swap", tx,
32794445fffbSMatthew Ahrens 	    "parent=%s", csa->ohds->ds_dir->dd_myname);
3280f18faf3fSek }
3281f18faf3fSek 
3282f18faf3fSek /*
3283ae46e4c7SMatthew Ahrens  * Swap 'clone' with its origin head datasets.  Used at the end of "zfs
3284ae46e4c7SMatthew Ahrens  * recv" into an existing fs to swizzle the file system to the new
3285ae46e4c7SMatthew Ahrens  * version, and by "zfs rollback".  Can also be used to swap two
3286ae46e4c7SMatthew Ahrens  * independent head datasets if neither has any snapshots.
3287f18faf3fSek  */
3288f18faf3fSek int
32893cb34c60Sahrens dsl_dataset_clone_swap(dsl_dataset_t *clone, dsl_dataset_t *origin_head,
32903cb34c60Sahrens     boolean_t force)
3291f18faf3fSek {
32923cb34c60Sahrens 	struct cloneswaparg csa;
3293745cd3c5Smaybee 	int error;
3294f18faf3fSek 
3295745cd3c5Smaybee 	ASSERT(clone->ds_owner);
3296745cd3c5Smaybee 	ASSERT(origin_head->ds_owner);
3297745cd3c5Smaybee retry:
329877972028SChris Kirby 	/*
329977972028SChris Kirby 	 * Need exclusive access for the swap. If we're swapping these
330077972028SChris Kirby 	 * datasets back after an error, we already hold the locks.
330177972028SChris Kirby 	 */
330277972028SChris Kirby 	if (!RW_WRITE_HELD(&clone->ds_rwlock))
330377972028SChris Kirby 		rw_enter(&clone->ds_rwlock, RW_WRITER);
330477972028SChris Kirby 	if (!RW_WRITE_HELD(&origin_head->ds_rwlock) &&
330577972028SChris Kirby 	    !rw_tryenter(&origin_head->ds_rwlock, RW_WRITER)) {
3306745cd3c5Smaybee 		rw_exit(&clone->ds_rwlock);
3307745cd3c5Smaybee 		rw_enter(&origin_head->ds_rwlock, RW_WRITER);
3308745cd3c5Smaybee 		if (!rw_tryenter(&clone->ds_rwlock, RW_WRITER)) {
3309745cd3c5Smaybee 			rw_exit(&origin_head->ds_rwlock);
3310745cd3c5Smaybee 			goto retry;
3311745cd3c5Smaybee 		}
3312745cd3c5Smaybee 	}
33133cb34c60Sahrens 	csa.cds = clone;
33143cb34c60Sahrens 	csa.ohds = origin_head;
33153cb34c60Sahrens 	csa.force = force;
3316745cd3c5Smaybee 	error = dsl_sync_task_do(clone->ds_dir->dd_pool,
3317f18faf3fSek 	    dsl_dataset_clone_swap_check,
3318745cd3c5Smaybee 	    dsl_dataset_clone_swap_sync, &csa, NULL, 9);
3319745cd3c5Smaybee 	return (error);
3320f18faf3fSek }
3321f18faf3fSek 
3322b1b8ab34Slling /*
3323b1b8ab34Slling  * Given a pool name and a dataset object number in that pool,
3324b1b8ab34Slling  * return the name of that dataset.
3325b1b8ab34Slling  */
3326b1b8ab34Slling int
3327b1b8ab34Slling dsl_dsobj_to_dsname(char *pname, uint64_t obj, char *buf)
3328b1b8ab34Slling {
3329b1b8ab34Slling 	spa_t *spa;
3330b1b8ab34Slling 	dsl_pool_t *dp;
3331745cd3c5Smaybee 	dsl_dataset_t *ds;
3332b1b8ab34Slling 	int error;
3333b1b8ab34Slling 
3334b1b8ab34Slling 	if ((error = spa_open(pname, &spa, FTAG)) != 0)
3335b1b8ab34Slling 		return (error);
3336b1b8ab34Slling 	dp = spa_get_dsl(spa);
3337b1b8ab34Slling 	rw_enter(&dp->dp_config_rwlock, RW_READER);
3338745cd3c5Smaybee 	if ((error = dsl_dataset_hold_obj(dp, obj, FTAG, &ds)) == 0) {
3339745cd3c5Smaybee 		dsl_dataset_name(ds, buf);
3340745cd3c5Smaybee 		dsl_dataset_rele(ds, FTAG);
3341b1b8ab34Slling 	}
3342b1b8ab34Slling 	rw_exit(&dp->dp_config_rwlock);
3343b1b8ab34Slling 	spa_close(spa, FTAG);
3344b1b8ab34Slling 
3345745cd3c5Smaybee 	return (error);
3346b1b8ab34Slling }
3347a9799022Sck 
3348a9799022Sck int
3349a9799022Sck dsl_dataset_check_quota(dsl_dataset_t *ds, boolean_t check_quota,
3350745cd3c5Smaybee     uint64_t asize, uint64_t inflight, uint64_t *used, uint64_t *ref_rsrv)
3351a9799022Sck {
3352a9799022Sck 	int error = 0;
3353a9799022Sck 
3354a9799022Sck 	ASSERT3S(asize, >, 0);
3355a9799022Sck 
33569082849eSck 	/*
33579082849eSck 	 * *ref_rsrv is the portion of asize that will come from any
33589082849eSck 	 * unconsumed refreservation space.
33599082849eSck 	 */
33609082849eSck 	*ref_rsrv = 0;
33619082849eSck 
3362a9799022Sck 	mutex_enter(&ds->ds_lock);
3363a9799022Sck 	/*
3364a9799022Sck 	 * Make a space adjustment for reserved bytes.
3365a9799022Sck 	 */
3366a9799022Sck 	if (ds->ds_reserved > ds->ds_phys->ds_unique_bytes) {
3367a9799022Sck 		ASSERT3U(*used, >=,
3368a9799022Sck 		    ds->ds_reserved - ds->ds_phys->ds_unique_bytes);
3369a9799022Sck 		*used -= (ds->ds_reserved - ds->ds_phys->ds_unique_bytes);
33709082849eSck 		*ref_rsrv =
33719082849eSck 		    asize - MIN(asize, parent_delta(ds, asize + inflight));
3372a9799022Sck 	}
3373a9799022Sck 
3374a9799022Sck 	if (!check_quota || ds->ds_quota == 0) {
3375a9799022Sck 		mutex_exit(&ds->ds_lock);
3376a9799022Sck 		return (0);
3377a9799022Sck 	}
3378a9799022Sck 	/*
3379a9799022Sck 	 * If they are requesting more space, and our current estimate
3380a9799022Sck 	 * is over quota, they get to try again unless the actual
3381a9799022Sck 	 * on-disk is over quota and there are no pending changes (which
3382a9799022Sck 	 * may free up space for us).
3383a9799022Sck 	 */
3384ad135b5dSChristopher Siden 	if (ds->ds_phys->ds_referenced_bytes + inflight >= ds->ds_quota) {
3385ad135b5dSChristopher Siden 		if (inflight > 0 ||
3386ad135b5dSChristopher Siden 		    ds->ds_phys->ds_referenced_bytes < ds->ds_quota)
3387a9799022Sck 			error = ERESTART;
3388a9799022Sck 		else
3389a9799022Sck 			error = EDQUOT;
3390a9799022Sck 	}
3391a9799022Sck 	mutex_exit(&ds->ds_lock);
3392a9799022Sck 
3393a9799022Sck 	return (error);
3394a9799022Sck }
3395a9799022Sck 
3396a9799022Sck /* ARGSUSED */
3397a9799022Sck static int
3398a9799022Sck dsl_dataset_set_quota_check(void *arg1, void *arg2, dmu_tx_t *tx)
3399a9799022Sck {
3400a9799022Sck 	dsl_dataset_t *ds = arg1;
340192241e0bSTom Erickson 	dsl_prop_setarg_t *psa = arg2;
340292241e0bSTom Erickson 	int err;
3403a9799022Sck 
3404a9799022Sck 	if (spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_REFQUOTA)
3405a9799022Sck 		return (ENOTSUP);
3406a9799022Sck 
340792241e0bSTom Erickson 	if ((err = dsl_prop_predict_sync(ds->ds_dir, psa)) != 0)
340892241e0bSTom Erickson 		return (err);
340992241e0bSTom Erickson 
341092241e0bSTom Erickson 	if (psa->psa_effective_value == 0)
3411a9799022Sck 		return (0);
3412a9799022Sck 
3413ad135b5dSChristopher Siden 	if (psa->psa_effective_value < ds->ds_phys->ds_referenced_bytes ||
341492241e0bSTom Erickson 	    psa->psa_effective_value < ds->ds_reserved)
3415a9799022Sck 		return (ENOSPC);
3416a9799022Sck 
3417a9799022Sck 	return (0);
3418a9799022Sck }
3419a9799022Sck 
34203f9d6ad7SLin Ling extern void dsl_prop_set_sync(void *, void *, dmu_tx_t *);
342192241e0bSTom Erickson 
3422a9799022Sck void
34233f9d6ad7SLin Ling dsl_dataset_set_quota_sync(void *arg1, void *arg2, dmu_tx_t *tx)
3424a9799022Sck {
3425a9799022Sck 	dsl_dataset_t *ds = arg1;
342692241e0bSTom Erickson 	dsl_prop_setarg_t *psa = arg2;
342792241e0bSTom Erickson 	uint64_t effective_value = psa->psa_effective_value;
3428a9799022Sck 
34293f9d6ad7SLin Ling 	dsl_prop_set_sync(ds, psa, tx);
343092241e0bSTom Erickson 	DSL_PROP_CHECK_PREDICTION(ds->ds_dir, psa);
3431a9799022Sck 
343292241e0bSTom Erickson 	if (ds->ds_quota != effective_value) {
343392241e0bSTom Erickson 		dmu_buf_will_dirty(ds->ds_dbuf, tx);
343492241e0bSTom Erickson 		ds->ds_quota = effective_value;
3435a9799022Sck 
34364445fffbSMatthew Ahrens 		spa_history_log_internal_ds(ds, "set refquota", tx,
34374445fffbSMatthew Ahrens 		    "refquota=%lld", (longlong_t)ds->ds_quota);
343892241e0bSTom Erickson 	}
3439a9799022Sck }
3440a9799022Sck 
3441a9799022Sck int
344292241e0bSTom Erickson dsl_dataset_set_quota(const char *dsname, zprop_source_t source, uint64_t quota)
3443a9799022Sck {
3444a9799022Sck 	dsl_dataset_t *ds;
344592241e0bSTom Erickson 	dsl_prop_setarg_t psa;
3446a9799022Sck 	int err;
3447a9799022Sck 
344892241e0bSTom Erickson 	dsl_prop_setarg_init_uint64(&psa, "refquota", source, &quota);
344992241e0bSTom Erickson 
3450745cd3c5Smaybee 	err = dsl_dataset_hold(dsname, FTAG, &ds);
3451a9799022Sck 	if (err)
3452a9799022Sck 		return (err);
3453a9799022Sck 
345492241e0bSTom Erickson 	/*
345592241e0bSTom Erickson 	 * If someone removes a file, then tries to set the quota, we
345692241e0bSTom Erickson 	 * want to make sure the file freeing takes effect.
345792241e0bSTom Erickson 	 */
345892241e0bSTom Erickson 	txg_wait_open(ds->ds_dir->dd_pool, 0);
345992241e0bSTom Erickson 
346092241e0bSTom Erickson 	err = dsl_sync_task_do(ds->ds_dir->dd_pool,
346192241e0bSTom Erickson 	    dsl_dataset_set_quota_check, dsl_dataset_set_quota_sync,
346292241e0bSTom Erickson 	    ds, &psa, 0);
3463a9799022Sck 
3464745cd3c5Smaybee 	dsl_dataset_rele(ds, FTAG);
3465a9799022Sck 	return (err);
3466a9799022Sck }
3467a9799022Sck 
3468a9799022Sck static int
3469a9799022Sck dsl_dataset_set_reservation_check(void *arg1, void *arg2, dmu_tx_t *tx)
3470a9799022Sck {
3471a9799022Sck 	dsl_dataset_t *ds = arg1;
347292241e0bSTom Erickson 	dsl_prop_setarg_t *psa = arg2;
347392241e0bSTom Erickson 	uint64_t effective_value;
3474a9799022Sck 	uint64_t unique;
347592241e0bSTom Erickson 	int err;
3476a9799022Sck 
3477a9799022Sck 	if (spa_version(ds->ds_dir->dd_pool->dp_spa) <
3478a9799022Sck 	    SPA_VERSION_REFRESERVATION)
3479a9799022Sck 		return (ENOTSUP);
3480a9799022Sck 
3481a9799022Sck 	if (dsl_dataset_is_snapshot(ds))
3482a9799022Sck 		return (EINVAL);
3483a9799022Sck 
348492241e0bSTom Erickson 	if ((err = dsl_prop_predict_sync(ds->ds_dir, psa)) != 0)
348592241e0bSTom Erickson 		return (err);
348692241e0bSTom Erickson 
348792241e0bSTom Erickson 	effective_value = psa->psa_effective_value;
348892241e0bSTom Erickson 
3489a9799022Sck 	/*
3490a9799022Sck 	 * If we are doing the preliminary check in open context, the
3491a9799022Sck 	 * space estimates may be inaccurate.
3492a9799022Sck 	 */
3493a9799022Sck 	if (!dmu_tx_is_syncing(tx))
3494a9799022Sck 		return (0);
3495a9799022Sck 
3496a9799022Sck 	mutex_enter(&ds->ds_lock);
34973f9d6ad7SLin Ling 	if (!DS_UNIQUE_IS_ACCURATE(ds))
34983f9d6ad7SLin Ling 		dsl_dataset_recalc_head_uniq(ds);
34993f9d6ad7SLin Ling 	unique = ds->ds_phys->ds_unique_bytes;
3500a9799022Sck 	mutex_exit(&ds->ds_lock);
3501a9799022Sck 
350292241e0bSTom Erickson 	if (MAX(unique, effective_value) > MAX(unique, ds->ds_reserved)) {
350392241e0bSTom Erickson 		uint64_t delta = MAX(unique, effective_value) -
3504379c004dSEric Schrock 		    MAX(unique, ds->ds_reserved);
3505379c004dSEric Schrock 
3506379c004dSEric Schrock 		if (delta > dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE))
3507379c004dSEric Schrock 			return (ENOSPC);
3508379c004dSEric Schrock 		if (ds->ds_quota > 0 &&
350992241e0bSTom Erickson 		    effective_value > ds->ds_quota)
3510379c004dSEric Schrock 			return (ENOSPC);
3511379c004dSEric Schrock 	}
3512a9799022Sck 
3513a9799022Sck 	return (0);
3514a9799022Sck }
3515a9799022Sck 
3516a9799022Sck static void
35173f9d6ad7SLin Ling dsl_dataset_set_reservation_sync(void *arg1, void *arg2, dmu_tx_t *tx)
3518a9799022Sck {
3519a9799022Sck 	dsl_dataset_t *ds = arg1;
352092241e0bSTom Erickson 	dsl_prop_setarg_t *psa = arg2;
352192241e0bSTom Erickson 	uint64_t effective_value = psa->psa_effective_value;
352202c8f3f0SMatthew Ahrens 	uint64_t unique;
352302c8f3f0SMatthew Ahrens 	int64_t delta;
352402c8f3f0SMatthew Ahrens 
35253f9d6ad7SLin Ling 	dsl_prop_set_sync(ds, psa, tx);
352692241e0bSTom Erickson 	DSL_PROP_CHECK_PREDICTION(ds->ds_dir, psa);
352792241e0bSTom Erickson 
352802c8f3f0SMatthew Ahrens 	dmu_buf_will_dirty(ds->ds_dbuf, tx);
352902c8f3f0SMatthew Ahrens 
353002c8f3f0SMatthew Ahrens 	mutex_enter(&ds->ds_dir->dd_lock);
353102c8f3f0SMatthew Ahrens 	mutex_enter(&ds->ds_lock);
35323f9d6ad7SLin Ling 	ASSERT(DS_UNIQUE_IS_ACCURATE(ds));
35333f9d6ad7SLin Ling 	unique = ds->ds_phys->ds_unique_bytes;
353492241e0bSTom Erickson 	delta = MAX(0, (int64_t)(effective_value - unique)) -
353502c8f3f0SMatthew Ahrens 	    MAX(0, (int64_t)(ds->ds_reserved - unique));
353692241e0bSTom Erickson 	ds->ds_reserved = effective_value;
353702c8f3f0SMatthew Ahrens 	mutex_exit(&ds->ds_lock);
353802c8f3f0SMatthew Ahrens 
353902c8f3f0SMatthew Ahrens 	dsl_dir_diduse_space(ds->ds_dir, DD_USED_REFRSRV, delta, 0, 0, tx);
354002c8f3f0SMatthew Ahrens 	mutex_exit(&ds->ds_dir->dd_lock);
3541a9799022Sck 
35424445fffbSMatthew Ahrens 	spa_history_log_internal_ds(ds, "set refreservation", tx,
35434445fffbSMatthew Ahrens 	    "refreservation=%lld", (longlong_t)effective_value);
3544a9799022Sck }
3545a9799022Sck 
3546a9799022Sck int
354792241e0bSTom Erickson dsl_dataset_set_reservation(const char *dsname, zprop_source_t source,
354892241e0bSTom Erickson     uint64_t reservation)
3549a9799022Sck {
3550a9799022Sck 	dsl_dataset_t *ds;
355192241e0bSTom Erickson 	dsl_prop_setarg_t psa;
3552a9799022Sck 	int err;
3553a9799022Sck 
355492241e0bSTom Erickson 	dsl_prop_setarg_init_uint64(&psa, "refreservation", source,
355592241e0bSTom Erickson 	    &reservation);
355692241e0bSTom Erickson 
3557745cd3c5Smaybee 	err = dsl_dataset_hold(dsname, FTAG, &ds);
3558a9799022Sck 	if (err)
3559a9799022Sck 		return (err);
3560a9799022Sck 
3561a9799022Sck 	err = dsl_sync_task_do(ds->ds_dir->dd_pool,
3562a9799022Sck 	    dsl_dataset_set_reservation_check,
356392241e0bSTom Erickson 	    dsl_dataset_set_reservation_sync, ds, &psa, 0);
356492241e0bSTom Erickson 
3565745cd3c5Smaybee 	dsl_dataset_rele(ds, FTAG);
3566a9799022Sck 	return (err);
3567a9799022Sck }
3568842727c2SChris Kirby 
3569c99e4bdcSChris Kirby typedef struct zfs_hold_cleanup_arg {
3570a7f53a56SChris Kirby 	dsl_pool_t *dp;
3571a7f53a56SChris Kirby 	uint64_t dsobj;
3572c99e4bdcSChris Kirby 	char htag[MAXNAMELEN];
3573c99e4bdcSChris Kirby } zfs_hold_cleanup_arg_t;
3574c99e4bdcSChris Kirby 
3575c99e4bdcSChris Kirby static void
3576c99e4bdcSChris Kirby dsl_dataset_user_release_onexit(void *arg)
3577c99e4bdcSChris Kirby {
3578c99e4bdcSChris Kirby 	zfs_hold_cleanup_arg_t *ca = arg;
3579c99e4bdcSChris Kirby 
3580a7f53a56SChris Kirby 	(void) dsl_dataset_user_release_tmp(ca->dp, ca->dsobj, ca->htag,
3581a7f53a56SChris Kirby 	    B_TRUE);
3582c99e4bdcSChris Kirby 	kmem_free(ca, sizeof (zfs_hold_cleanup_arg_t));
3583c99e4bdcSChris Kirby }
3584c99e4bdcSChris Kirby 
3585a7f53a56SChris Kirby void
3586a7f53a56SChris Kirby dsl_register_onexit_hold_cleanup(dsl_dataset_t *ds, const char *htag,
3587a7f53a56SChris Kirby     minor_t minor)
3588a7f53a56SChris Kirby {
3589a7f53a56SChris Kirby 	zfs_hold_cleanup_arg_t *ca;
3590a7f53a56SChris Kirby 
3591a7f53a56SChris Kirby 	ca = kmem_alloc(sizeof (zfs_hold_cleanup_arg_t), KM_SLEEP);
3592a7f53a56SChris Kirby 	ca->dp = ds->ds_dir->dd_pool;
3593a7f53a56SChris Kirby 	ca->dsobj = ds->ds_object;
3594a7f53a56SChris Kirby 	(void) strlcpy(ca->htag, htag, sizeof (ca->htag));
3595b420f3adSRichard Lowe 	VERIFY3U(0, ==, zfs_onexit_add_cb(minor,
3596a7f53a56SChris Kirby 	    dsl_dataset_user_release_onexit, ca, NULL));
3597a7f53a56SChris Kirby }
3598a7f53a56SChris Kirby 
359915508ac0SChris Kirby /*
360099d5e173STim Haley  * If you add new checks here, you may need to add
360199d5e173STim Haley  * additional checks to the "temporary" case in
360299d5e173STim Haley  * snapshot_check() in dmu_objset.c.
360315508ac0SChris Kirby  */
3604842727c2SChris Kirby static int
3605842727c2SChris Kirby dsl_dataset_user_hold_check(void *arg1, void *arg2, dmu_tx_t *tx)
3606842727c2SChris Kirby {
3607842727c2SChris Kirby 	dsl_dataset_t *ds = arg1;
3608ca45db41SChris Kirby 	struct dsl_ds_holdarg *ha = arg2;
36094445fffbSMatthew Ahrens 	const char *htag = ha->htag;
3610842727c2SChris Kirby 	objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
3611842727c2SChris Kirby 	int error = 0;
3612842727c2SChris Kirby 
3613842727c2SChris Kirby 	if (spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_USERREFS)
3614842727c2SChris Kirby 		return (ENOTSUP);
3615842727c2SChris Kirby 
3616842727c2SChris Kirby 	if (!dsl_dataset_is_snapshot(ds))
3617842727c2SChris Kirby 		return (EINVAL);
3618842727c2SChris Kirby 
3619842727c2SChris Kirby 	/* tags must be unique */
3620842727c2SChris Kirby 	mutex_enter(&ds->ds_lock);
3621842727c2SChris Kirby 	if (ds->ds_phys->ds_userrefs_obj) {
3622842727c2SChris Kirby 		error = zap_lookup(mos, ds->ds_phys->ds_userrefs_obj, htag,
3623842727c2SChris Kirby 		    8, 1, tx);
3624842727c2SChris Kirby 		if (error == 0)
3625842727c2SChris Kirby 			error = EEXIST;
3626842727c2SChris Kirby 		else if (error == ENOENT)
3627842727c2SChris Kirby 			error = 0;
3628842727c2SChris Kirby 	}
3629842727c2SChris Kirby 	mutex_exit(&ds->ds_lock);
3630842727c2SChris Kirby 
363115508ac0SChris Kirby 	if (error == 0 && ha->temphold &&
363215508ac0SChris Kirby 	    strlen(htag) + MAX_TAG_PREFIX_LEN >= MAXNAMELEN)
363315508ac0SChris Kirby 		error = E2BIG;
363415508ac0SChris Kirby 
3635842727c2SChris Kirby 	return (error);
3636842727c2SChris Kirby }
3637842727c2SChris Kirby 
363899d5e173STim Haley void
36393f9d6ad7SLin Ling dsl_dataset_user_hold_sync(void *arg1, void *arg2, dmu_tx_t *tx)
3640842727c2SChris Kirby {
3641842727c2SChris Kirby 	dsl_dataset_t *ds = arg1;
3642ca45db41SChris Kirby 	struct dsl_ds_holdarg *ha = arg2;
36434445fffbSMatthew Ahrens 	const char *htag = ha->htag;
3644ca45db41SChris Kirby 	dsl_pool_t *dp = ds->ds_dir->dd_pool;
3645ca45db41SChris Kirby 	objset_t *mos = dp->dp_meta_objset;
364615508ac0SChris Kirby 	uint64_t now = gethrestime_sec();
3647842727c2SChris Kirby 	uint64_t zapobj;
3648842727c2SChris Kirby 
3649842727c2SChris Kirby 	mutex_enter(&ds->ds_lock);
3650842727c2SChris Kirby 	if (ds->ds_phys->ds_userrefs_obj == 0) {
3651842727c2SChris Kirby 		/*
3652842727c2SChris Kirby 		 * This is the first user hold for this dataset.  Create
3653842727c2SChris Kirby 		 * the userrefs zap object.
3654842727c2SChris Kirby 		 */
3655842727c2SChris Kirby 		dmu_buf_will_dirty(ds->ds_dbuf, tx);
3656842727c2SChris Kirby 		zapobj = ds->ds_phys->ds_userrefs_obj =
3657842727c2SChris Kirby 		    zap_create(mos, DMU_OT_USERREFS, DMU_OT_NONE, 0, tx);
3658842727c2SChris Kirby 	} else {
3659842727c2SChris Kirby 		zapobj = ds->ds_phys->ds_userrefs_obj;
3660842727c2SChris Kirby 	}
3661842727c2SChris Kirby 	ds->ds_userrefs++;
3662842727c2SChris Kirby 	mutex_exit(&ds->ds_lock);
3663842727c2SChris Kirby 
3664842727c2SChris Kirby 	VERIFY(0 == zap_add(mos, zapobj, htag, 8, 1, &now, tx));
3665842727c2SChris Kirby 
3666ca45db41SChris Kirby 	if (ha->temphold) {
3667ca45db41SChris Kirby 		VERIFY(0 == dsl_pool_user_hold(dp, ds->ds_object,
3668ca45db41SChris Kirby 		    htag, &now, tx));
3669ca45db41SChris Kirby 	}
3670ca45db41SChris Kirby 
36714445fffbSMatthew Ahrens 	spa_history_log_internal_ds(ds, "hold", tx,
36724445fffbSMatthew Ahrens 	    "tag = %s temp = %d holds now = %llu",
36734445fffbSMatthew Ahrens 	    htag, (int)ha->temphold, ds->ds_userrefs);
3674842727c2SChris Kirby }
3675842727c2SChris Kirby 
3676842727c2SChris Kirby static int
3677fd136879SMatthew Ahrens dsl_dataset_user_hold_one(const char *dsname, void *arg)
3678842727c2SChris Kirby {
3679842727c2SChris Kirby 	struct dsl_ds_holdarg *ha = arg;
3680842727c2SChris Kirby 	dsl_dataset_t *ds;
3681842727c2SChris Kirby 	int error;
3682842727c2SChris Kirby 	char *name;
3683842727c2SChris Kirby 
3684842727c2SChris Kirby 	/* alloc a buffer to hold dsname@snapname plus terminating NULL */
3685ae46e4c7SMatthew Ahrens 	name = kmem_asprintf("%s@%s", dsname, ha->snapname);
3686842727c2SChris Kirby 	error = dsl_dataset_hold(name, ha->dstg, &ds);
3687ae46e4c7SMatthew Ahrens 	strfree(name);
3688842727c2SChris Kirby 	if (error == 0) {
3689d7747cbcSChris Kirby 		ha->gotone = B_TRUE;
3690842727c2SChris Kirby 		dsl_sync_task_create(ha->dstg, dsl_dataset_user_hold_check,
3691ca45db41SChris Kirby 		    dsl_dataset_user_hold_sync, ds, ha, 0);
3692842727c2SChris Kirby 	} else if (error == ENOENT && ha->recursive) {
3693842727c2SChris Kirby 		error = 0;
3694842727c2SChris Kirby 	} else {
3695fd136879SMatthew Ahrens 		(void) strlcpy(ha->failed, dsname, sizeof (ha->failed));
3696842727c2SChris Kirby 	}
3697842727c2SChris Kirby 	return (error);
3698842727c2SChris Kirby }
3699842727c2SChris Kirby 
3700a7f53a56SChris Kirby int
3701a7f53a56SChris Kirby dsl_dataset_user_hold_for_send(dsl_dataset_t *ds, char *htag,
3702a7f53a56SChris Kirby     boolean_t temphold)
3703a7f53a56SChris Kirby {
3704a7f53a56SChris Kirby 	struct dsl_ds_holdarg *ha;
3705a7f53a56SChris Kirby 	int error;
3706a7f53a56SChris Kirby 
3707a7f53a56SChris Kirby 	ha = kmem_zalloc(sizeof (struct dsl_ds_holdarg), KM_SLEEP);
3708a7f53a56SChris Kirby 	ha->htag = htag;
3709a7f53a56SChris Kirby 	ha->temphold = temphold;
3710a7f53a56SChris Kirby 	error = dsl_sync_task_do(ds->ds_dir->dd_pool,
3711a7f53a56SChris Kirby 	    dsl_dataset_user_hold_check, dsl_dataset_user_hold_sync,
3712a7f53a56SChris Kirby 	    ds, ha, 0);
3713a7f53a56SChris Kirby 	kmem_free(ha, sizeof (struct dsl_ds_holdarg));
3714a7f53a56SChris Kirby 
3715a7f53a56SChris Kirby 	return (error);
3716a7f53a56SChris Kirby }
3717a7f53a56SChris Kirby 
3718842727c2SChris Kirby int
3719842727c2SChris Kirby dsl_dataset_user_hold(char *dsname, char *snapname, char *htag,
3720c99e4bdcSChris Kirby     boolean_t recursive, boolean_t temphold, int cleanup_fd)
3721842727c2SChris Kirby {
3722842727c2SChris Kirby 	struct dsl_ds_holdarg *ha;
3723842727c2SChris Kirby 	dsl_sync_task_t *dst;
3724842727c2SChris Kirby 	spa_t *spa;
3725842727c2SChris Kirby 	int error;
3726a7f53a56SChris Kirby 	minor_t minor = 0;
3727a7f53a56SChris Kirby 
3728a7f53a56SChris Kirby 	if (cleanup_fd != -1) {
3729a7f53a56SChris Kirby 		/* Currently we only support cleanup-on-exit of tempholds. */
3730a7f53a56SChris Kirby 		if (!temphold)
3731a7f53a56SChris Kirby 			return (EINVAL);
3732a7f53a56SChris Kirby 		error = zfs_onexit_fd_hold(cleanup_fd, &minor);
3733a7f53a56SChris Kirby 		if (error)
3734a7f53a56SChris Kirby 			return (error);
3735a7f53a56SChris Kirby 	}
3736842727c2SChris Kirby 
3737842727c2SChris Kirby 	ha = kmem_zalloc(sizeof (struct dsl_ds_holdarg), KM_SLEEP);
3738842727c2SChris Kirby 
3739842727c2SChris Kirby 	(void) strlcpy(ha->failed, dsname, sizeof (ha->failed));
3740842727c2SChris Kirby 
3741842727c2SChris Kirby 	error = spa_open(dsname, &spa, FTAG);
3742842727c2SChris Kirby 	if (error) {
3743842727c2SChris Kirby 		kmem_free(ha, sizeof (struct dsl_ds_holdarg));
3744a7f53a56SChris Kirby 		if (cleanup_fd != -1)
3745a7f53a56SChris Kirby 			zfs_onexit_fd_rele(cleanup_fd);
3746842727c2SChris Kirby 		return (error);
3747842727c2SChris Kirby 	}
3748842727c2SChris Kirby 
3749842727c2SChris Kirby 	ha->dstg = dsl_sync_task_group_create(spa_get_dsl(spa));
3750842727c2SChris Kirby 	ha->htag = htag;
3751842727c2SChris Kirby 	ha->snapname = snapname;
3752842727c2SChris Kirby 	ha->recursive = recursive;
3753ca45db41SChris Kirby 	ha->temphold = temphold;
3754c99e4bdcSChris Kirby 
3755842727c2SChris Kirby 	if (recursive) {
3756842727c2SChris Kirby 		error = dmu_objset_find(dsname, dsl_dataset_user_hold_one,
3757842727c2SChris Kirby 		    ha, DS_FIND_CHILDREN);
3758842727c2SChris Kirby 	} else {
3759842727c2SChris Kirby 		error = dsl_dataset_user_hold_one(dsname, ha);
3760842727c2SChris Kirby 	}
3761842727c2SChris Kirby 	if (error == 0)
3762842727c2SChris Kirby 		error = dsl_sync_task_group_wait(ha->dstg);
3763842727c2SChris Kirby 
3764842727c2SChris Kirby 	for (dst = list_head(&ha->dstg->dstg_tasks); dst;
3765842727c2SChris Kirby 	    dst = list_next(&ha->dstg->dstg_tasks, dst)) {
3766842727c2SChris Kirby 		dsl_dataset_t *ds = dst->dst_arg1;
3767842727c2SChris Kirby 
3768842727c2SChris Kirby 		if (dst->dst_err) {
3769842727c2SChris Kirby 			dsl_dataset_name(ds, ha->failed);
3770842727c2SChris Kirby 			*strchr(ha->failed, '@') = '\0';
3771a7f53a56SChris Kirby 		} else if (error == 0 && minor != 0 && temphold) {
3772a7f53a56SChris Kirby 			/*
3773a7f53a56SChris Kirby 			 * If this hold is to be released upon process exit,
3774a7f53a56SChris Kirby 			 * register that action now.
3775a7f53a56SChris Kirby 			 */
3776a7f53a56SChris Kirby 			dsl_register_onexit_hold_cleanup(ds, htag, minor);
3777842727c2SChris Kirby 		}
3778842727c2SChris Kirby 		dsl_dataset_rele(ds, ha->dstg);
3779842727c2SChris Kirby 	}
3780842727c2SChris Kirby 
3781d7747cbcSChris Kirby 	if (error == 0 && recursive && !ha->gotone)
3782d7747cbcSChris Kirby 		error = ENOENT;
3783d7747cbcSChris Kirby 
3784842727c2SChris Kirby 	if (error)
3785fd136879SMatthew Ahrens 		(void) strlcpy(dsname, ha->failed, sizeof (ha->failed));
3786842727c2SChris Kirby 
3787842727c2SChris Kirby 	dsl_sync_task_group_destroy(ha->dstg);
3788c99e4bdcSChris Kirby 
3789842727c2SChris Kirby 	kmem_free(ha, sizeof (struct dsl_ds_holdarg));
3790842727c2SChris Kirby 	spa_close(spa, FTAG);
3791a7f53a56SChris Kirby 	if (cleanup_fd != -1)
3792a7f53a56SChris Kirby 		zfs_onexit_fd_rele(cleanup_fd);
3793842727c2SChris Kirby 	return (error);
3794842727c2SChris Kirby }
3795842727c2SChris Kirby 
3796842727c2SChris Kirby struct dsl_ds_releasearg {
3797842727c2SChris Kirby 	dsl_dataset_t *ds;
3798842727c2SChris Kirby 	const char *htag;
3799842727c2SChris Kirby 	boolean_t own;		/* do we own or just hold ds? */
3800842727c2SChris Kirby };
3801842727c2SChris Kirby 
3802842727c2SChris Kirby static int
3803842727c2SChris Kirby dsl_dataset_release_might_destroy(dsl_dataset_t *ds, const char *htag,
3804842727c2SChris Kirby     boolean_t *might_destroy)
3805842727c2SChris Kirby {
3806842727c2SChris Kirby 	objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
3807842727c2SChris Kirby 	uint64_t zapobj;
3808842727c2SChris Kirby 	uint64_t tmp;
3809842727c2SChris Kirby 	int error;
3810842727c2SChris Kirby 
3811842727c2SChris Kirby 	*might_destroy = B_FALSE;
3812842727c2SChris Kirby 
3813842727c2SChris Kirby 	mutex_enter(&ds->ds_lock);
3814842727c2SChris Kirby 	zapobj = ds->ds_phys->ds_userrefs_obj;
3815842727c2SChris Kirby 	if (zapobj == 0) {
3816842727c2SChris Kirby 		/* The tag can't possibly exist */
3817842727c2SChris Kirby 		mutex_exit(&ds->ds_lock);
3818842727c2SChris Kirby 		return (ESRCH);
3819842727c2SChris Kirby 	}
3820842727c2SChris Kirby 
3821842727c2SChris Kirby 	/* Make sure the tag exists */
3822842727c2SChris Kirby 	error = zap_lookup(mos, zapobj, htag, 8, 1, &tmp);
3823842727c2SChris Kirby 	if (error) {
3824842727c2SChris Kirby 		mutex_exit(&ds->ds_lock);
3825842727c2SChris Kirby 		if (error == ENOENT)
3826842727c2SChris Kirby 			error = ESRCH;
3827842727c2SChris Kirby 		return (error);
3828842727c2SChris Kirby 	}
3829842727c2SChris Kirby 
3830842727c2SChris Kirby 	if (ds->ds_userrefs == 1 && ds->ds_phys->ds_num_children == 1 &&
3831842727c2SChris Kirby 	    DS_IS_DEFER_DESTROY(ds))
3832842727c2SChris Kirby 		*might_destroy = B_TRUE;
3833842727c2SChris Kirby 
3834842727c2SChris Kirby 	mutex_exit(&ds->ds_lock);
3835842727c2SChris Kirby 	return (0);
3836842727c2SChris Kirby }
3837842727c2SChris Kirby 
3838842727c2SChris Kirby static int
3839842727c2SChris Kirby dsl_dataset_user_release_check(void *arg1, void *tag, dmu_tx_t *tx)
3840842727c2SChris Kirby {
3841842727c2SChris Kirby 	struct dsl_ds_releasearg *ra = arg1;
3842842727c2SChris Kirby 	dsl_dataset_t *ds = ra->ds;
3843842727c2SChris Kirby 	boolean_t might_destroy;
3844842727c2SChris Kirby 	int error;
3845842727c2SChris Kirby 
3846842727c2SChris Kirby 	if (spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_USERREFS)
3847842727c2SChris Kirby 		return (ENOTSUP);
3848842727c2SChris Kirby 
3849842727c2SChris Kirby 	error = dsl_dataset_release_might_destroy(ds, ra->htag, &might_destroy);
3850842727c2SChris Kirby 	if (error)
3851842727c2SChris Kirby 		return (error);
3852842727c2SChris Kirby 
3853842727c2SChris Kirby 	if (might_destroy) {
3854842727c2SChris Kirby 		struct dsl_ds_destroyarg dsda = {0};
3855842727c2SChris Kirby 
3856842727c2SChris Kirby 		if (dmu_tx_is_syncing(tx)) {
3857842727c2SChris Kirby 			/*
3858842727c2SChris Kirby 			 * If we're not prepared to remove the snapshot,
3859842727c2SChris Kirby 			 * we can't allow the release to happen right now.
3860842727c2SChris Kirby 			 */
3861842727c2SChris Kirby 			if (!ra->own)
3862842727c2SChris Kirby 				return (EBUSY);
3863842727c2SChris Kirby 		}
3864842727c2SChris Kirby 		dsda.ds = ds;
3865842727c2SChris Kirby 		dsda.releasing = B_TRUE;
3866842727c2SChris Kirby 		return (dsl_dataset_destroy_check(&dsda, tag, tx));
3867842727c2SChris Kirby 	}
3868842727c2SChris Kirby 
3869842727c2SChris Kirby 	return (0);
3870842727c2SChris Kirby }
3871842727c2SChris Kirby 
3872842727c2SChris Kirby static void
38733f9d6ad7SLin Ling dsl_dataset_user_release_sync(void *arg1, void *tag, dmu_tx_t *tx)
3874842727c2SChris Kirby {
3875842727c2SChris Kirby 	struct dsl_ds_releasearg *ra = arg1;
3876842727c2SChris Kirby 	dsl_dataset_t *ds = ra->ds;
3877ca45db41SChris Kirby 	dsl_pool_t *dp = ds->ds_dir->dd_pool;
3878ca45db41SChris Kirby 	objset_t *mos = dp->dp_meta_objset;
3879842727c2SChris Kirby 	uint64_t zapobj;
3880842727c2SChris Kirby 	uint64_t refs;
3881ca45db41SChris Kirby 	int error;
3882842727c2SChris Kirby 
3883842727c2SChris Kirby 	mutex_enter(&ds->ds_lock);
3884842727c2SChris Kirby 	ds->ds_userrefs--;
3885842727c2SChris Kirby 	refs = ds->ds_userrefs;
3886842727c2SChris Kirby 	mutex_exit(&ds->ds_lock);
3887ca45db41SChris Kirby 	error = dsl_pool_user_release(dp, ds->ds_object, ra->htag, tx);
3888ca45db41SChris Kirby 	VERIFY(error == 0 || error == ENOENT);
3889842727c2SChris Kirby 	zapobj = ds->ds_phys->ds_userrefs_obj;
3890842727c2SChris Kirby 	VERIFY(0 == zap_remove(mos, zapobj, ra->htag, tx));
3891347eec8eSChristopher Siden 
3892347eec8eSChristopher Siden 	spa_history_log_internal_ds(ds, "release", tx,
3893347eec8eSChristopher Siden 	    "tag = %s refs now = %lld", ra->htag, (longlong_t)refs);
3894347eec8eSChristopher Siden 
3895842727c2SChris Kirby 	if (ds->ds_userrefs == 0 && ds->ds_phys->ds_num_children == 1 &&
3896842727c2SChris Kirby 	    DS_IS_DEFER_DESTROY(ds)) {
3897842727c2SChris Kirby 		struct dsl_ds_destroyarg dsda = {0};
3898842727c2SChris Kirby 
3899842727c2SChris Kirby 		ASSERT(ra->own);
3900842727c2SChris Kirby 		dsda.ds = ds;
3901842727c2SChris Kirby 		dsda.releasing = B_TRUE;
3902842727c2SChris Kirby 		/* We already did the destroy_check */
39033f9d6ad7SLin Ling 		dsl_dataset_destroy_sync(&dsda, tag, tx);
3904842727c2SChris Kirby 	}
3905842727c2SChris Kirby }
3906842727c2SChris Kirby 
3907842727c2SChris Kirby static int
3908fd136879SMatthew Ahrens dsl_dataset_user_release_one(const char *dsname, void *arg)
3909842727c2SChris Kirby {
3910842727c2SChris Kirby 	struct dsl_ds_holdarg *ha = arg;
3911842727c2SChris Kirby 	struct dsl_ds_releasearg *ra;
3912842727c2SChris Kirby 	dsl_dataset_t *ds;
3913842727c2SChris Kirby 	int error;
3914842727c2SChris Kirby 	void *dtag = ha->dstg;
3915842727c2SChris Kirby 	char *name;
3916842727c2SChris Kirby 	boolean_t own = B_FALSE;
3917842727c2SChris Kirby 	boolean_t might_destroy;
3918842727c2SChris Kirby 
3919842727c2SChris Kirby 	/* alloc a buffer to hold dsname@snapname, plus the terminating NULL */
3920ae46e4c7SMatthew Ahrens 	name = kmem_asprintf("%s@%s", dsname, ha->snapname);
3921842727c2SChris Kirby 	error = dsl_dataset_hold(name, dtag, &ds);
3922ae46e4c7SMatthew Ahrens 	strfree(name);
3923842727c2SChris Kirby 	if (error == ENOENT && ha->recursive)
3924842727c2SChris Kirby 		return (0);
3925fd136879SMatthew Ahrens 	(void) strlcpy(ha->failed, dsname, sizeof (ha->failed));
3926842727c2SChris Kirby 	if (error)
3927842727c2SChris Kirby 		return (error);
3928842727c2SChris Kirby 
3929d7747cbcSChris Kirby 	ha->gotone = B_TRUE;
3930d7747cbcSChris Kirby 
3931842727c2SChris Kirby 	ASSERT(dsl_dataset_is_snapshot(ds));
3932842727c2SChris Kirby 
3933842727c2SChris Kirby 	error = dsl_dataset_release_might_destroy(ds, ha->htag, &might_destroy);
3934842727c2SChris Kirby 	if (error) {
3935842727c2SChris Kirby 		dsl_dataset_rele(ds, dtag);
3936842727c2SChris Kirby 		return (error);
3937842727c2SChris Kirby 	}
3938842727c2SChris Kirby 
3939842727c2SChris Kirby 	if (might_destroy) {
3940842727c2SChris Kirby #ifdef _KERNEL
39415afc78aaSChris Kirby 		name = kmem_asprintf("%s@%s", dsname, ha->snapname);
3942842727c2SChris Kirby 		error = zfs_unmount_snap(name, NULL);
39435afc78aaSChris Kirby 		strfree(name);
3944842727c2SChris Kirby 		if (error) {
3945842727c2SChris Kirby 			dsl_dataset_rele(ds, dtag);
3946842727c2SChris Kirby 			return (error);
3947842727c2SChris Kirby 		}
3948842727c2SChris Kirby #endif
3949503ad85cSMatthew Ahrens 		if (!dsl_dataset_tryown(ds, B_TRUE, dtag)) {
3950842727c2SChris Kirby 			dsl_dataset_rele(ds, dtag);
3951842727c2SChris Kirby 			return (EBUSY);
3952842727c2SChris Kirby 		} else {
3953842727c2SChris Kirby 			own = B_TRUE;
3954842727c2SChris Kirby 			dsl_dataset_make_exclusive(ds, dtag);
3955842727c2SChris Kirby 		}
3956842727c2SChris Kirby 	}
3957842727c2SChris Kirby 
3958842727c2SChris Kirby 	ra = kmem_alloc(sizeof (struct dsl_ds_releasearg), KM_SLEEP);
3959842727c2SChris Kirby 	ra->ds = ds;
3960842727c2SChris Kirby 	ra->htag = ha->htag;
3961842727c2SChris Kirby 	ra->own = own;
3962842727c2SChris Kirby 	dsl_sync_task_create(ha->dstg, dsl_dataset_user_release_check,
3963842727c2SChris Kirby 	    dsl_dataset_user_release_sync, ra, dtag, 0);
3964842727c2SChris Kirby 
3965842727c2SChris Kirby 	return (0);
3966842727c2SChris Kirby }
3967842727c2SChris Kirby 
3968842727c2SChris Kirby int
3969842727c2SChris Kirby dsl_dataset_user_release(char *dsname, char *snapname, char *htag,
3970842727c2SChris Kirby     boolean_t recursive)
3971842727c2SChris Kirby {
3972842727c2SChris Kirby 	struct dsl_ds_holdarg *ha;
3973842727c2SChris Kirby 	dsl_sync_task_t *dst;
3974842727c2SChris Kirby 	spa_t *spa;
3975842727c2SChris Kirby 	int error;
3976842727c2SChris Kirby 
3977620252bcSChris Kirby top:
3978842727c2SChris Kirby 	ha = kmem_zalloc(sizeof (struct dsl_ds_holdarg), KM_SLEEP);
3979842727c2SChris Kirby 
3980842727c2SChris Kirby 	(void) strlcpy(ha->failed, dsname, sizeof (ha->failed));
3981842727c2SChris Kirby 
3982842727c2SChris Kirby 	error = spa_open(dsname, &spa, FTAG);
3983842727c2SChris Kirby 	if (error) {
3984842727c2SChris Kirby 		kmem_free(ha, sizeof (struct dsl_ds_holdarg));
3985842727c2SChris Kirby 		return (error);
3986842727c2SChris Kirby 	}
3987842727c2SChris Kirby 
3988842727c2SChris Kirby 	ha->dstg = dsl_sync_task_group_create(spa_get_dsl(spa));
3989842727c2SChris Kirby 	ha->htag = htag;
3990842727c2SChris Kirby 	ha->snapname = snapname;
3991842727c2SChris Kirby 	ha->recursive = recursive;
3992842727c2SChris Kirby 	if (recursive) {
3993842727c2SChris Kirby 		error = dmu_objset_find(dsname, dsl_dataset_user_release_one,
3994842727c2SChris Kirby 		    ha, DS_FIND_CHILDREN);
3995842727c2SChris Kirby 	} else {
3996842727c2SChris Kirby 		error = dsl_dataset_user_release_one(dsname, ha);
3997842727c2SChris Kirby 	}
3998842727c2SChris Kirby 	if (error == 0)
3999842727c2SChris Kirby 		error = dsl_sync_task_group_wait(ha->dstg);
4000842727c2SChris Kirby 
4001842727c2SChris Kirby 	for (dst = list_head(&ha->dstg->dstg_tasks); dst;
4002842727c2SChris Kirby 	    dst = list_next(&ha->dstg->dstg_tasks, dst)) {
4003842727c2SChris Kirby 		struct dsl_ds_releasearg *ra = dst->dst_arg1;
4004842727c2SChris Kirby 		dsl_dataset_t *ds = ra->ds;
4005842727c2SChris Kirby 
4006842727c2SChris Kirby 		if (dst->dst_err)
4007842727c2SChris Kirby 			dsl_dataset_name(ds, ha->failed);
4008842727c2SChris Kirby 
4009842727c2SChris Kirby 		if (ra->own)
4010842727c2SChris Kirby 			dsl_dataset_disown(ds, ha->dstg);
4011842727c2SChris Kirby 		else
4012842727c2SChris Kirby 			dsl_dataset_rele(ds, ha->dstg);
4013842727c2SChris Kirby 
4014842727c2SChris Kirby 		kmem_free(ra, sizeof (struct dsl_ds_releasearg));
4015842727c2SChris Kirby 	}
4016842727c2SChris Kirby 
4017d7747cbcSChris Kirby 	if (error == 0 && recursive && !ha->gotone)
4018d7747cbcSChris Kirby 		error = ENOENT;
4019d7747cbcSChris Kirby 
4020620252bcSChris Kirby 	if (error && error != EBUSY)
4021fd136879SMatthew Ahrens 		(void) strlcpy(dsname, ha->failed, sizeof (ha->failed));
4022842727c2SChris Kirby 
4023842727c2SChris Kirby 	dsl_sync_task_group_destroy(ha->dstg);
4024842727c2SChris Kirby 	kmem_free(ha, sizeof (struct dsl_ds_holdarg));
4025842727c2SChris Kirby 	spa_close(spa, FTAG);
4026620252bcSChris Kirby 
4027620252bcSChris Kirby 	/*
4028620252bcSChris Kirby 	 * We can get EBUSY if we were racing with deferred destroy and
4029620252bcSChris Kirby 	 * dsl_dataset_user_release_check() hadn't done the necessary
4030620252bcSChris Kirby 	 * open context setup.  We can also get EBUSY if we're racing
4031620252bcSChris Kirby 	 * with destroy and that thread is the ds_owner.  Either way
4032620252bcSChris Kirby 	 * the busy condition should be transient, and we should retry
4033620252bcSChris Kirby 	 * the release operation.
4034620252bcSChris Kirby 	 */
4035620252bcSChris Kirby 	if (error == EBUSY)
4036620252bcSChris Kirby 		goto top;
4037620252bcSChris Kirby 
4038842727c2SChris Kirby 	return (error);
4039842727c2SChris Kirby }
4040842727c2SChris Kirby 
4041ca45db41SChris Kirby /*
4042a7f53a56SChris Kirby  * Called at spa_load time (with retry == B_FALSE) to release a stale
4043a7f53a56SChris Kirby  * temporary user hold. Also called by the onexit code (with retry == B_TRUE).
4044ca45db41SChris Kirby  */
4045ca45db41SChris Kirby int
4046a7f53a56SChris Kirby dsl_dataset_user_release_tmp(dsl_pool_t *dp, uint64_t dsobj, char *htag,
4047a7f53a56SChris Kirby     boolean_t retry)
4048ca45db41SChris Kirby {
4049ca45db41SChris Kirby 	dsl_dataset_t *ds;
4050ca45db41SChris Kirby 	char *snap;
4051ca45db41SChris Kirby 	char *name;
4052ca45db41SChris Kirby 	int namelen;
4053ca45db41SChris Kirby 	int error;
4054ca45db41SChris Kirby 
4055a7f53a56SChris Kirby 	do {
4056a7f53a56SChris Kirby 		rw_enter(&dp->dp_config_rwlock, RW_READER);
4057a7f53a56SChris Kirby 		error = dsl_dataset_hold_obj(dp, dsobj, FTAG, &ds);
4058a7f53a56SChris Kirby 		rw_exit(&dp->dp_config_rwlock);
4059a7f53a56SChris Kirby 		if (error)
4060a7f53a56SChris Kirby 			return (error);
4061a7f53a56SChris Kirby 		namelen = dsl_dataset_namelen(ds)+1;
4062a7f53a56SChris Kirby 		name = kmem_alloc(namelen, KM_SLEEP);
4063a7f53a56SChris Kirby 		dsl_dataset_name(ds, name);
4064a7f53a56SChris Kirby 		dsl_dataset_rele(ds, FTAG);
4065ca45db41SChris Kirby 
4066a7f53a56SChris Kirby 		snap = strchr(name, '@');
4067a7f53a56SChris Kirby 		*snap = '\0';
4068a7f53a56SChris Kirby 		++snap;
4069a7f53a56SChris Kirby 		error = dsl_dataset_user_release(name, snap, htag, B_FALSE);
4070a7f53a56SChris Kirby 		kmem_free(name, namelen);
4071a7f53a56SChris Kirby 
4072a7f53a56SChris Kirby 		/*
4073a7f53a56SChris Kirby 		 * The object can't have been destroyed because we have a hold,
4074a7f53a56SChris Kirby 		 * but it might have been renamed, resulting in ENOENT.  Retry
4075a7f53a56SChris Kirby 		 * if we've been requested to do so.
4076a7f53a56SChris Kirby 		 *
4077a7f53a56SChris Kirby 		 * It would be nice if we could use the dsobj all the way
4078a7f53a56SChris Kirby 		 * through and avoid ENOENT entirely.  But we might need to
4079a7f53a56SChris Kirby 		 * unmount the snapshot, and there's currently no way to lookup
4080a7f53a56SChris Kirby 		 * a vfsp using a ZFS object id.
4081a7f53a56SChris Kirby 		 */
4082a7f53a56SChris Kirby 	} while ((error == ENOENT) && retry);
4083a7f53a56SChris Kirby 
4084a7f53a56SChris Kirby 	return (error);
4085ca45db41SChris Kirby }
4086ca45db41SChris Kirby 
4087842727c2SChris Kirby int
4088842727c2SChris Kirby dsl_dataset_get_holds(const char *dsname, nvlist_t **nvp)
4089842727c2SChris Kirby {
4090842727c2SChris Kirby 	dsl_dataset_t *ds;
4091842727c2SChris Kirby 	int err;
4092842727c2SChris Kirby 
4093842727c2SChris Kirby 	err = dsl_dataset_hold(dsname, FTAG, &ds);
4094842727c2SChris Kirby 	if (err)
4095842727c2SChris Kirby 		return (err);
4096842727c2SChris Kirby 
4097842727c2SChris Kirby 	VERIFY(0 == nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP));
4098842727c2SChris Kirby 	if (ds->ds_phys->ds_userrefs_obj != 0) {
4099842727c2SChris Kirby 		zap_attribute_t *za;
4100842727c2SChris Kirby 		zap_cursor_t zc;
4101842727c2SChris Kirby 
4102842727c2SChris Kirby 		za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
4103842727c2SChris Kirby 		for (zap_cursor_init(&zc, ds->ds_dir->dd_pool->dp_meta_objset,
4104842727c2SChris Kirby 		    ds->ds_phys->ds_userrefs_obj);
4105842727c2SChris Kirby 		    zap_cursor_retrieve(&zc, za) == 0;
4106842727c2SChris Kirby 		    zap_cursor_advance(&zc)) {
4107842727c2SChris Kirby 			VERIFY(0 == nvlist_add_uint64(*nvp, za->za_name,
4108842727c2SChris Kirby 			    za->za_first_integer));
4109842727c2SChris Kirby 		}
4110842727c2SChris Kirby 		zap_cursor_fini(&zc);
4111842727c2SChris Kirby 		kmem_free(za, sizeof (zap_attribute_t));
4112842727c2SChris Kirby 	}
4113842727c2SChris Kirby 	dsl_dataset_rele(ds, FTAG);
4114842727c2SChris Kirby 	return (0);
4115842727c2SChris Kirby }
4116503ad85cSMatthew Ahrens 
4117503ad85cSMatthew Ahrens /*
411819b94df9SMatthew Ahrens  * Note, this function is used as the callback for dmu_objset_find().  We
4119503ad85cSMatthew Ahrens  * always return 0 so that we will continue to find and process
4120503ad85cSMatthew Ahrens  * inconsistent datasets, even if we encounter an error trying to
4121503ad85cSMatthew Ahrens  * process one of them.
4122503ad85cSMatthew Ahrens  */
4123503ad85cSMatthew Ahrens /* ARGSUSED */
4124503ad85cSMatthew Ahrens int
4125fd136879SMatthew Ahrens dsl_destroy_inconsistent(const char *dsname, void *arg)
4126503ad85cSMatthew Ahrens {
4127503ad85cSMatthew Ahrens 	dsl_dataset_t *ds;
4128503ad85cSMatthew Ahrens 
4129503ad85cSMatthew Ahrens 	if (dsl_dataset_own(dsname, B_TRUE, FTAG, &ds) == 0) {
4130503ad85cSMatthew Ahrens 		if (DS_IS_INCONSISTENT(ds))
4131503ad85cSMatthew Ahrens 			(void) dsl_dataset_destroy(ds, FTAG, B_FALSE);
4132503ad85cSMatthew Ahrens 		else
4133503ad85cSMatthew Ahrens 			dsl_dataset_disown(ds, FTAG);
4134503ad85cSMatthew Ahrens 	}
4135503ad85cSMatthew Ahrens 	return (0);
4136503ad85cSMatthew Ahrens }
413719b94df9SMatthew Ahrens 
413819b94df9SMatthew Ahrens /*
413919b94df9SMatthew Ahrens  * Return (in *usedp) the amount of space written in new that is not
414019b94df9SMatthew Ahrens  * present in oldsnap.  New may be a snapshot or the head.  Old must be
414119b94df9SMatthew Ahrens  * a snapshot before new, in new's filesystem (or its origin).  If not then
414219b94df9SMatthew Ahrens  * fail and return EINVAL.
414319b94df9SMatthew Ahrens  *
414419b94df9SMatthew Ahrens  * The written space is calculated by considering two components:  First, we
414519b94df9SMatthew Ahrens  * ignore any freed space, and calculate the written as new's used space
414619b94df9SMatthew Ahrens  * minus old's used space.  Next, we add in the amount of space that was freed
414719b94df9SMatthew Ahrens  * between the two snapshots, thus reducing new's used space relative to old's.
414819b94df9SMatthew Ahrens  * Specifically, this is the space that was born before old->ds_creation_txg,
414919b94df9SMatthew Ahrens  * and freed before new (ie. on new's deadlist or a previous deadlist).
415019b94df9SMatthew Ahrens  *
415119b94df9SMatthew Ahrens  * space freed                         [---------------------]
415219b94df9SMatthew Ahrens  * snapshots                       ---O-------O--------O-------O------
415319b94df9SMatthew Ahrens  *                                         oldsnap            new
415419b94df9SMatthew Ahrens  */
415519b94df9SMatthew Ahrens int
415619b94df9SMatthew Ahrens dsl_dataset_space_written(dsl_dataset_t *oldsnap, dsl_dataset_t *new,
415719b94df9SMatthew Ahrens     uint64_t *usedp, uint64_t *compp, uint64_t *uncompp)
415819b94df9SMatthew Ahrens {
415919b94df9SMatthew Ahrens 	int err = 0;
416019b94df9SMatthew Ahrens 	uint64_t snapobj;
416119b94df9SMatthew Ahrens 	dsl_pool_t *dp = new->ds_dir->dd_pool;
416219b94df9SMatthew Ahrens 
416319b94df9SMatthew Ahrens 	*usedp = 0;
4164ad135b5dSChristopher Siden 	*usedp += new->ds_phys->ds_referenced_bytes;
4165ad135b5dSChristopher Siden 	*usedp -= oldsnap->ds_phys->ds_referenced_bytes;
416619b94df9SMatthew Ahrens 
416719b94df9SMatthew Ahrens 	*compp = 0;
416819b94df9SMatthew Ahrens 	*compp += new->ds_phys->ds_compressed_bytes;
416919b94df9SMatthew Ahrens 	*compp -= oldsnap->ds_phys->ds_compressed_bytes;
417019b94df9SMatthew Ahrens 
417119b94df9SMatthew Ahrens 	*uncompp = 0;
417219b94df9SMatthew Ahrens 	*uncompp += new->ds_phys->ds_uncompressed_bytes;
417319b94df9SMatthew Ahrens 	*uncompp -= oldsnap->ds_phys->ds_uncompressed_bytes;
417419b94df9SMatthew Ahrens 
417519b94df9SMatthew Ahrens 	rw_enter(&dp->dp_config_rwlock, RW_READER);
417619b94df9SMatthew Ahrens 	snapobj = new->ds_object;
417719b94df9SMatthew Ahrens 	while (snapobj != oldsnap->ds_object) {
417819b94df9SMatthew Ahrens 		dsl_dataset_t *snap;
417919b94df9SMatthew Ahrens 		uint64_t used, comp, uncomp;
418019b94df9SMatthew Ahrens 
4181ad135b5dSChristopher Siden 		if (snapobj == new->ds_object) {
4182ad135b5dSChristopher Siden 			snap = new;
4183ad135b5dSChristopher Siden 		} else {
4184ad135b5dSChristopher Siden 			err = dsl_dataset_hold_obj(dp, snapobj, FTAG, &snap);
4185ad135b5dSChristopher Siden 			if (err != 0)
4186ad135b5dSChristopher Siden 				break;
4187ad135b5dSChristopher Siden 		}
418819b94df9SMatthew Ahrens 
418919b94df9SMatthew Ahrens 		if (snap->ds_phys->ds_prev_snap_txg ==
419019b94df9SMatthew Ahrens 		    oldsnap->ds_phys->ds_creation_txg) {
419119b94df9SMatthew Ahrens 			/*
419219b94df9SMatthew Ahrens 			 * The blocks in the deadlist can not be born after
419319b94df9SMatthew Ahrens 			 * ds_prev_snap_txg, so get the whole deadlist space,
419419b94df9SMatthew Ahrens 			 * which is more efficient (especially for old-format
419519b94df9SMatthew Ahrens 			 * deadlists).  Unfortunately the deadlist code
419619b94df9SMatthew Ahrens 			 * doesn't have enough information to make this
419719b94df9SMatthew Ahrens 			 * optimization itself.
419819b94df9SMatthew Ahrens 			 */
419919b94df9SMatthew Ahrens 			dsl_deadlist_space(&snap->ds_deadlist,
420019b94df9SMatthew Ahrens 			    &used, &comp, &uncomp);
420119b94df9SMatthew Ahrens 		} else {
420219b94df9SMatthew Ahrens 			dsl_deadlist_space_range(&snap->ds_deadlist,
420319b94df9SMatthew Ahrens 			    0, oldsnap->ds_phys->ds_creation_txg,
420419b94df9SMatthew Ahrens 			    &used, &comp, &uncomp);
420519b94df9SMatthew Ahrens 		}
420619b94df9SMatthew Ahrens 		*usedp += used;
420719b94df9SMatthew Ahrens 		*compp += comp;
420819b94df9SMatthew Ahrens 		*uncompp += uncomp;
420919b94df9SMatthew Ahrens 
421019b94df9SMatthew Ahrens 		/*
421119b94df9SMatthew Ahrens 		 * If we get to the beginning of the chain of snapshots
421219b94df9SMatthew Ahrens 		 * (ds_prev_snap_obj == 0) before oldsnap, then oldsnap
421319b94df9SMatthew Ahrens 		 * was not a snapshot of/before new.
421419b94df9SMatthew Ahrens 		 */
421519b94df9SMatthew Ahrens 		snapobj = snap->ds_phys->ds_prev_snap_obj;
4216ad135b5dSChristopher Siden 		if (snap != new)
4217ad135b5dSChristopher Siden 			dsl_dataset_rele(snap, FTAG);
421819b94df9SMatthew Ahrens 		if (snapobj == 0) {
421919b94df9SMatthew Ahrens 			err = EINVAL;
422019b94df9SMatthew Ahrens 			break;
422119b94df9SMatthew Ahrens 		}
422219b94df9SMatthew Ahrens 
422319b94df9SMatthew Ahrens 	}
422419b94df9SMatthew Ahrens 	rw_exit(&dp->dp_config_rwlock);
422519b94df9SMatthew Ahrens 	return (err);
422619b94df9SMatthew Ahrens }
422719b94df9SMatthew Ahrens 
422819b94df9SMatthew Ahrens /*
422919b94df9SMatthew Ahrens  * Return (in *usedp) the amount of space that will be reclaimed if firstsnap,
423019b94df9SMatthew Ahrens  * lastsnap, and all snapshots in between are deleted.
423119b94df9SMatthew Ahrens  *
423219b94df9SMatthew Ahrens  * blocks that would be freed            [---------------------------]
423319b94df9SMatthew Ahrens  * snapshots                       ---O-------O--------O-------O--------O
423419b94df9SMatthew Ahrens  *                                        firstsnap        lastsnap
423519b94df9SMatthew Ahrens  *
423619b94df9SMatthew Ahrens  * This is the set of blocks that were born after the snap before firstsnap,
423719b94df9SMatthew Ahrens  * (birth > firstsnap->prev_snap_txg) and died before the snap after the
423819b94df9SMatthew Ahrens  * last snap (ie, is on lastsnap->ds_next->ds_deadlist or an earlier deadlist).
423919b94df9SMatthew Ahrens  * We calculate this by iterating over the relevant deadlists (from the snap
424019b94df9SMatthew Ahrens  * after lastsnap, backward to the snap after firstsnap), summing up the
424119b94df9SMatthew Ahrens  * space on the deadlist that was born after the snap before firstsnap.
424219b94df9SMatthew Ahrens  */
424319b94df9SMatthew Ahrens int
424419b94df9SMatthew Ahrens dsl_dataset_space_wouldfree(dsl_dataset_t *firstsnap,
424519b94df9SMatthew Ahrens     dsl_dataset_t *lastsnap,
424619b94df9SMatthew Ahrens     uint64_t *usedp, uint64_t *compp, uint64_t *uncompp)
424719b94df9SMatthew Ahrens {
424819b94df9SMatthew Ahrens 	int err = 0;
424919b94df9SMatthew Ahrens 	uint64_t snapobj;
425019b94df9SMatthew Ahrens 	dsl_pool_t *dp = firstsnap->ds_dir->dd_pool;
425119b94df9SMatthew Ahrens 
425219b94df9SMatthew Ahrens 	ASSERT(dsl_dataset_is_snapshot(firstsnap));
425319b94df9SMatthew Ahrens 	ASSERT(dsl_dataset_is_snapshot(lastsnap));
425419b94df9SMatthew Ahrens 
425519b94df9SMatthew Ahrens 	/*
425619b94df9SMatthew Ahrens 	 * Check that the snapshots are in the same dsl_dir, and firstsnap
425719b94df9SMatthew Ahrens 	 * is before lastsnap.
425819b94df9SMatthew Ahrens 	 */
425919b94df9SMatthew Ahrens 	if (firstsnap->ds_dir != lastsnap->ds_dir ||
426019b94df9SMatthew Ahrens 	    firstsnap->ds_phys->ds_creation_txg >
426119b94df9SMatthew Ahrens 	    lastsnap->ds_phys->ds_creation_txg)
426219b94df9SMatthew Ahrens 		return (EINVAL);
426319b94df9SMatthew Ahrens 
426419b94df9SMatthew Ahrens 	*usedp = *compp = *uncompp = 0;
426519b94df9SMatthew Ahrens 
426619b94df9SMatthew Ahrens 	rw_enter(&dp->dp_config_rwlock, RW_READER);
426719b94df9SMatthew Ahrens 	snapobj = lastsnap->ds_phys->ds_next_snap_obj;
426819b94df9SMatthew Ahrens 	while (snapobj != firstsnap->ds_object) {
426919b94df9SMatthew Ahrens 		dsl_dataset_t *ds;
427019b94df9SMatthew Ahrens 		uint64_t used, comp, uncomp;
427119b94df9SMatthew Ahrens 
427219b94df9SMatthew Ahrens 		err = dsl_dataset_hold_obj(dp, snapobj, FTAG, &ds);
427319b94df9SMatthew Ahrens 		if (err != 0)
427419b94df9SMatthew Ahrens 			break;
427519b94df9SMatthew Ahrens 
427619b94df9SMatthew Ahrens 		dsl_deadlist_space_range(&ds->ds_deadlist,
427719b94df9SMatthew Ahrens 		    firstsnap->ds_phys->ds_prev_snap_txg, UINT64_MAX,
427819b94df9SMatthew Ahrens 		    &used, &comp, &uncomp);
427919b94df9SMatthew Ahrens 		*usedp += used;
428019b94df9SMatthew Ahrens 		*compp += comp;
428119b94df9SMatthew Ahrens 		*uncompp += uncomp;
428219b94df9SMatthew Ahrens 
428319b94df9SMatthew Ahrens 		snapobj = ds->ds_phys->ds_prev_snap_obj;
428419b94df9SMatthew Ahrens 		ASSERT3U(snapobj, !=, 0);
428519b94df9SMatthew Ahrens 		dsl_dataset_rele(ds, FTAG);
428619b94df9SMatthew Ahrens 	}
428719b94df9SMatthew Ahrens 	rw_exit(&dp->dp_config_rwlock);
428819b94df9SMatthew Ahrens 	return (err);
428919b94df9SMatthew Ahrens }
4290