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 /* 22*12296SLin.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 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 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 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 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 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 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 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 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 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 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 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 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 549*12296SLin.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 && 62611022STom.Erickson@Sun.COM zap_contains(mos, zapobj, ZPROP_HAS_RECVD) == 0) { 62711022STom.Erickson@Sun.COM dummy = 0; 62811022STom.Erickson@Sun.COM err = zap_update(mos, zapobj, inheritstr, 62911022STom.Erickson@Sun.COM 8, 1, &dummy, tx); 63011022STom.Erickson@Sun.COM ASSERT(err == 0); 63111022STom.Erickson@Sun.COM } 63211022STom.Erickson@Sun.COM break; 63311022STom.Erickson@Sun.COM case ZPROP_SRC_RECEIVED: 63411022STom.Erickson@Sun.COM /* 63511022STom.Erickson@Sun.COM * set propname$recvd -> value 63611022STom.Erickson@Sun.COM */ 63711022STom.Erickson@Sun.COM err = zap_update(mos, zapobj, recvdstr, 63811022STom.Erickson@Sun.COM psa->psa_intsz, psa->psa_numints, psa->psa_value, tx); 63911022STom.Erickson@Sun.COM ASSERT(err == 0); 64011022STom.Erickson@Sun.COM break; 64111022STom.Erickson@Sun.COM case (ZPROP_SRC_NONE | ZPROP_SRC_LOCAL | ZPROP_SRC_RECEIVED): 64211022STom.Erickson@Sun.COM /* 64311022STom.Erickson@Sun.COM * clear local and received settings 64411022STom.Erickson@Sun.COM * - remove propname 64511022STom.Erickson@Sun.COM * - remove propname$inherit 64611022STom.Erickson@Sun.COM * - remove propname$recvd 64711022STom.Erickson@Sun.COM */ 64811022STom.Erickson@Sun.COM err = zap_remove(mos, zapobj, propname, tx); 64911022STom.Erickson@Sun.COM ASSERT(err == 0 || err == ENOENT); 65011022STom.Erickson@Sun.COM err = zap_remove(mos, zapobj, inheritstr, tx); 65111022STom.Erickson@Sun.COM ASSERT(err == 0 || err == ENOENT); 65211022STom.Erickson@Sun.COM /* FALLTHRU */ 65311022STom.Erickson@Sun.COM case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED): 65411022STom.Erickson@Sun.COM /* 65511022STom.Erickson@Sun.COM * remove propname$recvd 65611022STom.Erickson@Sun.COM */ 65711022STom.Erickson@Sun.COM err = zap_remove(mos, zapobj, recvdstr, tx); 65811022STom.Erickson@Sun.COM ASSERT(err == 0 || err == ENOENT); 65911022STom.Erickson@Sun.COM break; 66011022STom.Erickson@Sun.COM default: 66111022STom.Erickson@Sun.COM cmn_err(CE_PANIC, "unexpected property source: %d", source); 66211022STom.Erickson@Sun.COM } 66311022STom.Erickson@Sun.COM 66411022STom.Erickson@Sun.COM strfree(inheritstr); 66511022STom.Erickson@Sun.COM strfree(recvdstr); 66611022STom.Erickson@Sun.COM 6672199Sahrens if (isint) { 66811022STom.Erickson@Sun.COM VERIFY(0 == dsl_prop_get_ds(ds, propname, 8, 1, &intval, NULL)); 66911022STom.Erickson@Sun.COM 67011022STom.Erickson@Sun.COM if (ds->ds_phys != NULL && dsl_dataset_is_snapshot(ds)) { 6717265Sahrens dsl_prop_cb_record_t *cbr; 6727265Sahrens /* 6737265Sahrens * It's a snapshot; nothing can inherit this 6747265Sahrens * property, so just look for callbacks on this 6757265Sahrens * ds here. 6767265Sahrens */ 6777265Sahrens mutex_enter(&ds->ds_dir->dd_lock); 6787265Sahrens for (cbr = list_head(&ds->ds_dir->dd_prop_cbs); cbr; 6797265Sahrens cbr = list_next(&ds->ds_dir->dd_prop_cbs, cbr)) { 6807265Sahrens if (cbr->cbr_ds == ds && 68111022STom.Erickson@Sun.COM strcmp(cbr->cbr_propname, propname) == 0) 6827265Sahrens cbr->cbr_func(cbr->cbr_arg, intval); 6837265Sahrens } 6847265Sahrens mutex_exit(&ds->ds_dir->dd_lock); 6857265Sahrens } else { 6867265Sahrens dsl_prop_changed_notify(ds->ds_dir->dd_pool, 68711022STom.Erickson@Sun.COM ds->ds_dir->dd_object, propname, intval, TRUE); 6887265Sahrens } 68911022STom.Erickson@Sun.COM 6904543Smarks (void) snprintf(valbuf, sizeof (valbuf), 6914543Smarks "%lld", (longlong_t)intval); 6924543Smarks valstr = valbuf; 6934543Smarks } else { 69411022STom.Erickson@Sun.COM if (source == ZPROP_SRC_LOCAL) { 69511022STom.Erickson@Sun.COM valstr = (char *)psa->psa_value; 69611022STom.Erickson@Sun.COM } else { 69711022STom.Erickson@Sun.COM tbuf = kmem_alloc(ZAP_MAXVALUELEN, KM_SLEEP); 69811022STom.Erickson@Sun.COM if (dsl_prop_get_ds(ds, propname, 1, 69911022STom.Erickson@Sun.COM ZAP_MAXVALUELEN, tbuf, NULL) == 0) 70011022STom.Erickson@Sun.COM valstr = tbuf; 70111022STom.Erickson@Sun.COM } 7024543Smarks } 70311022STom.Erickson@Sun.COM 704*12296SLin.Ling@Sun.COM spa_history_log_internal((source == ZPROP_SRC_NONE || 70511022STom.Erickson@Sun.COM source == ZPROP_SRC_INHERITED) ? LOG_DS_INHERIT : 706*12296SLin.Ling@Sun.COM LOG_DS_PROPSET, ds->ds_dir->dd_pool->dp_spa, tx, 70711022STom.Erickson@Sun.COM "%s=%s dataset = %llu", propname, 70811022STom.Erickson@Sun.COM (valstr == NULL ? "" : valstr), ds->ds_object); 70911022STom.Erickson@Sun.COM 71011022STom.Erickson@Sun.COM if (tbuf != NULL) 71111022STom.Erickson@Sun.COM kmem_free(tbuf, ZAP_MAXVALUELEN); 712789Sahrens } 713789Sahrens 7149355SMatthew.Ahrens@Sun.COM void 715*12296SLin.Ling@Sun.COM dsl_props_set_sync(void *arg1, void *arg2, dmu_tx_t *tx) 7168697SRichard.Morris@Sun.COM { 7178697SRichard.Morris@Sun.COM dsl_dataset_t *ds = arg1; 71811022STom.Erickson@Sun.COM dsl_props_arg_t *pa = arg2; 71911022STom.Erickson@Sun.COM nvlist_t *props = pa->pa_props; 72011022STom.Erickson@Sun.COM dsl_prop_setarg_t psa; 7218697SRichard.Morris@Sun.COM nvpair_t *elem = NULL; 7228697SRichard.Morris@Sun.COM 72311022STom.Erickson@Sun.COM psa.psa_source = pa->pa_source; 7248697SRichard.Morris@Sun.COM 72511022STom.Erickson@Sun.COM while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 72611022STom.Erickson@Sun.COM nvpair_t *pair = elem; 72711022STom.Erickson@Sun.COM 72811022STom.Erickson@Sun.COM psa.psa_name = nvpair_name(pair); 7298697SRichard.Morris@Sun.COM 73011022STom.Erickson@Sun.COM if (nvpair_type(pair) == DATA_TYPE_NVLIST) { 73111022STom.Erickson@Sun.COM /* 73211022STom.Erickson@Sun.COM * dsl_prop_get_all_impl() returns properties in this 73311022STom.Erickson@Sun.COM * format. 73411022STom.Erickson@Sun.COM */ 73511022STom.Erickson@Sun.COM nvlist_t *attrs; 73611022STom.Erickson@Sun.COM VERIFY(nvpair_value_nvlist(pair, &attrs) == 0); 73711022STom.Erickson@Sun.COM VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 73811022STom.Erickson@Sun.COM &pair) == 0); 73911022STom.Erickson@Sun.COM } 74011022STom.Erickson@Sun.COM 74111022STom.Erickson@Sun.COM if (nvpair_type(pair) == DATA_TYPE_STRING) { 74211022STom.Erickson@Sun.COM VERIFY(nvpair_value_string(pair, 74311022STom.Erickson@Sun.COM (char **)&psa.psa_value) == 0); 74411022STom.Erickson@Sun.COM psa.psa_intsz = 1; 74511022STom.Erickson@Sun.COM psa.psa_numints = strlen(psa.psa_value) + 1; 7468697SRichard.Morris@Sun.COM } else { 7478697SRichard.Morris@Sun.COM uint64_t intval; 74811022STom.Erickson@Sun.COM VERIFY(nvpair_value_uint64(pair, &intval) == 0); 74911022STom.Erickson@Sun.COM psa.psa_intsz = sizeof (intval); 75011022STom.Erickson@Sun.COM psa.psa_numints = 1; 75111022STom.Erickson@Sun.COM psa.psa_value = &intval; 7528697SRichard.Morris@Sun.COM } 753*12296SLin.Ling@Sun.COM dsl_prop_set_sync(ds, &psa, tx); 7548697SRichard.Morris@Sun.COM } 7558697SRichard.Morris@Sun.COM } 7568697SRichard.Morris@Sun.COM 7575378Sck153898 void 75810242Schris.kirby@sun.com dsl_dir_prop_set_uint64_sync(dsl_dir_t *dd, const char *name, uint64_t val, 759*12296SLin.Ling@Sun.COM dmu_tx_t *tx) 7605378Sck153898 { 7615378Sck153898 objset_t *mos = dd->dd_pool->dp_meta_objset; 7625378Sck153898 uint64_t zapobj = dd->dd_phys->dd_props_zapobj; 7635378Sck153898 7645378Sck153898 ASSERT(dmu_tx_is_syncing(tx)); 7655378Sck153898 7665378Sck153898 VERIFY(0 == zap_update(mos, zapobj, name, sizeof (val), 1, &val, tx)); 7675378Sck153898 7685378Sck153898 dsl_prop_changed_notify(dd->dd_pool, dd->dd_object, name, val, TRUE); 7695378Sck153898 770*12296SLin.Ling@Sun.COM spa_history_log_internal(LOG_DS_PROPSET, dd->dd_pool->dp_spa, tx, 7715378Sck153898 "%s=%llu dataset = %llu", name, (u_longlong_t)val, 7725378Sck153898 dd->dd_phys->dd_head_dataset_obj); 7735378Sck153898 } 7745378Sck153898 775789Sahrens int 77611022STom.Erickson@Sun.COM dsl_prop_set(const char *dsname, const char *propname, zprop_source_t source, 7772885Sahrens int intsz, int numints, const void *buf) 7782885Sahrens { 7797265Sahrens dsl_dataset_t *ds; 7809643SEric.Taylor@Sun.COM uint64_t version; 7817265Sahrens int err; 78211022STom.Erickson@Sun.COM dsl_prop_setarg_t psa; 7832885Sahrens 7842641Sahrens /* 7852641Sahrens * We must do these checks before we get to the syncfunc, since 7862641Sahrens * it can't fail. 7872641Sahrens */ 7882641Sahrens if (strlen(propname) >= ZAP_MAXNAMELEN) 7892641Sahrens return (ENAMETOOLONG); 7902641Sahrens 7917265Sahrens err = dsl_dataset_hold(dsname, FTAG, &ds); 7921544Seschrock if (err) 7931544Seschrock return (err); 7947265Sahrens 7959643SEric.Taylor@Sun.COM version = spa_version(ds->ds_dir->dd_pool->dp_spa); 7969643SEric.Taylor@Sun.COM if (intsz * numints >= (version < SPA_VERSION_STMF_PROP ? 7979643SEric.Taylor@Sun.COM ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) { 7989643SEric.Taylor@Sun.COM dsl_dataset_rele(ds, FTAG); 7999643SEric.Taylor@Sun.COM return (E2BIG); 8009643SEric.Taylor@Sun.COM } 8017265Sahrens if (dsl_dataset_is_snapshot(ds) && 8029643SEric.Taylor@Sun.COM version < SPA_VERSION_SNAP_PROPS) { 8037265Sahrens dsl_dataset_rele(ds, FTAG); 8047265Sahrens return (ENOTSUP); 8057265Sahrens } 8067265Sahrens 80711022STom.Erickson@Sun.COM psa.psa_name = propname; 80811022STom.Erickson@Sun.COM psa.psa_source = source; 80911022STom.Erickson@Sun.COM psa.psa_intsz = intsz; 81011022STom.Erickson@Sun.COM psa.psa_numints = numints; 81111022STom.Erickson@Sun.COM psa.psa_value = buf; 81211022STom.Erickson@Sun.COM psa.psa_effective_value = -1ULL; 81311022STom.Erickson@Sun.COM 8147265Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 8157265Sahrens NULL, dsl_prop_set_sync, ds, &psa, 2); 8167265Sahrens 8177265Sahrens dsl_dataset_rele(ds, FTAG); 818789Sahrens return (err); 819789Sahrens } 8201356Seschrock 8218697SRichard.Morris@Sun.COM int 82211022STom.Erickson@Sun.COM dsl_props_set(const char *dsname, zprop_source_t source, nvlist_t *props) 8238697SRichard.Morris@Sun.COM { 8248697SRichard.Morris@Sun.COM dsl_dataset_t *ds; 8259643SEric.Taylor@Sun.COM uint64_t version; 8268697SRichard.Morris@Sun.COM nvpair_t *elem = NULL; 82711022STom.Erickson@Sun.COM dsl_props_arg_t pa; 8288697SRichard.Morris@Sun.COM int err; 8298697SRichard.Morris@Sun.COM 8309643SEric.Taylor@Sun.COM if (err = dsl_dataset_hold(dsname, FTAG, &ds)) 8319643SEric.Taylor@Sun.COM return (err); 8328924SRichard.Morris@Sun.COM /* 8338924SRichard.Morris@Sun.COM * Do these checks before the syncfunc, since it can't fail. 8348924SRichard.Morris@Sun.COM */ 8359643SEric.Taylor@Sun.COM version = spa_version(ds->ds_dir->dd_pool->dp_spa); 83611022STom.Erickson@Sun.COM while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 8379643SEric.Taylor@Sun.COM if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) { 8389643SEric.Taylor@Sun.COM dsl_dataset_rele(ds, FTAG); 8398924SRichard.Morris@Sun.COM return (ENAMETOOLONG); 8409643SEric.Taylor@Sun.COM } 8418697SRichard.Morris@Sun.COM if (nvpair_type(elem) == DATA_TYPE_STRING) { 8428697SRichard.Morris@Sun.COM char *valstr; 8438697SRichard.Morris@Sun.COM VERIFY(nvpair_value_string(elem, &valstr) == 0); 8449643SEric.Taylor@Sun.COM if (strlen(valstr) >= (version < 8459643SEric.Taylor@Sun.COM SPA_VERSION_STMF_PROP ? 8469643SEric.Taylor@Sun.COM ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) { 8479643SEric.Taylor@Sun.COM dsl_dataset_rele(ds, FTAG); 8488924SRichard.Morris@Sun.COM return (E2BIG); 8499643SEric.Taylor@Sun.COM } 8508697SRichard.Morris@Sun.COM } 8518697SRichard.Morris@Sun.COM } 8528697SRichard.Morris@Sun.COM 8538697SRichard.Morris@Sun.COM if (dsl_dataset_is_snapshot(ds) && 8549643SEric.Taylor@Sun.COM version < SPA_VERSION_SNAP_PROPS) { 8558697SRichard.Morris@Sun.COM dsl_dataset_rele(ds, FTAG); 8568697SRichard.Morris@Sun.COM return (ENOTSUP); 8578697SRichard.Morris@Sun.COM } 8588697SRichard.Morris@Sun.COM 85911022STom.Erickson@Sun.COM pa.pa_props = props; 86011022STom.Erickson@Sun.COM pa.pa_source = source; 86111022STom.Erickson@Sun.COM 8628697SRichard.Morris@Sun.COM err = dsl_sync_task_do(ds->ds_dir->dd_pool, 86311022STom.Erickson@Sun.COM NULL, dsl_props_set_sync, ds, &pa, 2); 8648697SRichard.Morris@Sun.COM 8658697SRichard.Morris@Sun.COM dsl_dataset_rele(ds, FTAG); 8668697SRichard.Morris@Sun.COM return (err); 8678697SRichard.Morris@Sun.COM } 8688697SRichard.Morris@Sun.COM 86911022STom.Erickson@Sun.COM typedef enum dsl_prop_getflags { 87011022STom.Erickson@Sun.COM DSL_PROP_GET_INHERITING = 0x1, /* searching parent of target ds */ 87111022STom.Erickson@Sun.COM DSL_PROP_GET_SNAPSHOT = 0x2, /* snapshot dataset */ 87211022STom.Erickson@Sun.COM DSL_PROP_GET_LOCAL = 0x4, /* local properties */ 87311022STom.Erickson@Sun.COM DSL_PROP_GET_RECEIVED = 0x8 /* received properties */ 87411022STom.Erickson@Sun.COM } dsl_prop_getflags_t; 87511022STom.Erickson@Sun.COM 87611022STom.Erickson@Sun.COM static int 87711022STom.Erickson@Sun.COM dsl_prop_get_all_impl(objset_t *mos, uint64_t propobj, 87811022STom.Erickson@Sun.COM const char *setpoint, dsl_prop_getflags_t flags, nvlist_t *nv) 87911022STom.Erickson@Sun.COM { 88011022STom.Erickson@Sun.COM zap_cursor_t zc; 88111022STom.Erickson@Sun.COM zap_attribute_t za; 88211022STom.Erickson@Sun.COM int err = 0; 88311022STom.Erickson@Sun.COM 88411022STom.Erickson@Sun.COM for (zap_cursor_init(&zc, mos, propobj); 88511022STom.Erickson@Sun.COM (err = zap_cursor_retrieve(&zc, &za)) == 0; 88611022STom.Erickson@Sun.COM zap_cursor_advance(&zc)) { 88711022STom.Erickson@Sun.COM nvlist_t *propval; 88811022STom.Erickson@Sun.COM zfs_prop_t prop; 88911022STom.Erickson@Sun.COM char buf[ZAP_MAXNAMELEN]; 89011022STom.Erickson@Sun.COM char *valstr; 89111022STom.Erickson@Sun.COM const char *suffix; 89211022STom.Erickson@Sun.COM const char *propname; 89311022STom.Erickson@Sun.COM const char *source; 89411022STom.Erickson@Sun.COM 89511022STom.Erickson@Sun.COM suffix = strchr(za.za_name, '$'); 89611022STom.Erickson@Sun.COM 89711022STom.Erickson@Sun.COM if (suffix == NULL) { 89811022STom.Erickson@Sun.COM /* 89911022STom.Erickson@Sun.COM * Skip local properties if we only want received 90011022STom.Erickson@Sun.COM * properties. 90111022STom.Erickson@Sun.COM */ 90211022STom.Erickson@Sun.COM if (flags & DSL_PROP_GET_RECEIVED) 90311022STom.Erickson@Sun.COM continue; 90411022STom.Erickson@Sun.COM 90511022STom.Erickson@Sun.COM propname = za.za_name; 90611022STom.Erickson@Sun.COM source = setpoint; 90711022STom.Erickson@Sun.COM } else if (strcmp(suffix, ZPROP_INHERIT_SUFFIX) == 0) { 90811022STom.Erickson@Sun.COM /* Skip explicitly inherited entries. */ 90911022STom.Erickson@Sun.COM continue; 91011022STom.Erickson@Sun.COM } else if (strcmp(suffix, ZPROP_RECVD_SUFFIX) == 0) { 91111022STom.Erickson@Sun.COM if (flags & DSL_PROP_GET_LOCAL) 91211022STom.Erickson@Sun.COM continue; 91311022STom.Erickson@Sun.COM 91411022STom.Erickson@Sun.COM (void) strncpy(buf, za.za_name, (suffix - za.za_name)); 91511022STom.Erickson@Sun.COM buf[suffix - za.za_name] = '\0'; 91611022STom.Erickson@Sun.COM propname = buf; 91711022STom.Erickson@Sun.COM 91811022STom.Erickson@Sun.COM if (!(flags & DSL_PROP_GET_RECEIVED)) { 91911022STom.Erickson@Sun.COM /* Skip if locally overridden. */ 92011022STom.Erickson@Sun.COM err = zap_contains(mos, propobj, propname); 92111022STom.Erickson@Sun.COM if (err == 0) 92211022STom.Erickson@Sun.COM continue; 92311022STom.Erickson@Sun.COM if (err != ENOENT) 92411022STom.Erickson@Sun.COM break; 92511022STom.Erickson@Sun.COM 92611022STom.Erickson@Sun.COM /* Skip if explicitly inherited. */ 92711022STom.Erickson@Sun.COM valstr = kmem_asprintf("%s%s", propname, 92811022STom.Erickson@Sun.COM ZPROP_INHERIT_SUFFIX); 92911022STom.Erickson@Sun.COM err = zap_contains(mos, propobj, valstr); 93011022STom.Erickson@Sun.COM strfree(valstr); 93111022STom.Erickson@Sun.COM if (err == 0) 93211022STom.Erickson@Sun.COM continue; 93311022STom.Erickson@Sun.COM if (err != ENOENT) 93411022STom.Erickson@Sun.COM break; 93511022STom.Erickson@Sun.COM } 93611022STom.Erickson@Sun.COM 93711022STom.Erickson@Sun.COM source = ((flags & DSL_PROP_GET_INHERITING) ? 93811022STom.Erickson@Sun.COM setpoint : ZPROP_SOURCE_VAL_RECVD); 93911022STom.Erickson@Sun.COM } else { 94011022STom.Erickson@Sun.COM /* 94111022STom.Erickson@Sun.COM * For backward compatibility, skip suffixes we don't 94211022STom.Erickson@Sun.COM * recognize. 94311022STom.Erickson@Sun.COM */ 94411022STom.Erickson@Sun.COM continue; 94511022STom.Erickson@Sun.COM } 94611022STom.Erickson@Sun.COM 94711022STom.Erickson@Sun.COM prop = zfs_name_to_prop(propname); 94811022STom.Erickson@Sun.COM 94911022STom.Erickson@Sun.COM /* Skip non-inheritable properties. */ 95011022STom.Erickson@Sun.COM if ((flags & DSL_PROP_GET_INHERITING) && prop != ZPROP_INVAL && 95111022STom.Erickson@Sun.COM !zfs_prop_inheritable(prop)) 95211022STom.Erickson@Sun.COM continue; 95311022STom.Erickson@Sun.COM 95411022STom.Erickson@Sun.COM /* Skip properties not valid for this type. */ 95511022STom.Erickson@Sun.COM if ((flags & DSL_PROP_GET_SNAPSHOT) && prop != ZPROP_INVAL && 95611022STom.Erickson@Sun.COM !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT)) 95711022STom.Erickson@Sun.COM continue; 95811022STom.Erickson@Sun.COM 95911022STom.Erickson@Sun.COM /* Skip properties already defined. */ 96011022STom.Erickson@Sun.COM if (nvlist_exists(nv, propname)) 96111022STom.Erickson@Sun.COM continue; 96211022STom.Erickson@Sun.COM 96311022STom.Erickson@Sun.COM VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 96411022STom.Erickson@Sun.COM if (za.za_integer_length == 1) { 96511022STom.Erickson@Sun.COM /* 96611022STom.Erickson@Sun.COM * String property 96711022STom.Erickson@Sun.COM */ 96811022STom.Erickson@Sun.COM char *tmp = kmem_alloc(za.za_num_integers, 96911022STom.Erickson@Sun.COM KM_SLEEP); 97011022STom.Erickson@Sun.COM err = zap_lookup(mos, propobj, 97111022STom.Erickson@Sun.COM za.za_name, 1, za.za_num_integers, tmp); 97211022STom.Erickson@Sun.COM if (err != 0) { 97311022STom.Erickson@Sun.COM kmem_free(tmp, za.za_num_integers); 97411022STom.Erickson@Sun.COM break; 97511022STom.Erickson@Sun.COM } 97611022STom.Erickson@Sun.COM VERIFY(nvlist_add_string(propval, ZPROP_VALUE, 97711022STom.Erickson@Sun.COM tmp) == 0); 97811022STom.Erickson@Sun.COM kmem_free(tmp, za.za_num_integers); 97911022STom.Erickson@Sun.COM } else { 98011022STom.Erickson@Sun.COM /* 98111022STom.Erickson@Sun.COM * Integer property 98211022STom.Erickson@Sun.COM */ 98311022STom.Erickson@Sun.COM ASSERT(za.za_integer_length == 8); 98411022STom.Erickson@Sun.COM (void) nvlist_add_uint64(propval, ZPROP_VALUE, 98511022STom.Erickson@Sun.COM za.za_first_integer); 98611022STom.Erickson@Sun.COM } 98711022STom.Erickson@Sun.COM 98811022STom.Erickson@Sun.COM VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, source) == 0); 98911022STom.Erickson@Sun.COM VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0); 99011022STom.Erickson@Sun.COM nvlist_free(propval); 99111022STom.Erickson@Sun.COM } 99211022STom.Erickson@Sun.COM zap_cursor_fini(&zc); 99311022STom.Erickson@Sun.COM if (err == ENOENT) 99411022STom.Erickson@Sun.COM err = 0; 99511022STom.Erickson@Sun.COM return (err); 99611022STom.Erickson@Sun.COM } 99711022STom.Erickson@Sun.COM 9981356Seschrock /* 9991356Seschrock * Iterate over all properties for this dataset and return them in an nvlist. 10001356Seschrock */ 100111022STom.Erickson@Sun.COM static int 100211022STom.Erickson@Sun.COM dsl_prop_get_all_ds(dsl_dataset_t *ds, nvlist_t **nvp, 100311022STom.Erickson@Sun.COM dsl_prop_getflags_t flags) 10041356Seschrock { 10052082Seschrock dsl_dir_t *dd = ds->ds_dir; 10067265Sahrens dsl_pool_t *dp = dd->dd_pool; 10077265Sahrens objset_t *mos = dp->dp_meta_objset; 100811022STom.Erickson@Sun.COM int err = 0; 100911022STom.Erickson@Sun.COM char setpoint[MAXNAMELEN]; 10101356Seschrock 10111356Seschrock VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); 10121356Seschrock 101311022STom.Erickson@Sun.COM if (dsl_dataset_is_snapshot(ds)) 101411022STom.Erickson@Sun.COM flags |= DSL_PROP_GET_SNAPSHOT; 10151356Seschrock 10161356Seschrock rw_enter(&dp->dp_config_rwlock, RW_READER); 10172885Sahrens 101811022STom.Erickson@Sun.COM if (ds->ds_phys->ds_props_obj != 0) { 101911022STom.Erickson@Sun.COM ASSERT(flags & DSL_PROP_GET_SNAPSHOT); 102011022STom.Erickson@Sun.COM dsl_dataset_name(ds, setpoint); 102111022STom.Erickson@Sun.COM err = dsl_prop_get_all_impl(mos, ds->ds_phys->ds_props_obj, 102211022STom.Erickson@Sun.COM setpoint, flags, *nvp); 102311022STom.Erickson@Sun.COM if (err) 102411022STom.Erickson@Sun.COM goto out; 102511022STom.Erickson@Sun.COM } 10261356Seschrock 102711022STom.Erickson@Sun.COM for (; dd != NULL; dd = dd->dd_parent) { 102811022STom.Erickson@Sun.COM if (dd != ds->ds_dir || (flags & DSL_PROP_GET_SNAPSHOT)) { 102911022STom.Erickson@Sun.COM if (flags & (DSL_PROP_GET_LOCAL | 103011022STom.Erickson@Sun.COM DSL_PROP_GET_RECEIVED)) 103111022STom.Erickson@Sun.COM break; 103211022STom.Erickson@Sun.COM flags |= DSL_PROP_GET_INHERITING; 103311022STom.Erickson@Sun.COM } 103411022STom.Erickson@Sun.COM dsl_dir_name(dd, setpoint); 103511022STom.Erickson@Sun.COM err = dsl_prop_get_all_impl(mos, dd->dd_phys->dd_props_zapobj, 103611022STom.Erickson@Sun.COM setpoint, flags, *nvp); 103711022STom.Erickson@Sun.COM if (err) 103811022STom.Erickson@Sun.COM break; 103911022STom.Erickson@Sun.COM } 104011022STom.Erickson@Sun.COM out: 104111022STom.Erickson@Sun.COM rw_exit(&dp->dp_config_rwlock); 104211022STom.Erickson@Sun.COM return (err); 104311022STom.Erickson@Sun.COM } 10447265Sahrens 104511022STom.Erickson@Sun.COM boolean_t 104611022STom.Erickson@Sun.COM dsl_prop_get_hasrecvd(objset_t *os) 104711022STom.Erickson@Sun.COM { 104811022STom.Erickson@Sun.COM dsl_dataset_t *ds = os->os_dsl_dataset; 104911022STom.Erickson@Sun.COM int rc; 105011022STom.Erickson@Sun.COM uint64_t dummy; 10511356Seschrock 105211022STom.Erickson@Sun.COM rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); 105311022STom.Erickson@Sun.COM rc = dsl_prop_get_ds(ds, ZPROP_HAS_RECVD, 8, 1, &dummy, NULL); 105411022STom.Erickson@Sun.COM rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 105511022STom.Erickson@Sun.COM ASSERT(rc != 0 || spa_version(os->os_spa) >= SPA_VERSION_RECVD_PROPS); 105611022STom.Erickson@Sun.COM return (rc == 0); 105711022STom.Erickson@Sun.COM } 10582676Seschrock 105911022STom.Erickson@Sun.COM static void 106011022STom.Erickson@Sun.COM dsl_prop_set_hasrecvd_impl(objset_t *os, zprop_source_t source) 106111022STom.Erickson@Sun.COM { 106211022STom.Erickson@Sun.COM dsl_dataset_t *ds = os->os_dsl_dataset; 106311022STom.Erickson@Sun.COM uint64_t dummy = 0; 106411022STom.Erickson@Sun.COM dsl_prop_setarg_t psa; 106511022STom.Erickson@Sun.COM 106611022STom.Erickson@Sun.COM if (spa_version(os->os_spa) < SPA_VERSION_RECVD_PROPS) 106711022STom.Erickson@Sun.COM return; 106811022STom.Erickson@Sun.COM 106911022STom.Erickson@Sun.COM dsl_prop_setarg_init_uint64(&psa, ZPROP_HAS_RECVD, source, &dummy); 107011022STom.Erickson@Sun.COM 107111022STom.Erickson@Sun.COM (void) dsl_sync_task_do(ds->ds_dir->dd_pool, NULL, 107211022STom.Erickson@Sun.COM dsl_prop_set_sync, ds, &psa, 2); 107311022STom.Erickson@Sun.COM } 10741356Seschrock 107511022STom.Erickson@Sun.COM /* 107611022STom.Erickson@Sun.COM * Call after successfully receiving properties to ensure that only the first 107711022STom.Erickson@Sun.COM * receive on or after SPA_VERSION_RECVD_PROPS blows away local properties. 107811022STom.Erickson@Sun.COM */ 107911022STom.Erickson@Sun.COM void 108011022STom.Erickson@Sun.COM dsl_prop_set_hasrecvd(objset_t *os) 108111022STom.Erickson@Sun.COM { 108211022STom.Erickson@Sun.COM if (dsl_prop_get_hasrecvd(os)) { 108311022STom.Erickson@Sun.COM ASSERT(spa_version(os->os_spa) >= SPA_VERSION_RECVD_PROPS); 108411022STom.Erickson@Sun.COM return; 108511022STom.Erickson@Sun.COM } 108611022STom.Erickson@Sun.COM dsl_prop_set_hasrecvd_impl(os, ZPROP_SRC_LOCAL); 108711022STom.Erickson@Sun.COM } 10881356Seschrock 108911022STom.Erickson@Sun.COM void 109011022STom.Erickson@Sun.COM dsl_prop_unset_hasrecvd(objset_t *os) 109111022STom.Erickson@Sun.COM { 109211022STom.Erickson@Sun.COM dsl_prop_set_hasrecvd_impl(os, ZPROP_SRC_NONE); 109311022STom.Erickson@Sun.COM } 109411022STom.Erickson@Sun.COM 109511022STom.Erickson@Sun.COM int 109611022STom.Erickson@Sun.COM dsl_prop_get_all(objset_t *os, nvlist_t **nvp) 109711022STom.Erickson@Sun.COM { 109811022STom.Erickson@Sun.COM return (dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, 0)); 109911022STom.Erickson@Sun.COM } 11001356Seschrock 110111022STom.Erickson@Sun.COM int 110211022STom.Erickson@Sun.COM dsl_prop_get_received(objset_t *os, nvlist_t **nvp) 110311022STom.Erickson@Sun.COM { 110411022STom.Erickson@Sun.COM /* 110511022STom.Erickson@Sun.COM * Received properties are not distinguishable from local properties 110611022STom.Erickson@Sun.COM * until the dataset has received properties on or after 110711022STom.Erickson@Sun.COM * SPA_VERSION_RECVD_PROPS. 110811022STom.Erickson@Sun.COM */ 110911022STom.Erickson@Sun.COM dsl_prop_getflags_t flags = (dsl_prop_get_hasrecvd(os) ? 111011022STom.Erickson@Sun.COM DSL_PROP_GET_RECEIVED : DSL_PROP_GET_LOCAL); 111111022STom.Erickson@Sun.COM return (dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, flags)); 11121356Seschrock } 11132885Sahrens 11142885Sahrens void 11152885Sahrens dsl_prop_nvlist_add_uint64(nvlist_t *nv, zfs_prop_t prop, uint64_t value) 11162885Sahrens { 11172885Sahrens nvlist_t *propval; 111811022STom.Erickson@Sun.COM const char *propname = zfs_prop_to_name(prop); 111911022STom.Erickson@Sun.COM uint64_t default_value; 112011022STom.Erickson@Sun.COM 112111022STom.Erickson@Sun.COM if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) { 112211022STom.Erickson@Sun.COM VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0); 112311022STom.Erickson@Sun.COM return; 112411022STom.Erickson@Sun.COM } 11252885Sahrens 11262885Sahrens VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 11275094Slling VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0); 112811022STom.Erickson@Sun.COM /* Indicate the default source if we can. */ 112911022STom.Erickson@Sun.COM if (dodefault(propname, 8, 1, &default_value) == 0 && 113011022STom.Erickson@Sun.COM value == default_value) { 113111022STom.Erickson@Sun.COM VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, "") == 0); 113211022STom.Erickson@Sun.COM } 113311022STom.Erickson@Sun.COM VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0); 11342885Sahrens nvlist_free(propval); 11352885Sahrens } 11362885Sahrens 11372885Sahrens void 11382885Sahrens dsl_prop_nvlist_add_string(nvlist_t *nv, zfs_prop_t prop, const char *value) 11392885Sahrens { 11402885Sahrens nvlist_t *propval; 114111022STom.Erickson@Sun.COM const char *propname = zfs_prop_to_name(prop); 114211022STom.Erickson@Sun.COM 114311022STom.Erickson@Sun.COM if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) { 114411022STom.Erickson@Sun.COM VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0); 114511022STom.Erickson@Sun.COM return; 114611022STom.Erickson@Sun.COM } 11472885Sahrens 11482885Sahrens VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 11495094Slling VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0); 115011022STom.Erickson@Sun.COM VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0); 11512885Sahrens nvlist_free(propval); 11522885Sahrens } 1153