]>
Commit | Line | Data |
---|---|---|
13fe0198 MA |
1 | /* |
2 | * CDDL HEADER START | |
3 | * | |
4 | * The contents of this file are subject to the terms of the | |
5 | * Common Development and Distribution License (the "License"). | |
6 | * You may not use this file except in compliance with the License. | |
7 | * | |
8 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | |
9 | * or http://www.opensolaris.org/os/licensing. | |
10 | * See the License for the specific language governing permissions | |
11 | * and limitations under the License. | |
12 | * | |
13 | * When distributing Covered Code, include this CDDL HEADER in each | |
14 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. | |
15 | * If applicable, add the following below this CDDL HEADER, with the | |
16 | * fields enclosed by brackets "[]" replaced with your own identifying | |
17 | * information: Portions Copyright [yyyy] [name of copyright owner] | |
18 | * | |
19 | * CDDL HEADER END | |
20 | */ | |
21 | /* | |
22 | * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. | |
d52d80b7 | 23 | * Copyright (c) 2012, 2018 by Delphix. All rights reserved. |
95fd54a1 | 24 | * Copyright (c) 2013 Steven Hartland. All rights reserved. |
788eb90c | 25 | * Copyright (c) 2013 by Joyent, Inc. All rights reserved. |
a0bd735a | 26 | * Copyright (c) 2016 Actifio, Inc. All rights reserved. |
13fe0198 MA |
27 | */ |
28 | ||
29 | #include <sys/zfs_context.h> | |
30 | #include <sys/dsl_userhold.h> | |
31 | #include <sys/dsl_dataset.h> | |
32 | #include <sys/dsl_synctask.h> | |
d99a0153 | 33 | #include <sys/dsl_destroy.h> |
13fe0198 MA |
34 | #include <sys/dmu_tx.h> |
35 | #include <sys/dsl_pool.h> | |
36 | #include <sys/dsl_dir.h> | |
37 | #include <sys/dmu_traverse.h> | |
38 | #include <sys/dsl_scan.h> | |
39 | #include <sys/dmu_objset.h> | |
40 | #include <sys/zap.h> | |
41 | #include <sys/zfeature.h> | |
42 | #include <sys/zfs_ioctl.h> | |
43 | #include <sys/dsl_deleg.h> | |
fa86b5db | 44 | #include <sys/dmu_impl.h> |
a0bd735a | 45 | #include <sys/zvol.h> |
d99a0153 | 46 | #include <sys/zcp.h> |
13fe0198 | 47 | |
19580676 | 48 | int |
13fe0198 MA |
49 | dsl_destroy_snapshot_check_impl(dsl_dataset_t *ds, boolean_t defer) |
50 | { | |
0c66c32d | 51 | if (!ds->ds_is_snapshot) |
2e528b49 | 52 | return (SET_ERROR(EINVAL)); |
13fe0198 MA |
53 | |
54 | if (dsl_dataset_long_held(ds)) | |
2e528b49 | 55 | return (SET_ERROR(EBUSY)); |
13fe0198 MA |
56 | |
57 | /* | |
58 | * Only allow deferred destroy on pools that support it. | |
59 | * NOTE: deferred destroy is only supported on snapshots. | |
60 | */ | |
61 | if (defer) { | |
62 | if (spa_version(ds->ds_dir->dd_pool->dp_spa) < | |
63 | SPA_VERSION_USERREFS) | |
2e528b49 | 64 | return (SET_ERROR(ENOTSUP)); |
13fe0198 MA |
65 | return (0); |
66 | } | |
67 | ||
68 | /* | |
69 | * If this snapshot has an elevated user reference count, | |
70 | * we can't destroy it yet. | |
71 | */ | |
72 | if (ds->ds_userrefs > 0) | |
2e528b49 | 73 | return (SET_ERROR(EBUSY)); |
13fe0198 MA |
74 | |
75 | /* | |
76 | * Can't delete a branch point. | |
77 | */ | |
d683ddbb | 78 | if (dsl_dataset_phys(ds)->ds_num_children > 1) |
2e528b49 | 79 | return (SET_ERROR(EEXIST)); |
13fe0198 MA |
80 | |
81 | return (0); | |
82 | } | |
83 | ||
d99a0153 | 84 | int |
13fe0198 MA |
85 | dsl_destroy_snapshot_check(void *arg, dmu_tx_t *tx) |
86 | { | |
d99a0153 CW |
87 | dsl_destroy_snapshot_arg_t *ddsa = arg; |
88 | const char *dsname = ddsa->ddsa_name; | |
89 | boolean_t defer = ddsa->ddsa_defer; | |
90 | ||
13fe0198 | 91 | dsl_pool_t *dp = dmu_tx_pool(tx); |
13fe0198 | 92 | int error = 0; |
d99a0153 | 93 | dsl_dataset_t *ds; |
13fe0198 | 94 | |
d99a0153 | 95 | error = dsl_dataset_hold(dp, dsname, FTAG, &ds); |
13fe0198 | 96 | |
d99a0153 CW |
97 | /* |
98 | * If the snapshot does not exist, silently ignore it, and | |
99 | * dsl_destroy_snapshot_sync() will be a no-op | |
100 | * (it's "already destroyed"). | |
101 | */ | |
102 | if (error == ENOENT) | |
103 | return (0); | |
13fe0198 | 104 | |
d99a0153 CW |
105 | if (error == 0) { |
106 | error = dsl_destroy_snapshot_check_impl(ds, defer); | |
107 | dsl_dataset_rele(ds, FTAG); | |
13fe0198 MA |
108 | } |
109 | ||
d99a0153 | 110 | return (error); |
13fe0198 MA |
111 | } |
112 | ||
113 | struct process_old_arg { | |
114 | dsl_dataset_t *ds; | |
115 | dsl_dataset_t *ds_prev; | |
116 | boolean_t after_branch_point; | |
117 | zio_t *pio; | |
118 | uint64_t used, comp, uncomp; | |
119 | }; | |
120 | ||
121 | static int | |
122 | process_old_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx) | |
123 | { | |
124 | struct process_old_arg *poa = arg; | |
125 | dsl_pool_t *dp = poa->ds->ds_dir->dd_pool; | |
126 | ||
b0bc7a84 MG |
127 | ASSERT(!BP_IS_HOLE(bp)); |
128 | ||
d683ddbb | 129 | if (bp->blk_birth <= dsl_dataset_phys(poa->ds)->ds_prev_snap_txg) { |
13fe0198 MA |
130 | dsl_deadlist_insert(&poa->ds->ds_deadlist, bp, tx); |
131 | if (poa->ds_prev && !poa->after_branch_point && | |
132 | bp->blk_birth > | |
d683ddbb JG |
133 | dsl_dataset_phys(poa->ds_prev)->ds_prev_snap_txg) { |
134 | dsl_dataset_phys(poa->ds_prev)->ds_unique_bytes += | |
13fe0198 MA |
135 | bp_get_dsize_sync(dp->dp_spa, bp); |
136 | } | |
137 | } else { | |
138 | poa->used += bp_get_dsize_sync(dp->dp_spa, bp); | |
139 | poa->comp += BP_GET_PSIZE(bp); | |
140 | poa->uncomp += BP_GET_UCSIZE(bp); | |
141 | dsl_free_sync(poa->pio, dp, tx->tx_txg, bp); | |
142 | } | |
143 | return (0); | |
144 | } | |
145 | ||
146 | static void | |
147 | process_old_deadlist(dsl_dataset_t *ds, dsl_dataset_t *ds_prev, | |
148 | dsl_dataset_t *ds_next, boolean_t after_branch_point, dmu_tx_t *tx) | |
149 | { | |
150 | struct process_old_arg poa = { 0 }; | |
151 | dsl_pool_t *dp = ds->ds_dir->dd_pool; | |
152 | objset_t *mos = dp->dp_meta_objset; | |
153 | uint64_t deadlist_obj; | |
154 | ||
155 | ASSERT(ds->ds_deadlist.dl_oldfmt); | |
156 | ASSERT(ds_next->ds_deadlist.dl_oldfmt); | |
157 | ||
158 | poa.ds = ds; | |
159 | poa.ds_prev = ds_prev; | |
160 | poa.after_branch_point = after_branch_point; | |
161 | poa.pio = zio_root(dp->dp_spa, NULL, NULL, ZIO_FLAG_MUSTSUCCEED); | |
162 | VERIFY0(bpobj_iterate(&ds_next->ds_deadlist.dl_bpobj, | |
163 | process_old_cb, &poa, tx)); | |
164 | VERIFY0(zio_wait(poa.pio)); | |
d683ddbb | 165 | ASSERT3U(poa.used, ==, dsl_dataset_phys(ds)->ds_unique_bytes); |
13fe0198 MA |
166 | |
167 | /* change snapused */ | |
168 | dsl_dir_diduse_space(ds->ds_dir, DD_USED_SNAP, | |
169 | -poa.used, -poa.comp, -poa.uncomp, tx); | |
170 | ||
171 | /* swap next's deadlist to our deadlist */ | |
172 | dsl_deadlist_close(&ds->ds_deadlist); | |
173 | dsl_deadlist_close(&ds_next->ds_deadlist); | |
d683ddbb JG |
174 | deadlist_obj = dsl_dataset_phys(ds)->ds_deadlist_obj; |
175 | dsl_dataset_phys(ds)->ds_deadlist_obj = | |
176 | dsl_dataset_phys(ds_next)->ds_deadlist_obj; | |
177 | dsl_dataset_phys(ds_next)->ds_deadlist_obj = deadlist_obj; | |
178 | dsl_deadlist_open(&ds->ds_deadlist, mos, | |
179 | dsl_dataset_phys(ds)->ds_deadlist_obj); | |
13fe0198 | 180 | dsl_deadlist_open(&ds_next->ds_deadlist, mos, |
d683ddbb | 181 | dsl_dataset_phys(ds_next)->ds_deadlist_obj); |
13fe0198 MA |
182 | } |
183 | ||
c434d880 | 184 | struct removeclonesnode { |
185 | list_node_t link; | |
186 | dsl_dataset_t *ds; | |
187 | }; | |
188 | ||
13fe0198 MA |
189 | static void |
190 | dsl_dataset_remove_clones_key(dsl_dataset_t *ds, uint64_t mintxg, dmu_tx_t *tx) | |
191 | { | |
192 | objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; | |
c434d880 | 193 | list_t clones; |
194 | struct removeclonesnode *rcn; | |
13fe0198 | 195 | |
c434d880 | 196 | list_create(&clones, sizeof (struct removeclonesnode), |
197 | offsetof(struct removeclonesnode, link)); | |
198 | ||
199 | rcn = kmem_zalloc(sizeof (struct removeclonesnode), KM_SLEEP); | |
200 | rcn->ds = ds; | |
201 | list_insert_head(&clones, rcn); | |
202 | ||
203 | for (; rcn != NULL; rcn = list_next(&clones, rcn)) { | |
204 | zap_cursor_t zc; | |
205 | zap_attribute_t za; | |
206 | /* | |
207 | * If it is the old version, dd_clones doesn't exist so we can't | |
208 | * find the clones, but dsl_deadlist_remove_key() is a no-op so | |
209 | * it doesn't matter. | |
210 | */ | |
211 | if (dsl_dir_phys(rcn->ds->ds_dir)->dd_clones == 0) | |
212 | continue; | |
213 | ||
214 | for (zap_cursor_init(&zc, mos, | |
215 | dsl_dir_phys(rcn->ds->ds_dir)->dd_clones); | |
216 | zap_cursor_retrieve(&zc, &za) == 0; | |
217 | zap_cursor_advance(&zc)) { | |
218 | dsl_dataset_t *clone; | |
219 | ||
220 | VERIFY0(dsl_dataset_hold_obj(rcn->ds->ds_dir->dd_pool, | |
221 | za.za_first_integer, FTAG, &clone)); | |
222 | if (clone->ds_dir->dd_origin_txg > mintxg) { | |
223 | dsl_deadlist_remove_key(&clone->ds_deadlist, | |
224 | mintxg, tx); | |
225 | if (dsl_dataset_remap_deadlist_exists(clone)) { | |
226 | dsl_deadlist_remove_key( | |
227 | &clone->ds_remap_deadlist, mintxg, | |
228 | tx); | |
229 | } | |
230 | rcn = kmem_zalloc( | |
231 | sizeof (struct removeclonesnode), KM_SLEEP); | |
232 | rcn->ds = clone; | |
233 | list_insert_tail(&clones, rcn); | |
234 | } else { | |
235 | dsl_dataset_rele(clone, FTAG); | |
a1d477c2 | 236 | } |
13fe0198 | 237 | } |
c434d880 | 238 | zap_cursor_fini(&zc); |
13fe0198 | 239 | } |
77831e17 | 240 | |
c434d880 | 241 | rcn = list_remove_head(&clones); |
242 | kmem_free(rcn, sizeof (struct removeclonesnode)); | |
243 | while ((rcn = list_remove_head(&clones)) != NULL) { | |
244 | dsl_dataset_rele(rcn->ds, FTAG); | |
245 | kmem_free(rcn, sizeof (struct removeclonesnode)); | |
246 | } | |
247 | list_destroy(&clones); | |
13fe0198 MA |
248 | } |
249 | ||
a1d477c2 MA |
250 | static void |
251 | dsl_destroy_snapshot_handle_remaps(dsl_dataset_t *ds, dsl_dataset_t *ds_next, | |
252 | dmu_tx_t *tx) | |
253 | { | |
254 | dsl_pool_t *dp = ds->ds_dir->dd_pool; | |
255 | ||
256 | /* Move blocks to be obsoleted to pool's obsolete list. */ | |
257 | if (dsl_dataset_remap_deadlist_exists(ds_next)) { | |
258 | if (!bpobj_is_open(&dp->dp_obsolete_bpobj)) | |
259 | dsl_pool_create_obsolete_bpobj(dp, tx); | |
260 | ||
261 | dsl_deadlist_move_bpobj(&ds_next->ds_remap_deadlist, | |
262 | &dp->dp_obsolete_bpobj, | |
263 | dsl_dataset_phys(ds)->ds_prev_snap_txg, tx); | |
264 | } | |
265 | ||
266 | /* Merge our deadlist into next's and free it. */ | |
267 | if (dsl_dataset_remap_deadlist_exists(ds)) { | |
268 | uint64_t remap_deadlist_object = | |
269 | dsl_dataset_get_remap_deadlist_object(ds); | |
270 | ASSERT(remap_deadlist_object != 0); | |
271 | ||
272 | mutex_enter(&ds_next->ds_remap_deadlist_lock); | |
273 | if (!dsl_dataset_remap_deadlist_exists(ds_next)) | |
274 | dsl_dataset_create_remap_deadlist(ds_next, tx); | |
275 | mutex_exit(&ds_next->ds_remap_deadlist_lock); | |
276 | ||
277 | dsl_deadlist_merge(&ds_next->ds_remap_deadlist, | |
278 | remap_deadlist_object, tx); | |
279 | dsl_dataset_destroy_remap_deadlist(ds, tx); | |
280 | } | |
281 | } | |
282 | ||
13fe0198 MA |
283 | void |
284 | dsl_destroy_snapshot_sync_impl(dsl_dataset_t *ds, boolean_t defer, dmu_tx_t *tx) | |
285 | { | |
13fe0198 MA |
286 | int after_branch_point = FALSE; |
287 | dsl_pool_t *dp = ds->ds_dir->dd_pool; | |
288 | objset_t *mos = dp->dp_meta_objset; | |
289 | dsl_dataset_t *ds_prev = NULL; | |
1c27024e | 290 | uint64_t obj; |
13fe0198 MA |
291 | |
292 | ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock)); | |
cc9bb3e5 | 293 | rrw_enter(&ds->ds_bp_rwlock, RW_READER, FTAG); |
d683ddbb | 294 | ASSERT3U(dsl_dataset_phys(ds)->ds_bp.blk_birth, <=, tx->tx_txg); |
cc9bb3e5 | 295 | rrw_exit(&ds->ds_bp_rwlock, FTAG); |
424fd7c3 | 296 | ASSERT(zfs_refcount_is_zero(&ds->ds_longholds)); |
13fe0198 MA |
297 | |
298 | if (defer && | |
d683ddbb JG |
299 | (ds->ds_userrefs > 0 || |
300 | dsl_dataset_phys(ds)->ds_num_children > 1)) { | |
13fe0198 MA |
301 | ASSERT(spa_version(dp->dp_spa) >= SPA_VERSION_USERREFS); |
302 | dmu_buf_will_dirty(ds->ds_dbuf, tx); | |
d683ddbb | 303 | dsl_dataset_phys(ds)->ds_flags |= DS_FLAG_DEFER_DESTROY; |
13fe0198 MA |
304 | spa_history_log_internal_ds(ds, "defer_destroy", tx, ""); |
305 | return; | |
306 | } | |
307 | ||
d683ddbb | 308 | ASSERT3U(dsl_dataset_phys(ds)->ds_num_children, <=, 1); |
13fe0198 MA |
309 | |
310 | /* We need to log before removing it from the namespace. */ | |
311 | spa_history_log_internal_ds(ds, "destroy", tx, ""); | |
312 | ||
313 | dsl_scan_ds_destroyed(ds, tx); | |
314 | ||
315 | obj = ds->ds_object; | |
316 | ||
1c27024e | 317 | for (spa_feature_t f = 0; f < SPA_FEATURES; f++) { |
d52d80b7 PD |
318 | if (dsl_dataset_feature_is_active(ds, f)) |
319 | dsl_dataset_deactivate_feature(ds, f, tx); | |
f1512ee6 | 320 | } |
d683ddbb | 321 | if (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) { |
13fe0198 MA |
322 | ASSERT3P(ds->ds_prev, ==, NULL); |
323 | VERIFY0(dsl_dataset_hold_obj(dp, | |
d683ddbb | 324 | dsl_dataset_phys(ds)->ds_prev_snap_obj, FTAG, &ds_prev)); |
13fe0198 | 325 | after_branch_point = |
d683ddbb | 326 | (dsl_dataset_phys(ds_prev)->ds_next_snap_obj != obj); |
13fe0198 MA |
327 | |
328 | dmu_buf_will_dirty(ds_prev->ds_dbuf, tx); | |
329 | if (after_branch_point && | |
d683ddbb | 330 | dsl_dataset_phys(ds_prev)->ds_next_clones_obj != 0) { |
13fe0198 | 331 | dsl_dataset_remove_from_next_clones(ds_prev, obj, tx); |
d683ddbb | 332 | if (dsl_dataset_phys(ds)->ds_next_snap_obj != 0) { |
13fe0198 | 333 | VERIFY0(zap_add_int(mos, |
d683ddbb JG |
334 | dsl_dataset_phys(ds_prev)-> |
335 | ds_next_clones_obj, | |
336 | dsl_dataset_phys(ds)->ds_next_snap_obj, | |
337 | tx)); | |
13fe0198 MA |
338 | } |
339 | } | |
340 | if (!after_branch_point) { | |
d683ddbb JG |
341 | dsl_dataset_phys(ds_prev)->ds_next_snap_obj = |
342 | dsl_dataset_phys(ds)->ds_next_snap_obj; | |
13fe0198 MA |
343 | } |
344 | } | |
345 | ||
1c27024e DB |
346 | dsl_dataset_t *ds_next; |
347 | uint64_t old_unique; | |
348 | uint64_t used = 0, comp = 0, uncomp = 0; | |
349 | ||
13fe0198 | 350 | VERIFY0(dsl_dataset_hold_obj(dp, |
d683ddbb JG |
351 | dsl_dataset_phys(ds)->ds_next_snap_obj, FTAG, &ds_next)); |
352 | ASSERT3U(dsl_dataset_phys(ds_next)->ds_prev_snap_obj, ==, obj); | |
13fe0198 | 353 | |
d683ddbb | 354 | old_unique = dsl_dataset_phys(ds_next)->ds_unique_bytes; |
13fe0198 MA |
355 | |
356 | dmu_buf_will_dirty(ds_next->ds_dbuf, tx); | |
d683ddbb JG |
357 | dsl_dataset_phys(ds_next)->ds_prev_snap_obj = |
358 | dsl_dataset_phys(ds)->ds_prev_snap_obj; | |
359 | dsl_dataset_phys(ds_next)->ds_prev_snap_txg = | |
360 | dsl_dataset_phys(ds)->ds_prev_snap_txg; | |
361 | ASSERT3U(dsl_dataset_phys(ds)->ds_prev_snap_txg, ==, | |
362 | ds_prev ? dsl_dataset_phys(ds_prev)->ds_creation_txg : 0); | |
13fe0198 MA |
363 | |
364 | if (ds_next->ds_deadlist.dl_oldfmt) { | |
365 | process_old_deadlist(ds, ds_prev, ds_next, | |
366 | after_branch_point, tx); | |
367 | } else { | |
368 | /* Adjust prev's unique space. */ | |
369 | if (ds_prev && !after_branch_point) { | |
370 | dsl_deadlist_space_range(&ds_next->ds_deadlist, | |
d683ddbb JG |
371 | dsl_dataset_phys(ds_prev)->ds_prev_snap_txg, |
372 | dsl_dataset_phys(ds)->ds_prev_snap_txg, | |
13fe0198 | 373 | &used, &comp, &uncomp); |
d683ddbb | 374 | dsl_dataset_phys(ds_prev)->ds_unique_bytes += used; |
13fe0198 MA |
375 | } |
376 | ||
377 | /* Adjust snapused. */ | |
378 | dsl_deadlist_space_range(&ds_next->ds_deadlist, | |
d683ddbb | 379 | dsl_dataset_phys(ds)->ds_prev_snap_txg, UINT64_MAX, |
13fe0198 MA |
380 | &used, &comp, &uncomp); |
381 | dsl_dir_diduse_space(ds->ds_dir, DD_USED_SNAP, | |
382 | -used, -comp, -uncomp, tx); | |
383 | ||
384 | /* Move blocks to be freed to pool's free list. */ | |
385 | dsl_deadlist_move_bpobj(&ds_next->ds_deadlist, | |
d683ddbb | 386 | &dp->dp_free_bpobj, dsl_dataset_phys(ds)->ds_prev_snap_txg, |
13fe0198 MA |
387 | tx); |
388 | dsl_dir_diduse_space(tx->tx_pool->dp_free_dir, | |
389 | DD_USED_HEAD, used, comp, uncomp, tx); | |
390 | ||
391 | /* Merge our deadlist into next's and free it. */ | |
392 | dsl_deadlist_merge(&ds_next->ds_deadlist, | |
d683ddbb | 393 | dsl_dataset_phys(ds)->ds_deadlist_obj, tx); |
13fe0198 | 394 | } |
a1d477c2 | 395 | |
13fe0198 | 396 | dsl_deadlist_close(&ds->ds_deadlist); |
d683ddbb | 397 | dsl_deadlist_free(mos, dsl_dataset_phys(ds)->ds_deadlist_obj, tx); |
13fe0198 | 398 | dmu_buf_will_dirty(ds->ds_dbuf, tx); |
d683ddbb | 399 | dsl_dataset_phys(ds)->ds_deadlist_obj = 0; |
13fe0198 | 400 | |
a1d477c2 MA |
401 | dsl_destroy_snapshot_handle_remaps(ds, ds_next, tx); |
402 | ||
13fe0198 MA |
403 | /* Collapse range in clone heads */ |
404 | dsl_dataset_remove_clones_key(ds, | |
d683ddbb | 405 | dsl_dataset_phys(ds)->ds_creation_txg, tx); |
13fe0198 | 406 | |
0c66c32d | 407 | if (ds_next->ds_is_snapshot) { |
13fe0198 MA |
408 | dsl_dataset_t *ds_nextnext; |
409 | ||
410 | /* | |
411 | * Update next's unique to include blocks which | |
412 | * were previously shared by only this snapshot | |
413 | * and it. Those blocks will be born after the | |
414 | * prev snap and before this snap, and will have | |
415 | * died after the next snap and before the one | |
416 | * after that (ie. be on the snap after next's | |
417 | * deadlist). | |
418 | */ | |
419 | VERIFY0(dsl_dataset_hold_obj(dp, | |
d683ddbb JG |
420 | dsl_dataset_phys(ds_next)->ds_next_snap_obj, |
421 | FTAG, &ds_nextnext)); | |
13fe0198 | 422 | dsl_deadlist_space_range(&ds_nextnext->ds_deadlist, |
d683ddbb JG |
423 | dsl_dataset_phys(ds)->ds_prev_snap_txg, |
424 | dsl_dataset_phys(ds)->ds_creation_txg, | |
13fe0198 | 425 | &used, &comp, &uncomp); |
d683ddbb | 426 | dsl_dataset_phys(ds_next)->ds_unique_bytes += used; |
13fe0198 MA |
427 | dsl_dataset_rele(ds_nextnext, FTAG); |
428 | ASSERT3P(ds_next->ds_prev, ==, NULL); | |
429 | ||
430 | /* Collapse range in this head. */ | |
1c27024e | 431 | dsl_dataset_t *hds; |
13fe0198 | 432 | VERIFY0(dsl_dataset_hold_obj(dp, |
d683ddbb | 433 | dsl_dir_phys(ds->ds_dir)->dd_head_dataset_obj, FTAG, &hds)); |
13fe0198 | 434 | dsl_deadlist_remove_key(&hds->ds_deadlist, |
d683ddbb | 435 | dsl_dataset_phys(ds)->ds_creation_txg, tx); |
a1d477c2 MA |
436 | if (dsl_dataset_remap_deadlist_exists(hds)) { |
437 | dsl_deadlist_remove_key(&hds->ds_remap_deadlist, | |
438 | dsl_dataset_phys(ds)->ds_creation_txg, tx); | |
439 | } | |
13fe0198 MA |
440 | dsl_dataset_rele(hds, FTAG); |
441 | ||
442 | } else { | |
443 | ASSERT3P(ds_next->ds_prev, ==, ds); | |
444 | dsl_dataset_rele(ds_next->ds_prev, ds_next); | |
445 | ds_next->ds_prev = NULL; | |
446 | if (ds_prev) { | |
447 | VERIFY0(dsl_dataset_hold_obj(dp, | |
d683ddbb | 448 | dsl_dataset_phys(ds)->ds_prev_snap_obj, |
13fe0198 MA |
449 | ds_next, &ds_next->ds_prev)); |
450 | } | |
451 | ||
452 | dsl_dataset_recalc_head_uniq(ds_next); | |
453 | ||
454 | /* | |
455 | * Reduce the amount of our unconsumed refreservation | |
456 | * being charged to our parent by the amount of | |
457 | * new unique data we have gained. | |
458 | */ | |
459 | if (old_unique < ds_next->ds_reserved) { | |
460 | int64_t mrsdelta; | |
461 | uint64_t new_unique = | |
d683ddbb | 462 | dsl_dataset_phys(ds_next)->ds_unique_bytes; |
13fe0198 MA |
463 | |
464 | ASSERT(old_unique <= new_unique); | |
465 | mrsdelta = MIN(new_unique - old_unique, | |
466 | ds_next->ds_reserved - old_unique); | |
467 | dsl_dir_diduse_space(ds->ds_dir, | |
468 | DD_USED_REFRSRV, -mrsdelta, 0, 0, tx); | |
469 | } | |
470 | } | |
471 | dsl_dataset_rele(ds_next, FTAG); | |
472 | ||
473 | /* | |
474 | * This must be done after the dsl_traverse(), because it will | |
475 | * re-open the objset. | |
476 | */ | |
477 | if (ds->ds_objset) { | |
478 | dmu_objset_evict(ds->ds_objset); | |
479 | ds->ds_objset = NULL; | |
480 | } | |
481 | ||
482 | /* remove from snapshot namespace */ | |
1c27024e | 483 | dsl_dataset_t *ds_head; |
d683ddbb | 484 | ASSERT(dsl_dataset_phys(ds)->ds_snapnames_zapobj == 0); |
13fe0198 | 485 | VERIFY0(dsl_dataset_hold_obj(dp, |
d683ddbb | 486 | dsl_dir_phys(ds->ds_dir)->dd_head_dataset_obj, FTAG, &ds_head)); |
13fe0198 MA |
487 | VERIFY0(dsl_dataset_get_snapname(ds)); |
488 | #ifdef ZFS_DEBUG | |
489 | { | |
490 | uint64_t val; | |
a0bd735a | 491 | int err; |
13fe0198 MA |
492 | |
493 | err = dsl_dataset_snap_lookup(ds_head, | |
494 | ds->ds_snapname, &val); | |
495 | ASSERT0(err); | |
496 | ASSERT3U(val, ==, obj); | |
497 | } | |
498 | #endif | |
788eb90c | 499 | VERIFY0(dsl_dataset_snap_remove(ds_head, ds->ds_snapname, tx, B_TRUE)); |
13fe0198 MA |
500 | dsl_dataset_rele(ds_head, FTAG); |
501 | ||
502 | if (ds_prev != NULL) | |
503 | dsl_dataset_rele(ds_prev, FTAG); | |
504 | ||
505 | spa_prop_clear_bootfs(dp->dp_spa, ds->ds_object, tx); | |
506 | ||
d683ddbb | 507 | if (dsl_dataset_phys(ds)->ds_next_clones_obj != 0) { |
13fe0198 MA |
508 | ASSERTV(uint64_t count); |
509 | ASSERT0(zap_count(mos, | |
d683ddbb JG |
510 | dsl_dataset_phys(ds)->ds_next_clones_obj, &count) && |
511 | count == 0); | |
13fe0198 | 512 | VERIFY0(dmu_object_free(mos, |
d683ddbb | 513 | dsl_dataset_phys(ds)->ds_next_clones_obj, tx)); |
13fe0198 | 514 | } |
d683ddbb JG |
515 | if (dsl_dataset_phys(ds)->ds_props_obj != 0) |
516 | VERIFY0(zap_destroy(mos, dsl_dataset_phys(ds)->ds_props_obj, | |
517 | tx)); | |
518 | if (dsl_dataset_phys(ds)->ds_userrefs_obj != 0) | |
519 | VERIFY0(zap_destroy(mos, dsl_dataset_phys(ds)->ds_userrefs_obj, | |
520 | tx)); | |
13fe0198 MA |
521 | dsl_dir_rele(ds->ds_dir, ds); |
522 | ds->ds_dir = NULL; | |
fa86b5db | 523 | dmu_object_free_zapified(mos, obj, tx); |
13fe0198 MA |
524 | } |
525 | ||
d99a0153 | 526 | void |
13fe0198 MA |
527 | dsl_destroy_snapshot_sync(void *arg, dmu_tx_t *tx) |
528 | { | |
d99a0153 CW |
529 | dsl_destroy_snapshot_arg_t *ddsa = arg; |
530 | const char *dsname = ddsa->ddsa_name; | |
531 | boolean_t defer = ddsa->ddsa_defer; | |
13fe0198 | 532 | |
d99a0153 CW |
533 | dsl_pool_t *dp = dmu_tx_pool(tx); |
534 | dsl_dataset_t *ds; | |
13fe0198 | 535 | |
d99a0153 CW |
536 | int error = dsl_dataset_hold(dp, dsname, FTAG, &ds); |
537 | if (error == ENOENT) | |
538 | return; | |
539 | ASSERT0(error); | |
540 | dsl_destroy_snapshot_sync_impl(ds, defer, tx); | |
541 | zvol_remove_minors(dp->dp_spa, dsname, B_TRUE); | |
542 | dsl_dataset_rele(ds, FTAG); | |
13fe0198 MA |
543 | } |
544 | ||
545 | /* | |
546 | * The semantics of this function are described in the comment above | |
547 | * lzc_destroy_snaps(). To summarize: | |
548 | * | |
549 | * The snapshots must all be in the same pool. | |
550 | * | |
551 | * Snapshots that don't exist will be silently ignored (considered to be | |
552 | * "already deleted"). | |
553 | * | |
554 | * On success, all snaps will be destroyed and this will return 0. | |
555 | * On failure, no snaps will be destroyed, the errlist will be filled in, | |
556 | * and this will return an errno. | |
557 | */ | |
558 | int | |
559 | dsl_destroy_snapshots_nvl(nvlist_t *snaps, boolean_t defer, | |
560 | nvlist_t *errlist) | |
561 | { | |
d99a0153 | 562 | if (nvlist_next_nvpair(snaps, NULL) == NULL) |
13fe0198 MA |
563 | return (0); |
564 | ||
d99a0153 CW |
565 | /* |
566 | * lzc_destroy_snaps() is documented to take an nvlist whose | |
8d103d88 SD |
567 | * values "don't matter". We need to convert that nvlist to |
568 | * one that we know can be converted to LUA. We also don't | |
569 | * care about any duplicate entries because the nvlist will | |
570 | * be converted to a LUA table which should take care of this. | |
d99a0153 | 571 | */ |
8d103d88 SD |
572 | nvlist_t *snaps_normalized; |
573 | VERIFY0(nvlist_alloc(&snaps_normalized, 0, KM_SLEEP)); | |
d99a0153 CW |
574 | for (nvpair_t *pair = nvlist_next_nvpair(snaps, NULL); |
575 | pair != NULL; pair = nvlist_next_nvpair(snaps, pair)) { | |
576 | fnvlist_add_boolean_value(snaps_normalized, | |
577 | nvpair_name(pair), B_TRUE); | |
578 | } | |
8d103d88 SD |
579 | |
580 | nvlist_t *arg; | |
581 | VERIFY0(nvlist_alloc(&arg, 0, KM_SLEEP)); | |
d99a0153 CW |
582 | fnvlist_add_nvlist(arg, "snaps", snaps_normalized); |
583 | fnvlist_free(snaps_normalized); | |
584 | fnvlist_add_boolean_value(arg, "defer", defer); | |
585 | ||
8d103d88 SD |
586 | nvlist_t *wrapper; |
587 | VERIFY0(nvlist_alloc(&wrapper, 0, KM_SLEEP)); | |
d99a0153 CW |
588 | fnvlist_add_nvlist(wrapper, ZCP_ARG_ARGLIST, arg); |
589 | fnvlist_free(arg); | |
590 | ||
591 | const char *program = | |
592 | "arg = ...\n" | |
593 | "snaps = arg['snaps']\n" | |
594 | "defer = arg['defer']\n" | |
595 | "errors = { }\n" | |
596 | "has_errors = false\n" | |
597 | "for snap, v in pairs(snaps) do\n" | |
598 | " errno = zfs.check.destroy{snap, defer=defer}\n" | |
599 | " zfs.debug('snap: ' .. snap .. ' errno: ' .. errno)\n" | |
600 | " if errno == ENOENT then\n" | |
601 | " snaps[snap] = nil\n" | |
602 | " elseif errno ~= 0 then\n" | |
603 | " errors[snap] = errno\n" | |
604 | " has_errors = true\n" | |
605 | " end\n" | |
606 | "end\n" | |
607 | "if has_errors then\n" | |
608 | " return errors\n" | |
609 | "end\n" | |
610 | "for snap, v in pairs(snaps) do\n" | |
611 | " errno = zfs.sync.destroy{snap, defer=defer}\n" | |
612 | " assert(errno == 0)\n" | |
613 | "end\n" | |
614 | "return { }\n"; | |
615 | ||
616 | nvlist_t *result = fnvlist_alloc(); | |
617 | int error = zcp_eval(nvpair_name(nvlist_next_nvpair(snaps, NULL)), | |
618 | program, | |
5b72a38d | 619 | B_TRUE, |
d99a0153 CW |
620 | 0, |
621 | zfs_lua_max_memlimit, | |
8d103d88 | 622 | nvlist_next_nvpair(wrapper, NULL), result); |
d99a0153 CW |
623 | if (error != 0) { |
624 | char *errorstr = NULL; | |
625 | (void) nvlist_lookup_string(result, ZCP_RET_ERROR, &errorstr); | |
626 | if (errorstr != NULL) { | |
627 | zfs_dbgmsg(errorstr); | |
628 | } | |
629 | return (error); | |
630 | } | |
631 | fnvlist_free(wrapper); | |
13fe0198 | 632 | |
d99a0153 CW |
633 | /* |
634 | * lzc_destroy_snaps() is documented to fill the errlist with | |
635 | * int32 values, so we need to covert the int64 values that are | |
636 | * returned from LUA. | |
637 | */ | |
638 | int rv = 0; | |
639 | nvlist_t *errlist_raw = fnvlist_lookup_nvlist(result, ZCP_RET_RETURN); | |
640 | for (nvpair_t *pair = nvlist_next_nvpair(errlist_raw, NULL); | |
641 | pair != NULL; pair = nvlist_next_nvpair(errlist_raw, pair)) { | |
642 | int32_t val = (int32_t)fnvpair_value_int64(pair); | |
643 | if (rv == 0) | |
644 | rv = val; | |
645 | fnvlist_add_int32(errlist, nvpair_name(pair), val); | |
646 | } | |
647 | fnvlist_free(result); | |
648 | return (rv); | |
13fe0198 MA |
649 | } |
650 | ||
651 | int | |
652 | dsl_destroy_snapshot(const char *name, boolean_t defer) | |
653 | { | |
654 | int error; | |
79c76d5b BB |
655 | nvlist_t *nvl = fnvlist_alloc(); |
656 | nvlist_t *errlist = fnvlist_alloc(); | |
13fe0198 MA |
657 | |
658 | fnvlist_add_boolean(nvl, name); | |
659 | error = dsl_destroy_snapshots_nvl(nvl, defer, errlist); | |
660 | fnvlist_free(errlist); | |
661 | fnvlist_free(nvl); | |
662 | return (error); | |
663 | } | |
664 | ||
665 | struct killarg { | |
666 | dsl_dataset_t *ds; | |
667 | dmu_tx_t *tx; | |
668 | }; | |
669 | ||
670 | /* ARGSUSED */ | |
671 | static int | |
672 | kill_blkptr(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, | |
5dbd68a3 | 673 | const zbookmark_phys_t *zb, const dnode_phys_t *dnp, void *arg) |
13fe0198 MA |
674 | { |
675 | struct killarg *ka = arg; | |
676 | dmu_tx_t *tx = ka->tx; | |
677 | ||
fcff0f35 | 678 | if (bp == NULL || BP_IS_HOLE(bp) || BP_IS_EMBEDDED(bp)) |
13fe0198 MA |
679 | return (0); |
680 | ||
681 | if (zb->zb_level == ZB_ZIL_LEVEL) { | |
682 | ASSERT(zilog != NULL); | |
683 | /* | |
684 | * It's a block in the intent log. It has no | |
685 | * accounting, so just free it. | |
686 | */ | |
687 | dsl_free(ka->tx->tx_pool, ka->tx->tx_txg, bp); | |
688 | } else { | |
689 | ASSERT(zilog == NULL); | |
d683ddbb JG |
690 | ASSERT3U(bp->blk_birth, >, |
691 | dsl_dataset_phys(ka->ds)->ds_prev_snap_txg); | |
13fe0198 MA |
692 | (void) dsl_dataset_block_kill(ka->ds, bp, tx, B_FALSE); |
693 | } | |
694 | ||
695 | return (0); | |
696 | } | |
697 | ||
698 | static void | |
699 | old_synchronous_dataset_destroy(dsl_dataset_t *ds, dmu_tx_t *tx) | |
700 | { | |
701 | struct killarg ka; | |
702 | ||
703 | /* | |
704 | * Free everything that we point to (that's born after | |
705 | * the previous snapshot, if we are a clone) | |
706 | * | |
707 | * NB: this should be very quick, because we already | |
708 | * freed all the objects in open context. | |
709 | */ | |
710 | ka.ds = ds; | |
711 | ka.tx = tx; | |
712 | VERIFY0(traverse_dataset(ds, | |
b5256303 TC |
713 | dsl_dataset_phys(ds)->ds_prev_snap_txg, TRAVERSE_POST | |
714 | TRAVERSE_NO_DECRYPT, kill_blkptr, &ka)); | |
d683ddbb JG |
715 | ASSERT(!DS_UNIQUE_IS_ACCURATE(ds) || |
716 | dsl_dataset_phys(ds)->ds_unique_bytes == 0); | |
13fe0198 MA |
717 | } |
718 | ||
13fe0198 MA |
719 | int |
720 | dsl_destroy_head_check_impl(dsl_dataset_t *ds, int expected_holds) | |
721 | { | |
722 | int error; | |
723 | uint64_t count; | |
724 | objset_t *mos; | |
725 | ||
0c66c32d JG |
726 | ASSERT(!ds->ds_is_snapshot); |
727 | if (ds->ds_is_snapshot) | |
2e528b49 | 728 | return (SET_ERROR(EINVAL)); |
13fe0198 | 729 | |
424fd7c3 | 730 | if (zfs_refcount_count(&ds->ds_longholds) != expected_holds) |
2e528b49 | 731 | return (SET_ERROR(EBUSY)); |
13fe0198 MA |
732 | |
733 | mos = ds->ds_dir->dd_pool->dp_meta_objset; | |
734 | ||
735 | /* | |
736 | * Can't delete a head dataset if there are snapshots of it. | |
737 | * (Except if the only snapshots are from the branch we cloned | |
738 | * from.) | |
739 | */ | |
740 | if (ds->ds_prev != NULL && | |
d683ddbb | 741 | dsl_dataset_phys(ds->ds_prev)->ds_next_snap_obj == ds->ds_object) |
2e528b49 | 742 | return (SET_ERROR(EBUSY)); |
13fe0198 MA |
743 | |
744 | /* | |
745 | * Can't delete if there are children of this fs. | |
746 | */ | |
747 | error = zap_count(mos, | |
d683ddbb | 748 | dsl_dir_phys(ds->ds_dir)->dd_child_dir_zapobj, &count); |
13fe0198 MA |
749 | if (error != 0) |
750 | return (error); | |
751 | if (count != 0) | |
2e528b49 | 752 | return (SET_ERROR(EEXIST)); |
13fe0198 MA |
753 | |
754 | if (dsl_dir_is_clone(ds->ds_dir) && DS_IS_DEFER_DESTROY(ds->ds_prev) && | |
d683ddbb | 755 | dsl_dataset_phys(ds->ds_prev)->ds_num_children == 2 && |
13fe0198 MA |
756 | ds->ds_prev->ds_userrefs == 0) { |
757 | /* We need to remove the origin snapshot as well. */ | |
424fd7c3 | 758 | if (!zfs_refcount_is_zero(&ds->ds_prev->ds_longholds)) |
2e528b49 | 759 | return (SET_ERROR(EBUSY)); |
13fe0198 MA |
760 | } |
761 | return (0); | |
762 | } | |
763 | ||
d99a0153 | 764 | int |
13fe0198 MA |
765 | dsl_destroy_head_check(void *arg, dmu_tx_t *tx) |
766 | { | |
767 | dsl_destroy_head_arg_t *ddha = arg; | |
768 | dsl_pool_t *dp = dmu_tx_pool(tx); | |
769 | dsl_dataset_t *ds; | |
770 | int error; | |
771 | ||
772 | error = dsl_dataset_hold(dp, ddha->ddha_name, FTAG, &ds); | |
773 | if (error != 0) | |
774 | return (error); | |
775 | ||
776 | error = dsl_destroy_head_check_impl(ds, 0); | |
777 | dsl_dataset_rele(ds, FTAG); | |
778 | return (error); | |
779 | } | |
780 | ||
781 | static void | |
782 | dsl_dir_destroy_sync(uint64_t ddobj, dmu_tx_t *tx) | |
783 | { | |
784 | dsl_dir_t *dd; | |
785 | dsl_pool_t *dp = dmu_tx_pool(tx); | |
786 | objset_t *mos = dp->dp_meta_objset; | |
787 | dd_used_t t; | |
788 | ||
789 | ASSERT(RRW_WRITE_HELD(&dmu_tx_pool(tx)->dp_config_rwlock)); | |
790 | ||
791 | VERIFY0(dsl_dir_hold_obj(dp, ddobj, NULL, FTAG, &dd)); | |
792 | ||
d683ddbb | 793 | ASSERT0(dsl_dir_phys(dd)->dd_head_dataset_obj); |
13fe0198 | 794 | |
0f5f2386 | 795 | /* Decrement the filesystem count for all parent filesystems. */ |
796 | if (dd->dd_parent != NULL) | |
788eb90c JJ |
797 | dsl_fs_ss_count_adjust(dd->dd_parent, -1, |
798 | DD_FIELD_FILESYSTEM_COUNT, tx); | |
799 | ||
13fe0198 MA |
800 | /* |
801 | * Remove our reservation. The impl() routine avoids setting the | |
802 | * actual property, which would require the (already destroyed) ds. | |
803 | */ | |
804 | dsl_dir_set_reservation_sync_impl(dd, 0, tx); | |
805 | ||
d683ddbb JG |
806 | ASSERT0(dsl_dir_phys(dd)->dd_used_bytes); |
807 | ASSERT0(dsl_dir_phys(dd)->dd_reserved); | |
13fe0198 | 808 | for (t = 0; t < DD_USED_NUM; t++) |
d683ddbb | 809 | ASSERT0(dsl_dir_phys(dd)->dd_used_breakdown[t]); |
13fe0198 | 810 | |
b5256303 TC |
811 | if (dd->dd_crypto_obj != 0) { |
812 | dsl_crypto_key_destroy_sync(dd->dd_crypto_obj, tx); | |
813 | (void) spa_keystore_unload_wkey_impl(dp->dp_spa, dd->dd_object); | |
814 | } | |
815 | ||
d683ddbb JG |
816 | VERIFY0(zap_destroy(mos, dsl_dir_phys(dd)->dd_child_dir_zapobj, tx)); |
817 | VERIFY0(zap_destroy(mos, dsl_dir_phys(dd)->dd_props_zapobj, tx)); | |
0aa5916a MA |
818 | if (dsl_dir_phys(dd)->dd_clones != 0) |
819 | VERIFY0(zap_destroy(mos, dsl_dir_phys(dd)->dd_clones, tx)); | |
d683ddbb | 820 | VERIFY0(dsl_deleg_destroy(mos, dsl_dir_phys(dd)->dd_deleg_zapobj, tx)); |
13fe0198 | 821 | VERIFY0(zap_remove(mos, |
d683ddbb JG |
822 | dsl_dir_phys(dd->dd_parent)->dd_child_dir_zapobj, |
823 | dd->dd_myname, tx)); | |
13fe0198 MA |
824 | |
825 | dsl_dir_rele(dd, FTAG); | |
fa86b5db | 826 | dmu_object_free_zapified(mos, ddobj, tx); |
13fe0198 MA |
827 | } |
828 | ||
829 | void | |
830 | dsl_destroy_head_sync_impl(dsl_dataset_t *ds, dmu_tx_t *tx) | |
831 | { | |
832 | dsl_pool_t *dp = dmu_tx_pool(tx); | |
833 | objset_t *mos = dp->dp_meta_objset; | |
834 | uint64_t obj, ddobj, prevobj = 0; | |
835 | boolean_t rmorigin; | |
13fe0198 | 836 | |
d683ddbb | 837 | ASSERT3U(dsl_dataset_phys(ds)->ds_num_children, <=, 1); |
13fe0198 | 838 | ASSERT(ds->ds_prev == NULL || |
d683ddbb | 839 | dsl_dataset_phys(ds->ds_prev)->ds_next_snap_obj != ds->ds_object); |
cc9bb3e5 | 840 | rrw_enter(&ds->ds_bp_rwlock, RW_READER, FTAG); |
d683ddbb | 841 | ASSERT3U(dsl_dataset_phys(ds)->ds_bp.blk_birth, <=, tx->tx_txg); |
cc9bb3e5 | 842 | rrw_exit(&ds->ds_bp_rwlock, FTAG); |
13fe0198 MA |
843 | ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock)); |
844 | ||
845 | /* We need to log before removing it from the namespace. */ | |
846 | spa_history_log_internal_ds(ds, "destroy", tx, ""); | |
847 | ||
848 | rmorigin = (dsl_dir_is_clone(ds->ds_dir) && | |
849 | DS_IS_DEFER_DESTROY(ds->ds_prev) && | |
d683ddbb | 850 | dsl_dataset_phys(ds->ds_prev)->ds_num_children == 2 && |
13fe0198 MA |
851 | ds->ds_prev->ds_userrefs == 0); |
852 | ||
9b67f605 | 853 | /* Remove our reservation. */ |
13fe0198 MA |
854 | if (ds->ds_reserved != 0) { |
855 | dsl_dataset_set_refreservation_sync_impl(ds, | |
856 | (ZPROP_SRC_NONE | ZPROP_SRC_LOCAL | ZPROP_SRC_RECEIVED), | |
857 | 0, tx); | |
858 | ASSERT0(ds->ds_reserved); | |
859 | } | |
860 | ||
241b5415 | 861 | obj = ds->ds_object; |
f1512ee6 | 862 | |
1c27024e | 863 | for (spa_feature_t f = 0; f < SPA_FEATURES; f++) { |
d52d80b7 PD |
864 | if (dsl_dataset_feature_is_active(ds, f)) |
865 | dsl_dataset_deactivate_feature(ds, f, tx); | |
241b5415 | 866 | } |
13fe0198 | 867 | |
241b5415 | 868 | dsl_scan_ds_destroyed(ds, tx); |
13fe0198 | 869 | |
d683ddbb | 870 | if (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) { |
13fe0198 MA |
871 | /* This is a clone */ |
872 | ASSERT(ds->ds_prev != NULL); | |
d683ddbb JG |
873 | ASSERT3U(dsl_dataset_phys(ds->ds_prev)->ds_next_snap_obj, !=, |
874 | obj); | |
875 | ASSERT0(dsl_dataset_phys(ds)->ds_next_snap_obj); | |
13fe0198 MA |
876 | |
877 | dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); | |
d683ddbb | 878 | if (dsl_dataset_phys(ds->ds_prev)->ds_next_clones_obj != 0) { |
13fe0198 MA |
879 | dsl_dataset_remove_from_next_clones(ds->ds_prev, |
880 | obj, tx); | |
881 | } | |
882 | ||
d683ddbb JG |
883 | ASSERT3U(dsl_dataset_phys(ds->ds_prev)->ds_num_children, >, 1); |
884 | dsl_dataset_phys(ds->ds_prev)->ds_num_children--; | |
13fe0198 MA |
885 | } |
886 | ||
13fe0198 MA |
887 | /* |
888 | * Destroy the deadlist. Unless it's a clone, the | |
a1d477c2 MA |
889 | * deadlist should be empty since the dataset has no snapshots. |
890 | * (If it's a clone, it's safe to ignore the deadlist contents | |
891 | * since they are still referenced by the origin snapshot.) | |
13fe0198 MA |
892 | */ |
893 | dsl_deadlist_close(&ds->ds_deadlist); | |
d683ddbb | 894 | dsl_deadlist_free(mos, dsl_dataset_phys(ds)->ds_deadlist_obj, tx); |
13fe0198 | 895 | dmu_buf_will_dirty(ds->ds_dbuf, tx); |
d683ddbb | 896 | dsl_dataset_phys(ds)->ds_deadlist_obj = 0; |
13fe0198 | 897 | |
a1d477c2 MA |
898 | if (dsl_dataset_remap_deadlist_exists(ds)) |
899 | dsl_dataset_destroy_remap_deadlist(ds, tx); | |
900 | ||
1c27024e | 901 | objset_t *os; |
13fe0198 MA |
902 | VERIFY0(dmu_objset_from_ds(ds, &os)); |
903 | ||
fa86b5db | 904 | if (!spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_ASYNC_DESTROY)) { |
13fe0198 MA |
905 | old_synchronous_dataset_destroy(ds, tx); |
906 | } else { | |
907 | /* | |
908 | * Move the bptree into the pool's list of trees to | |
909 | * clean up and update space accounting information. | |
910 | */ | |
911 | uint64_t used, comp, uncomp; | |
912 | ||
913 | zil_destroy_sync(dmu_objset_zil(os), tx); | |
914 | ||
fa86b5db MA |
915 | if (!spa_feature_is_active(dp->dp_spa, |
916 | SPA_FEATURE_ASYNC_DESTROY)) { | |
2696dfaf | 917 | dsl_scan_t *scn = dp->dp_scan; |
fa86b5db MA |
918 | spa_feature_incr(dp->dp_spa, SPA_FEATURE_ASYNC_DESTROY, |
919 | tx); | |
13fe0198 MA |
920 | dp->dp_bptree_obj = bptree_alloc(mos, tx); |
921 | VERIFY0(zap_add(mos, | |
922 | DMU_POOL_DIRECTORY_OBJECT, | |
923 | DMU_POOL_BPTREE_OBJ, sizeof (uint64_t), 1, | |
924 | &dp->dp_bptree_obj, tx)); | |
2696dfaf GW |
925 | ASSERT(!scn->scn_async_destroying); |
926 | scn->scn_async_destroying = B_TRUE; | |
13fe0198 MA |
927 | } |
928 | ||
d683ddbb JG |
929 | used = dsl_dir_phys(ds->ds_dir)->dd_used_bytes; |
930 | comp = dsl_dir_phys(ds->ds_dir)->dd_compressed_bytes; | |
931 | uncomp = dsl_dir_phys(ds->ds_dir)->dd_uncompressed_bytes; | |
13fe0198 MA |
932 | |
933 | ASSERT(!DS_UNIQUE_IS_ACCURATE(ds) || | |
d683ddbb | 934 | dsl_dataset_phys(ds)->ds_unique_bytes == used); |
13fe0198 | 935 | |
cc9bb3e5 | 936 | rrw_enter(&ds->ds_bp_rwlock, RW_READER, FTAG); |
13fe0198 | 937 | bptree_add(mos, dp->dp_bptree_obj, |
d683ddbb JG |
938 | &dsl_dataset_phys(ds)->ds_bp, |
939 | dsl_dataset_phys(ds)->ds_prev_snap_txg, | |
13fe0198 | 940 | used, comp, uncomp, tx); |
cc9bb3e5 | 941 | rrw_exit(&ds->ds_bp_rwlock, FTAG); |
13fe0198 MA |
942 | dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, |
943 | -used, -comp, -uncomp, tx); | |
944 | dsl_dir_diduse_space(dp->dp_free_dir, DD_USED_HEAD, | |
945 | used, comp, uncomp, tx); | |
946 | } | |
947 | ||
948 | if (ds->ds_prev != NULL) { | |
949 | if (spa_version(dp->dp_spa) >= SPA_VERSION_DIR_CLONES) { | |
950 | VERIFY0(zap_remove_int(mos, | |
d683ddbb | 951 | dsl_dir_phys(ds->ds_prev->ds_dir)->dd_clones, |
13fe0198 MA |
952 | ds->ds_object, tx)); |
953 | } | |
954 | prevobj = ds->ds_prev->ds_object; | |
955 | dsl_dataset_rele(ds->ds_prev, ds); | |
956 | ds->ds_prev = NULL; | |
957 | } | |
958 | ||
959 | /* | |
960 | * This must be done after the dsl_traverse(), because it will | |
961 | * re-open the objset. | |
962 | */ | |
963 | if (ds->ds_objset) { | |
964 | dmu_objset_evict(ds->ds_objset); | |
965 | ds->ds_objset = NULL; | |
966 | } | |
967 | ||
968 | /* Erase the link in the dir */ | |
969 | dmu_buf_will_dirty(ds->ds_dir->dd_dbuf, tx); | |
d683ddbb | 970 | dsl_dir_phys(ds->ds_dir)->dd_head_dataset_obj = 0; |
13fe0198 | 971 | ddobj = ds->ds_dir->dd_object; |
d683ddbb JG |
972 | ASSERT(dsl_dataset_phys(ds)->ds_snapnames_zapobj != 0); |
973 | VERIFY0(zap_destroy(mos, | |
974 | dsl_dataset_phys(ds)->ds_snapnames_zapobj, tx)); | |
13fe0198 | 975 | |
da536844 | 976 | if (ds->ds_bookmarks != 0) { |
d683ddbb | 977 | VERIFY0(zap_destroy(mos, ds->ds_bookmarks, tx)); |
da536844 MA |
978 | spa_feature_decr(dp->dp_spa, SPA_FEATURE_BOOKMARKS, tx); |
979 | } | |
980 | ||
13fe0198 MA |
981 | spa_prop_clear_bootfs(dp->dp_spa, ds->ds_object, tx); |
982 | ||
d683ddbb JG |
983 | ASSERT0(dsl_dataset_phys(ds)->ds_next_clones_obj); |
984 | ASSERT0(dsl_dataset_phys(ds)->ds_props_obj); | |
985 | ASSERT0(dsl_dataset_phys(ds)->ds_userrefs_obj); | |
13fe0198 MA |
986 | dsl_dir_rele(ds->ds_dir, ds); |
987 | ds->ds_dir = NULL; | |
fa86b5db | 988 | dmu_object_free_zapified(mos, obj, tx); |
13fe0198 MA |
989 | |
990 | dsl_dir_destroy_sync(ddobj, tx); | |
991 | ||
992 | if (rmorigin) { | |
993 | dsl_dataset_t *prev; | |
994 | VERIFY0(dsl_dataset_hold_obj(dp, prevobj, FTAG, &prev)); | |
995 | dsl_destroy_snapshot_sync_impl(prev, B_FALSE, tx); | |
996 | dsl_dataset_rele(prev, FTAG); | |
997 | } | |
998 | } | |
999 | ||
d99a0153 | 1000 | void |
13fe0198 MA |
1001 | dsl_destroy_head_sync(void *arg, dmu_tx_t *tx) |
1002 | { | |
1003 | dsl_destroy_head_arg_t *ddha = arg; | |
1004 | dsl_pool_t *dp = dmu_tx_pool(tx); | |
1005 | dsl_dataset_t *ds; | |
1006 | ||
1007 | VERIFY0(dsl_dataset_hold(dp, ddha->ddha_name, FTAG, &ds)); | |
1008 | dsl_destroy_head_sync_impl(ds, tx); | |
a0bd735a | 1009 | zvol_remove_minors(dp->dp_spa, ddha->ddha_name, B_TRUE); |
13fe0198 MA |
1010 | dsl_dataset_rele(ds, FTAG); |
1011 | } | |
1012 | ||
1013 | static void | |
1014 | dsl_destroy_head_begin_sync(void *arg, dmu_tx_t *tx) | |
1015 | { | |
1016 | dsl_destroy_head_arg_t *ddha = arg; | |
1017 | dsl_pool_t *dp = dmu_tx_pool(tx); | |
1018 | dsl_dataset_t *ds; | |
1019 | ||
1020 | VERIFY0(dsl_dataset_hold(dp, ddha->ddha_name, FTAG, &ds)); | |
1021 | ||
1022 | /* Mark it as inconsistent on-disk, in case we crash */ | |
1023 | dmu_buf_will_dirty(ds->ds_dbuf, tx); | |
d683ddbb | 1024 | dsl_dataset_phys(ds)->ds_flags |= DS_FLAG_INCONSISTENT; |
13fe0198 MA |
1025 | |
1026 | spa_history_log_internal_ds(ds, "destroy begin", tx, ""); | |
1027 | dsl_dataset_rele(ds, FTAG); | |
1028 | } | |
1029 | ||
1030 | int | |
1031 | dsl_destroy_head(const char *name) | |
1032 | { | |
1033 | dsl_destroy_head_arg_t ddha; | |
1034 | int error; | |
1035 | spa_t *spa; | |
1036 | boolean_t isenabled; | |
1037 | ||
1038 | #ifdef _KERNEL | |
1039 | zfs_destroy_unmount_origin(name); | |
1040 | #endif | |
1041 | ||
1042 | error = spa_open(name, &spa, FTAG); | |
1043 | if (error != 0) | |
1044 | return (error); | |
fa86b5db | 1045 | isenabled = spa_feature_is_enabled(spa, SPA_FEATURE_ASYNC_DESTROY); |
13fe0198 MA |
1046 | spa_close(spa, FTAG); |
1047 | ||
1048 | ddha.ddha_name = name; | |
1049 | ||
1050 | if (!isenabled) { | |
1051 | objset_t *os; | |
1052 | ||
1053 | error = dsl_sync_task(name, dsl_destroy_head_check, | |
3d45fdd6 | 1054 | dsl_destroy_head_begin_sync, &ddha, |
d2734cce | 1055 | 0, ZFS_SPACE_CHECK_DESTROY); |
13fe0198 MA |
1056 | if (error != 0) |
1057 | return (error); | |
1058 | ||
1059 | /* | |
1060 | * Head deletion is processed in one txg on old pools; | |
1061 | * remove the objects from open context so that the txg sync | |
1062 | * is not too long. | |
1063 | */ | |
b5256303 TC |
1064 | error = dmu_objset_own(name, DMU_OST_ANY, B_FALSE, B_FALSE, |
1065 | FTAG, &os); | |
13fe0198 | 1066 | if (error == 0) { |
13fe0198 | 1067 | uint64_t prev_snap_txg = |
d683ddbb JG |
1068 | dsl_dataset_phys(dmu_objset_ds(os))-> |
1069 | ds_prev_snap_txg; | |
1c27024e | 1070 | for (uint64_t obj = 0; error == 0; |
13fe0198 MA |
1071 | error = dmu_object_next(os, &obj, FALSE, |
1072 | prev_snap_txg)) | |
b663a23d | 1073 | (void) dmu_free_long_object(os, obj); |
13fe0198 MA |
1074 | /* sync out all frees */ |
1075 | txg_wait_synced(dmu_objset_pool(os), 0); | |
b5256303 | 1076 | dmu_objset_disown(os, B_FALSE, FTAG); |
13fe0198 MA |
1077 | } |
1078 | } | |
1079 | ||
1080 | return (dsl_sync_task(name, dsl_destroy_head_check, | |
d2734cce | 1081 | dsl_destroy_head_sync, &ddha, 0, ZFS_SPACE_CHECK_DESTROY)); |
13fe0198 MA |
1082 | } |
1083 | ||
1084 | /* | |
1085 | * Note, this function is used as the callback for dmu_objset_find(). We | |
1086 | * always return 0 so that we will continue to find and process | |
1087 | * inconsistent datasets, even if we encounter an error trying to | |
1088 | * process one of them. | |
1089 | */ | |
1090 | /* ARGSUSED */ | |
1091 | int | |
1092 | dsl_destroy_inconsistent(const char *dsname, void *arg) | |
1093 | { | |
1094 | objset_t *os; | |
1095 | ||
1096 | if (dmu_objset_hold(dsname, FTAG, &os) == 0) { | |
47dfff3b MA |
1097 | boolean_t need_destroy = DS_IS_INCONSISTENT(dmu_objset_ds(os)); |
1098 | ||
1099 | /* | |
1100 | * If the dataset is inconsistent because a resumable receive | |
1101 | * has failed, then do not destroy it. | |
1102 | */ | |
1103 | if (dsl_dataset_has_resume_receive_state(dmu_objset_ds(os))) | |
1104 | need_destroy = B_FALSE; | |
1105 | ||
13fe0198 | 1106 | dmu_objset_rele(os, FTAG); |
47dfff3b | 1107 | if (need_destroy) |
13fe0198 MA |
1108 | (void) dsl_destroy_head(dsname); |
1109 | } | |
1110 | return (0); | |
1111 | } | |
1112 | ||
1113 | ||
93ce2b4c | 1114 | #if defined(_KERNEL) |
13fe0198 MA |
1115 | EXPORT_SYMBOL(dsl_destroy_head); |
1116 | EXPORT_SYMBOL(dsl_destroy_head_sync_impl); | |
1117 | EXPORT_SYMBOL(dsl_dataset_user_hold_check_one); | |
1118 | EXPORT_SYMBOL(dsl_destroy_snapshot_sync_impl); | |
1119 | EXPORT_SYMBOL(dsl_destroy_inconsistent); | |
1120 | EXPORT_SYMBOL(dsl_dataset_user_release_tmp); | |
1121 | EXPORT_SYMBOL(dsl_destroy_head_check_impl); | |
1122 | #endif |