Mercurial > illumos > illumos-gate
annotate usr/src/uts/common/fs/zfs/dsl_dataset.c @ 5094:71a3e95fb9e2
PSARC 2007/342 Enhanced ZFS Pool Properties
PSARC 2007/482 zpool upgrade -V
6565437 zpool property extensions
6561384 want 'zpool upgrade -V <version>' to upgrade to specific version number
6582755 zfs.h has some incorrect version macros
6595601 libzfs headers declare functions which don't exist
6603938 libzfs is using VERIFY() again
6538984 duplicated messages when get pool properties from an unsupported pool version
author | lling |
---|---|
date | Wed, 19 Sep 2007 10:32:40 -0700 |
parents | 8d0de61ff354 |
children | 6752aa2bd5bc |
rev | line source |
---|---|
789 | 1 /* |
2 * CDDL HEADER START | |
3 * | |
4 * The contents of this file are subject to the terms of the | |
1544 | 5 * Common Development and Distribution License (the "License"). |
6 * You may not use this file except in compliance with the License. | |
789 | 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 /* | |
3444
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3025
diff
changeset
|
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. |
789 | 23 * Use is subject to license terms. |
24 */ | |
25 | |
26 #pragma ident "%Z%%M% %I% %E% SMI" | |
27 | |
28 #include <sys/dmu_objset.h> | |
29 #include <sys/dsl_dataset.h> | |
30 #include <sys/dsl_dir.h> | |
2082 | 31 #include <sys/dsl_prop.h> |
2199 | 32 #include <sys/dsl_synctask.h> |
789 | 33 #include <sys/dmu_traverse.h> |
34 #include <sys/dmu_tx.h> | |
35 #include <sys/arc.h> | |
36 #include <sys/zio.h> | |
37 #include <sys/zap.h> | |
38 #include <sys/unique.h> | |
39 #include <sys/zfs_context.h> | |
4007 | 40 #include <sys/zfs_ioctl.h> |
4543 | 41 #include <sys/spa.h> |
42 #include <sys/sunddi.h> | |
789 | 43 |
2199 | 44 static dsl_checkfunc_t dsl_dataset_destroy_begin_check; |
45 static dsl_syncfunc_t dsl_dataset_destroy_begin_sync; | |
46 static dsl_checkfunc_t dsl_dataset_rollback_check; | |
47 static dsl_syncfunc_t dsl_dataset_rollback_sync; | |
48 static dsl_checkfunc_t dsl_dataset_destroy_check; | |
49 static dsl_syncfunc_t dsl_dataset_destroy_sync; | |
1731
1efa8b3d1296
6402598 'zfs destroy <fs>' can take a long time, stopping up the txg train
bonwick
parents:
1544
diff
changeset
|
50 |
3444
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3025
diff
changeset
|
51 #define DS_REF_MAX (1ULL << 62) |
789 | 52 |
53 #define DSL_DEADLIST_BLOCKSIZE SPA_MAXBLOCKSIZE | |
54 | |
55 /* | |
56 * We use weighted reference counts to express the various forms of exclusion | |
57 * between different open modes. A STANDARD open is 1 point, an EXCLUSIVE open | |
3444
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3025
diff
changeset
|
58 * is DS_REF_MAX, and a PRIMARY open is little more than half of an EXCLUSIVE. |
789 | 59 * This makes the exclusion logic simple: the total refcnt for all opens cannot |
3444
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3025
diff
changeset
|
60 * exceed DS_REF_MAX. For example, EXCLUSIVE opens are exclusive because their |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3025
diff
changeset
|
61 * weight (DS_REF_MAX) consumes the entire refcnt space. PRIMARY opens consume |
789 | 62 * just over half of the refcnt space, so there can't be more than one, but it |
63 * can peacefully coexist with any number of STANDARD opens. | |
64 */ | |
65 static uint64_t ds_refcnt_weight[DS_MODE_LEVELS] = { | |
3444
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3025
diff
changeset
|
66 0, /* DS_MODE_NONE - invalid */ |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3025
diff
changeset
|
67 1, /* DS_MODE_STANDARD - unlimited number */ |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3025
diff
changeset
|
68 (DS_REF_MAX >> 1) + 1, /* DS_MODE_PRIMARY - only one of these */ |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3025
diff
changeset
|
69 DS_REF_MAX /* DS_MODE_EXCLUSIVE - no other opens */ |
789 | 70 }; |
71 | |
72 | |
73 void | |
74 dsl_dataset_block_born(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx) | |
75 { | |
2082 | 76 int used = bp_get_dasize(tx->tx_pool->dp_spa, bp); |
789 | 77 int compressed = BP_GET_PSIZE(bp); |
78 int uncompressed = BP_GET_UCSIZE(bp); | |
79 | |
80 dprintf_bp(bp, "born, ds=%p\n", ds); | |
81 | |
82 ASSERT(dmu_tx_is_syncing(tx)); | |
83 /* It could have been compressed away to nothing */ | |
84 if (BP_IS_HOLE(bp)) | |
85 return; | |
86 ASSERT(BP_GET_TYPE(bp) != DMU_OT_NONE); | |
87 ASSERT3U(BP_GET_TYPE(bp), <, DMU_OT_NUMTYPES); | |
88 if (ds == NULL) { | |
89 /* | |
90 * Account for the meta-objset space in its placeholder | |
91 * dsl_dir. | |
92 */ | |
93 ASSERT3U(compressed, ==, uncompressed); /* it's all metadata */ | |
94 dsl_dir_diduse_space(tx->tx_pool->dp_mos_dir, | |
95 used, compressed, uncompressed, tx); | |
96 dsl_dir_dirty(tx->tx_pool->dp_mos_dir, tx); | |
97 return; | |
98 } | |
99 dmu_buf_will_dirty(ds->ds_dbuf, tx); | |
100 mutex_enter(&ds->ds_lock); | |
101 ds->ds_phys->ds_used_bytes += used; | |
102 ds->ds_phys->ds_compressed_bytes += compressed; | |
103 ds->ds_phys->ds_uncompressed_bytes += uncompressed; | |
104 ds->ds_phys->ds_unique_bytes += used; | |
105 mutex_exit(&ds->ds_lock); | |
106 dsl_dir_diduse_space(ds->ds_dir, | |
107 used, compressed, uncompressed, tx); | |
108 } | |
109 | |
110 void | |
3547
e396e0a440b1
6512391 DMU should leverage ZIO dependencies to achieve greater parallelism
maybee
parents:
3444
diff
changeset
|
111 dsl_dataset_block_kill(dsl_dataset_t *ds, blkptr_t *bp, zio_t *pio, |
e396e0a440b1
6512391 DMU should leverage ZIO dependencies to achieve greater parallelism
maybee
parents:
3444
diff
changeset
|
112 dmu_tx_t *tx) |
789 | 113 { |
2082 | 114 int used = bp_get_dasize(tx->tx_pool->dp_spa, bp); |
789 | 115 int compressed = BP_GET_PSIZE(bp); |
116 int uncompressed = BP_GET_UCSIZE(bp); | |
117 | |
118 ASSERT(dmu_tx_is_syncing(tx)); | |
3547
e396e0a440b1
6512391 DMU should leverage ZIO dependencies to achieve greater parallelism
maybee
parents:
3444
diff
changeset
|
119 /* No block pointer => nothing to free */ |
789 | 120 if (BP_IS_HOLE(bp)) |
121 return; | |
122 | |
123 ASSERT(used > 0); | |
124 if (ds == NULL) { | |
3547
e396e0a440b1
6512391 DMU should leverage ZIO dependencies to achieve greater parallelism
maybee
parents:
3444
diff
changeset
|
125 int err; |
789 | 126 /* |
127 * Account for the meta-objset space in its placeholder | |
128 * dataset. | |
129 */ | |
3547
e396e0a440b1
6512391 DMU should leverage ZIO dependencies to achieve greater parallelism
maybee
parents:
3444
diff
changeset
|
130 err = arc_free(pio, tx->tx_pool->dp_spa, |
e396e0a440b1
6512391 DMU should leverage ZIO dependencies to achieve greater parallelism
maybee
parents:
3444
diff
changeset
|
131 tx->tx_txg, bp, NULL, NULL, pio ? ARC_NOWAIT: ARC_WAIT); |
e396e0a440b1
6512391 DMU should leverage ZIO dependencies to achieve greater parallelism
maybee
parents:
3444
diff
changeset
|
132 ASSERT(err == 0); |
789 | 133 |
134 dsl_dir_diduse_space(tx->tx_pool->dp_mos_dir, | |
135 -used, -compressed, -uncompressed, tx); | |
136 dsl_dir_dirty(tx->tx_pool->dp_mos_dir, tx); | |
137 return; | |
138 } | |
139 ASSERT3P(tx->tx_pool, ==, ds->ds_dir->dd_pool); | |
140 | |
141 dmu_buf_will_dirty(ds->ds_dbuf, tx); | |
142 | |
143 if (bp->blk_birth > ds->ds_phys->ds_prev_snap_txg) { | |
3547
e396e0a440b1
6512391 DMU should leverage ZIO dependencies to achieve greater parallelism
maybee
parents:
3444
diff
changeset
|
144 int err; |
e396e0a440b1
6512391 DMU should leverage ZIO dependencies to achieve greater parallelism
maybee
parents:
3444
diff
changeset
|
145 |
789 | 146 dprintf_bp(bp, "freeing: %s", ""); |
3547
e396e0a440b1
6512391 DMU should leverage ZIO dependencies to achieve greater parallelism
maybee
parents:
3444
diff
changeset
|
147 err = arc_free(pio, tx->tx_pool->dp_spa, |
e396e0a440b1
6512391 DMU should leverage ZIO dependencies to achieve greater parallelism
maybee
parents:
3444
diff
changeset
|
148 tx->tx_txg, bp, NULL, NULL, pio ? ARC_NOWAIT: ARC_WAIT); |
e396e0a440b1
6512391 DMU should leverage ZIO dependencies to achieve greater parallelism
maybee
parents:
3444
diff
changeset
|
149 ASSERT(err == 0); |
789 | 150 |
151 mutex_enter(&ds->ds_lock); | |
152 /* XXX unique_bytes is not accurate for head datasets */ | |
153 /* ASSERT3U(ds->ds_phys->ds_unique_bytes, >=, used); */ | |
154 ds->ds_phys->ds_unique_bytes -= used; | |
155 mutex_exit(&ds->ds_lock); | |
156 dsl_dir_diduse_space(ds->ds_dir, | |
157 -used, -compressed, -uncompressed, tx); | |
158 } else { | |
159 dprintf_bp(bp, "putting on dead list: %s", ""); | |
1544 | 160 VERIFY(0 == bplist_enqueue(&ds->ds_deadlist, bp, tx)); |
789 | 161 /* if (bp->blk_birth > prev prev snap txg) prev unique += bs */ |
162 if (ds->ds_phys->ds_prev_snap_obj != 0) { | |
163 ASSERT3U(ds->ds_prev->ds_object, ==, | |
164 ds->ds_phys->ds_prev_snap_obj); | |
165 ASSERT(ds->ds_prev->ds_phys->ds_num_children > 0); | |
166 if (ds->ds_prev->ds_phys->ds_next_snap_obj == | |
2082 | 167 ds->ds_object && bp->blk_birth > |
789 | 168 ds->ds_prev->ds_phys->ds_prev_snap_txg) { |
169 dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); | |
170 mutex_enter(&ds->ds_prev->ds_lock); | |
171 ds->ds_prev->ds_phys->ds_unique_bytes += | |
172 used; | |
173 mutex_exit(&ds->ds_prev->ds_lock); | |
174 } | |
175 } | |
176 } | |
177 mutex_enter(&ds->ds_lock); | |
178 ASSERT3U(ds->ds_phys->ds_used_bytes, >=, used); | |
179 ds->ds_phys->ds_used_bytes -= used; | |
180 ASSERT3U(ds->ds_phys->ds_compressed_bytes, >=, compressed); | |
181 ds->ds_phys->ds_compressed_bytes -= compressed; | |
182 ASSERT3U(ds->ds_phys->ds_uncompressed_bytes, >=, uncompressed); | |
183 ds->ds_phys->ds_uncompressed_bytes -= uncompressed; | |
184 mutex_exit(&ds->ds_lock); | |
185 } | |
186 | |
1544 | 187 uint64_t |
188 dsl_dataset_prev_snap_txg(dsl_dataset_t *ds) | |
789 | 189 { |
2885 | 190 uint64_t trysnap = 0; |
191 | |
789 | 192 if (ds == NULL) |
1544 | 193 return (0); |
789 | 194 /* |
195 * The snapshot creation could fail, but that would cause an | |
196 * incorrect FALSE return, which would only result in an | |
197 * overestimation of the amount of space that an operation would | |
198 * consume, which is OK. | |
199 * | |
200 * There's also a small window where we could miss a pending | |
201 * snapshot, because we could set the sync task in the quiescing | |
202 * phase. So this should only be used as a guess. | |
203 */ | |
2885 | 204 if (ds->ds_trysnap_txg > |
205 spa_last_synced_txg(ds->ds_dir->dd_pool->dp_spa)) | |
206 trysnap = ds->ds_trysnap_txg; | |
207 return (MAX(ds->ds_phys->ds_prev_snap_txg, trysnap)); | |
1544 | 208 } |
209 | |
210 int | |
211 dsl_dataset_block_freeable(dsl_dataset_t *ds, uint64_t blk_birth) | |
212 { | |
213 return (blk_birth > dsl_dataset_prev_snap_txg(ds)); | |
789 | 214 } |
215 | |
216 /* ARGSUSED */ | |
217 static void | |
218 dsl_dataset_evict(dmu_buf_t *db, void *dsv) | |
219 { | |
220 dsl_dataset_t *ds = dsv; | |
221 | |
3444
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3025
diff
changeset
|
222 /* open_refcount == DS_REF_MAX when deleting */ |
789 | 223 ASSERT(ds->ds_open_refcount == 0 || |
3444
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3025
diff
changeset
|
224 ds->ds_open_refcount == DS_REF_MAX); |
789 | 225 |
226 dprintf_ds(ds, "evicting %s\n", ""); | |
227 | |
4787 | 228 unique_remove(ds->ds_fsid_guid); |
789 | 229 |
230 if (ds->ds_user_ptr != NULL) | |
231 ds->ds_user_evict_func(ds, ds->ds_user_ptr); | |
232 | |
233 if (ds->ds_prev) { | |
234 dsl_dataset_close(ds->ds_prev, DS_MODE_NONE, ds); | |
235 ds->ds_prev = NULL; | |
236 } | |
237 | |
238 bplist_close(&ds->ds_deadlist); | |
239 dsl_dir_close(ds->ds_dir, ds); | |
240 | |
4787 | 241 ASSERT(!list_link_active(&ds->ds_synced_link)); |
789 | 242 |
2856 | 243 mutex_destroy(&ds->ds_lock); |
4787 | 244 mutex_destroy(&ds->ds_opening_lock); |
2856 | 245 mutex_destroy(&ds->ds_deadlist.bpl_lock); |
246 | |
789 | 247 kmem_free(ds, sizeof (dsl_dataset_t)); |
248 } | |
249 | |
1544 | 250 static int |
789 | 251 dsl_dataset_get_snapname(dsl_dataset_t *ds) |
252 { | |
253 dsl_dataset_phys_t *headphys; | |
254 int err; | |
255 dmu_buf_t *headdbuf; | |
256 dsl_pool_t *dp = ds->ds_dir->dd_pool; | |
257 objset_t *mos = dp->dp_meta_objset; | |
258 | |
259 if (ds->ds_snapname[0]) | |
1544 | 260 return (0); |
789 | 261 if (ds->ds_phys->ds_next_snap_obj == 0) |
1544 | 262 return (0); |
789 | 263 |
1544 | 264 err = dmu_bonus_hold(mos, ds->ds_dir->dd_phys->dd_head_dataset_obj, |
265 FTAG, &headdbuf); | |
266 if (err) | |
267 return (err); | |
789 | 268 headphys = headdbuf->db_data; |
269 err = zap_value_search(dp->dp_meta_objset, | |
4577 | 270 headphys->ds_snapnames_zapobj, ds->ds_object, 0, ds->ds_snapname); |
1544 | 271 dmu_buf_rele(headdbuf, FTAG); |
272 return (err); | |
789 | 273 } |
274 | |
1544 | 275 int |
789 | 276 dsl_dataset_open_obj(dsl_pool_t *dp, uint64_t dsobj, const char *snapname, |
1544 | 277 int mode, void *tag, dsl_dataset_t **dsp) |
789 | 278 { |
279 uint64_t weight = ds_refcnt_weight[DS_MODE_LEVEL(mode)]; | |
280 objset_t *mos = dp->dp_meta_objset; | |
281 dmu_buf_t *dbuf; | |
282 dsl_dataset_t *ds; | |
1544 | 283 int err; |
789 | 284 |
285 ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock) || | |
286 dsl_pool_sync_context(dp)); | |
287 | |
1544 | 288 err = dmu_bonus_hold(mos, dsobj, tag, &dbuf); |
289 if (err) | |
290 return (err); | |
789 | 291 ds = dmu_buf_get_user(dbuf); |
292 if (ds == NULL) { | |
293 dsl_dataset_t *winner; | |
294 | |
295 ds = kmem_zalloc(sizeof (dsl_dataset_t), KM_SLEEP); | |
296 ds->ds_dbuf = dbuf; | |
297 ds->ds_object = dsobj; | |
298 ds->ds_phys = dbuf->db_data; | |
299 | |
2856 | 300 mutex_init(&ds->ds_lock, NULL, MUTEX_DEFAULT, NULL); |
4787 | 301 mutex_init(&ds->ds_opening_lock, NULL, MUTEX_DEFAULT, NULL); |
2856 | 302 mutex_init(&ds->ds_deadlist.bpl_lock, NULL, MUTEX_DEFAULT, |
303 NULL); | |
304 | |
1544 | 305 err = bplist_open(&ds->ds_deadlist, |
789 | 306 mos, ds->ds_phys->ds_deadlist_obj); |
1544 | 307 if (err == 0) { |
308 err = dsl_dir_open_obj(dp, | |
309 ds->ds_phys->ds_dir_obj, NULL, ds, &ds->ds_dir); | |
310 } | |
311 if (err) { | |
312 /* | |
313 * we don't really need to close the blist if we | |
314 * just opened it. | |
315 */ | |
2856 | 316 mutex_destroy(&ds->ds_lock); |
4787 | 317 mutex_destroy(&ds->ds_opening_lock); |
2856 | 318 mutex_destroy(&ds->ds_deadlist.bpl_lock); |
1544 | 319 kmem_free(ds, sizeof (dsl_dataset_t)); |
320 dmu_buf_rele(dbuf, tag); | |
321 return (err); | |
322 } | |
789 | 323 |
324 if (ds->ds_dir->dd_phys->dd_head_dataset_obj == dsobj) { | |
325 ds->ds_snapname[0] = '\0'; | |
326 if (ds->ds_phys->ds_prev_snap_obj) { | |
1544 | 327 err = dsl_dataset_open_obj(dp, |
789 | 328 ds->ds_phys->ds_prev_snap_obj, NULL, |
1544 | 329 DS_MODE_NONE, ds, &ds->ds_prev); |
789 | 330 } |
331 } else { | |
332 if (snapname) { | |
333 #ifdef ZFS_DEBUG | |
334 dsl_dataset_phys_t *headphys; | |
1544 | 335 dmu_buf_t *headdbuf; |
336 err = dmu_bonus_hold(mos, | |
337 ds->ds_dir->dd_phys->dd_head_dataset_obj, | |
338 FTAG, &headdbuf); | |
339 if (err == 0) { | |
340 headphys = headdbuf->db_data; | |
341 uint64_t foundobj; | |
342 err = zap_lookup(dp->dp_meta_objset, | |
343 headphys->ds_snapnames_zapobj, | |
344 snapname, sizeof (foundobj), 1, | |
345 &foundobj); | |
346 ASSERT3U(foundobj, ==, dsobj); | |
347 dmu_buf_rele(headdbuf, FTAG); | |
348 } | |
789 | 349 #endif |
350 (void) strcat(ds->ds_snapname, snapname); | |
351 } else if (zfs_flags & ZFS_DEBUG_SNAPNAMES) { | |
1544 | 352 err = dsl_dataset_get_snapname(ds); |
789 | 353 } |
354 } | |
355 | |
1544 | 356 if (err == 0) { |
357 winner = dmu_buf_set_user_ie(dbuf, ds, &ds->ds_phys, | |
358 dsl_dataset_evict); | |
359 } | |
360 if (err || winner) { | |
789 | 361 bplist_close(&ds->ds_deadlist); |
362 if (ds->ds_prev) { | |
363 dsl_dataset_close(ds->ds_prev, | |
364 DS_MODE_NONE, ds); | |
365 } | |
366 dsl_dir_close(ds->ds_dir, ds); | |
2856 | 367 mutex_destroy(&ds->ds_lock); |
4787 | 368 mutex_destroy(&ds->ds_opening_lock); |
2856 | 369 mutex_destroy(&ds->ds_deadlist.bpl_lock); |
789 | 370 kmem_free(ds, sizeof (dsl_dataset_t)); |
1544 | 371 if (err) { |
372 dmu_buf_rele(dbuf, tag); | |
373 return (err); | |
374 } | |
789 | 375 ds = winner; |
376 } else { | |
4787 | 377 ds->ds_fsid_guid = |
789 | 378 unique_insert(ds->ds_phys->ds_fsid_guid); |
379 } | |
380 } | |
381 ASSERT3P(ds->ds_dbuf, ==, dbuf); | |
382 ASSERT3P(ds->ds_phys, ==, dbuf->db_data); | |
383 | |
384 mutex_enter(&ds->ds_lock); | |
385 if ((DS_MODE_LEVEL(mode) == DS_MODE_PRIMARY && | |
2082 | 386 (ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT) && |
387 !DS_MODE_IS_INCONSISTENT(mode)) || | |
3444
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3025
diff
changeset
|
388 (ds->ds_open_refcount + weight > DS_REF_MAX)) { |
789 | 389 mutex_exit(&ds->ds_lock); |
390 dsl_dataset_close(ds, DS_MODE_NONE, tag); | |
1544 | 391 return (EBUSY); |
789 | 392 } |
393 ds->ds_open_refcount += weight; | |
394 mutex_exit(&ds->ds_lock); | |
395 | |
1544 | 396 *dsp = ds; |
397 return (0); | |
789 | 398 } |
399 | |
400 int | |
401 dsl_dataset_open_spa(spa_t *spa, const char *name, int mode, | |
402 void *tag, dsl_dataset_t **dsp) | |
403 { | |
404 dsl_dir_t *dd; | |
405 dsl_pool_t *dp; | |
406 const char *tail; | |
407 uint64_t obj; | |
408 dsl_dataset_t *ds = NULL; | |
409 int err = 0; | |
410 | |
1544 | 411 err = dsl_dir_open_spa(spa, name, FTAG, &dd, &tail); |
412 if (err) | |
413 return (err); | |
789 | 414 |
415 dp = dd->dd_pool; | |
416 obj = dd->dd_phys->dd_head_dataset_obj; | |
417 rw_enter(&dp->dp_config_rwlock, RW_READER); | |
418 if (obj == 0) { | |
419 /* A dataset with no associated objset */ | |
420 err = ENOENT; | |
421 goto out; | |
422 } | |
423 | |
424 if (tail != NULL) { | |
425 objset_t *mos = dp->dp_meta_objset; | |
426 | |
1544 | 427 err = dsl_dataset_open_obj(dp, obj, NULL, |
428 DS_MODE_NONE, tag, &ds); | |
429 if (err) | |
430 goto out; | |
789 | 431 obj = ds->ds_phys->ds_snapnames_zapobj; |
432 dsl_dataset_close(ds, DS_MODE_NONE, tag); | |
433 ds = NULL; | |
434 | |
435 if (tail[0] != '@') { | |
436 err = ENOENT; | |
437 goto out; | |
438 } | |
439 tail++; | |
440 | |
441 /* Look for a snapshot */ | |
442 if (!DS_MODE_IS_READONLY(mode)) { | |
443 err = EROFS; | |
444 goto out; | |
445 } | |
446 dprintf("looking for snapshot '%s'\n", tail); | |
447 err = zap_lookup(mos, obj, tail, 8, 1, &obj); | |
448 if (err) | |
449 goto out; | |
450 } | |
1544 | 451 err = dsl_dataset_open_obj(dp, obj, tail, mode, tag, &ds); |
789 | 452 |
453 out: | |
454 rw_exit(&dp->dp_config_rwlock); | |
455 dsl_dir_close(dd, FTAG); | |
456 | |
457 ASSERT3U((err == 0), ==, (ds != NULL)); | |
458 /* ASSERT(ds == NULL || strcmp(name, ds->ds_name) == 0); */ | |
459 | |
460 *dsp = ds; | |
461 return (err); | |
462 } | |
463 | |
464 int | |
465 dsl_dataset_open(const char *name, int mode, void *tag, dsl_dataset_t **dsp) | |
466 { | |
467 return (dsl_dataset_open_spa(NULL, name, mode, tag, dsp)); | |
468 } | |
469 | |
470 void | |
471 dsl_dataset_name(dsl_dataset_t *ds, char *name) | |
472 { | |
473 if (ds == NULL) { | |
474 (void) strcpy(name, "mos"); | |
475 } else { | |
476 dsl_dir_name(ds->ds_dir, name); | |
1544 | 477 VERIFY(0 == dsl_dataset_get_snapname(ds)); |
789 | 478 if (ds->ds_snapname[0]) { |
479 (void) strcat(name, "@"); | |
480 if (!MUTEX_HELD(&ds->ds_lock)) { | |
481 /* | |
482 * We use a "recursive" mutex so that we | |
483 * can call dprintf_ds() with ds_lock held. | |
484 */ | |
485 mutex_enter(&ds->ds_lock); | |
486 (void) strcat(name, ds->ds_snapname); | |
487 mutex_exit(&ds->ds_lock); | |
488 } else { | |
489 (void) strcat(name, ds->ds_snapname); | |
490 } | |
491 } | |
492 } | |
493 } | |
494 | |
3978
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
495 static int |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
496 dsl_dataset_namelen(dsl_dataset_t *ds) |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
497 { |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
498 int result; |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
499 |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
500 if (ds == NULL) { |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
501 result = 3; /* "mos" */ |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
502 } else { |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
503 result = dsl_dir_namelen(ds->ds_dir); |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
504 VERIFY(0 == dsl_dataset_get_snapname(ds)); |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
505 if (ds->ds_snapname[0]) { |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
506 ++result; /* adding one for the @-sign */ |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
507 if (!MUTEX_HELD(&ds->ds_lock)) { |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
508 /* see dsl_datset_name */ |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
509 mutex_enter(&ds->ds_lock); |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
510 result += strlen(ds->ds_snapname); |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
511 mutex_exit(&ds->ds_lock); |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
512 } else { |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
513 result += strlen(ds->ds_snapname); |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
514 } |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
515 } |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
516 } |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
517 |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
518 return (result); |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
519 } |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
520 |
789 | 521 void |
522 dsl_dataset_close(dsl_dataset_t *ds, int mode, void *tag) | |
523 { | |
524 uint64_t weight = ds_refcnt_weight[DS_MODE_LEVEL(mode)]; | |
525 mutex_enter(&ds->ds_lock); | |
526 ASSERT3U(ds->ds_open_refcount, >=, weight); | |
527 ds->ds_open_refcount -= weight; | |
528 dprintf_ds(ds, "closing mode %u refcount now 0x%llx\n", | |
529 mode, ds->ds_open_refcount); | |
530 mutex_exit(&ds->ds_lock); | |
531 | |
1544 | 532 dmu_buf_rele(ds->ds_dbuf, tag); |
789 | 533 } |
534 | |
535 void | |
536 dsl_dataset_create_root(dsl_pool_t *dp, uint64_t *ddobjp, dmu_tx_t *tx) | |
537 { | |
538 objset_t *mos = dp->dp_meta_objset; | |
539 dmu_buf_t *dbuf; | |
540 dsl_dataset_phys_t *dsphys; | |
541 dsl_dataset_t *ds; | |
542 uint64_t dsobj; | |
543 dsl_dir_t *dd; | |
544 | |
545 dsl_dir_create_root(mos, ddobjp, tx); | |
1544 | 546 VERIFY(0 == dsl_dir_open_obj(dp, *ddobjp, NULL, FTAG, &dd)); |
789 | 547 |
928
36d72fe4da29
6349314 dmu_object_type names incorrect for DSL Directories and DSL Datasets
tabriz
parents:
885
diff
changeset
|
548 dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, |
36d72fe4da29
6349314 dmu_object_type names incorrect for DSL Directories and DSL Datasets
tabriz
parents:
885
diff
changeset
|
549 DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); |
1544 | 550 VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); |
789 | 551 dmu_buf_will_dirty(dbuf, tx); |
552 dsphys = dbuf->db_data; | |
553 dsphys->ds_dir_obj = dd->dd_object; | |
554 dsphys->ds_fsid_guid = unique_create(); | |
555 (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, | |
556 sizeof (dsphys->ds_guid)); | |
557 dsphys->ds_snapnames_zapobj = | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
789
diff
changeset
|
558 zap_create(mos, DMU_OT_DSL_DS_SNAP_MAP, DMU_OT_NONE, 0, tx); |
789 | 559 dsphys->ds_creation_time = gethrestime_sec(); |
560 dsphys->ds_creation_txg = tx->tx_txg; | |
561 dsphys->ds_deadlist_obj = | |
562 bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); | |
1544 | 563 dmu_buf_rele(dbuf, FTAG); |
789 | 564 |
565 dmu_buf_will_dirty(dd->dd_dbuf, tx); | |
566 dd->dd_phys->dd_head_dataset_obj = dsobj; | |
567 dsl_dir_close(dd, FTAG); | |
568 | |
1544 | 569 VERIFY(0 == |
570 dsl_dataset_open_obj(dp, dsobj, NULL, DS_MODE_NONE, FTAG, &ds)); | |
3547
e396e0a440b1
6512391 DMU should leverage ZIO dependencies to achieve greater parallelism
maybee
parents:
3444
diff
changeset
|
571 (void) dmu_objset_create_impl(dp->dp_spa, ds, |
e396e0a440b1
6512391 DMU should leverage ZIO dependencies to achieve greater parallelism
maybee
parents:
3444
diff
changeset
|
572 &ds->ds_phys->ds_bp, DMU_OST_ZFS, tx); |
789 | 573 dsl_dataset_close(ds, DS_MODE_NONE, FTAG); |
574 } | |
575 | |
2199 | 576 uint64_t |
577 dsl_dataset_create_sync(dsl_dir_t *pdd, | |
789 | 578 const char *lastname, dsl_dataset_t *clone_parent, dmu_tx_t *tx) |
579 { | |
2199 | 580 dsl_pool_t *dp = pdd->dd_pool; |
789 | 581 dmu_buf_t *dbuf; |
582 dsl_dataset_phys_t *dsphys; | |
2199 | 583 uint64_t dsobj, ddobj; |
789 | 584 objset_t *mos = dp->dp_meta_objset; |
585 dsl_dir_t *dd; | |
586 | |
2199 | 587 ASSERT(clone_parent == NULL || clone_parent->ds_dir->dd_pool == dp); |
588 ASSERT(clone_parent == NULL || | |
589 clone_parent->ds_phys->ds_num_children > 0); | |
789 | 590 ASSERT(lastname[0] != '@'); |
591 ASSERT(dmu_tx_is_syncing(tx)); | |
592 | |
2199 | 593 ddobj = dsl_dir_create_sync(pdd, lastname, tx); |
594 VERIFY(0 == dsl_dir_open_obj(dp, ddobj, lastname, FTAG, &dd)); | |
789 | 595 |
928
36d72fe4da29
6349314 dmu_object_type names incorrect for DSL Directories and DSL Datasets
tabriz
parents:
885
diff
changeset
|
596 dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, |
36d72fe4da29
6349314 dmu_object_type names incorrect for DSL Directories and DSL Datasets
tabriz
parents:
885
diff
changeset
|
597 DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); |
1544 | 598 VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); |
789 | 599 dmu_buf_will_dirty(dbuf, tx); |
600 dsphys = dbuf->db_data; | |
601 dsphys->ds_dir_obj = dd->dd_object; | |
602 dsphys->ds_fsid_guid = unique_create(); | |
603 (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, | |
604 sizeof (dsphys->ds_guid)); | |
605 dsphys->ds_snapnames_zapobj = | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
789
diff
changeset
|
606 zap_create(mos, DMU_OT_DSL_DS_SNAP_MAP, DMU_OT_NONE, 0, tx); |
789 | 607 dsphys->ds_creation_time = gethrestime_sec(); |
608 dsphys->ds_creation_txg = tx->tx_txg; | |
609 dsphys->ds_deadlist_obj = | |
610 bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); | |
611 if (clone_parent) { | |
612 dsphys->ds_prev_snap_obj = clone_parent->ds_object; | |
613 dsphys->ds_prev_snap_txg = | |
614 clone_parent->ds_phys->ds_creation_txg; | |
615 dsphys->ds_used_bytes = | |
616 clone_parent->ds_phys->ds_used_bytes; | |
617 dsphys->ds_compressed_bytes = | |
618 clone_parent->ds_phys->ds_compressed_bytes; | |
619 dsphys->ds_uncompressed_bytes = | |
620 clone_parent->ds_phys->ds_uncompressed_bytes; | |
621 dsphys->ds_bp = clone_parent->ds_phys->ds_bp; | |
622 | |
623 dmu_buf_will_dirty(clone_parent->ds_dbuf, tx); | |
624 clone_parent->ds_phys->ds_num_children++; | |
625 | |
626 dmu_buf_will_dirty(dd->dd_dbuf, tx); | |
627 dd->dd_phys->dd_clone_parent_obj = clone_parent->ds_object; | |
628 } | |
1544 | 629 dmu_buf_rele(dbuf, FTAG); |
789 | 630 |
631 dmu_buf_will_dirty(dd->dd_dbuf, tx); | |
632 dd->dd_phys->dd_head_dataset_obj = dsobj; | |
633 dsl_dir_close(dd, FTAG); | |
634 | |
2199 | 635 return (dsobj); |
636 } | |
637 | |
638 struct destroyarg { | |
639 dsl_sync_task_group_t *dstg; | |
640 char *snapname; | |
641 char *failed; | |
642 }; | |
643 | |
644 static int | |
645 dsl_snapshot_destroy_one(char *name, void *arg) | |
646 { | |
647 struct destroyarg *da = arg; | |
648 dsl_dataset_t *ds; | |
649 char *cp; | |
650 int err; | |
651 | |
652 (void) strcat(name, "@"); | |
653 (void) strcat(name, da->snapname); | |
654 err = dsl_dataset_open(name, | |
655 DS_MODE_EXCLUSIVE | DS_MODE_READONLY | DS_MODE_INCONSISTENT, | |
4007 | 656 da->dstg, &ds); |
2199 | 657 cp = strchr(name, '@'); |
658 *cp = '\0'; | |
659 if (err == ENOENT) | |
660 return (0); | |
661 if (err) { | |
662 (void) strcpy(da->failed, name); | |
663 return (err); | |
664 } | |
665 | |
666 dsl_sync_task_create(da->dstg, dsl_dataset_destroy_check, | |
4007 | 667 dsl_dataset_destroy_sync, ds, da->dstg, 0); |
789 | 668 return (0); |
669 } | |
670 | |
2199 | 671 /* |
672 * Destroy 'snapname' in all descendants of 'fsname'. | |
673 */ | |
674 #pragma weak dmu_snapshots_destroy = dsl_snapshots_destroy | |
675 int | |
676 dsl_snapshots_destroy(char *fsname, char *snapname) | |
677 { | |
678 int err; | |
679 struct destroyarg da; | |
680 dsl_sync_task_t *dst; | |
681 spa_t *spa; | |
682 | |
4603
c7840c367d00
6494569 zfs recv -d pool/<doesn't exist> core dumps for top-level filesystem backups
ahrens
parents:
4577
diff
changeset
|
683 err = spa_open(fsname, &spa, FTAG); |
2199 | 684 if (err) |
685 return (err); | |
686 da.dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); | |
687 da.snapname = snapname; | |
688 da.failed = fsname; | |
689 | |
690 err = dmu_objset_find(fsname, | |
2417 | 691 dsl_snapshot_destroy_one, &da, DS_FIND_CHILDREN); |
2199 | 692 |
693 if (err == 0) | |
694 err = dsl_sync_task_group_wait(da.dstg); | |
695 | |
696 for (dst = list_head(&da.dstg->dstg_tasks); dst; | |
697 dst = list_next(&da.dstg->dstg_tasks, dst)) { | |
698 dsl_dataset_t *ds = dst->dst_arg1; | |
699 if (dst->dst_err) { | |
700 dsl_dataset_name(ds, fsname); | |
4603
c7840c367d00
6494569 zfs recv -d pool/<doesn't exist> core dumps for top-level filesystem backups
ahrens
parents:
4577
diff
changeset
|
701 *strchr(fsname, '@') = '\0'; |
2199 | 702 } |
703 /* | |
704 * If it was successful, destroy_sync would have | |
705 * closed the ds | |
706 */ | |
707 if (err) | |
4007 | 708 dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, da.dstg); |
2199 | 709 } |
710 | |
711 dsl_sync_task_group_destroy(da.dstg); | |
712 spa_close(spa, FTAG); | |
713 return (err); | |
714 } | |
715 | |
789 | 716 int |
717 dsl_dataset_destroy(const char *name) | |
718 { | |
719 int err; | |
2199 | 720 dsl_sync_task_group_t *dstg; |
721 objset_t *os; | |
722 dsl_dataset_t *ds; | |
789 | 723 dsl_dir_t *dd; |
2199 | 724 uint64_t obj; |
725 | |
726 if (strchr(name, '@')) { | |
727 /* Destroying a snapshot is simpler */ | |
728 err = dsl_dataset_open(name, | |
729 DS_MODE_EXCLUSIVE | DS_MODE_READONLY | DS_MODE_INCONSISTENT, | |
730 FTAG, &ds); | |
731 if (err) | |
732 return (err); | |
733 err = dsl_sync_task_do(ds->ds_dir->dd_pool, | |
734 dsl_dataset_destroy_check, dsl_dataset_destroy_sync, | |
735 ds, FTAG, 0); | |
736 if (err) | |
737 dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); | |
738 return (err); | |
739 } | |
740 | |
741 err = dmu_objset_open(name, DMU_OST_ANY, | |
742 DS_MODE_EXCLUSIVE | DS_MODE_INCONSISTENT, &os); | |
743 if (err) | |
744 return (err); | |
745 ds = os->os->os_dsl_dataset; | |
746 dd = ds->ds_dir; | |
789 | 747 |
2199 | 748 /* |
749 * Check for errors and mark this ds as inconsistent, in | |
750 * case we crash while freeing the objects. | |
751 */ | |
752 err = dsl_sync_task_do(dd->dd_pool, dsl_dataset_destroy_begin_check, | |
753 dsl_dataset_destroy_begin_sync, ds, NULL, 0); | |
754 if (err) { | |
755 dmu_objset_close(os); | |
756 return (err); | |
757 } | |
758 | |
759 /* | |
760 * remove the objects in open context, so that we won't | |
761 * have too much to do in syncing context. | |
762 */ | |
3025
4e5ee8301d84
6424466 "panic: data after EOF" when unmounting abused pool
ahrens
parents:
2885
diff
changeset
|
763 for (obj = 0; err == 0; err = dmu_object_next(os, &obj, FALSE, |
4e5ee8301d84
6424466 "panic: data after EOF" when unmounting abused pool
ahrens
parents:
2885
diff
changeset
|
764 ds->ds_phys->ds_prev_snap_txg)) { |
2199 | 765 dmu_tx_t *tx = dmu_tx_create(os); |
766 dmu_tx_hold_free(tx, obj, 0, DMU_OBJECT_END); | |
767 dmu_tx_hold_bonus(tx, obj); | |
768 err = dmu_tx_assign(tx, TXG_WAIT); | |
769 if (err) { | |
770 /* | |
771 * Perhaps there is not enough disk | |
772 * space. Just deal with it from | |
773 * dsl_dataset_destroy_sync(). | |
774 */ | |
775 dmu_tx_abort(tx); | |
776 continue; | |
777 } | |
778 VERIFY(0 == dmu_object_free(os, obj, tx)); | |
779 dmu_tx_commit(tx); | |
780 } | |
781 /* Make sure it's not dirty before we finish destroying it. */ | |
782 txg_wait_synced(dd->dd_pool, 0); | |
783 | |
784 dmu_objset_close(os); | |
785 if (err != ESRCH) | |
786 return (err); | |
787 | |
788 err = dsl_dataset_open(name, | |
789 DS_MODE_EXCLUSIVE | DS_MODE_READONLY | DS_MODE_INCONSISTENT, | |
790 FTAG, &ds); | |
1544 | 791 if (err) |
792 return (err); | |
789 | 793 |
2199 | 794 err = dsl_dir_open(name, FTAG, &dd, NULL); |
795 if (err) { | |
796 dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); | |
797 return (err); | |
789 | 798 } |
799 | |
2199 | 800 /* |
801 * Blow away the dsl_dir + head dataset. | |
802 */ | |
803 dstg = dsl_sync_task_group_create(ds->ds_dir->dd_pool); | |
804 dsl_sync_task_create(dstg, dsl_dataset_destroy_check, | |
805 dsl_dataset_destroy_sync, ds, FTAG, 0); | |
806 dsl_sync_task_create(dstg, dsl_dir_destroy_check, | |
807 dsl_dir_destroy_sync, dd, FTAG, 0); | |
808 err = dsl_sync_task_group_wait(dstg); | |
809 dsl_sync_task_group_destroy(dstg); | |
810 /* if it is successful, *destroy_sync will close the ds+dd */ | |
811 if (err) { | |
812 dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); | |
813 dsl_dir_close(dd, FTAG); | |
814 } | |
789 | 815 return (err); |
816 } | |
817 | |
818 int | |
2199 | 819 dsl_dataset_rollback(dsl_dataset_t *ds) |
789 | 820 { |
3444
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3025
diff
changeset
|
821 ASSERT3U(ds->ds_open_refcount, ==, DS_REF_MAX); |
2199 | 822 return (dsl_sync_task_do(ds->ds_dir->dd_pool, |
823 dsl_dataset_rollback_check, dsl_dataset_rollback_sync, | |
824 ds, NULL, 0)); | |
789 | 825 } |
826 | |
827 void * | |
828 dsl_dataset_set_user_ptr(dsl_dataset_t *ds, | |
829 void *p, dsl_dataset_evict_func_t func) | |
830 { | |
831 void *old; | |
832 | |
833 mutex_enter(&ds->ds_lock); | |
834 old = ds->ds_user_ptr; | |
835 if (old == NULL) { | |
836 ds->ds_user_ptr = p; | |
837 ds->ds_user_evict_func = func; | |
838 } | |
839 mutex_exit(&ds->ds_lock); | |
840 return (old); | |
841 } | |
842 | |
843 void * | |
844 dsl_dataset_get_user_ptr(dsl_dataset_t *ds) | |
845 { | |
846 return (ds->ds_user_ptr); | |
847 } | |
848 | |
849 | |
3547
e396e0a440b1
6512391 DMU should leverage ZIO dependencies to achieve greater parallelism
maybee
parents:
3444
diff
changeset
|
850 blkptr_t * |
e396e0a440b1
6512391 DMU should leverage ZIO dependencies to achieve greater parallelism
maybee
parents:
3444
diff
changeset
|
851 dsl_dataset_get_blkptr(dsl_dataset_t *ds) |
789 | 852 { |
3547
e396e0a440b1
6512391 DMU should leverage ZIO dependencies to achieve greater parallelism
maybee
parents:
3444
diff
changeset
|
853 return (&ds->ds_phys->ds_bp); |
789 | 854 } |
855 | |
856 void | |
857 dsl_dataset_set_blkptr(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx) | |
858 { | |
859 ASSERT(dmu_tx_is_syncing(tx)); | |
860 /* If it's the meta-objset, set dp_meta_rootbp */ | |
861 if (ds == NULL) { | |
862 tx->tx_pool->dp_meta_rootbp = *bp; | |
863 } else { | |
864 dmu_buf_will_dirty(ds->ds_dbuf, tx); | |
865 ds->ds_phys->ds_bp = *bp; | |
866 } | |
867 } | |
868 | |
869 spa_t * | |
870 dsl_dataset_get_spa(dsl_dataset_t *ds) | |
871 { | |
872 return (ds->ds_dir->dd_pool->dp_spa); | |
873 } | |
874 | |
875 void | |
876 dsl_dataset_dirty(dsl_dataset_t *ds, dmu_tx_t *tx) | |
877 { | |
878 dsl_pool_t *dp; | |
879 | |
880 if (ds == NULL) /* this is the meta-objset */ | |
881 return; | |
882 | |
883 ASSERT(ds->ds_user_ptr != NULL); | |
2885 | 884 |
885 if (ds->ds_phys->ds_next_snap_obj != 0) | |
886 panic("dirtying snapshot!"); | |
789 | 887 |
888 dp = ds->ds_dir->dd_pool; | |
889 | |
890 if (txg_list_add(&dp->dp_dirty_datasets, ds, tx->tx_txg) == 0) { | |
891 /* up the hold count until we can be written out */ | |
892 dmu_buf_add_ref(ds->ds_dbuf, ds); | |
893 } | |
894 } | |
895 | |
896 struct killarg { | |
897 uint64_t *usedp; | |
898 uint64_t *compressedp; | |
899 uint64_t *uncompressedp; | |
900 zio_t *zio; | |
901 dmu_tx_t *tx; | |
902 }; | |
903 | |
904 static int | |
905 kill_blkptr(traverse_blk_cache_t *bc, spa_t *spa, void *arg) | |
906 { | |
907 struct killarg *ka = arg; | |
908 blkptr_t *bp = &bc->bc_blkptr; | |
909 | |
910 ASSERT3U(bc->bc_errno, ==, 0); | |
911 | |
912 /* | |
913 * Since this callback is not called concurrently, no lock is | |
914 * needed on the accounting values. | |
915 */ | |
2082 | 916 *ka->usedp += bp_get_dasize(spa, bp); |
789 | 917 *ka->compressedp += BP_GET_PSIZE(bp); |
918 *ka->uncompressedp += BP_GET_UCSIZE(bp); | |
919 /* XXX check for EIO? */ | |
920 (void) arc_free(ka->zio, spa, ka->tx->tx_txg, bp, NULL, NULL, | |
921 ARC_NOWAIT); | |
922 return (0); | |
923 } | |
924 | |
925 /* ARGSUSED */ | |
2199 | 926 static int |
927 dsl_dataset_rollback_check(void *arg1, void *arg2, dmu_tx_t *tx) | |
789 | 928 { |
2199 | 929 dsl_dataset_t *ds = arg1; |
789 | 930 |
2199 | 931 /* |
932 * There must be a previous snapshot. I suppose we could roll | |
933 * it back to being empty (and re-initialize the upper (ZPL) | |
934 * layer). But for now there's no way to do this via the user | |
935 * interface. | |
936 */ | |
937 if (ds->ds_phys->ds_prev_snap_txg == 0) | |
789 | 938 return (EINVAL); |
939 | |
2199 | 940 /* |
941 * This must not be a snapshot. | |
942 */ | |
943 if (ds->ds_phys->ds_next_snap_obj != 0) | |
944 return (EINVAL); | |
789 | 945 |
946 /* | |
947 * If we made changes this txg, traverse_dsl_dataset won't find | |
948 * them. Try again. | |
949 */ | |
2199 | 950 if (ds->ds_phys->ds_bp.blk_birth >= tx->tx_txg) |
789 | 951 return (EAGAIN); |
2199 | 952 |
953 return (0); | |
954 } | |
789 | 955 |
2199 | 956 /* ARGSUSED */ |
957 static void | |
4543 | 958 dsl_dataset_rollback_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) |
2199 | 959 { |
960 dsl_dataset_t *ds = arg1; | |
961 objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; | |
789 | 962 |
963 dmu_buf_will_dirty(ds->ds_dbuf, tx); | |
964 | |
4967
8d0de61ff354
6597381 BAD TRAP: type=e (#pf Page fault) rp=ffffff00043a48f0 addr=28 occurred in module "<unknown>" due to
perrin
parents:
4935
diff
changeset
|
965 /* |
8d0de61ff354
6597381 BAD TRAP: type=e (#pf Page fault) rp=ffffff00043a48f0 addr=28 occurred in module "<unknown>" due to
perrin
parents:
4935
diff
changeset
|
966 * Before the roll back destroy the zil. |
8d0de61ff354
6597381 BAD TRAP: type=e (#pf Page fault) rp=ffffff00043a48f0 addr=28 occurred in module "<unknown>" due to
perrin
parents:
4935
diff
changeset
|
967 * Note, ds_user_ptr can be null if we are doing a "zfs receive -F" |
8d0de61ff354
6597381 BAD TRAP: type=e (#pf Page fault) rp=ffffff00043a48f0 addr=28 occurred in module "<unknown>" due to
perrin
parents:
4935
diff
changeset
|
968 */ |
8d0de61ff354
6597381 BAD TRAP: type=e (#pf Page fault) rp=ffffff00043a48f0 addr=28 occurred in module "<unknown>" due to
perrin
parents:
4935
diff
changeset
|
969 if (ds->ds_user_ptr != NULL) { |
8d0de61ff354
6597381 BAD TRAP: type=e (#pf Page fault) rp=ffffff00043a48f0 addr=28 occurred in module "<unknown>" due to
perrin
parents:
4935
diff
changeset
|
970 zil_rollback_destroy( |
8d0de61ff354
6597381 BAD TRAP: type=e (#pf Page fault) rp=ffffff00043a48f0 addr=28 occurred in module "<unknown>" due to
perrin
parents:
4935
diff
changeset
|
971 ((objset_impl_t *)ds->ds_user_ptr)->os_zil, tx); |
8d0de61ff354
6597381 BAD TRAP: type=e (#pf Page fault) rp=ffffff00043a48f0 addr=28 occurred in module "<unknown>" due to
perrin
parents:
4935
diff
changeset
|
972 } |
4935
c80bf0e6f4aa
6534949 Stale need for range locking comment in zvol.c
perrin
parents:
4787
diff
changeset
|
973 |
789 | 974 /* Zero out the deadlist. */ |
975 bplist_close(&ds->ds_deadlist); | |
976 bplist_destroy(mos, ds->ds_phys->ds_deadlist_obj, tx); | |
977 ds->ds_phys->ds_deadlist_obj = | |
978 bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); | |
1544 | 979 VERIFY(0 == bplist_open(&ds->ds_deadlist, mos, |
980 ds->ds_phys->ds_deadlist_obj)); | |
789 | 981 |
982 { | |
983 /* Free blkptrs that we gave birth to */ | |
984 zio_t *zio; | |
985 uint64_t used = 0, compressed = 0, uncompressed = 0; | |
986 struct killarg ka; | |
987 | |
988 zio = zio_root(tx->tx_pool->dp_spa, NULL, NULL, | |
989 ZIO_FLAG_MUSTSUCCEED); | |
990 ka.usedp = &used; | |
991 ka.compressedp = &compressed; | |
992 ka.uncompressedp = &uncompressed; | |
993 ka.zio = zio; | |
994 ka.tx = tx; | |
995 (void) traverse_dsl_dataset(ds, ds->ds_phys->ds_prev_snap_txg, | |
996 ADVANCE_POST, kill_blkptr, &ka); | |
997 (void) zio_wait(zio); | |
998 | |
2199 | 999 dsl_dir_diduse_space(ds->ds_dir, |
789 | 1000 -used, -compressed, -uncompressed, tx); |
1001 } | |
1002 | |
2199 | 1003 /* Change our contents to that of the prev snapshot */ |
789 | 1004 ASSERT3U(ds->ds_prev->ds_object, ==, ds->ds_phys->ds_prev_snap_obj); |
1005 ds->ds_phys->ds_bp = ds->ds_prev->ds_phys->ds_bp; | |
1006 ds->ds_phys->ds_used_bytes = ds->ds_prev->ds_phys->ds_used_bytes; | |
1007 ds->ds_phys->ds_compressed_bytes = | |
1008 ds->ds_prev->ds_phys->ds_compressed_bytes; | |
1009 ds->ds_phys->ds_uncompressed_bytes = | |
1010 ds->ds_prev->ds_phys->ds_uncompressed_bytes; | |
2082 | 1011 ds->ds_phys->ds_flags = ds->ds_prev->ds_phys->ds_flags; |
789 | 1012 ds->ds_phys->ds_unique_bytes = 0; |
1013 | |
2532
752725c22841
6448999 panic: used == ds->ds_phys->ds_unique_bytes
ahrens
parents:
2417
diff
changeset
|
1014 if (ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) { |
752725c22841
6448999 panic: used == ds->ds_phys->ds_unique_bytes
ahrens
parents:
2417
diff
changeset
|
1015 dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); |
752725c22841
6448999 panic: used == ds->ds_phys->ds_unique_bytes
ahrens
parents:
2417
diff
changeset
|
1016 ds->ds_prev->ds_phys->ds_unique_bytes = 0; |
752725c22841
6448999 panic: used == ds->ds_phys->ds_unique_bytes
ahrens
parents:
2417
diff
changeset
|
1017 } |
4543 | 1018 |
1019 spa_history_internal_log(LOG_DS_ROLLBACK, ds->ds_dir->dd_pool->dp_spa, | |
1020 tx, cr, "dataset = %llu", ds->ds_object); | |
789 | 1021 } |
1022 | |
1731
1efa8b3d1296
6402598 'zfs destroy <fs>' can take a long time, stopping up the txg train
bonwick
parents:
1544
diff
changeset
|
1023 /* ARGSUSED */ |
1efa8b3d1296
6402598 'zfs destroy <fs>' can take a long time, stopping up the txg train
bonwick
parents:
1544
diff
changeset
|
1024 static int |
2199 | 1025 dsl_dataset_destroy_begin_check(void *arg1, void *arg2, dmu_tx_t *tx) |
1731
1efa8b3d1296
6402598 'zfs destroy <fs>' can take a long time, stopping up the txg train
bonwick
parents:
1544
diff
changeset
|
1026 { |
2199 | 1027 dsl_dataset_t *ds = arg1; |
1731
1efa8b3d1296
6402598 'zfs destroy <fs>' can take a long time, stopping up the txg train
bonwick
parents:
1544
diff
changeset
|
1028 |
1efa8b3d1296
6402598 'zfs destroy <fs>' can take a long time, stopping up the txg train
bonwick
parents:
1544
diff
changeset
|
1029 /* |
1efa8b3d1296
6402598 'zfs destroy <fs>' can take a long time, stopping up the txg train
bonwick
parents:
1544
diff
changeset
|
1030 * Can't delete a head dataset if there are snapshots of it. |
1efa8b3d1296
6402598 'zfs destroy <fs>' can take a long time, stopping up the txg train
bonwick
parents:
1544
diff
changeset
|
1031 * (Except if the only snapshots are from the branch we cloned |
1efa8b3d1296
6402598 'zfs destroy <fs>' can take a long time, stopping up the txg train
bonwick
parents:
1544
diff
changeset
|
1032 * from.) |
1efa8b3d1296
6402598 'zfs destroy <fs>' can take a long time, stopping up the txg train
bonwick
parents:
1544
diff
changeset
|
1033 */ |
1efa8b3d1296
6402598 'zfs destroy <fs>' can take a long time, stopping up the txg train
bonwick
parents:
1544
diff
changeset
|
1034 if (ds->ds_prev != NULL && |
1efa8b3d1296
6402598 'zfs destroy <fs>' can take a long time, stopping up the txg train
bonwick
parents:
1544
diff
changeset
|
1035 ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) |
1efa8b3d1296
6402598 'zfs destroy <fs>' can take a long time, stopping up the txg train
bonwick
parents:
1544
diff
changeset
|
1036 return (EINVAL); |
1efa8b3d1296
6402598 'zfs destroy <fs>' can take a long time, stopping up the txg train
bonwick
parents:
1544
diff
changeset
|
1037 |
1efa8b3d1296
6402598 'zfs destroy <fs>' can take a long time, stopping up the txg train
bonwick
parents:
1544
diff
changeset
|
1038 return (0); |
1efa8b3d1296
6402598 'zfs destroy <fs>' can take a long time, stopping up the txg train
bonwick
parents:
1544
diff
changeset
|
1039 } |
1efa8b3d1296
6402598 'zfs destroy <fs>' can take a long time, stopping up the txg train
bonwick
parents:
1544
diff
changeset
|
1040 |
2199 | 1041 /* ARGSUSED */ |
1042 static void | |
4543 | 1043 dsl_dataset_destroy_begin_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) |
789 | 1044 { |
2199 | 1045 dsl_dataset_t *ds = arg1; |
4543 | 1046 dsl_pool_t *dp = ds->ds_dir->dd_pool; |
789 | 1047 |
2199 | 1048 /* Mark it as inconsistent on-disk, in case we crash */ |
1049 dmu_buf_will_dirty(ds->ds_dbuf, tx); | |
1050 ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; | |
4543 | 1051 |
1052 spa_history_internal_log(LOG_DS_DESTROY_BEGIN, dp->dp_spa, tx, | |
1053 cr, "dataset = %llu", ds->ds_object); | |
2199 | 1054 } |
789 | 1055 |
2199 | 1056 /* ARGSUSED */ |
1057 static int | |
1058 dsl_dataset_destroy_check(void *arg1, void *arg2, dmu_tx_t *tx) | |
1059 { | |
1060 dsl_dataset_t *ds = arg1; | |
789 | 1061 |
1062 /* Can't delete a branch point. */ | |
2199 | 1063 if (ds->ds_phys->ds_num_children > 1) |
1064 return (EEXIST); | |
789 | 1065 |
1066 /* | |
1067 * Can't delete a head dataset if there are snapshots of it. | |
1068 * (Except if the only snapshots are from the branch we cloned | |
1069 * from.) | |
1070 */ | |
1071 if (ds->ds_prev != NULL && | |
2199 | 1072 ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) |
789 | 1073 return (EINVAL); |
1074 | |
1075 /* | |
1076 * If we made changes this txg, traverse_dsl_dataset won't find | |
1077 * them. Try again. | |
1078 */ | |
2199 | 1079 if (ds->ds_phys->ds_bp.blk_birth >= tx->tx_txg) |
789 | 1080 return (EAGAIN); |
2199 | 1081 |
1082 /* XXX we should do some i/o error checking... */ | |
1083 return (0); | |
1084 } | |
1085 | |
1086 static void | |
4543 | 1087 dsl_dataset_destroy_sync(void *arg1, void *tag, cred_t *cr, dmu_tx_t *tx) |
2199 | 1088 { |
1089 dsl_dataset_t *ds = arg1; | |
1090 uint64_t used = 0, compressed = 0, uncompressed = 0; | |
1091 zio_t *zio; | |
1092 int err; | |
1093 int after_branch_point = FALSE; | |
1094 dsl_pool_t *dp = ds->ds_dir->dd_pool; | |
1095 objset_t *mos = dp->dp_meta_objset; | |
1096 dsl_dataset_t *ds_prev = NULL; | |
1097 uint64_t obj; | |
1098 | |
3444
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3025
diff
changeset
|
1099 ASSERT3U(ds->ds_open_refcount, ==, DS_REF_MAX); |
2199 | 1100 ASSERT3U(ds->ds_phys->ds_num_children, <=, 1); |
1101 ASSERT(ds->ds_prev == NULL || | |
1102 ds->ds_prev->ds_phys->ds_next_snap_obj != ds->ds_object); | |
1103 ASSERT3U(ds->ds_phys->ds_bp.blk_birth, <=, tx->tx_txg); | |
1104 | |
1105 ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); | |
1106 | |
1107 obj = ds->ds_object; | |
789 | 1108 |
1109 if (ds->ds_phys->ds_prev_snap_obj != 0) { | |
1110 if (ds->ds_prev) { | |
1111 ds_prev = ds->ds_prev; | |
1112 } else { | |
2199 | 1113 VERIFY(0 == dsl_dataset_open_obj(dp, |
789 | 1114 ds->ds_phys->ds_prev_snap_obj, NULL, |
2199 | 1115 DS_MODE_NONE, FTAG, &ds_prev)); |
789 | 1116 } |
1117 after_branch_point = | |
1118 (ds_prev->ds_phys->ds_next_snap_obj != obj); | |
1119 | |
1120 dmu_buf_will_dirty(ds_prev->ds_dbuf, tx); | |
1121 if (after_branch_point && | |
1122 ds->ds_phys->ds_next_snap_obj == 0) { | |
1123 /* This clone is toast. */ | |
1124 ASSERT(ds_prev->ds_phys->ds_num_children > 1); | |
1125 ds_prev->ds_phys->ds_num_children--; | |
1126 } else if (!after_branch_point) { | |
1127 ds_prev->ds_phys->ds_next_snap_obj = | |
1128 ds->ds_phys->ds_next_snap_obj; | |
1129 } | |
1130 } | |
1131 | |
1132 zio = zio_root(dp->dp_spa, NULL, NULL, ZIO_FLAG_MUSTSUCCEED); | |
1133 | |
1134 if (ds->ds_phys->ds_next_snap_obj != 0) { | |
2199 | 1135 blkptr_t bp; |
789 | 1136 dsl_dataset_t *ds_next; |
1137 uint64_t itor = 0; | |
1138 | |
1139 spa_scrub_restart(dp->dp_spa, tx->tx_txg); | |
1140 | |
2199 | 1141 VERIFY(0 == dsl_dataset_open_obj(dp, |
1544 | 1142 ds->ds_phys->ds_next_snap_obj, NULL, |
1143 DS_MODE_NONE, FTAG, &ds_next)); | |
789 | 1144 ASSERT3U(ds_next->ds_phys->ds_prev_snap_obj, ==, obj); |
1145 | |
1146 dmu_buf_will_dirty(ds_next->ds_dbuf, tx); | |
1147 ds_next->ds_phys->ds_prev_snap_obj = | |
1148 ds->ds_phys->ds_prev_snap_obj; | |
1149 ds_next->ds_phys->ds_prev_snap_txg = | |
1150 ds->ds_phys->ds_prev_snap_txg; | |
1151 ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==, | |
1152 ds_prev ? ds_prev->ds_phys->ds_creation_txg : 0); | |
1153 | |
1154 /* | |
1155 * Transfer to our deadlist (which will become next's | |
1156 * new deadlist) any entries from next's current | |
1157 * deadlist which were born before prev, and free the | |
1158 * other entries. | |
1159 * | |
1160 * XXX we're doing this long task with the config lock held | |
1161 */ | |
1162 while (bplist_iterate(&ds_next->ds_deadlist, &itor, | |
1163 &bp) == 0) { | |
1164 if (bp.blk_birth <= ds->ds_phys->ds_prev_snap_txg) { | |
1544 | 1165 VERIFY(0 == bplist_enqueue(&ds->ds_deadlist, |
1166 &bp, tx)); | |
789 | 1167 if (ds_prev && !after_branch_point && |
1168 bp.blk_birth > | |
1169 ds_prev->ds_phys->ds_prev_snap_txg) { | |
1170 ds_prev->ds_phys->ds_unique_bytes += | |
2082 | 1171 bp_get_dasize(dp->dp_spa, &bp); |
789 | 1172 } |
1173 } else { | |
2082 | 1174 used += bp_get_dasize(dp->dp_spa, &bp); |
789 | 1175 compressed += BP_GET_PSIZE(&bp); |
1176 uncompressed += BP_GET_UCSIZE(&bp); | |
1177 /* XXX check return value? */ | |
1178 (void) arc_free(zio, dp->dp_spa, tx->tx_txg, | |
1179 &bp, NULL, NULL, ARC_NOWAIT); | |
1180 } | |
1181 } | |
1182 | |
1183 /* free next's deadlist */ | |
1184 bplist_close(&ds_next->ds_deadlist); | |
1185 bplist_destroy(mos, ds_next->ds_phys->ds_deadlist_obj, tx); | |
1186 | |
1187 /* set next's deadlist to our deadlist */ | |
1188 ds_next->ds_phys->ds_deadlist_obj = | |
1189 ds->ds_phys->ds_deadlist_obj; | |
1544 | 1190 VERIFY(0 == bplist_open(&ds_next->ds_deadlist, mos, |
1191 ds_next->ds_phys->ds_deadlist_obj)); | |
789 | 1192 ds->ds_phys->ds_deadlist_obj = 0; |
1193 | |
1194 if (ds_next->ds_phys->ds_next_snap_obj != 0) { | |
1195 /* | |
1196 * Update next's unique to include blocks which | |
1197 * were previously shared by only this snapshot | |
1198 * and it. Those blocks will be born after the | |
1199 * prev snap and before this snap, and will have | |
1200 * died after the next snap and before the one | |
1201 * after that (ie. be on the snap after next's | |
1202 * deadlist). | |
1203 * | |
1204 * XXX we're doing this long task with the | |
1205 * config lock held | |
1206 */ | |
1207 dsl_dataset_t *ds_after_next; | |
1208 | |
2199 | 1209 VERIFY(0 == dsl_dataset_open_obj(dp, |
789 | 1210 ds_next->ds_phys->ds_next_snap_obj, NULL, |
1544 | 1211 DS_MODE_NONE, FTAG, &ds_after_next)); |
789 | 1212 itor = 0; |
1213 while (bplist_iterate(&ds_after_next->ds_deadlist, | |
1214 &itor, &bp) == 0) { | |
1215 if (bp.blk_birth > | |
1216 ds->ds_phys->ds_prev_snap_txg && | |
1217 bp.blk_birth <= | |
1218 ds->ds_phys->ds_creation_txg) { | |
1219 ds_next->ds_phys->ds_unique_bytes += | |
2082 | 1220 bp_get_dasize(dp->dp_spa, &bp); |
789 | 1221 } |
1222 } | |
1223 | |
1224 dsl_dataset_close(ds_after_next, DS_MODE_NONE, FTAG); | |
1225 ASSERT3P(ds_next->ds_prev, ==, NULL); | |
1226 } else { | |
1227 /* | |
1228 * It would be nice to update the head dataset's | |
1229 * unique. To do so we would have to traverse | |
1230 * it for blocks born after ds_prev, which is | |
1231 * pretty expensive just to maintain something | |
1232 * for debugging purposes. | |
1233 */ | |
1234 ASSERT3P(ds_next->ds_prev, ==, ds); | |
1235 dsl_dataset_close(ds_next->ds_prev, DS_MODE_NONE, | |
1236 ds_next); | |
1237 if (ds_prev) { | |
2199 | 1238 VERIFY(0 == dsl_dataset_open_obj(dp, |
1544 | 1239 ds->ds_phys->ds_prev_snap_obj, NULL, |
1240 DS_MODE_NONE, ds_next, &ds_next->ds_prev)); | |
789 | 1241 } else { |
1242 ds_next->ds_prev = NULL; | |
1243 } | |
1244 } | |
1245 dsl_dataset_close(ds_next, DS_MODE_NONE, FTAG); | |
1246 | |
1247 /* | |
1248 * NB: unique_bytes is not accurate for head objsets | |
1249 * because we don't update it when we delete the most | |
1250 * recent snapshot -- see above comment. | |
1251 */ | |
1252 ASSERT3U(used, ==, ds->ds_phys->ds_unique_bytes); | |
1253 } else { | |
1254 /* | |
1255 * There's no next snapshot, so this is a head dataset. | |
1256 * Destroy the deadlist. Unless it's a clone, the | |
1257 * deadlist should be empty. (If it's a clone, it's | |
1258 * safe to ignore the deadlist contents.) | |
1259 */ | |
1260 struct killarg ka; | |
1261 | |
1262 ASSERT(after_branch_point || bplist_empty(&ds->ds_deadlist)); | |
1263 bplist_close(&ds->ds_deadlist); | |
1264 bplist_destroy(mos, ds->ds_phys->ds_deadlist_obj, tx); | |
1265 ds->ds_phys->ds_deadlist_obj = 0; | |
1266 | |
1267 /* | |
1268 * Free everything that we point to (that's born after | |
1269 * the previous snapshot, if we are a clone) | |
1270 * | |
1271 * XXX we're doing this long task with the config lock held | |
1272 */ | |
1273 ka.usedp = &used; | |
1274 ka.compressedp = &compressed; | |
1275 ka.uncompressedp = &uncompressed; | |
1276 ka.zio = zio; | |
1277 ka.tx = tx; | |
1278 err = traverse_dsl_dataset(ds, ds->ds_phys->ds_prev_snap_txg, | |
1279 ADVANCE_POST, kill_blkptr, &ka); | |
1280 ASSERT3U(err, ==, 0); | |
1281 } | |
1282 | |
1283 err = zio_wait(zio); | |
1284 ASSERT3U(err, ==, 0); | |
1285 | |
2199 | 1286 dsl_dir_diduse_space(ds->ds_dir, -used, -compressed, -uncompressed, tx); |
789 | 1287 |
1288 if (ds->ds_phys->ds_snapnames_zapobj) { | |
1289 err = zap_destroy(mos, ds->ds_phys->ds_snapnames_zapobj, tx); | |
1290 ASSERT(err == 0); | |
1291 } | |
1292 | |
2199 | 1293 if (ds->ds_dir->dd_phys->dd_head_dataset_obj == ds->ds_object) { |
789 | 1294 /* Erase the link in the dataset */ |
2199 | 1295 dmu_buf_will_dirty(ds->ds_dir->dd_dbuf, tx); |
1296 ds->ds_dir->dd_phys->dd_head_dataset_obj = 0; | |
789 | 1297 /* |
1298 * dsl_dir_sync_destroy() called us, they'll destroy | |
1299 * the dataset. | |
1300 */ | |
1301 } else { | |
1302 /* remove from snapshot namespace */ | |
1303 dsl_dataset_t *ds_head; | |
2199 | 1304 VERIFY(0 == dsl_dataset_open_obj(dp, |
1305 ds->ds_dir->dd_phys->dd_head_dataset_obj, NULL, | |
1544 | 1306 DS_MODE_NONE, FTAG, &ds_head)); |
2207
47efcb3433a7
6439370 assertion failures possible in dsl_dataset_destroy_sync()
ahrens
parents:
2199
diff
changeset
|
1307 VERIFY(0 == dsl_dataset_get_snapname(ds)); |
789 | 1308 #ifdef ZFS_DEBUG |
1309 { | |
1310 uint64_t val; | |
1311 err = zap_lookup(mos, | |
1312 ds_head->ds_phys->ds_snapnames_zapobj, | |
2199 | 1313 ds->ds_snapname, 8, 1, &val); |
789 | 1314 ASSERT3U(err, ==, 0); |
1315 ASSERT3U(val, ==, obj); | |
1316 } | |
1317 #endif | |
1318 err = zap_remove(mos, ds_head->ds_phys->ds_snapnames_zapobj, | |
2199 | 1319 ds->ds_snapname, tx); |
789 | 1320 ASSERT(err == 0); |
1321 dsl_dataset_close(ds_head, DS_MODE_NONE, FTAG); | |
1322 } | |
1323 | |
1324 if (ds_prev && ds->ds_prev != ds_prev) | |
1325 dsl_dataset_close(ds_prev, DS_MODE_NONE, FTAG); | |
1326 | |
5094 | 1327 spa_prop_clear_bootfs(dp->dp_spa, ds->ds_object, tx); |
4543 | 1328 spa_history_internal_log(LOG_DS_DESTROY, dp->dp_spa, tx, |
1329 cr, "dataset = %llu", ds->ds_object); | |
1330 | |
2199 | 1331 dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, tag); |
1332 VERIFY(0 == dmu_object_free(mos, obj, tx)); | |
3912 | 1333 |
2199 | 1334 } |
1335 | |
1336 /* ARGSUSED */ | |
1337 int | |
1338 dsl_dataset_snapshot_check(void *arg1, void *arg2, dmu_tx_t *tx) | |
1339 { | |
1340 objset_t *os = arg1; | |
1341 dsl_dataset_t *ds = os->os->os_dsl_dataset; | |
1342 const char *snapname = arg2; | |
1343 objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; | |
1344 int err; | |
1345 uint64_t value; | |
789 | 1346 |
1347 /* | |
2199 | 1348 * We don't allow multiple snapshots of the same txg. If there |
1349 * is already one, try again. | |
1350 */ | |
1351 if (ds->ds_phys->ds_prev_snap_txg >= tx->tx_txg) | |
1352 return (EAGAIN); | |
1353 | |
1354 /* | |
1355 * Check for conflicting name snapshot name. | |
789 | 1356 */ |
2199 | 1357 err = zap_lookup(mos, ds->ds_phys->ds_snapnames_zapobj, |
1358 snapname, 8, 1, &value); | |
1359 if (err == 0) | |
1360 return (EEXIST); | |
1361 if (err != ENOENT) | |
1362 return (err); | |
789 | 1363 |
3978
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
1364 /* |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
1365 * Check that the dataset's name is not too long. Name consists |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
1366 * of the dataset's length + 1 for the @-sign + snapshot name's length |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
1367 */ |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
1368 if (dsl_dataset_namelen(ds) + 1 + strlen(snapname) >= MAXNAMELEN) |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
1369 return (ENAMETOOLONG); |
2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
mmusante
parents:
3912
diff
changeset
|
1370 |
2199 | 1371 ds->ds_trysnap_txg = tx->tx_txg; |
789 | 1372 return (0); |
1373 } | |
1374 | |
2199 | 1375 void |
4543 | 1376 dsl_dataset_snapshot_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) |
789 | 1377 { |
2199 | 1378 objset_t *os = arg1; |
1379 dsl_dataset_t *ds = os->os->os_dsl_dataset; | |
1380 const char *snapname = arg2; | |
1381 dsl_pool_t *dp = ds->ds_dir->dd_pool; | |
789 | 1382 dmu_buf_t *dbuf; |
1383 dsl_dataset_phys_t *dsphys; | |
2199 | 1384 uint64_t dsobj; |
789 | 1385 objset_t *mos = dp->dp_meta_objset; |
1386 int err; | |
1387 | |
1388 spa_scrub_restart(dp->dp_spa, tx->tx_txg); | |
2199 | 1389 ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); |
789 | 1390 |
928
36d72fe4da29
6349314 dmu_object_type names incorrect for DSL Directories and DSL Datasets
tabriz
parents:
885
diff
changeset
|
1391 dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, |
36d72fe4da29
6349314 dmu_object_type names incorrect for DSL Directories and DSL Datasets
tabriz
parents:
885
diff
changeset
|
1392 DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); |
1544 | 1393 VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); |
789 | 1394 dmu_buf_will_dirty(dbuf, tx); |
1395 dsphys = dbuf->db_data; | |
2199 | 1396 dsphys->ds_dir_obj = ds->ds_dir->dd_object; |
789 | 1397 dsphys->ds_fsid_guid = unique_create(); |
1398 (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, | |
1399 sizeof (dsphys->ds_guid)); | |
1400 dsphys->ds_prev_snap_obj = ds->ds_phys->ds_prev_snap_obj; | |
1401 dsphys->ds_prev_snap_txg = ds->ds_phys->ds_prev_snap_txg; | |
1402 dsphys->ds_next_snap_obj = ds->ds_object; | |
1403 dsphys->ds_num_children = 1; | |
1404 dsphys->ds_creation_time = gethrestime_sec(); | |
1405 dsphys->ds_creation_txg = tx->tx_txg; | |
1406 dsphys->ds_deadlist_obj = ds->ds_phys->ds_deadlist_obj; | |
1407 dsphys->ds_used_bytes = ds->ds_phys->ds_used_bytes; | |
1408 dsphys->ds_compressed_bytes = ds->ds_phys->ds_compressed_bytes; | |
1409 dsphys->ds_uncompressed_bytes = ds->ds_phys->ds_uncompressed_bytes; | |
2082 | 1410 dsphys->ds_flags = ds->ds_phys->ds_flags; |
789 | 1411 dsphys->ds_bp = ds->ds_phys->ds_bp; |
1544 | 1412 dmu_buf_rele(dbuf, FTAG); |
789 | 1413 |
2199 | 1414 ASSERT3U(ds->ds_prev != 0, ==, ds->ds_phys->ds_prev_snap_obj != 0); |
1415 if (ds->ds_prev) { | |
1416 ASSERT(ds->ds_prev->ds_phys->ds_next_snap_obj == | |
789 | 1417 ds->ds_object || |
2199 | 1418 ds->ds_prev->ds_phys->ds_num_children > 1); |
1419 if (ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) { | |
1420 dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); | |
789 | 1421 ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==, |
2199 | 1422 ds->ds_prev->ds_phys->ds_creation_txg); |
1423 ds->ds_prev->ds_phys->ds_next_snap_obj = dsobj; | |
789 | 1424 } |
1425 } | |
1426 | |
1427 bplist_close(&ds->ds_deadlist); | |
1428 dmu_buf_will_dirty(ds->ds_dbuf, tx); | |
1429 ASSERT3U(ds->ds_phys->ds_prev_snap_txg, <, dsphys->ds_creation_txg); | |
1430 ds->ds_phys->ds_prev_snap_obj = dsobj; | |
1431 ds->ds_phys->ds_prev_snap_txg = dsphys->ds_creation_txg; | |
1432 ds->ds_phys->ds_unique_bytes = 0; | |
1433 ds->ds_phys->ds_deadlist_obj = | |
1434 bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); | |
1544 | 1435 VERIFY(0 == bplist_open(&ds->ds_deadlist, mos, |
1436 ds->ds_phys->ds_deadlist_obj)); | |
789 | 1437 |
1438 dprintf("snap '%s' -> obj %llu\n", snapname, dsobj); | |
1439 err = zap_add(mos, ds->ds_phys->ds_snapnames_zapobj, | |
1440 snapname, 8, 1, &dsobj, tx); | |
1441 ASSERT(err == 0); | |
1442 | |
1443 if (ds->ds_prev) | |
1444 dsl_dataset_close(ds->ds_prev, DS_MODE_NONE, ds); | |
1544 | 1445 VERIFY(0 == dsl_dataset_open_obj(dp, |
1446 ds->ds_phys->ds_prev_snap_obj, snapname, | |
1447 DS_MODE_NONE, ds, &ds->ds_prev)); | |
4543 | 1448 |
1449 spa_history_internal_log(LOG_DS_SNAPSHOT, dp->dp_spa, tx, cr, | |
4603
c7840c367d00
6494569 zfs recv -d pool/<doesn't exist> core dumps for top-level filesystem backups
ahrens
parents:
4577
diff
changeset
|
1450 "dataset = %llu", dsobj); |
789 | 1451 } |
1452 | |
1453 void | |
3547
e396e0a440b1
6512391 DMU should leverage ZIO dependencies to achieve greater parallelism
maybee
parents:
3444
diff
changeset
|
1454 dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx) |
789 | 1455 { |
1456 ASSERT(dmu_tx_is_syncing(tx)); | |
1457 ASSERT(ds->ds_user_ptr != NULL); | |
1458 ASSERT(ds->ds_phys->ds_next_snap_obj == 0); | |
1459 | |
4787 | 1460 /* |
1461 * in case we had to change ds_fsid_guid when we opened it, | |
1462 * sync it out now. | |
1463 */ | |
1464 dmu_buf_will_dirty(ds->ds_dbuf, tx); | |
1465 ds->ds_phys->ds_fsid_guid = ds->ds_fsid_guid; | |
1466 | |
789 | 1467 dsl_dir_dirty(ds->ds_dir, tx); |
3547
e396e0a440b1
6512391 DMU should leverage ZIO dependencies to achieve greater parallelism
maybee
parents:
3444
diff
changeset
|
1468 dmu_objset_sync(ds->ds_user_ptr, zio, tx); |
789 | 1469 } |
1470 | |
1471 void | |
2885 | 1472 dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv) |
789 | 1473 { |
2885 | 1474 dsl_dir_stats(ds->ds_dir, nv); |
789 | 1475 |
2885 | 1476 dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATION, |
1477 ds->ds_phys->ds_creation_time); | |
1478 dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATETXG, | |
1479 ds->ds_phys->ds_creation_txg); | |
1480 dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFERENCED, | |
1481 ds->ds_phys->ds_used_bytes); | |
789 | 1482 |
1483 if (ds->ds_phys->ds_next_snap_obj) { | |
1484 /* | |
1485 * This is a snapshot; override the dd's space used with | |
2885 | 1486 * our unique space and compression ratio. |
789 | 1487 */ |
2885 | 1488 dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED, |
1489 ds->ds_phys->ds_unique_bytes); | |
1490 dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO, | |
1491 ds->ds_phys->ds_compressed_bytes == 0 ? 100 : | |
1492 (ds->ds_phys->ds_uncompressed_bytes * 100 / | |
1493 ds->ds_phys->ds_compressed_bytes)); | |
789 | 1494 } |
1495 } | |
1496 | |
2885 | 1497 void |
1498 dsl_dataset_fast_stat(dsl_dataset_t *ds, dmu_objset_stats_t *stat) | |
789 | 1499 { |
2885 | 1500 stat->dds_creation_txg = ds->ds_phys->ds_creation_txg; |
1501 stat->dds_inconsistent = ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT; | |
1502 if (ds->ds_phys->ds_next_snap_obj) { | |
1503 stat->dds_is_snapshot = B_TRUE; | |
1504 stat->dds_num_clones = ds->ds_phys->ds_num_children - 1; | |
1505 } | |
1506 | |
1507 /* clone origin is really a dsl_dir thing... */ | |
1508 if (ds->ds_dir->dd_phys->dd_clone_parent_obj) { | |
1509 dsl_dataset_t *ods; | |
1510 | |
1511 rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); | |
1512 VERIFY(0 == dsl_dataset_open_obj(ds->ds_dir->dd_pool, | |
1513 ds->ds_dir->dd_phys->dd_clone_parent_obj, | |
1514 NULL, DS_MODE_NONE, FTAG, &ods)); | |
1515 dsl_dataset_name(ods, stat->dds_clone_of); | |
1516 dsl_dataset_close(ods, DS_MODE_NONE, FTAG); | |
1517 rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); | |
1518 } | |
1519 } | |
1520 | |
1521 uint64_t | |
1522 dsl_dataset_fsid_guid(dsl_dataset_t *ds) | |
1523 { | |
4787 | 1524 return (ds->ds_fsid_guid); |
2885 | 1525 } |
1526 | |
1527 void | |
1528 dsl_dataset_space(dsl_dataset_t *ds, | |
1529 uint64_t *refdbytesp, uint64_t *availbytesp, | |
1530 uint64_t *usedobjsp, uint64_t *availobjsp) | |
1531 { | |
1532 *refdbytesp = ds->ds_phys->ds_used_bytes; | |
1533 *availbytesp = dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE); | |
1534 *usedobjsp = ds->ds_phys->ds_bp.blk_fill; | |
1535 *availobjsp = DN_MAX_OBJECT - *usedobjsp; | |
789 | 1536 } |
1537 | |
2199 | 1538 /* ARGSUSED */ |
789 | 1539 static int |
2199 | 1540 dsl_dataset_snapshot_rename_check(void *arg1, void *arg2, dmu_tx_t *tx) |
789 | 1541 { |
2199 | 1542 dsl_dataset_t *ds = arg1; |
1543 char *newsnapname = arg2; | |
1544 dsl_dir_t *dd = ds->ds_dir; | |
789 | 1545 objset_t *mos = dd->dd_pool->dp_meta_objset; |
2199 | 1546 dsl_dataset_t *hds; |
1547 uint64_t val; | |
789 | 1548 int err; |
1549 | |
2199 | 1550 err = dsl_dataset_open_obj(dd->dd_pool, |
1551 dd->dd_phys->dd_head_dataset_obj, NULL, DS_MODE_NONE, FTAG, &hds); | |
789 | 1552 if (err) |
1553 return (err); | |
1554 | |
2199 | 1555 /* new name better not be in use */ |
1556 err = zap_lookup(mos, hds->ds_phys->ds_snapnames_zapobj, | |
1557 newsnapname, 8, 1, &val); | |
1558 dsl_dataset_close(hds, DS_MODE_NONE, FTAG); | |
789 | 1559 |
2199 | 1560 if (err == 0) |
1561 err = EEXIST; | |
1562 else if (err == ENOENT) | |
1563 err = 0; | |
4007 | 1564 |
1565 /* dataset name + 1 for the "@" + the new snapshot name must fit */ | |
1566 if (dsl_dir_namelen(ds->ds_dir) + 1 + strlen(newsnapname) >= MAXNAMELEN) | |
1567 err = ENAMETOOLONG; | |
1568 | |
2199 | 1569 return (err); |
1570 } | |
789 | 1571 |
2199 | 1572 static void |
4543 | 1573 dsl_dataset_snapshot_rename_sync(void *arg1, void *arg2, |
1574 cred_t *cr, dmu_tx_t *tx) | |
2199 | 1575 { |
1576 dsl_dataset_t *ds = arg1; | |
4543 | 1577 const char *newsnapname = arg2; |
2199 | 1578 dsl_dir_t *dd = ds->ds_dir; |
1579 objset_t *mos = dd->dd_pool->dp_meta_objset; | |
1580 dsl_dataset_t *hds; | |
1581 int err; | |
789 | 1582 |
2199 | 1583 ASSERT(ds->ds_phys->ds_next_snap_obj != 0); |
789 | 1584 |
2199 | 1585 VERIFY(0 == dsl_dataset_open_obj(dd->dd_pool, |
1586 dd->dd_phys->dd_head_dataset_obj, NULL, DS_MODE_NONE, FTAG, &hds)); | |
789 | 1587 |
2199 | 1588 VERIFY(0 == dsl_dataset_get_snapname(ds)); |
1589 err = zap_remove(mos, hds->ds_phys->ds_snapnames_zapobj, | |
1590 ds->ds_snapname, tx); | |
789 | 1591 ASSERT3U(err, ==, 0); |
2199 | 1592 mutex_enter(&ds->ds_lock); |
1593 (void) strcpy(ds->ds_snapname, newsnapname); | |
1594 mutex_exit(&ds->ds_lock); | |
1595 err = zap_add(mos, hds->ds_phys->ds_snapnames_zapobj, | |
1596 ds->ds_snapname, 8, 1, &ds->ds_object, tx); | |
789 | 1597 ASSERT3U(err, ==, 0); |
1598 | |
4543 | 1599 spa_history_internal_log(LOG_DS_RENAME, dd->dd_pool->dp_spa, tx, |
1600 cr, "dataset = %llu", ds->ds_object); | |
2199 | 1601 dsl_dataset_close(hds, DS_MODE_NONE, FTAG); |
789 | 1602 } |
1603 | |
4007 | 1604 struct renamearg { |
1605 dsl_sync_task_group_t *dstg; | |
1606 char failed[MAXPATHLEN]; | |
1607 char *oldsnap; | |
1608 char *newsnap; | |
1609 }; | |
1610 | |
1611 static int | |
1612 dsl_snapshot_rename_one(char *name, void *arg) | |
1613 { | |
1614 struct renamearg *ra = arg; | |
1615 dsl_dataset_t *ds = NULL; | |
1616 char *cp; | |
1617 int err; | |
1618 | |
1619 cp = name + strlen(name); | |
1620 *cp = '@'; | |
1621 (void) strcpy(cp + 1, ra->oldsnap); | |
4543 | 1622 |
1623 /* | |
1624 * For recursive snapshot renames the parent won't be changing | |
1625 * so we just pass name for both the to/from argument. | |
1626 */ | |
1627 if (err = zfs_secpolicy_rename_perms(name, name, CRED())) { | |
1628 (void) strcpy(ra->failed, name); | |
1629 return (err); | |
1630 } | |
1631 | |
4007 | 1632 err = dsl_dataset_open(name, DS_MODE_READONLY | DS_MODE_STANDARD, |
1633 ra->dstg, &ds); | |
1634 if (err == ENOENT) { | |
1635 *cp = '\0'; | |
1636 return (0); | |
1637 } | |
1638 if (err) { | |
1639 (void) strcpy(ra->failed, name); | |
1640 *cp = '\0'; | |
1641 dsl_dataset_close(ds, DS_MODE_STANDARD, ra->dstg); | |
1642 return (err); | |
1643 } | |
1644 | |
1645 #ifdef _KERNEL | |
1646 /* for all filesystems undergoing rename, we'll need to unmount it */ | |
1647 (void) zfs_unmount_snap(name, NULL); | |
1648 #endif | |
1649 | |
1650 *cp = '\0'; | |
1651 | |
1652 dsl_sync_task_create(ra->dstg, dsl_dataset_snapshot_rename_check, | |
1653 dsl_dataset_snapshot_rename_sync, ds, ra->newsnap, 0); | |
1654 | |
1655 return (0); | |
1656 } | |
1657 | |
1658 static int | |
1659 dsl_recursive_rename(char *oldname, const char *newname) | |
1660 { | |
1661 int err; | |
1662 struct renamearg *ra; | |
1663 dsl_sync_task_t *dst; | |
1664 spa_t *spa; | |
1665 char *cp, *fsname = spa_strdup(oldname); | |
1666 int len = strlen(oldname); | |
1667 | |
1668 /* truncate the snapshot name to get the fsname */ | |
1669 cp = strchr(fsname, '@'); | |
1670 *cp = '\0'; | |
1671 | |
4603
c7840c367d00
6494569 zfs recv -d pool/<doesn't exist> core dumps for top-level filesystem backups
ahrens
parents:
4577
diff
changeset
|
1672 err = spa_open(fsname, &spa, FTAG); |
4007 | 1673 if (err) { |
1674 kmem_free(fsname, len + 1); | |
1675 return (err); | |
1676 } | |
1677 ra = kmem_alloc(sizeof (struct renamearg), KM_SLEEP); | |
1678 ra->dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); | |
1679 | |
1680 ra->oldsnap = strchr(oldname, '@') + 1; | |
1681 ra->newsnap = strchr(newname, '@') + 1; | |
1682 *ra->failed = '\0'; | |
1683 | |
1684 err = dmu_objset_find(fsname, dsl_snapshot_rename_one, ra, | |
1685 DS_FIND_CHILDREN); | |
1686 kmem_free(fsname, len + 1); | |
1687 | |
1688 if (err == 0) { | |
1689 err = dsl_sync_task_group_wait(ra->dstg); | |
1690 } | |
1691 | |
1692 for (dst = list_head(&ra->dstg->dstg_tasks); dst; | |
1693 dst = list_next(&ra->dstg->dstg_tasks, dst)) { | |
1694 dsl_dataset_t *ds = dst->dst_arg1; | |
1695 if (dst->dst_err) { | |
1696 dsl_dir_name(ds->ds_dir, ra->failed); | |
4009
1a9b4fbc0d2a
6479884 want 'zfs rename -r' to recursively rename snapshots (fix lint)
mmusante
parents:
4007
diff
changeset
|
1697 (void) strcat(ra->failed, "@"); |
1a9b4fbc0d2a
6479884 want 'zfs rename -r' to recursively rename snapshots (fix lint)
mmusante
parents:
4007
diff
changeset
|
1698 (void) strcat(ra->failed, ra->newsnap); |
4007 | 1699 } |
1700 dsl_dataset_close(ds, DS_MODE_STANDARD, ra->dstg); | |
1701 } | |
1702 | |
4543 | 1703 if (err) |
1704 (void) strcpy(oldname, ra->failed); | |
4007 | 1705 |
1706 dsl_sync_task_group_destroy(ra->dstg); | |
1707 kmem_free(ra, sizeof (struct renamearg)); | |
1708 spa_close(spa, FTAG); | |
1709 return (err); | |
1710 } | |
1711 | |
4569
e80d40447f27
6355623 zfs rename to a valid dataset name, but its snapshot name becomes too long, panics the system
mmusante
parents:
4543
diff
changeset
|
1712 static int |
e80d40447f27
6355623 zfs rename to a valid dataset name, but its snapshot name becomes too long, panics the system
mmusante
parents:
4543
diff
changeset
|
1713 dsl_valid_rename(char *oldname, void *arg) |
e80d40447f27
6355623 zfs rename to a valid dataset name, but its snapshot name becomes too long, panics the system
mmusante
parents:
4543
diff
changeset
|
1714 { |
e80d40447f27
6355623 zfs rename to a valid dataset name, but its snapshot name becomes too long, panics the system
mmusante
parents:
4543
diff
changeset
|
1715 int delta = *(int *)arg; |
e80d40447f27
6355623 zfs rename to a valid dataset name, but its snapshot name becomes too long, panics the system
mmusante
parents:
4543
diff
changeset
|
1716 |
e80d40447f27
6355623 zfs rename to a valid dataset name, but its snapshot name becomes too long, panics the system
mmusante
parents:
4543
diff
changeset
|
1717 if (strlen(oldname) + delta >= MAXNAMELEN) |
e80d40447f27
6355623 zfs rename to a valid dataset name, but its snapshot name becomes too long, panics the system
mmusante
parents:
4543
diff
changeset
|
1718 return (ENAMETOOLONG); |
e80d40447f27
6355623 zfs rename to a valid dataset name, but its snapshot name becomes too long, panics the system
mmusante
parents:
4543
diff
changeset
|
1719 |
e80d40447f27
6355623 zfs rename to a valid dataset name, but its snapshot name becomes too long, panics the system
mmusante
parents:
4543
diff
changeset
|
1720 return (0); |
e80d40447f27
6355623 zfs rename to a valid dataset name, but its snapshot name becomes too long, panics the system
mmusante
parents:
4543
diff
changeset
|
1721 } |
e80d40447f27
6355623 zfs rename to a valid dataset name, but its snapshot name becomes too long, panics the system
mmusante
parents:
4543
diff
changeset
|
1722 |
789 | 1723 #pragma weak dmu_objset_rename = dsl_dataset_rename |
1724 int | |
4007 | 1725 dsl_dataset_rename(char *oldname, const char *newname, |
1726 boolean_t recursive) | |
789 | 1727 { |
1728 dsl_dir_t *dd; | |
2199 | 1729 dsl_dataset_t *ds; |
789 | 1730 const char *tail; |
1731 int err; | |
1732 | |
2199 | 1733 err = dsl_dir_open(oldname, FTAG, &dd, &tail); |
1544 | 1734 if (err) |
1735 return (err); | |
789 | 1736 if (tail == NULL) { |
4569
e80d40447f27
6355623 zfs rename to a valid dataset name, but its snapshot name becomes too long, panics the system
mmusante
parents:
4543
diff
changeset
|
1737 int delta = strlen(newname) - strlen(oldname); |
e80d40447f27
6355623 zfs rename to a valid dataset name, but its snapshot name becomes too long, panics the system
mmusante
parents:
4543
diff
changeset
|
1738 |
e80d40447f27
6355623 zfs rename to a valid dataset name, but its snapshot name becomes too long, panics the system
mmusante
parents:
4543
diff
changeset
|
1739 /* if we're growing, validate child size lengths */ |
e80d40447f27
6355623 zfs rename to a valid dataset name, but its snapshot name becomes too long, panics the system
mmusante
parents:
4543
diff
changeset
|
1740 if (delta > 0) |
e80d40447f27
6355623 zfs rename to a valid dataset name, but its snapshot name becomes too long, panics the system
mmusante
parents:
4543
diff
changeset
|
1741 err = dmu_objset_find(oldname, dsl_valid_rename, |
e80d40447f27
6355623 zfs rename to a valid dataset name, but its snapshot name becomes too long, panics the system
mmusante
parents:
4543
diff
changeset
|
1742 &delta, DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS); |
e80d40447f27
6355623 zfs rename to a valid dataset name, but its snapshot name becomes too long, panics the system
mmusante
parents:
4543
diff
changeset
|
1743 |
e80d40447f27
6355623 zfs rename to a valid dataset name, but its snapshot name becomes too long, panics the system
mmusante
parents:
4543
diff
changeset
|
1744 if (!err) |
e80d40447f27
6355623 zfs rename to a valid dataset name, but its snapshot name becomes too long, panics the system
mmusante
parents:
4543
diff
changeset
|
1745 err = dsl_dir_rename(dd, newname); |
789 | 1746 dsl_dir_close(dd, FTAG); |
1747 return (err); | |
1748 } | |
1749 if (tail[0] != '@') { | |
1750 /* the name ended in a nonexistant component */ | |
1751 dsl_dir_close(dd, FTAG); | |
1752 return (ENOENT); | |
1753 } | |
1754 | |
2199 | 1755 dsl_dir_close(dd, FTAG); |
1756 | |
1757 /* new name must be snapshot in same filesystem */ | |
1758 tail = strchr(newname, '@'); | |
1759 if (tail == NULL) | |
1760 return (EINVAL); | |
1761 tail++; | |
1762 if (strncmp(oldname, newname, tail - newname) != 0) | |
1763 return (EXDEV); | |
789 | 1764 |
4007 | 1765 if (recursive) { |
1766 err = dsl_recursive_rename(oldname, newname); | |
1767 } else { | |
1768 err = dsl_dataset_open(oldname, | |
1769 DS_MODE_READONLY | DS_MODE_STANDARD, FTAG, &ds); | |
1770 if (err) | |
1771 return (err); | |
2199 | 1772 |
4007 | 1773 err = dsl_sync_task_do(ds->ds_dir->dd_pool, |
1774 dsl_dataset_snapshot_rename_check, | |
1775 dsl_dataset_snapshot_rename_sync, ds, (char *)tail, 1); | |
2199 | 1776 |
4007 | 1777 dsl_dataset_close(ds, DS_MODE_STANDARD, FTAG); |
1778 } | |
2199 | 1779 |
789 | 1780 return (err); |
1781 } | |
2082 | 1782 |
2199 | 1783 struct promotearg { |
1784 uint64_t used, comp, uncomp, unique; | |
1785 uint64_t newnext_obj, snapnames_obj; | |
1786 }; | |
1787 | |
4543 | 1788 /* ARGSUSED */ |
2082 | 1789 static int |
2199 | 1790 dsl_dataset_promote_check(void *arg1, void *arg2, dmu_tx_t *tx) |
2082 | 1791 { |
2199 | 1792 dsl_dataset_t *hds = arg1; |
1793 struct promotearg *pa = arg2; | |
1794 dsl_dir_t *dd = hds->ds_dir; | |
1795 dsl_pool_t *dp = hds->ds_dir->dd_pool; | |
2082 | 1796 dsl_dir_t *pdd = NULL; |
1797 dsl_dataset_t *ds = NULL; | |
1798 dsl_dataset_t *pivot_ds = NULL; | |
1799 dsl_dataset_t *newnext_ds = NULL; | |
1800 int err; | |
1801 char *name = NULL; | |
2199 | 1802 uint64_t itor = 0; |
2082 | 1803 blkptr_t bp; |
1804 | |
2199 | 1805 bzero(pa, sizeof (*pa)); |
1806 | |
2082 | 1807 /* Check that it is a clone */ |
1808 if (dd->dd_phys->dd_clone_parent_obj == 0) | |
1809 return (EINVAL); | |
1810 | |
2199 | 1811 /* Since this is so expensive, don't do the preliminary check */ |
1812 if (!dmu_tx_is_syncing(tx)) | |
1813 return (0); | |
1814 | |
1815 if (err = dsl_dataset_open_obj(dp, | |
2082 | 1816 dd->dd_phys->dd_clone_parent_obj, |
1817 NULL, DS_MODE_EXCLUSIVE, FTAG, &pivot_ds)) | |
1818 goto out; | |
1819 pdd = pivot_ds->ds_dir; | |
2199 | 1820 |
1821 { | |
1822 dsl_dataset_t *phds; | |
1823 if (err = dsl_dataset_open_obj(dd->dd_pool, | |
1824 pdd->dd_phys->dd_head_dataset_obj, | |
1825 NULL, DS_MODE_NONE, FTAG, &phds)) | |
1826 goto out; | |
1827 pa->snapnames_obj = phds->ds_phys->ds_snapnames_zapobj; | |
1828 dsl_dataset_close(phds, DS_MODE_NONE, FTAG); | |
1829 } | |
2082 | 1830 |
1831 if (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE) { | |
1832 err = EXDEV; | |
1833 goto out; | |
1834 } | |
1835 | |
1836 /* find pivot point's new next ds */ | |
1837 VERIFY(0 == dsl_dataset_open_obj(dd->dd_pool, hds->ds_object, | |
1838 NULL, DS_MODE_NONE, FTAG, &newnext_ds)); | |
1839 while (newnext_ds->ds_phys->ds_prev_snap_obj != pivot_ds->ds_object) { | |
1840 dsl_dataset_t *prev; | |
1841 | |
1842 if (err = dsl_dataset_open_obj(dd->dd_pool, | |
2199 | 1843 newnext_ds->ds_phys->ds_prev_snap_obj, |
1844 NULL, DS_MODE_NONE, FTAG, &prev)) | |
2082 | 1845 goto out; |
1846 dsl_dataset_close(newnext_ds, DS_MODE_NONE, FTAG); | |
1847 newnext_ds = prev; | |
1848 } | |
2199 | 1849 pa->newnext_obj = newnext_ds->ds_object; |
2082 | 1850 |
1851 /* compute pivot point's new unique space */ | |
1852 while ((err = bplist_iterate(&newnext_ds->ds_deadlist, | |
1853 &itor, &bp)) == 0) { | |
1854 if (bp.blk_birth > pivot_ds->ds_phys->ds_prev_snap_txg) | |
2199 | 1855 pa->unique += bp_get_dasize(dd->dd_pool->dp_spa, &bp); |
2082 | 1856 } |
1857 if (err != ENOENT) | |
1858 goto out; | |
1859 | |
1860 /* Walk the snapshots that we are moving */ | |
1861 name = kmem_alloc(MAXPATHLEN, KM_SLEEP); | |
1862 ds = pivot_ds; | |
1863 /* CONSTCOND */ | |
1864 while (TRUE) { | |
1865 uint64_t val, dlused, dlcomp, dluncomp; | |
1866 dsl_dataset_t *prev; | |
1867 | |
1868 /* Check that the snapshot name does not conflict */ | |
1869 dsl_dataset_name(ds, name); | |
1870 err = zap_lookup(dd->dd_pool->dp_meta_objset, | |
1871 hds->ds_phys->ds_snapnames_zapobj, ds->ds_snapname, | |
1872 8, 1, &val); | |
1873 if (err != ENOENT) { | |
1874 if (err == 0) | |
1875 err = EEXIST; | |
1876 goto out; | |
1877 } | |
1878 | |
1879 /* | |
1880 * compute space to transfer. Each snapshot gave birth to: | |
1881 * (my used) - (prev's used) + (deadlist's used) | |
1882 */ | |
2199 | 1883 pa->used += ds->ds_phys->ds_used_bytes; |
1884 pa->comp += ds->ds_phys->ds_compressed_bytes; | |
1885 pa->uncomp += ds->ds_phys->ds_uncompressed_bytes; | |
2082 | 1886 |
1887 /* If we reach the first snapshot, we're done. */ | |
1888 if (ds->ds_phys->ds_prev_snap_obj == 0) | |
1889 break; | |
1890 | |
1891 if (err = bplist_space(&ds->ds_deadlist, | |
1892 &dlused, &dlcomp, &dluncomp)) | |
1893 goto out; | |
1894 if (err = dsl_dataset_open_obj(dd->dd_pool, | |
1895 ds->ds_phys->ds_prev_snap_obj, NULL, DS_MODE_EXCLUSIVE, | |
1896 FTAG, &prev)) | |
1897 goto out; | |
2199 | 1898 pa->used += dlused - prev->ds_phys->ds_used_bytes; |
1899 pa->comp += dlcomp - prev->ds_phys->ds_compressed_bytes; | |
1900 pa->uncomp += dluncomp - prev->ds_phys->ds_uncompressed_bytes; | |
2082 | 1901 |
1902 /* | |
1903 * We could be a clone of a clone. If we reach our | |
1904 * parent's branch point, we're done. | |
1905 */ | |
1906 if (prev->ds_phys->ds_next_snap_obj != ds->ds_object) { | |
1907 dsl_dataset_close(prev, DS_MODE_EXCLUSIVE, FTAG); | |
1908 break; | |
1909 } | |
1910 if (ds != pivot_ds) | |
1911 dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); | |
1912 ds = prev; | |
1913 } | |
1914 | |
1915 /* Check that there is enough space here */ | |
2199 | 1916 err = dsl_dir_transfer_possible(pdd, dd, pa->used); |
1917 | |
1918 out: | |
1919 if (ds && ds != pivot_ds) | |
1920 dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); | |
1921 if (pivot_ds) | |
1922 dsl_dataset_close(pivot_ds, DS_MODE_EXCLUSIVE, FTAG); | |
1923 if (newnext_ds) | |
1924 dsl_dataset_close(newnext_ds, DS_MODE_NONE, FTAG); | |
1925 if (name) | |
1926 kmem_free(name, MAXPATHLEN); | |
1927 return (err); | |
1928 } | |
2082 | 1929 |
2199 | 1930 static void |
4543 | 1931 dsl_dataset_promote_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) |
2199 | 1932 { |
1933 dsl_dataset_t *hds = arg1; | |
1934 struct promotearg *pa = arg2; | |
1935 dsl_dir_t *dd = hds->ds_dir; | |
1936 dsl_pool_t *dp = hds->ds_dir->dd_pool; | |
1937 dsl_dir_t *pdd = NULL; | |
1938 dsl_dataset_t *ds, *pivot_ds; | |
1939 char *name; | |
1940 | |
1941 ASSERT(dd->dd_phys->dd_clone_parent_obj != 0); | |
1942 ASSERT(0 == (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE)); | |
1943 | |
1944 VERIFY(0 == dsl_dataset_open_obj(dp, | |
1945 dd->dd_phys->dd_clone_parent_obj, | |
1946 NULL, DS_MODE_EXCLUSIVE, FTAG, &pivot_ds)); | |
2417 | 1947 /* |
1948 * We need to explicitly open pdd, since pivot_ds's pdd will be | |
1949 * changing. | |
1950 */ | |
1951 VERIFY(0 == dsl_dir_open_obj(dp, pivot_ds->ds_dir->dd_object, | |
1952 NULL, FTAG, &pdd)); | |
2082 | 1953 |
1954 /* move snapshots to this dir */ | |
2199 | 1955 name = kmem_alloc(MAXPATHLEN, KM_SLEEP); |
2082 | 1956 ds = pivot_ds; |
1957 /* CONSTCOND */ | |
1958 while (TRUE) { | |
1959 dsl_dataset_t *prev; | |
1960 | |
1961 /* move snap name entry */ | |
1962 dsl_dataset_name(ds, name); | |
2199 | 1963 VERIFY(0 == zap_remove(dp->dp_meta_objset, |
1964 pa->snapnames_obj, ds->ds_snapname, tx)); | |
1965 VERIFY(0 == zap_add(dp->dp_meta_objset, | |
2082 | 1966 hds->ds_phys->ds_snapnames_zapobj, ds->ds_snapname, |
1967 8, 1, &ds->ds_object, tx)); | |
1968 | |
1969 /* change containing dsl_dir */ | |
1970 dmu_buf_will_dirty(ds->ds_dbuf, tx); | |
1971 ASSERT3U(ds->ds_phys->ds_dir_obj, ==, pdd->dd_object); | |
1972 ds->ds_phys->ds_dir_obj = dd->dd_object; | |
1973 ASSERT3P(ds->ds_dir, ==, pdd); | |
1974 dsl_dir_close(ds->ds_dir, ds); | |
2199 | 1975 VERIFY(0 == dsl_dir_open_obj(dp, dd->dd_object, |
2082 | 1976 NULL, ds, &ds->ds_dir)); |
1977 | |
1978 ASSERT3U(dsl_prop_numcb(ds), ==, 0); | |
1979 | |
1980 if (ds->ds_phys->ds_prev_snap_obj == 0) | |
1981 break; | |
1982 | |
2199 | 1983 VERIFY(0 == dsl_dataset_open_obj(dp, |
2082 | 1984 ds->ds_phys->ds_prev_snap_obj, NULL, DS_MODE_EXCLUSIVE, |
1985 FTAG, &prev)); | |
1986 | |
1987 if (prev->ds_phys->ds_next_snap_obj != ds->ds_object) { | |
1988 dsl_dataset_close(prev, DS_MODE_EXCLUSIVE, FTAG); | |
1989 break; | |
1990 } | |
1991 if (ds != pivot_ds) | |
1992 dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); | |
1993 ds = prev; | |
1994 } | |
2199 | 1995 if (ds != pivot_ds) |
1996 dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); | |
2082 | 1997 |
1998 /* change pivot point's next snap */ | |
1999 dmu_buf_will_dirty(pivot_ds->ds_dbuf, tx); | |
2199 | 2000 pivot_ds->ds_phys->ds_next_snap_obj = pa->newnext_obj; |
2082 | 2001 |
2002 /* change clone_parent-age */ | |
2003 dmu_buf_will_dirty(dd->dd_dbuf, tx); | |
2004 ASSERT3U(dd->dd_phys->dd_clone_parent_obj, ==, pivot_ds->ds_object); | |
2005 dd->dd_phys->dd_clone_parent_obj = pdd->dd_phys->dd_clone_parent_obj; | |
2006 dmu_buf_will_dirty(pdd->dd_dbuf, tx); | |
2007 pdd->dd_phys->dd_clone_parent_obj = pivot_ds->ds_object; | |
2008 | |
2009 /* change space accounting */ | |
2199 | 2010 dsl_dir_diduse_space(pdd, -pa->used, -pa->comp, -pa->uncomp, tx); |
2011 dsl_dir_diduse_space(dd, pa->used, pa->comp, pa->uncomp, tx); | |
2012 pivot_ds->ds_phys->ds_unique_bytes = pa->unique; | |
2082 | 2013 |
4543 | 2014 /* log history record */ |
2015 spa_history_internal_log(LOG_DS_PROMOTE, dd->dd_pool->dp_spa, tx, | |
2016 cr, "dataset = %llu", ds->ds_object); | |
2017 | |
2417 | 2018 dsl_dir_close(pdd, FTAG); |
2199 | 2019 dsl_dataset_close(pivot_ds, DS_MODE_EXCLUSIVE, FTAG); |
2020 kmem_free(name, MAXPATHLEN); | |
2082 | 2021 } |
2022 | |
2023 int | |
2024 dsl_dataset_promote(const char *name) | |
2025 { | |
2026 dsl_dataset_t *ds; | |
2027 int err; | |
2028 dmu_object_info_t doi; | |
2199 | 2029 struct promotearg pa; |
2082 | 2030 |
2031 err = dsl_dataset_open(name, DS_MODE_NONE, FTAG, &ds); | |
2032 if (err) | |
2033 return (err); | |
2034 | |
2035 err = dmu_object_info(ds->ds_dir->dd_pool->dp_meta_objset, | |
2036 ds->ds_phys->ds_snapnames_zapobj, &doi); | |
2037 if (err) { | |
2038 dsl_dataset_close(ds, DS_MODE_NONE, FTAG); | |
2039 return (err); | |
2040 } | |
2041 | |
2042 /* | |
2043 * Add in 128x the snapnames zapobj size, since we will be moving | |
2044 * a bunch of snapnames to the promoted ds, and dirtying their | |
2045 * bonus buffers. | |
2046 */ | |
2199 | 2047 err = dsl_sync_task_do(ds->ds_dir->dd_pool, |
2048 dsl_dataset_promote_check, | |
2049 dsl_dataset_promote_sync, ds, &pa, 2 + 2 * doi.doi_physical_blks); | |
2082 | 2050 dsl_dataset_close(ds, DS_MODE_NONE, FTAG); |
2051 return (err); | |
2052 } | |
3912 | 2053 |
2054 /* | |
2055 * Given a pool name and a dataset object number in that pool, | |
2056 * return the name of that dataset. | |
2057 */ | |
2058 int | |
2059 dsl_dsobj_to_dsname(char *pname, uint64_t obj, char *buf) | |
2060 { | |
2061 spa_t *spa; | |
2062 dsl_pool_t *dp; | |
2063 dsl_dataset_t *ds = NULL; | |
2064 int error; | |
2065 | |
2066 if ((error = spa_open(pname, &spa, FTAG)) != 0) | |
2067 return (error); | |
2068 dp = spa_get_dsl(spa); | |
2069 rw_enter(&dp->dp_config_rwlock, RW_READER); | |
2070 if ((error = dsl_dataset_open_obj(dp, obj, | |
2071 NULL, DS_MODE_NONE, FTAG, &ds)) != 0) { | |
2072 rw_exit(&dp->dp_config_rwlock); | |
2073 spa_close(spa, FTAG); | |
2074 return (error); | |
2075 } | |
2076 dsl_dataset_name(ds, buf); | |
2077 dsl_dataset_close(ds, DS_MODE_NONE, FTAG); | |
2078 rw_exit(&dp->dp_config_rwlock); | |
2079 spa_close(spa, FTAG); | |
2080 | |
2081 return (0); | |
2082 } |