146 * that err has a valid post-loop value.
147 */
148 err = SET_ERROR(ENOENT);
149 }
150
151 if (err == ENOENT)
152 err = dodefault(propname, intsz, numints, buf);
153
154 strfree(inheritstr);
155 strfree(recvdstr);
156
157 return (err);
158 }
159
160 int
161 dsl_prop_get_ds(dsl_dataset_t *ds, const char *propname,
162 int intsz, int numints, void *buf, char *setpoint)
163 {
164 zfs_prop_t prop = zfs_name_to_prop(propname);
165 boolean_t inheritable;
166 boolean_t snapshot;
167 uint64_t zapobj;
168
169 ASSERT(dsl_pool_config_held(ds->ds_dir->dd_pool));
170 inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop));
171 snapshot = dsl_dataset_is_snapshot(ds);
172 zapobj = dsl_dataset_phys(ds)->ds_props_obj;
173
174 if (zapobj != 0) {
175 objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
176 int err;
177
178 ASSERT(snapshot);
179
180 /* Check for a local value. */
181 err = zap_lookup(mos, zapobj, propname, intsz, numints, buf);
182 if (err != ENOENT) {
183 if (setpoint != NULL && err == 0)
184 dsl_dataset_name(ds, setpoint);
185 return (err);
186 }
187
188 /*
189 * Skip the check for a received value if there is an explicit
190 * inheritance entry.
191 */
192 if (inheritable) {
193 char *inheritstr = kmem_asprintf("%s%s", propname,
194 ZPROP_INHERIT_SUFFIX);
195 err = zap_contains(mos, zapobj, inheritstr);
196 strfree(inheritstr);
197 if (err != 0 && err != ENOENT)
198 return (err);
199 }
200
201 if (err == ENOENT) {
202 /* Check for a received value. */
203 char *recvdstr = kmem_asprintf("%s%s", propname,
204 ZPROP_RECVD_SUFFIX);
205 err = zap_lookup(mos, zapobj, recvdstr,
206 intsz, numints, buf);
207 strfree(recvdstr);
208 if (err != ENOENT) {
209 if (setpoint != NULL && err == 0)
210 (void) strcpy(setpoint,
211 ZPROP_SOURCE_VAL_RECVD);
212 return (err);
213 }
214 }
215 }
216
217 return (dsl_prop_get_dd(ds->ds_dir, propname,
218 intsz, numints, buf, setpoint, snapshot));
219 }
220
221 /*
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.
225 *
226 * Return 0 on success, errno if the prop is not an integer value.
227 */
228 int
229 dsl_prop_register(dsl_dataset_t *ds, const char *propname,
230 dsl_prop_changed_cb_t *callback, void *cbarg)
231 {
232 dsl_dir_t *dd = ds->ds_dir;
233 dsl_pool_t *dp = dd->dd_pool;
234 uint64_t value;
235 dsl_prop_cb_record_t *cbr;
236 int err;
237
238 ASSERT(dsl_pool_config_held(dp));
528 }
529
530 void
531 dsl_prop_set_sync_impl(dsl_dataset_t *ds, const char *propname,
532 zprop_source_t source, int intsz, int numints, const void *value,
533 dmu_tx_t *tx)
534 {
535 objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
536 uint64_t zapobj, intval, dummy;
537 int isint;
538 char valbuf[32];
539 const char *valstr = NULL;
540 char *inheritstr;
541 char *recvdstr;
542 char *tbuf = NULL;
543 int err;
544 uint64_t version = spa_version(ds->ds_dir->dd_pool->dp_spa);
545
546 isint = (dodefault(propname, 8, 1, &intval) == 0);
547
548 if (dsl_dataset_is_snapshot(ds)) {
549 ASSERT(version >= SPA_VERSION_SNAP_PROPS);
550 if (dsl_dataset_phys(ds)->ds_props_obj == 0) {
551 dmu_buf_will_dirty(ds->ds_dbuf, tx);
552 dsl_dataset_phys(ds)->ds_props_obj =
553 zap_create(mos,
554 DMU_OT_DSL_PROPS, DMU_OT_NONE, 0, tx);
555 }
556 zapobj = dsl_dataset_phys(ds)->ds_props_obj;
557 } else {
558 zapobj = dsl_dir_phys(ds->ds_dir)->dd_props_zapobj;
559 }
560
561 if (version < SPA_VERSION_RECVD_PROPS) {
562 if (source & ZPROP_SRC_NONE)
563 source = ZPROP_SRC_NONE;
564 else if (source & ZPROP_SRC_RECEIVED)
565 source = ZPROP_SRC_LOCAL;
566 }
567
568 inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX);
625 err = zap_remove(mos, zapobj, inheritstr, tx);
626 ASSERT(err == 0 || err == ENOENT);
627 /* FALLTHRU */
628 case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED):
629 /*
630 * remove propname$recvd
631 */
632 err = zap_remove(mos, zapobj, recvdstr, tx);
633 ASSERT(err == 0 || err == ENOENT);
634 break;
635 default:
636 cmn_err(CE_PANIC, "unexpected property source: %d", source);
637 }
638
639 strfree(inheritstr);
640 strfree(recvdstr);
641
642 if (isint) {
643 VERIFY0(dsl_prop_get_int_ds(ds, propname, &intval));
644
645 if (dsl_dataset_is_snapshot(ds)) {
646 dsl_prop_cb_record_t *cbr;
647 /*
648 * It's a snapshot; nothing can inherit this
649 * property, so just look for callbacks on this
650 * ds here.
651 */
652 mutex_enter(&ds->ds_dir->dd_lock);
653 for (cbr = list_head(&ds->ds_dir->dd_prop_cbs); cbr;
654 cbr = list_next(&ds->ds_dir->dd_prop_cbs, cbr)) {
655 if (cbr->cbr_ds == ds &&
656 strcmp(cbr->cbr_propname, propname) == 0)
657 cbr->cbr_func(cbr->cbr_arg, intval);
658 }
659 mutex_exit(&ds->ds_dir->dd_lock);
660 } else {
661 dsl_prop_changed_notify(ds->ds_dir->dd_pool,
662 ds->ds_dir->dd_object, propname, intval, TRUE);
663 }
664
665 (void) snprintf(valbuf, sizeof (valbuf),
743 if (err != 0)
744 return (err);
745
746 version = spa_version(ds->ds_dir->dd_pool->dp_spa);
747 while ((elem = nvlist_next_nvpair(dpsa->dpsa_props, elem)) != NULL) {
748 if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) {
749 dsl_dataset_rele(ds, FTAG);
750 return (SET_ERROR(ENAMETOOLONG));
751 }
752 if (nvpair_type(elem) == DATA_TYPE_STRING) {
753 char *valstr = fnvpair_value_string(elem);
754 if (strlen(valstr) >= (version <
755 SPA_VERSION_STMF_PROP ?
756 ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) {
757 dsl_dataset_rele(ds, FTAG);
758 return (E2BIG);
759 }
760 }
761 }
762
763 if (dsl_dataset_is_snapshot(ds) && version < SPA_VERSION_SNAP_PROPS) {
764 dsl_dataset_rele(ds, FTAG);
765 return (SET_ERROR(ENOTSUP));
766 }
767 dsl_dataset_rele(ds, FTAG);
768 return (0);
769 }
770
771 void
772 dsl_props_set_sync_impl(dsl_dataset_t *ds, zprop_source_t source,
773 nvlist_t *props, dmu_tx_t *tx)
774 {
775 nvpair_t *elem = NULL;
776
777 while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
778 nvpair_t *pair = elem;
779
780 if (nvpair_type(pair) == DATA_TYPE_NVLIST) {
781 /*
782 * dsl_prop_get_all_impl() returns properties in this
783 * format.
966 if (err == ENOENT)
967 err = 0;
968 return (err);
969 }
970
971 /*
972 * Iterate over all properties for this dataset and return them in an nvlist.
973 */
974 static int
975 dsl_prop_get_all_ds(dsl_dataset_t *ds, nvlist_t **nvp,
976 dsl_prop_getflags_t flags)
977 {
978 dsl_dir_t *dd = ds->ds_dir;
979 dsl_pool_t *dp = dd->dd_pool;
980 objset_t *mos = dp->dp_meta_objset;
981 int err = 0;
982 char setpoint[MAXNAMELEN];
983
984 VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
985
986 if (dsl_dataset_is_snapshot(ds))
987 flags |= DSL_PROP_GET_SNAPSHOT;
988
989 ASSERT(dsl_pool_config_held(dp));
990
991 if (dsl_dataset_phys(ds)->ds_props_obj != 0) {
992 ASSERT(flags & DSL_PROP_GET_SNAPSHOT);
993 dsl_dataset_name(ds, setpoint);
994 err = dsl_prop_get_all_impl(mos,
995 dsl_dataset_phys(ds)->ds_props_obj, setpoint, flags, *nvp);
996 if (err)
997 goto out;
998 }
999
1000 for (; dd != NULL; dd = dd->dd_parent) {
1001 if (dd != ds->ds_dir || (flags & DSL_PROP_GET_SNAPSHOT)) {
1002 if (flags & (DSL_PROP_GET_LOCAL |
1003 DSL_PROP_GET_RECEIVED))
1004 break;
1005 flags |= DSL_PROP_GET_INHERITING;
1006 }
|
146 * that err has a valid post-loop value.
147 */
148 err = SET_ERROR(ENOENT);
149 }
150
151 if (err == ENOENT)
152 err = dodefault(propname, intsz, numints, buf);
153
154 strfree(inheritstr);
155 strfree(recvdstr);
156
157 return (err);
158 }
159
160 int
161 dsl_prop_get_ds(dsl_dataset_t *ds, const char *propname,
162 int intsz, int numints, void *buf, char *setpoint)
163 {
164 zfs_prop_t prop = zfs_name_to_prop(propname);
165 boolean_t inheritable;
166 uint64_t zapobj;
167
168 ASSERT(dsl_pool_config_held(ds->ds_dir->dd_pool));
169 inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop));
170 zapobj = dsl_dataset_phys(ds)->ds_props_obj;
171
172 if (zapobj != 0) {
173 objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
174 int err;
175
176 ASSERT(ds->ds_is_snapshot);
177
178 /* Check for a local value. */
179 err = zap_lookup(mos, zapobj, propname, intsz, numints, buf);
180 if (err != ENOENT) {
181 if (setpoint != NULL && err == 0)
182 dsl_dataset_name(ds, setpoint);
183 return (err);
184 }
185
186 /*
187 * Skip the check for a received value if there is an explicit
188 * inheritance entry.
189 */
190 if (inheritable) {
191 char *inheritstr = kmem_asprintf("%s%s", propname,
192 ZPROP_INHERIT_SUFFIX);
193 err = zap_contains(mos, zapobj, inheritstr);
194 strfree(inheritstr);
195 if (err != 0 && err != ENOENT)
196 return (err);
197 }
198
199 if (err == ENOENT) {
200 /* Check for a received value. */
201 char *recvdstr = kmem_asprintf("%s%s", propname,
202 ZPROP_RECVD_SUFFIX);
203 err = zap_lookup(mos, zapobj, recvdstr,
204 intsz, numints, buf);
205 strfree(recvdstr);
206 if (err != ENOENT) {
207 if (setpoint != NULL && err == 0)
208 (void) strcpy(setpoint,
209 ZPROP_SOURCE_VAL_RECVD);
210 return (err);
211 }
212 }
213 }
214
215 return (dsl_prop_get_dd(ds->ds_dir, propname,
216 intsz, numints, buf, setpoint, ds->ds_is_snapshot));
217 }
218
219 /*
220 * Register interest in the named property. We'll call the callback
221 * once to notify it of the current property value, and again each time
222 * the property changes, until this callback is unregistered.
223 *
224 * Return 0 on success, errno if the prop is not an integer value.
225 */
226 int
227 dsl_prop_register(dsl_dataset_t *ds, const char *propname,
228 dsl_prop_changed_cb_t *callback, void *cbarg)
229 {
230 dsl_dir_t *dd = ds->ds_dir;
231 dsl_pool_t *dp = dd->dd_pool;
232 uint64_t value;
233 dsl_prop_cb_record_t *cbr;
234 int err;
235
236 ASSERT(dsl_pool_config_held(dp));
526 }
527
528 void
529 dsl_prop_set_sync_impl(dsl_dataset_t *ds, const char *propname,
530 zprop_source_t source, int intsz, int numints, const void *value,
531 dmu_tx_t *tx)
532 {
533 objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
534 uint64_t zapobj, intval, dummy;
535 int isint;
536 char valbuf[32];
537 const char *valstr = NULL;
538 char *inheritstr;
539 char *recvdstr;
540 char *tbuf = NULL;
541 int err;
542 uint64_t version = spa_version(ds->ds_dir->dd_pool->dp_spa);
543
544 isint = (dodefault(propname, 8, 1, &intval) == 0);
545
546 if (ds->ds_is_snapshot) {
547 ASSERT(version >= SPA_VERSION_SNAP_PROPS);
548 if (dsl_dataset_phys(ds)->ds_props_obj == 0) {
549 dmu_buf_will_dirty(ds->ds_dbuf, tx);
550 dsl_dataset_phys(ds)->ds_props_obj =
551 zap_create(mos,
552 DMU_OT_DSL_PROPS, DMU_OT_NONE, 0, tx);
553 }
554 zapobj = dsl_dataset_phys(ds)->ds_props_obj;
555 } else {
556 zapobj = dsl_dir_phys(ds->ds_dir)->dd_props_zapobj;
557 }
558
559 if (version < SPA_VERSION_RECVD_PROPS) {
560 if (source & ZPROP_SRC_NONE)
561 source = ZPROP_SRC_NONE;
562 else if (source & ZPROP_SRC_RECEIVED)
563 source = ZPROP_SRC_LOCAL;
564 }
565
566 inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX);
623 err = zap_remove(mos, zapobj, inheritstr, tx);
624 ASSERT(err == 0 || err == ENOENT);
625 /* FALLTHRU */
626 case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED):
627 /*
628 * remove propname$recvd
629 */
630 err = zap_remove(mos, zapobj, recvdstr, tx);
631 ASSERT(err == 0 || err == ENOENT);
632 break;
633 default:
634 cmn_err(CE_PANIC, "unexpected property source: %d", source);
635 }
636
637 strfree(inheritstr);
638 strfree(recvdstr);
639
640 if (isint) {
641 VERIFY0(dsl_prop_get_int_ds(ds, propname, &intval));
642
643 if (ds->ds_is_snapshot) {
644 dsl_prop_cb_record_t *cbr;
645 /*
646 * It's a snapshot; nothing can inherit this
647 * property, so just look for callbacks on this
648 * ds here.
649 */
650 mutex_enter(&ds->ds_dir->dd_lock);
651 for (cbr = list_head(&ds->ds_dir->dd_prop_cbs); cbr;
652 cbr = list_next(&ds->ds_dir->dd_prop_cbs, cbr)) {
653 if (cbr->cbr_ds == ds &&
654 strcmp(cbr->cbr_propname, propname) == 0)
655 cbr->cbr_func(cbr->cbr_arg, intval);
656 }
657 mutex_exit(&ds->ds_dir->dd_lock);
658 } else {
659 dsl_prop_changed_notify(ds->ds_dir->dd_pool,
660 ds->ds_dir->dd_object, propname, intval, TRUE);
661 }
662
663 (void) snprintf(valbuf, sizeof (valbuf),
741 if (err != 0)
742 return (err);
743
744 version = spa_version(ds->ds_dir->dd_pool->dp_spa);
745 while ((elem = nvlist_next_nvpair(dpsa->dpsa_props, elem)) != NULL) {
746 if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) {
747 dsl_dataset_rele(ds, FTAG);
748 return (SET_ERROR(ENAMETOOLONG));
749 }
750 if (nvpair_type(elem) == DATA_TYPE_STRING) {
751 char *valstr = fnvpair_value_string(elem);
752 if (strlen(valstr) >= (version <
753 SPA_VERSION_STMF_PROP ?
754 ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) {
755 dsl_dataset_rele(ds, FTAG);
756 return (E2BIG);
757 }
758 }
759 }
760
761 if (ds->ds_is_snapshot && version < SPA_VERSION_SNAP_PROPS) {
762 dsl_dataset_rele(ds, FTAG);
763 return (SET_ERROR(ENOTSUP));
764 }
765 dsl_dataset_rele(ds, FTAG);
766 return (0);
767 }
768
769 void
770 dsl_props_set_sync_impl(dsl_dataset_t *ds, zprop_source_t source,
771 nvlist_t *props, dmu_tx_t *tx)
772 {
773 nvpair_t *elem = NULL;
774
775 while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
776 nvpair_t *pair = elem;
777
778 if (nvpair_type(pair) == DATA_TYPE_NVLIST) {
779 /*
780 * dsl_prop_get_all_impl() returns properties in this
781 * format.
964 if (err == ENOENT)
965 err = 0;
966 return (err);
967 }
968
969 /*
970 * Iterate over all properties for this dataset and return them in an nvlist.
971 */
972 static int
973 dsl_prop_get_all_ds(dsl_dataset_t *ds, nvlist_t **nvp,
974 dsl_prop_getflags_t flags)
975 {
976 dsl_dir_t *dd = ds->ds_dir;
977 dsl_pool_t *dp = dd->dd_pool;
978 objset_t *mos = dp->dp_meta_objset;
979 int err = 0;
980 char setpoint[MAXNAMELEN];
981
982 VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
983
984 if (ds->ds_is_snapshot)
985 flags |= DSL_PROP_GET_SNAPSHOT;
986
987 ASSERT(dsl_pool_config_held(dp));
988
989 if (dsl_dataset_phys(ds)->ds_props_obj != 0) {
990 ASSERT(flags & DSL_PROP_GET_SNAPSHOT);
991 dsl_dataset_name(ds, setpoint);
992 err = dsl_prop_get_all_impl(mos,
993 dsl_dataset_phys(ds)->ds_props_obj, setpoint, flags, *nvp);
994 if (err)
995 goto out;
996 }
997
998 for (; dd != NULL; dd = dd->dd_parent) {
999 if (dd != ds->ds_dir || (flags & DSL_PROP_GET_SNAPSHOT)) {
1000 if (flags & (DSL_PROP_GET_LOCAL |
1001 DSL_PROP_GET_RECEIVED))
1002 break;
1003 flags |= DSL_PROP_GET_INHERITING;
1004 }
|