1789Sahrens /*
2789Sahrens * CDDL HEADER START
3789Sahrens *
4789Sahrens * The contents of this file are subject to the terms of the
51544Seschrock * Common Development and Distribution License (the "License").
61544Seschrock * You may not use this file except in compliance with the License.
7789Sahrens *
8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9789Sahrens * or http://www.opensolaris.org/os/licensing.
10789Sahrens * See the License for the specific language governing permissions
11789Sahrens * and limitations under the License.
12789Sahrens *
13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each
14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15789Sahrens * If applicable, add the following below this CDDL HEADER, with the
16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying
17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner]
18789Sahrens *
19789Sahrens * CDDL HEADER END
20789Sahrens */
21789Sahrens /*
2212296SLin.Ling@Sun.COM * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23789Sahrens */
24789Sahrens
2511022STom.Erickson@Sun.COM #include <sys/zfs_context.h>
26789Sahrens #include <sys/dmu.h>
271356Seschrock #include <sys/dmu_objset.h>
28789Sahrens #include <sys/dmu_tx.h>
29789Sahrens #include <sys/dsl_dataset.h>
30789Sahrens #include <sys/dsl_dir.h>
31789Sahrens #include <sys/dsl_prop.h>
322199Sahrens #include <sys/dsl_synctask.h>
33789Sahrens #include <sys/spa.h>
34789Sahrens #include <sys/zap.h>
35789Sahrens #include <sys/fs/zfs.h>
36789Sahrens
37789Sahrens #include "zfs_prop.h"
38789Sahrens
3911022STom.Erickson@Sun.COM #define ZPROP_INHERIT_SUFFIX "$inherit"
4011022STom.Erickson@Sun.COM #define ZPROP_RECVD_SUFFIX "$recvd"
4111022STom.Erickson@Sun.COM
42789Sahrens static int
dodefault(const char * propname,int intsz,int numints,void * buf)4311022STom.Erickson@Sun.COM dodefault(const char *propname, int intsz, int numints, void *buf)
44789Sahrens {
45789Sahrens zfs_prop_t prop;
46789Sahrens
475331Samw /*
485331Samw * The setonce properties are read-only, BUT they still
495331Samw * have a default value that can be used as the initial
505331Samw * value.
515331Samw */
525094Slling if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL ||
535331Samw (zfs_prop_readonly(prop) && !zfs_prop_setonce(prop)))
54789Sahrens return (ENOENT);
55789Sahrens
564787Sahrens if (zfs_prop_get_type(prop) == PROP_TYPE_STRING) {
57789Sahrens if (intsz != 1)
58789Sahrens return (EOVERFLOW);
595094Slling (void) strncpy(buf, zfs_prop_default_string(prop),
6011022STom.Erickson@Sun.COM numints);
61789Sahrens } else {
6211022STom.Erickson@Sun.COM if (intsz != 8 || numints < 1)
63789Sahrens return (EOVERFLOW);
64789Sahrens
65789Sahrens *(uint64_t *)buf = zfs_prop_default_numeric(prop);
66789Sahrens }
67789Sahrens
68789Sahrens return (0);
69789Sahrens }
70789Sahrens
717265Sahrens int
dsl_prop_get_dd(dsl_dir_t * dd,const char * propname,int intsz,int numints,void * buf,char * setpoint,boolean_t snapshot)727265Sahrens dsl_prop_get_dd(dsl_dir_t *dd, const char *propname,
7311022STom.Erickson@Sun.COM int intsz, int numints, void *buf, char *setpoint, boolean_t snapshot)
74789Sahrens {
752082Seschrock int err = ENOENT;
7611022STom.Erickson@Sun.COM dsl_dir_t *target = dd;
777265Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset;
782676Seschrock zfs_prop_t prop;
7911022STom.Erickson@Sun.COM boolean_t inheritable;
8011022STom.Erickson@Sun.COM boolean_t inheriting = B_FALSE;
8111022STom.Erickson@Sun.COM char *inheritstr;
8211022STom.Erickson@Sun.COM char *recvdstr;
83789Sahrens
847265Sahrens ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock));
857265Sahrens
86789Sahrens if (setpoint)
87789Sahrens setpoint[0] = '\0';
88789Sahrens
892676Seschrock prop = zfs_name_to_prop(propname);
9011022STom.Erickson@Sun.COM inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop));
9111022STom.Erickson@Sun.COM inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX);
9211022STom.Erickson@Sun.COM recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX);
932676Seschrock
942082Seschrock /*
9511022STom.Erickson@Sun.COM * Note: dd may become NULL, therefore we shouldn't dereference it
9611022STom.Erickson@Sun.COM * after this loop.
972082Seschrock */
982082Seschrock for (; dd != NULL; dd = dd->dd_parent) {
992082Seschrock ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock));
10011022STom.Erickson@Sun.COM
10111022STom.Erickson@Sun.COM if (dd != target || snapshot) {
10211022STom.Erickson@Sun.COM if (!inheritable)
10311022STom.Erickson@Sun.COM break;
10411022STom.Erickson@Sun.COM inheriting = B_TRUE;
10511022STom.Erickson@Sun.COM }
10611022STom.Erickson@Sun.COM
10711022STom.Erickson@Sun.COM /* Check for a local value. */
10811022STom.Erickson@Sun.COM err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj, propname,
10911022STom.Erickson@Sun.COM intsz, numints, buf);
110789Sahrens if (err != ENOENT) {
11111022STom.Erickson@Sun.COM if (setpoint != NULL && err == 0)
112789Sahrens dsl_dir_name(dd, setpoint);
113789Sahrens break;
114789Sahrens }
1152676Seschrock
1162676Seschrock /*
11711022STom.Erickson@Sun.COM * Skip the check for a received value if there is an explicit
11811022STom.Erickson@Sun.COM * inheritance entry.
1192676Seschrock */
12011022STom.Erickson@Sun.COM err = zap_contains(mos, dd->dd_phys->dd_props_zapobj,
12111022STom.Erickson@Sun.COM inheritstr);
12211022STom.Erickson@Sun.COM if (err != 0 && err != ENOENT)
1232676Seschrock break;
12411022STom.Erickson@Sun.COM
12511022STom.Erickson@Sun.COM if (err == ENOENT) {
12611022STom.Erickson@Sun.COM /* Check for a received value. */
12711022STom.Erickson@Sun.COM err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj,
12811022STom.Erickson@Sun.COM recvdstr, intsz, numints, buf);
12911022STom.Erickson@Sun.COM if (err != ENOENT) {
13011022STom.Erickson@Sun.COM if (setpoint != NULL && err == 0) {
13111022STom.Erickson@Sun.COM if (inheriting) {
13211022STom.Erickson@Sun.COM dsl_dir_name(dd, setpoint);
13311022STom.Erickson@Sun.COM } else {
13411022STom.Erickson@Sun.COM (void) strcpy(setpoint,
13511022STom.Erickson@Sun.COM ZPROP_SOURCE_VAL_RECVD);
13611022STom.Erickson@Sun.COM }
13711022STom.Erickson@Sun.COM }
13811022STom.Erickson@Sun.COM break;
13911022STom.Erickson@Sun.COM }
14011022STom.Erickson@Sun.COM }
14111022STom.Erickson@Sun.COM
14211022STom.Erickson@Sun.COM /*
14311022STom.Erickson@Sun.COM * If we found an explicit inheritance entry, err is zero even
14411022STom.Erickson@Sun.COM * though we haven't yet found the value, so reinitializing err
14511022STom.Erickson@Sun.COM * at the end of the loop (instead of at the beginning) ensures
14611022STom.Erickson@Sun.COM * that err has a valid post-loop value.
14711022STom.Erickson@Sun.COM */
14811022STom.Erickson@Sun.COM err = ENOENT;
149789Sahrens }
15011022STom.Erickson@Sun.COM
151789Sahrens if (err == ENOENT)
15211022STom.Erickson@Sun.COM err = dodefault(propname, intsz, numints, buf);
15311022STom.Erickson@Sun.COM
15411022STom.Erickson@Sun.COM strfree(inheritstr);
15511022STom.Erickson@Sun.COM strfree(recvdstr);
156789Sahrens
157789Sahrens return (err);
158789Sahrens }
159789Sahrens
1607265Sahrens int
dsl_prop_get_ds(dsl_dataset_t * ds,const char * propname,int intsz,int numints,void * buf,char * setpoint)1617265Sahrens dsl_prop_get_ds(dsl_dataset_t *ds, const char *propname,
16211022STom.Erickson@Sun.COM int intsz, int numints, void *buf, char *setpoint)
1637265Sahrens {
16411022STom.Erickson@Sun.COM zfs_prop_t prop = zfs_name_to_prop(propname);
16511022STom.Erickson@Sun.COM boolean_t inheritable;
16611022STom.Erickson@Sun.COM boolean_t snapshot;
16711022STom.Erickson@Sun.COM uint64_t zapobj;
1687265Sahrens
16911022STom.Erickson@Sun.COM ASSERT(RW_LOCK_HELD(&ds->ds_dir->dd_pool->dp_config_rwlock));
17011022STom.Erickson@Sun.COM inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop));
17111022STom.Erickson@Sun.COM snapshot = (ds->ds_phys != NULL && dsl_dataset_is_snapshot(ds));
17211022STom.Erickson@Sun.COM zapobj = (ds->ds_phys == NULL ? 0 : ds->ds_phys->ds_props_obj);
17311022STom.Erickson@Sun.COM
17411022STom.Erickson@Sun.COM if (zapobj != 0) {
17511022STom.Erickson@Sun.COM objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
17611022STom.Erickson@Sun.COM int err;
17711022STom.Erickson@Sun.COM
17811022STom.Erickson@Sun.COM ASSERT(snapshot);
17911022STom.Erickson@Sun.COM
18011022STom.Erickson@Sun.COM /* Check for a local value. */
18111022STom.Erickson@Sun.COM err = zap_lookup(mos, zapobj, propname, intsz, numints, buf);
1827265Sahrens if (err != ENOENT) {
18311022STom.Erickson@Sun.COM if (setpoint != NULL && err == 0)
1847265Sahrens dsl_dataset_name(ds, setpoint);
1857265Sahrens return (err);
1867265Sahrens }
18711022STom.Erickson@Sun.COM
18811022STom.Erickson@Sun.COM /*
18911022STom.Erickson@Sun.COM * Skip the check for a received value if there is an explicit
19011022STom.Erickson@Sun.COM * inheritance entry.
19111022STom.Erickson@Sun.COM */
19211022STom.Erickson@Sun.COM if (inheritable) {
19311022STom.Erickson@Sun.COM char *inheritstr = kmem_asprintf("%s%s", propname,
19411022STom.Erickson@Sun.COM ZPROP_INHERIT_SUFFIX);
19511022STom.Erickson@Sun.COM err = zap_contains(mos, zapobj, inheritstr);
19611022STom.Erickson@Sun.COM strfree(inheritstr);
19711022STom.Erickson@Sun.COM if (err != 0 && err != ENOENT)
19811022STom.Erickson@Sun.COM return (err);
19911022STom.Erickson@Sun.COM }
20011022STom.Erickson@Sun.COM
20111022STom.Erickson@Sun.COM if (err == ENOENT) {
20211022STom.Erickson@Sun.COM /* Check for a received value. */
20311022STom.Erickson@Sun.COM char *recvdstr = kmem_asprintf("%s%s", propname,
20411022STom.Erickson@Sun.COM ZPROP_RECVD_SUFFIX);
20511022STom.Erickson@Sun.COM err = zap_lookup(mos, zapobj, recvdstr,
20611022STom.Erickson@Sun.COM intsz, numints, buf);
20711022STom.Erickson@Sun.COM strfree(recvdstr);
20811022STom.Erickson@Sun.COM if (err != ENOENT) {
20911022STom.Erickson@Sun.COM if (setpoint != NULL && err == 0)
21011022STom.Erickson@Sun.COM (void) strcpy(setpoint,
21111022STom.Erickson@Sun.COM ZPROP_SOURCE_VAL_RECVD);
21211022STom.Erickson@Sun.COM return (err);
21311022STom.Erickson@Sun.COM }
21411022STom.Erickson@Sun.COM }
2157265Sahrens }
2167265Sahrens
2177265Sahrens return (dsl_prop_get_dd(ds->ds_dir, propname,
21811022STom.Erickson@Sun.COM intsz, numints, buf, setpoint, snapshot));
2197265Sahrens }
2207265Sahrens
221789Sahrens /*
222789Sahrens * Register interest in the named property. We'll call the callback
223789Sahrens * once to notify it of the current property value, and again each time
224789Sahrens * the property changes, until this callback is unregistered.
225789Sahrens *
226789Sahrens * Return 0 on success, errno if the prop is not an integer value.
227789Sahrens */
228789Sahrens int
dsl_prop_register(dsl_dataset_t * ds,const char * propname,dsl_prop_changed_cb_t * callback,void * cbarg)229789Sahrens dsl_prop_register(dsl_dataset_t *ds, const char *propname,
230789Sahrens dsl_prop_changed_cb_t *callback, void *cbarg)
231789Sahrens {
2322082Seschrock dsl_dir_t *dd = ds->ds_dir;
2337265Sahrens dsl_pool_t *dp = dd->dd_pool;
234789Sahrens uint64_t value;
235789Sahrens dsl_prop_cb_record_t *cbr;
236789Sahrens int err;
2372199Sahrens int need_rwlock;
238789Sahrens
2397265Sahrens need_rwlock = !RW_WRITE_HELD(&dp->dp_config_rwlock);
2402199Sahrens if (need_rwlock)
2417265Sahrens rw_enter(&dp->dp_config_rwlock, RW_READER);
242789Sahrens
2437265Sahrens err = dsl_prop_get_ds(ds, propname, 8, 1, &value, NULL);
244789Sahrens if (err != 0) {
2455569Sck153898 if (need_rwlock)
2467265Sahrens rw_exit(&dp->dp_config_rwlock);
247789Sahrens return (err);
248789Sahrens }
249789Sahrens
250789Sahrens cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP);
2512082Seschrock cbr->cbr_ds = ds;
252789Sahrens cbr->cbr_propname = kmem_alloc(strlen(propname)+1, KM_SLEEP);
253789Sahrens (void) strcpy((char *)cbr->cbr_propname, propname);
254789Sahrens cbr->cbr_func = callback;
255789Sahrens cbr->cbr_arg = cbarg;
256789Sahrens mutex_enter(&dd->dd_lock);
257789Sahrens list_insert_head(&dd->dd_prop_cbs, cbr);
258789Sahrens mutex_exit(&dd->dd_lock);
259789Sahrens
260789Sahrens cbr->cbr_func(cbr->cbr_arg, value);
261789Sahrens
2622199Sahrens if (need_rwlock)
2637265Sahrens rw_exit(&dp->dp_config_rwlock);
264789Sahrens return (0);
265789Sahrens }
266789Sahrens
267789Sahrens int
dsl_prop_get(const char * dsname,const char * propname,int intsz,int numints,void * buf,char * setpoint)2687265Sahrens dsl_prop_get(const char *dsname, const char *propname,
2694543Smarks int intsz, int numints, void *buf, char *setpoint)
2704543Smarks {
2717265Sahrens dsl_dataset_t *ds;
272789Sahrens int err;
273789Sahrens
2747265Sahrens err = dsl_dataset_hold(dsname, FTAG, &ds);
2751544Seschrock if (err)
2761544Seschrock return (err);
277789Sahrens
2787265Sahrens rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER);
2797265Sahrens err = dsl_prop_get_ds(ds, propname, intsz, numints, buf, setpoint);
2807265Sahrens rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock);
281789Sahrens
2827265Sahrens dsl_dataset_rele(ds, FTAG);
283789Sahrens return (err);
284789Sahrens }
285789Sahrens
286789Sahrens /*
287789Sahrens * Get the current property value. It may have changed by the time this
288789Sahrens * function returns, so it is NOT safe to follow up with
289789Sahrens * dsl_prop_register() and assume that the value has not changed in
290789Sahrens * between.
291789Sahrens *
292789Sahrens * Return 0 on success, ENOENT if ddname is invalid.
293789Sahrens */
294789Sahrens int
dsl_prop_get_integer(const char * ddname,const char * propname,uint64_t * valuep,char * setpoint)295789Sahrens dsl_prop_get_integer(const char *ddname, const char *propname,
296789Sahrens uint64_t *valuep, char *setpoint)
297789Sahrens {
298789Sahrens return (dsl_prop_get(ddname, propname, 8, 1, valuep, setpoint));
299789Sahrens }
300789Sahrens
30111022STom.Erickson@Sun.COM void
dsl_prop_setarg_init_uint64(dsl_prop_setarg_t * psa,const char * propname,zprop_source_t source,uint64_t * value)30211022STom.Erickson@Sun.COM dsl_prop_setarg_init_uint64(dsl_prop_setarg_t *psa, const char *propname,
30311022STom.Erickson@Sun.COM zprop_source_t source, uint64_t *value)
30411022STom.Erickson@Sun.COM {
30511022STom.Erickson@Sun.COM psa->psa_name = propname;
30611022STom.Erickson@Sun.COM psa->psa_source = source;
30711022STom.Erickson@Sun.COM psa->psa_intsz = 8;
30811022STom.Erickson@Sun.COM psa->psa_numints = 1;
30911022STom.Erickson@Sun.COM psa->psa_value = value;
31011022STom.Erickson@Sun.COM
31111022STom.Erickson@Sun.COM psa->psa_effective_value = -1ULL;
31211022STom.Erickson@Sun.COM }
31311022STom.Erickson@Sun.COM
31411022STom.Erickson@Sun.COM /*
31511022STom.Erickson@Sun.COM * Predict the effective value of the given special property if it were set with
31611022STom.Erickson@Sun.COM * the given value and source. This is not a general purpose function. It exists
31711022STom.Erickson@Sun.COM * only to handle the special requirements of the quota and reservation
31811022STom.Erickson@Sun.COM * properties. The fact that these properties are non-inheritable greatly
31911022STom.Erickson@Sun.COM * simplifies the prediction logic.
32011022STom.Erickson@Sun.COM *
32111022STom.Erickson@Sun.COM * Returns 0 on success, a positive error code on failure, or -1 if called with
32211022STom.Erickson@Sun.COM * a property not handled by this function.
32311022STom.Erickson@Sun.COM */
32411022STom.Erickson@Sun.COM int
dsl_prop_predict_sync(dsl_dir_t * dd,dsl_prop_setarg_t * psa)32511022STom.Erickson@Sun.COM dsl_prop_predict_sync(dsl_dir_t *dd, dsl_prop_setarg_t *psa)
32611022STom.Erickson@Sun.COM {
32711022STom.Erickson@Sun.COM const char *propname = psa->psa_name;
32811022STom.Erickson@Sun.COM zfs_prop_t prop = zfs_name_to_prop(propname);
32911022STom.Erickson@Sun.COM zprop_source_t source = psa->psa_source;
33011022STom.Erickson@Sun.COM objset_t *mos;
33111022STom.Erickson@Sun.COM uint64_t zapobj;
33211022STom.Erickson@Sun.COM uint64_t version;
33311022STom.Erickson@Sun.COM char *recvdstr;
33411022STom.Erickson@Sun.COM int err = 0;
33511022STom.Erickson@Sun.COM
33611022STom.Erickson@Sun.COM switch (prop) {
33711022STom.Erickson@Sun.COM case ZFS_PROP_QUOTA:
33811022STom.Erickson@Sun.COM case ZFS_PROP_RESERVATION:
33911022STom.Erickson@Sun.COM case ZFS_PROP_REFQUOTA:
34011022STom.Erickson@Sun.COM case ZFS_PROP_REFRESERVATION:
34111022STom.Erickson@Sun.COM break;
34211022STom.Erickson@Sun.COM default:
34311022STom.Erickson@Sun.COM return (-1);
34411022STom.Erickson@Sun.COM }
34511022STom.Erickson@Sun.COM
34611022STom.Erickson@Sun.COM mos = dd->dd_pool->dp_meta_objset;
34711022STom.Erickson@Sun.COM zapobj = dd->dd_phys->dd_props_zapobj;
34811022STom.Erickson@Sun.COM recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX);
34911022STom.Erickson@Sun.COM
35011022STom.Erickson@Sun.COM version = spa_version(dd->dd_pool->dp_spa);
35111022STom.Erickson@Sun.COM if (version < SPA_VERSION_RECVD_PROPS) {
35211022STom.Erickson@Sun.COM if (source & ZPROP_SRC_NONE)
35311022STom.Erickson@Sun.COM source = ZPROP_SRC_NONE;
35411022STom.Erickson@Sun.COM else if (source & ZPROP_SRC_RECEIVED)
35511022STom.Erickson@Sun.COM source = ZPROP_SRC_LOCAL;
35611022STom.Erickson@Sun.COM }
35711022STom.Erickson@Sun.COM
35811022STom.Erickson@Sun.COM switch (source) {
35911022STom.Erickson@Sun.COM case ZPROP_SRC_NONE:
36011022STom.Erickson@Sun.COM /* Revert to the received value, if any. */
36111022STom.Erickson@Sun.COM err = zap_lookup(mos, zapobj, recvdstr, 8, 1,
36211022STom.Erickson@Sun.COM &psa->psa_effective_value);
36311022STom.Erickson@Sun.COM if (err == ENOENT)
36411022STom.Erickson@Sun.COM psa->psa_effective_value = 0;
36511022STom.Erickson@Sun.COM break;
36611022STom.Erickson@Sun.COM case ZPROP_SRC_LOCAL:
36711022STom.Erickson@Sun.COM psa->psa_effective_value = *(uint64_t *)psa->psa_value;
36811022STom.Erickson@Sun.COM break;
36911022STom.Erickson@Sun.COM case ZPROP_SRC_RECEIVED:
37011022STom.Erickson@Sun.COM /*
37111022STom.Erickson@Sun.COM * If there's no local setting, then the new received value will
37211022STom.Erickson@Sun.COM * be the effective value.
37311022STom.Erickson@Sun.COM */
37411022STom.Erickson@Sun.COM err = zap_lookup(mos, zapobj, propname, 8, 1,
37511022STom.Erickson@Sun.COM &psa->psa_effective_value);
37611022STom.Erickson@Sun.COM if (err == ENOENT)
37711022STom.Erickson@Sun.COM psa->psa_effective_value = *(uint64_t *)psa->psa_value;
37811022STom.Erickson@Sun.COM break;
37911022STom.Erickson@Sun.COM case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED):
38011022STom.Erickson@Sun.COM /*
38111022STom.Erickson@Sun.COM * We're clearing the received value, so the local setting (if
38211022STom.Erickson@Sun.COM * it exists) remains the effective value.
38311022STom.Erickson@Sun.COM */
38411022STom.Erickson@Sun.COM err = zap_lookup(mos, zapobj, propname, 8, 1,
38511022STom.Erickson@Sun.COM &psa->psa_effective_value);
38611022STom.Erickson@Sun.COM if (err == ENOENT)
38711022STom.Erickson@Sun.COM psa->psa_effective_value = 0;
38811022STom.Erickson@Sun.COM break;
38911022STom.Erickson@Sun.COM default:
39011022STom.Erickson@Sun.COM cmn_err(CE_PANIC, "unexpected property source: %d", source);
39111022STom.Erickson@Sun.COM }
39211022STom.Erickson@Sun.COM
39311022STom.Erickson@Sun.COM strfree(recvdstr);
39411022STom.Erickson@Sun.COM
39511022STom.Erickson@Sun.COM if (err == ENOENT)
39611022STom.Erickson@Sun.COM return (0);
39711022STom.Erickson@Sun.COM
39811022STom.Erickson@Sun.COM return (err);
39911022STom.Erickson@Sun.COM }
40011022STom.Erickson@Sun.COM
40111022STom.Erickson@Sun.COM #ifdef ZFS_DEBUG
40211022STom.Erickson@Sun.COM void
dsl_prop_check_prediction(dsl_dir_t * dd,dsl_prop_setarg_t * psa)40311022STom.Erickson@Sun.COM dsl_prop_check_prediction(dsl_dir_t *dd, dsl_prop_setarg_t *psa)
40411022STom.Erickson@Sun.COM {
40511022STom.Erickson@Sun.COM zfs_prop_t prop = zfs_name_to_prop(psa->psa_name);
40611022STom.Erickson@Sun.COM uint64_t intval;
40711022STom.Erickson@Sun.COM char setpoint[MAXNAMELEN];
40811022STom.Erickson@Sun.COM uint64_t version = spa_version(dd->dd_pool->dp_spa);
40911022STom.Erickson@Sun.COM int err;
41011022STom.Erickson@Sun.COM
41111022STom.Erickson@Sun.COM if (version < SPA_VERSION_RECVD_PROPS) {
41211022STom.Erickson@Sun.COM switch (prop) {
41311022STom.Erickson@Sun.COM case ZFS_PROP_QUOTA:
41411022STom.Erickson@Sun.COM case ZFS_PROP_RESERVATION:
41511022STom.Erickson@Sun.COM return;
41611022STom.Erickson@Sun.COM }
41711022STom.Erickson@Sun.COM }
41811022STom.Erickson@Sun.COM
41911022STom.Erickson@Sun.COM err = dsl_prop_get_dd(dd, psa->psa_name, 8, 1, &intval,
42011022STom.Erickson@Sun.COM setpoint, B_FALSE);
42111022STom.Erickson@Sun.COM if (err == 0 && intval != psa->psa_effective_value) {
42211022STom.Erickson@Sun.COM cmn_err(CE_PANIC, "%s property, source: %x, "
42311022STom.Erickson@Sun.COM "predicted effective value: %llu, "
42411022STom.Erickson@Sun.COM "actual effective value: %llu (setpoint: %s)",
42511022STom.Erickson@Sun.COM psa->psa_name, psa->psa_source,
42611022STom.Erickson@Sun.COM (unsigned long long)psa->psa_effective_value,
42711022STom.Erickson@Sun.COM (unsigned long long)intval, setpoint);
42811022STom.Erickson@Sun.COM }
42911022STom.Erickson@Sun.COM }
43011022STom.Erickson@Sun.COM #endif
43111022STom.Erickson@Sun.COM
432789Sahrens /*
433789Sahrens * Unregister this callback. Return 0 on success, ENOENT if ddname is
434789Sahrens * invalid, ENOMSG if no matching callback registered.
435789Sahrens */
436789Sahrens int
dsl_prop_unregister(dsl_dataset_t * ds,const char * propname,dsl_prop_changed_cb_t * callback,void * cbarg)437789Sahrens dsl_prop_unregister(dsl_dataset_t *ds, const char *propname,
438789Sahrens dsl_prop_changed_cb_t *callback, void *cbarg)
439789Sahrens {
4402082Seschrock dsl_dir_t *dd = ds->ds_dir;
441789Sahrens dsl_prop_cb_record_t *cbr;
442789Sahrens
443789Sahrens mutex_enter(&dd->dd_lock);
444789Sahrens for (cbr = list_head(&dd->dd_prop_cbs);
445789Sahrens cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) {
4462082Seschrock if (cbr->cbr_ds == ds &&
447789Sahrens cbr->cbr_func == callback &&
4482082Seschrock cbr->cbr_arg == cbarg &&
4492082Seschrock strcmp(cbr->cbr_propname, propname) == 0)
450789Sahrens break;
451789Sahrens }
452789Sahrens
453789Sahrens if (cbr == NULL) {
454789Sahrens mutex_exit(&dd->dd_lock);
455789Sahrens return (ENOMSG);
456789Sahrens }
457789Sahrens
458789Sahrens list_remove(&dd->dd_prop_cbs, cbr);
459789Sahrens mutex_exit(&dd->dd_lock);
460789Sahrens kmem_free((void*)cbr->cbr_propname, strlen(cbr->cbr_propname)+1);
461789Sahrens kmem_free(cbr, sizeof (dsl_prop_cb_record_t));
462789Sahrens
463789Sahrens return (0);
464789Sahrens }
465789Sahrens
4662082Seschrock /*
4672082Seschrock * Return the number of callbacks that are registered for this dataset.
4682082Seschrock */
4692082Seschrock int
dsl_prop_numcb(dsl_dataset_t * ds)4702082Seschrock dsl_prop_numcb(dsl_dataset_t *ds)
4712082Seschrock {
4722082Seschrock dsl_dir_t *dd = ds->ds_dir;
4732082Seschrock dsl_prop_cb_record_t *cbr;
4742082Seschrock int num = 0;
4752082Seschrock
4762082Seschrock mutex_enter(&dd->dd_lock);
4772082Seschrock for (cbr = list_head(&dd->dd_prop_cbs);
4782082Seschrock cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) {
4792082Seschrock if (cbr->cbr_ds == ds)
4802082Seschrock num++;
4812082Seschrock }
4822082Seschrock mutex_exit(&dd->dd_lock);
4832082Seschrock
4842082Seschrock return (num);
4852082Seschrock }
4862082Seschrock
487789Sahrens static void
dsl_prop_changed_notify(dsl_pool_t * dp,uint64_t ddobj,const char * propname,uint64_t value,int first)488789Sahrens dsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj,
489789Sahrens const char *propname, uint64_t value, int first)
490789Sahrens {
491789Sahrens dsl_dir_t *dd;
492789Sahrens dsl_prop_cb_record_t *cbr;
493789Sahrens objset_t *mos = dp->dp_meta_objset;
4942199Sahrens zap_cursor_t zc;
4956047Sahrens zap_attribute_t *za;
496789Sahrens int err;
497789Sahrens
498789Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock));
4991544Seschrock err = dsl_dir_open_obj(dp, ddobj, NULL, FTAG, &dd);
5001544Seschrock if (err)
5011544Seschrock return;
502789Sahrens
503789Sahrens if (!first) {
504789Sahrens /*
505789Sahrens * If the prop is set here, then this change is not
506789Sahrens * being inherited here or below; stop the recursion.
507789Sahrens */
50811022STom.Erickson@Sun.COM err = zap_contains(mos, dd->dd_phys->dd_props_zapobj, propname);
509789Sahrens if (err == 0) {
510789Sahrens dsl_dir_close(dd, FTAG);
511789Sahrens return;
512789Sahrens }
513789Sahrens ASSERT3U(err, ==, ENOENT);
514789Sahrens }
515789Sahrens
516789Sahrens mutex_enter(&dd->dd_lock);
5177265Sahrens for (cbr = list_head(&dd->dd_prop_cbs); cbr;
5187265Sahrens cbr = list_next(&dd->dd_prop_cbs, cbr)) {
5197265Sahrens uint64_t propobj = cbr->cbr_ds->ds_phys->ds_props_obj;
5207265Sahrens
5217265Sahrens if (strcmp(cbr->cbr_propname, propname) != 0)
5227265Sahrens continue;
5237265Sahrens
5247265Sahrens /*
5257265Sahrens * If the property is set on this ds, then it is not
5267265Sahrens * inherited here; don't call the callback.
5277265Sahrens */
52811022STom.Erickson@Sun.COM if (propobj && 0 == zap_contains(mos, propobj, propname))
5297265Sahrens continue;
5307265Sahrens
5317265Sahrens cbr->cbr_func(cbr->cbr_arg, value);
532789Sahrens }
533789Sahrens mutex_exit(&dd->dd_lock);
534789Sahrens
5356047Sahrens za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
5362199Sahrens for (zap_cursor_init(&zc, mos,
5372199Sahrens dd->dd_phys->dd_child_dir_zapobj);
5386047Sahrens zap_cursor_retrieve(&zc, za) == 0;
5392199Sahrens zap_cursor_advance(&zc)) {
5406047Sahrens dsl_prop_changed_notify(dp, za->za_first_integer,
5412199Sahrens propname, value, FALSE);
542789Sahrens }
5436047Sahrens kmem_free(za, sizeof (zap_attribute_t));
5442199Sahrens zap_cursor_fini(&zc);
545789Sahrens dsl_dir_close(dd, FTAG);
546789Sahrens }
547789Sahrens
54811022STom.Erickson@Sun.COM void
dsl_prop_set_sync(void * arg1,void * arg2,dmu_tx_t * tx)54912296SLin.Ling@Sun.COM dsl_prop_set_sync(void *arg1, void *arg2, dmu_tx_t *tx)
550789Sahrens {
5517265Sahrens dsl_dataset_t *ds = arg1;
55211022STom.Erickson@Sun.COM dsl_prop_setarg_t *psa = arg2;
5537265Sahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
55411022STom.Erickson@Sun.COM uint64_t zapobj, intval, dummy;
5552199Sahrens int isint;
5564543Smarks char valbuf[32];
55711022STom.Erickson@Sun.COM char *valstr = NULL;
55811022STom.Erickson@Sun.COM char *inheritstr;
55911022STom.Erickson@Sun.COM char *recvdstr;
56011022STom.Erickson@Sun.COM char *tbuf = NULL;
56111022STom.Erickson@Sun.COM int err;
56211022STom.Erickson@Sun.COM uint64_t version = spa_version(ds->ds_dir->dd_pool->dp_spa);
56311022STom.Erickson@Sun.COM const char *propname = psa->psa_name;
56411022STom.Erickson@Sun.COM zprop_source_t source = psa->psa_source;
565789Sahrens
56611022STom.Erickson@Sun.COM isint = (dodefault(propname, 8, 1, &intval) == 0);
56711022STom.Erickson@Sun.COM
56811022STom.Erickson@Sun.COM if (ds->ds_phys != NULL && dsl_dataset_is_snapshot(ds)) {
56911022STom.Erickson@Sun.COM ASSERT(version >= SPA_VERSION_SNAP_PROPS);
5707265Sahrens if (ds->ds_phys->ds_props_obj == 0) {
5717265Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx);
5727265Sahrens ds->ds_phys->ds_props_obj =
5737265Sahrens zap_create(mos,
5747265Sahrens DMU_OT_DSL_PROPS, DMU_OT_NONE, 0, tx);
5757265Sahrens }
5767265Sahrens zapobj = ds->ds_phys->ds_props_obj;
5777265Sahrens } else {
5787265Sahrens zapobj = ds->ds_dir->dd_phys->dd_props_zapobj;
5797265Sahrens }
5807265Sahrens
58111022STom.Erickson@Sun.COM if (version < SPA_VERSION_RECVD_PROPS) {
58211022STom.Erickson@Sun.COM zfs_prop_t prop = zfs_name_to_prop(propname);
58311022STom.Erickson@Sun.COM if (prop == ZFS_PROP_QUOTA || prop == ZFS_PROP_RESERVATION)
58411022STom.Erickson@Sun.COM return;
58511022STom.Erickson@Sun.COM
58611022STom.Erickson@Sun.COM if (source & ZPROP_SRC_NONE)
58711022STom.Erickson@Sun.COM source = ZPROP_SRC_NONE;
58811022STom.Erickson@Sun.COM else if (source & ZPROP_SRC_RECEIVED)
58911022STom.Erickson@Sun.COM source = ZPROP_SRC_LOCAL;
590789Sahrens }
591789Sahrens
59211022STom.Erickson@Sun.COM inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX);
59311022STom.Erickson@Sun.COM recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX);
59411022STom.Erickson@Sun.COM
59511022STom.Erickson@Sun.COM switch (source) {
59611022STom.Erickson@Sun.COM case ZPROP_SRC_NONE:
59711022STom.Erickson@Sun.COM /*
59811022STom.Erickson@Sun.COM * revert to received value, if any (inherit -S)
59911022STom.Erickson@Sun.COM * - remove propname
60011022STom.Erickson@Sun.COM * - remove propname$inherit
60111022STom.Erickson@Sun.COM */
60211022STom.Erickson@Sun.COM err = zap_remove(mos, zapobj, propname, tx);
60311022STom.Erickson@Sun.COM ASSERT(err == 0 || err == ENOENT);
60411022STom.Erickson@Sun.COM err = zap_remove(mos, zapobj, inheritstr, tx);
60511022STom.Erickson@Sun.COM ASSERT(err == 0 || err == ENOENT);
60611022STom.Erickson@Sun.COM break;
60711022STom.Erickson@Sun.COM case ZPROP_SRC_LOCAL:
60811022STom.Erickson@Sun.COM /*
60911022STom.Erickson@Sun.COM * remove propname$inherit
61011022STom.Erickson@Sun.COM * set propname -> value
61111022STom.Erickson@Sun.COM */
61211022STom.Erickson@Sun.COM err = zap_remove(mos, zapobj, inheritstr, tx);
61311022STom.Erickson@Sun.COM ASSERT(err == 0 || err == ENOENT);
61411022STom.Erickson@Sun.COM VERIFY(0 == zap_update(mos, zapobj, propname,
61511022STom.Erickson@Sun.COM psa->psa_intsz, psa->psa_numints, psa->psa_value, tx));
61611022STom.Erickson@Sun.COM break;
61711022STom.Erickson@Sun.COM case ZPROP_SRC_INHERITED:
61811022STom.Erickson@Sun.COM /*
61911022STom.Erickson@Sun.COM * explicitly inherit
62011022STom.Erickson@Sun.COM * - remove propname
62111022STom.Erickson@Sun.COM * - set propname$inherit
62211022STom.Erickson@Sun.COM */
62311022STom.Erickson@Sun.COM err = zap_remove(mos, zapobj, propname, tx);
62411022STom.Erickson@Sun.COM ASSERT(err == 0 || err == ENOENT);
62511022STom.Erickson@Sun.COM if (version >= SPA_VERSION_RECVD_PROPS &&
626*12455STom.Erickson@Sun.COM dsl_prop_get_ds(ds, ZPROP_HAS_RECVD, 8, 1, &dummy,
627*12455STom.Erickson@Sun.COM NULL) == 0) {
62811022STom.Erickson@Sun.COM dummy = 0;
62911022STom.Erickson@Sun.COM err = zap_update(mos, zapobj, inheritstr,
63011022STom.Erickson@Sun.COM 8, 1, &dummy, tx);
63111022STom.Erickson@Sun.COM ASSERT(err == 0);
63211022STom.Erickson@Sun.COM }
63311022STom.Erickson@Sun.COM break;
63411022STom.Erickson@Sun.COM case ZPROP_SRC_RECEIVED:
63511022STom.Erickson@Sun.COM /*
63611022STom.Erickson@Sun.COM * set propname$recvd -> value
63711022STom.Erickson@Sun.COM */
63811022STom.Erickson@Sun.COM err = zap_update(mos, zapobj, recvdstr,
63911022STom.Erickson@Sun.COM psa->psa_intsz, psa->psa_numints, psa->psa_value, tx);
64011022STom.Erickson@Sun.COM ASSERT(err == 0);
64111022STom.Erickson@Sun.COM break;
64211022STom.Erickson@Sun.COM case (ZPROP_SRC_NONE | ZPROP_SRC_LOCAL | ZPROP_SRC_RECEIVED):
64311022STom.Erickson@Sun.COM /*
64411022STom.Erickson@Sun.COM * clear local and received settings
64511022STom.Erickson@Sun.COM * - remove propname
64611022STom.Erickson@Sun.COM * - remove propname$inherit
64711022STom.Erickson@Sun.COM * - remove propname$recvd
64811022STom.Erickson@Sun.COM */
64911022STom.Erickson@Sun.COM err = zap_remove(mos, zapobj, propname, tx);
65011022STom.Erickson@Sun.COM ASSERT(err == 0 || err == ENOENT);
65111022STom.Erickson@Sun.COM err = zap_remove(mos, zapobj, inheritstr, tx);
65211022STom.Erickson@Sun.COM ASSERT(err == 0 || err == ENOENT);
65311022STom.Erickson@Sun.COM /* FALLTHRU */
65411022STom.Erickson@Sun.COM case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED):
65511022STom.Erickson@Sun.COM /*
65611022STom.Erickson@Sun.COM * remove propname$recvd
65711022STom.Erickson@Sun.COM */
65811022STom.Erickson@Sun.COM err = zap_remove(mos, zapobj, recvdstr, tx);
65911022STom.Erickson@Sun.COM ASSERT(err == 0 || err == ENOENT);
66011022STom.Erickson@Sun.COM break;
66111022STom.Erickson@Sun.COM default:
66211022STom.Erickson@Sun.COM cmn_err(CE_PANIC, "unexpected property source: %d", source);
66311022STom.Erickson@Sun.COM }
66411022STom.Erickson@Sun.COM
66511022STom.Erickson@Sun.COM strfree(inheritstr);
66611022STom.Erickson@Sun.COM strfree(recvdstr);
66711022STom.Erickson@Sun.COM
6682199Sahrens if (isint) {
66911022STom.Erickson@Sun.COM VERIFY(0 == dsl_prop_get_ds(ds, propname, 8, 1, &intval, NULL));
67011022STom.Erickson@Sun.COM
67111022STom.Erickson@Sun.COM if (ds->ds_phys != NULL && dsl_dataset_is_snapshot(ds)) {
6727265Sahrens dsl_prop_cb_record_t *cbr;
6737265Sahrens /*
6747265Sahrens * It's a snapshot; nothing can inherit this
6757265Sahrens * property, so just look for callbacks on this
6767265Sahrens * ds here.
6777265Sahrens */
6787265Sahrens mutex_enter(&ds->ds_dir->dd_lock);
6797265Sahrens for (cbr = list_head(&ds->ds_dir->dd_prop_cbs); cbr;
6807265Sahrens cbr = list_next(&ds->ds_dir->dd_prop_cbs, cbr)) {
6817265Sahrens if (cbr->cbr_ds == ds &&
68211022STom.Erickson@Sun.COM strcmp(cbr->cbr_propname, propname) == 0)
6837265Sahrens cbr->cbr_func(cbr->cbr_arg, intval);
6847265Sahrens }
6857265Sahrens mutex_exit(&ds->ds_dir->dd_lock);
6867265Sahrens } else {
6877265Sahrens dsl_prop_changed_notify(ds->ds_dir->dd_pool,
68811022STom.Erickson@Sun.COM ds->ds_dir->dd_object, propname, intval, TRUE);
6897265Sahrens }
69011022STom.Erickson@Sun.COM
6914543Smarks (void) snprintf(valbuf, sizeof (valbuf),
6924543Smarks "%lld", (longlong_t)intval);
6934543Smarks valstr = valbuf;
6944543Smarks } else {
69511022STom.Erickson@Sun.COM if (source == ZPROP_SRC_LOCAL) {
69611022STom.Erickson@Sun.COM valstr = (char *)psa->psa_value;
69711022STom.Erickson@Sun.COM } else {
69811022STom.Erickson@Sun.COM tbuf = kmem_alloc(ZAP_MAXVALUELEN, KM_SLEEP);
69911022STom.Erickson@Sun.COM if (dsl_prop_get_ds(ds, propname, 1,
70011022STom.Erickson@Sun.COM ZAP_MAXVALUELEN, tbuf, NULL) == 0)
70111022STom.Erickson@Sun.COM valstr = tbuf;
70211022STom.Erickson@Sun.COM }
7034543Smarks }
70411022STom.Erickson@Sun.COM
70512296SLin.Ling@Sun.COM spa_history_log_internal((source == ZPROP_SRC_NONE ||
70611022STom.Erickson@Sun.COM source == ZPROP_SRC_INHERITED) ? LOG_DS_INHERIT :
70712296SLin.Ling@Sun.COM LOG_DS_PROPSET, ds->ds_dir->dd_pool->dp_spa, tx,
70811022STom.Erickson@Sun.COM "%s=%s dataset = %llu", propname,
70911022STom.Erickson@Sun.COM (valstr == NULL ? "" : valstr), ds->ds_object);
71011022STom.Erickson@Sun.COM
71111022STom.Erickson@Sun.COM if (tbuf != NULL)
71211022STom.Erickson@Sun.COM kmem_free(tbuf, ZAP_MAXVALUELEN);
713789Sahrens }
714789Sahrens
7159355SMatthew.Ahrens@Sun.COM void
dsl_props_set_sync(void * arg1,void * arg2,dmu_tx_t * tx)71612296SLin.Ling@Sun.COM dsl_props_set_sync(void *arg1, void *arg2, dmu_tx_t *tx)
7178697SRichard.Morris@Sun.COM {
7188697SRichard.Morris@Sun.COM dsl_dataset_t *ds = arg1;
71911022STom.Erickson@Sun.COM dsl_props_arg_t *pa = arg2;
72011022STom.Erickson@Sun.COM nvlist_t *props = pa->pa_props;
72111022STom.Erickson@Sun.COM dsl_prop_setarg_t psa;
7228697SRichard.Morris@Sun.COM nvpair_t *elem = NULL;
7238697SRichard.Morris@Sun.COM
72411022STom.Erickson@Sun.COM psa.psa_source = pa->pa_source;
7258697SRichard.Morris@Sun.COM
72611022STom.Erickson@Sun.COM while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
72711022STom.Erickson@Sun.COM nvpair_t *pair = elem;
72811022STom.Erickson@Sun.COM
72911022STom.Erickson@Sun.COM psa.psa_name = nvpair_name(pair);
7308697SRichard.Morris@Sun.COM
73111022STom.Erickson@Sun.COM if (nvpair_type(pair) == DATA_TYPE_NVLIST) {
73211022STom.Erickson@Sun.COM /*
73311022STom.Erickson@Sun.COM * dsl_prop_get_all_impl() returns properties in this
73411022STom.Erickson@Sun.COM * format.
73511022STom.Erickson@Sun.COM */
73611022STom.Erickson@Sun.COM nvlist_t *attrs;
73711022STom.Erickson@Sun.COM VERIFY(nvpair_value_nvlist(pair, &attrs) == 0);
73811022STom.Erickson@Sun.COM VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE,
73911022STom.Erickson@Sun.COM &pair) == 0);
74011022STom.Erickson@Sun.COM }
74111022STom.Erickson@Sun.COM
74211022STom.Erickson@Sun.COM if (nvpair_type(pair) == DATA_TYPE_STRING) {
74311022STom.Erickson@Sun.COM VERIFY(nvpair_value_string(pair,
74411022STom.Erickson@Sun.COM (char **)&psa.psa_value) == 0);
74511022STom.Erickson@Sun.COM psa.psa_intsz = 1;
74611022STom.Erickson@Sun.COM psa.psa_numints = strlen(psa.psa_value) + 1;
7478697SRichard.Morris@Sun.COM } else {
7488697SRichard.Morris@Sun.COM uint64_t intval;
74911022STom.Erickson@Sun.COM VERIFY(nvpair_value_uint64(pair, &intval) == 0);
75011022STom.Erickson@Sun.COM psa.psa_intsz = sizeof (intval);
75111022STom.Erickson@Sun.COM psa.psa_numints = 1;
75211022STom.Erickson@Sun.COM psa.psa_value = &intval;
7538697SRichard.Morris@Sun.COM }
75412296SLin.Ling@Sun.COM dsl_prop_set_sync(ds, &psa, tx);
7558697SRichard.Morris@Sun.COM }
7568697SRichard.Morris@Sun.COM }
7578697SRichard.Morris@Sun.COM
7585378Sck153898 void
dsl_dir_prop_set_uint64_sync(dsl_dir_t * dd,const char * name,uint64_t val,dmu_tx_t * tx)75910242Schris.kirby@sun.com dsl_dir_prop_set_uint64_sync(dsl_dir_t *dd, const char *name, uint64_t val,
76012296SLin.Ling@Sun.COM dmu_tx_t *tx)
7615378Sck153898 {
7625378Sck153898 objset_t *mos = dd->dd_pool->dp_meta_objset;
7635378Sck153898 uint64_t zapobj = dd->dd_phys->dd_props_zapobj;
7645378Sck153898
7655378Sck153898 ASSERT(dmu_tx_is_syncing(tx));
7665378Sck153898
7675378Sck153898 VERIFY(0 == zap_update(mos, zapobj, name, sizeof (val), 1, &val, tx));
7685378Sck153898
7695378Sck153898 dsl_prop_changed_notify(dd->dd_pool, dd->dd_object, name, val, TRUE);
7705378Sck153898
77112296SLin.Ling@Sun.COM spa_history_log_internal(LOG_DS_PROPSET, dd->dd_pool->dp_spa, tx,
7725378Sck153898 "%s=%llu dataset = %llu", name, (u_longlong_t)val,
7735378Sck153898 dd->dd_phys->dd_head_dataset_obj);
7745378Sck153898 }
7755378Sck153898
776789Sahrens int
dsl_prop_set(const char * dsname,const char * propname,zprop_source_t source,int intsz,int numints,const void * buf)77711022STom.Erickson@Sun.COM dsl_prop_set(const char *dsname, const char *propname, zprop_source_t source,
7782885Sahrens int intsz, int numints, const void *buf)
7792885Sahrens {
7807265Sahrens dsl_dataset_t *ds;
7819643SEric.Taylor@Sun.COM uint64_t version;
7827265Sahrens int err;
78311022STom.Erickson@Sun.COM dsl_prop_setarg_t psa;
7842885Sahrens
7852641Sahrens /*
7862641Sahrens * We must do these checks before we get to the syncfunc, since
7872641Sahrens * it can't fail.
7882641Sahrens */
7892641Sahrens if (strlen(propname) >= ZAP_MAXNAMELEN)
7902641Sahrens return (ENAMETOOLONG);
7912641Sahrens
7927265Sahrens err = dsl_dataset_hold(dsname, FTAG, &ds);
7931544Seschrock if (err)
7941544Seschrock return (err);
7957265Sahrens
7969643SEric.Taylor@Sun.COM version = spa_version(ds->ds_dir->dd_pool->dp_spa);
7979643SEric.Taylor@Sun.COM if (intsz * numints >= (version < SPA_VERSION_STMF_PROP ?
7989643SEric.Taylor@Sun.COM ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) {
7999643SEric.Taylor@Sun.COM dsl_dataset_rele(ds, FTAG);
8009643SEric.Taylor@Sun.COM return (E2BIG);
8019643SEric.Taylor@Sun.COM }
8027265Sahrens if (dsl_dataset_is_snapshot(ds) &&
8039643SEric.Taylor@Sun.COM version < SPA_VERSION_SNAP_PROPS) {
8047265Sahrens dsl_dataset_rele(ds, FTAG);
8057265Sahrens return (ENOTSUP);
8067265Sahrens }
8077265Sahrens
80811022STom.Erickson@Sun.COM psa.psa_name = propname;
80911022STom.Erickson@Sun.COM psa.psa_source = source;
81011022STom.Erickson@Sun.COM psa.psa_intsz = intsz;
81111022STom.Erickson@Sun.COM psa.psa_numints = numints;
81211022STom.Erickson@Sun.COM psa.psa_value = buf;
81311022STom.Erickson@Sun.COM psa.psa_effective_value = -1ULL;
81411022STom.Erickson@Sun.COM
8157265Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool,
8167265Sahrens NULL, dsl_prop_set_sync, ds, &psa, 2);
8177265Sahrens
8187265Sahrens dsl_dataset_rele(ds, FTAG);
819789Sahrens return (err);
820789Sahrens }
8211356Seschrock
8228697SRichard.Morris@Sun.COM int
dsl_props_set(const char * dsname,zprop_source_t source,nvlist_t * props)82311022STom.Erickson@Sun.COM dsl_props_set(const char *dsname, zprop_source_t source, nvlist_t *props)
8248697SRichard.Morris@Sun.COM {
8258697SRichard.Morris@Sun.COM dsl_dataset_t *ds;
8269643SEric.Taylor@Sun.COM uint64_t version;
8278697SRichard.Morris@Sun.COM nvpair_t *elem = NULL;
82811022STom.Erickson@Sun.COM dsl_props_arg_t pa;
8298697SRichard.Morris@Sun.COM int err;
8308697SRichard.Morris@Sun.COM
8319643SEric.Taylor@Sun.COM if (err = dsl_dataset_hold(dsname, FTAG, &ds))
8329643SEric.Taylor@Sun.COM return (err);
8338924SRichard.Morris@Sun.COM /*
8348924SRichard.Morris@Sun.COM * Do these checks before the syncfunc, since it can't fail.
8358924SRichard.Morris@Sun.COM */
8369643SEric.Taylor@Sun.COM version = spa_version(ds->ds_dir->dd_pool->dp_spa);
83711022STom.Erickson@Sun.COM while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
8389643SEric.Taylor@Sun.COM if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) {
8399643SEric.Taylor@Sun.COM dsl_dataset_rele(ds, FTAG);
8408924SRichard.Morris@Sun.COM return (ENAMETOOLONG);
8419643SEric.Taylor@Sun.COM }
8428697SRichard.Morris@Sun.COM if (nvpair_type(elem) == DATA_TYPE_STRING) {
8438697SRichard.Morris@Sun.COM char *valstr;
8448697SRichard.Morris@Sun.COM VERIFY(nvpair_value_string(elem, &valstr) == 0);
8459643SEric.Taylor@Sun.COM if (strlen(valstr) >= (version <
8469643SEric.Taylor@Sun.COM SPA_VERSION_STMF_PROP ?
8479643SEric.Taylor@Sun.COM ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) {
8489643SEric.Taylor@Sun.COM dsl_dataset_rele(ds, FTAG);
8498924SRichard.Morris@Sun.COM return (E2BIG);
8509643SEric.Taylor@Sun.COM }
8518697SRichard.Morris@Sun.COM }
8528697SRichard.Morris@Sun.COM }
8538697SRichard.Morris@Sun.COM
8548697SRichard.Morris@Sun.COM if (dsl_dataset_is_snapshot(ds) &&
8559643SEric.Taylor@Sun.COM version < SPA_VERSION_SNAP_PROPS) {
8568697SRichard.Morris@Sun.COM dsl_dataset_rele(ds, FTAG);
8578697SRichard.Morris@Sun.COM return (ENOTSUP);
8588697SRichard.Morris@Sun.COM }
8598697SRichard.Morris@Sun.COM
86011022STom.Erickson@Sun.COM pa.pa_props = props;
86111022STom.Erickson@Sun.COM pa.pa_source = source;
86211022STom.Erickson@Sun.COM
8638697SRichard.Morris@Sun.COM err = dsl_sync_task_do(ds->ds_dir->dd_pool,
86411022STom.Erickson@Sun.COM NULL, dsl_props_set_sync, ds, &pa, 2);
8658697SRichard.Morris@Sun.COM
8668697SRichard.Morris@Sun.COM dsl_dataset_rele(ds, FTAG);
8678697SRichard.Morris@Sun.COM return (err);
8688697SRichard.Morris@Sun.COM }
8698697SRichard.Morris@Sun.COM
87011022STom.Erickson@Sun.COM typedef enum dsl_prop_getflags {
87111022STom.Erickson@Sun.COM DSL_PROP_GET_INHERITING = 0x1, /* searching parent of target ds */
87211022STom.Erickson@Sun.COM DSL_PROP_GET_SNAPSHOT = 0x2, /* snapshot dataset */
87311022STom.Erickson@Sun.COM DSL_PROP_GET_LOCAL = 0x4, /* local properties */
87411022STom.Erickson@Sun.COM DSL_PROP_GET_RECEIVED = 0x8 /* received properties */
87511022STom.Erickson@Sun.COM } dsl_prop_getflags_t;
87611022STom.Erickson@Sun.COM
87711022STom.Erickson@Sun.COM static int
dsl_prop_get_all_impl(objset_t * mos,uint64_t propobj,const char * setpoint,dsl_prop_getflags_t flags,nvlist_t * nv)87811022STom.Erickson@Sun.COM dsl_prop_get_all_impl(objset_t *mos, uint64_t propobj,
87911022STom.Erickson@Sun.COM const char *setpoint, dsl_prop_getflags_t flags, nvlist_t *nv)
88011022STom.Erickson@Sun.COM {
88111022STom.Erickson@Sun.COM zap_cursor_t zc;
88211022STom.Erickson@Sun.COM zap_attribute_t za;
88311022STom.Erickson@Sun.COM int err = 0;
88411022STom.Erickson@Sun.COM
88511022STom.Erickson@Sun.COM for (zap_cursor_init(&zc, mos, propobj);
88611022STom.Erickson@Sun.COM (err = zap_cursor_retrieve(&zc, &za)) == 0;
88711022STom.Erickson@Sun.COM zap_cursor_advance(&zc)) {
88811022STom.Erickson@Sun.COM nvlist_t *propval;
88911022STom.Erickson@Sun.COM zfs_prop_t prop;
89011022STom.Erickson@Sun.COM char buf[ZAP_MAXNAMELEN];
89111022STom.Erickson@Sun.COM char *valstr;
89211022STom.Erickson@Sun.COM const char *suffix;
89311022STom.Erickson@Sun.COM const char *propname;
89411022STom.Erickson@Sun.COM const char *source;
89511022STom.Erickson@Sun.COM
89611022STom.Erickson@Sun.COM suffix = strchr(za.za_name, '$');
89711022STom.Erickson@Sun.COM
89811022STom.Erickson@Sun.COM if (suffix == NULL) {
89911022STom.Erickson@Sun.COM /*
90011022STom.Erickson@Sun.COM * Skip local properties if we only want received
90111022STom.Erickson@Sun.COM * properties.
90211022STom.Erickson@Sun.COM */
90311022STom.Erickson@Sun.COM if (flags & DSL_PROP_GET_RECEIVED)
90411022STom.Erickson@Sun.COM continue;
90511022STom.Erickson@Sun.COM
90611022STom.Erickson@Sun.COM propname = za.za_name;
90711022STom.Erickson@Sun.COM source = setpoint;
90811022STom.Erickson@Sun.COM } else if (strcmp(suffix, ZPROP_INHERIT_SUFFIX) == 0) {
90911022STom.Erickson@Sun.COM /* Skip explicitly inherited entries. */
91011022STom.Erickson@Sun.COM continue;
91111022STom.Erickson@Sun.COM } else if (strcmp(suffix, ZPROP_RECVD_SUFFIX) == 0) {
91211022STom.Erickson@Sun.COM if (flags & DSL_PROP_GET_LOCAL)
91311022STom.Erickson@Sun.COM continue;
91411022STom.Erickson@Sun.COM
91511022STom.Erickson@Sun.COM (void) strncpy(buf, za.za_name, (suffix - za.za_name));
91611022STom.Erickson@Sun.COM buf[suffix - za.za_name] = '\0';
91711022STom.Erickson@Sun.COM propname = buf;
91811022STom.Erickson@Sun.COM
91911022STom.Erickson@Sun.COM if (!(flags & DSL_PROP_GET_RECEIVED)) {
92011022STom.Erickson@Sun.COM /* Skip if locally overridden. */
92111022STom.Erickson@Sun.COM err = zap_contains(mos, propobj, propname);
92211022STom.Erickson@Sun.COM if (err == 0)
92311022STom.Erickson@Sun.COM continue;
92411022STom.Erickson@Sun.COM if (err != ENOENT)
92511022STom.Erickson@Sun.COM break;
92611022STom.Erickson@Sun.COM
92711022STom.Erickson@Sun.COM /* Skip if explicitly inherited. */
92811022STom.Erickson@Sun.COM valstr = kmem_asprintf("%s%s", propname,
92911022STom.Erickson@Sun.COM ZPROP_INHERIT_SUFFIX);
93011022STom.Erickson@Sun.COM err = zap_contains(mos, propobj, valstr);
93111022STom.Erickson@Sun.COM strfree(valstr);
93211022STom.Erickson@Sun.COM if (err == 0)
93311022STom.Erickson@Sun.COM continue;
93411022STom.Erickson@Sun.COM if (err != ENOENT)
93511022STom.Erickson@Sun.COM break;
93611022STom.Erickson@Sun.COM }
93711022STom.Erickson@Sun.COM
93811022STom.Erickson@Sun.COM source = ((flags & DSL_PROP_GET_INHERITING) ?
93911022STom.Erickson@Sun.COM setpoint : ZPROP_SOURCE_VAL_RECVD);
94011022STom.Erickson@Sun.COM } else {
94111022STom.Erickson@Sun.COM /*
94211022STom.Erickson@Sun.COM * For backward compatibility, skip suffixes we don't
94311022STom.Erickson@Sun.COM * recognize.
94411022STom.Erickson@Sun.COM */
94511022STom.Erickson@Sun.COM continue;
94611022STom.Erickson@Sun.COM }
94711022STom.Erickson@Sun.COM
94811022STom.Erickson@Sun.COM prop = zfs_name_to_prop(propname);
94911022STom.Erickson@Sun.COM
95011022STom.Erickson@Sun.COM /* Skip non-inheritable properties. */
95111022STom.Erickson@Sun.COM if ((flags & DSL_PROP_GET_INHERITING) && prop != ZPROP_INVAL &&
95211022STom.Erickson@Sun.COM !zfs_prop_inheritable(prop))
95311022STom.Erickson@Sun.COM continue;
95411022STom.Erickson@Sun.COM
95511022STom.Erickson@Sun.COM /* Skip properties not valid for this type. */
95611022STom.Erickson@Sun.COM if ((flags & DSL_PROP_GET_SNAPSHOT) && prop != ZPROP_INVAL &&
95711022STom.Erickson@Sun.COM !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT))
95811022STom.Erickson@Sun.COM continue;
95911022STom.Erickson@Sun.COM
96011022STom.Erickson@Sun.COM /* Skip properties already defined. */
96111022STom.Erickson@Sun.COM if (nvlist_exists(nv, propname))
96211022STom.Erickson@Sun.COM continue;
96311022STom.Erickson@Sun.COM
96411022STom.Erickson@Sun.COM VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
96511022STom.Erickson@Sun.COM if (za.za_integer_length == 1) {
96611022STom.Erickson@Sun.COM /*
96711022STom.Erickson@Sun.COM * String property
96811022STom.Erickson@Sun.COM */
96911022STom.Erickson@Sun.COM char *tmp = kmem_alloc(za.za_num_integers,
97011022STom.Erickson@Sun.COM KM_SLEEP);
97111022STom.Erickson@Sun.COM err = zap_lookup(mos, propobj,
97211022STom.Erickson@Sun.COM za.za_name, 1, za.za_num_integers, tmp);
97311022STom.Erickson@Sun.COM if (err != 0) {
97411022STom.Erickson@Sun.COM kmem_free(tmp, za.za_num_integers);
97511022STom.Erickson@Sun.COM break;
97611022STom.Erickson@Sun.COM }
97711022STom.Erickson@Sun.COM VERIFY(nvlist_add_string(propval, ZPROP_VALUE,
97811022STom.Erickson@Sun.COM tmp) == 0);
97911022STom.Erickson@Sun.COM kmem_free(tmp, za.za_num_integers);
98011022STom.Erickson@Sun.COM } else {
98111022STom.Erickson@Sun.COM /*
98211022STom.Erickson@Sun.COM * Integer property
98311022STom.Erickson@Sun.COM */
98411022STom.Erickson@Sun.COM ASSERT(za.za_integer_length == 8);
98511022STom.Erickson@Sun.COM (void) nvlist_add_uint64(propval, ZPROP_VALUE,
98611022STom.Erickson@Sun.COM za.za_first_integer);
98711022STom.Erickson@Sun.COM }
98811022STom.Erickson@Sun.COM
98911022STom.Erickson@Sun.COM VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, source) == 0);
99011022STom.Erickson@Sun.COM VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
99111022STom.Erickson@Sun.COM nvlist_free(propval);
99211022STom.Erickson@Sun.COM }
99311022STom.Erickson@Sun.COM zap_cursor_fini(&zc);
99411022STom.Erickson@Sun.COM if (err == ENOENT)
99511022STom.Erickson@Sun.COM err = 0;
99611022STom.Erickson@Sun.COM return (err);
99711022STom.Erickson@Sun.COM }
99811022STom.Erickson@Sun.COM
9991356Seschrock /*
10001356Seschrock * Iterate over all properties for this dataset and return them in an nvlist.
10011356Seschrock */
100211022STom.Erickson@Sun.COM static int
dsl_prop_get_all_ds(dsl_dataset_t * ds,nvlist_t ** nvp,dsl_prop_getflags_t flags)100311022STom.Erickson@Sun.COM dsl_prop_get_all_ds(dsl_dataset_t *ds, nvlist_t **nvp,
100411022STom.Erickson@Sun.COM dsl_prop_getflags_t flags)
10051356Seschrock {
10062082Seschrock dsl_dir_t *dd = ds->ds_dir;
10077265Sahrens dsl_pool_t *dp = dd->dd_pool;
10087265Sahrens objset_t *mos = dp->dp_meta_objset;
100911022STom.Erickson@Sun.COM int err = 0;
101011022STom.Erickson@Sun.COM char setpoint[MAXNAMELEN];
10111356Seschrock
10121356Seschrock VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
10131356Seschrock
101411022STom.Erickson@Sun.COM if (dsl_dataset_is_snapshot(ds))
101511022STom.Erickson@Sun.COM flags |= DSL_PROP_GET_SNAPSHOT;
10161356Seschrock
10171356Seschrock rw_enter(&dp->dp_config_rwlock, RW_READER);
10182885Sahrens
101911022STom.Erickson@Sun.COM if (ds->ds_phys->ds_props_obj != 0) {
102011022STom.Erickson@Sun.COM ASSERT(flags & DSL_PROP_GET_SNAPSHOT);
102111022STom.Erickson@Sun.COM dsl_dataset_name(ds, setpoint);
102211022STom.Erickson@Sun.COM err = dsl_prop_get_all_impl(mos, ds->ds_phys->ds_props_obj,
102311022STom.Erickson@Sun.COM setpoint, flags, *nvp);
102411022STom.Erickson@Sun.COM if (err)
102511022STom.Erickson@Sun.COM goto out;
102611022STom.Erickson@Sun.COM }
10271356Seschrock
102811022STom.Erickson@Sun.COM for (; dd != NULL; dd = dd->dd_parent) {
102911022STom.Erickson@Sun.COM if (dd != ds->ds_dir || (flags & DSL_PROP_GET_SNAPSHOT)) {
103011022STom.Erickson@Sun.COM if (flags & (DSL_PROP_GET_LOCAL |
103111022STom.Erickson@Sun.COM DSL_PROP_GET_RECEIVED))
103211022STom.Erickson@Sun.COM break;
103311022STom.Erickson@Sun.COM flags |= DSL_PROP_GET_INHERITING;
103411022STom.Erickson@Sun.COM }
103511022STom.Erickson@Sun.COM dsl_dir_name(dd, setpoint);
103611022STom.Erickson@Sun.COM err = dsl_prop_get_all_impl(mos, dd->dd_phys->dd_props_zapobj,
103711022STom.Erickson@Sun.COM setpoint, flags, *nvp);
103811022STom.Erickson@Sun.COM if (err)
103911022STom.Erickson@Sun.COM break;
104011022STom.Erickson@Sun.COM }
104111022STom.Erickson@Sun.COM out:
104211022STom.Erickson@Sun.COM rw_exit(&dp->dp_config_rwlock);
104311022STom.Erickson@Sun.COM return (err);
104411022STom.Erickson@Sun.COM }
10457265Sahrens
104611022STom.Erickson@Sun.COM boolean_t
dsl_prop_get_hasrecvd(objset_t * os)104711022STom.Erickson@Sun.COM dsl_prop_get_hasrecvd(objset_t *os)
104811022STom.Erickson@Sun.COM {
104911022STom.Erickson@Sun.COM dsl_dataset_t *ds = os->os_dsl_dataset;
105011022STom.Erickson@Sun.COM int rc;
105111022STom.Erickson@Sun.COM uint64_t dummy;
10521356Seschrock
105311022STom.Erickson@Sun.COM rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER);
105411022STom.Erickson@Sun.COM rc = dsl_prop_get_ds(ds, ZPROP_HAS_RECVD, 8, 1, &dummy, NULL);
105511022STom.Erickson@Sun.COM rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock);
105611022STom.Erickson@Sun.COM ASSERT(rc != 0 || spa_version(os->os_spa) >= SPA_VERSION_RECVD_PROPS);
105711022STom.Erickson@Sun.COM return (rc == 0);
105811022STom.Erickson@Sun.COM }
10592676Seschrock
106011022STom.Erickson@Sun.COM static void
dsl_prop_set_hasrecvd_impl(objset_t * os,zprop_source_t source)106111022STom.Erickson@Sun.COM dsl_prop_set_hasrecvd_impl(objset_t *os, zprop_source_t source)
106211022STom.Erickson@Sun.COM {
106311022STom.Erickson@Sun.COM dsl_dataset_t *ds = os->os_dsl_dataset;
106411022STom.Erickson@Sun.COM uint64_t dummy = 0;
106511022STom.Erickson@Sun.COM dsl_prop_setarg_t psa;
106611022STom.Erickson@Sun.COM
106711022STom.Erickson@Sun.COM if (spa_version(os->os_spa) < SPA_VERSION_RECVD_PROPS)
106811022STom.Erickson@Sun.COM return;
106911022STom.Erickson@Sun.COM
107011022STom.Erickson@Sun.COM dsl_prop_setarg_init_uint64(&psa, ZPROP_HAS_RECVD, source, &dummy);
107111022STom.Erickson@Sun.COM
107211022STom.Erickson@Sun.COM (void) dsl_sync_task_do(ds->ds_dir->dd_pool, NULL,
107311022STom.Erickson@Sun.COM dsl_prop_set_sync, ds, &psa, 2);
107411022STom.Erickson@Sun.COM }
10751356Seschrock
107611022STom.Erickson@Sun.COM /*
107711022STom.Erickson@Sun.COM * Call after successfully receiving properties to ensure that only the first
107811022STom.Erickson@Sun.COM * receive on or after SPA_VERSION_RECVD_PROPS blows away local properties.
107911022STom.Erickson@Sun.COM */
108011022STom.Erickson@Sun.COM void
dsl_prop_set_hasrecvd(objset_t * os)108111022STom.Erickson@Sun.COM dsl_prop_set_hasrecvd(objset_t *os)
108211022STom.Erickson@Sun.COM {
108311022STom.Erickson@Sun.COM if (dsl_prop_get_hasrecvd(os)) {
108411022STom.Erickson@Sun.COM ASSERT(spa_version(os->os_spa) >= SPA_VERSION_RECVD_PROPS);
108511022STom.Erickson@Sun.COM return;
108611022STom.Erickson@Sun.COM }
108711022STom.Erickson@Sun.COM dsl_prop_set_hasrecvd_impl(os, ZPROP_SRC_LOCAL);
108811022STom.Erickson@Sun.COM }
10891356Seschrock
109011022STom.Erickson@Sun.COM void
dsl_prop_unset_hasrecvd(objset_t * os)109111022STom.Erickson@Sun.COM dsl_prop_unset_hasrecvd(objset_t *os)
109211022STom.Erickson@Sun.COM {
109311022STom.Erickson@Sun.COM dsl_prop_set_hasrecvd_impl(os, ZPROP_SRC_NONE);
109411022STom.Erickson@Sun.COM }
109511022STom.Erickson@Sun.COM
109611022STom.Erickson@Sun.COM int
dsl_prop_get_all(objset_t * os,nvlist_t ** nvp)109711022STom.Erickson@Sun.COM dsl_prop_get_all(objset_t *os, nvlist_t **nvp)
109811022STom.Erickson@Sun.COM {
109911022STom.Erickson@Sun.COM return (dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, 0));
110011022STom.Erickson@Sun.COM }
11011356Seschrock
110211022STom.Erickson@Sun.COM int
dsl_prop_get_received(objset_t * os,nvlist_t ** nvp)110311022STom.Erickson@Sun.COM dsl_prop_get_received(objset_t *os, nvlist_t **nvp)
110411022STom.Erickson@Sun.COM {
110511022STom.Erickson@Sun.COM /*
110611022STom.Erickson@Sun.COM * Received properties are not distinguishable from local properties
110711022STom.Erickson@Sun.COM * until the dataset has received properties on or after
110811022STom.Erickson@Sun.COM * SPA_VERSION_RECVD_PROPS.
110911022STom.Erickson@Sun.COM */
111011022STom.Erickson@Sun.COM dsl_prop_getflags_t flags = (dsl_prop_get_hasrecvd(os) ?
111111022STom.Erickson@Sun.COM DSL_PROP_GET_RECEIVED : DSL_PROP_GET_LOCAL);
111211022STom.Erickson@Sun.COM return (dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, flags));
11131356Seschrock }
11142885Sahrens
11152885Sahrens void
dsl_prop_nvlist_add_uint64(nvlist_t * nv,zfs_prop_t prop,uint64_t value)11162885Sahrens dsl_prop_nvlist_add_uint64(nvlist_t *nv, zfs_prop_t prop, uint64_t value)
11172885Sahrens {
11182885Sahrens nvlist_t *propval;
111911022STom.Erickson@Sun.COM const char *propname = zfs_prop_to_name(prop);
112011022STom.Erickson@Sun.COM uint64_t default_value;
112111022STom.Erickson@Sun.COM
112211022STom.Erickson@Sun.COM if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) {
112311022STom.Erickson@Sun.COM VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0);
112411022STom.Erickson@Sun.COM return;
112511022STom.Erickson@Sun.COM }
11262885Sahrens
11272885Sahrens VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
11285094Slling VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0);
112911022STom.Erickson@Sun.COM /* Indicate the default source if we can. */
113011022STom.Erickson@Sun.COM if (dodefault(propname, 8, 1, &default_value) == 0 &&
113111022STom.Erickson@Sun.COM value == default_value) {
113211022STom.Erickson@Sun.COM VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, "") == 0);
113311022STom.Erickson@Sun.COM }
113411022STom.Erickson@Sun.COM VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
11352885Sahrens nvlist_free(propval);
11362885Sahrens }
11372885Sahrens
11382885Sahrens void
dsl_prop_nvlist_add_string(nvlist_t * nv,zfs_prop_t prop,const char * value)11392885Sahrens dsl_prop_nvlist_add_string(nvlist_t *nv, zfs_prop_t prop, const char *value)
11402885Sahrens {
11412885Sahrens nvlist_t *propval;
114211022STom.Erickson@Sun.COM const char *propname = zfs_prop_to_name(prop);
114311022STom.Erickson@Sun.COM
114411022STom.Erickson@Sun.COM if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) {
114511022STom.Erickson@Sun.COM VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0);
114611022STom.Erickson@Sun.COM return;
114711022STom.Erickson@Sun.COM }
11482885Sahrens
11492885Sahrens VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
11505094Slling VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0);
115111022STom.Erickson@Sun.COM VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
11522885Sahrens nvlist_free(propval);
11532885Sahrens }
1154