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
:
419 err
= dsl_prop_get_dd(dd
, psa
->psa_name
, 8, 1, &intval
,
421 if (err
== 0 && intval
!= psa
->psa_effective_value
) {
422 cmn_err(CE_PANIC
, "%s property, source: %x, "
423 "predicted effective value: %llu, "
424 "actual effective value: %llu (setpoint: %s)",
425 psa
->psa_name
, psa
->psa_source
,
426 (unsigned long long)psa
->psa_effective_value
,
427 (unsigned long long)intval
, setpoint
);
433 * Unregister this callback. Return 0 on success, ENOENT if ddname is
434 * invalid, ENOMSG if no matching callback registered.
437 dsl_prop_unregister(dsl_dataset_t
*ds
, const char *propname
,
438 dsl_prop_changed_cb_t
*callback
, void *cbarg
)
440 dsl_dir_t
*dd
= ds
->ds_dir
;
441 dsl_prop_cb_record_t
*cbr
;
443 mutex_enter(&dd
->dd_lock
);
444 for (cbr
= list_head(&dd
->dd_prop_cbs
);
445 cbr
; cbr
= list_next(&dd
->dd_prop_cbs
, cbr
)) {
446 if (cbr
->cbr_ds
== ds
&&
447 cbr
->cbr_func
== callback
&&
448 cbr
->cbr_arg
== cbarg
&&
449 strcmp(cbr
->cbr_propname
, propname
) == 0)
454 mutex_exit(&dd
->dd_lock
);
458 list_remove(&dd
->dd_prop_cbs
, cbr
);
459 mutex_exit(&dd
->dd_lock
);
460 kmem_free((void*)cbr
->cbr_propname
, strlen(cbr
->cbr_propname
)+1);
461 kmem_free(cbr
, sizeof (dsl_prop_cb_record_t
));
467 * Return the number of callbacks that are registered for this dataset.
470 dsl_prop_numcb(dsl_dataset_t
*ds
)
472 dsl_dir_t
*dd
= ds
->ds_dir
;
473 dsl_prop_cb_record_t
*cbr
;
476 mutex_enter(&dd
->dd_lock
);
477 for (cbr
= list_head(&dd
->dd_prop_cbs
);
478 cbr
; cbr
= list_next(&dd
->dd_prop_cbs
, cbr
)) {
479 if (cbr
->cbr_ds
== ds
)
482 mutex_exit(&dd
->dd_lock
);
488 dsl_prop_changed_notify(dsl_pool_t
*dp
, uint64_t ddobj
,
489 const char *propname
, uint64_t value
, int first
)
492 dsl_prop_cb_record_t
*cbr
;
493 objset_t
*mos
= dp
->dp_meta_objset
;
498 ASSERT(RW_WRITE_HELD(&dp
->dp_config_rwlock
));
499 err
= dsl_dir_open_obj(dp
, ddobj
, NULL
, FTAG
, &dd
);
505 * If the prop is set here, then this change is not
506 * being inherited here or below; stop the recursion.
508 err
= zap_contains(mos
, dd
->dd_phys
->dd_props_zapobj
, propname
);
510 dsl_dir_close(dd
, FTAG
);
513 ASSERT3U(err
, ==, ENOENT
);
516 mutex_enter(&dd
->dd_lock
);
517 for (cbr
= list_head(&dd
->dd_prop_cbs
); cbr
;
518 cbr
= list_next(&dd
->dd_prop_cbs
, cbr
)) {
519 uint64_t propobj
= cbr
->cbr_ds
->ds_phys
->ds_props_obj
;
521 if (strcmp(cbr
->cbr_propname
, propname
) != 0)
525 * If the property is set on this ds, then it is not
526 * inherited here; don't call the callback.
528 if (propobj
&& 0 == zap_contains(mos
, propobj
, propname
))
531 cbr
->cbr_func(cbr
->cbr_arg
, value
);
533 mutex_exit(&dd
->dd_lock
);
535 za
= kmem_alloc(sizeof (zap_attribute_t
), KM_SLEEP
);
536 for (zap_cursor_init(&zc
, mos
,
537 dd
->dd_phys
->dd_child_dir_zapobj
);
538 zap_cursor_retrieve(&zc
, za
) == 0;
539 zap_cursor_advance(&zc
)) {
540 dsl_prop_changed_notify(dp
, za
->za_first_integer
,
541 propname
, value
, FALSE
);
543 kmem_free(za
, sizeof (zap_attribute_t
));
544 zap_cursor_fini(&zc
);
545 dsl_dir_close(dd
, FTAG
);
549 dsl_prop_set_sync(void *arg1
, void *arg2
, dmu_tx_t
*tx
)
551 dsl_dataset_t
*ds
= arg1
;
552 dsl_prop_setarg_t
*psa
= arg2
;
553 objset_t
*mos
= ds
->ds_dir
->dd_pool
->dp_meta_objset
;
554 uint64_t zapobj
, intval
, dummy
;
562 uint64_t version
= spa_version(ds
->ds_dir
->dd_pool
->dp_spa
);
563 const char *propname
= psa
->psa_name
;
564 zprop_source_t source
= psa
->psa_source
;
566 isint
= (dodefault(propname
, 8, 1, &intval
) == 0);
568 if (ds
->ds_phys
!= NULL
&& dsl_dataset_is_snapshot(ds
)) {
569 ASSERT(version
>= SPA_VERSION_SNAP_PROPS
);
570 if (ds
->ds_phys
->ds_props_obj
== 0) {
571 dmu_buf_will_dirty(ds
->ds_dbuf
, tx
);
572 ds
->ds_phys
->ds_props_obj
=
574 DMU_OT_DSL_PROPS
, DMU_OT_NONE
, 0, tx
);
576 zapobj
= ds
->ds_phys
->ds_props_obj
;
578 zapobj
= ds
->ds_dir
->dd_phys
->dd_props_zapobj
;
581 if (version
< SPA_VERSION_RECVD_PROPS
) {
582 zfs_prop_t prop
= zfs_name_to_prop(propname
);
583 if (prop
== ZFS_PROP_QUOTA
|| prop
== ZFS_PROP_RESERVATION
)
586 if (source
& ZPROP_SRC_NONE
)
587 source
= ZPROP_SRC_NONE
;
588 else if (source
& ZPROP_SRC_RECEIVED
)
589 source
= ZPROP_SRC_LOCAL
;
592 inheritstr
= kmem_asprintf("%s%s", propname
, ZPROP_INHERIT_SUFFIX
);
593 recvdstr
= kmem_asprintf("%s%s", propname
, ZPROP_RECVD_SUFFIX
);
598 * revert to received value, if any (inherit -S)
600 * - remove propname$inherit
602 err
= zap_remove(mos
, zapobj
, propname
, tx
);
603 ASSERT(err
== 0 || err
== ENOENT
);
604 err
= zap_remove(mos
, zapobj
, inheritstr
, tx
);
605 ASSERT(err
== 0 || err
== ENOENT
);
607 case ZPROP_SRC_LOCAL
:
609 * remove propname$inherit
610 * set propname -> value
612 err
= zap_remove(mos
, zapobj
, inheritstr
, tx
);
613 ASSERT(err
== 0 || err
== ENOENT
);
614 VERIFY(0 == zap_update(mos
, zapobj
, propname
,
615 psa
->psa_intsz
, psa
->psa_numints
, psa
->psa_value
, tx
));
617 case ZPROP_SRC_INHERITED
:
621 * - set propname$inherit
623 err
= zap_remove(mos
, zapobj
, propname
, tx
);
624 ASSERT(err
== 0 || err
== ENOENT
);
625 if (version
>= SPA_VERSION_RECVD_PROPS
&&
626 dsl_prop_get_ds(ds
, ZPROP_HAS_RECVD
, 8, 1, &dummy
,
629 err
= zap_update(mos
, zapobj
, inheritstr
,
634 case ZPROP_SRC_RECEIVED
:
636 * set propname$recvd -> value
638 err
= zap_update(mos
, zapobj
, recvdstr
,
639 psa
->psa_intsz
, psa
->psa_numints
, psa
->psa_value
, tx
);
642 case (ZPROP_SRC_NONE
| ZPROP_SRC_LOCAL
| ZPROP_SRC_RECEIVED
):
644 * clear local and received settings
646 * - remove propname$inherit
647 * - remove propname$recvd
649 err
= zap_remove(mos
, zapobj
, propname
, tx
);
650 ASSERT(err
== 0 || err
== ENOENT
);
651 err
= zap_remove(mos
, zapobj
, inheritstr
, tx
);
652 ASSERT(err
== 0 || err
== ENOENT
);
654 case (ZPROP_SRC_NONE
| ZPROP_SRC_RECEIVED
):
656 * remove propname$recvd
658 err
= zap_remove(mos
, zapobj
, recvdstr
, tx
);
659 ASSERT(err
== 0 || err
== ENOENT
);
662 cmn_err(CE_PANIC
, "unexpected property source: %d", source
);
669 VERIFY(0 == dsl_prop_get_ds(ds
, propname
, 8, 1, &intval
, NULL
));
671 if (ds
->ds_phys
!= NULL
&& dsl_dataset_is_snapshot(ds
)) {
672 dsl_prop_cb_record_t
*cbr
;
674 * It's a snapshot; nothing can inherit this
675 * property, so just look for callbacks on this
678 mutex_enter(&ds
->ds_dir
->dd_lock
);
679 for (cbr
= list_head(&ds
->ds_dir
->dd_prop_cbs
); cbr
;
680 cbr
= list_next(&ds
->ds_dir
->dd_prop_cbs
, cbr
)) {
681 if (cbr
->cbr_ds
== ds
&&
682 strcmp(cbr
->cbr_propname
, propname
) == 0)
683 cbr
->cbr_func(cbr
->cbr_arg
, intval
);
685 mutex_exit(&ds
->ds_dir
->dd_lock
);
687 dsl_prop_changed_notify(ds
->ds_dir
->dd_pool
,
688 ds
->ds_dir
->dd_object
, propname
, intval
, TRUE
);
691 (void) snprintf(valbuf
, sizeof (valbuf
),
692 "%lld", (longlong_t
)intval
);
695 if (source
== ZPROP_SRC_LOCAL
) {
696 valstr
= (char *)psa
->psa_value
;
698 tbuf
= kmem_alloc(ZAP_MAXVALUELEN
, KM_SLEEP
);
699 if (dsl_prop_get_ds(ds
, propname
, 1,
700 ZAP_MAXVALUELEN
, tbuf
, NULL
) == 0)
705 spa_history_log_internal((source
== ZPROP_SRC_NONE
||
706 source
== ZPROP_SRC_INHERITED
) ? LOG_DS_INHERIT
:
707 LOG_DS_PROPSET
, ds
->ds_dir
->dd_pool
->dp_spa
, tx
,
708 "%s=%s dataset = %llu", propname
,
709 (valstr
== NULL
? "" : valstr
), ds
->ds_object
);
712 kmem_free(tbuf
, ZAP_MAXVALUELEN
);
716 dsl_props_set_sync(void *arg1
, void *arg2
, dmu_tx_t
*tx
)
718 dsl_dataset_t
*ds
= arg1
;
719 dsl_props_arg_t
*pa
= arg2
;
720 nvlist_t
*props
= pa
->pa_props
;
721 dsl_prop_setarg_t psa
;
722 nvpair_t
*elem
= NULL
;
724 psa
.psa_source
= pa
->pa_source
;
726 while ((elem
= nvlist_next_nvpair(props
, elem
)) != NULL
) {
727 nvpair_t
*pair
= elem
;
729 psa
.psa_name
= nvpair_name(pair
);
731 if (nvpair_type(pair
) == DATA_TYPE_NVLIST
) {
733 * dsl_prop_get_all_impl() returns properties in this
737 VERIFY(nvpair_value_nvlist(pair
, &attrs
) == 0);
738 VERIFY(nvlist_lookup_nvpair(attrs
, ZPROP_VALUE
,
742 if (nvpair_type(pair
) == DATA_TYPE_STRING
) {
743 VERIFY(nvpair_value_string(pair
,
744 (char **)&psa
.psa_value
) == 0);
746 psa
.psa_numints
= strlen(psa
.psa_value
) + 1;
749 VERIFY(nvpair_value_uint64(pair
, &intval
) == 0);
750 psa
.psa_intsz
= sizeof (intval
);
752 psa
.psa_value
= &intval
;
754 dsl_prop_set_sync(ds
, &psa
, tx
);
759 dsl_dir_prop_set_uint64_sync(dsl_dir_t
*dd
, const char *name
, uint64_t val
,
762 objset_t
*mos
= dd
->dd_pool
->dp_meta_objset
;
763 uint64_t zapobj
= dd
->dd_phys
->dd_props_zapobj
;
765 ASSERT(dmu_tx_is_syncing(tx
));
767 VERIFY(0 == zap_update(mos
, zapobj
, name
, sizeof (val
), 1, &val
, tx
));
769 dsl_prop_changed_notify(dd
->dd_pool
, dd
->dd_object
, name
, val
, TRUE
);
771 spa_history_log_internal(LOG_DS_PROPSET
, dd
->dd_pool
->dp_spa
, tx
,
772 "%s=%llu dataset = %llu", name
, (u_longlong_t
)val
,
773 dd
->dd_phys
->dd_head_dataset_obj
);
777 dsl_prop_set(const char *dsname
, const char *propname
, zprop_source_t source
,
778 int intsz
, int numints
, const void *buf
)
783 dsl_prop_setarg_t psa
;
786 * We must do these checks before we get to the syncfunc, since
789 if (strlen(propname
) >= ZAP_MAXNAMELEN
)
790 return (ENAMETOOLONG
);
792 err
= dsl_dataset_hold(dsname
, FTAG
, &ds
);
796 version
= spa_version(ds
->ds_dir
->dd_pool
->dp_spa
);
797 if (intsz
* numints
>= (version
< SPA_VERSION_STMF_PROP
?
798 ZAP_OLDMAXVALUELEN
: ZAP_MAXVALUELEN
)) {
799 dsl_dataset_rele(ds
, FTAG
);
802 if (dsl_dataset_is_snapshot(ds
) &&
803 version
< SPA_VERSION_SNAP_PROPS
) {
804 dsl_dataset_rele(ds
, FTAG
);
808 psa
.psa_name
= propname
;
809 psa
.psa_source
= source
;
810 psa
.psa_intsz
= intsz
;
811 psa
.psa_numints
= numints
;
813 psa
.psa_effective_value
= -1ULL;
815 err
= dsl_sync_task_do(ds
->ds_dir
->dd_pool
,
816 NULL
, dsl_prop_set_sync
, ds
, &psa
, 2);
818 dsl_dataset_rele(ds
, FTAG
);
823 dsl_props_set(const char *dsname
, zprop_source_t source
, nvlist_t
*props
)
827 nvpair_t
*elem
= NULL
;
831 if (err
= dsl_dataset_hold(dsname
, FTAG
, &ds
))
834 * Do these checks before the syncfunc, since it can't fail.
836 version
= spa_version(ds
->ds_dir
->dd_pool
->dp_spa
);
837 while ((elem
= nvlist_next_nvpair(props
, elem
)) != NULL
) {
838 if (strlen(nvpair_name(elem
)) >= ZAP_MAXNAMELEN
) {
839 dsl_dataset_rele(ds
, FTAG
);
840 return (ENAMETOOLONG
);
842 if (nvpair_type(elem
) == DATA_TYPE_STRING
) {
844 VERIFY(nvpair_value_string(elem
, &valstr
) == 0);
845 if (strlen(valstr
) >= (version
<
846 SPA_VERSION_STMF_PROP
?
847 ZAP_OLDMAXVALUELEN
: ZAP_MAXVALUELEN
)) {
848 dsl_dataset_rele(ds
, FTAG
);
854 if (dsl_dataset_is_snapshot(ds
) &&
855 version
< SPA_VERSION_SNAP_PROPS
) {
856 dsl_dataset_rele(ds
, FTAG
);
861 pa
.pa_source
= source
;
863 err
= dsl_sync_task_do(ds
->ds_dir
->dd_pool
,
864 NULL
, dsl_props_set_sync
, ds
, &pa
, 2);
866 dsl_dataset_rele(ds
, FTAG
);
870 typedef enum dsl_prop_getflags
{
871 DSL_PROP_GET_INHERITING
= 0x1, /* searching parent of target ds */
872 DSL_PROP_GET_SNAPSHOT
= 0x2, /* snapshot dataset */
873 DSL_PROP_GET_LOCAL
= 0x4, /* local properties */
874 DSL_PROP_GET_RECEIVED
= 0x8 /* received properties */
875 } dsl_prop_getflags_t
;
878 dsl_prop_get_all_impl(objset_t
*mos
, uint64_t propobj
,
879 const char *setpoint
, dsl_prop_getflags_t flags
, nvlist_t
*nv
)
885 for (zap_cursor_init(&zc
, mos
, propobj
);
886 (err
= zap_cursor_retrieve(&zc
, &za
)) == 0;
887 zap_cursor_advance(&zc
)) {
890 char buf
[ZAP_MAXNAMELEN
];
893 const char *propname
;
896 suffix
= strchr(za
.za_name
, '$');
898 if (suffix
== NULL
) {
900 * Skip local properties if we only want received
903 if (flags
& DSL_PROP_GET_RECEIVED
)
906 propname
= za
.za_name
;
908 } else if (strcmp(suffix
, ZPROP_INHERIT_SUFFIX
) == 0) {
909 /* Skip explicitly inherited entries. */
911 } else if (strcmp(suffix
, ZPROP_RECVD_SUFFIX
) == 0) {
912 if (flags
& DSL_PROP_GET_LOCAL
)
915 (void) strncpy(buf
, za
.za_name
, (suffix
- za
.za_name
));
916 buf
[suffix
- za
.za_name
] = '\0';
919 if (!(flags
& DSL_PROP_GET_RECEIVED
)) {
920 /* Skip if locally overridden. */
921 err
= zap_contains(mos
, propobj
, propname
);
927 /* Skip if explicitly inherited. */
928 valstr
= kmem_asprintf("%s%s", propname
,
929 ZPROP_INHERIT_SUFFIX
);
930 err
= zap_contains(mos
, propobj
, valstr
);
938 source
= ((flags
& DSL_PROP_GET_INHERITING
) ?
939 setpoint
: ZPROP_SOURCE_VAL_RECVD
);
942 * For backward compatibility, skip suffixes we don't
948 prop
= zfs_name_to_prop(propname
);
950 /* Skip non-inheritable properties. */
951 if ((flags
& DSL_PROP_GET_INHERITING
) && prop
!= ZPROP_INVAL
&&
952 !zfs_prop_inheritable(prop
))
955 /* Skip properties not valid for this type. */
956 if ((flags
& DSL_PROP_GET_SNAPSHOT
) && prop
!= ZPROP_INVAL
&&
957 !zfs_prop_valid_for_type(prop
, ZFS_TYPE_SNAPSHOT
))
960 /* Skip properties already defined. */
961 if (nvlist_exists(nv
, propname
))
964 VERIFY(nvlist_alloc(&propval
, NV_UNIQUE_NAME
, KM_SLEEP
) == 0);
965 if (za
.za_integer_length
== 1) {
969 char *tmp
= kmem_alloc(za
.za_num_integers
,
971 err
= zap_lookup(mos
, propobj
,
972 za
.za_name
, 1, za
.za_num_integers
, tmp
);
974 kmem_free(tmp
, za
.za_num_integers
);
977 VERIFY(nvlist_add_string(propval
, ZPROP_VALUE
,
979 kmem_free(tmp
, za
.za_num_integers
);
984 ASSERT(za
.za_integer_length
== 8);
985 (void) nvlist_add_uint64(propval
, ZPROP_VALUE
,
986 za
.za_first_integer
);
989 VERIFY(nvlist_add_string(propval
, ZPROP_SOURCE
, source
) == 0);
990 VERIFY(nvlist_add_nvlist(nv
, propname
, propval
) == 0);
991 nvlist_free(propval
);
993 zap_cursor_fini(&zc
);
1000 * Iterate over all properties for this dataset and return them in an nvlist.
1003 dsl_prop_get_all_ds(dsl_dataset_t
*ds
, nvlist_t
**nvp
,
1004 dsl_prop_getflags_t flags
)
1006 dsl_dir_t
*dd
= ds
->ds_dir
;
1007 dsl_pool_t
*dp
= dd
->dd_pool
;
1008 objset_t
*mos
= dp
->dp_meta_objset
;
1010 char setpoint
[MAXNAMELEN
];
1012 VERIFY(nvlist_alloc(nvp
, NV_UNIQUE_NAME
, KM_SLEEP
) == 0);
1014 if (dsl_dataset_is_snapshot(ds
))
1015 flags
|= DSL_PROP_GET_SNAPSHOT
;
1017 rw_enter(&dp
->dp_config_rwlock
, RW_READER
);
1019 if (ds
->ds_phys
->ds_props_obj
!= 0) {
1020 ASSERT(flags
& DSL_PROP_GET_SNAPSHOT
);
1021 dsl_dataset_name(ds
, setpoint
);
1022 err
= dsl_prop_get_all_impl(mos
, ds
->ds_phys
->ds_props_obj
,
1023 setpoint
, flags
, *nvp
);
1028 for (; dd
!= NULL
; dd
= dd
->dd_parent
) {
1029 if (dd
!= ds
->ds_dir
|| (flags
& DSL_PROP_GET_SNAPSHOT
)) {
1030 if (flags
& (DSL_PROP_GET_LOCAL
|
1031 DSL_PROP_GET_RECEIVED
))
1033 flags
|= DSL_PROP_GET_INHERITING
;
1035 dsl_dir_name(dd
, setpoint
);
1036 err
= dsl_prop_get_all_impl(mos
, dd
->dd_phys
->dd_props_zapobj
,
1037 setpoint
, flags
, *nvp
);
1042 rw_exit(&dp
->dp_config_rwlock
);
1047 dsl_prop_get_hasrecvd(objset_t
*os
)
1049 dsl_dataset_t
*ds
= os
->os_dsl_dataset
;
1053 rw_enter(&ds
->ds_dir
->dd_pool
->dp_config_rwlock
, RW_READER
);
1054 rc
= dsl_prop_get_ds(ds
, ZPROP_HAS_RECVD
, 8, 1, &dummy
, NULL
);
1055 rw_exit(&ds
->ds_dir
->dd_pool
->dp_config_rwlock
);
1056 ASSERT(rc
!= 0 || spa_version(os
->os_spa
) >= SPA_VERSION_RECVD_PROPS
);
1061 dsl_prop_set_hasrecvd_impl(objset_t
*os
, zprop_source_t source
)
1063 dsl_dataset_t
*ds
= os
->os_dsl_dataset
;
1065 dsl_prop_setarg_t psa
;
1067 if (spa_version(os
->os_spa
) < SPA_VERSION_RECVD_PROPS
)
1070 dsl_prop_setarg_init_uint64(&psa
, ZPROP_HAS_RECVD
, source
, &dummy
);
1072 (void) dsl_sync_task_do(ds
->ds_dir
->dd_pool
, NULL
,
1073 dsl_prop_set_sync
, ds
, &psa
, 2);
1077 * Call after successfully receiving properties to ensure that only the first
1078 * receive on or after SPA_VERSION_RECVD_PROPS blows away local properties.
1081 dsl_prop_set_hasrecvd(objset_t
*os
)
1083 if (dsl_prop_get_hasrecvd(os
)) {
1084 ASSERT(spa_version(os
->os_spa
) >= SPA_VERSION_RECVD_PROPS
);
1087 dsl_prop_set_hasrecvd_impl(os
, ZPROP_SRC_LOCAL
);
1091 dsl_prop_unset_hasrecvd(objset_t
*os
)
1093 dsl_prop_set_hasrecvd_impl(os
, ZPROP_SRC_NONE
);
1097 dsl_prop_get_all(objset_t
*os
, nvlist_t
**nvp
)
1099 return (dsl_prop_get_all_ds(os
->os_dsl_dataset
, nvp
, 0));
1103 dsl_prop_get_received(objset_t
*os
, nvlist_t
**nvp
)
1106 * Received properties are not distinguishable from local properties
1107 * until the dataset has received properties on or after
1108 * SPA_VERSION_RECVD_PROPS.
1110 dsl_prop_getflags_t flags
= (dsl_prop_get_hasrecvd(os
) ?
1111 DSL_PROP_GET_RECEIVED
: DSL_PROP_GET_LOCAL
);
1112 return (dsl_prop_get_all_ds(os
->os_dsl_dataset
, nvp
, flags
));
1116 dsl_prop_nvlist_add_uint64(nvlist_t
*nv
, zfs_prop_t prop
, uint64_t value
)
1119 const char *propname
= zfs_prop_to_name(prop
);
1120 uint64_t default_value
;
1122 if (nvlist_lookup_nvlist(nv
, propname
, &propval
) == 0) {
1123 VERIFY(nvlist_add_uint64(propval
, ZPROP_VALUE
, value
) == 0);
1127 VERIFY(nvlist_alloc(&propval
, NV_UNIQUE_NAME
, KM_SLEEP
) == 0);
1128 VERIFY(nvlist_add_uint64(propval
, ZPROP_VALUE
, value
) == 0);
1129 /* Indicate the default source if we can. */
1130 if (dodefault(propname
, 8, 1, &default_value
) == 0 &&
1131 value
== default_value
) {
1132 VERIFY(nvlist_add_string(propval
, ZPROP_SOURCE
, "") == 0);
1134 VERIFY(nvlist_add_nvlist(nv
, propname
, propval
) == 0);
1135 nvlist_free(propval
);
1139 dsl_prop_nvlist_add_string(nvlist_t
*nv
, zfs_prop_t prop
, const char *value
)
1142 const char *propname
= zfs_prop_to_name(prop
);
1144 if (nvlist_lookup_nvlist(nv
, propname
, &propval
) == 0) {
1145 VERIFY(nvlist_add_string(propval
, ZPROP_VALUE
, value
) == 0);
1149 VERIFY(nvlist_alloc(&propval
, NV_UNIQUE_NAME
, KM_SLEEP
) == 0);
1150 VERIFY(nvlist_add_string(propval
, ZPROP_VALUE
, value
) == 0);
1151 VERIFY(nvlist_add_nvlist(nv
, propname
, propval
) == 0);
1152 nvlist_free(propval
);