6 * You may not use this file except in compliance with the License.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
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 Martin Matuska. All rights reserved.
25 * Copyright 2015, Joyent, Inc.
26 */
27
28 #include <sys/zfs_context.h>
29 #include <sys/dmu.h>
30 #include <sys/dmu_objset.h>
31 #include <sys/dmu_tx.h>
32 #include <sys/dsl_dataset.h>
33 #include <sys/dsl_dir.h>
34 #include <sys/dsl_prop.h>
35 #include <sys/dsl_synctask.h>
36 #include <sys/spa.h>
37 #include <sys/zap.h>
38 #include <sys/fs/zfs.h>
39
40 #include "zfs_prop.h"
41
42 #define ZPROP_INHERIT_SUFFIX "$inherit"
43 #define ZPROP_RECVD_SUFFIX "$recvd"
44
45 static int
46 dodefault(zfs_prop_t prop, int intsz, int numints, void *buf)
47 {
48 /*
49 * The setonce properties are read-only, BUT they still
50 * have a default value that can be used as the initial
51 * value.
52 */
53 if (prop == ZPROP_INVAL ||
54 (zfs_prop_readonly(prop) && !zfs_prop_setonce(prop)))
55 return (SET_ERROR(ENOENT));
56
57 if (zfs_prop_get_type(prop) == PROP_TYPE_STRING) {
58 if (intsz != 1)
59 return (SET_ERROR(EOVERFLOW));
60 (void) strncpy(buf, zfs_prop_default_string(prop),
61 numints);
62 } else {
63 if (intsz != 8 || numints < 1)
64 return (SET_ERROR(EOVERFLOW));
270 /*
271 * Register interest in the named property. We'll call the callback
272 * once to notify it of the current property value, and again each time
273 * the property changes, until this callback is unregistered.
274 *
275 * Return 0 on success, errno if the prop is not an integer value.
276 */
277 int
278 dsl_prop_register(dsl_dataset_t *ds, const char *propname,
279 dsl_prop_changed_cb_t *callback, void *cbarg)
280 {
281 dsl_dir_t *dd = ds->ds_dir;
282 dsl_pool_t *dp = dd->dd_pool;
283 uint64_t value;
284 dsl_prop_record_t *pr;
285 dsl_prop_cb_record_t *cbr;
286 int err;
287
288 ASSERT(dsl_pool_config_held(dp));
289
290 err = dsl_prop_get_int_ds(ds, propname, &value);
291 if (err != 0)
292 return (err);
293
294 cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP);
295 cbr->cbr_ds = ds;
296 cbr->cbr_func = callback;
297 cbr->cbr_arg = cbarg;
298
299 mutex_enter(&dd->dd_lock);
300 pr = dsl_prop_record_find(dd, propname);
301 if (pr == NULL)
302 pr = dsl_prop_record_create(dd, propname);
303 cbr->cbr_pr = pr;
304 list_insert_head(&pr->pr_cbs, cbr);
305 list_insert_head(&ds->ds_prop_cbs, cbr);
306 mutex_exit(&dd->dd_lock);
307
308 cbr->cbr_func(cbr->cbr_arg, value);
309 return (0);
310 }
460 boolean_t
461 dsl_prop_hascb(dsl_dataset_t *ds)
462 {
463 return (!list_is_empty(&ds->ds_prop_cbs));
464 }
465
466 /* ARGSUSED */
467 static int
468 dsl_prop_notify_all_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg)
469 {
470 dsl_dir_t *dd = ds->ds_dir;
471 dsl_prop_record_t *pr;
472 dsl_prop_cb_record_t *cbr;
473
474 mutex_enter(&dd->dd_lock);
475 for (pr = list_head(&dd->dd_props);
476 pr; pr = list_next(&dd->dd_props, pr)) {
477 for (cbr = list_head(&pr->pr_cbs); cbr;
478 cbr = list_next(&pr->pr_cbs, cbr)) {
479 uint64_t value;
480
481 /*
482 * Callback entries do not have holds on their
483 * datasets so that datasets with registered
484 * callbacks are still eligible for eviction.
485 * Unlike operations to update properties on a
486 * single dataset, we are performing a recursive
487 * descent of related head datasets. The caller
488 * of this function only has a dataset hold on
489 * the passed in head dataset, not the snapshots
490 * associated with this dataset. Without a hold,
491 * the dataset pointer within callback records
492 * for snapshots can be invalidated by eviction
493 * at any time.
494 *
495 * Use dsl_dataset_try_add_ref() to verify
496 * that the dataset for a snapshot has not
497 * begun eviction processing and to prevent
498 * eviction from occurring for the duration of
499 * the callback. If the hold attempt fails,
500 * this object is already being evicted and the
501 * callback can be safely ignored.
502 */
503 if (ds != cbr->cbr_ds &&
504 !dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG))
505 continue;
506
507 if (dsl_prop_get_ds(cbr->cbr_ds,
508 cbr->cbr_pr->pr_propname, sizeof (value), 1,
509 &value, NULL) == 0)
510 cbr->cbr_func(cbr->cbr_arg, value);
511
512 if (ds != cbr->cbr_ds)
513 dsl_dataset_rele(cbr->cbr_ds, FTAG);
514 }
515 }
516 mutex_exit(&dd->dd_lock);
517
518 return (0);
519 }
520
521 /*
522 * Update all property values for ddobj & its descendants. This is used
523 * when renaming the dir.
524 */
525 void
526 dsl_prop_notify_all(dsl_dir_t *dd)
527 {
528 dsl_pool_t *dp = dd->dd_pool;
529 ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock));
530 (void) dmu_objset_find_dp(dp, dd->dd_object, dsl_prop_notify_all_cb,
603 }
604 kmem_free(za, sizeof (zap_attribute_t));
605 zap_cursor_fini(&zc);
606 dsl_dir_rele(dd, FTAG);
607 }
608
609 void
610 dsl_prop_set_sync_impl(dsl_dataset_t *ds, const char *propname,
611 zprop_source_t source, int intsz, int numints, const void *value,
612 dmu_tx_t *tx)
613 {
614 objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
615 uint64_t zapobj, intval, dummy;
616 int isint;
617 char valbuf[32];
618 const char *valstr = NULL;
619 char *inheritstr;
620 char *recvdstr;
621 char *tbuf = NULL;
622 int err;
623 uint64_t version = spa_version(ds->ds_dir->dd_pool->dp_spa);
624
625 isint = (dodefault(zfs_name_to_prop(propname), 8, 1, &intval) == 0);
626
627 if (ds->ds_is_snapshot) {
628 ASSERT(version >= SPA_VERSION_SNAP_PROPS);
629 if (dsl_dataset_phys(ds)->ds_props_obj == 0) {
630 dmu_buf_will_dirty(ds->ds_dbuf, tx);
631 dsl_dataset_phys(ds)->ds_props_obj =
632 zap_create(mos,
633 DMU_OT_DSL_PROPS, DMU_OT_NONE, 0, tx);
634 }
635 zapobj = dsl_dataset_phys(ds)->ds_props_obj;
636 } else {
637 zapobj = dsl_dir_phys(ds->ds_dir)->dd_props_zapobj;
638 }
639
640 if (version < SPA_VERSION_RECVD_PROPS) {
641 if (source & ZPROP_SRC_NONE)
642 source = ZPROP_SRC_NONE;
643 else if (source & ZPROP_SRC_RECEIVED)
701 */
702 err = zap_remove(mos, zapobj, propname, tx);
703 ASSERT(err == 0 || err == ENOENT);
704 err = zap_remove(mos, zapobj, inheritstr, tx);
705 ASSERT(err == 0 || err == ENOENT);
706 /* FALLTHRU */
707 case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED):
708 /*
709 * remove propname$recvd
710 */
711 err = zap_remove(mos, zapobj, recvdstr, tx);
712 ASSERT(err == 0 || err == ENOENT);
713 break;
714 default:
715 cmn_err(CE_PANIC, "unexpected property source: %d", source);
716 }
717
718 strfree(inheritstr);
719 strfree(recvdstr);
720
721 if (isint) {
722 VERIFY0(dsl_prop_get_int_ds(ds, propname, &intval));
723
724 if (ds->ds_is_snapshot) {
725 dsl_prop_cb_record_t *cbr;
726 /*
727 * It's a snapshot; nothing can inherit this
728 * property, so just look for callbacks on this
729 * ds here.
730 */
731 mutex_enter(&ds->ds_dir->dd_lock);
732 for (cbr = list_head(&ds->ds_prop_cbs); cbr;
733 cbr = list_next(&ds->ds_prop_cbs, cbr)) {
734 if (strcmp(cbr->cbr_pr->pr_propname,
735 propname) == 0)
736 cbr->cbr_func(cbr->cbr_arg, intval);
737 }
738 mutex_exit(&ds->ds_dir->dd_lock);
739 } else {
740 dsl_prop_changed_notify(ds->ds_dir->dd_pool,
741 ds->ds_dir->dd_object, propname, intval, TRUE);
785
786 fnvlist_add_string(nvl, propname, value);
787 error = dsl_props_set(dsname, source, nvl);
788 fnvlist_free(nvl);
789 return (error);
790 }
791
792 int
793 dsl_prop_inherit(const char *dsname, const char *propname,
794 zprop_source_t source)
795 {
796 nvlist_t *nvl = fnvlist_alloc();
797 int error;
798
799 fnvlist_add_boolean(nvl, propname);
800 error = dsl_props_set(dsname, source, nvl);
801 fnvlist_free(nvl);
802 return (error);
803 }
804
805 typedef struct dsl_props_set_arg {
806 const char *dpsa_dsname;
807 zprop_source_t dpsa_source;
808 nvlist_t *dpsa_props;
809 } dsl_props_set_arg_t;
810
811 static int
812 dsl_props_set_check(void *arg, dmu_tx_t *tx)
813 {
814 dsl_props_set_arg_t *dpsa = arg;
815 dsl_pool_t *dp = dmu_tx_pool(tx);
816 dsl_dataset_t *ds;
817 uint64_t version;
818 nvpair_t *elem = NULL;
819 int err;
820
821 err = dsl_dataset_hold(dp, dpsa->dpsa_dsname, FTAG, &ds);
822 if (err != 0)
823 return (err);
824
825 version = spa_version(ds->ds_dir->dd_pool->dp_spa);
826 while ((elem = nvlist_next_nvpair(dpsa->dpsa_props, elem)) != NULL) {
827 if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) {
828 dsl_dataset_rele(ds, FTAG);
829 return (SET_ERROR(ENAMETOOLONG));
830 }
831 if (nvpair_type(elem) == DATA_TYPE_STRING) {
832 char *valstr = fnvpair_value_string(elem);
833 if (strlen(valstr) >= (version <
834 SPA_VERSION_STMF_PROP ?
835 ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) {
836 dsl_dataset_rele(ds, FTAG);
837 return (E2BIG);
838 }
839 }
840 }
841
842 if (ds->ds_is_snapshot && version < SPA_VERSION_SNAP_PROPS) {
843 dsl_dataset_rele(ds, FTAG);
844 return (SET_ERROR(ENOTSUP));
845 }
846 dsl_dataset_rele(ds, FTAG);
847 return (0);
848 }
849
850 void
851 dsl_props_set_sync_impl(dsl_dataset_t *ds, zprop_source_t source,
852 nvlist_t *props, dmu_tx_t *tx)
853 {
854 nvpair_t *elem = NULL;
855
856 while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
857 nvpair_t *pair = elem;
858 const char *name = nvpair_name(pair);
859
860 if (nvpair_type(pair) == DATA_TYPE_NVLIST) {
861 /*
862 * This usually happens when we reuse the nvlist_t data
863 * returned by the counterpart dsl_prop_get_all_impl().
864 * For instance we do this to restore the original
865 * received properties when an error occurs in the
866 * zfs_ioc_recv() codepath.
867 */
868 nvlist_t *attrs = fnvpair_value_nvlist(pair);
869 pair = fnvlist_lookup_nvpair(attrs, ZPROP_VALUE);
870 }
871
872 if (nvpair_type(pair) == DATA_TYPE_STRING) {
873 const char *value = fnvpair_value_string(pair);
874 dsl_prop_set_sync_impl(ds, name,
875 source, 1, strlen(value) + 1, value, tx);
876 } else if (nvpair_type(pair) == DATA_TYPE_UINT64) {
877 uint64_t intval = fnvpair_value_uint64(pair);
878 dsl_prop_set_sync_impl(ds, name,
879 source, sizeof (intval), 1, &intval, tx);
880 } else if (nvpair_type(pair) == DATA_TYPE_BOOLEAN) {
881 dsl_prop_set_sync_impl(ds, name,
882 source, 0, 0, NULL, tx);
883 } else {
884 panic("invalid nvpair type");
885 }
886 }
887 }
888
889 static void
890 dsl_props_set_sync(void *arg, dmu_tx_t *tx)
891 {
892 dsl_props_set_arg_t *dpsa = arg;
893 dsl_pool_t *dp = dmu_tx_pool(tx);
894 dsl_dataset_t *ds;
895
896 VERIFY0(dsl_dataset_hold(dp, dpsa->dpsa_dsname, FTAG, &ds));
897 dsl_props_set_sync_impl(ds, dpsa->dpsa_source, dpsa->dpsa_props, tx);
898 dsl_dataset_rele(ds, FTAG);
899 }
900
901 /*
902 * All-or-nothing; if any prop can't be set, nothing will be modified.
903 */
904 int
905 dsl_props_set(const char *dsname, zprop_source_t source, nvlist_t *props)
906 {
907 dsl_props_set_arg_t dpsa;
908 int nblks = 0;
909
910 dpsa.dpsa_dsname = dsname;
911 dpsa.dpsa_source = source;
912 dpsa.dpsa_props = props;
913
914 /*
915 * If the source includes NONE, then we will only be removing entries
916 * from the ZAP object. In that case don't check for ENOSPC.
917 */
918 if ((source & ZPROP_SRC_NONE) == 0)
919 nblks = 2 * fnvlist_num_pairs(props);
920
921 return (dsl_sync_task(dsname, dsl_props_set_check, dsl_props_set_sync,
922 &dpsa, nblks, ZFS_SPACE_CHECK_RESERVED));
923 }
924
925 typedef enum dsl_prop_getflags {
926 DSL_PROP_GET_INHERITING = 0x1, /* searching parent of target ds */
927 DSL_PROP_GET_SNAPSHOT = 0x2, /* snapshot dataset */
928 DSL_PROP_GET_LOCAL = 0x4, /* local properties */
929 DSL_PROP_GET_RECEIVED = 0x8 /* received properties */
930 } dsl_prop_getflags_t;
931
932 static int
933 dsl_prop_get_all_impl(objset_t *mos, uint64_t propobj,
934 const char *setpoint, dsl_prop_getflags_t flags, nvlist_t *nv)
935 {
936 zap_cursor_t zc;
937 zap_attribute_t za;
938 int err = 0;
939
940 for (zap_cursor_init(&zc, mos, propobj);
941 (err = zap_cursor_retrieve(&zc, &za)) == 0;
942 zap_cursor_advance(&zc)) {
943 nvlist_t *propval;
944 zfs_prop_t prop;
1012 !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT))
1013 continue;
1014
1015 /* Skip properties already defined. */
1016 if (nvlist_exists(nv, propname))
1017 continue;
1018
1019 VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1020 if (za.za_integer_length == 1) {
1021 /*
1022 * String property
1023 */
1024 char *tmp = kmem_alloc(za.za_num_integers,
1025 KM_SLEEP);
1026 err = zap_lookup(mos, propobj,
1027 za.za_name, 1, za.za_num_integers, tmp);
1028 if (err != 0) {
1029 kmem_free(tmp, za.za_num_integers);
1030 break;
1031 }
1032 VERIFY(nvlist_add_string(propval, ZPROP_VALUE,
1033 tmp) == 0);
1034 kmem_free(tmp, za.za_num_integers);
1035 } else {
1036 /*
1037 * Integer property
1038 */
1039 ASSERT(za.za_integer_length == 8);
1040 (void) nvlist_add_uint64(propval, ZPROP_VALUE,
1041 za.za_first_integer);
1042 }
1043
1044 VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, source) == 0);
1045 VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
1046 nvlist_free(propval);
1047 }
1048 zap_cursor_fini(&zc);
1049 if (err == ENOENT)
1050 err = 0;
1051 return (err);
1052 }
1053
1054 /*
1055 * Iterate over all properties for this dataset and return them in an nvlist.
1056 */
1057 static int
1058 dsl_prop_get_all_ds(dsl_dataset_t *ds, nvlist_t **nvp,
1059 dsl_prop_getflags_t flags)
|
6 * You may not use this file except in compliance with the License.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
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 Martin Matuska. All rights reserved.
25 * Copyright 2015, Joyent, Inc.
26 * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
27 */
28
29 #include <sys/zfs_context.h>
30 #include <sys/dmu.h>
31 #include <sys/dmu_objset.h>
32 #include <sys/dmu_tx.h>
33 #include <sys/dsl_dataset.h>
34 #include <sys/dsl_dir.h>
35 #include <sys/dsl_prop.h>
36 #include <sys/dsl_synctask.h>
37 #include <sys/zfeature.h>
38 #include <sys/spa.h>
39 #include <sys/zap.h>
40 #include <sys/fs/zfs.h>
41 #include <sys/wbc.h>
42
43 #include "zfs_prop.h"
44 #include "zfs_errno.h"
45
46 static int
47 dodefault(zfs_prop_t prop, int intsz, int numints, void *buf)
48 {
49 /*
50 * The setonce properties are read-only, BUT they still
51 * have a default value that can be used as the initial
52 * value.
53 */
54 if (prop == ZPROP_INVAL ||
55 (zfs_prop_readonly(prop) && !zfs_prop_setonce(prop)))
56 return (SET_ERROR(ENOENT));
57
58 if (zfs_prop_get_type(prop) == PROP_TYPE_STRING) {
59 if (intsz != 1)
60 return (SET_ERROR(EOVERFLOW));
61 (void) strncpy(buf, zfs_prop_default_string(prop),
62 numints);
63 } else {
64 if (intsz != 8 || numints < 1)
65 return (SET_ERROR(EOVERFLOW));
271 /*
272 * Register interest in the named property. We'll call the callback
273 * once to notify it of the current property value, and again each time
274 * the property changes, until this callback is unregistered.
275 *
276 * Return 0 on success, errno if the prop is not an integer value.
277 */
278 int
279 dsl_prop_register(dsl_dataset_t *ds, const char *propname,
280 dsl_prop_changed_cb_t *callback, void *cbarg)
281 {
282 dsl_dir_t *dd = ds->ds_dir;
283 dsl_pool_t *dp = dd->dd_pool;
284 uint64_t value;
285 dsl_prop_record_t *pr;
286 dsl_prop_cb_record_t *cbr;
287 int err;
288
289 ASSERT(dsl_pool_config_held(dp));
290
291 if (zfs_name_to_prop(propname) == ZFS_PROP_WBC_MODE) {
292 wbc_mode_prop_val_t val;
293
294 err = dsl_prop_get_ds(ds, propname, 8,
295 WBC_MODE_PROP_VAL_SZ, &val, NULL);
296 if (err == 0)
297 value = (uintptr_t)((void *)&val);
298 } else
299 err = dsl_prop_get_int_ds(ds, propname, &value);
300
301 if (err != 0)
302 return (err);
303
304 cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP);
305 cbr->cbr_ds = ds;
306 cbr->cbr_func = callback;
307 cbr->cbr_arg = cbarg;
308
309 mutex_enter(&dd->dd_lock);
310 pr = dsl_prop_record_find(dd, propname);
311 if (pr == NULL)
312 pr = dsl_prop_record_create(dd, propname);
313 cbr->cbr_pr = pr;
314 list_insert_head(&pr->pr_cbs, cbr);
315 list_insert_head(&ds->ds_prop_cbs, cbr);
316 mutex_exit(&dd->dd_lock);
317
318 cbr->cbr_func(cbr->cbr_arg, value);
319 return (0);
320 }
470 boolean_t
471 dsl_prop_hascb(dsl_dataset_t *ds)
472 {
473 return (!list_is_empty(&ds->ds_prop_cbs));
474 }
475
476 /* ARGSUSED */
477 static int
478 dsl_prop_notify_all_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg)
479 {
480 dsl_dir_t *dd = ds->ds_dir;
481 dsl_prop_record_t *pr;
482 dsl_prop_cb_record_t *cbr;
483
484 mutex_enter(&dd->dd_lock);
485 for (pr = list_head(&dd->dd_props);
486 pr; pr = list_next(&dd->dd_props, pr)) {
487 for (cbr = list_head(&pr->pr_cbs); cbr;
488 cbr = list_next(&pr->pr_cbs, cbr)) {
489 uint64_t value;
490 const char *propname;
491
492 /*
493 * Callback entries do not have holds on their
494 * datasets so that datasets with registered
495 * callbacks are still eligible for eviction.
496 * Unlike operations to update properties on a
497 * single dataset, we are performing a recursive
498 * descent of related head datasets. The caller
499 * of this function only has a dataset hold on
500 * the passed in head dataset, not the snapshots
501 * associated with this dataset. Without a hold,
502 * the dataset pointer within callback records
503 * for snapshots can be invalidated by eviction
504 * at any time.
505 *
506 * Use dsl_dataset_try_add_ref() to verify
507 * that the dataset for a snapshot has not
508 * begun eviction processing and to prevent
509 * eviction from occurring for the duration of
510 * the callback. If the hold attempt fails,
511 * this object is already being evicted and the
512 * callback can be safely ignored.
513 */
514 if (ds != cbr->cbr_ds &&
515 !dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG))
516 continue;
517
518 propname = cbr->cbr_pr->pr_propname;
519 if (zfs_name_to_prop(propname) == ZFS_PROP_WBC_MODE) {
520 wbc_mode_prop_val_t val;
521
522 if (dsl_prop_get_ds(cbr->cbr_ds, propname, 8,
523 WBC_MODE_PROP_VAL_SZ, &val, NULL) == 0) {
524 value = (uintptr_t)((void *)&val);
525 cbr->cbr_func(cbr->cbr_arg, value);
526 }
527 } else if (dsl_prop_get_ds(cbr->cbr_ds, propname,
528 sizeof (value), 1, &value, NULL) == 0) {
529 cbr->cbr_func(cbr->cbr_arg, value);
530 }
531
532 if (ds != cbr->cbr_ds)
533 dsl_dataset_rele(cbr->cbr_ds, FTAG);
534 }
535 }
536 mutex_exit(&dd->dd_lock);
537
538 return (0);
539 }
540
541 /*
542 * Update all property values for ddobj & its descendants. This is used
543 * when renaming the dir.
544 */
545 void
546 dsl_prop_notify_all(dsl_dir_t *dd)
547 {
548 dsl_pool_t *dp = dd->dd_pool;
549 ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock));
550 (void) dmu_objset_find_dp(dp, dd->dd_object, dsl_prop_notify_all_cb,
623 }
624 kmem_free(za, sizeof (zap_attribute_t));
625 zap_cursor_fini(&zc);
626 dsl_dir_rele(dd, FTAG);
627 }
628
629 void
630 dsl_prop_set_sync_impl(dsl_dataset_t *ds, const char *propname,
631 zprop_source_t source, int intsz, int numints, const void *value,
632 dmu_tx_t *tx)
633 {
634 objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
635 uint64_t zapobj, intval, dummy;
636 int isint;
637 char valbuf[32];
638 const char *valstr = NULL;
639 char *inheritstr;
640 char *recvdstr;
641 char *tbuf = NULL;
642 int err;
643 spa_t *spa = ds->ds_dir->dd_pool->dp_spa;
644 uint64_t version = spa_version(spa);
645
646 isint = (dodefault(zfs_name_to_prop(propname), 8, 1, &intval) == 0);
647
648 if (ds->ds_is_snapshot) {
649 ASSERT(version >= SPA_VERSION_SNAP_PROPS);
650 if (dsl_dataset_phys(ds)->ds_props_obj == 0) {
651 dmu_buf_will_dirty(ds->ds_dbuf, tx);
652 dsl_dataset_phys(ds)->ds_props_obj =
653 zap_create(mos,
654 DMU_OT_DSL_PROPS, DMU_OT_NONE, 0, tx);
655 }
656 zapobj = dsl_dataset_phys(ds)->ds_props_obj;
657 } else {
658 zapobj = dsl_dir_phys(ds->ds_dir)->dd_props_zapobj;
659 }
660
661 if (version < SPA_VERSION_RECVD_PROPS) {
662 if (source & ZPROP_SRC_NONE)
663 source = ZPROP_SRC_NONE;
664 else if (source & ZPROP_SRC_RECEIVED)
722 */
723 err = zap_remove(mos, zapobj, propname, tx);
724 ASSERT(err == 0 || err == ENOENT);
725 err = zap_remove(mos, zapobj, inheritstr, tx);
726 ASSERT(err == 0 || err == ENOENT);
727 /* FALLTHRU */
728 case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED):
729 /*
730 * remove propname$recvd
731 */
732 err = zap_remove(mos, zapobj, recvdstr, tx);
733 ASSERT(err == 0 || err == ENOENT);
734 break;
735 default:
736 cmn_err(CE_PANIC, "unexpected property source: %d", source);
737 }
738
739 strfree(inheritstr);
740 strfree(recvdstr);
741
742 if (zfs_name_to_prop(propname) == ZFS_PROP_WBC_MODE) {
743 wbc_mode_prop_val_t val;
744
745 VERIFY0(dsl_prop_get_ds(ds, propname, 8,
746 WBC_MODE_PROP_VAL_SZ, &val, NULL));
747
748 dsl_prop_changed_notify(ds->ds_dir->dd_pool,
749 ds->ds_dir->dd_object, propname,
750 (uintptr_t)((void *)&val), TRUE);
751
752 /*
753 * Flow diagram of ZFS_PROP_WBC_MODE states
754 *
755 * off (root_ds_object == 0, txg_off == 0)
756 * (user sees wbc_mode=off, source=default)
757 *
758 * user operation "set on" ==>>
759 *
760 * on (root_ds_object != 0, txg_off == 0)
761 * (user sees wbc_mode=on, source=local)
762 *
763 * user operation "set off" ==>>
764 *
765 * off_delayed (root_ds_object != 0, txg_off != 0)
766 * (user sees wbc_mode=off, source=local)
767 *
768 * internal operation "inherit" ==>>
769 *
770 * off (root_ds_object == 0, txg_off == 0)
771 * (user sees wbc_mode=off, source=default)
772 */
773 if (val.root_ds_object == 0)
774 spa_feature_decr(spa, SPA_FEATURE_WBC, tx);
775 else if (val.txg_off == 0)
776 spa_feature_incr(spa, SPA_FEATURE_WBC, tx);
777
778 (void) snprintf(valbuf, sizeof (valbuf),
779 "%s", (val.root_ds_object != 0 &&
780 val.txg_off == 0) ? "on" : "off");
781 valstr = valbuf;
782 } else if (isint) {
783 VERIFY0(dsl_prop_get_int_ds(ds, propname, &intval));
784
785 if (ds->ds_is_snapshot) {
786 dsl_prop_cb_record_t *cbr;
787 /*
788 * It's a snapshot; nothing can inherit this
789 * property, so just look for callbacks on this
790 * ds here.
791 */
792 mutex_enter(&ds->ds_dir->dd_lock);
793 for (cbr = list_head(&ds->ds_prop_cbs); cbr;
794 cbr = list_next(&ds->ds_prop_cbs, cbr)) {
795 if (strcmp(cbr->cbr_pr->pr_propname,
796 propname) == 0)
797 cbr->cbr_func(cbr->cbr_arg, intval);
798 }
799 mutex_exit(&ds->ds_dir->dd_lock);
800 } else {
801 dsl_prop_changed_notify(ds->ds_dir->dd_pool,
802 ds->ds_dir->dd_object, propname, intval, TRUE);
846
847 fnvlist_add_string(nvl, propname, value);
848 error = dsl_props_set(dsname, source, nvl);
849 fnvlist_free(nvl);
850 return (error);
851 }
852
853 int
854 dsl_prop_inherit(const char *dsname, const char *propname,
855 zprop_source_t source)
856 {
857 nvlist_t *nvl = fnvlist_alloc();
858 int error;
859
860 fnvlist_add_boolean(nvl, propname);
861 error = dsl_props_set(dsname, source, nvl);
862 fnvlist_free(nvl);
863 return (error);
864 }
865
866 /* ARGSUSED */
867 static int
868 dsl_prop_wbc_mode_check_child_cb(dsl_pool_t *dp,
869 dsl_dataset_t *ds, void *arg)
870 {
871 int err;
872 zfs_prop_t *prop = arg;
873 objset_t *os = NULL;
874
875 err = dmu_objset_from_ds(ds, &os);
876 if (err != 0)
877 return (err);
878
879 if (*prop == ZFS_PROP_DEDUP) {
880 /*
881 * User tries to set ZFS_PROP_DEDUP.
882 * In this case we just check that
883 * the target DS and its children
884 * do not use writecache
885 */
886 if (os->os_wbc_mode != ZFS_WBC_MODE_OFF)
887 return (SET_ERROR(EKZFS_WBCCONFLICT));
888 } else {
889 ASSERT3U(*prop, ==, ZFS_PROP_WBC_MODE);
890
891 /*
892 * User tries to set ZFS_PROP_WBC_MODE.
893 * In this case we need check that
894 * the target DS and its children
895 * do not use writecache and dedup
896 */
897 if (os->os_wbc_mode != ZFS_WBC_MODE_OFF)
898 return (SET_ERROR(EKZFS_WBCCHILD));
899
900 if (os->os_dedup_checksum != ZIO_CHECKSUM_OFF)
901 return (SET_ERROR(EKZFS_WBCCONFLICT));
902 }
903
904 return (0);
905 }
906
907 static int
908 dsl_prop_wbc_mode_check(dsl_dataset_t *ds, objset_t *os)
909 {
910 int err = 0;
911 zfs_prop_t prop = ZFS_PROP_WBC_MODE;
912
913 if (os->os_wbc_mode != ZFS_WBC_MODE_OFF) {
914 /*
915 * ZFS_PROP_WBC_MODE cannot be set for
916 * a child DS if the prop was set for
917 * the parent
918 */
919 if (os->os_wbc_root_ds_obj != ds->ds_object)
920 return (SET_ERROR(EKZFS_WBCPARENT));
921 } else {
922 /*
923 * Is not allowed to change wbc_mode for parent
924 * if its children already have the changed prop
925 */
926 err = dmu_objset_find_dp(ds->ds_dir->dd_pool,
927 ds->ds_dir->dd_object,
928 dsl_prop_wbc_mode_check_child_cb, &prop,
929 DS_FIND_CHILDREN);
930 }
931
932 return (err);
933 }
934
935 typedef struct dsl_props_set_arg {
936 const char *dpsa_dsname;
937 zprop_source_t dpsa_source;
938 nvlist_t *dpsa_props;
939 } dsl_props_set_arg_t;
940
941 static int
942 dsl_props_set_check(void *arg, dmu_tx_t *tx)
943 {
944 dsl_props_set_arg_t *dpsa = arg;
945 dsl_pool_t *dp = dmu_tx_pool(tx);
946 dsl_dataset_t *ds;
947 objset_t *os = NULL;
948 uint64_t version;
949 nvpair_t *elem = NULL;
950 int err;
951
952 err = dsl_dataset_hold(dp, dpsa->dpsa_dsname, FTAG, &ds);
953 if (err != 0)
954 return (err);
955
956 err = dmu_objset_from_ds(ds, &os);
957 if (err != 0) {
958 dsl_dataset_rele(ds, FTAG);
959 return (err);
960 }
961
962 version = spa_version(ds->ds_dir->dd_pool->dp_spa);
963 while ((elem = nvlist_next_nvpair(dpsa->dpsa_props, elem)) != NULL) {
964 const char *prop_name = nvpair_name(elem);
965 zfs_prop_t prop = zfs_name_to_prop(prop_name);
966
967 if (strlen(prop_name) >= ZAP_MAXNAMELEN) {
968 dsl_dataset_rele(ds, FTAG);
969 return (SET_ERROR(ENAMETOOLONG));
970 }
971
972 /*
973 * Deduplication and WBC cannot be used together
974 * This code returns error also for case when
975 * WBC is ON, DEDUP is off and a user tries
976 * to do DEDUP=off, because in this case the code
977 * will be more complex, but benefit is too small
978 */
979 if (prop == ZFS_PROP_DEDUP) {
980 if (os->os_wbc_root_ds_obj != 0) {
981 dsl_dataset_rele(ds, FTAG);
982 return (SET_ERROR(EKZFS_WBCCONFLICT));
983 }
984
985 /*
986 * Need to be sure that children DS
987 * do not use writecache
988 */
989 err = dmu_objset_find_dp(ds->ds_dir->dd_pool,
990 ds->ds_dir->dd_object,
991 dsl_prop_wbc_mode_check_child_cb, &prop,
992 DS_FIND_CHILDREN);
993 if (err != 0) {
994 dsl_dataset_rele(ds, FTAG);
995 return (err);
996 }
997 }
998
999 if (prop == ZFS_PROP_WBC_MODE) {
1000 uint64_t wbc_mode_new = 0;
1001 data_type_t elem_type = nvpair_type(elem);
1002
1003 if (elem_type == DATA_TYPE_UINT64)
1004 wbc_mode_new = fnvpair_value_uint64(elem);
1005
1006 if (os->os_wbc_root_ds_obj == ds->ds_object &&
1007 elem_type == DATA_TYPE_UINT64) {
1008
1009 /*
1010 * ZFS_WBC_MODE_OFF_DELAYED means that
1011 * the coresponding wbc_instance is in
1012 * transition state: from ON to OFF
1013 * so ON/OFF is not permitted
1014 */
1015 if (os->os_wbc_mode ==
1016 ZFS_WBC_MODE_OFF_DELAYED) {
1017 dsl_dataset_rele(ds, FTAG);
1018 return (SET_ERROR(EINPROGRESS));
1019 }
1020
1021 ASSERT3U(os->os_wbc_mode, ==, ZFS_WBC_MODE_ON);
1022
1023 /* Check for double ON */
1024 if (wbc_mode_new == ZFS_WBC_MODE_ON) {
1025 dsl_dataset_rele(ds, FTAG);
1026 return (SET_ERROR(EALREADY));
1027 }
1028 }
1029
1030 err = dsl_prop_wbc_mode_check(ds, os);
1031 if (err != 0) {
1032 dsl_dataset_rele(ds, FTAG);
1033 return (err);
1034 }
1035
1036 /* Check for double OFF */
1037 if (os->os_wbc_root_ds_obj == 0 &&
1038 elem_type == DATA_TYPE_UINT64 &&
1039 wbc_mode_new == ZFS_WBC_MODE_OFF) {
1040 dsl_dataset_rele(ds, FTAG);
1041 return (SET_ERROR(EALREADY));
1042 }
1043
1044 continue;
1045 }
1046
1047 if (nvpair_type(elem) == DATA_TYPE_STRING) {
1048 char *valstr = fnvpair_value_string(elem);
1049 if (strlen(valstr) >= (version <
1050 SPA_VERSION_STMF_PROP ?
1051 ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) {
1052 dsl_dataset_rele(ds, FTAG);
1053 return (SET_ERROR(E2BIG));
1054 }
1055 }
1056
1057 }
1058
1059 if (ds->ds_is_snapshot && version < SPA_VERSION_SNAP_PROPS) {
1060 dsl_dataset_rele(ds, FTAG);
1061 return (SET_ERROR(ENOTSUP));
1062 }
1063 dsl_dataset_rele(ds, FTAG);
1064 return (0);
1065 }
1066
1067 void
1068 dsl_props_set_sync_impl(dsl_dataset_t *ds, zprop_source_t source,
1069 nvlist_t *props, dmu_tx_t *tx)
1070 {
1071 nvpair_t *elem = NULL;
1072
1073 while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
1074 nvpair_t *pair = elem;
1075
1076 if (nvpair_type(pair) == DATA_TYPE_NVLIST) {
1077 /*
1078 * dsl_prop_get_all_impl() returns properties in this
1079 * format.
1080 */
1081 nvlist_t *attrs = fnvpair_value_nvlist(pair);
1082 pair = fnvlist_lookup_nvpair(attrs, ZPROP_VALUE);
1083 }
1084
1085 if (nvpair_type(pair) == DATA_TYPE_STRING) {
1086 const char *value = fnvpair_value_string(pair);
1087 dsl_prop_set_sync_impl(ds, nvpair_name(pair),
1088 source, 1, strlen(value) + 1, value, tx);
1089 } else if (nvpair_type(pair) == DATA_TYPE_UINT64) {
1090 const char *propname = nvpair_name(pair);
1091 zfs_prop_t prop = zfs_name_to_prop(propname);
1092 uint64_t intval = fnvpair_value_uint64(pair);
1093
1094 if (prop == ZFS_PROP_WBC_MODE) {
1095 wbc_mode_prop_val_t val;
1096
1097 /*
1098 * Disabling WBC involves the following:
1099 * 1) all the subsequent data writes will
1100 * stop using special vdev
1101 * 2) already WriteBackCached data blocks
1102 * (with TXG <= txg_off below) will gradually
1103 * migrated from special vdev
1104 *
1105 * To handle this need to remember TXG.
1106 * WBC will be completely disabled for this DS,
1107 * after WBC-window cross this TXG
1108 */
1109 val.txg_off = (intval == 0) ? tx->tx_txg : 0;
1110 val.root_ds_object = ds->ds_object;
1111 val.flags = 0;
1112
1113 dsl_prop_set_sync_impl(ds, nvpair_name(pair),
1114 source, 8, WBC_MODE_PROP_VAL_SZ, &val, tx);
1115 } else {
1116 dsl_prop_set_sync_impl(ds, nvpair_name(pair),
1117 source, sizeof (intval), 1, &intval, tx);
1118 }
1119 } else if (nvpair_type(pair) == DATA_TYPE_BOOLEAN) {
1120 dsl_prop_set_sync_impl(ds, nvpair_name(pair),
1121 source, 0, 0, NULL, tx);
1122 } else {
1123 panic("invalid nvpair type");
1124 }
1125 }
1126 }
1127
1128 static void
1129 dsl_props_set_sync(void *arg, dmu_tx_t *tx)
1130 {
1131 dsl_props_set_arg_t *dpsa = arg;
1132 dsl_pool_t *dp = dmu_tx_pool(tx);
1133 dsl_dataset_t *ds;
1134 objset_t *os = NULL;
1135
1136 VERIFY0(dsl_dataset_hold(dp, dpsa->dpsa_dsname, FTAG, &ds));
1137 /*
1138 * Need to initialize os, to be sure that non-mounted datasets and
1139 * non-exposed zvols will receive notification about modified
1140 * properties.
1141 * During the initialization a property can register its callback
1142 * that will be called if the property is changed.
1143 * dsl_props_set_sync_impl() calls dsl_prop_changed_notify()
1144 * that calls the required callback if it exists.
1145 */
1146 VERIFY0(dmu_objset_from_ds(ds, &os));
1147 dsl_props_set_sync_impl(ds, dpsa->dpsa_source, dpsa->dpsa_props, tx);
1148 dsl_dataset_rele(ds, FTAG);
1149 }
1150
1151 /*
1152 * All-or-nothing; if any prop can't be set, nothing will be modified.
1153 */
1154 int
1155 dsl_props_set(const char *dsname, zprop_source_t source, nvlist_t *props)
1156 {
1157 dsl_props_set_arg_t dpsa;
1158 int nblks = 0;
1159
1160 dpsa.dpsa_dsname = dsname;
1161 dpsa.dpsa_source = source;
1162 dpsa.dpsa_props = props;
1163
1164 /*
1165 * If the source includes NONE, then we will only be removing entries
1166 * from the ZAP object. In that case don't check for ENOSPC.
1167 */
1168 if ((source & ZPROP_SRC_NONE) == 0)
1169 nblks = 2 * fnvlist_num_pairs(props);
1170
1171 return (dsl_sync_task(dsname, dsl_props_set_check, dsl_props_set_sync,
1172 &dpsa, nblks, ZFS_SPACE_CHECK_RESERVED));
1173 }
1174
1175 static void
1176 dsl_props_mds_set_sync(void *arg, dmu_tx_t *tx)
1177 {
1178 dsl_props_set_arg_t *top_dpsa = arg;
1179 dsl_pool_t *dp = dmu_tx_pool(tx);
1180 nvlist_t *dss_props = top_dpsa->dpsa_props;
1181 nvpair_t *pair = NULL;
1182
1183 while ((pair = nvlist_next_nvpair(dss_props, pair)) != NULL) {
1184 dsl_props_set_arg_t dpsa;
1185 dsl_dataset_t *ds = NULL;
1186 const char *ds_name;
1187
1188 ds_name = nvpair_name(pair);
1189 VERIFY0(dsl_dataset_hold(dp, ds_name, FTAG, &ds));
1190
1191 dpsa.dpsa_dsname = ds_name;
1192 dpsa.dpsa_source = ZPROP_SRC_LOCAL;
1193 dpsa.dpsa_props = fnvpair_value_nvlist(pair);
1194
1195 dsl_props_set_sync(&dpsa, tx);
1196 dsl_dataset_rele(ds, FTAG);
1197 }
1198 }
1199
1200 static int
1201 dsl_props_mds_set_check(void *arg, dmu_tx_t *tx)
1202 {
1203 dsl_props_set_arg_t *top_dpsa = arg;
1204 dsl_pool_t *dp = dmu_tx_pool(tx);
1205 nvlist_t *dss_props = top_dpsa->dpsa_props;
1206 nvpair_t *pair = NULL;
1207
1208 while ((pair = nvlist_next_nvpair(dss_props, pair)) != NULL) {
1209 dsl_props_set_arg_t dpsa;
1210 dsl_dataset_t *ds = NULL;
1211 const char *ds_name;
1212 int err;
1213
1214 ds_name = nvpair_name(pair);
1215 err = dsl_dataset_hold(dp, ds_name, FTAG, &ds);
1216 if (err != 0)
1217 return (err);
1218
1219 if (nvpair_type(pair) != DATA_TYPE_NVLIST) {
1220 dsl_dataset_rele(ds, FTAG);
1221 return (SET_ERROR(EINVAL));
1222 }
1223
1224 dpsa.dpsa_dsname = ds_name;
1225 dpsa.dpsa_source = ZPROP_SRC_LOCAL;
1226 dpsa.dpsa_props = fnvpair_value_nvlist(pair);
1227
1228 err = dsl_props_set_check(&dpsa, tx);
1229 dsl_dataset_rele(ds, FTAG);
1230 if (err != 0)
1231 return (err);
1232 }
1233
1234 return (0);
1235 }
1236
1237
1238 /*
1239 * The given 'dss_props' nvlist represents the following struct:
1240 * ds1 -> prop1:value
1241 * -> prop3:value
1242 * ds2 -> prop1:value
1243 * -> prop2:value
1244 *
1245 * All-or-nothing: if any prop can't be set, nothing will be modified.
1246 */
1247 int
1248 dsl_props_set_mds(const char *pool_name, nvlist_t *dss_props,
1249 size_t num_props)
1250 {
1251 dsl_props_set_arg_t dpsa;
1252
1253 dpsa.dpsa_dsname = pool_name;
1254 dpsa.dpsa_source = ZPROP_SRC_LOCAL;
1255 dpsa.dpsa_props = dss_props;
1256
1257 return (dsl_sync_task(pool_name, dsl_props_mds_set_check,
1258 dsl_props_mds_set_sync, &dpsa, 2 * num_props,
1259 ZFS_SPACE_CHECK_RESERVED));
1260 }
1261
1262 typedef enum dsl_prop_getflags {
1263 DSL_PROP_GET_INHERITING = 0x1, /* searching parent of target ds */
1264 DSL_PROP_GET_SNAPSHOT = 0x2, /* snapshot dataset */
1265 DSL_PROP_GET_LOCAL = 0x4, /* local properties */
1266 DSL_PROP_GET_RECEIVED = 0x8 /* received properties */
1267 } dsl_prop_getflags_t;
1268
1269 static int
1270 dsl_prop_get_all_impl(objset_t *mos, uint64_t propobj,
1271 const char *setpoint, dsl_prop_getflags_t flags, nvlist_t *nv)
1272 {
1273 zap_cursor_t zc;
1274 zap_attribute_t za;
1275 int err = 0;
1276
1277 for (zap_cursor_init(&zc, mos, propobj);
1278 (err = zap_cursor_retrieve(&zc, &za)) == 0;
1279 zap_cursor_advance(&zc)) {
1280 nvlist_t *propval;
1281 zfs_prop_t prop;
1349 !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT))
1350 continue;
1351
1352 /* Skip properties already defined. */
1353 if (nvlist_exists(nv, propname))
1354 continue;
1355
1356 VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1357 if (za.za_integer_length == 1) {
1358 /*
1359 * String property
1360 */
1361 char *tmp = kmem_alloc(za.za_num_integers,
1362 KM_SLEEP);
1363 err = zap_lookup(mos, propobj,
1364 za.za_name, 1, za.za_num_integers, tmp);
1365 if (err != 0) {
1366 kmem_free(tmp, za.za_num_integers);
1367 break;
1368 }
1369
1370 VERIFY(nvlist_add_string(propval, ZPROP_VALUE,
1371 tmp) == 0);
1372 kmem_free(tmp, za.za_num_integers);
1373 } else {
1374 /*
1375 * Integer property
1376 */
1377 ASSERT(za.za_integer_length == 8);
1378
1379 if (prop == ZFS_PROP_WBC_MODE) {
1380 wbc_mode_prop_val_t val;
1381
1382 ASSERT(za.za_num_integers ==
1383 WBC_MODE_PROP_VAL_SZ);
1384
1385 err = zap_lookup(mos, propobj,
1386 za.za_name, 8, za.za_num_integers, &val);
1387 if (err != 0)
1388 break;
1389
1390 if (val.root_ds_object != 0 &&
1391 val.txg_off == 0)
1392 za.za_first_integer = ZFS_WBC_MODE_ON;
1393 else
1394 za.za_first_integer = ZFS_WBC_MODE_OFF;
1395 }
1396
1397 (void) nvlist_add_uint64(propval, ZPROP_VALUE,
1398 za.za_first_integer);
1399 }
1400
1401 VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, source) == 0);
1402 VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
1403 nvlist_free(propval);
1404 }
1405 zap_cursor_fini(&zc);
1406 if (err == ENOENT)
1407 err = 0;
1408 return (err);
1409 }
1410
1411 /*
1412 * Iterate over all properties for this dataset and return them in an nvlist.
1413 */
1414 static int
1415 dsl_prop_get_all_ds(dsl_dataset_t *ds, nvlist_t **nvp,
1416 dsl_prop_getflags_t flags)
|