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.
25 #include <sys/zfs_context.h>
27 #include <sys/dmu_objset.h>
28 #include <sys/dmu_tx.h>
29 #include <sys/dsl_dataset.h>
30 #include <sys/dsl_dir.h>
31 #include <sys/dsl_prop.h>
32 #include <sys/dsl_synctask.h>
35 #include <sys/fs/zfs.h>
39 #define ZPROP_INHERIT_SUFFIX "$inherit"
40 #define ZPROP_RECVD_SUFFIX "$recvd"
43 dodefault(const char *propname
, int intsz
, int numints
, void *buf
)
48 * The setonce properties are read-only, BUT they still
49 * have a default value that can be used as the initial
52 if ((prop
= zfs_name_to_prop(propname
)) == ZPROP_INVAL
||
53 (zfs_prop_readonly(prop
) && !zfs_prop_setonce(prop
)))
56 if (zfs_prop_get_type(prop
) == PROP_TYPE_STRING
) {
59 (void) strncpy(buf
, zfs_prop_default_string(prop
),
62 if (intsz
!= 8 || numints
< 1)
65 *(uint64_t *)buf
= zfs_prop_default_numeric(prop
);
72 dsl_prop_get_dd(dsl_dir_t
*dd
, const char *propname
,
73 int intsz
, int numints
, void *buf
, char *setpoint
, boolean_t snapshot
)
76 dsl_dir_t
*target
= dd
;
77 objset_t
*mos
= dd
->dd_pool
->dp_meta_objset
;
79 boolean_t inheritable
;
80 boolean_t inheriting
= B_FALSE
;
84 ASSERT(RW_LOCK_HELD(&dd
->dd_pool
->dp_config_rwlock
));
89 prop
= zfs_name_to_prop(propname
);
90 inheritable
= (prop
== ZPROP_INVAL
|| zfs_prop_inheritable(prop
));
91 inheritstr
= kmem_asprintf("%s%s", propname
, ZPROP_INHERIT_SUFFIX
);
92 recvdstr
= kmem_asprintf("%s%s", propname
, ZPROP_RECVD_SUFFIX
);
95 * Note: dd may become NULL, therefore we shouldn't dereference it
98 for (; dd
!= NULL
; dd
= dd
->dd_parent
) {
99 ASSERT(RW_LOCK_HELD(&dd
->dd_pool
->dp_config_rwlock
));
101 if (dd
!= target
|| snapshot
) {
107 /* Check for a local value. */
108 err
= zap_lookup(mos
, dd
->dd_phys
->dd_props_zapobj
, propname
,
109 intsz
, numints
, buf
);
111 if (setpoint
!= NULL
&& err
== 0)
112 dsl_dir_name(dd
, setpoint
);
117 * Skip the check for a received value if there is an explicit
120 err
= zap_contains(mos
, dd
->dd_phys
->dd_props_zapobj
,
122 if (err
!= 0 && err
!= ENOENT
)
126 /* Check for a received value. */
127 err
= zap_lookup(mos
, dd
->dd_phys
->dd_props_zapobj
,
128 recvdstr
, intsz
, numints
, buf
);
130 if (setpoint
!= NULL
&& err
== 0) {
132 dsl_dir_name(dd
, setpoint
);
134 (void) strcpy(setpoint
,
135 ZPROP_SOURCE_VAL_RECVD
);
143 * If we found an explicit inheritance entry, err is zero even
144 * though we haven't yet found the value, so reinitializing err
145 * at the end of the loop (instead of at the beginning) ensures
146 * that err has a valid post-loop value.
152 err
= dodefault(propname
, intsz
, numints
, buf
);
161 dsl_prop_get_ds(dsl_dataset_t
*ds
, const char *propname
,
162 int intsz
, int numints
, void *buf
, char *setpoint
)
164 zfs_prop_t prop
= zfs_name_to_prop(propname
);
165 boolean_t inheritable
;
169 ASSERT(RW_LOCK_HELD(&ds
->ds_dir
->dd_pool
->dp_config_rwlock
));
170 inheritable
= (prop
== ZPROP_INVAL
|| zfs_prop_inheritable(prop
));
171 snapshot
= (ds
->ds_phys
!= NULL
&& dsl_dataset_is_snapshot(ds
));
172 zapobj
= (ds
->ds_phys
== NULL
? 0 : ds
->ds_phys
->ds_props_obj
);
175 objset_t
*mos
= ds
->ds_dir
->dd_pool
->dp_meta_objset
;
180 /* Check for a local value. */
181 err
= zap_lookup(mos
, zapobj
, propname
, intsz
, numints
, buf
);
183 if (setpoint
!= NULL
&& err
== 0)
184 dsl_dataset_name(ds
, setpoint
);
189 * Skip the check for a received value if there is an explicit
193 char *inheritstr
= kmem_asprintf("%s%s", propname
,
194 ZPROP_INHERIT_SUFFIX
);
195 err
= zap_contains(mos
, zapobj
, inheritstr
);
197 if (err
!= 0 && err
!= ENOENT
)
202 /* Check for a received value. */
203 char *recvdstr
= kmem_asprintf("%s%s", propname
,
205 err
= zap_lookup(mos
, zapobj
, recvdstr
,
206 intsz
, numints
, buf
);
209 if (setpoint
!= NULL
&& err
== 0)
210 (void) strcpy(setpoint
,
211 ZPROP_SOURCE_VAL_RECVD
);
217 return (dsl_prop_get_dd(ds
->ds_dir
, propname
,
218 intsz
, numints
, buf
, setpoint
, snapshot
));
222 * Register interest in the named property. We'll call the callback
223 * once to notify it of the current property value, and again each time
224 * the property changes, until this callback is unregistered.
226 * Return 0 on success, errno if the prop is not an integer value.
229 dsl_prop_register(dsl_dataset_t
*ds
, const char *propname
,
230 dsl_prop_changed_cb_t
*callback
, void *cbarg
)
232 dsl_dir_t
*dd
= ds
->ds_dir
;
233 dsl_pool_t
*dp
= dd
->dd_pool
;
235 dsl_prop_cb_record_t
*cbr
;
239 need_rwlock
= !RW_WRITE_HELD(&dp
->dp_config_rwlock
);
241 rw_enter(&dp
->dp_config_rwlock
, RW_READER
);
243 err
= dsl_prop_get_ds(ds
, propname
, 8, 1, &value
, NULL
);
246 rw_exit(&dp
->dp_config_rwlock
);
250 cbr
= kmem_alloc(sizeof (dsl_prop_cb_record_t
), KM_SLEEP
);
252 cbr
->cbr_propname
= kmem_alloc(strlen(propname
)+1, KM_SLEEP
);
253 (void) strcpy((char *)cbr
->cbr_propname
, propname
);
254 cbr
->cbr_func
= callback
;
255 cbr
->cbr_arg
= cbarg
;
256 mutex_enter(&dd
->dd_lock
);
257 list_insert_head(&dd
->dd_prop_cbs
, cbr
);
258 mutex_exit(&dd
->dd_lock
);
260 cbr
->cbr_func(cbr
->cbr_arg
, value
);
263 rw_exit(&dp
->dp_config_rwlock
);
268 dsl_prop_get(const char *dsname
, const char *propname
,
269 int intsz
, int numints
, void *buf
, char *setpoint
)
274 err
= dsl_dataset_hold(dsname
, FTAG
, &ds
);
278 rw_enter(&ds
->ds_dir
->dd_pool
->dp_config_rwlock
, RW_READER
);
279 err
= dsl_prop_get_ds(ds
, propname
, intsz
, numints
, buf
, setpoint
);
280 rw_exit(&ds
->ds_dir
->dd_pool
->dp_config_rwlock
);
282 dsl_dataset_rele(ds
, FTAG
);
287 * Get the current property value. It may have changed by the time this
288 * function returns, so it is NOT safe to follow up with
289 * dsl_prop_register() and assume that the value has not changed in
292 * Return 0 on success, ENOENT if ddname is invalid.
295 dsl_prop_get_integer(const char *ddname
, const char *propname
,
296 uint64_t *valuep
, char *setpoint
)
298 return (dsl_prop_get(ddname
, propname
, 8, 1, valuep
, setpoint
));
302 dsl_prop_setarg_init_uint64(dsl_prop_setarg_t
*psa
, const char *propname
,
303 zprop_source_t source
, uint64_t *value
)
305 psa
->psa_name
= propname
;
306 psa
->psa_source
= source
;
308 psa
->psa_numints
= 1;
309 psa
->psa_value
= value
;
311 psa
->psa_effective_value
= -1ULL;
315 * Predict the effective value of the given special property if it were set with
316 * the given value and source. This is not a general purpose function. It exists
317 * only to handle the special requirements of the quota and reservation
318 * properties. The fact that these properties are non-inheritable greatly
319 * simplifies the prediction logic.
321 * Returns 0 on success, a positive error code on failure, or -1 if called with
322 * a property not handled by this function.
325 dsl_prop_predict_sync(dsl_dir_t
*dd
, dsl_prop_setarg_t
*psa
)
327 const char *propname
= psa
->psa_name
;
328 zfs_prop_t prop
= zfs_name_to_prop(propname
);
329 zprop_source_t source
= psa
->psa_source
;
338 case ZFS_PROP_RESERVATION
:
339 case ZFS_PROP_REFQUOTA
:
340 case ZFS_PROP_REFRESERVATION
:
346 mos
= dd
->dd_pool
->dp_meta_objset
;
347 zapobj
= dd
->dd_phys
->dd_props_zapobj
;
348 recvdstr
= kmem_asprintf("%s%s", propname
, ZPROP_RECVD_SUFFIX
);
350 version
= spa_version(dd
->dd_pool
->dp_spa
);
351 if (version
< SPA_VERSION_RECVD_PROPS
) {
352 if (source
& ZPROP_SRC_NONE
)
353 source
= ZPROP_SRC_NONE
;
354 else if (source
& ZPROP_SRC_RECEIVED
)
355 source
= ZPROP_SRC_LOCAL
;
360 /* Revert to the received value, if any. */
361 err
= zap_lookup(mos
, zapobj
, recvdstr
, 8, 1,
362 &psa
->psa_effective_value
);
364 psa
->psa_effective_value
= 0;
366 case ZPROP_SRC_LOCAL
:
367 psa
->psa_effective_value
= *(uint64_t *)psa
->psa_value
;
369 case ZPROP_SRC_RECEIVED
:
371 * If there's no local setting, then the new received value will
372 * be the effective value.
374 err
= zap_lookup(mos
, zapobj
, propname
, 8, 1,
375 &psa
->psa_effective_value
);
377 psa
->psa_effective_value
= *(uint64_t *)psa
->psa_value
;
379 case (ZPROP_SRC_NONE
| ZPROP_SRC_RECEIVED
):
381 * We're clearing the received value, so the local setting (if
382 * it exists) remains the effective value.
384 err
= zap_lookup(mos
, zapobj
, propname
, 8, 1,
385 &psa
->psa_effective_value
);
387 psa
->psa_effective_value
= 0;
390 cmn_err(CE_PANIC
, "unexpected property source: %d", source
);
403 dsl_prop_check_prediction(dsl_dir_t
*dd
, dsl_prop_setarg_t
*psa
)
405 zfs_prop_t prop
= zfs_name_to_prop(psa
->psa_name
);
407 char setpoint
[MAXNAMELEN
];
408 uint64_t version
= spa_version(dd
->dd_pool
->dp_spa
);
411 if (version
< SPA_VERSION_RECVD_PROPS
) {
414 case ZFS_PROP_RESERVATION
:
421 err
= dsl_prop_get_dd(dd
, psa
->psa_name
, 8, 1, &intval
,
423 if (err
== 0 && intval
!= psa
->psa_effective_value
) {
424 cmn_err(CE_PANIC
, "%s property, source: %x, "
425 "predicted effective value: %llu, "
426 "actual effective value: %llu (setpoint: %s)",
427 psa
->psa_name
, psa
->psa_source
,
428 (unsigned long long)psa
->psa_effective_value
,
429 (unsigned long long)intval
, setpoint
);
435 * Unregister this callback. Return 0 on success, ENOENT if ddname is
436 * invalid, ENOMSG if no matching callback registered.
439 dsl_prop_unregister(dsl_dataset_t
*ds
, const char *propname
,
440 dsl_prop_changed_cb_t
*callback
, void *cbarg
)
442 dsl_dir_t
*dd
= ds
->ds_dir
;
443 dsl_prop_cb_record_t
*cbr
;
445 mutex_enter(&dd
->dd_lock
);
446 for (cbr
= list_head(&dd
->dd_prop_cbs
);
447 cbr
; cbr
= list_next(&dd
->dd_prop_cbs
, cbr
)) {
448 if (cbr
->cbr_ds
== ds
&&
449 cbr
->cbr_func
== callback
&&
450 cbr
->cbr_arg
== cbarg
&&
451 strcmp(cbr
->cbr_propname
, propname
) == 0)
456 mutex_exit(&dd
->dd_lock
);
460 list_remove(&dd
->dd_prop_cbs
, cbr
);
461 mutex_exit(&dd
->dd_lock
);
462 kmem_free((void*)cbr
->cbr_propname
, strlen(cbr
->cbr_propname
)+1);
463 kmem_free(cbr
, sizeof (dsl_prop_cb_record_t
));
469 * Return the number of callbacks that are registered for this dataset.
472 dsl_prop_numcb(dsl_dataset_t
*ds
)
474 dsl_dir_t
*dd
= ds
->ds_dir
;
475 dsl_prop_cb_record_t
*cbr
;
478 mutex_enter(&dd
->dd_lock
);
479 for (cbr
= list_head(&dd
->dd_prop_cbs
);
480 cbr
; cbr
= list_next(&dd
->dd_prop_cbs
, cbr
)) {
481 if (cbr
->cbr_ds
== ds
)
484 mutex_exit(&dd
->dd_lock
);
490 dsl_prop_changed_notify(dsl_pool_t
*dp
, uint64_t ddobj
,
491 const char *propname
, uint64_t value
, int first
)
494 dsl_prop_cb_record_t
*cbr
;
495 objset_t
*mos
= dp
->dp_meta_objset
;
500 ASSERT(RW_WRITE_HELD(&dp
->dp_config_rwlock
));
501 err
= dsl_dir_open_obj(dp
, ddobj
, NULL
, FTAG
, &dd
);
507 * If the prop is set here, then this change is not
508 * being inherited here or below; stop the recursion.
510 err
= zap_contains(mos
, dd
->dd_phys
->dd_props_zapobj
, propname
);
512 dsl_dir_close(dd
, FTAG
);
515 ASSERT3U(err
, ==, ENOENT
);
518 mutex_enter(&dd
->dd_lock
);
519 for (cbr
= list_head(&dd
->dd_prop_cbs
); cbr
;
520 cbr
= list_next(&dd
->dd_prop_cbs
, cbr
)) {
521 uint64_t propobj
= cbr
->cbr_ds
->ds_phys
->ds_props_obj
;
523 if (strcmp(cbr
->cbr_propname
, propname
) != 0)
527 * If the property is set on this ds, then it is not
528 * inherited here; don't call the callback.
530 if (propobj
&& 0 == zap_contains(mos
, propobj
, propname
))
533 cbr
->cbr_func(cbr
->cbr_arg
, value
);
535 mutex_exit(&dd
->dd_lock
);
537 za
= kmem_alloc(sizeof (zap_attribute_t
), KM_SLEEP
);
538 for (zap_cursor_init(&zc
, mos
,
539 dd
->dd_phys
->dd_child_dir_zapobj
);
540 zap_cursor_retrieve(&zc
, za
) == 0;
541 zap_cursor_advance(&zc
)) {
542 dsl_prop_changed_notify(dp
, za
->za_first_integer
,
543 propname
, value
, FALSE
);
545 kmem_free(za
, sizeof (zap_attribute_t
));
546 zap_cursor_fini(&zc
);
547 dsl_dir_close(dd
, FTAG
);
551 dsl_prop_set_sync(void *arg1
, void *arg2
, dmu_tx_t
*tx
)
553 dsl_dataset_t
*ds
= arg1
;
554 dsl_prop_setarg_t
*psa
= arg2
;
555 objset_t
*mos
= ds
->ds_dir
->dd_pool
->dp_meta_objset
;
556 uint64_t zapobj
, intval
, dummy
;
564 uint64_t version
= spa_version(ds
->ds_dir
->dd_pool
->dp_spa
);
565 const char *propname
= psa
->psa_name
;
566 zprop_source_t source
= psa
->psa_source
;
568 isint
= (dodefault(propname
, 8, 1, &intval
) == 0);
570 if (ds
->ds_phys
!= NULL
&& dsl_dataset_is_snapshot(ds
)) {
571 ASSERT(version
>= SPA_VERSION_SNAP_PROPS
);
572 if (ds
->ds_phys
->ds_props_obj
== 0) {
573 dmu_buf_will_dirty(ds
->ds_dbuf
, tx
);
574 ds
->ds_phys
->ds_props_obj
=
576 DMU_OT_DSL_PROPS
, DMU_OT_NONE
, 0, tx
);
578 zapobj
= ds
->ds_phys
->ds_props_obj
;
580 zapobj
= ds
->ds_dir
->dd_phys
->dd_props_zapobj
;
583 if (version
< SPA_VERSION_RECVD_PROPS
) {
584 zfs_prop_t prop
= zfs_name_to_prop(propname
);
585 if (prop
== ZFS_PROP_QUOTA
|| prop
== ZFS_PROP_RESERVATION
)
588 if (source
& ZPROP_SRC_NONE
)
589 source
= ZPROP_SRC_NONE
;
590 else if (source
& ZPROP_SRC_RECEIVED
)
591 source
= ZPROP_SRC_LOCAL
;
594 inheritstr
= kmem_asprintf("%s%s", propname
, ZPROP_INHERIT_SUFFIX
);
595 recvdstr
= kmem_asprintf("%s%s", propname
, ZPROP_RECVD_SUFFIX
);
600 * revert to received value, if any (inherit -S)
602 * - remove propname$inherit
604 err
= zap_remove(mos
, zapobj
, propname
, tx
);
605 ASSERT(err
== 0 || err
== ENOENT
);
606 err
= zap_remove(mos
, zapobj
, inheritstr
, tx
);
607 ASSERT(err
== 0 || err
== ENOENT
);
609 case ZPROP_SRC_LOCAL
:
611 * remove propname$inherit
612 * set propname -> value
614 err
= zap_remove(mos
, zapobj
, inheritstr
, tx
);
615 ASSERT(err
== 0 || err
== ENOENT
);
616 VERIFY(0 == zap_update(mos
, zapobj
, propname
,
617 psa
->psa_intsz
, psa
->psa_numints
, psa
->psa_value
, tx
));
619 case ZPROP_SRC_INHERITED
:
623 * - set propname$inherit
625 err
= zap_remove(mos
, zapobj
, propname
, tx
);
626 ASSERT(err
== 0 || err
== ENOENT
);
627 if (version
>= SPA_VERSION_RECVD_PROPS
&&
628 dsl_prop_get_ds(ds
, ZPROP_HAS_RECVD
, 8, 1, &dummy
,
631 err
= zap_update(mos
, zapobj
, inheritstr
,
636 case ZPROP_SRC_RECEIVED
:
638 * set propname$recvd -> value
640 err
= zap_update(mos
, zapobj
, recvdstr
,
641 psa
->psa_intsz
, psa
->psa_numints
, psa
->psa_value
, tx
);
644 case (ZPROP_SRC_NONE
| ZPROP_SRC_LOCAL
| ZPROP_SRC_RECEIVED
):
646 * clear local and received settings
648 * - remove propname$inherit
649 * - remove propname$recvd
651 err
= zap_remove(mos
, zapobj
, propname
, tx
);
652 ASSERT(err
== 0 || err
== ENOENT
);
653 err
= zap_remove(mos
, zapobj
, inheritstr
, tx
);
654 ASSERT(err
== 0 || err
== ENOENT
);
656 case (ZPROP_SRC_NONE
| ZPROP_SRC_RECEIVED
):
658 * remove propname$recvd
660 err
= zap_remove(mos
, zapobj
, recvdstr
, tx
);
661 ASSERT(err
== 0 || err
== ENOENT
);
664 cmn_err(CE_PANIC
, "unexpected property source: %d", source
);
671 VERIFY(0 == dsl_prop_get_ds(ds
, propname
, 8, 1, &intval
, NULL
));
673 if (ds
->ds_phys
!= NULL
&& dsl_dataset_is_snapshot(ds
)) {
674 dsl_prop_cb_record_t
*cbr
;
676 * It's a snapshot; nothing can inherit this
677 * property, so just look for callbacks on this
680 mutex_enter(&ds
->ds_dir
->dd_lock
);
681 for (cbr
= list_head(&ds
->ds_dir
->dd_prop_cbs
); cbr
;
682 cbr
= list_next(&ds
->ds_dir
->dd_prop_cbs
, cbr
)) {
683 if (cbr
->cbr_ds
== ds
&&
684 strcmp(cbr
->cbr_propname
, propname
) == 0)
685 cbr
->cbr_func(cbr
->cbr_arg
, intval
);
687 mutex_exit(&ds
->ds_dir
->dd_lock
);
689 dsl_prop_changed_notify(ds
->ds_dir
->dd_pool
,
690 ds
->ds_dir
->dd_object
, propname
, intval
, TRUE
);
693 (void) snprintf(valbuf
, sizeof (valbuf
),
694 "%lld", (longlong_t
)intval
);
697 if (source
== ZPROP_SRC_LOCAL
) {
698 valstr
= (char *)psa
->psa_value
;
700 tbuf
= kmem_alloc(ZAP_MAXVALUELEN
, KM_SLEEP
);
701 if (dsl_prop_get_ds(ds
, propname
, 1,
702 ZAP_MAXVALUELEN
, tbuf
, NULL
) == 0)
707 spa_history_log_internal((source
== ZPROP_SRC_NONE
||
708 source
== ZPROP_SRC_INHERITED
) ? LOG_DS_INHERIT
:
709 LOG_DS_PROPSET
, ds
->ds_dir
->dd_pool
->dp_spa
, tx
,
710 "%s=%s dataset = %llu", propname
,
711 (valstr
== NULL
? "" : valstr
), ds
->ds_object
);
714 kmem_free(tbuf
, ZAP_MAXVALUELEN
);
718 dsl_props_set_sync(void *arg1
, void *arg2
, dmu_tx_t
*tx
)
720 dsl_dataset_t
*ds
= arg1
;
721 dsl_props_arg_t
*pa
= arg2
;
722 nvlist_t
*props
= pa
->pa_props
;
723 dsl_prop_setarg_t psa
;
724 nvpair_t
*elem
= NULL
;
726 psa
.psa_source
= pa
->pa_source
;
728 while ((elem
= nvlist_next_nvpair(props
, elem
)) != NULL
) {
729 nvpair_t
*pair
= elem
;
731 psa
.psa_name
= nvpair_name(pair
);
733 if (nvpair_type(pair
) == DATA_TYPE_NVLIST
) {
735 * dsl_prop_get_all_impl() returns properties in this
739 VERIFY(nvpair_value_nvlist(pair
, &attrs
) == 0);
740 VERIFY(nvlist_lookup_nvpair(attrs
, ZPROP_VALUE
,
744 if (nvpair_type(pair
) == DATA_TYPE_STRING
) {
745 VERIFY(nvpair_value_string(pair
,
746 (char **)&psa
.psa_value
) == 0);
748 psa
.psa_numints
= strlen(psa
.psa_value
) + 1;
751 VERIFY(nvpair_value_uint64(pair
, &intval
) == 0);
752 psa
.psa_intsz
= sizeof (intval
);
754 psa
.psa_value
= &intval
;
756 dsl_prop_set_sync(ds
, &psa
, tx
);
761 dsl_dir_prop_set_uint64_sync(dsl_dir_t
*dd
, const char *name
, uint64_t val
,
764 objset_t
*mos
= dd
->dd_pool
->dp_meta_objset
;
765 uint64_t zapobj
= dd
->dd_phys
->dd_props_zapobj
;
767 ASSERT(dmu_tx_is_syncing(tx
));
769 VERIFY(0 == zap_update(mos
, zapobj
, name
, sizeof (val
), 1, &val
, tx
));
771 dsl_prop_changed_notify(dd
->dd_pool
, dd
->dd_object
, name
, val
, TRUE
);
773 spa_history_log_internal(LOG_DS_PROPSET
, dd
->dd_pool
->dp_spa
, tx
,
774 "%s=%llu dataset = %llu", name
, (u_longlong_t
)val
,
775 dd
->dd_phys
->dd_head_dataset_obj
);
779 dsl_prop_set(const char *dsname
, const char *propname
, zprop_source_t source
,
780 int intsz
, int numints
, const void *buf
)
785 dsl_prop_setarg_t psa
;
788 * We must do these checks before we get to the syncfunc, since
791 if (strlen(propname
) >= ZAP_MAXNAMELEN
)
792 return (ENAMETOOLONG
);
794 err
= dsl_dataset_hold(dsname
, FTAG
, &ds
);
798 version
= spa_version(ds
->ds_dir
->dd_pool
->dp_spa
);
799 if (intsz
* numints
>= (version
< SPA_VERSION_STMF_PROP
?
800 ZAP_OLDMAXVALUELEN
: ZAP_MAXVALUELEN
)) {
801 dsl_dataset_rele(ds
, FTAG
);
804 if (dsl_dataset_is_snapshot(ds
) &&
805 version
< SPA_VERSION_SNAP_PROPS
) {
806 dsl_dataset_rele(ds
, FTAG
);
810 psa
.psa_name
= propname
;
811 psa
.psa_source
= source
;
812 psa
.psa_intsz
= intsz
;
813 psa
.psa_numints
= numints
;
815 psa
.psa_effective_value
= -1ULL;
817 err
= dsl_sync_task_do(ds
->ds_dir
->dd_pool
,
818 NULL
, dsl_prop_set_sync
, ds
, &psa
, 2);
820 dsl_dataset_rele(ds
, FTAG
);
825 dsl_props_set(const char *dsname
, zprop_source_t source
, nvlist_t
*props
)
829 nvpair_t
*elem
= NULL
;
833 if ((err
= dsl_dataset_hold(dsname
, FTAG
, &ds
)))
836 * Do these checks before the syncfunc, since it can't fail.
838 version
= spa_version(ds
->ds_dir
->dd_pool
->dp_spa
);
839 while ((elem
= nvlist_next_nvpair(props
, elem
)) != NULL
) {
840 if (strlen(nvpair_name(elem
)) >= ZAP_MAXNAMELEN
) {
841 dsl_dataset_rele(ds
, FTAG
);
842 return (ENAMETOOLONG
);
844 if (nvpair_type(elem
) == DATA_TYPE_STRING
) {
846 VERIFY(nvpair_value_string(elem
, &valstr
) == 0);
847 if (strlen(valstr
) >= (version
<
848 SPA_VERSION_STMF_PROP
?
849 ZAP_OLDMAXVALUELEN
: ZAP_MAXVALUELEN
)) {
850 dsl_dataset_rele(ds
, FTAG
);
856 if (dsl_dataset_is_snapshot(ds
) &&
857 version
< SPA_VERSION_SNAP_PROPS
) {
858 dsl_dataset_rele(ds
, FTAG
);
863 pa
.pa_source
= source
;
865 err
= dsl_sync_task_do(ds
->ds_dir
->dd_pool
,
866 NULL
, dsl_props_set_sync
, ds
, &pa
, 2);
868 dsl_dataset_rele(ds
, FTAG
);
872 typedef enum dsl_prop_getflags
{
873 DSL_PROP_GET_INHERITING
= 0x1, /* searching parent of target ds */
874 DSL_PROP_GET_SNAPSHOT
= 0x2, /* snapshot dataset */
875 DSL_PROP_GET_LOCAL
= 0x4, /* local properties */
876 DSL_PROP_GET_RECEIVED
= 0x8 /* received properties */
877 } dsl_prop_getflags_t
;
880 dsl_prop_get_all_impl(objset_t
*mos
, uint64_t propobj
,
881 const char *setpoint
, dsl_prop_getflags_t flags
, nvlist_t
*nv
)
887 for (zap_cursor_init(&zc
, mos
, propobj
);
888 (err
= zap_cursor_retrieve(&zc
, &za
)) == 0;
889 zap_cursor_advance(&zc
)) {
892 char buf
[ZAP_MAXNAMELEN
];
895 const char *propname
;
898 suffix
= strchr(za
.za_name
, '$');
900 if (suffix
== NULL
) {
902 * Skip local properties if we only want received
905 if (flags
& DSL_PROP_GET_RECEIVED
)
908 propname
= za
.za_name
;
910 } else if (strcmp(suffix
, ZPROP_INHERIT_SUFFIX
) == 0) {
911 /* Skip explicitly inherited entries. */
913 } else if (strcmp(suffix
, ZPROP_RECVD_SUFFIX
) == 0) {
914 if (flags
& DSL_PROP_GET_LOCAL
)
917 (void) strncpy(buf
, za
.za_name
, (suffix
- za
.za_name
));
918 buf
[suffix
- za
.za_name
] = '\0';
921 if (!(flags
& DSL_PROP_GET_RECEIVED
)) {
922 /* Skip if locally overridden. */
923 err
= zap_contains(mos
, propobj
, propname
);
929 /* Skip if explicitly inherited. */
930 valstr
= kmem_asprintf("%s%s", propname
,
931 ZPROP_INHERIT_SUFFIX
);
932 err
= zap_contains(mos
, propobj
, valstr
);
940 source
= ((flags
& DSL_PROP_GET_INHERITING
) ?
941 setpoint
: ZPROP_SOURCE_VAL_RECVD
);
944 * For backward compatibility, skip suffixes we don't
950 prop
= zfs_name_to_prop(propname
);
952 /* Skip non-inheritable properties. */
953 if ((flags
& DSL_PROP_GET_INHERITING
) && prop
!= ZPROP_INVAL
&&
954 !zfs_prop_inheritable(prop
))
957 /* Skip properties not valid for this type. */
958 if ((flags
& DSL_PROP_GET_SNAPSHOT
) && prop
!= ZPROP_INVAL
&&
959 !zfs_prop_valid_for_type(prop
, ZFS_TYPE_SNAPSHOT
))
962 /* Skip properties already defined. */
963 if (nvlist_exists(nv
, propname
))
966 VERIFY(nvlist_alloc(&propval
, NV_UNIQUE_NAME
, KM_SLEEP
) == 0);
967 if (za
.za_integer_length
== 1) {
971 char *tmp
= kmem_alloc(za
.za_num_integers
,
973 err
= zap_lookup(mos
, propobj
,
974 za
.za_name
, 1, za
.za_num_integers
, tmp
);
976 kmem_free(tmp
, za
.za_num_integers
);
979 VERIFY(nvlist_add_string(propval
, ZPROP_VALUE
,
981 kmem_free(tmp
, za
.za_num_integers
);
986 ASSERT(za
.za_integer_length
== 8);
987 (void) nvlist_add_uint64(propval
, ZPROP_VALUE
,
988 za
.za_first_integer
);
991 VERIFY(nvlist_add_string(propval
, ZPROP_SOURCE
, source
) == 0);
992 VERIFY(nvlist_add_nvlist(nv
, propname
, propval
) == 0);
993 nvlist_free(propval
);
995 zap_cursor_fini(&zc
);
1002 * Iterate over all properties for this dataset and return them in an nvlist.
1005 dsl_prop_get_all_ds(dsl_dataset_t
*ds
, nvlist_t
**nvp
,
1006 dsl_prop_getflags_t flags
)
1008 dsl_dir_t
*dd
= ds
->ds_dir
;
1009 dsl_pool_t
*dp
= dd
->dd_pool
;
1010 objset_t
*mos
= dp
->dp_meta_objset
;
1012 char setpoint
[MAXNAMELEN
];
1014 VERIFY(nvlist_alloc(nvp
, NV_UNIQUE_NAME
, KM_SLEEP
) == 0);
1016 if (dsl_dataset_is_snapshot(ds
))
1017 flags
|= DSL_PROP_GET_SNAPSHOT
;
1019 rw_enter(&dp
->dp_config_rwlock
, RW_READER
);
1021 if (ds
->ds_phys
->ds_props_obj
!= 0) {
1022 ASSERT(flags
& DSL_PROP_GET_SNAPSHOT
);
1023 dsl_dataset_name(ds
, setpoint
);
1024 err
= dsl_prop_get_all_impl(mos
, ds
->ds_phys
->ds_props_obj
,
1025 setpoint
, flags
, *nvp
);
1030 for (; dd
!= NULL
; dd
= dd
->dd_parent
) {
1031 if (dd
!= ds
->ds_dir
|| (flags
& DSL_PROP_GET_SNAPSHOT
)) {
1032 if (flags
& (DSL_PROP_GET_LOCAL
|
1033 DSL_PROP_GET_RECEIVED
))
1035 flags
|= DSL_PROP_GET_INHERITING
;
1037 dsl_dir_name(dd
, setpoint
);
1038 err
= dsl_prop_get_all_impl(mos
, dd
->dd_phys
->dd_props_zapobj
,
1039 setpoint
, flags
, *nvp
);
1044 rw_exit(&dp
->dp_config_rwlock
);
1049 dsl_prop_get_hasrecvd(objset_t
*os
)
1051 dsl_dataset_t
*ds
= os
->os_dsl_dataset
;
1055 rw_enter(&ds
->ds_dir
->dd_pool
->dp_config_rwlock
, RW_READER
);
1056 rc
= dsl_prop_get_ds(ds
, ZPROP_HAS_RECVD
, 8, 1, &dummy
, NULL
);
1057 rw_exit(&ds
->ds_dir
->dd_pool
->dp_config_rwlock
);
1058 ASSERT(rc
!= 0 || spa_version(os
->os_spa
) >= SPA_VERSION_RECVD_PROPS
);
1063 dsl_prop_set_hasrecvd_impl(objset_t
*os
, zprop_source_t source
)
1065 dsl_dataset_t
*ds
= os
->os_dsl_dataset
;
1067 dsl_prop_setarg_t psa
;
1069 if (spa_version(os
->os_spa
) < SPA_VERSION_RECVD_PROPS
)
1072 dsl_prop_setarg_init_uint64(&psa
, ZPROP_HAS_RECVD
, source
, &dummy
);
1074 (void) dsl_sync_task_do(ds
->ds_dir
->dd_pool
, NULL
,
1075 dsl_prop_set_sync
, ds
, &psa
, 2);
1079 * Call after successfully receiving properties to ensure that only the first
1080 * receive on or after SPA_VERSION_RECVD_PROPS blows away local properties.
1083 dsl_prop_set_hasrecvd(objset_t
*os
)
1085 if (dsl_prop_get_hasrecvd(os
)) {
1086 ASSERT(spa_version(os
->os_spa
) >= SPA_VERSION_RECVD_PROPS
);
1089 dsl_prop_set_hasrecvd_impl(os
, ZPROP_SRC_LOCAL
);
1093 dsl_prop_unset_hasrecvd(objset_t
*os
)
1095 dsl_prop_set_hasrecvd_impl(os
, ZPROP_SRC_NONE
);
1099 dsl_prop_get_all(objset_t
*os
, nvlist_t
**nvp
)
1101 return (dsl_prop_get_all_ds(os
->os_dsl_dataset
, nvp
, 0));
1105 dsl_prop_get_received(objset_t
*os
, nvlist_t
**nvp
)
1108 * Received properties are not distinguishable from local properties
1109 * until the dataset has received properties on or after
1110 * SPA_VERSION_RECVD_PROPS.
1112 dsl_prop_getflags_t flags
= (dsl_prop_get_hasrecvd(os
) ?
1113 DSL_PROP_GET_RECEIVED
: DSL_PROP_GET_LOCAL
);
1114 return (dsl_prop_get_all_ds(os
->os_dsl_dataset
, nvp
, flags
));
1118 dsl_prop_nvlist_add_uint64(nvlist_t
*nv
, zfs_prop_t prop
, uint64_t value
)
1121 const char *propname
= zfs_prop_to_name(prop
);
1122 uint64_t default_value
;
1124 if (nvlist_lookup_nvlist(nv
, propname
, &propval
) == 0) {
1125 VERIFY(nvlist_add_uint64(propval
, ZPROP_VALUE
, value
) == 0);
1129 VERIFY(nvlist_alloc(&propval
, NV_UNIQUE_NAME
, KM_SLEEP
) == 0);
1130 VERIFY(nvlist_add_uint64(propval
, ZPROP_VALUE
, value
) == 0);
1131 /* Indicate the default source if we can. */
1132 if (dodefault(propname
, 8, 1, &default_value
) == 0 &&
1133 value
== default_value
) {
1134 VERIFY(nvlist_add_string(propval
, ZPROP_SOURCE
, "") == 0);
1136 VERIFY(nvlist_add_nvlist(nv
, propname
, propval
) == 0);
1137 nvlist_free(propval
);
1141 dsl_prop_nvlist_add_string(nvlist_t
*nv
, zfs_prop_t prop
, const char *value
)
1144 const char *propname
= zfs_prop_to_name(prop
);
1146 if (nvlist_lookup_nvlist(nv
, propname
, &propval
) == 0) {
1147 VERIFY(nvlist_add_string(propval
, ZPROP_VALUE
, value
) == 0);
1151 VERIFY(nvlist_alloc(&propval
, NV_UNIQUE_NAME
, KM_SLEEP
) == 0);
1152 VERIFY(nvlist_add_string(propval
, ZPROP_VALUE
, value
) == 0);
1153 VERIFY(nvlist_add_nvlist(nv
, propname
, propval
) == 0);
1154 nvlist_free(propval
);