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 /* 226047Sahrens * Copyright 2008 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 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), 605094Slling numint); 61789Sahrens } else { 62789Sahrens if (intsz != 8 || numint < 1) 63789Sahrens return (EOVERFLOW); 64789Sahrens 65789Sahrens *(uint64_t *)buf = zfs_prop_default_numeric(prop); 66789Sahrens } 67789Sahrens 68789Sahrens return (0); 69789Sahrens } 70789Sahrens 71*7265Sahrens int 72*7265Sahrens dsl_prop_get_dd(dsl_dir_t *dd, const char *propname, 73789Sahrens int intsz, int numint, void *buf, char *setpoint) 74789Sahrens { 752082Seschrock int err = ENOENT; 76*7265Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 772676Seschrock zfs_prop_t prop; 78789Sahrens 79*7265Sahrens ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock)); 80*7265Sahrens 81789Sahrens if (setpoint) 82789Sahrens setpoint[0] = '\0'; 83789Sahrens 842676Seschrock prop = zfs_name_to_prop(propname); 852676Seschrock 862082Seschrock /* 872082Seschrock * Note: dd may be NULL, therefore we shouldn't dereference it 882082Seschrock * ouside this loop. 892082Seschrock */ 902082Seschrock for (; dd != NULL; dd = dd->dd_parent) { 912082Seschrock ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock)); 92789Sahrens err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj, 93789Sahrens propname, intsz, numint, buf); 94789Sahrens if (err != ENOENT) { 95789Sahrens if (setpoint) 96789Sahrens dsl_dir_name(dd, setpoint); 97789Sahrens break; 98789Sahrens } 992676Seschrock 1002676Seschrock /* 1012676Seschrock * Break out of this loop for non-inheritable properties. 1022676Seschrock */ 1035331Samw if (prop != ZPROP_INVAL && !zfs_prop_inheritable(prop)) 1042676Seschrock break; 105789Sahrens } 106789Sahrens if (err == ENOENT) 107789Sahrens err = dodefault(propname, intsz, numint, buf); 108789Sahrens 109789Sahrens return (err); 110789Sahrens } 111789Sahrens 112*7265Sahrens int 113*7265Sahrens dsl_prop_get_ds(dsl_dataset_t *ds, const char *propname, 114*7265Sahrens int intsz, int numint, void *buf, char *setpoint) 115*7265Sahrens { 116*7265Sahrens ASSERT(RW_LOCK_HELD(&ds->ds_dir->dd_pool->dp_config_rwlock)); 117*7265Sahrens 118*7265Sahrens if (ds->ds_phys->ds_props_obj) { 119*7265Sahrens int err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset, 120*7265Sahrens ds->ds_phys->ds_props_obj, propname, intsz, numint, buf); 121*7265Sahrens if (err != ENOENT) { 122*7265Sahrens if (setpoint) 123*7265Sahrens dsl_dataset_name(ds, setpoint); 124*7265Sahrens return (err); 125*7265Sahrens } 126*7265Sahrens } 127*7265Sahrens 128*7265Sahrens return (dsl_prop_get_dd(ds->ds_dir, propname, 129*7265Sahrens intsz, numint, buf, setpoint)); 130*7265Sahrens } 131*7265Sahrens 132789Sahrens /* 133789Sahrens * Register interest in the named property. We'll call the callback 134789Sahrens * once to notify it of the current property value, and again each time 135789Sahrens * the property changes, until this callback is unregistered. 136789Sahrens * 137789Sahrens * Return 0 on success, errno if the prop is not an integer value. 138789Sahrens */ 139789Sahrens int 140789Sahrens dsl_prop_register(dsl_dataset_t *ds, const char *propname, 141789Sahrens dsl_prop_changed_cb_t *callback, void *cbarg) 142789Sahrens { 1432082Seschrock dsl_dir_t *dd = ds->ds_dir; 144*7265Sahrens dsl_pool_t *dp = dd->dd_pool; 145789Sahrens uint64_t value; 146789Sahrens dsl_prop_cb_record_t *cbr; 147789Sahrens int err; 1482199Sahrens int need_rwlock; 149789Sahrens 150*7265Sahrens need_rwlock = !RW_WRITE_HELD(&dp->dp_config_rwlock); 1512199Sahrens if (need_rwlock) 152*7265Sahrens rw_enter(&dp->dp_config_rwlock, RW_READER); 153789Sahrens 154*7265Sahrens err = dsl_prop_get_ds(ds, propname, 8, 1, &value, NULL); 155789Sahrens if (err != 0) { 1565569Sck153898 if (need_rwlock) 157*7265Sahrens rw_exit(&dp->dp_config_rwlock); 158789Sahrens return (err); 159789Sahrens } 160789Sahrens 161789Sahrens cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP); 1622082Seschrock cbr->cbr_ds = ds; 163789Sahrens cbr->cbr_propname = kmem_alloc(strlen(propname)+1, KM_SLEEP); 164789Sahrens (void) strcpy((char *)cbr->cbr_propname, propname); 165789Sahrens cbr->cbr_func = callback; 166789Sahrens cbr->cbr_arg = cbarg; 167789Sahrens mutex_enter(&dd->dd_lock); 168789Sahrens list_insert_head(&dd->dd_prop_cbs, cbr); 169789Sahrens mutex_exit(&dd->dd_lock); 170789Sahrens 171789Sahrens cbr->cbr_func(cbr->cbr_arg, value); 172789Sahrens 173*7265Sahrens VERIFY(0 == dsl_dir_open_obj(dp, dd->dd_object, 1741544Seschrock NULL, cbr, &dd)); 1752199Sahrens if (need_rwlock) 176*7265Sahrens rw_exit(&dp->dp_config_rwlock); 177*7265Sahrens /* Leave dir open until this callback is unregistered */ 178789Sahrens return (0); 179789Sahrens } 180789Sahrens 181789Sahrens int 182*7265Sahrens dsl_prop_get(const char *dsname, const char *propname, 1834543Smarks int intsz, int numints, void *buf, char *setpoint) 1844543Smarks { 185*7265Sahrens dsl_dataset_t *ds; 186789Sahrens int err; 187789Sahrens 188*7265Sahrens err = dsl_dataset_hold(dsname, FTAG, &ds); 1891544Seschrock if (err) 1901544Seschrock return (err); 191789Sahrens 192*7265Sahrens rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); 193*7265Sahrens err = dsl_prop_get_ds(ds, propname, intsz, numints, buf, setpoint); 194*7265Sahrens rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 195789Sahrens 196*7265Sahrens dsl_dataset_rele(ds, FTAG); 197789Sahrens return (err); 198789Sahrens } 199789Sahrens 200789Sahrens /* 201789Sahrens * Get the current property value. It may have changed by the time this 202789Sahrens * function returns, so it is NOT safe to follow up with 203789Sahrens * dsl_prop_register() and assume that the value has not changed in 204789Sahrens * between. 205789Sahrens * 206789Sahrens * Return 0 on success, ENOENT if ddname is invalid. 207789Sahrens */ 208789Sahrens int 209789Sahrens dsl_prop_get_integer(const char *ddname, const char *propname, 210789Sahrens uint64_t *valuep, char *setpoint) 211789Sahrens { 212789Sahrens return (dsl_prop_get(ddname, propname, 8, 1, valuep, setpoint)); 213789Sahrens } 214789Sahrens 215789Sahrens /* 216789Sahrens * Unregister this callback. Return 0 on success, ENOENT if ddname is 217789Sahrens * invalid, ENOMSG if no matching callback registered. 218789Sahrens */ 219789Sahrens int 220789Sahrens dsl_prop_unregister(dsl_dataset_t *ds, const char *propname, 221789Sahrens dsl_prop_changed_cb_t *callback, void *cbarg) 222789Sahrens { 2232082Seschrock dsl_dir_t *dd = ds->ds_dir; 224789Sahrens dsl_prop_cb_record_t *cbr; 225789Sahrens 226789Sahrens mutex_enter(&dd->dd_lock); 227789Sahrens for (cbr = list_head(&dd->dd_prop_cbs); 228789Sahrens cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { 2292082Seschrock if (cbr->cbr_ds == ds && 230789Sahrens cbr->cbr_func == callback && 2312082Seschrock cbr->cbr_arg == cbarg && 2322082Seschrock strcmp(cbr->cbr_propname, propname) == 0) 233789Sahrens break; 234789Sahrens } 235789Sahrens 236789Sahrens if (cbr == NULL) { 237789Sahrens mutex_exit(&dd->dd_lock); 238789Sahrens return (ENOMSG); 239789Sahrens } 240789Sahrens 241789Sahrens list_remove(&dd->dd_prop_cbs, cbr); 242789Sahrens mutex_exit(&dd->dd_lock); 243789Sahrens kmem_free((void*)cbr->cbr_propname, strlen(cbr->cbr_propname)+1); 244789Sahrens kmem_free(cbr, sizeof (dsl_prop_cb_record_t)); 245789Sahrens 246789Sahrens /* Clean up from dsl_prop_register */ 247789Sahrens dsl_dir_close(dd, cbr); 248789Sahrens return (0); 249789Sahrens } 250789Sahrens 2512082Seschrock /* 2522082Seschrock * Return the number of callbacks that are registered for this dataset. 2532082Seschrock */ 2542082Seschrock int 2552082Seschrock dsl_prop_numcb(dsl_dataset_t *ds) 2562082Seschrock { 2572082Seschrock dsl_dir_t *dd = ds->ds_dir; 2582082Seschrock dsl_prop_cb_record_t *cbr; 2592082Seschrock int num = 0; 2602082Seschrock 2612082Seschrock mutex_enter(&dd->dd_lock); 2622082Seschrock for (cbr = list_head(&dd->dd_prop_cbs); 2632082Seschrock cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { 2642082Seschrock if (cbr->cbr_ds == ds) 2652082Seschrock num++; 2662082Seschrock } 2672082Seschrock mutex_exit(&dd->dd_lock); 2682082Seschrock 2692082Seschrock return (num); 2702082Seschrock } 2712082Seschrock 272789Sahrens static void 273789Sahrens dsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj, 274789Sahrens const char *propname, uint64_t value, int first) 275789Sahrens { 276789Sahrens dsl_dir_t *dd; 277789Sahrens dsl_prop_cb_record_t *cbr; 278789Sahrens objset_t *mos = dp->dp_meta_objset; 2792199Sahrens zap_cursor_t zc; 2806047Sahrens zap_attribute_t *za; 281789Sahrens int err; 282*7265Sahrens uint64_t dummyval; 283789Sahrens 284789Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 2851544Seschrock err = dsl_dir_open_obj(dp, ddobj, NULL, FTAG, &dd); 2861544Seschrock if (err) 2871544Seschrock return; 288789Sahrens 289789Sahrens if (!first) { 290789Sahrens /* 291789Sahrens * If the prop is set here, then this change is not 292789Sahrens * being inherited here or below; stop the recursion. 293789Sahrens */ 294789Sahrens err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj, propname, 295*7265Sahrens 8, 1, &dummyval); 296789Sahrens if (err == 0) { 297789Sahrens dsl_dir_close(dd, FTAG); 298789Sahrens return; 299789Sahrens } 300789Sahrens ASSERT3U(err, ==, ENOENT); 301789Sahrens } 302789Sahrens 303789Sahrens mutex_enter(&dd->dd_lock); 304*7265Sahrens for (cbr = list_head(&dd->dd_prop_cbs); cbr; 305*7265Sahrens cbr = list_next(&dd->dd_prop_cbs, cbr)) { 306*7265Sahrens uint64_t propobj = cbr->cbr_ds->ds_phys->ds_props_obj; 307*7265Sahrens 308*7265Sahrens if (strcmp(cbr->cbr_propname, propname) != 0) 309*7265Sahrens continue; 310*7265Sahrens 311*7265Sahrens /* 312*7265Sahrens * If the property is set on this ds, then it is not 313*7265Sahrens * inherited here; don't call the callback. 314*7265Sahrens */ 315*7265Sahrens if (propobj && 0 == zap_lookup(mos, propobj, propname, 316*7265Sahrens 8, 1, &dummyval)) 317*7265Sahrens continue; 318*7265Sahrens 319*7265Sahrens cbr->cbr_func(cbr->cbr_arg, value); 320789Sahrens } 321789Sahrens mutex_exit(&dd->dd_lock); 322789Sahrens 3236047Sahrens za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP); 3242199Sahrens for (zap_cursor_init(&zc, mos, 3252199Sahrens dd->dd_phys->dd_child_dir_zapobj); 3266047Sahrens zap_cursor_retrieve(&zc, za) == 0; 3272199Sahrens zap_cursor_advance(&zc)) { 3286047Sahrens dsl_prop_changed_notify(dp, za->za_first_integer, 3292199Sahrens propname, value, FALSE); 330789Sahrens } 3316047Sahrens kmem_free(za, sizeof (zap_attribute_t)); 3322199Sahrens zap_cursor_fini(&zc); 333789Sahrens dsl_dir_close(dd, FTAG); 334789Sahrens } 335789Sahrens 336789Sahrens struct prop_set_arg { 337789Sahrens const char *name; 338789Sahrens int intsz; 339789Sahrens int numints; 340789Sahrens const void *buf; 341789Sahrens }; 342789Sahrens 3432199Sahrens 3442199Sahrens static void 3454543Smarks dsl_prop_set_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 346789Sahrens { 347*7265Sahrens dsl_dataset_t *ds = arg1; 3482199Sahrens struct prop_set_arg *psa = arg2; 349*7265Sahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 350*7265Sahrens uint64_t zapobj, intval; 3512199Sahrens int isint; 3524543Smarks char valbuf[32]; 3534543Smarks char *valstr; 354789Sahrens 355789Sahrens isint = (dodefault(psa->name, 8, 1, &intval) == 0); 356789Sahrens 357*7265Sahrens if (dsl_dataset_is_snapshot(ds)) { 358*7265Sahrens ASSERT(spa_version(ds->ds_dir->dd_pool->dp_spa) >= 359*7265Sahrens SPA_VERSION_SNAP_PROPS); 360*7265Sahrens if (ds->ds_phys->ds_props_obj == 0) { 361*7265Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 362*7265Sahrens ds->ds_phys->ds_props_obj = 363*7265Sahrens zap_create(mos, 364*7265Sahrens DMU_OT_DSL_PROPS, DMU_OT_NONE, 0, tx); 365*7265Sahrens } 366*7265Sahrens zapobj = ds->ds_phys->ds_props_obj; 367*7265Sahrens } else { 368*7265Sahrens zapobj = ds->ds_dir->dd_phys->dd_props_zapobj; 369*7265Sahrens } 370*7265Sahrens 371789Sahrens if (psa->numints == 0) { 3722199Sahrens int err = zap_remove(mos, zapobj, psa->name, tx); 3732199Sahrens ASSERT(err == 0 || err == ENOENT); 3742199Sahrens if (isint) { 375*7265Sahrens VERIFY(0 == dsl_prop_get_ds(ds, 3762199Sahrens psa->name, 8, 1, &intval, NULL)); 377789Sahrens } 378789Sahrens } else { 3792199Sahrens VERIFY(0 == zap_update(mos, zapobj, psa->name, 3802199Sahrens psa->intsz, psa->numints, psa->buf, tx)); 381789Sahrens if (isint) 382789Sahrens intval = *(uint64_t *)psa->buf; 383789Sahrens } 384789Sahrens 3852199Sahrens if (isint) { 386*7265Sahrens if (dsl_dataset_is_snapshot(ds)) { 387*7265Sahrens dsl_prop_cb_record_t *cbr; 388*7265Sahrens /* 389*7265Sahrens * It's a snapshot; nothing can inherit this 390*7265Sahrens * property, so just look for callbacks on this 391*7265Sahrens * ds here. 392*7265Sahrens */ 393*7265Sahrens mutex_enter(&ds->ds_dir->dd_lock); 394*7265Sahrens for (cbr = list_head(&ds->ds_dir->dd_prop_cbs); cbr; 395*7265Sahrens cbr = list_next(&ds->ds_dir->dd_prop_cbs, cbr)) { 396*7265Sahrens if (cbr->cbr_ds == ds && 397*7265Sahrens strcmp(cbr->cbr_propname, psa->name) == 0) 398*7265Sahrens cbr->cbr_func(cbr->cbr_arg, intval); 399*7265Sahrens } 400*7265Sahrens mutex_exit(&ds->ds_dir->dd_lock); 401*7265Sahrens } else { 402*7265Sahrens dsl_prop_changed_notify(ds->ds_dir->dd_pool, 403*7265Sahrens ds->ds_dir->dd_object, psa->name, intval, TRUE); 404*7265Sahrens } 405789Sahrens } 4064543Smarks if (isint) { 4074543Smarks (void) snprintf(valbuf, sizeof (valbuf), 4084543Smarks "%lld", (longlong_t)intval); 4094543Smarks valstr = valbuf; 4104543Smarks } else { 4114543Smarks valstr = (char *)psa->buf; 4124543Smarks } 4134543Smarks spa_history_internal_log((psa->numints == 0) ? LOG_DS_INHERIT : 414*7265Sahrens LOG_DS_PROPSET, ds->ds_dir->dd_pool->dp_spa, tx, cr, 415*7265Sahrens "%s=%s dataset = %llu", psa->name, valstr, ds->ds_object); 416789Sahrens } 417789Sahrens 4185378Sck153898 void 4195378Sck153898 dsl_prop_set_uint64_sync(dsl_dir_t *dd, const char *name, uint64_t val, 4205378Sck153898 cred_t *cr, dmu_tx_t *tx) 4215378Sck153898 { 4225378Sck153898 objset_t *mos = dd->dd_pool->dp_meta_objset; 4235378Sck153898 uint64_t zapobj = dd->dd_phys->dd_props_zapobj; 4245378Sck153898 4255378Sck153898 ASSERT(dmu_tx_is_syncing(tx)); 4265378Sck153898 4275378Sck153898 VERIFY(0 == zap_update(mos, zapobj, name, sizeof (val), 1, &val, tx)); 4285378Sck153898 4295378Sck153898 dsl_prop_changed_notify(dd->dd_pool, dd->dd_object, name, val, TRUE); 4305378Sck153898 4315378Sck153898 spa_history_internal_log(LOG_DS_PROPSET, dd->dd_pool->dp_spa, tx, cr, 4325378Sck153898 "%s=%llu dataset = %llu", name, (u_longlong_t)val, 4335378Sck153898 dd->dd_phys->dd_head_dataset_obj); 4345378Sck153898 } 4355378Sck153898 436789Sahrens int 437*7265Sahrens dsl_prop_set(const char *dsname, const char *propname, 4382885Sahrens int intsz, int numints, const void *buf) 4392885Sahrens { 440*7265Sahrens dsl_dataset_t *ds; 441*7265Sahrens int err; 4422885Sahrens struct prop_set_arg psa; 4432885Sahrens 4442641Sahrens /* 4452641Sahrens * We must do these checks before we get to the syncfunc, since 4462641Sahrens * it can't fail. 4472641Sahrens */ 4482641Sahrens if (strlen(propname) >= ZAP_MAXNAMELEN) 4492641Sahrens return (ENAMETOOLONG); 4502641Sahrens if (intsz * numints >= ZAP_MAXVALUELEN) 4512641Sahrens return (E2BIG); 4522641Sahrens 453*7265Sahrens err = dsl_dataset_hold(dsname, FTAG, &ds); 4541544Seschrock if (err) 4551544Seschrock return (err); 456*7265Sahrens 457*7265Sahrens if (dsl_dataset_is_snapshot(ds) && 458*7265Sahrens spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_SNAP_PROPS) { 459*7265Sahrens dsl_dataset_rele(ds, FTAG); 460*7265Sahrens return (ENOTSUP); 461*7265Sahrens } 462*7265Sahrens 463*7265Sahrens psa.name = propname; 464*7265Sahrens psa.intsz = intsz; 465*7265Sahrens psa.numints = numints; 466*7265Sahrens psa.buf = buf; 467*7265Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 468*7265Sahrens NULL, dsl_prop_set_sync, ds, &psa, 2); 469*7265Sahrens 470*7265Sahrens dsl_dataset_rele(ds, FTAG); 471789Sahrens return (err); 472789Sahrens } 4731356Seschrock 4741356Seschrock /* 4751356Seschrock * Iterate over all properties for this dataset and return them in an nvlist. 4761356Seschrock */ 4771356Seschrock int 4786689Smaybee dsl_prop_get_all(objset_t *os, nvlist_t **nvp, boolean_t local) 4791356Seschrock { 4801356Seschrock dsl_dataset_t *ds = os->os->os_dsl_dataset; 4812082Seschrock dsl_dir_t *dd = ds->ds_dir; 482*7265Sahrens boolean_t snapshot = dsl_dataset_is_snapshot(ds); 4831356Seschrock int err = 0; 484*7265Sahrens dsl_pool_t *dp = dd->dd_pool; 485*7265Sahrens objset_t *mos = dp->dp_meta_objset; 486*7265Sahrens uint64_t propobj = ds->ds_phys->ds_props_obj; 4871356Seschrock 4881356Seschrock VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); 4891356Seschrock 490*7265Sahrens if (local && snapshot && !propobj) 491*7265Sahrens return (0); 4921356Seschrock 4931356Seschrock rw_enter(&dp->dp_config_rwlock, RW_READER); 494*7265Sahrens while (dd != NULL) { 4952885Sahrens char setpoint[MAXNAMELEN]; 4962885Sahrens zap_cursor_t zc; 4972885Sahrens zap_attribute_t za; 498*7265Sahrens dsl_dir_t *dd_next; 4992885Sahrens 500*7265Sahrens if (propobj) { 501*7265Sahrens dsl_dataset_name(ds, setpoint); 502*7265Sahrens dd_next = dd; 503*7265Sahrens } else { 504*7265Sahrens dsl_dir_name(dd, setpoint); 505*7265Sahrens propobj = dd->dd_phys->dd_props_zapobj; 506*7265Sahrens dd_next = dd->dd_parent; 507*7265Sahrens } 5081356Seschrock 509*7265Sahrens for (zap_cursor_init(&zc, mos, propobj); 5101356Seschrock (err = zap_cursor_retrieve(&zc, &za)) == 0; 5111356Seschrock zap_cursor_advance(&zc)) { 5122885Sahrens nvlist_t *propval; 513*7265Sahrens zfs_prop_t prop = zfs_name_to_prop(za.za_name); 514*7265Sahrens 515*7265Sahrens /* Skip non-inheritable properties. */ 516*7265Sahrens if (prop != ZPROP_INVAL && 517*7265Sahrens !zfs_prop_inheritable(prop) && 518*7265Sahrens (dd != ds->ds_dir || (snapshot && dd != dd_next))) 5191356Seschrock continue; 5201356Seschrock 521*7265Sahrens /* Skip properties not valid for this type. */ 522*7265Sahrens if (snapshot && prop != ZPROP_INVAL && 5235331Samw !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT)) 5245331Samw continue; 5255331Samw 526*7265Sahrens /* Skip properties already defined */ 5272676Seschrock if (nvlist_lookup_nvlist(*nvp, za.za_name, 5282676Seschrock &propval) == 0) 5292676Seschrock continue; 5302676Seschrock 5312676Seschrock VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, 5321356Seschrock KM_SLEEP) == 0); 5331356Seschrock if (za.za_integer_length == 1) { 5341356Seschrock /* 5351356Seschrock * String property 5361356Seschrock */ 5372885Sahrens char *tmp = kmem_alloc(za.za_num_integers, 5382885Sahrens KM_SLEEP); 539*7265Sahrens err = zap_lookup(mos, propobj, 540*7265Sahrens za.za_name, 1, za.za_num_integers, tmp); 5411356Seschrock if (err != 0) { 5421356Seschrock kmem_free(tmp, za.za_num_integers); 5431356Seschrock break; 5441356Seschrock } 5455094Slling VERIFY(nvlist_add_string(propval, ZPROP_VALUE, 5465094Slling tmp) == 0); 5471356Seschrock kmem_free(tmp, za.za_num_integers); 5481356Seschrock } else { 5491356Seschrock /* 5501356Seschrock * Integer property 5511356Seschrock */ 5521356Seschrock ASSERT(za.za_integer_length == 8); 5535094Slling (void) nvlist_add_uint64(propval, ZPROP_VALUE, 5545094Slling za.za_first_integer); 5551356Seschrock } 5561356Seschrock 5575094Slling VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, 5585094Slling setpoint) == 0); 5591356Seschrock VERIFY(nvlist_add_nvlist(*nvp, za.za_name, 5602676Seschrock propval) == 0); 5612676Seschrock nvlist_free(propval); 5621356Seschrock } 5631356Seschrock zap_cursor_fini(&zc); 5641356Seschrock 5652082Seschrock if (err != ENOENT) 5661356Seschrock break; 5672082Seschrock err = 0; 5686689Smaybee /* 5696689Smaybee * If we are just after the props that have been set 5706689Smaybee * locally, then we are done after the first iteration. 5716689Smaybee */ 5726689Smaybee if (local) 5736689Smaybee break; 574*7265Sahrens dd = dd_next; 575*7265Sahrens propobj = 0; 5761356Seschrock } 5771356Seschrock rw_exit(&dp->dp_config_rwlock); 5781356Seschrock 5791356Seschrock return (err); 5801356Seschrock } 5812885Sahrens 5822885Sahrens void 5832885Sahrens dsl_prop_nvlist_add_uint64(nvlist_t *nv, zfs_prop_t prop, uint64_t value) 5842885Sahrens { 5852885Sahrens nvlist_t *propval; 5862885Sahrens 5872885Sahrens VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 5885094Slling VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0); 5892885Sahrens VERIFY(nvlist_add_nvlist(nv, zfs_prop_to_name(prop), propval) == 0); 5902885Sahrens nvlist_free(propval); 5912885Sahrens } 5922885Sahrens 5932885Sahrens void 5942885Sahrens dsl_prop_nvlist_add_string(nvlist_t *nv, zfs_prop_t prop, const char *value) 5952885Sahrens { 5962885Sahrens nvlist_t *propval; 5972885Sahrens 5982885Sahrens VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 5995094Slling VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0); 6002885Sahrens VERIFY(nvlist_add_nvlist(nv, zfs_prop_to_name(prop), propval) == 0); 6012885Sahrens nvlist_free(propval); 6022885Sahrens } 603