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) 2012, 2015 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
&& dsl_dataset_phys(ds
)->ds_userrefs_obj
!= 0) {
70 error
= zap_lookup(mos
, dsl_dataset_phys(ds
)->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 (dsl_dataset_phys(ds
)->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
= dsl_dataset_phys(ds
)->ds_userrefs_obj
=
150 zap_create(mos
, DMU_OT_USERREFS
, DMU_OT_NONE
, 0, tx
);
152 zapobj
= dsl_dataset_phys(ds
)->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
[ZFS_MAX_DATASET_NAME_LEN
];
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
,
321 fnvlist_num_pairs(holds
), ZFS_SPACE_CHECK_RESERVED
);
322 fnvlist_free(dduha
.dduha_chkholds
);
327 typedef int (dsl_holdfunc_t
)(dsl_pool_t
*dp
, const char *name
, void *tag
,
328 dsl_dataset_t
**dsp
);
330 typedef struct dsl_dataset_user_release_arg
{
331 dsl_holdfunc_t
*ddura_holdfunc
;
332 nvlist_t
*ddura_holds
;
333 nvlist_t
*ddura_todelete
;
334 nvlist_t
*ddura_errlist
;
335 nvlist_t
*ddura_chkholds
;
336 } dsl_dataset_user_release_arg_t
;
338 /* Place a dataset hold on the snapshot identified by passed dsobj string */
340 dsl_dataset_hold_obj_string(dsl_pool_t
*dp
, const char *dsobj
, void *tag
,
343 return (dsl_dataset_hold_obj(dp
, zfs_strtonum(dsobj
, NULL
), tag
, dsp
));
347 dsl_dataset_user_release_check_one(dsl_dataset_user_release_arg_t
*ddura
,
348 dsl_dataset_t
*ds
, nvlist_t
*holds
, const char *snapname
)
351 nvlist_t
*holds_found
;
355 if (!ds
->ds_is_snapshot
)
356 return (SET_ERROR(EINVAL
));
358 if (nvlist_empty(holds
))
362 mos
= ds
->ds_dir
->dd_pool
->dp_meta_objset
;
363 zapobj
= dsl_dataset_phys(ds
)->ds_userrefs_obj
;
364 holds_found
= fnvlist_alloc();
366 for (nvpair_t
*pair
= nvlist_next_nvpair(holds
, NULL
); pair
!= NULL
;
367 pair
= nvlist_next_nvpair(holds
, pair
)) {
370 const char *holdname
= nvpair_name(pair
);
373 error
= zap_lookup(mos
, zapobj
, holdname
, 8, 1, &tmp
);
375 error
= SET_ERROR(ENOENT
);
378 * Non-existent holds are put on the errlist, but don't
379 * cause an overall failure.
381 if (error
== ENOENT
) {
382 if (ddura
->ddura_errlist
!= NULL
) {
383 char *errtag
= kmem_asprintf("%s#%s",
385 fnvlist_add_int32(ddura
->ddura_errlist
, errtag
,
393 fnvlist_free(holds_found
);
397 fnvlist_add_boolean(holds_found
, holdname
);
401 if (DS_IS_DEFER_DESTROY(ds
) &&
402 dsl_dataset_phys(ds
)->ds_num_children
== 1 &&
403 ds
->ds_userrefs
== numholds
) {
404 /* we need to destroy the snapshot as well */
405 if (dsl_dataset_long_held(ds
)) {
406 fnvlist_free(holds_found
);
407 return (SET_ERROR(EBUSY
));
409 fnvlist_add_boolean(ddura
->ddura_todelete
, snapname
);
413 fnvlist_add_nvlist(ddura
->ddura_chkholds
, snapname
,
416 fnvlist_free(holds_found
);
422 dsl_dataset_user_release_check(void *arg
, dmu_tx_t
*tx
)
424 dsl_dataset_user_release_arg_t
*ddura
;
425 dsl_holdfunc_t
*holdfunc
;
428 if (!dmu_tx_is_syncing(tx
))
431 dp
= dmu_tx_pool(tx
);
433 ASSERT(RRW_WRITE_HELD(&dp
->dp_config_rwlock
));
436 holdfunc
= ddura
->ddura_holdfunc
;
438 for (nvpair_t
*pair
= nvlist_next_nvpair(ddura
->ddura_holds
, NULL
);
439 pair
!= NULL
; pair
= nvlist_next_nvpair(ddura
->ddura_holds
, pair
)) {
443 const char *snapname
= nvpair_name(pair
);
445 error
= nvpair_value_nvlist(pair
, &holds
);
447 error
= (SET_ERROR(EINVAL
));
449 error
= holdfunc(dp
, snapname
, FTAG
, &ds
);
451 error
= dsl_dataset_user_release_check_one(ddura
, ds
,
453 dsl_dataset_rele(ds
, FTAG
);
456 if (ddura
->ddura_errlist
!= NULL
) {
457 fnvlist_add_int32(ddura
->ddura_errlist
,
461 * Non-existent snapshots are put on the errlist,
462 * but don't cause an overall failure.
473 dsl_dataset_user_release_sync_one(dsl_dataset_t
*ds
, nvlist_t
*holds
,
476 dsl_pool_t
*dp
= ds
->ds_dir
->dd_pool
;
477 objset_t
*mos
= dp
->dp_meta_objset
;
479 for (nvpair_t
*pair
= nvlist_next_nvpair(holds
, NULL
); pair
!= NULL
;
480 pair
= nvlist_next_nvpair(holds
, pair
)) {
482 const char *holdname
= nvpair_name(pair
);
484 /* Remove temporary hold if one exists. */
485 error
= dsl_pool_user_release(dp
, ds
->ds_object
, holdname
, tx
);
486 VERIFY(error
== 0 || error
== ENOENT
);
488 VERIFY0(zap_remove(mos
, dsl_dataset_phys(ds
)->ds_userrefs_obj
,
492 spa_history_log_internal_ds(ds
, "release", tx
,
493 "tag=%s refs=%lld", holdname
, (longlong_t
)ds
->ds_userrefs
);
498 dsl_dataset_user_release_sync(void *arg
, dmu_tx_t
*tx
)
500 dsl_dataset_user_release_arg_t
*ddura
= arg
;
501 dsl_holdfunc_t
*holdfunc
= ddura
->ddura_holdfunc
;
502 dsl_pool_t
*dp
= dmu_tx_pool(tx
);
504 ASSERT(RRW_WRITE_HELD(&dp
->dp_config_rwlock
));
506 for (nvpair_t
*pair
= nvlist_next_nvpair(ddura
->ddura_chkholds
, NULL
);
507 pair
!= NULL
; pair
= nvlist_next_nvpair(ddura
->ddura_chkholds
,
510 const char *name
= nvpair_name(pair
);
512 VERIFY0(holdfunc(dp
, name
, FTAG
, &ds
));
514 dsl_dataset_user_release_sync_one(ds
,
515 fnvpair_value_nvlist(pair
), tx
);
516 if (nvlist_exists(ddura
->ddura_todelete
, name
)) {
517 ASSERT(ds
->ds_userrefs
== 0 &&
518 dsl_dataset_phys(ds
)->ds_num_children
== 1 &&
519 DS_IS_DEFER_DESTROY(ds
));
520 dsl_destroy_snapshot_sync_impl(ds
, B_FALSE
, tx
);
522 dsl_dataset_rele(ds
, FTAG
);
527 * The full semantics of this function are described in the comment above
531 * Releases holds specified in the nvl holds.
533 * holds is nvl of snapname -> { holdname, ... }
534 * errlist will be filled in with snapname -> error
536 * If tmpdp is not NULL the names for holds should be the dsobj's of snapshots,
537 * otherwise they should be the names of shapshots.
539 * As a release may cause snapshots to be destroyed this trys to ensure they
542 * The release of non-existent holds are skipped.
544 * At least one hold must have been released for the this function to succeed
548 dsl_dataset_user_release_impl(nvlist_t
*holds
, nvlist_t
*errlist
,
551 dsl_dataset_user_release_arg_t ddura
;
556 pair
= nvlist_next_nvpair(holds
, NULL
);
561 * The release may cause snapshots to be destroyed; make sure they
565 /* Temporary holds are specified by dsobj string. */
566 ddura
.ddura_holdfunc
= dsl_dataset_hold_obj_string
;
567 pool
= spa_name(tmpdp
->dp_spa
);
569 for (pair
= nvlist_next_nvpair(holds
, NULL
); pair
!= NULL
;
570 pair
= nvlist_next_nvpair(holds
, pair
)) {
573 dsl_pool_config_enter(tmpdp
, FTAG
);
574 error
= dsl_dataset_hold_obj_string(tmpdp
,
575 nvpair_name(pair
), FTAG
, &ds
);
577 char name
[ZFS_MAX_DATASET_NAME_LEN
];
578 dsl_dataset_name(ds
, name
);
579 dsl_pool_config_exit(tmpdp
, FTAG
);
580 dsl_dataset_rele(ds
, FTAG
);
581 (void) zfs_unmount_snap(name
);
583 dsl_pool_config_exit(tmpdp
, FTAG
);
588 /* Non-temporary holds are specified by name. */
589 ddura
.ddura_holdfunc
= dsl_dataset_hold
;
590 pool
= nvpair_name(pair
);
592 for (pair
= nvlist_next_nvpair(holds
, NULL
); pair
!= NULL
;
593 pair
= nvlist_next_nvpair(holds
, pair
)) {
594 (void) zfs_unmount_snap(nvpair_name(pair
));
599 ddura
.ddura_holds
= holds
;
600 ddura
.ddura_errlist
= errlist
;
601 ddura
.ddura_todelete
= fnvlist_alloc();
602 ddura
.ddura_chkholds
= fnvlist_alloc();
604 error
= dsl_sync_task(pool
, dsl_dataset_user_release_check
,
605 dsl_dataset_user_release_sync
, &ddura
, 0, ZFS_SPACE_CHECK_NONE
);
606 fnvlist_free(ddura
.ddura_todelete
);
607 fnvlist_free(ddura
.ddura_chkholds
);
613 * holds is nvl of snapname -> { holdname, ... }
614 * errlist will be filled in with snapname -> error
617 dsl_dataset_user_release(nvlist_t
*holds
, nvlist_t
*errlist
)
619 return (dsl_dataset_user_release_impl(holds
, errlist
, NULL
));
623 * holds is nvl of snapdsobj -> { holdname, ... }
626 dsl_dataset_user_release_tmp(struct dsl_pool
*dp
, nvlist_t
*holds
)
629 (void) dsl_dataset_user_release_impl(holds
, NULL
, dp
);
633 dsl_dataset_get_holds(const char *dsname
, nvlist_t
*nvl
)
639 err
= dsl_pool_hold(dsname
, FTAG
, &dp
);
642 err
= dsl_dataset_hold(dp
, dsname
, FTAG
, &ds
);
644 dsl_pool_rele(dp
, FTAG
);
648 if (dsl_dataset_phys(ds
)->ds_userrefs_obj
!= 0) {
652 za
= kmem_alloc(sizeof (zap_attribute_t
), KM_SLEEP
);
653 for (zap_cursor_init(&zc
, ds
->ds_dir
->dd_pool
->dp_meta_objset
,
654 dsl_dataset_phys(ds
)->ds_userrefs_obj
);
655 zap_cursor_retrieve(&zc
, za
) == 0;
656 zap_cursor_advance(&zc
)) {
657 fnvlist_add_uint64(nvl
, za
->za_name
,
658 za
->za_first_integer
);
660 zap_cursor_fini(&zc
);
661 kmem_free(za
, sizeof (zap_attribute_t
));
663 dsl_dataset_rele(ds
, FTAG
);
664 dsl_pool_rele(dp
, FTAG
);