1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5ea8dc4b6Seschrock * Common Development and Distribution License (the "License"). 6ea8dc4b6Seschrock * You may not use this file except in compliance with the License. 7fa9e4066Sahrens * 8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 10fa9e4066Sahrens * See the License for the specific language governing permissions 11fa9e4066Sahrens * and limitations under the License. 12fa9e4066Sahrens * 13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18fa9e4066Sahrens * 19fa9e4066Sahrens * CDDL HEADER END 20fa9e4066Sahrens */ 21fa9e4066Sahrens /* 225c0b6a79SRich Morris * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23fa9e4066Sahrens * Use is subject to license terms. 24fa9e4066Sahrens */ 25fa9e4066Sahrens 26*92241e0bSTom Erickson #include <sys/zfs_context.h> 27fa9e4066Sahrens #include <sys/dmu.h> 287f7322feSeschrock #include <sys/dmu_objset.h> 29fa9e4066Sahrens #include <sys/dmu_tx.h> 30fa9e4066Sahrens #include <sys/dsl_dataset.h> 31fa9e4066Sahrens #include <sys/dsl_dir.h> 32fa9e4066Sahrens #include <sys/dsl_prop.h> 331d452cf5Sahrens #include <sys/dsl_synctask.h> 34fa9e4066Sahrens #include <sys/spa.h> 35fa9e4066Sahrens #include <sys/zap.h> 36fa9e4066Sahrens #include <sys/fs/zfs.h> 37fa9e4066Sahrens 38fa9e4066Sahrens #include "zfs_prop.h" 39fa9e4066Sahrens 40*92241e0bSTom Erickson #define ZPROP_INHERIT_SUFFIX "$inherit" 41*92241e0bSTom Erickson #define ZPROP_RECVD_SUFFIX "$recvd" 42*92241e0bSTom Erickson 43fa9e4066Sahrens static int 44*92241e0bSTom Erickson dodefault(const char *propname, int intsz, int numints, void *buf) 45fa9e4066Sahrens { 46fa9e4066Sahrens zfs_prop_t prop; 47fa9e4066Sahrens 48da6c28aaSamw /* 49da6c28aaSamw * The setonce properties are read-only, BUT they still 50da6c28aaSamw * have a default value that can be used as the initial 51da6c28aaSamw * value. 52da6c28aaSamw */ 53990b4856Slling if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL || 54da6c28aaSamw (zfs_prop_readonly(prop) && !zfs_prop_setonce(prop))) 55fa9e4066Sahrens return (ENOENT); 56fa9e4066Sahrens 5791ebeef5Sahrens if (zfs_prop_get_type(prop) == PROP_TYPE_STRING) { 58fa9e4066Sahrens if (intsz != 1) 59fa9e4066Sahrens return (EOVERFLOW); 60990b4856Slling (void) strncpy(buf, zfs_prop_default_string(prop), 61*92241e0bSTom Erickson numints); 62fa9e4066Sahrens } else { 63*92241e0bSTom Erickson if (intsz != 8 || numints < 1) 64fa9e4066Sahrens return (EOVERFLOW); 65fa9e4066Sahrens 66fa9e4066Sahrens *(uint64_t *)buf = zfs_prop_default_numeric(prop); 67fa9e4066Sahrens } 68fa9e4066Sahrens 69fa9e4066Sahrens return (0); 70fa9e4066Sahrens } 71fa9e4066Sahrens 72bb0ade09Sahrens int 73bb0ade09Sahrens dsl_prop_get_dd(dsl_dir_t *dd, const char *propname, 74*92241e0bSTom Erickson int intsz, int numints, void *buf, char *setpoint, boolean_t snapshot) 75fa9e4066Sahrens { 7699653d4eSeschrock int err = ENOENT; 77*92241e0bSTom Erickson dsl_dir_t *target = dd; 78bb0ade09Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 79e9dbad6fSeschrock zfs_prop_t prop; 80*92241e0bSTom Erickson boolean_t inheritable; 81*92241e0bSTom Erickson boolean_t inheriting = B_FALSE; 82*92241e0bSTom Erickson char *inheritstr; 83*92241e0bSTom Erickson char *recvdstr; 84fa9e4066Sahrens 85bb0ade09Sahrens ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock)); 86bb0ade09Sahrens 87fa9e4066Sahrens if (setpoint) 88fa9e4066Sahrens setpoint[0] = '\0'; 89fa9e4066Sahrens 90e9dbad6fSeschrock prop = zfs_name_to_prop(propname); 91*92241e0bSTom Erickson inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop)); 92*92241e0bSTom Erickson inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX); 93*92241e0bSTom Erickson recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX); 94e9dbad6fSeschrock 9599653d4eSeschrock /* 96*92241e0bSTom Erickson * Note: dd may become NULL, therefore we shouldn't dereference it 97*92241e0bSTom Erickson * after this loop. 9899653d4eSeschrock */ 9999653d4eSeschrock for (; dd != NULL; dd = dd->dd_parent) { 10099653d4eSeschrock ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock)); 101*92241e0bSTom Erickson 102*92241e0bSTom Erickson if (dd != target || snapshot) { 103*92241e0bSTom Erickson if (!inheritable) 104*92241e0bSTom Erickson break; 105*92241e0bSTom Erickson inheriting = B_TRUE; 106*92241e0bSTom Erickson } 107*92241e0bSTom Erickson 108*92241e0bSTom Erickson /* Check for a local value. */ 109*92241e0bSTom Erickson err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj, propname, 110*92241e0bSTom Erickson intsz, numints, buf); 111fa9e4066Sahrens if (err != ENOENT) { 112*92241e0bSTom Erickson if (setpoint != NULL && err == 0) 113fa9e4066Sahrens dsl_dir_name(dd, setpoint); 114fa9e4066Sahrens break; 115fa9e4066Sahrens } 116e9dbad6fSeschrock 117e9dbad6fSeschrock /* 118*92241e0bSTom Erickson * Skip the check for a received value if there is an explicit 119*92241e0bSTom Erickson * inheritance entry. 120e9dbad6fSeschrock */ 121*92241e0bSTom Erickson err = zap_contains(mos, dd->dd_phys->dd_props_zapobj, 122*92241e0bSTom Erickson inheritstr); 123*92241e0bSTom Erickson if (err != 0 && err != ENOENT) 124e9dbad6fSeschrock break; 125*92241e0bSTom Erickson 126*92241e0bSTom Erickson if (err == ENOENT) { 127*92241e0bSTom Erickson /* Check for a received value. */ 128*92241e0bSTom Erickson err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj, 129*92241e0bSTom Erickson recvdstr, intsz, numints, buf); 130*92241e0bSTom Erickson if (err != ENOENT) { 131*92241e0bSTom Erickson if (setpoint != NULL && err == 0) { 132*92241e0bSTom Erickson if (inheriting) { 133*92241e0bSTom Erickson dsl_dir_name(dd, setpoint); 134*92241e0bSTom Erickson } else { 135*92241e0bSTom Erickson (void) strcpy(setpoint, 136*92241e0bSTom Erickson ZPROP_SOURCE_VAL_RECVD); 137*92241e0bSTom Erickson } 138*92241e0bSTom Erickson } 139*92241e0bSTom Erickson break; 140*92241e0bSTom Erickson } 141*92241e0bSTom Erickson } 142*92241e0bSTom Erickson 143*92241e0bSTom Erickson /* 144*92241e0bSTom Erickson * If we found an explicit inheritance entry, err is zero even 145*92241e0bSTom Erickson * though we haven't yet found the value, so reinitializing err 146*92241e0bSTom Erickson * at the end of the loop (instead of at the beginning) ensures 147*92241e0bSTom Erickson * that err has a valid post-loop value. 148*92241e0bSTom Erickson */ 149*92241e0bSTom Erickson err = ENOENT; 150fa9e4066Sahrens } 151*92241e0bSTom Erickson 152fa9e4066Sahrens if (err == ENOENT) 153*92241e0bSTom Erickson err = dodefault(propname, intsz, numints, buf); 154*92241e0bSTom Erickson 155*92241e0bSTom Erickson strfree(inheritstr); 156*92241e0bSTom Erickson strfree(recvdstr); 157fa9e4066Sahrens 158fa9e4066Sahrens return (err); 159fa9e4066Sahrens } 160fa9e4066Sahrens 161bb0ade09Sahrens int 162bb0ade09Sahrens dsl_prop_get_ds(dsl_dataset_t *ds, const char *propname, 163*92241e0bSTom Erickson int intsz, int numints, void *buf, char *setpoint) 164bb0ade09Sahrens { 165*92241e0bSTom Erickson zfs_prop_t prop = zfs_name_to_prop(propname); 166*92241e0bSTom Erickson boolean_t inheritable; 167*92241e0bSTom Erickson boolean_t snapshot; 168*92241e0bSTom Erickson uint64_t zapobj; 169*92241e0bSTom Erickson 170bb0ade09Sahrens ASSERT(RW_LOCK_HELD(&ds->ds_dir->dd_pool->dp_config_rwlock)); 171*92241e0bSTom Erickson inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop)); 172*92241e0bSTom Erickson snapshot = (ds->ds_phys != NULL && dsl_dataset_is_snapshot(ds)); 173*92241e0bSTom Erickson zapobj = (ds->ds_phys == NULL ? 0 : ds->ds_phys->ds_props_obj); 174*92241e0bSTom Erickson 175*92241e0bSTom Erickson if (zapobj != 0) { 176*92241e0bSTom Erickson objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 177*92241e0bSTom Erickson int err; 178bb0ade09Sahrens 179*92241e0bSTom Erickson ASSERT(snapshot); 180*92241e0bSTom Erickson 181*92241e0bSTom Erickson /* Check for a local value. */ 182*92241e0bSTom Erickson err = zap_lookup(mos, zapobj, propname, intsz, numints, buf); 183bb0ade09Sahrens if (err != ENOENT) { 184*92241e0bSTom Erickson if (setpoint != NULL && err == 0) 185bb0ade09Sahrens dsl_dataset_name(ds, setpoint); 186bb0ade09Sahrens return (err); 187bb0ade09Sahrens } 188*92241e0bSTom Erickson 189*92241e0bSTom Erickson /* 190*92241e0bSTom Erickson * Skip the check for a received value if there is an explicit 191*92241e0bSTom Erickson * inheritance entry. 192*92241e0bSTom Erickson */ 193*92241e0bSTom Erickson if (inheritable) { 194*92241e0bSTom Erickson char *inheritstr = kmem_asprintf("%s%s", propname, 195*92241e0bSTom Erickson ZPROP_INHERIT_SUFFIX); 196*92241e0bSTom Erickson err = zap_contains(mos, zapobj, inheritstr); 197*92241e0bSTom Erickson strfree(inheritstr); 198*92241e0bSTom Erickson if (err != 0 && err != ENOENT) 199*92241e0bSTom Erickson return (err); 200*92241e0bSTom Erickson } 201*92241e0bSTom Erickson 202*92241e0bSTom Erickson if (err == ENOENT) { 203*92241e0bSTom Erickson /* Check for a received value. */ 204*92241e0bSTom Erickson char *recvdstr = kmem_asprintf("%s%s", propname, 205*92241e0bSTom Erickson ZPROP_RECVD_SUFFIX); 206*92241e0bSTom Erickson err = zap_lookup(mos, zapobj, recvdstr, 207*92241e0bSTom Erickson intsz, numints, buf); 208*92241e0bSTom Erickson strfree(recvdstr); 209*92241e0bSTom Erickson if (err != ENOENT) { 210*92241e0bSTom Erickson if (setpoint != NULL && err == 0) 211*92241e0bSTom Erickson (void) strcpy(setpoint, 212*92241e0bSTom Erickson ZPROP_SOURCE_VAL_RECVD); 213*92241e0bSTom Erickson return (err); 214*92241e0bSTom Erickson } 215*92241e0bSTom Erickson } 216bb0ade09Sahrens } 217bb0ade09Sahrens 218bb0ade09Sahrens return (dsl_prop_get_dd(ds->ds_dir, propname, 219*92241e0bSTom Erickson intsz, numints, buf, setpoint, snapshot)); 220bb0ade09Sahrens } 221bb0ade09Sahrens 222fa9e4066Sahrens /* 223fa9e4066Sahrens * Register interest in the named property. We'll call the callback 224fa9e4066Sahrens * once to notify it of the current property value, and again each time 225fa9e4066Sahrens * the property changes, until this callback is unregistered. 226fa9e4066Sahrens * 227fa9e4066Sahrens * Return 0 on success, errno if the prop is not an integer value. 228fa9e4066Sahrens */ 229fa9e4066Sahrens int 230fa9e4066Sahrens dsl_prop_register(dsl_dataset_t *ds, const char *propname, 231fa9e4066Sahrens dsl_prop_changed_cb_t *callback, void *cbarg) 232fa9e4066Sahrens { 23399653d4eSeschrock dsl_dir_t *dd = ds->ds_dir; 234bb0ade09Sahrens dsl_pool_t *dp = dd->dd_pool; 235fa9e4066Sahrens uint64_t value; 236fa9e4066Sahrens dsl_prop_cb_record_t *cbr; 237fa9e4066Sahrens int err; 2381d452cf5Sahrens int need_rwlock; 239fa9e4066Sahrens 240bb0ade09Sahrens need_rwlock = !RW_WRITE_HELD(&dp->dp_config_rwlock); 2411d452cf5Sahrens if (need_rwlock) 242bb0ade09Sahrens rw_enter(&dp->dp_config_rwlock, RW_READER); 243fa9e4066Sahrens 244bb0ade09Sahrens err = dsl_prop_get_ds(ds, propname, 8, 1, &value, NULL); 245fa9e4066Sahrens if (err != 0) { 24627345066Sck if (need_rwlock) 247bb0ade09Sahrens rw_exit(&dp->dp_config_rwlock); 248fa9e4066Sahrens return (err); 249fa9e4066Sahrens } 250fa9e4066Sahrens 251fa9e4066Sahrens cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP); 25299653d4eSeschrock cbr->cbr_ds = ds; 253fa9e4066Sahrens cbr->cbr_propname = kmem_alloc(strlen(propname)+1, KM_SLEEP); 254fa9e4066Sahrens (void) strcpy((char *)cbr->cbr_propname, propname); 255fa9e4066Sahrens cbr->cbr_func = callback; 256fa9e4066Sahrens cbr->cbr_arg = cbarg; 257fa9e4066Sahrens mutex_enter(&dd->dd_lock); 258fa9e4066Sahrens list_insert_head(&dd->dd_prop_cbs, cbr); 259fa9e4066Sahrens mutex_exit(&dd->dd_lock); 260fa9e4066Sahrens 261fa9e4066Sahrens cbr->cbr_func(cbr->cbr_arg, value); 262fa9e4066Sahrens 263bb0ade09Sahrens VERIFY(0 == dsl_dir_open_obj(dp, dd->dd_object, 264ea8dc4b6Seschrock NULL, cbr, &dd)); 2651d452cf5Sahrens if (need_rwlock) 266bb0ade09Sahrens rw_exit(&dp->dp_config_rwlock); 267bb0ade09Sahrens /* Leave dir open until this callback is unregistered */ 268fa9e4066Sahrens return (0); 269fa9e4066Sahrens } 270fa9e4066Sahrens 271fa9e4066Sahrens int 272bb0ade09Sahrens dsl_prop_get(const char *dsname, const char *propname, 273fa9e4066Sahrens int intsz, int numints, void *buf, char *setpoint) 274fa9e4066Sahrens { 275bb0ade09Sahrens dsl_dataset_t *ds; 276fa9e4066Sahrens int err; 277fa9e4066Sahrens 278bb0ade09Sahrens err = dsl_dataset_hold(dsname, FTAG, &ds); 279ea8dc4b6Seschrock if (err) 280ea8dc4b6Seschrock return (err); 281fa9e4066Sahrens 282bb0ade09Sahrens rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); 283bb0ade09Sahrens err = dsl_prop_get_ds(ds, propname, intsz, numints, buf, setpoint); 284bb0ade09Sahrens rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 285fa9e4066Sahrens 286bb0ade09Sahrens dsl_dataset_rele(ds, FTAG); 287fa9e4066Sahrens return (err); 288fa9e4066Sahrens } 289fa9e4066Sahrens 290fa9e4066Sahrens /* 291fa9e4066Sahrens * Get the current property value. It may have changed by the time this 292fa9e4066Sahrens * function returns, so it is NOT safe to follow up with 293fa9e4066Sahrens * dsl_prop_register() and assume that the value has not changed in 294fa9e4066Sahrens * between. 295fa9e4066Sahrens * 296fa9e4066Sahrens * Return 0 on success, ENOENT if ddname is invalid. 297fa9e4066Sahrens */ 298fa9e4066Sahrens int 299fa9e4066Sahrens dsl_prop_get_integer(const char *ddname, const char *propname, 300fa9e4066Sahrens uint64_t *valuep, char *setpoint) 301fa9e4066Sahrens { 302fa9e4066Sahrens return (dsl_prop_get(ddname, propname, 8, 1, valuep, setpoint)); 303fa9e4066Sahrens } 304fa9e4066Sahrens 305*92241e0bSTom Erickson void 306*92241e0bSTom Erickson dsl_prop_setarg_init_uint64(dsl_prop_setarg_t *psa, const char *propname, 307*92241e0bSTom Erickson zprop_source_t source, uint64_t *value) 308*92241e0bSTom Erickson { 309*92241e0bSTom Erickson psa->psa_name = propname; 310*92241e0bSTom Erickson psa->psa_source = source; 311*92241e0bSTom Erickson psa->psa_intsz = 8; 312*92241e0bSTom Erickson psa->psa_numints = 1; 313*92241e0bSTom Erickson psa->psa_value = value; 314*92241e0bSTom Erickson 315*92241e0bSTom Erickson psa->psa_effective_value = -1ULL; 316*92241e0bSTom Erickson } 317*92241e0bSTom Erickson 318*92241e0bSTom Erickson /* 319*92241e0bSTom Erickson * Predict the effective value of the given special property if it were set with 320*92241e0bSTom Erickson * the given value and source. This is not a general purpose function. It exists 321*92241e0bSTom Erickson * only to handle the special requirements of the quota and reservation 322*92241e0bSTom Erickson * properties. The fact that these properties are non-inheritable greatly 323*92241e0bSTom Erickson * simplifies the prediction logic. 324*92241e0bSTom Erickson * 325*92241e0bSTom Erickson * Returns 0 on success, a positive error code on failure, or -1 if called with 326*92241e0bSTom Erickson * a property not handled by this function. 327*92241e0bSTom Erickson */ 328*92241e0bSTom Erickson int 329*92241e0bSTom Erickson dsl_prop_predict_sync(dsl_dir_t *dd, dsl_prop_setarg_t *psa) 330*92241e0bSTom Erickson { 331*92241e0bSTom Erickson const char *propname = psa->psa_name; 332*92241e0bSTom Erickson zfs_prop_t prop = zfs_name_to_prop(propname); 333*92241e0bSTom Erickson zprop_source_t source = psa->psa_source; 334*92241e0bSTom Erickson objset_t *mos; 335*92241e0bSTom Erickson uint64_t zapobj; 336*92241e0bSTom Erickson uint64_t version; 337*92241e0bSTom Erickson char *recvdstr; 338*92241e0bSTom Erickson int err = 0; 339*92241e0bSTom Erickson 340*92241e0bSTom Erickson switch (prop) { 341*92241e0bSTom Erickson case ZFS_PROP_QUOTA: 342*92241e0bSTom Erickson case ZFS_PROP_RESERVATION: 343*92241e0bSTom Erickson case ZFS_PROP_REFQUOTA: 344*92241e0bSTom Erickson case ZFS_PROP_REFRESERVATION: 345*92241e0bSTom Erickson break; 346*92241e0bSTom Erickson default: 347*92241e0bSTom Erickson return (-1); 348*92241e0bSTom Erickson } 349*92241e0bSTom Erickson 350*92241e0bSTom Erickson mos = dd->dd_pool->dp_meta_objset; 351*92241e0bSTom Erickson zapobj = dd->dd_phys->dd_props_zapobj; 352*92241e0bSTom Erickson recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX); 353*92241e0bSTom Erickson 354*92241e0bSTom Erickson version = spa_version(dd->dd_pool->dp_spa); 355*92241e0bSTom Erickson if (version < SPA_VERSION_RECVD_PROPS) { 356*92241e0bSTom Erickson if (source & ZPROP_SRC_NONE) 357*92241e0bSTom Erickson source = ZPROP_SRC_NONE; 358*92241e0bSTom Erickson else if (source & ZPROP_SRC_RECEIVED) 359*92241e0bSTom Erickson source = ZPROP_SRC_LOCAL; 360*92241e0bSTom Erickson } 361*92241e0bSTom Erickson 362*92241e0bSTom Erickson switch (source) { 363*92241e0bSTom Erickson case ZPROP_SRC_NONE: 364*92241e0bSTom Erickson /* Revert to the received value, if any. */ 365*92241e0bSTom Erickson err = zap_lookup(mos, zapobj, recvdstr, 8, 1, 366*92241e0bSTom Erickson &psa->psa_effective_value); 367*92241e0bSTom Erickson if (err == ENOENT) 368*92241e0bSTom Erickson psa->psa_effective_value = 0; 369*92241e0bSTom Erickson break; 370*92241e0bSTom Erickson case ZPROP_SRC_LOCAL: 371*92241e0bSTom Erickson psa->psa_effective_value = *(uint64_t *)psa->psa_value; 372*92241e0bSTom Erickson break; 373*92241e0bSTom Erickson case ZPROP_SRC_RECEIVED: 374*92241e0bSTom Erickson /* 375*92241e0bSTom Erickson * If there's no local setting, then the new received value will 376*92241e0bSTom Erickson * be the effective value. 377*92241e0bSTom Erickson */ 378*92241e0bSTom Erickson err = zap_lookup(mos, zapobj, propname, 8, 1, 379*92241e0bSTom Erickson &psa->psa_effective_value); 380*92241e0bSTom Erickson if (err == ENOENT) 381*92241e0bSTom Erickson psa->psa_effective_value = *(uint64_t *)psa->psa_value; 382*92241e0bSTom Erickson break; 383*92241e0bSTom Erickson case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED): 384*92241e0bSTom Erickson /* 385*92241e0bSTom Erickson * We're clearing the received value, so the local setting (if 386*92241e0bSTom Erickson * it exists) remains the effective value. 387*92241e0bSTom Erickson */ 388*92241e0bSTom Erickson err = zap_lookup(mos, zapobj, propname, 8, 1, 389*92241e0bSTom Erickson &psa->psa_effective_value); 390*92241e0bSTom Erickson if (err == ENOENT) 391*92241e0bSTom Erickson psa->psa_effective_value = 0; 392*92241e0bSTom Erickson break; 393*92241e0bSTom Erickson default: 394*92241e0bSTom Erickson cmn_err(CE_PANIC, "unexpected property source: %d", source); 395*92241e0bSTom Erickson } 396*92241e0bSTom Erickson 397*92241e0bSTom Erickson strfree(recvdstr); 398*92241e0bSTom Erickson 399*92241e0bSTom Erickson if (err == ENOENT) 400*92241e0bSTom Erickson return (0); 401*92241e0bSTom Erickson 402*92241e0bSTom Erickson return (err); 403*92241e0bSTom Erickson } 404*92241e0bSTom Erickson 405*92241e0bSTom Erickson #ifdef ZFS_DEBUG 406*92241e0bSTom Erickson void 407*92241e0bSTom Erickson dsl_prop_check_prediction(dsl_dir_t *dd, dsl_prop_setarg_t *psa) 408*92241e0bSTom Erickson { 409*92241e0bSTom Erickson zfs_prop_t prop = zfs_name_to_prop(psa->psa_name); 410*92241e0bSTom Erickson uint64_t intval; 411*92241e0bSTom Erickson char setpoint[MAXNAMELEN]; 412*92241e0bSTom Erickson uint64_t version = spa_version(dd->dd_pool->dp_spa); 413*92241e0bSTom Erickson int err; 414*92241e0bSTom Erickson 415*92241e0bSTom Erickson if (version < SPA_VERSION_RECVD_PROPS) { 416*92241e0bSTom Erickson switch (prop) { 417*92241e0bSTom Erickson case ZFS_PROP_QUOTA: 418*92241e0bSTom Erickson case ZFS_PROP_RESERVATION: 419*92241e0bSTom Erickson return; 420*92241e0bSTom Erickson } 421*92241e0bSTom Erickson } 422*92241e0bSTom Erickson 423*92241e0bSTom Erickson err = dsl_prop_get_dd(dd, psa->psa_name, 8, 1, &intval, 424*92241e0bSTom Erickson setpoint, B_FALSE); 425*92241e0bSTom Erickson if (err == 0 && intval != psa->psa_effective_value) { 426*92241e0bSTom Erickson cmn_err(CE_PANIC, "%s property, source: %x, " 427*92241e0bSTom Erickson "predicted effective value: %llu, " 428*92241e0bSTom Erickson "actual effective value: %llu (setpoint: %s)", 429*92241e0bSTom Erickson psa->psa_name, psa->psa_source, 430*92241e0bSTom Erickson (unsigned long long)psa->psa_effective_value, 431*92241e0bSTom Erickson (unsigned long long)intval, setpoint); 432*92241e0bSTom Erickson } 433*92241e0bSTom Erickson } 434*92241e0bSTom Erickson #endif 435*92241e0bSTom Erickson 436fa9e4066Sahrens /* 437fa9e4066Sahrens * Unregister this callback. Return 0 on success, ENOENT if ddname is 438fa9e4066Sahrens * invalid, ENOMSG if no matching callback registered. 439fa9e4066Sahrens */ 440fa9e4066Sahrens int 441fa9e4066Sahrens dsl_prop_unregister(dsl_dataset_t *ds, const char *propname, 442fa9e4066Sahrens dsl_prop_changed_cb_t *callback, void *cbarg) 443fa9e4066Sahrens { 44499653d4eSeschrock dsl_dir_t *dd = ds->ds_dir; 445fa9e4066Sahrens dsl_prop_cb_record_t *cbr; 446fa9e4066Sahrens 447fa9e4066Sahrens mutex_enter(&dd->dd_lock); 448fa9e4066Sahrens for (cbr = list_head(&dd->dd_prop_cbs); 449fa9e4066Sahrens cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { 45099653d4eSeschrock if (cbr->cbr_ds == ds && 451fa9e4066Sahrens cbr->cbr_func == callback && 45299653d4eSeschrock cbr->cbr_arg == cbarg && 45399653d4eSeschrock strcmp(cbr->cbr_propname, propname) == 0) 454fa9e4066Sahrens break; 455fa9e4066Sahrens } 456fa9e4066Sahrens 457fa9e4066Sahrens if (cbr == NULL) { 458fa9e4066Sahrens mutex_exit(&dd->dd_lock); 459fa9e4066Sahrens return (ENOMSG); 460fa9e4066Sahrens } 461fa9e4066Sahrens 462fa9e4066Sahrens list_remove(&dd->dd_prop_cbs, cbr); 463fa9e4066Sahrens mutex_exit(&dd->dd_lock); 464fa9e4066Sahrens kmem_free((void*)cbr->cbr_propname, strlen(cbr->cbr_propname)+1); 465fa9e4066Sahrens kmem_free(cbr, sizeof (dsl_prop_cb_record_t)); 466fa9e4066Sahrens 467fa9e4066Sahrens /* Clean up from dsl_prop_register */ 468fa9e4066Sahrens dsl_dir_close(dd, cbr); 469fa9e4066Sahrens return (0); 470fa9e4066Sahrens } 471fa9e4066Sahrens 47299653d4eSeschrock /* 47399653d4eSeschrock * Return the number of callbacks that are registered for this dataset. 47499653d4eSeschrock */ 47599653d4eSeschrock int 47699653d4eSeschrock dsl_prop_numcb(dsl_dataset_t *ds) 47799653d4eSeschrock { 47899653d4eSeschrock dsl_dir_t *dd = ds->ds_dir; 47999653d4eSeschrock dsl_prop_cb_record_t *cbr; 48099653d4eSeschrock int num = 0; 48199653d4eSeschrock 48299653d4eSeschrock mutex_enter(&dd->dd_lock); 48399653d4eSeschrock for (cbr = list_head(&dd->dd_prop_cbs); 48499653d4eSeschrock cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { 48599653d4eSeschrock if (cbr->cbr_ds == ds) 48699653d4eSeschrock num++; 48799653d4eSeschrock } 48899653d4eSeschrock mutex_exit(&dd->dd_lock); 48999653d4eSeschrock 49099653d4eSeschrock return (num); 49199653d4eSeschrock } 49299653d4eSeschrock 493fa9e4066Sahrens static void 494fa9e4066Sahrens dsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj, 495fa9e4066Sahrens const char *propname, uint64_t value, int first) 496fa9e4066Sahrens { 497fa9e4066Sahrens dsl_dir_t *dd; 498fa9e4066Sahrens dsl_prop_cb_record_t *cbr; 499fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 5001d452cf5Sahrens zap_cursor_t zc; 501d8d77200Sahrens zap_attribute_t *za; 502fa9e4066Sahrens int err; 503fa9e4066Sahrens 504fa9e4066Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 505ea8dc4b6Seschrock err = dsl_dir_open_obj(dp, ddobj, NULL, FTAG, &dd); 506ea8dc4b6Seschrock if (err) 507ea8dc4b6Seschrock return; 508fa9e4066Sahrens 509fa9e4066Sahrens if (!first) { 510fa9e4066Sahrens /* 511fa9e4066Sahrens * If the prop is set here, then this change is not 512fa9e4066Sahrens * being inherited here or below; stop the recursion. 513fa9e4066Sahrens */ 514*92241e0bSTom Erickson err = zap_contains(mos, dd->dd_phys->dd_props_zapobj, propname); 515fa9e4066Sahrens if (err == 0) { 516fa9e4066Sahrens dsl_dir_close(dd, FTAG); 517fa9e4066Sahrens return; 518fa9e4066Sahrens } 519fa9e4066Sahrens ASSERT3U(err, ==, ENOENT); 520fa9e4066Sahrens } 521fa9e4066Sahrens 522fa9e4066Sahrens mutex_enter(&dd->dd_lock); 523bb0ade09Sahrens for (cbr = list_head(&dd->dd_prop_cbs); cbr; 524bb0ade09Sahrens cbr = list_next(&dd->dd_prop_cbs, cbr)) { 525bb0ade09Sahrens uint64_t propobj = cbr->cbr_ds->ds_phys->ds_props_obj; 526bb0ade09Sahrens 527bb0ade09Sahrens if (strcmp(cbr->cbr_propname, propname) != 0) 528bb0ade09Sahrens continue; 529bb0ade09Sahrens 530bb0ade09Sahrens /* 531bb0ade09Sahrens * If the property is set on this ds, then it is not 532bb0ade09Sahrens * inherited here; don't call the callback. 533bb0ade09Sahrens */ 534*92241e0bSTom Erickson if (propobj && 0 == zap_contains(mos, propobj, propname)) 535bb0ade09Sahrens continue; 536bb0ade09Sahrens 537bb0ade09Sahrens cbr->cbr_func(cbr->cbr_arg, value); 538fa9e4066Sahrens } 539fa9e4066Sahrens mutex_exit(&dd->dd_lock); 540fa9e4066Sahrens 541d8d77200Sahrens za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP); 5421d452cf5Sahrens for (zap_cursor_init(&zc, mos, 5431d452cf5Sahrens dd->dd_phys->dd_child_dir_zapobj); 544d8d77200Sahrens zap_cursor_retrieve(&zc, za) == 0; 5451d452cf5Sahrens zap_cursor_advance(&zc)) { 546d8d77200Sahrens dsl_prop_changed_notify(dp, za->za_first_integer, 5471d452cf5Sahrens propname, value, FALSE); 548fa9e4066Sahrens } 549d8d77200Sahrens kmem_free(za, sizeof (zap_attribute_t)); 5501d452cf5Sahrens zap_cursor_fini(&zc); 551fa9e4066Sahrens dsl_dir_close(dd, FTAG); 552fa9e4066Sahrens } 553fa9e4066Sahrens 554*92241e0bSTom Erickson void 555ecd6cf80Smarks dsl_prop_set_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 556fa9e4066Sahrens { 557bb0ade09Sahrens dsl_dataset_t *ds = arg1; 558*92241e0bSTom Erickson dsl_prop_setarg_t *psa = arg2; 559bb0ade09Sahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 560*92241e0bSTom Erickson uint64_t zapobj, intval, dummy; 5611d452cf5Sahrens int isint; 562ecd6cf80Smarks char valbuf[32]; 563*92241e0bSTom Erickson char *valstr = NULL; 564*92241e0bSTom Erickson char *inheritstr; 565*92241e0bSTom Erickson char *recvdstr; 566*92241e0bSTom Erickson char *tbuf = NULL; 567*92241e0bSTom Erickson int err; 568*92241e0bSTom Erickson uint64_t version = spa_version(ds->ds_dir->dd_pool->dp_spa); 569*92241e0bSTom Erickson const char *propname = psa->psa_name; 570*92241e0bSTom Erickson zprop_source_t source = psa->psa_source; 571fa9e4066Sahrens 572*92241e0bSTom Erickson isint = (dodefault(propname, 8, 1, &intval) == 0); 573fa9e4066Sahrens 574*92241e0bSTom Erickson if (ds->ds_phys != NULL && dsl_dataset_is_snapshot(ds)) { 575*92241e0bSTom Erickson ASSERT(version >= SPA_VERSION_SNAP_PROPS); 576bb0ade09Sahrens if (ds->ds_phys->ds_props_obj == 0) { 577bb0ade09Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 578bb0ade09Sahrens ds->ds_phys->ds_props_obj = 579bb0ade09Sahrens zap_create(mos, 580bb0ade09Sahrens DMU_OT_DSL_PROPS, DMU_OT_NONE, 0, tx); 581bb0ade09Sahrens } 582bb0ade09Sahrens zapobj = ds->ds_phys->ds_props_obj; 583bb0ade09Sahrens } else { 584bb0ade09Sahrens zapobj = ds->ds_dir->dd_phys->dd_props_zapobj; 585bb0ade09Sahrens } 586bb0ade09Sahrens 587*92241e0bSTom Erickson if (version < SPA_VERSION_RECVD_PROPS) { 588*92241e0bSTom Erickson zfs_prop_t prop = zfs_name_to_prop(propname); 589*92241e0bSTom Erickson if (prop == ZFS_PROP_QUOTA || prop == ZFS_PROP_RESERVATION) 590*92241e0bSTom Erickson return; 591*92241e0bSTom Erickson 592*92241e0bSTom Erickson if (source & ZPROP_SRC_NONE) 593*92241e0bSTom Erickson source = ZPROP_SRC_NONE; 594*92241e0bSTom Erickson else if (source & ZPROP_SRC_RECEIVED) 595*92241e0bSTom Erickson source = ZPROP_SRC_LOCAL; 596*92241e0bSTom Erickson } 597*92241e0bSTom Erickson 598*92241e0bSTom Erickson inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX); 599*92241e0bSTom Erickson recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX); 600*92241e0bSTom Erickson 601*92241e0bSTom Erickson switch (source) { 602*92241e0bSTom Erickson case ZPROP_SRC_NONE: 603*92241e0bSTom Erickson /* 604*92241e0bSTom Erickson * revert to received value, if any (inherit -S) 605*92241e0bSTom Erickson * - remove propname 606*92241e0bSTom Erickson * - remove propname$inherit 607*92241e0bSTom Erickson */ 608*92241e0bSTom Erickson err = zap_remove(mos, zapobj, propname, tx); 609*92241e0bSTom Erickson ASSERT(err == 0 || err == ENOENT); 610*92241e0bSTom Erickson err = zap_remove(mos, zapobj, inheritstr, tx); 611*92241e0bSTom Erickson ASSERT(err == 0 || err == ENOENT); 612*92241e0bSTom Erickson break; 613*92241e0bSTom Erickson case ZPROP_SRC_LOCAL: 614*92241e0bSTom Erickson /* 615*92241e0bSTom Erickson * remove propname$inherit 616*92241e0bSTom Erickson * set propname -> value 617*92241e0bSTom Erickson */ 618*92241e0bSTom Erickson err = zap_remove(mos, zapobj, inheritstr, tx); 619*92241e0bSTom Erickson ASSERT(err == 0 || err == ENOENT); 620*92241e0bSTom Erickson VERIFY(0 == zap_update(mos, zapobj, propname, 621*92241e0bSTom Erickson psa->psa_intsz, psa->psa_numints, psa->psa_value, tx)); 622*92241e0bSTom Erickson break; 623*92241e0bSTom Erickson case ZPROP_SRC_INHERITED: 624*92241e0bSTom Erickson /* 625*92241e0bSTom Erickson * explicitly inherit 626*92241e0bSTom Erickson * - remove propname 627*92241e0bSTom Erickson * - set propname$inherit 628*92241e0bSTom Erickson */ 629*92241e0bSTom Erickson err = zap_remove(mos, zapobj, propname, tx); 6301d452cf5Sahrens ASSERT(err == 0 || err == ENOENT); 631*92241e0bSTom Erickson if (version >= SPA_VERSION_RECVD_PROPS && 632*92241e0bSTom Erickson zap_contains(mos, zapobj, ZPROP_HAS_RECVD) == 0) { 633*92241e0bSTom Erickson dummy = 0; 634*92241e0bSTom Erickson err = zap_update(mos, zapobj, inheritstr, 635*92241e0bSTom Erickson 8, 1, &dummy, tx); 636*92241e0bSTom Erickson ASSERT(err == 0); 637fa9e4066Sahrens } 638*92241e0bSTom Erickson break; 639*92241e0bSTom Erickson case ZPROP_SRC_RECEIVED: 640*92241e0bSTom Erickson /* 641*92241e0bSTom Erickson * set propname$recvd -> value 642*92241e0bSTom Erickson */ 643*92241e0bSTom Erickson err = zap_update(mos, zapobj, recvdstr, 644*92241e0bSTom Erickson psa->psa_intsz, psa->psa_numints, psa->psa_value, tx); 645*92241e0bSTom Erickson ASSERT(err == 0); 646*92241e0bSTom Erickson break; 647*92241e0bSTom Erickson case (ZPROP_SRC_NONE | ZPROP_SRC_LOCAL | ZPROP_SRC_RECEIVED): 648*92241e0bSTom Erickson /* 649*92241e0bSTom Erickson * clear local and received settings 650*92241e0bSTom Erickson * - remove propname 651*92241e0bSTom Erickson * - remove propname$inherit 652*92241e0bSTom Erickson * - remove propname$recvd 653*92241e0bSTom Erickson */ 654*92241e0bSTom Erickson err = zap_remove(mos, zapobj, propname, tx); 655*92241e0bSTom Erickson ASSERT(err == 0 || err == ENOENT); 656*92241e0bSTom Erickson err = zap_remove(mos, zapobj, inheritstr, tx); 657*92241e0bSTom Erickson ASSERT(err == 0 || err == ENOENT); 658*92241e0bSTom Erickson /* FALLTHRU */ 659*92241e0bSTom Erickson case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED): 660*92241e0bSTom Erickson /* 661*92241e0bSTom Erickson * remove propname$recvd 662*92241e0bSTom Erickson */ 663*92241e0bSTom Erickson err = zap_remove(mos, zapobj, recvdstr, tx); 664*92241e0bSTom Erickson ASSERT(err == 0 || err == ENOENT); 665*92241e0bSTom Erickson break; 666*92241e0bSTom Erickson default: 667*92241e0bSTom Erickson cmn_err(CE_PANIC, "unexpected property source: %d", source); 668fa9e4066Sahrens } 669fa9e4066Sahrens 670*92241e0bSTom Erickson strfree(inheritstr); 671*92241e0bSTom Erickson strfree(recvdstr); 672*92241e0bSTom Erickson 6731d452cf5Sahrens if (isint) { 674*92241e0bSTom Erickson VERIFY(0 == dsl_prop_get_ds(ds, propname, 8, 1, &intval, NULL)); 675*92241e0bSTom Erickson 676*92241e0bSTom Erickson if (ds->ds_phys != NULL && dsl_dataset_is_snapshot(ds)) { 677bb0ade09Sahrens dsl_prop_cb_record_t *cbr; 678bb0ade09Sahrens /* 679bb0ade09Sahrens * It's a snapshot; nothing can inherit this 680bb0ade09Sahrens * property, so just look for callbacks on this 681bb0ade09Sahrens * ds here. 682bb0ade09Sahrens */ 683bb0ade09Sahrens mutex_enter(&ds->ds_dir->dd_lock); 684bb0ade09Sahrens for (cbr = list_head(&ds->ds_dir->dd_prop_cbs); cbr; 685bb0ade09Sahrens cbr = list_next(&ds->ds_dir->dd_prop_cbs, cbr)) { 686bb0ade09Sahrens if (cbr->cbr_ds == ds && 687*92241e0bSTom Erickson strcmp(cbr->cbr_propname, propname) == 0) 688bb0ade09Sahrens cbr->cbr_func(cbr->cbr_arg, intval); 689bb0ade09Sahrens } 690bb0ade09Sahrens mutex_exit(&ds->ds_dir->dd_lock); 691bb0ade09Sahrens } else { 692bb0ade09Sahrens dsl_prop_changed_notify(ds->ds_dir->dd_pool, 693*92241e0bSTom Erickson ds->ds_dir->dd_object, propname, intval, TRUE); 694bb0ade09Sahrens } 695*92241e0bSTom Erickson 696ecd6cf80Smarks (void) snprintf(valbuf, sizeof (valbuf), 697ecd6cf80Smarks "%lld", (longlong_t)intval); 698ecd6cf80Smarks valstr = valbuf; 699ecd6cf80Smarks } else { 700*92241e0bSTom Erickson if (source == ZPROP_SRC_LOCAL) { 701*92241e0bSTom Erickson valstr = (char *)psa->psa_value; 702*92241e0bSTom Erickson } else { 703*92241e0bSTom Erickson tbuf = kmem_alloc(ZAP_MAXVALUELEN, KM_SLEEP); 704*92241e0bSTom Erickson if (dsl_prop_get_ds(ds, propname, 1, 705*92241e0bSTom Erickson ZAP_MAXVALUELEN, tbuf, NULL) == 0) 706*92241e0bSTom Erickson valstr = tbuf; 707*92241e0bSTom Erickson } 708ecd6cf80Smarks } 709*92241e0bSTom Erickson 710*92241e0bSTom Erickson spa_history_internal_log((source == ZPROP_SRC_NONE || 711*92241e0bSTom Erickson source == ZPROP_SRC_INHERITED) ? LOG_DS_INHERIT : 712bb0ade09Sahrens LOG_DS_PROPSET, ds->ds_dir->dd_pool->dp_spa, tx, cr, 713*92241e0bSTom Erickson "%s=%s dataset = %llu", propname, 714*92241e0bSTom Erickson (valstr == NULL ? "" : valstr), ds->ds_object); 715*92241e0bSTom Erickson 716*92241e0bSTom Erickson if (tbuf != NULL) 717*92241e0bSTom Erickson kmem_free(tbuf, ZAP_MAXVALUELEN); 718fa9e4066Sahrens } 719fa9e4066Sahrens 720ea2f5b9eSMatthew Ahrens void 7215c0b6a79SRich Morris dsl_props_set_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 7225c0b6a79SRich Morris { 7235c0b6a79SRich Morris dsl_dataset_t *ds = arg1; 724*92241e0bSTom Erickson dsl_props_arg_t *pa = arg2; 725*92241e0bSTom Erickson nvlist_t *props = pa->pa_props; 726*92241e0bSTom Erickson dsl_prop_setarg_t psa; 7275c0b6a79SRich Morris nvpair_t *elem = NULL; 7285c0b6a79SRich Morris 729*92241e0bSTom Erickson psa.psa_source = pa->pa_source; 7305c0b6a79SRich Morris 731*92241e0bSTom Erickson while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 732*92241e0bSTom Erickson nvpair_t *pair = elem; 7335c0b6a79SRich Morris 734*92241e0bSTom Erickson psa.psa_name = nvpair_name(pair); 735*92241e0bSTom Erickson 736*92241e0bSTom Erickson if (nvpair_type(pair) == DATA_TYPE_NVLIST) { 737*92241e0bSTom Erickson /* 738*92241e0bSTom Erickson * dsl_prop_get_all_impl() returns properties in this 739*92241e0bSTom Erickson * format. 740*92241e0bSTom Erickson */ 741*92241e0bSTom Erickson nvlist_t *attrs; 742*92241e0bSTom Erickson VERIFY(nvpair_value_nvlist(pair, &attrs) == 0); 743*92241e0bSTom Erickson VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 744*92241e0bSTom Erickson &pair) == 0); 745*92241e0bSTom Erickson } 746*92241e0bSTom Erickson 747*92241e0bSTom Erickson if (nvpair_type(pair) == DATA_TYPE_STRING) { 748*92241e0bSTom Erickson VERIFY(nvpair_value_string(pair, 749*92241e0bSTom Erickson (char **)&psa.psa_value) == 0); 750*92241e0bSTom Erickson psa.psa_intsz = 1; 751*92241e0bSTom Erickson psa.psa_numints = strlen(psa.psa_value) + 1; 7525c0b6a79SRich Morris } else { 7535c0b6a79SRich Morris uint64_t intval; 754*92241e0bSTom Erickson VERIFY(nvpair_value_uint64(pair, &intval) == 0); 755*92241e0bSTom Erickson psa.psa_intsz = sizeof (intval); 756*92241e0bSTom Erickson psa.psa_numints = 1; 757*92241e0bSTom Erickson psa.psa_value = &intval; 7585c0b6a79SRich Morris } 7595c0b6a79SRich Morris dsl_prop_set_sync(ds, &psa, cr, tx); 7605c0b6a79SRich Morris } 7615c0b6a79SRich Morris } 7625c0b6a79SRich Morris 763a9799022Sck void 764842727c2SChris Kirby dsl_dir_prop_set_uint64_sync(dsl_dir_t *dd, const char *name, uint64_t val, 765a9799022Sck cred_t *cr, dmu_tx_t *tx) 766a9799022Sck { 767a9799022Sck objset_t *mos = dd->dd_pool->dp_meta_objset; 768a9799022Sck uint64_t zapobj = dd->dd_phys->dd_props_zapobj; 769a9799022Sck 770a9799022Sck ASSERT(dmu_tx_is_syncing(tx)); 771a9799022Sck 772a9799022Sck VERIFY(0 == zap_update(mos, zapobj, name, sizeof (val), 1, &val, tx)); 773a9799022Sck 774a9799022Sck dsl_prop_changed_notify(dd->dd_pool, dd->dd_object, name, val, TRUE); 775a9799022Sck 776a9799022Sck spa_history_internal_log(LOG_DS_PROPSET, dd->dd_pool->dp_spa, tx, cr, 777a9799022Sck "%s=%llu dataset = %llu", name, (u_longlong_t)val, 778a9799022Sck dd->dd_phys->dd_head_dataset_obj); 779a9799022Sck } 780a9799022Sck 781a2eea2e1Sahrens int 782*92241e0bSTom Erickson dsl_prop_set(const char *dsname, const char *propname, zprop_source_t source, 783fa9e4066Sahrens int intsz, int numints, const void *buf) 784fa9e4066Sahrens { 785bb0ade09Sahrens dsl_dataset_t *ds; 786478ed9adSEric Taylor uint64_t version; 787fa9e4066Sahrens int err; 788*92241e0bSTom Erickson dsl_prop_setarg_t psa; 789fa9e4066Sahrens 790455d5089Sahrens /* 791455d5089Sahrens * We must do these checks before we get to the syncfunc, since 792455d5089Sahrens * it can't fail. 793455d5089Sahrens */ 794455d5089Sahrens if (strlen(propname) >= ZAP_MAXNAMELEN) 795455d5089Sahrens return (ENAMETOOLONG); 796455d5089Sahrens 797bb0ade09Sahrens err = dsl_dataset_hold(dsname, FTAG, &ds); 798ea8dc4b6Seschrock if (err) 799ea8dc4b6Seschrock return (err); 800bb0ade09Sahrens 801478ed9adSEric Taylor version = spa_version(ds->ds_dir->dd_pool->dp_spa); 802478ed9adSEric Taylor if (intsz * numints >= (version < SPA_VERSION_STMF_PROP ? 803478ed9adSEric Taylor ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) { 804478ed9adSEric Taylor dsl_dataset_rele(ds, FTAG); 805478ed9adSEric Taylor return (E2BIG); 806478ed9adSEric Taylor } 807bb0ade09Sahrens if (dsl_dataset_is_snapshot(ds) && 808478ed9adSEric Taylor version < SPA_VERSION_SNAP_PROPS) { 809bb0ade09Sahrens dsl_dataset_rele(ds, FTAG); 810bb0ade09Sahrens return (ENOTSUP); 811bb0ade09Sahrens } 812bb0ade09Sahrens 813*92241e0bSTom Erickson psa.psa_name = propname; 814*92241e0bSTom Erickson psa.psa_source = source; 815*92241e0bSTom Erickson psa.psa_intsz = intsz; 816*92241e0bSTom Erickson psa.psa_numints = numints; 817*92241e0bSTom Erickson psa.psa_value = buf; 818*92241e0bSTom Erickson psa.psa_effective_value = -1ULL; 819*92241e0bSTom Erickson 820bb0ade09Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 821bb0ade09Sahrens NULL, dsl_prop_set_sync, ds, &psa, 2); 822bb0ade09Sahrens 823bb0ade09Sahrens dsl_dataset_rele(ds, FTAG); 824fa9e4066Sahrens return (err); 825fa9e4066Sahrens } 8267f7322feSeschrock 8275c0b6a79SRich Morris int 828*92241e0bSTom Erickson dsl_props_set(const char *dsname, zprop_source_t source, nvlist_t *props) 8295c0b6a79SRich Morris { 8305c0b6a79SRich Morris dsl_dataset_t *ds; 831478ed9adSEric Taylor uint64_t version; 8325c0b6a79SRich Morris nvpair_t *elem = NULL; 833*92241e0bSTom Erickson dsl_props_arg_t pa; 8345c0b6a79SRich Morris int err; 8355c0b6a79SRich Morris 836478ed9adSEric Taylor if (err = dsl_dataset_hold(dsname, FTAG, &ds)) 837478ed9adSEric Taylor return (err); 838ccba0801SRich Morris /* 839ccba0801SRich Morris * Do these checks before the syncfunc, since it can't fail. 840ccba0801SRich Morris */ 841478ed9adSEric Taylor version = spa_version(ds->ds_dir->dd_pool->dp_spa); 842*92241e0bSTom Erickson while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 843478ed9adSEric Taylor if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) { 844478ed9adSEric Taylor dsl_dataset_rele(ds, FTAG); 845ccba0801SRich Morris return (ENAMETOOLONG); 846478ed9adSEric Taylor } 8475c0b6a79SRich Morris if (nvpair_type(elem) == DATA_TYPE_STRING) { 8485c0b6a79SRich Morris char *valstr; 8495c0b6a79SRich Morris VERIFY(nvpair_value_string(elem, &valstr) == 0); 850478ed9adSEric Taylor if (strlen(valstr) >= (version < 851478ed9adSEric Taylor SPA_VERSION_STMF_PROP ? 852478ed9adSEric Taylor ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) { 853478ed9adSEric Taylor dsl_dataset_rele(ds, FTAG); 854ccba0801SRich Morris return (E2BIG); 855478ed9adSEric Taylor } 8565c0b6a79SRich Morris } 8575c0b6a79SRich Morris } 8585c0b6a79SRich Morris 8595c0b6a79SRich Morris if (dsl_dataset_is_snapshot(ds) && 860478ed9adSEric Taylor version < SPA_VERSION_SNAP_PROPS) { 8615c0b6a79SRich Morris dsl_dataset_rele(ds, FTAG); 8625c0b6a79SRich Morris return (ENOTSUP); 8635c0b6a79SRich Morris } 8645c0b6a79SRich Morris 865*92241e0bSTom Erickson pa.pa_props = props; 866*92241e0bSTom Erickson pa.pa_source = source; 867*92241e0bSTom Erickson 8685c0b6a79SRich Morris err = dsl_sync_task_do(ds->ds_dir->dd_pool, 869*92241e0bSTom Erickson NULL, dsl_props_set_sync, ds, &pa, 2); 8705c0b6a79SRich Morris 8715c0b6a79SRich Morris dsl_dataset_rele(ds, FTAG); 8725c0b6a79SRich Morris return (err); 8735c0b6a79SRich Morris } 8745c0b6a79SRich Morris 875*92241e0bSTom Erickson typedef enum dsl_prop_getflags { 876*92241e0bSTom Erickson DSL_PROP_GET_INHERITING = 0x1, /* searching parent of target ds */ 877*92241e0bSTom Erickson DSL_PROP_GET_SNAPSHOT = 0x2, /* snapshot dataset */ 878*92241e0bSTom Erickson DSL_PROP_GET_LOCAL = 0x4, /* local properties */ 879*92241e0bSTom Erickson DSL_PROP_GET_RECEIVED = 0x8 /* received properties */ 880*92241e0bSTom Erickson } dsl_prop_getflags_t; 881*92241e0bSTom Erickson 882*92241e0bSTom Erickson static int 883*92241e0bSTom Erickson dsl_prop_get_all_impl(objset_t *mos, uint64_t propobj, 884*92241e0bSTom Erickson const char *setpoint, dsl_prop_getflags_t flags, nvlist_t *nv) 885*92241e0bSTom Erickson { 886*92241e0bSTom Erickson zap_cursor_t zc; 887*92241e0bSTom Erickson zap_attribute_t za; 888*92241e0bSTom Erickson int err = 0; 889*92241e0bSTom Erickson 890*92241e0bSTom Erickson for (zap_cursor_init(&zc, mos, propobj); 891*92241e0bSTom Erickson (err = zap_cursor_retrieve(&zc, &za)) == 0; 892*92241e0bSTom Erickson zap_cursor_advance(&zc)) { 893*92241e0bSTom Erickson nvlist_t *propval; 894*92241e0bSTom Erickson zfs_prop_t prop; 895*92241e0bSTom Erickson char buf[ZAP_MAXNAMELEN]; 896*92241e0bSTom Erickson char *valstr; 897*92241e0bSTom Erickson const char *suffix; 898*92241e0bSTom Erickson const char *propname; 899*92241e0bSTom Erickson const char *source; 900*92241e0bSTom Erickson 901*92241e0bSTom Erickson suffix = strchr(za.za_name, '$'); 902*92241e0bSTom Erickson 903*92241e0bSTom Erickson if (suffix == NULL) { 904*92241e0bSTom Erickson /* 905*92241e0bSTom Erickson * Skip local properties if we only want received 906*92241e0bSTom Erickson * properties. 907*92241e0bSTom Erickson */ 908*92241e0bSTom Erickson if (flags & DSL_PROP_GET_RECEIVED) 909*92241e0bSTom Erickson continue; 910*92241e0bSTom Erickson 911*92241e0bSTom Erickson propname = za.za_name; 912*92241e0bSTom Erickson source = setpoint; 913*92241e0bSTom Erickson } else if (strcmp(suffix, ZPROP_INHERIT_SUFFIX) == 0) { 914*92241e0bSTom Erickson /* Skip explicitly inherited entries. */ 915*92241e0bSTom Erickson continue; 916*92241e0bSTom Erickson } else if (strcmp(suffix, ZPROP_RECVD_SUFFIX) == 0) { 917*92241e0bSTom Erickson if (flags & DSL_PROP_GET_LOCAL) 918*92241e0bSTom Erickson continue; 919*92241e0bSTom Erickson 920*92241e0bSTom Erickson (void) strncpy(buf, za.za_name, (suffix - za.za_name)); 921*92241e0bSTom Erickson buf[suffix - za.za_name] = '\0'; 922*92241e0bSTom Erickson propname = buf; 923*92241e0bSTom Erickson 924*92241e0bSTom Erickson if (!(flags & DSL_PROP_GET_RECEIVED)) { 925*92241e0bSTom Erickson /* Skip if locally overridden. */ 926*92241e0bSTom Erickson err = zap_contains(mos, propobj, propname); 927*92241e0bSTom Erickson if (err == 0) 928*92241e0bSTom Erickson continue; 929*92241e0bSTom Erickson if (err != ENOENT) 930*92241e0bSTom Erickson break; 931*92241e0bSTom Erickson 932*92241e0bSTom Erickson /* Skip if explicitly inherited. */ 933*92241e0bSTom Erickson valstr = kmem_asprintf("%s%s", propname, 934*92241e0bSTom Erickson ZPROP_INHERIT_SUFFIX); 935*92241e0bSTom Erickson err = zap_contains(mos, propobj, valstr); 936*92241e0bSTom Erickson strfree(valstr); 937*92241e0bSTom Erickson if (err == 0) 938*92241e0bSTom Erickson continue; 939*92241e0bSTom Erickson if (err != ENOENT) 940*92241e0bSTom Erickson break; 941*92241e0bSTom Erickson } 942*92241e0bSTom Erickson 943*92241e0bSTom Erickson source = ((flags & DSL_PROP_GET_INHERITING) ? 944*92241e0bSTom Erickson setpoint : ZPROP_SOURCE_VAL_RECVD); 945*92241e0bSTom Erickson } else { 946*92241e0bSTom Erickson /* 947*92241e0bSTom Erickson * For backward compatibility, skip suffixes we don't 948*92241e0bSTom Erickson * recognize. 949*92241e0bSTom Erickson */ 950*92241e0bSTom Erickson continue; 951*92241e0bSTom Erickson } 952*92241e0bSTom Erickson 953*92241e0bSTom Erickson prop = zfs_name_to_prop(propname); 954*92241e0bSTom Erickson 955*92241e0bSTom Erickson /* Skip non-inheritable properties. */ 956*92241e0bSTom Erickson if ((flags & DSL_PROP_GET_INHERITING) && prop != ZPROP_INVAL && 957*92241e0bSTom Erickson !zfs_prop_inheritable(prop)) 958*92241e0bSTom Erickson continue; 959*92241e0bSTom Erickson 960*92241e0bSTom Erickson /* Skip properties not valid for this type. */ 961*92241e0bSTom Erickson if ((flags & DSL_PROP_GET_SNAPSHOT) && prop != ZPROP_INVAL && 962*92241e0bSTom Erickson !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT)) 963*92241e0bSTom Erickson continue; 964*92241e0bSTom Erickson 965*92241e0bSTom Erickson /* Skip properties already defined. */ 966*92241e0bSTom Erickson if (nvlist_exists(nv, propname)) 967*92241e0bSTom Erickson continue; 968*92241e0bSTom Erickson 969*92241e0bSTom Erickson VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 970*92241e0bSTom Erickson if (za.za_integer_length == 1) { 971*92241e0bSTom Erickson /* 972*92241e0bSTom Erickson * String property 973*92241e0bSTom Erickson */ 974*92241e0bSTom Erickson char *tmp = kmem_alloc(za.za_num_integers, 975*92241e0bSTom Erickson KM_SLEEP); 976*92241e0bSTom Erickson err = zap_lookup(mos, propobj, 977*92241e0bSTom Erickson za.za_name, 1, za.za_num_integers, tmp); 978*92241e0bSTom Erickson if (err != 0) { 979*92241e0bSTom Erickson kmem_free(tmp, za.za_num_integers); 980*92241e0bSTom Erickson break; 981*92241e0bSTom Erickson } 982*92241e0bSTom Erickson VERIFY(nvlist_add_string(propval, ZPROP_VALUE, 983*92241e0bSTom Erickson tmp) == 0); 984*92241e0bSTom Erickson kmem_free(tmp, za.za_num_integers); 985*92241e0bSTom Erickson } else { 986*92241e0bSTom Erickson /* 987*92241e0bSTom Erickson * Integer property 988*92241e0bSTom Erickson */ 989*92241e0bSTom Erickson ASSERT(za.za_integer_length == 8); 990*92241e0bSTom Erickson (void) nvlist_add_uint64(propval, ZPROP_VALUE, 991*92241e0bSTom Erickson za.za_first_integer); 992*92241e0bSTom Erickson } 993*92241e0bSTom Erickson 994*92241e0bSTom Erickson VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, source) == 0); 995*92241e0bSTom Erickson VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0); 996*92241e0bSTom Erickson nvlist_free(propval); 997*92241e0bSTom Erickson } 998*92241e0bSTom Erickson zap_cursor_fini(&zc); 999*92241e0bSTom Erickson if (err == ENOENT) 1000*92241e0bSTom Erickson err = 0; 1001*92241e0bSTom Erickson return (err); 1002*92241e0bSTom Erickson } 1003*92241e0bSTom Erickson 10047f7322feSeschrock /* 10057f7322feSeschrock * Iterate over all properties for this dataset and return them in an nvlist. 10067f7322feSeschrock */ 1007*92241e0bSTom Erickson static int 1008*92241e0bSTom Erickson dsl_prop_get_all_ds(dsl_dataset_t *ds, nvlist_t **nvp, 1009*92241e0bSTom Erickson dsl_prop_getflags_t flags) 10107f7322feSeschrock { 101199653d4eSeschrock dsl_dir_t *dd = ds->ds_dir; 1012bb0ade09Sahrens dsl_pool_t *dp = dd->dd_pool; 1013bb0ade09Sahrens objset_t *mos = dp->dp_meta_objset; 1014*92241e0bSTom Erickson int err = 0; 1015*92241e0bSTom Erickson char setpoint[MAXNAMELEN]; 10167f7322feSeschrock 10177f7322feSeschrock VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); 10187f7322feSeschrock 1019*92241e0bSTom Erickson if (dsl_dataset_is_snapshot(ds)) 1020*92241e0bSTom Erickson flags |= DSL_PROP_GET_SNAPSHOT; 10217f7322feSeschrock 10227f7322feSeschrock rw_enter(&dp->dp_config_rwlock, RW_READER); 1023*92241e0bSTom Erickson 1024*92241e0bSTom Erickson if (ds->ds_phys->ds_props_obj != 0) { 1025*92241e0bSTom Erickson ASSERT(flags & DSL_PROP_GET_SNAPSHOT); 1026*92241e0bSTom Erickson dsl_dataset_name(ds, setpoint); 1027*92241e0bSTom Erickson err = dsl_prop_get_all_impl(mos, ds->ds_phys->ds_props_obj, 1028*92241e0bSTom Erickson setpoint, flags, *nvp); 1029*92241e0bSTom Erickson if (err) 1030*92241e0bSTom Erickson goto out; 1031*92241e0bSTom Erickson } 1032*92241e0bSTom Erickson 1033*92241e0bSTom Erickson for (; dd != NULL; dd = dd->dd_parent) { 1034*92241e0bSTom Erickson if (dd != ds->ds_dir || (flags & DSL_PROP_GET_SNAPSHOT)) { 1035*92241e0bSTom Erickson if (flags & (DSL_PROP_GET_LOCAL | 1036*92241e0bSTom Erickson DSL_PROP_GET_RECEIVED)) 1037*92241e0bSTom Erickson break; 1038*92241e0bSTom Erickson flags |= DSL_PROP_GET_INHERITING; 1039bb0ade09Sahrens } 1040*92241e0bSTom Erickson dsl_dir_name(dd, setpoint); 1041*92241e0bSTom Erickson err = dsl_prop_get_all_impl(mos, dd->dd_phys->dd_props_zapobj, 1042*92241e0bSTom Erickson setpoint, flags, *nvp); 1043*92241e0bSTom Erickson if (err) 1044*92241e0bSTom Erickson break; 1045*92241e0bSTom Erickson } 1046*92241e0bSTom Erickson out: 1047*92241e0bSTom Erickson rw_exit(&dp->dp_config_rwlock); 1048*92241e0bSTom Erickson return (err); 1049*92241e0bSTom Erickson } 1050a2eea2e1Sahrens 1051*92241e0bSTom Erickson boolean_t 1052*92241e0bSTom Erickson dsl_prop_get_hasrecvd(objset_t *os) 1053*92241e0bSTom Erickson { 1054*92241e0bSTom Erickson dsl_dataset_t *ds = os->os_dsl_dataset; 1055*92241e0bSTom Erickson int rc; 1056*92241e0bSTom Erickson uint64_t dummy; 1057bb0ade09Sahrens 1058*92241e0bSTom Erickson rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); 1059*92241e0bSTom Erickson rc = dsl_prop_get_ds(ds, ZPROP_HAS_RECVD, 8, 1, &dummy, NULL); 1060*92241e0bSTom Erickson rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 1061*92241e0bSTom Erickson ASSERT(rc != 0 || spa_version(os->os_spa) >= SPA_VERSION_RECVD_PROPS); 1062*92241e0bSTom Erickson return (rc == 0); 1063*92241e0bSTom Erickson } 1064e9dbad6fSeschrock 1065*92241e0bSTom Erickson static void 1066*92241e0bSTom Erickson dsl_prop_set_hasrecvd_impl(objset_t *os, zprop_source_t source) 1067*92241e0bSTom Erickson { 1068*92241e0bSTom Erickson dsl_dataset_t *ds = os->os_dsl_dataset; 1069*92241e0bSTom Erickson uint64_t dummy = 0; 1070*92241e0bSTom Erickson dsl_prop_setarg_t psa; 1071da6c28aaSamw 1072*92241e0bSTom Erickson if (spa_version(os->os_spa) < SPA_VERSION_RECVD_PROPS) 1073*92241e0bSTom Erickson return; 10747f7322feSeschrock 1075*92241e0bSTom Erickson dsl_prop_setarg_init_uint64(&psa, ZPROP_HAS_RECVD, source, &dummy); 10767f7322feSeschrock 1077*92241e0bSTom Erickson (void) dsl_sync_task_do(ds->ds_dir->dd_pool, NULL, 1078*92241e0bSTom Erickson dsl_prop_set_sync, ds, &psa, 2); 1079*92241e0bSTom Erickson } 10807f7322feSeschrock 1081*92241e0bSTom Erickson /* 1082*92241e0bSTom Erickson * Call after successfully receiving properties to ensure that only the first 1083*92241e0bSTom Erickson * receive on or after SPA_VERSION_RECVD_PROPS blows away local properties. 1084*92241e0bSTom Erickson */ 1085*92241e0bSTom Erickson void 1086*92241e0bSTom Erickson dsl_prop_set_hasrecvd(objset_t *os) 1087*92241e0bSTom Erickson { 1088*92241e0bSTom Erickson if (dsl_prop_get_hasrecvd(os)) { 1089*92241e0bSTom Erickson ASSERT(spa_version(os->os_spa) >= SPA_VERSION_RECVD_PROPS); 1090*92241e0bSTom Erickson return; 10917f7322feSeschrock } 1092*92241e0bSTom Erickson dsl_prop_set_hasrecvd_impl(os, ZPROP_SRC_LOCAL); 1093*92241e0bSTom Erickson } 10947f7322feSeschrock 1095*92241e0bSTom Erickson void 1096*92241e0bSTom Erickson dsl_prop_unset_hasrecvd(objset_t *os) 1097*92241e0bSTom Erickson { 1098*92241e0bSTom Erickson dsl_prop_set_hasrecvd_impl(os, ZPROP_SRC_NONE); 1099*92241e0bSTom Erickson } 1100*92241e0bSTom Erickson 1101*92241e0bSTom Erickson int 1102*92241e0bSTom Erickson dsl_prop_get_all(objset_t *os, nvlist_t **nvp) 1103*92241e0bSTom Erickson { 1104*92241e0bSTom Erickson return (dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, 0)); 1105*92241e0bSTom Erickson } 1106*92241e0bSTom Erickson 1107*92241e0bSTom Erickson int 1108*92241e0bSTom Erickson dsl_prop_get_received(objset_t *os, nvlist_t **nvp) 1109*92241e0bSTom Erickson { 1110*92241e0bSTom Erickson /* 1111*92241e0bSTom Erickson * Received properties are not distinguishable from local properties 1112*92241e0bSTom Erickson * until the dataset has received properties on or after 1113*92241e0bSTom Erickson * SPA_VERSION_RECVD_PROPS. 1114*92241e0bSTom Erickson */ 1115*92241e0bSTom Erickson dsl_prop_getflags_t flags = (dsl_prop_get_hasrecvd(os) ? 1116*92241e0bSTom Erickson DSL_PROP_GET_RECEIVED : DSL_PROP_GET_LOCAL); 1117*92241e0bSTom Erickson return (dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, flags)); 11187f7322feSeschrock } 1119a2eea2e1Sahrens 1120a2eea2e1Sahrens void 1121a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nvlist_t *nv, zfs_prop_t prop, uint64_t value) 1122a2eea2e1Sahrens { 1123a2eea2e1Sahrens nvlist_t *propval; 1124*92241e0bSTom Erickson const char *propname = zfs_prop_to_name(prop); 1125*92241e0bSTom Erickson uint64_t default_value; 1126*92241e0bSTom Erickson 1127*92241e0bSTom Erickson if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) { 1128*92241e0bSTom Erickson VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0); 1129*92241e0bSTom Erickson return; 1130*92241e0bSTom Erickson } 1131a2eea2e1Sahrens 1132a2eea2e1Sahrens VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1133990b4856Slling VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0); 1134*92241e0bSTom Erickson /* Indicate the default source if we can. */ 1135*92241e0bSTom Erickson if (dodefault(propname, 8, 1, &default_value) == 0 && 1136*92241e0bSTom Erickson value == default_value) { 1137*92241e0bSTom Erickson VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, "") == 0); 1138*92241e0bSTom Erickson } 1139*92241e0bSTom Erickson VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0); 1140a2eea2e1Sahrens nvlist_free(propval); 1141a2eea2e1Sahrens } 1142a2eea2e1Sahrens 1143a2eea2e1Sahrens void 1144a2eea2e1Sahrens dsl_prop_nvlist_add_string(nvlist_t *nv, zfs_prop_t prop, const char *value) 1145a2eea2e1Sahrens { 1146a2eea2e1Sahrens nvlist_t *propval; 1147*92241e0bSTom Erickson const char *propname = zfs_prop_to_name(prop); 1148*92241e0bSTom Erickson 1149*92241e0bSTom Erickson if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) { 1150*92241e0bSTom Erickson VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0); 1151*92241e0bSTom Erickson return; 1152*92241e0bSTom Erickson } 1153a2eea2e1Sahrens 1154a2eea2e1Sahrens VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1155990b4856Slling VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0); 1156*92241e0bSTom Erickson VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0); 1157a2eea2e1Sahrens nvlist_free(propval); 1158a2eea2e1Sahrens } 1159