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 /* 224543Smarks * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23789Sahrens * Use is subject to license terms. 24789Sahrens */ 25789Sahrens 26789Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 27789Sahrens 28789Sahrens #include <sys/dmu.h> 291356Seschrock #include <sys/dmu_objset.h> 30789Sahrens #include <sys/dmu_tx.h> 31789Sahrens #include <sys/dsl_dataset.h> 32789Sahrens #include <sys/dsl_dir.h> 33789Sahrens #include <sys/dsl_prop.h> 342199Sahrens #include <sys/dsl_synctask.h> 35789Sahrens #include <sys/spa.h> 36789Sahrens #include <sys/zio_checksum.h> /* for the default checksum value */ 37789Sahrens #include <sys/zap.h> 38789Sahrens #include <sys/fs/zfs.h> 39789Sahrens 40789Sahrens #include "zfs_prop.h" 41789Sahrens 42789Sahrens static int 43789Sahrens dodefault(const char *propname, int intsz, int numint, void *buf) 44789Sahrens { 45789Sahrens zfs_prop_t prop; 46789Sahrens 47789Sahrens if ((prop = zfs_name_to_prop(propname)) == ZFS_PROP_INVAL || 48789Sahrens zfs_prop_readonly(prop)) 49789Sahrens return (ENOENT); 50789Sahrens 51*4787Sahrens if (zfs_prop_get_type(prop) == PROP_TYPE_STRING) { 52789Sahrens if (intsz != 1) 53789Sahrens return (EOVERFLOW); 541356Seschrock (void) strncpy(buf, zfs_prop_default_string(prop), numint); 55789Sahrens } else { 56789Sahrens if (intsz != 8 || numint < 1) 57789Sahrens return (EOVERFLOW); 58789Sahrens 59789Sahrens *(uint64_t *)buf = zfs_prop_default_numeric(prop); 60789Sahrens } 61789Sahrens 62789Sahrens return (0); 63789Sahrens } 64789Sahrens 65789Sahrens static int 662082Seschrock dsl_prop_get_impl(dsl_dir_t *dd, const char *propname, 67789Sahrens int intsz, int numint, void *buf, char *setpoint) 68789Sahrens { 692082Seschrock int err = ENOENT; 702676Seschrock zfs_prop_t prop; 71789Sahrens 72789Sahrens if (setpoint) 73789Sahrens setpoint[0] = '\0'; 74789Sahrens 752676Seschrock prop = zfs_name_to_prop(propname); 762676Seschrock 772082Seschrock /* 782082Seschrock * Note: dd may be NULL, therefore we shouldn't dereference it 792082Seschrock * ouside this loop. 802082Seschrock */ 812082Seschrock for (; dd != NULL; dd = dd->dd_parent) { 822082Seschrock objset_t *mos = dd->dd_pool->dp_meta_objset; 832082Seschrock ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock)); 84789Sahrens err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj, 85789Sahrens propname, intsz, numint, buf); 86789Sahrens if (err != ENOENT) { 87789Sahrens if (setpoint) 88789Sahrens dsl_dir_name(dd, setpoint); 89789Sahrens break; 90789Sahrens } 912676Seschrock 922676Seschrock /* 932676Seschrock * Break out of this loop for non-inheritable properties. 942676Seschrock */ 952676Seschrock if (prop != ZFS_PROP_INVAL && 962676Seschrock !zfs_prop_inheritable(prop)) 972676Seschrock break; 98789Sahrens } 99789Sahrens if (err == ENOENT) 100789Sahrens err = dodefault(propname, intsz, numint, buf); 101789Sahrens 102789Sahrens return (err); 103789Sahrens } 104789Sahrens 105789Sahrens /* 106789Sahrens * Register interest in the named property. We'll call the callback 107789Sahrens * once to notify it of the current property value, and again each time 108789Sahrens * the property changes, until this callback is unregistered. 109789Sahrens * 110789Sahrens * Return 0 on success, errno if the prop is not an integer value. 111789Sahrens */ 112789Sahrens int 113789Sahrens dsl_prop_register(dsl_dataset_t *ds, const char *propname, 114789Sahrens dsl_prop_changed_cb_t *callback, void *cbarg) 115789Sahrens { 1162082Seschrock dsl_dir_t *dd = ds->ds_dir; 117789Sahrens uint64_t value; 118789Sahrens dsl_prop_cb_record_t *cbr; 119789Sahrens int err; 1202199Sahrens int need_rwlock; 121789Sahrens 1222199Sahrens need_rwlock = !RW_WRITE_HELD(&dd->dd_pool->dp_config_rwlock); 1232199Sahrens if (need_rwlock) 1242199Sahrens rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 125789Sahrens 1262082Seschrock err = dsl_prop_get_impl(dd, propname, 8, 1, &value, NULL); 127789Sahrens if (err != 0) { 128789Sahrens rw_exit(&dd->dd_pool->dp_config_rwlock); 129789Sahrens return (err); 130789Sahrens } 131789Sahrens 132789Sahrens cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP); 1332082Seschrock cbr->cbr_ds = ds; 134789Sahrens cbr->cbr_propname = kmem_alloc(strlen(propname)+1, KM_SLEEP); 135789Sahrens (void) strcpy((char *)cbr->cbr_propname, propname); 136789Sahrens cbr->cbr_func = callback; 137789Sahrens cbr->cbr_arg = cbarg; 138789Sahrens mutex_enter(&dd->dd_lock); 139789Sahrens list_insert_head(&dd->dd_prop_cbs, cbr); 140789Sahrens mutex_exit(&dd->dd_lock); 141789Sahrens 142789Sahrens cbr->cbr_func(cbr->cbr_arg, value); 143789Sahrens 1441544Seschrock VERIFY(0 == dsl_dir_open_obj(dd->dd_pool, dd->dd_object, 1451544Seschrock NULL, cbr, &dd)); 1462199Sahrens if (need_rwlock) 1472199Sahrens rw_exit(&dd->dd_pool->dp_config_rwlock); 148789Sahrens /* Leave dataset open until this callback is unregistered */ 149789Sahrens return (0); 150789Sahrens } 151789Sahrens 152789Sahrens int 153789Sahrens dsl_prop_get_ds(dsl_dir_t *dd, const char *propname, 154789Sahrens int intsz, int numints, void *buf, char *setpoint) 155789Sahrens { 156789Sahrens int err; 157789Sahrens 158789Sahrens rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 1592082Seschrock err = dsl_prop_get_impl(dd, propname, intsz, numints, buf, setpoint); 160789Sahrens rw_exit(&dd->dd_pool->dp_config_rwlock); 161789Sahrens 162789Sahrens return (err); 163789Sahrens } 164789Sahrens 1654543Smarks /* 1664543Smarks * Get property when config lock is already held. 1674543Smarks */ 1684543Smarks int dsl_prop_get_ds_locked(dsl_dir_t *dd, const char *propname, 1694543Smarks int intsz, int numints, void *buf, char *setpoint) 1704543Smarks { 1714543Smarks ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock)); 1724543Smarks return (dsl_prop_get_impl(dd, propname, intsz, numints, buf, setpoint)); 1734543Smarks } 1744543Smarks 175789Sahrens int 176789Sahrens dsl_prop_get(const char *ddname, const char *propname, 177789Sahrens int intsz, int numints, void *buf, char *setpoint) 178789Sahrens { 179789Sahrens dsl_dir_t *dd; 180789Sahrens const char *tail; 181789Sahrens int err; 182789Sahrens 1831544Seschrock err = dsl_dir_open(ddname, FTAG, &dd, &tail); 1841544Seschrock if (err) 1851544Seschrock return (err); 186789Sahrens if (tail && tail[0] != '@') { 187789Sahrens dsl_dir_close(dd, FTAG); 188789Sahrens return (ENOENT); 189789Sahrens } 190789Sahrens 191789Sahrens err = dsl_prop_get_ds(dd, propname, intsz, numints, buf, setpoint); 192789Sahrens 193789Sahrens dsl_dir_close(dd, FTAG); 194789Sahrens return (err); 195789Sahrens } 196789Sahrens 197789Sahrens /* 198789Sahrens * Get the current property value. It may have changed by the time this 199789Sahrens * function returns, so it is NOT safe to follow up with 200789Sahrens * dsl_prop_register() and assume that the value has not changed in 201789Sahrens * between. 202789Sahrens * 203789Sahrens * Return 0 on success, ENOENT if ddname is invalid. 204789Sahrens */ 205789Sahrens int 206789Sahrens dsl_prop_get_integer(const char *ddname, const char *propname, 207789Sahrens uint64_t *valuep, char *setpoint) 208789Sahrens { 209789Sahrens return (dsl_prop_get(ddname, propname, 8, 1, valuep, setpoint)); 210789Sahrens } 211789Sahrens 212789Sahrens /* 213789Sahrens * Unregister this callback. Return 0 on success, ENOENT if ddname is 214789Sahrens * invalid, ENOMSG if no matching callback registered. 215789Sahrens */ 216789Sahrens int 217789Sahrens dsl_prop_unregister(dsl_dataset_t *ds, const char *propname, 218789Sahrens dsl_prop_changed_cb_t *callback, void *cbarg) 219789Sahrens { 2202082Seschrock dsl_dir_t *dd = ds->ds_dir; 221789Sahrens dsl_prop_cb_record_t *cbr; 222789Sahrens 223789Sahrens mutex_enter(&dd->dd_lock); 224789Sahrens for (cbr = list_head(&dd->dd_prop_cbs); 225789Sahrens cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { 2262082Seschrock if (cbr->cbr_ds == ds && 227789Sahrens cbr->cbr_func == callback && 2282082Seschrock cbr->cbr_arg == cbarg && 2292082Seschrock strcmp(cbr->cbr_propname, propname) == 0) 230789Sahrens break; 231789Sahrens } 232789Sahrens 233789Sahrens if (cbr == NULL) { 234789Sahrens mutex_exit(&dd->dd_lock); 235789Sahrens return (ENOMSG); 236789Sahrens } 237789Sahrens 238789Sahrens list_remove(&dd->dd_prop_cbs, cbr); 239789Sahrens mutex_exit(&dd->dd_lock); 240789Sahrens kmem_free((void*)cbr->cbr_propname, strlen(cbr->cbr_propname)+1); 241789Sahrens kmem_free(cbr, sizeof (dsl_prop_cb_record_t)); 242789Sahrens 243789Sahrens /* Clean up from dsl_prop_register */ 244789Sahrens dsl_dir_close(dd, cbr); 245789Sahrens return (0); 246789Sahrens } 247789Sahrens 2482082Seschrock /* 2492082Seschrock * Return the number of callbacks that are registered for this dataset. 2502082Seschrock */ 2512082Seschrock int 2522082Seschrock dsl_prop_numcb(dsl_dataset_t *ds) 2532082Seschrock { 2542082Seschrock dsl_dir_t *dd = ds->ds_dir; 2552082Seschrock dsl_prop_cb_record_t *cbr; 2562082Seschrock int num = 0; 2572082Seschrock 2582082Seschrock mutex_enter(&dd->dd_lock); 2592082Seschrock for (cbr = list_head(&dd->dd_prop_cbs); 2602082Seschrock cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { 2612082Seschrock if (cbr->cbr_ds == ds) 2622082Seschrock num++; 2632082Seschrock } 2642082Seschrock mutex_exit(&dd->dd_lock); 2652082Seschrock 2662082Seschrock return (num); 2672082Seschrock } 2682082Seschrock 269789Sahrens static void 270789Sahrens dsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj, 271789Sahrens const char *propname, uint64_t value, int first) 272789Sahrens { 273789Sahrens dsl_dir_t *dd; 274789Sahrens dsl_prop_cb_record_t *cbr; 275789Sahrens objset_t *mos = dp->dp_meta_objset; 2762199Sahrens zap_cursor_t zc; 2772199Sahrens zap_attribute_t za; 278789Sahrens int err; 279789Sahrens 280789Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 2811544Seschrock err = dsl_dir_open_obj(dp, ddobj, NULL, FTAG, &dd); 2821544Seschrock if (err) 2831544Seschrock return; 284789Sahrens 285789Sahrens if (!first) { 286789Sahrens /* 287789Sahrens * If the prop is set here, then this change is not 288789Sahrens * being inherited here or below; stop the recursion. 289789Sahrens */ 290789Sahrens err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj, propname, 291789Sahrens 8, 1, &value); 292789Sahrens if (err == 0) { 293789Sahrens dsl_dir_close(dd, FTAG); 294789Sahrens return; 295789Sahrens } 296789Sahrens ASSERT3U(err, ==, ENOENT); 297789Sahrens } 298789Sahrens 299789Sahrens mutex_enter(&dd->dd_lock); 300789Sahrens for (cbr = list_head(&dd->dd_prop_cbs); 301789Sahrens cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { 302789Sahrens if (strcmp(cbr->cbr_propname, propname) == 0) { 303789Sahrens cbr->cbr_func(cbr->cbr_arg, value); 304789Sahrens } 305789Sahrens } 306789Sahrens mutex_exit(&dd->dd_lock); 307789Sahrens 3082199Sahrens for (zap_cursor_init(&zc, mos, 3092199Sahrens dd->dd_phys->dd_child_dir_zapobj); 3102199Sahrens zap_cursor_retrieve(&zc, &za) == 0; 3112199Sahrens zap_cursor_advance(&zc)) { 3122199Sahrens /* XXX recursion could blow stack; esp. za! */ 3132199Sahrens dsl_prop_changed_notify(dp, za.za_first_integer, 3142199Sahrens propname, value, FALSE); 315789Sahrens } 3162199Sahrens zap_cursor_fini(&zc); 317789Sahrens dsl_dir_close(dd, FTAG); 318789Sahrens } 319789Sahrens 320789Sahrens struct prop_set_arg { 321789Sahrens const char *name; 322789Sahrens int intsz; 323789Sahrens int numints; 324789Sahrens const void *buf; 325789Sahrens }; 326789Sahrens 3272199Sahrens 3282199Sahrens static void 3294543Smarks dsl_prop_set_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 330789Sahrens { 3312199Sahrens dsl_dir_t *dd = arg1; 3322199Sahrens struct prop_set_arg *psa = arg2; 333789Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 334789Sahrens uint64_t zapobj = dd->dd_phys->dd_props_zapobj; 335789Sahrens uint64_t intval; 3362199Sahrens int isint; 3374543Smarks char valbuf[32]; 3384543Smarks char *valstr; 339789Sahrens 340789Sahrens isint = (dodefault(psa->name, 8, 1, &intval) == 0); 341789Sahrens 342789Sahrens if (psa->numints == 0) { 3432199Sahrens int err = zap_remove(mos, zapobj, psa->name, tx); 3442199Sahrens ASSERT(err == 0 || err == ENOENT); 3452199Sahrens if (isint) { 3462199Sahrens VERIFY(0 == dsl_prop_get_impl(dd->dd_parent, 3472199Sahrens psa->name, 8, 1, &intval, NULL)); 348789Sahrens } 349789Sahrens } else { 3502199Sahrens VERIFY(0 == zap_update(mos, zapobj, psa->name, 3512199Sahrens psa->intsz, psa->numints, psa->buf, tx)); 352789Sahrens if (isint) 353789Sahrens intval = *(uint64_t *)psa->buf; 354789Sahrens } 355789Sahrens 3562199Sahrens if (isint) { 357789Sahrens dsl_prop_changed_notify(dd->dd_pool, 358789Sahrens dd->dd_object, psa->name, intval, TRUE); 359789Sahrens } 3604543Smarks if (isint) { 3614543Smarks (void) snprintf(valbuf, sizeof (valbuf), 3624543Smarks "%lld", (longlong_t)intval); 3634543Smarks valstr = valbuf; 3644543Smarks } else { 3654543Smarks valstr = (char *)psa->buf; 3664543Smarks } 3674543Smarks spa_history_internal_log((psa->numints == 0) ? LOG_DS_INHERIT : 3684543Smarks LOG_DS_PROPSET, dd->dd_pool->dp_spa, tx, cr, 3694543Smarks "%s=%s dataset = %llu", psa->name, valstr, 3704543Smarks dd->dd_phys->dd_head_dataset_obj); 371789Sahrens } 372789Sahrens 373789Sahrens int 3742885Sahrens dsl_prop_set_dd(dsl_dir_t *dd, const char *propname, 3752885Sahrens int intsz, int numints, const void *buf) 3762885Sahrens { 3772885Sahrens struct prop_set_arg psa; 3782885Sahrens 3792885Sahrens psa.name = propname; 3802885Sahrens psa.intsz = intsz; 3812885Sahrens psa.numints = numints; 3822885Sahrens psa.buf = buf; 3832885Sahrens 3842885Sahrens return (dsl_sync_task_do(dd->dd_pool, 3852885Sahrens NULL, dsl_prop_set_sync, dd, &psa, 2)); 3862885Sahrens } 3872885Sahrens 3882885Sahrens int 389789Sahrens dsl_prop_set(const char *ddname, const char *propname, 390789Sahrens int intsz, int numints, const void *buf) 391789Sahrens { 392789Sahrens dsl_dir_t *dd; 393789Sahrens int err; 394789Sahrens 3952641Sahrens /* 3962641Sahrens * We must do these checks before we get to the syncfunc, since 3972641Sahrens * it can't fail. 3982641Sahrens */ 3992641Sahrens if (strlen(propname) >= ZAP_MAXNAMELEN) 4002641Sahrens return (ENAMETOOLONG); 4012641Sahrens if (intsz * numints >= ZAP_MAXVALUELEN) 4022641Sahrens return (E2BIG); 4032641Sahrens 4041544Seschrock err = dsl_dir_open(ddname, FTAG, &dd, NULL); 4051544Seschrock if (err) 4061544Seschrock return (err); 4072885Sahrens err = dsl_prop_set_dd(dd, propname, intsz, numints, buf); 408789Sahrens dsl_dir_close(dd, FTAG); 409789Sahrens return (err); 410789Sahrens } 4111356Seschrock 4121356Seschrock /* 4131356Seschrock * Iterate over all properties for this dataset and return them in an nvlist. 4141356Seschrock */ 4151356Seschrock int 4161356Seschrock dsl_prop_get_all(objset_t *os, nvlist_t **nvp) 4171356Seschrock { 4181356Seschrock dsl_dataset_t *ds = os->os->os_dsl_dataset; 4192082Seschrock dsl_dir_t *dd = ds->ds_dir; 4201356Seschrock int err = 0; 4211356Seschrock dsl_pool_t *dp; 4221356Seschrock objset_t *mos; 4231356Seschrock 4241356Seschrock if (dsl_dataset_is_snapshot(ds)) { 4251356Seschrock VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); 4261356Seschrock return (0); 4271356Seschrock } 4281356Seschrock 4291356Seschrock VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); 4301356Seschrock 4311356Seschrock dp = dd->dd_pool; 4321356Seschrock mos = dp->dp_meta_objset; 4331356Seschrock 4341356Seschrock rw_enter(&dp->dp_config_rwlock, RW_READER); 4352082Seschrock for (; dd != NULL; dd = dd->dd_parent) { 4362885Sahrens char setpoint[MAXNAMELEN]; 4372885Sahrens zap_cursor_t zc; 4382885Sahrens zap_attribute_t za; 4392885Sahrens 4401356Seschrock dsl_dir_name(dd, setpoint); 4411356Seschrock 4421356Seschrock for (zap_cursor_init(&zc, mos, dd->dd_phys->dd_props_zapobj); 4431356Seschrock (err = zap_cursor_retrieve(&zc, &za)) == 0; 4441356Seschrock zap_cursor_advance(&zc)) { 4452885Sahrens nvlist_t *propval; 4462885Sahrens zfs_prop_t prop; 4472676Seschrock /* 4482676Seschrock * Skip non-inheritable properties. 4492676Seschrock */ 4502676Seschrock if ((prop = zfs_name_to_prop(za.za_name)) != 4512676Seschrock ZFS_PROP_INVAL && !zfs_prop_inheritable(prop) && 4522676Seschrock dd != ds->ds_dir) 4531356Seschrock continue; 4541356Seschrock 4552676Seschrock if (nvlist_lookup_nvlist(*nvp, za.za_name, 4562676Seschrock &propval) == 0) 4572676Seschrock continue; 4582676Seschrock 4592676Seschrock VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, 4601356Seschrock KM_SLEEP) == 0); 4611356Seschrock if (za.za_integer_length == 1) { 4621356Seschrock /* 4631356Seschrock * String property 4641356Seschrock */ 4652885Sahrens char *tmp = kmem_alloc(za.za_num_integers, 4662885Sahrens KM_SLEEP); 4671356Seschrock err = zap_lookup(mos, 4681356Seschrock dd->dd_phys->dd_props_zapobj, 4691356Seschrock za.za_name, 1, za.za_num_integers, 4701356Seschrock tmp); 4711356Seschrock if (err != 0) { 4721356Seschrock kmem_free(tmp, za.za_num_integers); 4731356Seschrock break; 4741356Seschrock } 4752676Seschrock VERIFY(nvlist_add_string(propval, 4761356Seschrock ZFS_PROP_VALUE, tmp) == 0); 4771356Seschrock kmem_free(tmp, za.za_num_integers); 4781356Seschrock } else { 4791356Seschrock /* 4801356Seschrock * Integer property 4811356Seschrock */ 4821356Seschrock ASSERT(za.za_integer_length == 8); 4832676Seschrock (void) nvlist_add_uint64(propval, 4842676Seschrock ZFS_PROP_VALUE, za.za_first_integer); 4851356Seschrock } 4861356Seschrock 4872676Seschrock VERIFY(nvlist_add_string(propval, 4881356Seschrock ZFS_PROP_SOURCE, setpoint) == 0); 4891356Seschrock VERIFY(nvlist_add_nvlist(*nvp, za.za_name, 4902676Seschrock propval) == 0); 4912676Seschrock nvlist_free(propval); 4921356Seschrock } 4931356Seschrock zap_cursor_fini(&zc); 4941356Seschrock 4952082Seschrock if (err != ENOENT) 4961356Seschrock break; 4972082Seschrock err = 0; 4981356Seschrock } 4991356Seschrock rw_exit(&dp->dp_config_rwlock); 5001356Seschrock 5011356Seschrock return (err); 5021356Seschrock } 5032885Sahrens 5042885Sahrens void 5052885Sahrens dsl_prop_nvlist_add_uint64(nvlist_t *nv, zfs_prop_t prop, uint64_t value) 5062885Sahrens { 5072885Sahrens nvlist_t *propval; 5082885Sahrens 5092885Sahrens VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 5102885Sahrens VERIFY(nvlist_add_uint64(propval, ZFS_PROP_VALUE, value) == 0); 5112885Sahrens VERIFY(nvlist_add_nvlist(nv, zfs_prop_to_name(prop), propval) == 0); 5122885Sahrens nvlist_free(propval); 5132885Sahrens } 5142885Sahrens 5152885Sahrens void 5162885Sahrens dsl_prop_nvlist_add_string(nvlist_t *nv, zfs_prop_t prop, const char *value) 5172885Sahrens { 5182885Sahrens nvlist_t *propval; 5192885Sahrens 5202885Sahrens VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 5212885Sahrens VERIFY(nvlist_add_string(propval, ZFS_PROP_VALUE, value) == 0); 5222885Sahrens VERIFY(nvlist_add_nvlist(nv, zfs_prop_to_name(prop), propval) == 0); 5232885Sahrens nvlist_free(propval); 5242885Sahrens } 525