1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5ea8dc4b6Seschrock * Common Development and Distribution License (the "License"). 6ea8dc4b6Seschrock * You may not use this file except in compliance with the License. 7fa9e4066Sahrens * 8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 10fa9e4066Sahrens * See the License for the specific language governing permissions 11fa9e4066Sahrens * and limitations under the License. 12fa9e4066Sahrens * 13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18fa9e4066Sahrens * 19fa9e4066Sahrens * CDDL HEADER END 20fa9e4066Sahrens */ 21fa9e4066Sahrens /* 22d8d77200Sahrens * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23fa9e4066Sahrens * Use is subject to license terms. 24fa9e4066Sahrens */ 25fa9e4066Sahrens 26fa9e4066Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 27fa9e4066Sahrens 28fa9e4066Sahrens #include <sys/dmu.h> 297f7322feSeschrock #include <sys/dmu_objset.h> 30fa9e4066Sahrens #include <sys/dmu_tx.h> 31fa9e4066Sahrens #include <sys/dsl_dataset.h> 32fa9e4066Sahrens #include <sys/dsl_dir.h> 33fa9e4066Sahrens #include <sys/dsl_prop.h> 341d452cf5Sahrens #include <sys/dsl_synctask.h> 35fa9e4066Sahrens #include <sys/spa.h> 36fa9e4066Sahrens #include <sys/zio_checksum.h> /* for the default checksum value */ 37fa9e4066Sahrens #include <sys/zap.h> 38fa9e4066Sahrens #include <sys/fs/zfs.h> 39fa9e4066Sahrens 40fa9e4066Sahrens #include "zfs_prop.h" 41fa9e4066Sahrens 42fa9e4066Sahrens static int 43fa9e4066Sahrens dodefault(const char *propname, int intsz, int numint, void *buf) 44fa9e4066Sahrens { 45fa9e4066Sahrens zfs_prop_t prop; 46fa9e4066Sahrens 47da6c28aaSamw /* 48da6c28aaSamw * The setonce properties are read-only, BUT they still 49da6c28aaSamw * have a default value that can be used as the initial 50da6c28aaSamw * value. 51da6c28aaSamw */ 52990b4856Slling if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL || 53da6c28aaSamw (zfs_prop_readonly(prop) && !zfs_prop_setonce(prop))) 54fa9e4066Sahrens return (ENOENT); 55fa9e4066Sahrens 5691ebeef5Sahrens if (zfs_prop_get_type(prop) == PROP_TYPE_STRING) { 57fa9e4066Sahrens if (intsz != 1) 58fa9e4066Sahrens return (EOVERFLOW); 59990b4856Slling (void) strncpy(buf, zfs_prop_default_string(prop), 60990b4856Slling numint); 61fa9e4066Sahrens } else { 62fa9e4066Sahrens if (intsz != 8 || numint < 1) 63fa9e4066Sahrens return (EOVERFLOW); 64fa9e4066Sahrens 65fa9e4066Sahrens *(uint64_t *)buf = zfs_prop_default_numeric(prop); 66fa9e4066Sahrens } 67fa9e4066Sahrens 68fa9e4066Sahrens return (0); 69fa9e4066Sahrens } 70fa9e4066Sahrens 71*bb0ade09Sahrens int 72*bb0ade09Sahrens dsl_prop_get_dd(dsl_dir_t *dd, const char *propname, 73fa9e4066Sahrens int intsz, int numint, void *buf, char *setpoint) 74fa9e4066Sahrens { 7599653d4eSeschrock int err = ENOENT; 76*bb0ade09Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 77e9dbad6fSeschrock zfs_prop_t prop; 78fa9e4066Sahrens 79*bb0ade09Sahrens ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock)); 80*bb0ade09Sahrens 81fa9e4066Sahrens if (setpoint) 82fa9e4066Sahrens setpoint[0] = '\0'; 83fa9e4066Sahrens 84e9dbad6fSeschrock prop = zfs_name_to_prop(propname); 85e9dbad6fSeschrock 8699653d4eSeschrock /* 8799653d4eSeschrock * Note: dd may be NULL, therefore we shouldn't dereference it 8899653d4eSeschrock * ouside this loop. 8999653d4eSeschrock */ 9099653d4eSeschrock for (; dd != NULL; dd = dd->dd_parent) { 9199653d4eSeschrock ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock)); 92fa9e4066Sahrens err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj, 93fa9e4066Sahrens propname, intsz, numint, buf); 94fa9e4066Sahrens if (err != ENOENT) { 95fa9e4066Sahrens if (setpoint) 96fa9e4066Sahrens dsl_dir_name(dd, setpoint); 97fa9e4066Sahrens break; 98fa9e4066Sahrens } 99e9dbad6fSeschrock 100e9dbad6fSeschrock /* 101e9dbad6fSeschrock * Break out of this loop for non-inheritable properties. 102e9dbad6fSeschrock */ 103da6c28aaSamw if (prop != ZPROP_INVAL && !zfs_prop_inheritable(prop)) 104e9dbad6fSeschrock break; 105fa9e4066Sahrens } 106fa9e4066Sahrens if (err == ENOENT) 107fa9e4066Sahrens err = dodefault(propname, intsz, numint, buf); 108fa9e4066Sahrens 109fa9e4066Sahrens return (err); 110fa9e4066Sahrens } 111fa9e4066Sahrens 112*bb0ade09Sahrens int 113*bb0ade09Sahrens dsl_prop_get_ds(dsl_dataset_t *ds, const char *propname, 114*bb0ade09Sahrens int intsz, int numint, void *buf, char *setpoint) 115*bb0ade09Sahrens { 116*bb0ade09Sahrens ASSERT(RW_LOCK_HELD(&ds->ds_dir->dd_pool->dp_config_rwlock)); 117*bb0ade09Sahrens 118*bb0ade09Sahrens if (ds->ds_phys->ds_props_obj) { 119*bb0ade09Sahrens int err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset, 120*bb0ade09Sahrens ds->ds_phys->ds_props_obj, propname, intsz, numint, buf); 121*bb0ade09Sahrens if (err != ENOENT) { 122*bb0ade09Sahrens if (setpoint) 123*bb0ade09Sahrens dsl_dataset_name(ds, setpoint); 124*bb0ade09Sahrens return (err); 125*bb0ade09Sahrens } 126*bb0ade09Sahrens } 127*bb0ade09Sahrens 128*bb0ade09Sahrens return (dsl_prop_get_dd(ds->ds_dir, propname, 129*bb0ade09Sahrens intsz, numint, buf, setpoint)); 130*bb0ade09Sahrens } 131*bb0ade09Sahrens 132fa9e4066Sahrens /* 133fa9e4066Sahrens * Register interest in the named property. We'll call the callback 134fa9e4066Sahrens * once to notify it of the current property value, and again each time 135fa9e4066Sahrens * the property changes, until this callback is unregistered. 136fa9e4066Sahrens * 137fa9e4066Sahrens * Return 0 on success, errno if the prop is not an integer value. 138fa9e4066Sahrens */ 139fa9e4066Sahrens int 140fa9e4066Sahrens dsl_prop_register(dsl_dataset_t *ds, const char *propname, 141fa9e4066Sahrens dsl_prop_changed_cb_t *callback, void *cbarg) 142fa9e4066Sahrens { 14399653d4eSeschrock dsl_dir_t *dd = ds->ds_dir; 144*bb0ade09Sahrens dsl_pool_t *dp = dd->dd_pool; 145fa9e4066Sahrens uint64_t value; 146fa9e4066Sahrens dsl_prop_cb_record_t *cbr; 147fa9e4066Sahrens int err; 1481d452cf5Sahrens int need_rwlock; 149fa9e4066Sahrens 150*bb0ade09Sahrens need_rwlock = !RW_WRITE_HELD(&dp->dp_config_rwlock); 1511d452cf5Sahrens if (need_rwlock) 152*bb0ade09Sahrens rw_enter(&dp->dp_config_rwlock, RW_READER); 153fa9e4066Sahrens 154*bb0ade09Sahrens err = dsl_prop_get_ds(ds, propname, 8, 1, &value, NULL); 155fa9e4066Sahrens if (err != 0) { 15627345066Sck if (need_rwlock) 157*bb0ade09Sahrens rw_exit(&dp->dp_config_rwlock); 158fa9e4066Sahrens return (err); 159fa9e4066Sahrens } 160fa9e4066Sahrens 161fa9e4066Sahrens cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP); 16299653d4eSeschrock cbr->cbr_ds = ds; 163fa9e4066Sahrens cbr->cbr_propname = kmem_alloc(strlen(propname)+1, KM_SLEEP); 164fa9e4066Sahrens (void) strcpy((char *)cbr->cbr_propname, propname); 165fa9e4066Sahrens cbr->cbr_func = callback; 166fa9e4066Sahrens cbr->cbr_arg = cbarg; 167fa9e4066Sahrens mutex_enter(&dd->dd_lock); 168fa9e4066Sahrens list_insert_head(&dd->dd_prop_cbs, cbr); 169fa9e4066Sahrens mutex_exit(&dd->dd_lock); 170fa9e4066Sahrens 171fa9e4066Sahrens cbr->cbr_func(cbr->cbr_arg, value); 172fa9e4066Sahrens 173*bb0ade09Sahrens VERIFY(0 == dsl_dir_open_obj(dp, dd->dd_object, 174ea8dc4b6Seschrock NULL, cbr, &dd)); 1751d452cf5Sahrens if (need_rwlock) 176*bb0ade09Sahrens rw_exit(&dp->dp_config_rwlock); 177*bb0ade09Sahrens /* Leave dir open until this callback is unregistered */ 178fa9e4066Sahrens return (0); 179fa9e4066Sahrens } 180fa9e4066Sahrens 181fa9e4066Sahrens int 182*bb0ade09Sahrens dsl_prop_get(const char *dsname, const char *propname, 183fa9e4066Sahrens int intsz, int numints, void *buf, char *setpoint) 184fa9e4066Sahrens { 185*bb0ade09Sahrens dsl_dataset_t *ds; 186fa9e4066Sahrens int err; 187fa9e4066Sahrens 188*bb0ade09Sahrens err = dsl_dataset_hold(dsname, FTAG, &ds); 189ea8dc4b6Seschrock if (err) 190ea8dc4b6Seschrock return (err); 191fa9e4066Sahrens 192*bb0ade09Sahrens rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); 193*bb0ade09Sahrens err = dsl_prop_get_ds(ds, propname, intsz, numints, buf, setpoint); 194*bb0ade09Sahrens rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 195fa9e4066Sahrens 196*bb0ade09Sahrens dsl_dataset_rele(ds, FTAG); 197fa9e4066Sahrens return (err); 198fa9e4066Sahrens } 199fa9e4066Sahrens 200fa9e4066Sahrens /* 201fa9e4066Sahrens * Get the current property value. It may have changed by the time this 202fa9e4066Sahrens * function returns, so it is NOT safe to follow up with 203fa9e4066Sahrens * dsl_prop_register() and assume that the value has not changed in 204fa9e4066Sahrens * between. 205fa9e4066Sahrens * 206fa9e4066Sahrens * Return 0 on success, ENOENT if ddname is invalid. 207fa9e4066Sahrens */ 208fa9e4066Sahrens int 209fa9e4066Sahrens dsl_prop_get_integer(const char *ddname, const char *propname, 210fa9e4066Sahrens uint64_t *valuep, char *setpoint) 211fa9e4066Sahrens { 212fa9e4066Sahrens return (dsl_prop_get(ddname, propname, 8, 1, valuep, setpoint)); 213fa9e4066Sahrens } 214fa9e4066Sahrens 215fa9e4066Sahrens /* 216fa9e4066Sahrens * Unregister this callback. Return 0 on success, ENOENT if ddname is 217fa9e4066Sahrens * invalid, ENOMSG if no matching callback registered. 218fa9e4066Sahrens */ 219fa9e4066Sahrens int 220fa9e4066Sahrens dsl_prop_unregister(dsl_dataset_t *ds, const char *propname, 221fa9e4066Sahrens dsl_prop_changed_cb_t *callback, void *cbarg) 222fa9e4066Sahrens { 22399653d4eSeschrock dsl_dir_t *dd = ds->ds_dir; 224fa9e4066Sahrens dsl_prop_cb_record_t *cbr; 225fa9e4066Sahrens 226fa9e4066Sahrens mutex_enter(&dd->dd_lock); 227fa9e4066Sahrens for (cbr = list_head(&dd->dd_prop_cbs); 228fa9e4066Sahrens cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { 22999653d4eSeschrock if (cbr->cbr_ds == ds && 230fa9e4066Sahrens cbr->cbr_func == callback && 23199653d4eSeschrock cbr->cbr_arg == cbarg && 23299653d4eSeschrock strcmp(cbr->cbr_propname, propname) == 0) 233fa9e4066Sahrens break; 234fa9e4066Sahrens } 235fa9e4066Sahrens 236fa9e4066Sahrens if (cbr == NULL) { 237fa9e4066Sahrens mutex_exit(&dd->dd_lock); 238fa9e4066Sahrens return (ENOMSG); 239fa9e4066Sahrens } 240fa9e4066Sahrens 241fa9e4066Sahrens list_remove(&dd->dd_prop_cbs, cbr); 242fa9e4066Sahrens mutex_exit(&dd->dd_lock); 243fa9e4066Sahrens kmem_free((void*)cbr->cbr_propname, strlen(cbr->cbr_propname)+1); 244fa9e4066Sahrens kmem_free(cbr, sizeof (dsl_prop_cb_record_t)); 245fa9e4066Sahrens 246fa9e4066Sahrens /* Clean up from dsl_prop_register */ 247fa9e4066Sahrens dsl_dir_close(dd, cbr); 248fa9e4066Sahrens return (0); 249fa9e4066Sahrens } 250fa9e4066Sahrens 25199653d4eSeschrock /* 25299653d4eSeschrock * Return the number of callbacks that are registered for this dataset. 25399653d4eSeschrock */ 25499653d4eSeschrock int 25599653d4eSeschrock dsl_prop_numcb(dsl_dataset_t *ds) 25699653d4eSeschrock { 25799653d4eSeschrock dsl_dir_t *dd = ds->ds_dir; 25899653d4eSeschrock dsl_prop_cb_record_t *cbr; 25999653d4eSeschrock int num = 0; 26099653d4eSeschrock 26199653d4eSeschrock mutex_enter(&dd->dd_lock); 26299653d4eSeschrock for (cbr = list_head(&dd->dd_prop_cbs); 26399653d4eSeschrock cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { 26499653d4eSeschrock if (cbr->cbr_ds == ds) 26599653d4eSeschrock num++; 26699653d4eSeschrock } 26799653d4eSeschrock mutex_exit(&dd->dd_lock); 26899653d4eSeschrock 26999653d4eSeschrock return (num); 27099653d4eSeschrock } 27199653d4eSeschrock 272fa9e4066Sahrens static void 273fa9e4066Sahrens dsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj, 274fa9e4066Sahrens const char *propname, uint64_t value, int first) 275fa9e4066Sahrens { 276fa9e4066Sahrens dsl_dir_t *dd; 277fa9e4066Sahrens dsl_prop_cb_record_t *cbr; 278fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 2791d452cf5Sahrens zap_cursor_t zc; 280d8d77200Sahrens zap_attribute_t *za; 281fa9e4066Sahrens int err; 282*bb0ade09Sahrens uint64_t dummyval; 283fa9e4066Sahrens 284fa9e4066Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 285ea8dc4b6Seschrock err = dsl_dir_open_obj(dp, ddobj, NULL, FTAG, &dd); 286ea8dc4b6Seschrock if (err) 287ea8dc4b6Seschrock return; 288fa9e4066Sahrens 289fa9e4066Sahrens if (!first) { 290fa9e4066Sahrens /* 291fa9e4066Sahrens * If the prop is set here, then this change is not 292fa9e4066Sahrens * being inherited here or below; stop the recursion. 293fa9e4066Sahrens */ 294fa9e4066Sahrens err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj, propname, 295*bb0ade09Sahrens 8, 1, &dummyval); 296fa9e4066Sahrens if (err == 0) { 297fa9e4066Sahrens dsl_dir_close(dd, FTAG); 298fa9e4066Sahrens return; 299fa9e4066Sahrens } 300fa9e4066Sahrens ASSERT3U(err, ==, ENOENT); 301fa9e4066Sahrens } 302fa9e4066Sahrens 303fa9e4066Sahrens mutex_enter(&dd->dd_lock); 304*bb0ade09Sahrens for (cbr = list_head(&dd->dd_prop_cbs); cbr; 305*bb0ade09Sahrens cbr = list_next(&dd->dd_prop_cbs, cbr)) { 306*bb0ade09Sahrens uint64_t propobj = cbr->cbr_ds->ds_phys->ds_props_obj; 307*bb0ade09Sahrens 308*bb0ade09Sahrens if (strcmp(cbr->cbr_propname, propname) != 0) 309*bb0ade09Sahrens continue; 310*bb0ade09Sahrens 311*bb0ade09Sahrens /* 312*bb0ade09Sahrens * If the property is set on this ds, then it is not 313*bb0ade09Sahrens * inherited here; don't call the callback. 314*bb0ade09Sahrens */ 315*bb0ade09Sahrens if (propobj && 0 == zap_lookup(mos, propobj, propname, 316*bb0ade09Sahrens 8, 1, &dummyval)) 317*bb0ade09Sahrens continue; 318*bb0ade09Sahrens 319*bb0ade09Sahrens cbr->cbr_func(cbr->cbr_arg, value); 320fa9e4066Sahrens } 321fa9e4066Sahrens mutex_exit(&dd->dd_lock); 322fa9e4066Sahrens 323d8d77200Sahrens za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP); 3241d452cf5Sahrens for (zap_cursor_init(&zc, mos, 3251d452cf5Sahrens dd->dd_phys->dd_child_dir_zapobj); 326d8d77200Sahrens zap_cursor_retrieve(&zc, za) == 0; 3271d452cf5Sahrens zap_cursor_advance(&zc)) { 328d8d77200Sahrens dsl_prop_changed_notify(dp, za->za_first_integer, 3291d452cf5Sahrens propname, value, FALSE); 330fa9e4066Sahrens } 331d8d77200Sahrens kmem_free(za, sizeof (zap_attribute_t)); 3321d452cf5Sahrens zap_cursor_fini(&zc); 333fa9e4066Sahrens dsl_dir_close(dd, FTAG); 334fa9e4066Sahrens } 335fa9e4066Sahrens 336fa9e4066Sahrens struct prop_set_arg { 337fa9e4066Sahrens const char *name; 338fa9e4066Sahrens int intsz; 339fa9e4066Sahrens int numints; 340fa9e4066Sahrens const void *buf; 341fa9e4066Sahrens }; 342fa9e4066Sahrens 3431d452cf5Sahrens 3441d452cf5Sahrens static void 345ecd6cf80Smarks dsl_prop_set_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 346fa9e4066Sahrens { 347*bb0ade09Sahrens dsl_dataset_t *ds = arg1; 3481d452cf5Sahrens struct prop_set_arg *psa = arg2; 349*bb0ade09Sahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 350*bb0ade09Sahrens uint64_t zapobj, intval; 3511d452cf5Sahrens int isint; 352ecd6cf80Smarks char valbuf[32]; 353ecd6cf80Smarks char *valstr; 354fa9e4066Sahrens 355fa9e4066Sahrens isint = (dodefault(psa->name, 8, 1, &intval) == 0); 356fa9e4066Sahrens 357*bb0ade09Sahrens if (dsl_dataset_is_snapshot(ds)) { 358*bb0ade09Sahrens ASSERT(spa_version(ds->ds_dir->dd_pool->dp_spa) >= 359*bb0ade09Sahrens SPA_VERSION_SNAP_PROPS); 360*bb0ade09Sahrens if (ds->ds_phys->ds_props_obj == 0) { 361*bb0ade09Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 362*bb0ade09Sahrens ds->ds_phys->ds_props_obj = 363*bb0ade09Sahrens zap_create(mos, 364*bb0ade09Sahrens DMU_OT_DSL_PROPS, DMU_OT_NONE, 0, tx); 365*bb0ade09Sahrens } 366*bb0ade09Sahrens zapobj = ds->ds_phys->ds_props_obj; 367*bb0ade09Sahrens } else { 368*bb0ade09Sahrens zapobj = ds->ds_dir->dd_phys->dd_props_zapobj; 369*bb0ade09Sahrens } 370*bb0ade09Sahrens 371fa9e4066Sahrens if (psa->numints == 0) { 3721d452cf5Sahrens int err = zap_remove(mos, zapobj, psa->name, tx); 3731d452cf5Sahrens ASSERT(err == 0 || err == ENOENT); 3741d452cf5Sahrens if (isint) { 375*bb0ade09Sahrens VERIFY(0 == dsl_prop_get_ds(ds, 3761d452cf5Sahrens psa->name, 8, 1, &intval, NULL)); 377fa9e4066Sahrens } 378fa9e4066Sahrens } else { 3791d452cf5Sahrens VERIFY(0 == zap_update(mos, zapobj, psa->name, 3801d452cf5Sahrens psa->intsz, psa->numints, psa->buf, tx)); 381fa9e4066Sahrens if (isint) 382fa9e4066Sahrens intval = *(uint64_t *)psa->buf; 383fa9e4066Sahrens } 384fa9e4066Sahrens 3851d452cf5Sahrens if (isint) { 386*bb0ade09Sahrens if (dsl_dataset_is_snapshot(ds)) { 387*bb0ade09Sahrens dsl_prop_cb_record_t *cbr; 388*bb0ade09Sahrens /* 389*bb0ade09Sahrens * It's a snapshot; nothing can inherit this 390*bb0ade09Sahrens * property, so just look for callbacks on this 391*bb0ade09Sahrens * ds here. 392*bb0ade09Sahrens */ 393*bb0ade09Sahrens mutex_enter(&ds->ds_dir->dd_lock); 394*bb0ade09Sahrens for (cbr = list_head(&ds->ds_dir->dd_prop_cbs); cbr; 395*bb0ade09Sahrens cbr = list_next(&ds->ds_dir->dd_prop_cbs, cbr)) { 396*bb0ade09Sahrens if (cbr->cbr_ds == ds && 397*bb0ade09Sahrens strcmp(cbr->cbr_propname, psa->name) == 0) 398*bb0ade09Sahrens cbr->cbr_func(cbr->cbr_arg, intval); 399*bb0ade09Sahrens } 400*bb0ade09Sahrens mutex_exit(&ds->ds_dir->dd_lock); 401*bb0ade09Sahrens } else { 402*bb0ade09Sahrens dsl_prop_changed_notify(ds->ds_dir->dd_pool, 403*bb0ade09Sahrens ds->ds_dir->dd_object, psa->name, intval, TRUE); 404*bb0ade09Sahrens } 405fa9e4066Sahrens } 406ecd6cf80Smarks if (isint) { 407ecd6cf80Smarks (void) snprintf(valbuf, sizeof (valbuf), 408ecd6cf80Smarks "%lld", (longlong_t)intval); 409ecd6cf80Smarks valstr = valbuf; 410ecd6cf80Smarks } else { 411ecd6cf80Smarks valstr = (char *)psa->buf; 412ecd6cf80Smarks } 413ecd6cf80Smarks spa_history_internal_log((psa->numints == 0) ? LOG_DS_INHERIT : 414*bb0ade09Sahrens LOG_DS_PROPSET, ds->ds_dir->dd_pool->dp_spa, tx, cr, 415*bb0ade09Sahrens "%s=%s dataset = %llu", psa->name, valstr, ds->ds_object); 416fa9e4066Sahrens } 417fa9e4066Sahrens 418a9799022Sck void 419a9799022Sck dsl_prop_set_uint64_sync(dsl_dir_t *dd, const char *name, uint64_t val, 420a9799022Sck cred_t *cr, dmu_tx_t *tx) 421a9799022Sck { 422a9799022Sck objset_t *mos = dd->dd_pool->dp_meta_objset; 423a9799022Sck uint64_t zapobj = dd->dd_phys->dd_props_zapobj; 424a9799022Sck 425a9799022Sck ASSERT(dmu_tx_is_syncing(tx)); 426a9799022Sck 427a9799022Sck VERIFY(0 == zap_update(mos, zapobj, name, sizeof (val), 1, &val, tx)); 428a9799022Sck 429a9799022Sck dsl_prop_changed_notify(dd->dd_pool, dd->dd_object, name, val, TRUE); 430a9799022Sck 431a9799022Sck spa_history_internal_log(LOG_DS_PROPSET, dd->dd_pool->dp_spa, tx, cr, 432a9799022Sck "%s=%llu dataset = %llu", name, (u_longlong_t)val, 433a9799022Sck dd->dd_phys->dd_head_dataset_obj); 434a9799022Sck } 435a9799022Sck 436a2eea2e1Sahrens int 437*bb0ade09Sahrens dsl_prop_set(const char *dsname, const char *propname, 438fa9e4066Sahrens int intsz, int numints, const void *buf) 439fa9e4066Sahrens { 440*bb0ade09Sahrens dsl_dataset_t *ds; 441fa9e4066Sahrens int err; 442*bb0ade09Sahrens struct prop_set_arg psa; 443fa9e4066Sahrens 444455d5089Sahrens /* 445455d5089Sahrens * We must do these checks before we get to the syncfunc, since 446455d5089Sahrens * it can't fail. 447455d5089Sahrens */ 448455d5089Sahrens if (strlen(propname) >= ZAP_MAXNAMELEN) 449455d5089Sahrens return (ENAMETOOLONG); 450455d5089Sahrens if (intsz * numints >= ZAP_MAXVALUELEN) 451455d5089Sahrens return (E2BIG); 452455d5089Sahrens 453*bb0ade09Sahrens err = dsl_dataset_hold(dsname, FTAG, &ds); 454ea8dc4b6Seschrock if (err) 455ea8dc4b6Seschrock return (err); 456*bb0ade09Sahrens 457*bb0ade09Sahrens if (dsl_dataset_is_snapshot(ds) && 458*bb0ade09Sahrens spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_SNAP_PROPS) { 459*bb0ade09Sahrens dsl_dataset_rele(ds, FTAG); 460*bb0ade09Sahrens return (ENOTSUP); 461*bb0ade09Sahrens } 462*bb0ade09Sahrens 463*bb0ade09Sahrens psa.name = propname; 464*bb0ade09Sahrens psa.intsz = intsz; 465*bb0ade09Sahrens psa.numints = numints; 466*bb0ade09Sahrens psa.buf = buf; 467*bb0ade09Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 468*bb0ade09Sahrens NULL, dsl_prop_set_sync, ds, &psa, 2); 469*bb0ade09Sahrens 470*bb0ade09Sahrens dsl_dataset_rele(ds, FTAG); 471fa9e4066Sahrens return (err); 472fa9e4066Sahrens } 4737f7322feSeschrock 4747f7322feSeschrock /* 4757f7322feSeschrock * Iterate over all properties for this dataset and return them in an nvlist. 4767f7322feSeschrock */ 4777f7322feSeschrock int 478745cd3c5Smaybee dsl_prop_get_all(objset_t *os, nvlist_t **nvp, boolean_t local) 4797f7322feSeschrock { 4807f7322feSeschrock dsl_dataset_t *ds = os->os->os_dsl_dataset; 48199653d4eSeschrock dsl_dir_t *dd = ds->ds_dir; 482*bb0ade09Sahrens boolean_t snapshot = dsl_dataset_is_snapshot(ds); 4837f7322feSeschrock int err = 0; 484*bb0ade09Sahrens dsl_pool_t *dp = dd->dd_pool; 485*bb0ade09Sahrens objset_t *mos = dp->dp_meta_objset; 486*bb0ade09Sahrens uint64_t propobj = ds->ds_phys->ds_props_obj; 4877f7322feSeschrock 4887f7322feSeschrock VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); 4897f7322feSeschrock 490*bb0ade09Sahrens if (local && snapshot && !propobj) 491*bb0ade09Sahrens return (0); 4927f7322feSeschrock 4937f7322feSeschrock rw_enter(&dp->dp_config_rwlock, RW_READER); 494*bb0ade09Sahrens while (dd != NULL) { 495a2eea2e1Sahrens char setpoint[MAXNAMELEN]; 496a2eea2e1Sahrens zap_cursor_t zc; 497a2eea2e1Sahrens zap_attribute_t za; 498*bb0ade09Sahrens dsl_dir_t *dd_next; 499*bb0ade09Sahrens 500*bb0ade09Sahrens if (propobj) { 501*bb0ade09Sahrens dsl_dataset_name(ds, setpoint); 502*bb0ade09Sahrens dd_next = dd; 503*bb0ade09Sahrens } else { 504*bb0ade09Sahrens dsl_dir_name(dd, setpoint); 505*bb0ade09Sahrens propobj = dd->dd_phys->dd_props_zapobj; 506*bb0ade09Sahrens dd_next = dd->dd_parent; 507*bb0ade09Sahrens } 508a2eea2e1Sahrens 509*bb0ade09Sahrens for (zap_cursor_init(&zc, mos, propobj); 5107f7322feSeschrock (err = zap_cursor_retrieve(&zc, &za)) == 0; 5117f7322feSeschrock zap_cursor_advance(&zc)) { 512a2eea2e1Sahrens nvlist_t *propval; 513*bb0ade09Sahrens zfs_prop_t prop = zfs_name_to_prop(za.za_name); 514*bb0ade09Sahrens 515*bb0ade09Sahrens /* Skip non-inheritable properties. */ 516*bb0ade09Sahrens if (prop != ZPROP_INVAL && 517*bb0ade09Sahrens !zfs_prop_inheritable(prop) && 518*bb0ade09Sahrens (dd != ds->ds_dir || (snapshot && dd != dd_next))) 519e9dbad6fSeschrock continue; 520e9dbad6fSeschrock 521*bb0ade09Sahrens /* Skip properties not valid for this type. */ 522*bb0ade09Sahrens if (snapshot && prop != ZPROP_INVAL && 523da6c28aaSamw !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT)) 524da6c28aaSamw continue; 525da6c28aaSamw 526*bb0ade09Sahrens /* Skip properties already defined */ 527e9dbad6fSeschrock if (nvlist_lookup_nvlist(*nvp, za.za_name, 528e9dbad6fSeschrock &propval) == 0) 5297f7322feSeschrock continue; 5307f7322feSeschrock 531e9dbad6fSeschrock VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, 5327f7322feSeschrock KM_SLEEP) == 0); 5337f7322feSeschrock if (za.za_integer_length == 1) { 5347f7322feSeschrock /* 5357f7322feSeschrock * String property 5367f7322feSeschrock */ 537a2eea2e1Sahrens char *tmp = kmem_alloc(za.za_num_integers, 538a2eea2e1Sahrens KM_SLEEP); 539*bb0ade09Sahrens err = zap_lookup(mos, propobj, 540*bb0ade09Sahrens za.za_name, 1, za.za_num_integers, tmp); 5417f7322feSeschrock if (err != 0) { 5427f7322feSeschrock kmem_free(tmp, za.za_num_integers); 5437f7322feSeschrock break; 5447f7322feSeschrock } 545990b4856Slling VERIFY(nvlist_add_string(propval, ZPROP_VALUE, 546990b4856Slling tmp) == 0); 5477f7322feSeschrock kmem_free(tmp, za.za_num_integers); 5487f7322feSeschrock } else { 5497f7322feSeschrock /* 5507f7322feSeschrock * Integer property 5517f7322feSeschrock */ 5527f7322feSeschrock ASSERT(za.za_integer_length == 8); 553990b4856Slling (void) nvlist_add_uint64(propval, ZPROP_VALUE, 554990b4856Slling za.za_first_integer); 5557f7322feSeschrock } 5567f7322feSeschrock 557990b4856Slling VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, 558990b4856Slling setpoint) == 0); 5597f7322feSeschrock VERIFY(nvlist_add_nvlist(*nvp, za.za_name, 560e9dbad6fSeschrock propval) == 0); 561e9dbad6fSeschrock nvlist_free(propval); 5627f7322feSeschrock } 5637f7322feSeschrock zap_cursor_fini(&zc); 5647f7322feSeschrock 56599653d4eSeschrock if (err != ENOENT) 5667f7322feSeschrock break; 56799653d4eSeschrock err = 0; 568745cd3c5Smaybee /* 569745cd3c5Smaybee * If we are just after the props that have been set 570745cd3c5Smaybee * locally, then we are done after the first iteration. 571745cd3c5Smaybee */ 572745cd3c5Smaybee if (local) 573745cd3c5Smaybee break; 574*bb0ade09Sahrens dd = dd_next; 575*bb0ade09Sahrens propobj = 0; 5767f7322feSeschrock } 5777f7322feSeschrock rw_exit(&dp->dp_config_rwlock); 5787f7322feSeschrock 5797f7322feSeschrock return (err); 5807f7322feSeschrock } 581a2eea2e1Sahrens 582a2eea2e1Sahrens void 583a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nvlist_t *nv, zfs_prop_t prop, uint64_t value) 584a2eea2e1Sahrens { 585a2eea2e1Sahrens nvlist_t *propval; 586a2eea2e1Sahrens 587a2eea2e1Sahrens VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 588990b4856Slling VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0); 589a2eea2e1Sahrens VERIFY(nvlist_add_nvlist(nv, zfs_prop_to_name(prop), propval) == 0); 590a2eea2e1Sahrens nvlist_free(propval); 591a2eea2e1Sahrens } 592a2eea2e1Sahrens 593a2eea2e1Sahrens void 594a2eea2e1Sahrens dsl_prop_nvlist_add_string(nvlist_t *nv, zfs_prop_t prop, const char *value) 595a2eea2e1Sahrens { 596a2eea2e1Sahrens nvlist_t *propval; 597a2eea2e1Sahrens 598a2eea2e1Sahrens VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 599990b4856Slling VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0); 600a2eea2e1Sahrens VERIFY(nvlist_add_nvlist(nv, zfs_prop_to_name(prop), propval) == 0); 601a2eea2e1Sahrens nvlist_free(propval); 602a2eea2e1Sahrens } 603