Mercurial > illumos > illumos-gate
annotate usr/src/uts/common/fs/zfs/dsl_dataset.c @ 4967:8d0de61ff354
6597381 BAD TRAP: type=e (#pf Page fault) rp=ffffff00043a48f0 addr=28 occurred in module "<unknown>" due to
author | perrin |
---|---|
date | Thu, 30 Aug 2007 15:15:28 -0700 |
parents | c80bf0e6f4aa |
children | 71a3e95fb9e2 |
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 | |
3912 | 1327 spa_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 } |