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 /* 228697SRichard.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 4169355SMatthew.Ahrens@Sun.COM void 4178697SRichard.Morris@Sun.COM dsl_props_set_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 4188697SRichard.Morris@Sun.COM { 4198697SRichard.Morris@Sun.COM dsl_dataset_t *ds = arg1; 4208697SRichard.Morris@Sun.COM nvlist_t *nvl = arg2; 4218697SRichard.Morris@Sun.COM nvpair_t *elem = NULL; 4228697SRichard.Morris@Sun.COM 4238697SRichard.Morris@Sun.COM while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 4248697SRichard.Morris@Sun.COM struct prop_set_arg psa; 4258697SRichard.Morris@Sun.COM 4268697SRichard.Morris@Sun.COM psa.name = nvpair_name(elem); 4278697SRichard.Morris@Sun.COM 4288697SRichard.Morris@Sun.COM if (nvpair_type(elem) == DATA_TYPE_STRING) { 4298697SRichard.Morris@Sun.COM VERIFY(nvpair_value_string(elem, 4308697SRichard.Morris@Sun.COM (char **)&psa.buf) == 0); 4318697SRichard.Morris@Sun.COM psa.intsz = 1; 4328697SRichard.Morris@Sun.COM psa.numints = strlen(psa.buf) + 1; 4338697SRichard.Morris@Sun.COM } else { 4348697SRichard.Morris@Sun.COM uint64_t intval; 4358697SRichard.Morris@Sun.COM VERIFY(nvpair_value_uint64(elem, &intval) == 0); 4368697SRichard.Morris@Sun.COM psa.intsz = sizeof (intval); 4378697SRichard.Morris@Sun.COM psa.numints = 1; 4388697SRichard.Morris@Sun.COM psa.buf = &intval; 4398697SRichard.Morris@Sun.COM } 4408697SRichard.Morris@Sun.COM dsl_prop_set_sync(ds, &psa, cr, tx); 4418697SRichard.Morris@Sun.COM } 4428697SRichard.Morris@Sun.COM } 4438697SRichard.Morris@Sun.COM 4445378Sck153898 void 445*10242Schris.kirby@sun.com dsl_dir_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; 4679643SEric.Taylor@Sun.COM uint64_t version; 4687265Sahrens int err; 4692885Sahrens struct prop_set_arg psa; 4702885Sahrens 4712641Sahrens /* 4722641Sahrens * We must do these checks before we get to the syncfunc, since 4732641Sahrens * it can't fail. 4742641Sahrens */ 4752641Sahrens if (strlen(propname) >= ZAP_MAXNAMELEN) 4762641Sahrens return (ENAMETOOLONG); 4772641Sahrens 4787265Sahrens err = dsl_dataset_hold(dsname, FTAG, &ds); 4791544Seschrock if (err) 4801544Seschrock return (err); 4817265Sahrens 4829643SEric.Taylor@Sun.COM version = spa_version(ds->ds_dir->dd_pool->dp_spa); 4839643SEric.Taylor@Sun.COM if (intsz * numints >= (version < SPA_VERSION_STMF_PROP ? 4849643SEric.Taylor@Sun.COM ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) { 4859643SEric.Taylor@Sun.COM dsl_dataset_rele(ds, FTAG); 4869643SEric.Taylor@Sun.COM return (E2BIG); 4879643SEric.Taylor@Sun.COM } 4887265Sahrens if (dsl_dataset_is_snapshot(ds) && 4899643SEric.Taylor@Sun.COM version < SPA_VERSION_SNAP_PROPS) { 4907265Sahrens dsl_dataset_rele(ds, FTAG); 4917265Sahrens return (ENOTSUP); 4927265Sahrens } 4937265Sahrens 4947265Sahrens psa.name = propname; 4957265Sahrens psa.intsz = intsz; 4967265Sahrens psa.numints = numints; 4977265Sahrens psa.buf = buf; 4987265Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 4997265Sahrens NULL, dsl_prop_set_sync, ds, &psa, 2); 5007265Sahrens 5017265Sahrens dsl_dataset_rele(ds, FTAG); 502789Sahrens return (err); 503789Sahrens } 5041356Seschrock 5058697SRichard.Morris@Sun.COM int 5068697SRichard.Morris@Sun.COM dsl_props_set(const char *dsname, nvlist_t *nvl) 5078697SRichard.Morris@Sun.COM { 5088697SRichard.Morris@Sun.COM dsl_dataset_t *ds; 5099643SEric.Taylor@Sun.COM uint64_t version; 5108697SRichard.Morris@Sun.COM nvpair_t *elem = NULL; 5118697SRichard.Morris@Sun.COM int err; 5128697SRichard.Morris@Sun.COM 5139643SEric.Taylor@Sun.COM if (err = dsl_dataset_hold(dsname, FTAG, &ds)) 5149643SEric.Taylor@Sun.COM return (err); 5158924SRichard.Morris@Sun.COM /* 5168924SRichard.Morris@Sun.COM * Do these checks before the syncfunc, since it can't fail. 5178924SRichard.Morris@Sun.COM */ 5189643SEric.Taylor@Sun.COM version = spa_version(ds->ds_dir->dd_pool->dp_spa); 5198697SRichard.Morris@Sun.COM while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 5209643SEric.Taylor@Sun.COM if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) { 5219643SEric.Taylor@Sun.COM dsl_dataset_rele(ds, FTAG); 5228924SRichard.Morris@Sun.COM return (ENAMETOOLONG); 5239643SEric.Taylor@Sun.COM } 5248697SRichard.Morris@Sun.COM if (nvpair_type(elem) == DATA_TYPE_STRING) { 5258697SRichard.Morris@Sun.COM char *valstr; 5268697SRichard.Morris@Sun.COM VERIFY(nvpair_value_string(elem, &valstr) == 0); 5279643SEric.Taylor@Sun.COM if (strlen(valstr) >= (version < 5289643SEric.Taylor@Sun.COM SPA_VERSION_STMF_PROP ? 5299643SEric.Taylor@Sun.COM ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) { 5309643SEric.Taylor@Sun.COM dsl_dataset_rele(ds, FTAG); 5318924SRichard.Morris@Sun.COM return (E2BIG); 5329643SEric.Taylor@Sun.COM } 5338697SRichard.Morris@Sun.COM } 5348697SRichard.Morris@Sun.COM } 5358697SRichard.Morris@Sun.COM 5368697SRichard.Morris@Sun.COM if (dsl_dataset_is_snapshot(ds) && 5379643SEric.Taylor@Sun.COM version < SPA_VERSION_SNAP_PROPS) { 5388697SRichard.Morris@Sun.COM dsl_dataset_rele(ds, FTAG); 5398697SRichard.Morris@Sun.COM return (ENOTSUP); 5408697SRichard.Morris@Sun.COM } 5418697SRichard.Morris@Sun.COM 5428697SRichard.Morris@Sun.COM err = dsl_sync_task_do(ds->ds_dir->dd_pool, 5438697SRichard.Morris@Sun.COM NULL, dsl_props_set_sync, ds, nvl, 2); 5448697SRichard.Morris@Sun.COM 5458697SRichard.Morris@Sun.COM dsl_dataset_rele(ds, FTAG); 5468697SRichard.Morris@Sun.COM return (err); 5478697SRichard.Morris@Sun.COM } 5488697SRichard.Morris@Sun.COM 5491356Seschrock /* 5501356Seschrock * Iterate over all properties for this dataset and return them in an nvlist. 5511356Seschrock */ 5521356Seschrock int 5536689Smaybee dsl_prop_get_all(objset_t *os, nvlist_t **nvp, boolean_t local) 5541356Seschrock { 5551356Seschrock dsl_dataset_t *ds = os->os->os_dsl_dataset; 5562082Seschrock dsl_dir_t *dd = ds->ds_dir; 5577265Sahrens boolean_t snapshot = dsl_dataset_is_snapshot(ds); 5581356Seschrock int err = 0; 5597265Sahrens dsl_pool_t *dp = dd->dd_pool; 5607265Sahrens objset_t *mos = dp->dp_meta_objset; 5617265Sahrens uint64_t propobj = ds->ds_phys->ds_props_obj; 5621356Seschrock 5631356Seschrock VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); 5641356Seschrock 5657265Sahrens if (local && snapshot && !propobj) 5667265Sahrens return (0); 5671356Seschrock 5681356Seschrock rw_enter(&dp->dp_config_rwlock, RW_READER); 5697265Sahrens while (dd != NULL) { 5702885Sahrens char setpoint[MAXNAMELEN]; 5712885Sahrens zap_cursor_t zc; 5722885Sahrens zap_attribute_t za; 5737265Sahrens dsl_dir_t *dd_next; 5742885Sahrens 5757265Sahrens if (propobj) { 5767265Sahrens dsl_dataset_name(ds, setpoint); 5777265Sahrens dd_next = dd; 5787265Sahrens } else { 5797265Sahrens dsl_dir_name(dd, setpoint); 5807265Sahrens propobj = dd->dd_phys->dd_props_zapobj; 5817265Sahrens dd_next = dd->dd_parent; 5827265Sahrens } 5831356Seschrock 5847265Sahrens for (zap_cursor_init(&zc, mos, propobj); 5851356Seschrock (err = zap_cursor_retrieve(&zc, &za)) == 0; 5861356Seschrock zap_cursor_advance(&zc)) { 5872885Sahrens nvlist_t *propval; 5887265Sahrens zfs_prop_t prop = zfs_name_to_prop(za.za_name); 5897265Sahrens 5907265Sahrens /* Skip non-inheritable properties. */ 5917265Sahrens if (prop != ZPROP_INVAL && 5927265Sahrens !zfs_prop_inheritable(prop) && 5937265Sahrens (dd != ds->ds_dir || (snapshot && dd != dd_next))) 5941356Seschrock continue; 5951356Seschrock 5967265Sahrens /* Skip properties not valid for this type. */ 5977265Sahrens if (snapshot && prop != ZPROP_INVAL && 5985331Samw !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT)) 5995331Samw continue; 6005331Samw 6017265Sahrens /* Skip properties already defined */ 6022676Seschrock if (nvlist_lookup_nvlist(*nvp, za.za_name, 6032676Seschrock &propval) == 0) 6042676Seschrock continue; 6052676Seschrock 6062676Seschrock VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, 6071356Seschrock KM_SLEEP) == 0); 6081356Seschrock if (za.za_integer_length == 1) { 6091356Seschrock /* 6101356Seschrock * String property 6111356Seschrock */ 6122885Sahrens char *tmp = kmem_alloc(za.za_num_integers, 6132885Sahrens KM_SLEEP); 6147265Sahrens err = zap_lookup(mos, propobj, 6157265Sahrens za.za_name, 1, za.za_num_integers, tmp); 6161356Seschrock if (err != 0) { 6171356Seschrock kmem_free(tmp, za.za_num_integers); 6181356Seschrock break; 6191356Seschrock } 6205094Slling VERIFY(nvlist_add_string(propval, ZPROP_VALUE, 6215094Slling tmp) == 0); 6221356Seschrock kmem_free(tmp, za.za_num_integers); 6231356Seschrock } else { 6241356Seschrock /* 6251356Seschrock * Integer property 6261356Seschrock */ 6271356Seschrock ASSERT(za.za_integer_length == 8); 6285094Slling (void) nvlist_add_uint64(propval, ZPROP_VALUE, 6295094Slling za.za_first_integer); 6301356Seschrock } 6311356Seschrock 6325094Slling VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, 6335094Slling setpoint) == 0); 6341356Seschrock VERIFY(nvlist_add_nvlist(*nvp, za.za_name, 6352676Seschrock propval) == 0); 6362676Seschrock nvlist_free(propval); 6371356Seschrock } 6381356Seschrock zap_cursor_fini(&zc); 6391356Seschrock 6402082Seschrock if (err != ENOENT) 6411356Seschrock break; 6422082Seschrock err = 0; 6436689Smaybee /* 6446689Smaybee * If we are just after the props that have been set 6456689Smaybee * locally, then we are done after the first iteration. 6466689Smaybee */ 6476689Smaybee if (local) 6486689Smaybee break; 6497265Sahrens dd = dd_next; 6507265Sahrens propobj = 0; 6511356Seschrock } 6521356Seschrock rw_exit(&dp->dp_config_rwlock); 6531356Seschrock 6541356Seschrock return (err); 6551356Seschrock } 6562885Sahrens 6572885Sahrens void 6582885Sahrens dsl_prop_nvlist_add_uint64(nvlist_t *nv, zfs_prop_t prop, uint64_t value) 6592885Sahrens { 6602885Sahrens nvlist_t *propval; 6612885Sahrens 6622885Sahrens VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 6635094Slling VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0); 6642885Sahrens VERIFY(nvlist_add_nvlist(nv, zfs_prop_to_name(prop), propval) == 0); 6652885Sahrens nvlist_free(propval); 6662885Sahrens } 6672885Sahrens 6682885Sahrens void 6692885Sahrens dsl_prop_nvlist_add_string(nvlist_t *nv, zfs_prop_t prop, const char *value) 6702885Sahrens { 6712885Sahrens nvlist_t *propval; 6722885Sahrens 6732885Sahrens VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 6745094Slling VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0); 6752885Sahrens VERIFY(nvlist_add_nvlist(nv, zfs_prop_to_name(prop), propval) == 0); 6762885Sahrens nvlist_free(propval); 6772885Sahrens } 678