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, 2014 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
);
88 if (spa_version(dp
->dp_spa
) < SPA_VERSION_USERREFS
)
89 return (SET_ERROR(ENOTSUP
));
91 if (!dmu_tx_is_syncing(tx
))
94 for (pair
= nvlist_next_nvpair(dduha
->dduha_holds
, NULL
);
95 pair
!= NULL
; pair
= nvlist_next_nvpair(dduha
->dduha_holds
, pair
)) {
100 /* must be a snapshot */
101 name
= nvpair_name(pair
);
102 if (strchr(name
, '@') == NULL
)
103 error
= SET_ERROR(EINVAL
);
106 error
= nvpair_value_string(pair
, &htag
);
109 error
= dsl_dataset_hold(dp
, name
, FTAG
, &ds
);
112 error
= dsl_dataset_user_hold_check_one(ds
, htag
,
113 dduha
->dduha_minor
!= 0, tx
);
114 dsl_dataset_rele(ds
, FTAG
);
118 fnvlist_add_string(dduha
->dduha_chkholds
, name
, htag
);
121 * We register ENOENT errors so they can be correctly
122 * reported if needed, such as when all holds fail.
124 fnvlist_add_int32(dduha
->dduha_errlist
, name
, error
);
135 dsl_dataset_user_hold_sync_one_impl(nvlist_t
*tmpholds
, dsl_dataset_t
*ds
,
136 const char *htag
, minor_t minor
, uint64_t now
, dmu_tx_t
*tx
)
138 dsl_pool_t
*dp
= ds
->ds_dir
->dd_pool
;
139 objset_t
*mos
= dp
->dp_meta_objset
;
142 ASSERT(RRW_WRITE_HELD(&dp
->dp_config_rwlock
));
144 if (dsl_dataset_phys(ds
)->ds_userrefs_obj
== 0) {
146 * This is the first user hold for this dataset. Create
147 * the userrefs zap object.
149 dmu_buf_will_dirty(ds
->ds_dbuf
, tx
);
150 zapobj
= dsl_dataset_phys(ds
)->ds_userrefs_obj
=
151 zap_create(mos
, DMU_OT_USERREFS
, DMU_OT_NONE
, 0, tx
);
153 zapobj
= dsl_dataset_phys(ds
)->ds_userrefs_obj
;
157 VERIFY0(zap_add(mos
, zapobj
, htag
, 8, 1, &now
, tx
));
160 char name
[MAXNAMELEN
];
163 VERIFY0(dsl_pool_user_hold(dp
, ds
->ds_object
,
165 (void) snprintf(name
, sizeof (name
), "%llx",
166 (u_longlong_t
)ds
->ds_object
);
168 if (nvlist_lookup_nvlist(tmpholds
, name
, &tags
) != 0) {
169 tags
= fnvlist_alloc();
170 fnvlist_add_boolean(tags
, htag
);
171 fnvlist_add_nvlist(tmpholds
, name
, tags
);
174 fnvlist_add_boolean(tags
, htag
);
178 spa_history_log_internal_ds(ds
, "hold", tx
,
179 "tag=%s temp=%d refs=%llu",
180 htag
, minor
!= 0, ds
->ds_userrefs
);
183 typedef struct zfs_hold_cleanup_arg
{
184 char zhca_spaname
[MAXNAMELEN
];
185 uint64_t zhca_spa_load_guid
;
186 nvlist_t
*zhca_holds
;
187 } zfs_hold_cleanup_arg_t
;
190 dsl_dataset_user_release_onexit(void *arg
)
192 zfs_hold_cleanup_arg_t
*ca
= arg
;
196 error
= spa_open(ca
->zhca_spaname
, &spa
, FTAG
);
198 zfs_dbgmsg("couldn't release holds on pool=%s "
199 "because pool is no longer loaded",
203 if (spa_load_guid(spa
) != ca
->zhca_spa_load_guid
) {
204 zfs_dbgmsg("couldn't release holds on pool=%s "
205 "because pool is no longer loaded (guid doesn't match)",
207 spa_close(spa
, FTAG
);
211 (void) dsl_dataset_user_release_tmp(spa_get_dsl(spa
), ca
->zhca_holds
);
212 fnvlist_free(ca
->zhca_holds
);
213 kmem_free(ca
, sizeof (zfs_hold_cleanup_arg_t
));
214 spa_close(spa
, FTAG
);
218 dsl_onexit_hold_cleanup(spa_t
*spa
, nvlist_t
*holds
, minor_t minor
)
220 zfs_hold_cleanup_arg_t
*ca
;
222 if (minor
== 0 || nvlist_empty(holds
)) {
228 ca
= kmem_alloc(sizeof (*ca
), KM_SLEEP
);
230 (void) strlcpy(ca
->zhca_spaname
, spa_name(spa
),
231 sizeof (ca
->zhca_spaname
));
232 ca
->zhca_spa_load_guid
= spa_load_guid(spa
);
233 ca
->zhca_holds
= holds
;
234 VERIFY0(zfs_onexit_add_cb(minor
,
235 dsl_dataset_user_release_onexit
, ca
, NULL
));
239 dsl_dataset_user_hold_sync_one(dsl_dataset_t
*ds
, const char *htag
,
240 minor_t minor
, uint64_t now
, dmu_tx_t
*tx
)
245 tmpholds
= fnvlist_alloc();
248 dsl_dataset_user_hold_sync_one_impl(tmpholds
, ds
, htag
, minor
, now
, tx
);
249 dsl_onexit_hold_cleanup(dsl_dataset_get_spa(ds
), tmpholds
, minor
);
253 dsl_dataset_user_hold_sync(void *arg
, dmu_tx_t
*tx
)
255 dsl_dataset_user_hold_arg_t
*dduha
= arg
;
256 dsl_pool_t
*dp
= dmu_tx_pool(tx
);
259 uint64_t now
= gethrestime_sec();
261 if (dduha
->dduha_minor
!= 0)
262 tmpholds
= fnvlist_alloc();
265 for (pair
= nvlist_next_nvpair(dduha
->dduha_chkholds
, NULL
);
267 pair
= nvlist_next_nvpair(dduha
->dduha_chkholds
, pair
)) {
270 VERIFY0(dsl_dataset_hold(dp
, nvpair_name(pair
), FTAG
, &ds
));
271 dsl_dataset_user_hold_sync_one_impl(tmpholds
, ds
,
272 fnvpair_value_string(pair
), dduha
->dduha_minor
, now
, tx
);
273 dsl_dataset_rele(ds
, FTAG
);
275 dsl_onexit_hold_cleanup(dp
->dp_spa
, tmpholds
, dduha
->dduha_minor
);
279 * The full semantics of this function are described in the comment above
283 * holds is nvl of snapname -> holdname
284 * errlist will be filled in with snapname -> error
286 * The snaphosts must all be in the same pool.
288 * Holds for snapshots that don't exist will be skipped.
290 * If none of the snapshots for requested holds exist then ENOENT will be
293 * If cleanup_minor is not 0, the holds will be temporary, which will be cleaned
294 * up when the process exits.
296 * On success all the holds, for snapshots that existed, will be created and 0
299 * On failure no holds will be created, the errlist will be filled in,
300 * and an errno will returned.
302 * In all cases the errlist will contain entries for holds where the snapshot
306 dsl_dataset_user_hold(nvlist_t
*holds
, minor_t cleanup_minor
, nvlist_t
*errlist
)
308 dsl_dataset_user_hold_arg_t dduha
;
312 pair
= nvlist_next_nvpair(holds
, NULL
);
316 dduha
.dduha_holds
= holds
;
317 dduha
.dduha_chkholds
= fnvlist_alloc();
318 dduha
.dduha_errlist
= errlist
;
319 dduha
.dduha_minor
= cleanup_minor
;
321 ret
= dsl_sync_task(nvpair_name(pair
), dsl_dataset_user_hold_check
,
322 dsl_dataset_user_hold_sync
, &dduha
,
323 fnvlist_num_pairs(holds
), ZFS_SPACE_CHECK_RESERVED
);
324 fnvlist_free(dduha
.dduha_chkholds
);
329 typedef int (dsl_holdfunc_t
)(dsl_pool_t
*dp
, const char *name
, void *tag
,
330 dsl_dataset_t
**dsp
);
332 typedef struct dsl_dataset_user_release_arg
{
333 dsl_holdfunc_t
*ddura_holdfunc
;
334 nvlist_t
*ddura_holds
;
335 nvlist_t
*ddura_todelete
;
336 nvlist_t
*ddura_errlist
;
337 nvlist_t
*ddura_chkholds
;
338 } dsl_dataset_user_release_arg_t
;
340 /* Place a dataset hold on the snapshot identified by passed dsobj string */
342 dsl_dataset_hold_obj_string(dsl_pool_t
*dp
, const char *dsobj
, void *tag
,
345 return (dsl_dataset_hold_obj(dp
, strtonum(dsobj
, NULL
), tag
, dsp
));
349 dsl_dataset_user_release_check_one(dsl_dataset_user_release_arg_t
*ddura
,
350 dsl_dataset_t
*ds
, nvlist_t
*holds
, const char *snapname
)
353 nvlist_t
*holds_found
;
358 if (!ds
->ds_is_snapshot
)
359 return (SET_ERROR(EINVAL
));
361 if (nvlist_empty(holds
))
365 mos
= ds
->ds_dir
->dd_pool
->dp_meta_objset
;
366 zapobj
= dsl_dataset_phys(ds
)->ds_userrefs_obj
;
367 VERIFY0(nvlist_alloc(&holds_found
, NV_UNIQUE_NAME
, KM_SLEEP
));
369 for (pair
= nvlist_next_nvpair(holds
, NULL
); pair
!= NULL
;
370 pair
= nvlist_next_nvpair(holds
, pair
)) {
373 const char *holdname
= nvpair_name(pair
);
376 error
= zap_lookup(mos
, zapobj
, holdname
, 8, 1, &tmp
);
378 error
= SET_ERROR(ENOENT
);
381 * Non-existent holds are put on the errlist, but don't
382 * cause an overall failure.
384 if (error
== ENOENT
) {
385 if (ddura
->ddura_errlist
!= NULL
) {
386 char *errtag
= kmem_asprintf("%s#%s",
388 fnvlist_add_int32(ddura
->ddura_errlist
, errtag
,
396 fnvlist_free(holds_found
);
400 fnvlist_add_boolean(holds_found
, holdname
);
404 if (DS_IS_DEFER_DESTROY(ds
) &&
405 dsl_dataset_phys(ds
)->ds_num_children
== 1 &&
406 ds
->ds_userrefs
== numholds
) {
407 /* we need to destroy the snapshot as well */
408 if (dsl_dataset_long_held(ds
)) {
409 fnvlist_free(holds_found
);
410 return (SET_ERROR(EBUSY
));
412 fnvlist_add_boolean(ddura
->ddura_todelete
, snapname
);
416 fnvlist_add_nvlist(ddura
->ddura_chkholds
, snapname
,
419 fnvlist_free(holds_found
);
425 dsl_dataset_user_release_check(void *arg
, dmu_tx_t
*tx
)
427 dsl_dataset_user_release_arg_t
*ddura
;
428 dsl_holdfunc_t
*holdfunc
;
432 if (!dmu_tx_is_syncing(tx
))
435 dp
= dmu_tx_pool(tx
);
437 ASSERT(RRW_WRITE_HELD(&dp
->dp_config_rwlock
));
440 holdfunc
= ddura
->ddura_holdfunc
;
442 for (pair
= nvlist_next_nvpair(ddura
->ddura_holds
, NULL
);
443 pair
!= NULL
; pair
= nvlist_next_nvpair(ddura
->ddura_holds
, pair
)) {
447 const char *snapname
= nvpair_name(pair
);
449 error
= nvpair_value_nvlist(pair
, &holds
);
451 error
= (SET_ERROR(EINVAL
));
453 error
= holdfunc(dp
, snapname
, FTAG
, &ds
);
455 error
= dsl_dataset_user_release_check_one(ddura
, ds
,
457 dsl_dataset_rele(ds
, FTAG
);
460 if (ddura
->ddura_errlist
!= NULL
) {
461 fnvlist_add_int32(ddura
->ddura_errlist
,
465 * Non-existent snapshots are put on the errlist,
466 * but don't cause an overall failure.
477 dsl_dataset_user_release_sync_one(dsl_dataset_t
*ds
, nvlist_t
*holds
,
480 dsl_pool_t
*dp
= ds
->ds_dir
->dd_pool
;
481 objset_t
*mos
= dp
->dp_meta_objset
;
484 for (pair
= nvlist_next_nvpair(holds
, NULL
); pair
!= NULL
;
485 pair
= nvlist_next_nvpair(holds
, pair
)) {
487 const char *holdname
= nvpair_name(pair
);
489 /* Remove temporary hold if one exists. */
490 error
= dsl_pool_user_release(dp
, ds
->ds_object
, holdname
, tx
);
491 VERIFY(error
== 0 || error
== ENOENT
);
493 VERIFY0(zap_remove(mos
, dsl_dataset_phys(ds
)->ds_userrefs_obj
,
497 spa_history_log_internal_ds(ds
, "release", tx
,
498 "tag=%s refs=%lld", holdname
, (longlong_t
)ds
->ds_userrefs
);
503 dsl_dataset_user_release_sync(void *arg
, dmu_tx_t
*tx
)
505 dsl_dataset_user_release_arg_t
*ddura
= arg
;
506 dsl_holdfunc_t
*holdfunc
= ddura
->ddura_holdfunc
;
507 dsl_pool_t
*dp
= dmu_tx_pool(tx
);
510 ASSERT(RRW_WRITE_HELD(&dp
->dp_config_rwlock
));
512 for (pair
= nvlist_next_nvpair(ddura
->ddura_chkholds
, NULL
);
513 pair
!= NULL
; pair
= nvlist_next_nvpair(ddura
->ddura_chkholds
,
516 const char *name
= nvpair_name(pair
);
518 VERIFY0(holdfunc(dp
, name
, FTAG
, &ds
));
520 dsl_dataset_user_release_sync_one(ds
,
521 fnvpair_value_nvlist(pair
), tx
);
522 if (nvlist_exists(ddura
->ddura_todelete
, name
)) {
523 ASSERT(ds
->ds_userrefs
== 0 &&
524 dsl_dataset_phys(ds
)->ds_num_children
== 1 &&
525 DS_IS_DEFER_DESTROY(ds
));
526 dsl_destroy_snapshot_sync_impl(ds
, B_FALSE
, tx
);
528 dsl_dataset_rele(ds
, FTAG
);
533 * The full semantics of this function are described in the comment above
537 * Releases holds specified in the nvl holds.
539 * holds is nvl of snapname -> { holdname, ... }
540 * errlist will be filled in with snapname -> error
542 * If tmpdp is not NULL the names for holds should be the dsobj's of snapshots,
543 * otherwise they should be the names of shapshots.
545 * As a release may cause snapshots to be destroyed this trys to ensure they
548 * The release of non-existent holds are skipped.
550 * At least one hold must have been released for the this function to succeed
554 dsl_dataset_user_release_impl(nvlist_t
*holds
, nvlist_t
*errlist
,
557 dsl_dataset_user_release_arg_t ddura
;
562 pair
= nvlist_next_nvpair(holds
, NULL
);
567 * The release may cause snapshots to be destroyed; make sure they
571 /* Temporary holds are specified by dsobj string. */
572 ddura
.ddura_holdfunc
= dsl_dataset_hold_obj_string
;
573 pool
= spa_name(tmpdp
->dp_spa
);
575 for (pair
= nvlist_next_nvpair(holds
, NULL
); pair
!= NULL
;
576 pair
= nvlist_next_nvpair(holds
, pair
)) {
579 dsl_pool_config_enter(tmpdp
, FTAG
);
580 error
= dsl_dataset_hold_obj_string(tmpdp
,
581 nvpair_name(pair
), FTAG
, &ds
);
583 char name
[MAXNAMELEN
];
584 dsl_dataset_name(ds
, name
);
585 dsl_pool_config_exit(tmpdp
, FTAG
);
586 dsl_dataset_rele(ds
, FTAG
);
587 (void) zfs_unmount_snap(name
);
589 dsl_pool_config_exit(tmpdp
, FTAG
);
594 /* Non-temporary holds are specified by name. */
595 ddura
.ddura_holdfunc
= dsl_dataset_hold
;
596 pool
= nvpair_name(pair
);
598 for (pair
= nvlist_next_nvpair(holds
, NULL
); pair
!= NULL
;
599 pair
= nvlist_next_nvpair(holds
, pair
)) {
600 (void) zfs_unmount_snap(nvpair_name(pair
));
605 ddura
.ddura_holds
= holds
;
606 ddura
.ddura_errlist
= errlist
;
607 VERIFY0(nvlist_alloc(&ddura
.ddura_todelete
, NV_UNIQUE_NAME
,
609 VERIFY0(nvlist_alloc(&ddura
.ddura_chkholds
, NV_UNIQUE_NAME
,
612 error
= dsl_sync_task(pool
, dsl_dataset_user_release_check
,
613 dsl_dataset_user_release_sync
, &ddura
, 0, ZFS_SPACE_CHECK_NONE
);
614 fnvlist_free(ddura
.ddura_todelete
);
615 fnvlist_free(ddura
.ddura_chkholds
);
621 * holds is nvl of snapname -> { holdname, ... }
622 * errlist will be filled in with snapname -> error
625 dsl_dataset_user_release(nvlist_t
*holds
, nvlist_t
*errlist
)
627 return (dsl_dataset_user_release_impl(holds
, errlist
, NULL
));
631 * holds is nvl of snapdsobj -> { holdname, ... }
634 dsl_dataset_user_release_tmp(struct dsl_pool
*dp
, nvlist_t
*holds
)
637 (void) dsl_dataset_user_release_impl(holds
, NULL
, dp
);
641 dsl_dataset_get_holds(const char *dsname
, nvlist_t
*nvl
)
647 err
= dsl_pool_hold(dsname
, FTAG
, &dp
);
650 err
= dsl_dataset_hold(dp
, dsname
, FTAG
, &ds
);
652 dsl_pool_rele(dp
, FTAG
);
656 if (dsl_dataset_phys(ds
)->ds_userrefs_obj
!= 0) {
660 za
= kmem_alloc(sizeof (zap_attribute_t
), KM_SLEEP
);
661 for (zap_cursor_init(&zc
, ds
->ds_dir
->dd_pool
->dp_meta_objset
,
662 dsl_dataset_phys(ds
)->ds_userrefs_obj
);
663 zap_cursor_retrieve(&zc
, za
) == 0;
664 zap_cursor_advance(&zc
)) {
665 fnvlist_add_uint64(nvl
, za
->za_name
,
666 za
->za_first_integer
);
668 zap_cursor_fini(&zc
);
669 kmem_free(za
, sizeof (zap_attribute_t
));
671 dsl_dataset_rele(ds
, FTAG
);
672 dsl_pool_rele(dp
, FTAG
);