1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 51544Seschrock * Common Development and Distribution License (the "License"). 61544Seschrock * You may not use this file except in compliance with the License. 7789Sahrens * 8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9789Sahrens * or http://www.opensolaris.org/os/licensing. 10789Sahrens * See the License for the specific language governing permissions 11789Sahrens * and limitations under the License. 12789Sahrens * 13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15789Sahrens * If applicable, add the following below this CDDL HEADER, with the 16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18789Sahrens * 19789Sahrens * CDDL HEADER END 20789Sahrens */ 21789Sahrens /* 22*8697SRichard.Morris@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23789Sahrens * Use is subject to license terms. 24789Sahrens */ 25789Sahrens 26789Sahrens #include <sys/dmu.h> 271356Seschrock #include <sys/dmu_objset.h> 28789Sahrens #include <sys/dmu_tx.h> 29789Sahrens #include <sys/dsl_dataset.h> 30789Sahrens #include <sys/dsl_dir.h> 31789Sahrens #include <sys/dsl_prop.h> 322199Sahrens #include <sys/dsl_synctask.h> 33789Sahrens #include <sys/spa.h> 34789Sahrens #include <sys/zio_checksum.h> /* for the default checksum value */ 35789Sahrens #include <sys/zap.h> 36789Sahrens #include <sys/fs/zfs.h> 37789Sahrens 38789Sahrens #include "zfs_prop.h" 39789Sahrens 40789Sahrens static int 41789Sahrens dodefault(const char *propname, int intsz, int numint, void *buf) 42789Sahrens { 43789Sahrens zfs_prop_t prop; 44789Sahrens 455331Samw /* 465331Samw * The setonce properties are read-only, BUT they still 475331Samw * have a default value that can be used as the initial 485331Samw * value. 495331Samw */ 505094Slling if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL || 515331Samw (zfs_prop_readonly(prop) && !zfs_prop_setonce(prop))) 52789Sahrens return (ENOENT); 53789Sahrens 544787Sahrens if (zfs_prop_get_type(prop) == PROP_TYPE_STRING) { 55789Sahrens if (intsz != 1) 56789Sahrens return (EOVERFLOW); 575094Slling (void) strncpy(buf, zfs_prop_default_string(prop), 585094Slling numint); 59789Sahrens } else { 60789Sahrens if (intsz != 8 || numint < 1) 61789Sahrens return (EOVERFLOW); 62789Sahrens 63789Sahrens *(uint64_t *)buf = zfs_prop_default_numeric(prop); 64789Sahrens } 65789Sahrens 66789Sahrens return (0); 67789Sahrens } 68789Sahrens 697265Sahrens int 707265Sahrens dsl_prop_get_dd(dsl_dir_t *dd, const char *propname, 71789Sahrens int intsz, int numint, void *buf, char *setpoint) 72789Sahrens { 732082Seschrock int err = ENOENT; 747265Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 752676Seschrock zfs_prop_t prop; 76789Sahrens 777265Sahrens ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock)); 787265Sahrens 79789Sahrens if (setpoint) 80789Sahrens setpoint[0] = '\0'; 81789Sahrens 822676Seschrock prop = zfs_name_to_prop(propname); 832676Seschrock 842082Seschrock /* 852082Seschrock * Note: dd may be NULL, therefore we shouldn't dereference it 862082Seschrock * ouside this loop. 872082Seschrock */ 882082Seschrock for (; dd != NULL; dd = dd->dd_parent) { 892082Seschrock ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock)); 90789Sahrens err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj, 91789Sahrens propname, intsz, numint, buf); 92789Sahrens if (err != ENOENT) { 93789Sahrens if (setpoint) 94789Sahrens dsl_dir_name(dd, setpoint); 95789Sahrens break; 96789Sahrens } 972676Seschrock 982676Seschrock /* 992676Seschrock * Break out of this loop for non-inheritable properties. 1002676Seschrock */ 1015331Samw if (prop != ZPROP_INVAL && !zfs_prop_inheritable(prop)) 1022676Seschrock break; 103789Sahrens } 104789Sahrens if (err == ENOENT) 105789Sahrens err = dodefault(propname, intsz, numint, buf); 106789Sahrens 107789Sahrens return (err); 108789Sahrens } 109789Sahrens 1107265Sahrens int 1117265Sahrens dsl_prop_get_ds(dsl_dataset_t *ds, const char *propname, 1127265Sahrens int intsz, int numint, void *buf, char *setpoint) 1137265Sahrens { 1147265Sahrens ASSERT(RW_LOCK_HELD(&ds->ds_dir->dd_pool->dp_config_rwlock)); 1157265Sahrens 1167265Sahrens if (ds->ds_phys->ds_props_obj) { 1177265Sahrens int err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset, 1187265Sahrens ds->ds_phys->ds_props_obj, propname, intsz, numint, buf); 1197265Sahrens if (err != ENOENT) { 1207265Sahrens if (setpoint) 1217265Sahrens dsl_dataset_name(ds, setpoint); 1227265Sahrens return (err); 1237265Sahrens } 1247265Sahrens } 1257265Sahrens 1267265Sahrens return (dsl_prop_get_dd(ds->ds_dir, propname, 1277265Sahrens intsz, numint, buf, setpoint)); 1287265Sahrens } 1297265Sahrens 130789Sahrens /* 131789Sahrens * Register interest in the named property. We'll call the callback 132789Sahrens * once to notify it of the current property value, and again each time 133789Sahrens * the property changes, until this callback is unregistered. 134789Sahrens * 135789Sahrens * Return 0 on success, errno if the prop is not an integer value. 136789Sahrens */ 137789Sahrens int 138789Sahrens dsl_prop_register(dsl_dataset_t *ds, const char *propname, 139789Sahrens dsl_prop_changed_cb_t *callback, void *cbarg) 140789Sahrens { 1412082Seschrock dsl_dir_t *dd = ds->ds_dir; 1427265Sahrens dsl_pool_t *dp = dd->dd_pool; 143789Sahrens uint64_t value; 144789Sahrens dsl_prop_cb_record_t *cbr; 145789Sahrens int err; 1462199Sahrens int need_rwlock; 147789Sahrens 1487265Sahrens need_rwlock = !RW_WRITE_HELD(&dp->dp_config_rwlock); 1492199Sahrens if (need_rwlock) 1507265Sahrens rw_enter(&dp->dp_config_rwlock, RW_READER); 151789Sahrens 1527265Sahrens err = dsl_prop_get_ds(ds, propname, 8, 1, &value, NULL); 153789Sahrens if (err != 0) { 1545569Sck153898 if (need_rwlock) 1557265Sahrens rw_exit(&dp->dp_config_rwlock); 156789Sahrens return (err); 157789Sahrens } 158789Sahrens 159789Sahrens cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP); 1602082Seschrock cbr->cbr_ds = ds; 161789Sahrens cbr->cbr_propname = kmem_alloc(strlen(propname)+1, KM_SLEEP); 162789Sahrens (void) strcpy((char *)cbr->cbr_propname, propname); 163789Sahrens cbr->cbr_func = callback; 164789Sahrens cbr->cbr_arg = cbarg; 165789Sahrens mutex_enter(&dd->dd_lock); 166789Sahrens list_insert_head(&dd->dd_prop_cbs, cbr); 167789Sahrens mutex_exit(&dd->dd_lock); 168789Sahrens 169789Sahrens cbr->cbr_func(cbr->cbr_arg, value); 170789Sahrens 1717265Sahrens VERIFY(0 == dsl_dir_open_obj(dp, dd->dd_object, 1721544Seschrock NULL, cbr, &dd)); 1732199Sahrens if (need_rwlock) 1747265Sahrens rw_exit(&dp->dp_config_rwlock); 1757265Sahrens /* Leave dir open until this callback is unregistered */ 176789Sahrens return (0); 177789Sahrens } 178789Sahrens 179789Sahrens int 1807265Sahrens dsl_prop_get(const char *dsname, const char *propname, 1814543Smarks int intsz, int numints, void *buf, char *setpoint) 1824543Smarks { 1837265Sahrens dsl_dataset_t *ds; 184789Sahrens int err; 185789Sahrens 1867265Sahrens err = dsl_dataset_hold(dsname, FTAG, &ds); 1871544Seschrock if (err) 1881544Seschrock return (err); 189789Sahrens 1907265Sahrens rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); 1917265Sahrens err = dsl_prop_get_ds(ds, propname, intsz, numints, buf, setpoint); 1927265Sahrens rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 193789Sahrens 1947265Sahrens dsl_dataset_rele(ds, FTAG); 195789Sahrens return (err); 196789Sahrens } 197789Sahrens 198789Sahrens /* 199789Sahrens * Get the current property value. It may have changed by the time this 200789Sahrens * function returns, so it is NOT safe to follow up with 201789Sahrens * dsl_prop_register() and assume that the value has not changed in 202789Sahrens * between. 203789Sahrens * 204789Sahrens * Return 0 on success, ENOENT if ddname is invalid. 205789Sahrens */ 206789Sahrens int 207789Sahrens dsl_prop_get_integer(const char *ddname, const char *propname, 208789Sahrens uint64_t *valuep, char *setpoint) 209789Sahrens { 210789Sahrens return (dsl_prop_get(ddname, propname, 8, 1, valuep, setpoint)); 211789Sahrens } 212789Sahrens 213789Sahrens /* 214789Sahrens * Unregister this callback. Return 0 on success, ENOENT if ddname is 215789Sahrens * invalid, ENOMSG if no matching callback registered. 216789Sahrens */ 217789Sahrens int 218789Sahrens dsl_prop_unregister(dsl_dataset_t *ds, const char *propname, 219789Sahrens dsl_prop_changed_cb_t *callback, void *cbarg) 220789Sahrens { 2212082Seschrock dsl_dir_t *dd = ds->ds_dir; 222789Sahrens dsl_prop_cb_record_t *cbr; 223789Sahrens 224789Sahrens mutex_enter(&dd->dd_lock); 225789Sahrens for (cbr = list_head(&dd->dd_prop_cbs); 226789Sahrens cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { 2272082Seschrock if (cbr->cbr_ds == ds && 228789Sahrens cbr->cbr_func == callback && 2292082Seschrock cbr->cbr_arg == cbarg && 2302082Seschrock strcmp(cbr->cbr_propname, propname) == 0) 231789Sahrens break; 232789Sahrens } 233789Sahrens 234789Sahrens if (cbr == NULL) { 235789Sahrens mutex_exit(&dd->dd_lock); 236789Sahrens return (ENOMSG); 237789Sahrens } 238789Sahrens 239789Sahrens list_remove(&dd->dd_prop_cbs, cbr); 240789Sahrens mutex_exit(&dd->dd_lock); 241789Sahrens kmem_free((void*)cbr->cbr_propname, strlen(cbr->cbr_propname)+1); 242789Sahrens kmem_free(cbr, sizeof (dsl_prop_cb_record_t)); 243789Sahrens 244789Sahrens /* Clean up from dsl_prop_register */ 245789Sahrens dsl_dir_close(dd, cbr); 246789Sahrens return (0); 247789Sahrens } 248789Sahrens 2492082Seschrock /* 2502082Seschrock * Return the number of callbacks that are registered for this dataset. 2512082Seschrock */ 2522082Seschrock int 2532082Seschrock dsl_prop_numcb(dsl_dataset_t *ds) 2542082Seschrock { 2552082Seschrock dsl_dir_t *dd = ds->ds_dir; 2562082Seschrock dsl_prop_cb_record_t *cbr; 2572082Seschrock int num = 0; 2582082Seschrock 2592082Seschrock mutex_enter(&dd->dd_lock); 2602082Seschrock for (cbr = list_head(&dd->dd_prop_cbs); 2612082Seschrock cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { 2622082Seschrock if (cbr->cbr_ds == ds) 2632082Seschrock num++; 2642082Seschrock } 2652082Seschrock mutex_exit(&dd->dd_lock); 2662082Seschrock 2672082Seschrock return (num); 2682082Seschrock } 2692082Seschrock 270789Sahrens static void 271789Sahrens dsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj, 272789Sahrens const char *propname, uint64_t value, int first) 273789Sahrens { 274789Sahrens dsl_dir_t *dd; 275789Sahrens dsl_prop_cb_record_t *cbr; 276789Sahrens objset_t *mos = dp->dp_meta_objset; 2772199Sahrens zap_cursor_t zc; 2786047Sahrens zap_attribute_t *za; 279789Sahrens int err; 2807265Sahrens uint64_t dummyval; 281789Sahrens 282789Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 2831544Seschrock err = dsl_dir_open_obj(dp, ddobj, NULL, FTAG, &dd); 2841544Seschrock if (err) 2851544Seschrock return; 286789Sahrens 287789Sahrens if (!first) { 288789Sahrens /* 289789Sahrens * If the prop is set here, then this change is not 290789Sahrens * being inherited here or below; stop the recursion. 291789Sahrens */ 292789Sahrens err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj, propname, 2937265Sahrens 8, 1, &dummyval); 294789Sahrens if (err == 0) { 295789Sahrens dsl_dir_close(dd, FTAG); 296789Sahrens return; 297789Sahrens } 298789Sahrens ASSERT3U(err, ==, ENOENT); 299789Sahrens } 300789Sahrens 301789Sahrens mutex_enter(&dd->dd_lock); 3027265Sahrens for (cbr = list_head(&dd->dd_prop_cbs); cbr; 3037265Sahrens cbr = list_next(&dd->dd_prop_cbs, cbr)) { 3047265Sahrens uint64_t propobj = cbr->cbr_ds->ds_phys->ds_props_obj; 3057265Sahrens 3067265Sahrens if (strcmp(cbr->cbr_propname, propname) != 0) 3077265Sahrens continue; 3087265Sahrens 3097265Sahrens /* 3107265Sahrens * If the property is set on this ds, then it is not 3117265Sahrens * inherited here; don't call the callback. 3127265Sahrens */ 3137265Sahrens if (propobj && 0 == zap_lookup(mos, propobj, propname, 3147265Sahrens 8, 1, &dummyval)) 3157265Sahrens continue; 3167265Sahrens 3177265Sahrens cbr->cbr_func(cbr->cbr_arg, value); 318789Sahrens } 319789Sahrens mutex_exit(&dd->dd_lock); 320789Sahrens 3216047Sahrens za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP); 3222199Sahrens for (zap_cursor_init(&zc, mos, 3232199Sahrens dd->dd_phys->dd_child_dir_zapobj); 3246047Sahrens zap_cursor_retrieve(&zc, za) == 0; 3252199Sahrens zap_cursor_advance(&zc)) { 3266047Sahrens dsl_prop_changed_notify(dp, za->za_first_integer, 3272199Sahrens propname, value, FALSE); 328789Sahrens } 3296047Sahrens kmem_free(za, sizeof (zap_attribute_t)); 3302199Sahrens zap_cursor_fini(&zc); 331789Sahrens dsl_dir_close(dd, FTAG); 332789Sahrens } 333789Sahrens 334789Sahrens struct prop_set_arg { 335789Sahrens const char *name; 336789Sahrens int intsz; 337789Sahrens int numints; 338789Sahrens const void *buf; 339789Sahrens }; 340789Sahrens 3412199Sahrens 3422199Sahrens static void 3434543Smarks dsl_prop_set_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 344789Sahrens { 3457265Sahrens dsl_dataset_t *ds = arg1; 3462199Sahrens struct prop_set_arg *psa = arg2; 3477265Sahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 3487265Sahrens uint64_t zapobj, intval; 3492199Sahrens int isint; 3504543Smarks char valbuf[32]; 3514543Smarks char *valstr; 352789Sahrens 353789Sahrens isint = (dodefault(psa->name, 8, 1, &intval) == 0); 354789Sahrens 3557265Sahrens if (dsl_dataset_is_snapshot(ds)) { 3567265Sahrens ASSERT(spa_version(ds->ds_dir->dd_pool->dp_spa) >= 3577265Sahrens SPA_VERSION_SNAP_PROPS); 3587265Sahrens if (ds->ds_phys->ds_props_obj == 0) { 3597265Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 3607265Sahrens ds->ds_phys->ds_props_obj = 3617265Sahrens zap_create(mos, 3627265Sahrens DMU_OT_DSL_PROPS, DMU_OT_NONE, 0, tx); 3637265Sahrens } 3647265Sahrens zapobj = ds->ds_phys->ds_props_obj; 3657265Sahrens } else { 3667265Sahrens zapobj = ds->ds_dir->dd_phys->dd_props_zapobj; 3677265Sahrens } 3687265Sahrens 369789Sahrens if (psa->numints == 0) { 3702199Sahrens int err = zap_remove(mos, zapobj, psa->name, tx); 3712199Sahrens ASSERT(err == 0 || err == ENOENT); 3722199Sahrens if (isint) { 3737265Sahrens VERIFY(0 == dsl_prop_get_ds(ds, 3742199Sahrens psa->name, 8, 1, &intval, NULL)); 375789Sahrens } 376789Sahrens } else { 3772199Sahrens VERIFY(0 == zap_update(mos, zapobj, psa->name, 3782199Sahrens psa->intsz, psa->numints, psa->buf, tx)); 379789Sahrens if (isint) 380789Sahrens intval = *(uint64_t *)psa->buf; 381789Sahrens } 382789Sahrens 3832199Sahrens if (isint) { 3847265Sahrens if (dsl_dataset_is_snapshot(ds)) { 3857265Sahrens dsl_prop_cb_record_t *cbr; 3867265Sahrens /* 3877265Sahrens * It's a snapshot; nothing can inherit this 3887265Sahrens * property, so just look for callbacks on this 3897265Sahrens * ds here. 3907265Sahrens */ 3917265Sahrens mutex_enter(&ds->ds_dir->dd_lock); 3927265Sahrens for (cbr = list_head(&ds->ds_dir->dd_prop_cbs); cbr; 3937265Sahrens cbr = list_next(&ds->ds_dir->dd_prop_cbs, cbr)) { 3947265Sahrens if (cbr->cbr_ds == ds && 3957265Sahrens strcmp(cbr->cbr_propname, psa->name) == 0) 3967265Sahrens cbr->cbr_func(cbr->cbr_arg, intval); 3977265Sahrens } 3987265Sahrens mutex_exit(&ds->ds_dir->dd_lock); 3997265Sahrens } else { 4007265Sahrens dsl_prop_changed_notify(ds->ds_dir->dd_pool, 4017265Sahrens ds->ds_dir->dd_object, psa->name, intval, TRUE); 4027265Sahrens } 403789Sahrens } 4044543Smarks if (isint) { 4054543Smarks (void) snprintf(valbuf, sizeof (valbuf), 4064543Smarks "%lld", (longlong_t)intval); 4074543Smarks valstr = valbuf; 4084543Smarks } else { 4094543Smarks valstr = (char *)psa->buf; 4104543Smarks } 4114543Smarks spa_history_internal_log((psa->numints == 0) ? LOG_DS_INHERIT : 4127265Sahrens LOG_DS_PROPSET, ds->ds_dir->dd_pool->dp_spa, tx, cr, 4137265Sahrens "%s=%s dataset = %llu", psa->name, valstr, ds->ds_object); 414789Sahrens } 415789Sahrens 416*8697SRichard.Morris@Sun.COM static void 417*8697SRichard.Morris@Sun.COM dsl_props_set_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 418*8697SRichard.Morris@Sun.COM { 419*8697SRichard.Morris@Sun.COM dsl_dataset_t *ds = arg1; 420*8697SRichard.Morris@Sun.COM nvlist_t *nvl = arg2; 421*8697SRichard.Morris@Sun.COM nvpair_t *elem = NULL; 422*8697SRichard.Morris@Sun.COM 423*8697SRichard.Morris@Sun.COM while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 424*8697SRichard.Morris@Sun.COM struct prop_set_arg psa; 425*8697SRichard.Morris@Sun.COM 426*8697SRichard.Morris@Sun.COM psa.name = nvpair_name(elem); 427*8697SRichard.Morris@Sun.COM 428*8697SRichard.Morris@Sun.COM if (nvpair_type(elem) == DATA_TYPE_STRING) { 429*8697SRichard.Morris@Sun.COM VERIFY(nvpair_value_string(elem, 430*8697SRichard.Morris@Sun.COM (char **)&psa.buf) == 0); 431*8697SRichard.Morris@Sun.COM psa.intsz = 1; 432*8697SRichard.Morris@Sun.COM psa.numints = strlen(psa.buf) + 1; 433*8697SRichard.Morris@Sun.COM } else { 434*8697SRichard.Morris@Sun.COM uint64_t intval; 435*8697SRichard.Morris@Sun.COM VERIFY(nvpair_value_uint64(elem, &intval) == 0); 436*8697SRichard.Morris@Sun.COM psa.intsz = sizeof (intval); 437*8697SRichard.Morris@Sun.COM psa.numints = 1; 438*8697SRichard.Morris@Sun.COM psa.buf = &intval; 439*8697SRichard.Morris@Sun.COM } 440*8697SRichard.Morris@Sun.COM dsl_prop_set_sync(ds, &psa, cr, tx); 441*8697SRichard.Morris@Sun.COM } 442*8697SRichard.Morris@Sun.COM } 443*8697SRichard.Morris@Sun.COM 4445378Sck153898 void 4455378Sck153898 dsl_prop_set_uint64_sync(dsl_dir_t *dd, const char *name, uint64_t val, 4465378Sck153898 cred_t *cr, dmu_tx_t *tx) 4475378Sck153898 { 4485378Sck153898 objset_t *mos = dd->dd_pool->dp_meta_objset; 4495378Sck153898 uint64_t zapobj = dd->dd_phys->dd_props_zapobj; 4505378Sck153898 4515378Sck153898 ASSERT(dmu_tx_is_syncing(tx)); 4525378Sck153898 4535378Sck153898 VERIFY(0 == zap_update(mos, zapobj, name, sizeof (val), 1, &val, tx)); 4545378Sck153898 4555378Sck153898 dsl_prop_changed_notify(dd->dd_pool, dd->dd_object, name, val, TRUE); 4565378Sck153898 4575378Sck153898 spa_history_internal_log(LOG_DS_PROPSET, dd->dd_pool->dp_spa, tx, cr, 4585378Sck153898 "%s=%llu dataset = %llu", name, (u_longlong_t)val, 4595378Sck153898 dd->dd_phys->dd_head_dataset_obj); 4605378Sck153898 } 4615378Sck153898 462789Sahrens int 4637265Sahrens dsl_prop_set(const char *dsname, const char *propname, 4642885Sahrens int intsz, int numints, const void *buf) 4652885Sahrens { 4667265Sahrens dsl_dataset_t *ds; 4677265Sahrens int err; 4682885Sahrens struct prop_set_arg psa; 4692885Sahrens 4702641Sahrens /* 4712641Sahrens * We must do these checks before we get to the syncfunc, since 4722641Sahrens * it can't fail. 4732641Sahrens */ 4742641Sahrens if (strlen(propname) >= ZAP_MAXNAMELEN) 4752641Sahrens return (ENAMETOOLONG); 4762641Sahrens if (intsz * numints >= ZAP_MAXVALUELEN) 4772641Sahrens return (E2BIG); 4782641Sahrens 4797265Sahrens err = dsl_dataset_hold(dsname, FTAG, &ds); 4801544Seschrock if (err) 4811544Seschrock return (err); 4827265Sahrens 4837265Sahrens if (dsl_dataset_is_snapshot(ds) && 4847265Sahrens spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_SNAP_PROPS) { 4857265Sahrens dsl_dataset_rele(ds, FTAG); 4867265Sahrens return (ENOTSUP); 4877265Sahrens } 4887265Sahrens 4897265Sahrens psa.name = propname; 4907265Sahrens psa.intsz = intsz; 4917265Sahrens psa.numints = numints; 4927265Sahrens psa.buf = buf; 4937265Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 4947265Sahrens NULL, dsl_prop_set_sync, ds, &psa, 2); 4957265Sahrens 4967265Sahrens dsl_dataset_rele(ds, FTAG); 497789Sahrens return (err); 498789Sahrens } 4991356Seschrock 500*8697SRichard.Morris@Sun.COM int 501*8697SRichard.Morris@Sun.COM dsl_props_set(const char *dsname, nvlist_t *nvl) 502*8697SRichard.Morris@Sun.COM { 503*8697SRichard.Morris@Sun.COM dsl_dataset_t *ds; 504*8697SRichard.Morris@Sun.COM nvpair_t *elem = NULL; 505*8697SRichard.Morris@Sun.COM int err; 506*8697SRichard.Morris@Sun.COM 507*8697SRichard.Morris@Sun.COM while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 508*8697SRichard.Morris@Sun.COM if (nvpair_type(elem) == DATA_TYPE_STRING) { 509*8697SRichard.Morris@Sun.COM char *valstr; 510*8697SRichard.Morris@Sun.COM VERIFY(nvpair_value_string(elem, &valstr) == 0); 511*8697SRichard.Morris@Sun.COM if (strlen(valstr) >= ZAP_MAXNAMELEN) 512*8697SRichard.Morris@Sun.COM return (ENAMETOOLONG); 513*8697SRichard.Morris@Sun.COM } 514*8697SRichard.Morris@Sun.COM } 515*8697SRichard.Morris@Sun.COM 516*8697SRichard.Morris@Sun.COM if (err = dsl_dataset_hold(dsname, FTAG, &ds)) 517*8697SRichard.Morris@Sun.COM return (err); 518*8697SRichard.Morris@Sun.COM 519*8697SRichard.Morris@Sun.COM if (dsl_dataset_is_snapshot(ds) && 520*8697SRichard.Morris@Sun.COM spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_SNAP_PROPS) { 521*8697SRichard.Morris@Sun.COM dsl_dataset_rele(ds, FTAG); 522*8697SRichard.Morris@Sun.COM return (ENOTSUP); 523*8697SRichard.Morris@Sun.COM } 524*8697SRichard.Morris@Sun.COM 525*8697SRichard.Morris@Sun.COM err = dsl_sync_task_do(ds->ds_dir->dd_pool, 526*8697SRichard.Morris@Sun.COM NULL, dsl_props_set_sync, ds, nvl, 2); 527*8697SRichard.Morris@Sun.COM 528*8697SRichard.Morris@Sun.COM dsl_dataset_rele(ds, FTAG); 529*8697SRichard.Morris@Sun.COM return (err); 530*8697SRichard.Morris@Sun.COM } 531*8697SRichard.Morris@Sun.COM 5321356Seschrock /* 5331356Seschrock * Iterate over all properties for this dataset and return them in an nvlist. 5341356Seschrock */ 5351356Seschrock int 5366689Smaybee dsl_prop_get_all(objset_t *os, nvlist_t **nvp, boolean_t local) 5371356Seschrock { 5381356Seschrock dsl_dataset_t *ds = os->os->os_dsl_dataset; 5392082Seschrock dsl_dir_t *dd = ds->ds_dir; 5407265Sahrens boolean_t snapshot = dsl_dataset_is_snapshot(ds); 5411356Seschrock int err = 0; 5427265Sahrens dsl_pool_t *dp = dd->dd_pool; 5437265Sahrens objset_t *mos = dp->dp_meta_objset; 5447265Sahrens uint64_t propobj = ds->ds_phys->ds_props_obj; 5451356Seschrock 5461356Seschrock VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); 5471356Seschrock 5487265Sahrens if (local && snapshot && !propobj) 5497265Sahrens return (0); 5501356Seschrock 5511356Seschrock rw_enter(&dp->dp_config_rwlock, RW_READER); 5527265Sahrens while (dd != NULL) { 5532885Sahrens char setpoint[MAXNAMELEN]; 5542885Sahrens zap_cursor_t zc; 5552885Sahrens zap_attribute_t za; 5567265Sahrens dsl_dir_t *dd_next; 5572885Sahrens 5587265Sahrens if (propobj) { 5597265Sahrens dsl_dataset_name(ds, setpoint); 5607265Sahrens dd_next = dd; 5617265Sahrens } else { 5627265Sahrens dsl_dir_name(dd, setpoint); 5637265Sahrens propobj = dd->dd_phys->dd_props_zapobj; 5647265Sahrens dd_next = dd->dd_parent; 5657265Sahrens } 5661356Seschrock 5677265Sahrens for (zap_cursor_init(&zc, mos, propobj); 5681356Seschrock (err = zap_cursor_retrieve(&zc, &za)) == 0; 5691356Seschrock zap_cursor_advance(&zc)) { 5702885Sahrens nvlist_t *propval; 5717265Sahrens zfs_prop_t prop = zfs_name_to_prop(za.za_name); 5727265Sahrens 5737265Sahrens /* Skip non-inheritable properties. */ 5747265Sahrens if (prop != ZPROP_INVAL && 5757265Sahrens !zfs_prop_inheritable(prop) && 5767265Sahrens (dd != ds->ds_dir || (snapshot && dd != dd_next))) 5771356Seschrock continue; 5781356Seschrock 5797265Sahrens /* Skip properties not valid for this type. */ 5807265Sahrens if (snapshot && prop != ZPROP_INVAL && 5815331Samw !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT)) 5825331Samw continue; 5835331Samw 5847265Sahrens /* Skip properties already defined */ 5852676Seschrock if (nvlist_lookup_nvlist(*nvp, za.za_name, 5862676Seschrock &propval) == 0) 5872676Seschrock continue; 5882676Seschrock 5892676Seschrock VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, 5901356Seschrock KM_SLEEP) == 0); 5911356Seschrock if (za.za_integer_length == 1) { 5921356Seschrock /* 5931356Seschrock * String property 5941356Seschrock */ 5952885Sahrens char *tmp = kmem_alloc(za.za_num_integers, 5962885Sahrens KM_SLEEP); 5977265Sahrens err = zap_lookup(mos, propobj, 5987265Sahrens za.za_name, 1, za.za_num_integers, tmp); 5991356Seschrock if (err != 0) { 6001356Seschrock kmem_free(tmp, za.za_num_integers); 6011356Seschrock break; 6021356Seschrock } 6035094Slling VERIFY(nvlist_add_string(propval, ZPROP_VALUE, 6045094Slling tmp) == 0); 6051356Seschrock kmem_free(tmp, za.za_num_integers); 6061356Seschrock } else { 6071356Seschrock /* 6081356Seschrock * Integer property 6091356Seschrock */ 6101356Seschrock ASSERT(za.za_integer_length == 8); 6115094Slling (void) nvlist_add_uint64(propval, ZPROP_VALUE, 6125094Slling za.za_first_integer); 6131356Seschrock } 6141356Seschrock 6155094Slling VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, 6165094Slling setpoint) == 0); 6171356Seschrock VERIFY(nvlist_add_nvlist(*nvp, za.za_name, 6182676Seschrock propval) == 0); 6192676Seschrock nvlist_free(propval); 6201356Seschrock } 6211356Seschrock zap_cursor_fini(&zc); 6221356Seschrock 6232082Seschrock if (err != ENOENT) 6241356Seschrock break; 6252082Seschrock err = 0; 6266689Smaybee /* 6276689Smaybee * If we are just after the props that have been set 6286689Smaybee * locally, then we are done after the first iteration. 6296689Smaybee */ 6306689Smaybee if (local) 6316689Smaybee break; 6327265Sahrens dd = dd_next; 6337265Sahrens propobj = 0; 6341356Seschrock } 6351356Seschrock rw_exit(&dp->dp_config_rwlock); 6361356Seschrock 6371356Seschrock return (err); 6381356Seschrock } 6392885Sahrens 6402885Sahrens void 6412885Sahrens dsl_prop_nvlist_add_uint64(nvlist_t *nv, zfs_prop_t prop, uint64_t value) 6422885Sahrens { 6432885Sahrens nvlist_t *propval; 6442885Sahrens 6452885Sahrens VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 6465094Slling VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0); 6472885Sahrens VERIFY(nvlist_add_nvlist(nv, zfs_prop_to_name(prop), propval) == 0); 6482885Sahrens nvlist_free(propval); 6492885Sahrens } 6502885Sahrens 6512885Sahrens void 6522885Sahrens dsl_prop_nvlist_add_string(nvlist_t *nv, zfs_prop_t prop, const char *value) 6532885Sahrens { 6542885Sahrens nvlist_t *propval; 6552885Sahrens 6562885Sahrens VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 6575094Slling VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0); 6582885Sahrens VERIFY(nvlist_add_nvlist(nv, zfs_prop_to_name(prop), propval) == 0); 6592885Sahrens nvlist_free(propval); 6602885Sahrens } 661