4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
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.
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]
22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 2013 by Delphix. All rights reserved.
24 * Copyright (c) 2013 Steven Hartland. All rights reserved.
27 #include <sys/zfs_context.h>
28 #include <sys/dsl_userhold.h>
29 #include <sys/dsl_dataset.h>
30 #include <sys/dsl_destroy.h>
31 #include <sys/dsl_synctask.h>
32 #include <sys/dmu_tx.h>
33 #include <sys/zfs_onexit.h>
34 #include <sys/dsl_pool.h>
35 #include <sys/dsl_dir.h>
36 #include <sys/zfs_ioctl.h>
39 typedef struct dsl_dataset_user_hold_arg
{
40 nvlist_t
*dduha_holds
;
41 nvlist_t
*dduha_chkholds
;
42 nvlist_t
*dduha_errlist
;
44 } dsl_dataset_user_hold_arg_t
;
47 * If you add new checks here, you may need to add additional checks to the
48 * "temporary" case in snapshot_check() in dmu_objset.c.
51 dsl_dataset_user_hold_check_one(dsl_dataset_t
*ds
, const char *htag
,
52 boolean_t temphold
, dmu_tx_t
*tx
)
54 dsl_pool_t
*dp
= dmu_tx_pool(tx
);
55 objset_t
*mos
= dp
->dp_meta_objset
;
58 ASSERT(dsl_pool_config_held(dp
));
60 if (strlen(htag
) > MAXNAMELEN
)
61 return (SET_ERROR(E2BIG
));
62 /* Tempholds have a more restricted length */
63 if (temphold
&& strlen(htag
) + MAX_TAG_PREFIX_LEN
>= MAXNAMELEN
)
64 return (SET_ERROR(E2BIG
));
66 /* tags must be unique (if ds already exists) */
67 if (ds
!= NULL
&& ds
->ds_phys
->ds_userrefs_obj
!= 0) {
70 error
= zap_lookup(mos
, ds
->ds_phys
->ds_userrefs_obj
,
73 error
= SET_ERROR(EEXIST
);
74 else if (error
== ENOENT
)
82 dsl_dataset_user_hold_check(void *arg
, dmu_tx_t
*tx
)
84 dsl_dataset_user_hold_arg_t
*dduha
= arg
;
85 dsl_pool_t
*dp
= dmu_tx_pool(tx
);
87 if (spa_version(dp
->dp_spa
) < SPA_VERSION_USERREFS
)
88 return (SET_ERROR(ENOTSUP
));
90 if (!dmu_tx_is_syncing(tx
))
93 for (nvpair_t
*pair
= nvlist_next_nvpair(dduha
->dduha_holds
, NULL
);
94 pair
!= NULL
; pair
= nvlist_next_nvpair(dduha
->dduha_holds
, pair
)) {
99 /* must be a snapshot */
100 name
= nvpair_name(pair
);
101 if (strchr(name
, '@') == NULL
)
102 error
= SET_ERROR(EINVAL
);
105 error
= nvpair_value_string(pair
, &htag
);
108 error
= dsl_dataset_hold(dp
, name
, FTAG
, &ds
);
111 error
= dsl_dataset_user_hold_check_one(ds
, htag
,
112 dduha
->dduha_minor
!= 0, tx
);
113 dsl_dataset_rele(ds
, FTAG
);
117 fnvlist_add_string(dduha
->dduha_chkholds
, name
, htag
);
120 * We register ENOENT errors so they can be correctly
121 * reported if needed, such as when all holds fail.
123 fnvlist_add_int32(dduha
->dduha_errlist
, name
, error
);
134 dsl_dataset_user_hold_sync_one_impl(nvlist_t
*tmpholds
, dsl_dataset_t
*ds
,
135 const char *htag
, minor_t minor
, uint64_t now
, dmu_tx_t
*tx
)
137 dsl_pool_t
*dp
= ds
->ds_dir
->dd_pool
;
138 objset_t
*mos
= dp
->dp_meta_objset
;
141 ASSERT(RRW_WRITE_HELD(&dp
->dp_config_rwlock
));
143 if (ds
->ds_phys
->ds_userrefs_obj
== 0) {
145 * This is the first user hold for this dataset. Create
146 * the userrefs zap object.
148 dmu_buf_will_dirty(ds
->ds_dbuf
, tx
);
149 zapobj
= ds
->ds_phys
->ds_userrefs_obj
=
150 zap_create(mos
, DMU_OT_USERREFS
, DMU_OT_NONE
, 0, tx
);
152 zapobj
= ds
->ds_phys
->ds_userrefs_obj
;
156 VERIFY0(zap_add(mos
, zapobj
, htag
, 8, 1, &now
, tx
));
159 char name
[MAXNAMELEN
];
162 VERIFY0(dsl_pool_user_hold(dp
, ds
->ds_object
,
164 (void) snprintf(name
, sizeof (name
), "%llx",
165 (u_longlong_t
)ds
->ds_object
);
167 if (nvlist_lookup_nvlist(tmpholds
, name
, &tags
) != 0) {
168 tags
= fnvlist_alloc();
169 fnvlist_add_boolean(tags
, htag
);
170 fnvlist_add_nvlist(tmpholds
, name
, tags
);
173 fnvlist_add_boolean(tags
, htag
);
177 spa_history_log_internal_ds(ds
, "hold", tx
,
178 "tag=%s temp=%d refs=%llu",
179 htag
, minor
!= 0, ds
->ds_userrefs
);
182 typedef struct zfs_hold_cleanup_arg
{
183 char zhca_spaname
[MAXNAMELEN
];
184 uint64_t zhca_spa_load_guid
;
185 nvlist_t
*zhca_holds
;
186 } zfs_hold_cleanup_arg_t
;
189 dsl_dataset_user_release_onexit(void *arg
)
191 zfs_hold_cleanup_arg_t
*ca
= arg
;
195 error
= spa_open(ca
->zhca_spaname
, &spa
, FTAG
);
197 zfs_dbgmsg("couldn't release holds on pool=%s "
198 "because pool is no longer loaded",
202 if (spa_load_guid(spa
) != ca
->zhca_spa_load_guid
) {
203 zfs_dbgmsg("couldn't release holds on pool=%s "
204 "because pool is no longer loaded (guid doesn't match)",
206 spa_close(spa
, FTAG
);
210 (void) dsl_dataset_user_release_tmp(spa_get_dsl(spa
), ca
->zhca_holds
);
211 fnvlist_free(ca
->zhca_holds
);
212 kmem_free(ca
, sizeof (zfs_hold_cleanup_arg_t
));
213 spa_close(spa
, FTAG
);
217 dsl_onexit_hold_cleanup(spa_t
*spa
, nvlist_t
*holds
, minor_t minor
)
219 zfs_hold_cleanup_arg_t
*ca
;
221 if (minor
== 0 || nvlist_empty(holds
)) {
227 ca
= kmem_alloc(sizeof (*ca
), KM_SLEEP
);
229 (void) strlcpy(ca
->zhca_spaname
, spa_name(spa
),
230 sizeof (ca
->zhca_spaname
));
231 ca
->zhca_spa_load_guid
= spa_load_guid(spa
);
232 ca
->zhca_holds
= holds
;
233 VERIFY0(zfs_onexit_add_cb(minor
,
234 dsl_dataset_user_release_onexit
, ca
, NULL
));
238 dsl_dataset_user_hold_sync_one(dsl_dataset_t
*ds
, const char *htag
,
239 minor_t minor
, uint64_t now
, dmu_tx_t
*tx
)
244 tmpholds
= fnvlist_alloc();
247 dsl_dataset_user_hold_sync_one_impl(tmpholds
, ds
, htag
, minor
, now
, tx
);
248 dsl_onexit_hold_cleanup(dsl_dataset_get_spa(ds
), tmpholds
, minor
);
252 dsl_dataset_user_hold_sync(void *arg
, dmu_tx_t
*tx
)
254 dsl_dataset_user_hold_arg_t
*dduha
= arg
;
255 dsl_pool_t
*dp
= dmu_tx_pool(tx
);
257 uint64_t now
= gethrestime_sec();
259 if (dduha
->dduha_minor
!= 0)
260 tmpholds
= fnvlist_alloc();
263 for (nvpair_t
*pair
= nvlist_next_nvpair(dduha
->dduha_chkholds
, NULL
);
265 pair
= nvlist_next_nvpair(dduha
->dduha_chkholds
, pair
)) {
268 VERIFY0(dsl_dataset_hold(dp
, nvpair_name(pair
), FTAG
, &ds
));
269 dsl_dataset_user_hold_sync_one_impl(tmpholds
, ds
,
270 fnvpair_value_string(pair
), dduha
->dduha_minor
, now
, tx
);
271 dsl_dataset_rele(ds
, FTAG
);
273 dsl_onexit_hold_cleanup(dp
->dp_spa
, tmpholds
, dduha
->dduha_minor
);
277 * The full semantics of this function are described in the comment above
281 * holds is nvl of snapname -> holdname
282 * errlist will be filled in with snapname -> error
284 * The snaphosts must all be in the same pool.
286 * Holds for snapshots that don't exist will be skipped.
288 * If none of the snapshots for requested holds exist then ENOENT will be
291 * If cleanup_minor is not 0, the holds will be temporary, which will be cleaned
292 * up when the process exits.
294 * On success all the holds, for snapshots that existed, will be created and 0
297 * On failure no holds will be created, the errlist will be filled in,
298 * and an errno will returned.
300 * In all cases the errlist will contain entries for holds where the snapshot
304 dsl_dataset_user_hold(nvlist_t
*holds
, minor_t cleanup_minor
, nvlist_t
*errlist
)
306 dsl_dataset_user_hold_arg_t dduha
;
310 pair
= nvlist_next_nvpair(holds
, NULL
);
314 dduha
.dduha_holds
= holds
;
315 dduha
.dduha_chkholds
= fnvlist_alloc();
316 dduha
.dduha_errlist
= errlist
;
317 dduha
.dduha_minor
= cleanup_minor
;
319 ret
= dsl_sync_task(nvpair_name(pair
), dsl_dataset_user_hold_check
,
320 dsl_dataset_user_hold_sync
, &dduha
, fnvlist_num_pairs(holds
));
321 fnvlist_free(dduha
.dduha_chkholds
);
326 typedef int (dsl_holdfunc_t
)(dsl_pool_t
*dp
, const char *name
, void *tag
,
327 dsl_dataset_t
**dsp
);
329 typedef struct dsl_dataset_user_release_arg
{
330 dsl_holdfunc_t
*ddura_holdfunc
;
331 nvlist_t
*ddura_holds
;
332 nvlist_t
*ddura_todelete
;
333 nvlist_t
*ddura_errlist
;
334 nvlist_t
*ddura_chkholds
;
335 } dsl_dataset_user_release_arg_t
;
337 /* Place a dataset hold on the snapshot identified by passed dsobj string */
339 dsl_dataset_hold_obj_string(dsl_pool_t
*dp
, const char *dsobj
, void *tag
,
342 return (dsl_dataset_hold_obj(dp
, strtonum(dsobj
, NULL
), tag
, dsp
));
346 dsl_dataset_user_release_check_one(dsl_dataset_user_release_arg_t
*ddura
,
347 dsl_dataset_t
*ds
, nvlist_t
*holds
, const char *snapname
)
350 nvlist_t
*holds_found
;
354 if (!dsl_dataset_is_snapshot(ds
))
355 return (SET_ERROR(EINVAL
));
357 if (nvlist_empty(holds
))
361 mos
= ds
->ds_dir
->dd_pool
->dp_meta_objset
;
362 zapobj
= ds
->ds_phys
->ds_userrefs_obj
;
363 holds_found
= fnvlist_alloc();
365 for (nvpair_t
*pair
= nvlist_next_nvpair(holds
, NULL
); pair
!= NULL
;
366 pair
= nvlist_next_nvpair(holds
, pair
)) {
369 const char *holdname
= nvpair_name(pair
);
372 error
= zap_lookup(mos
, zapobj
, holdname
, 8, 1, &tmp
);
374 error
= SET_ERROR(ENOENT
);
377 * Non-existent holds are put on the errlist, but don't
378 * cause an overall failure.
380 if (error
== ENOENT
) {
381 if (ddura
->ddura_errlist
!= NULL
) {
382 char *errtag
= kmem_asprintf("%s#%s",
384 fnvlist_add_int32(ddura
->ddura_errlist
, errtag
,
392 fnvlist_free(holds_found
);
396 fnvlist_add_boolean(holds_found
, holdname
);
400 if (DS_IS_DEFER_DESTROY(ds
) && ds
->ds_phys
->ds_num_children
== 1 &&
401 ds
->ds_userrefs
== numholds
) {
402 /* we need to destroy the snapshot as well */
403 if (dsl_dataset_long_held(ds
)) {
404 fnvlist_free(holds_found
);
405 return (SET_ERROR(EBUSY
));
407 fnvlist_add_boolean(ddura
->ddura_todelete
, snapname
);
411 fnvlist_add_nvlist(ddura
->ddura_chkholds
, snapname
,
414 fnvlist_free(holds_found
);
420 dsl_dataset_user_release_check(void *arg
, dmu_tx_t
*tx
)
422 dsl_dataset_user_release_arg_t
*ddura
;
423 dsl_holdfunc_t
*holdfunc
;
426 if (!dmu_tx_is_syncing(tx
))
429 dp
= dmu_tx_pool(tx
);
431 ASSERT(RRW_WRITE_HELD(&dp
->dp_config_rwlock
));
434 holdfunc
= ddura
->ddura_holdfunc
;
436 for (nvpair_t
*pair
= nvlist_next_nvpair(ddura
->ddura_holds
, NULL
);
437 pair
!= NULL
; pair
= nvlist_next_nvpair(ddura
->ddura_holds
, pair
)) {
441 const char *snapname
= nvpair_name(pair
);
443 error
= nvpair_value_nvlist(pair
, &holds
);
445 error
= (SET_ERROR(EINVAL
));
447 error
= holdfunc(dp
, snapname
, FTAG
, &ds
);
449 error
= dsl_dataset_user_release_check_one(ddura
, ds
,
451 dsl_dataset_rele(ds
, FTAG
);
454 if (ddura
->ddura_errlist
!= NULL
) {
455 fnvlist_add_int32(ddura
->ddura_errlist
,
459 * Non-existent snapshots are put on the errlist,
460 * but don't cause an overall failure.
471 dsl_dataset_user_release_sync_one(dsl_dataset_t
*ds
, nvlist_t
*holds
,
474 dsl_pool_t
*dp
= ds
->ds_dir
->dd_pool
;
475 objset_t
*mos
= dp
->dp_meta_objset
;
477 for (nvpair_t
*pair
= nvlist_next_nvpair(holds
, NULL
); pair
!= NULL
;
478 pair
= nvlist_next_nvpair(holds
, pair
)) {
480 const char *holdname
= nvpair_name(pair
);
482 /* Remove temporary hold if one exists. */
483 error
= dsl_pool_user_release(dp
, ds
->ds_object
, holdname
, tx
);
484 VERIFY(error
== 0 || error
== ENOENT
);
486 VERIFY0(zap_remove(mos
, ds
->ds_phys
->ds_userrefs_obj
, holdname
,
490 spa_history_log_internal_ds(ds
, "release", tx
,
491 "tag=%s refs=%lld", holdname
, (longlong_t
)ds
->ds_userrefs
);
496 dsl_dataset_user_release_sync(void *arg
, dmu_tx_t
*tx
)
498 dsl_dataset_user_release_arg_t
*ddura
= arg
;
499 dsl_holdfunc_t
*holdfunc
= ddura
->ddura_holdfunc
;
500 dsl_pool_t
*dp
= dmu_tx_pool(tx
);
502 ASSERT(RRW_WRITE_HELD(&dp
->dp_config_rwlock
));
504 for (nvpair_t
*pair
= nvlist_next_nvpair(ddura
->ddura_chkholds
, NULL
);
505 pair
!= NULL
; pair
= nvlist_next_nvpair(ddura
->ddura_chkholds
,
508 const char *name
= nvpair_name(pair
);
510 VERIFY0(holdfunc(dp
, name
, FTAG
, &ds
));
512 dsl_dataset_user_release_sync_one(ds
,
513 fnvpair_value_nvlist(pair
), tx
);
514 if (nvlist_exists(ddura
->ddura_todelete
, name
)) {
515 ASSERT(ds
->ds_userrefs
== 0 &&
516 ds
->ds_phys
->ds_num_children
== 1 &&
517 DS_IS_DEFER_DESTROY(ds
));
518 dsl_destroy_snapshot_sync_impl(ds
, B_FALSE
, tx
);
520 dsl_dataset_rele(ds
, FTAG
);
525 * The full semantics of this function are described in the comment above
529 * Releases holds specified in the nvl holds.
531 * holds is nvl of snapname -> { holdname, ... }
532 * errlist will be filled in with snapname -> error
534 * If tmpdp is not NULL the names for holds should be the dsobj's of snapshots,
535 * otherwise they should be the names of shapshots.
537 * As a release may cause snapshots to be destroyed this trys to ensure they
540 * The release of non-existent holds are skipped.
542 * At least one hold must have been released for the this function to succeed
546 dsl_dataset_user_release_impl(nvlist_t
*holds
, nvlist_t
*errlist
,
549 dsl_dataset_user_release_arg_t ddura
;
554 pair
= nvlist_next_nvpair(holds
, NULL
);
559 * The release may cause snapshots to be destroyed; make sure they
563 /* Temporary holds are specified by dsobj string. */
564 ddura
.ddura_holdfunc
= dsl_dataset_hold_obj_string
;
565 pool
= spa_name(tmpdp
->dp_spa
);
567 for (pair
= nvlist_next_nvpair(holds
, NULL
); pair
!= NULL
;
568 pair
= nvlist_next_nvpair(holds
, pair
)) {
571 dsl_pool_config_enter(tmpdp
, FTAG
);
572 error
= dsl_dataset_hold_obj_string(tmpdp
,
573 nvpair_name(pair
), FTAG
, &ds
);
575 char name
[MAXNAMELEN
];
576 dsl_dataset_name(ds
, name
);
577 dsl_pool_config_exit(tmpdp
, FTAG
);
578 dsl_dataset_rele(ds
, FTAG
);
579 (void) zfs_unmount_snap(name
);
581 dsl_pool_config_exit(tmpdp
, FTAG
);
586 /* Non-temporary holds are specified by name. */
587 ddura
.ddura_holdfunc
= dsl_dataset_hold
;
588 pool
= nvpair_name(pair
);
590 for (pair
= nvlist_next_nvpair(holds
, NULL
); pair
!= NULL
;
591 pair
= nvlist_next_nvpair(holds
, pair
)) {
592 (void) zfs_unmount_snap(nvpair_name(pair
));
597 ddura
.ddura_holds
= holds
;
598 ddura
.ddura_errlist
= errlist
;
599 ddura
.ddura_todelete
= fnvlist_alloc();
600 ddura
.ddura_chkholds
= fnvlist_alloc();
602 error
= dsl_sync_task(pool
, dsl_dataset_user_release_check
,
603 dsl_dataset_user_release_sync
, &ddura
, 0);
604 fnvlist_free(ddura
.ddura_todelete
);
605 fnvlist_free(ddura
.ddura_chkholds
);
611 * holds is nvl of snapname -> { holdname, ... }
612 * errlist will be filled in with snapname -> error
615 dsl_dataset_user_release(nvlist_t
*holds
, nvlist_t
*errlist
)
617 return (dsl_dataset_user_release_impl(holds
, errlist
, NULL
));
621 * holds is nvl of snapdsobj -> { holdname, ... }
624 dsl_dataset_user_release_tmp(struct dsl_pool
*dp
, nvlist_t
*holds
)
627 (void) dsl_dataset_user_release_impl(holds
, NULL
, dp
);
631 dsl_dataset_get_holds(const char *dsname
, nvlist_t
*nvl
)
637 err
= dsl_pool_hold(dsname
, FTAG
, &dp
);
640 err
= dsl_dataset_hold(dp
, dsname
, FTAG
, &ds
);
642 dsl_pool_rele(dp
, FTAG
);
646 if (ds
->ds_phys
->ds_userrefs_obj
!= 0) {
650 za
= kmem_alloc(sizeof (zap_attribute_t
), KM_SLEEP
);
651 for (zap_cursor_init(&zc
, ds
->ds_dir
->dd_pool
->dp_meta_objset
,
652 ds
->ds_phys
->ds_userrefs_obj
);
653 zap_cursor_retrieve(&zc
, za
) == 0;
654 zap_cursor_advance(&zc
)) {
655 fnvlist_add_uint64(nvl
, za
->za_name
,
656 za
->za_first_integer
);
658 zap_cursor_fini(&zc
);
659 kmem_free(za
, sizeof (zap_attribute_t
));
661 dsl_dataset_rele(ds
, FTAG
);
662 dsl_pool_rele(dp
, FTAG
);