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 /* 22ecd6cf80Smarks * Copyright 2007 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 47*990b4856Slling if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL || 48fa9e4066Sahrens zfs_prop_readonly(prop)) 49fa9e4066Sahrens return (ENOENT); 50fa9e4066Sahrens 5191ebeef5Sahrens if (zfs_prop_get_type(prop) == PROP_TYPE_STRING) { 52fa9e4066Sahrens if (intsz != 1) 53fa9e4066Sahrens return (EOVERFLOW); 54*990b4856Slling (void) strncpy(buf, zfs_prop_default_string(prop), 55*990b4856Slling numint); 56fa9e4066Sahrens } else { 57fa9e4066Sahrens if (intsz != 8 || numint < 1) 58fa9e4066Sahrens return (EOVERFLOW); 59fa9e4066Sahrens 60fa9e4066Sahrens *(uint64_t *)buf = zfs_prop_default_numeric(prop); 61fa9e4066Sahrens } 62fa9e4066Sahrens 63fa9e4066Sahrens return (0); 64fa9e4066Sahrens } 65fa9e4066Sahrens 66fa9e4066Sahrens static int 6799653d4eSeschrock dsl_prop_get_impl(dsl_dir_t *dd, const char *propname, 68fa9e4066Sahrens int intsz, int numint, void *buf, char *setpoint) 69fa9e4066Sahrens { 7099653d4eSeschrock int err = ENOENT; 71e9dbad6fSeschrock zfs_prop_t prop; 72fa9e4066Sahrens 73fa9e4066Sahrens if (setpoint) 74fa9e4066Sahrens setpoint[0] = '\0'; 75fa9e4066Sahrens 76e9dbad6fSeschrock prop = zfs_name_to_prop(propname); 77e9dbad6fSeschrock 7899653d4eSeschrock /* 7999653d4eSeschrock * Note: dd may be NULL, therefore we shouldn't dereference it 8099653d4eSeschrock * ouside this loop. 8199653d4eSeschrock */ 8299653d4eSeschrock for (; dd != NULL; dd = dd->dd_parent) { 8399653d4eSeschrock objset_t *mos = dd->dd_pool->dp_meta_objset; 8499653d4eSeschrock ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock)); 85fa9e4066Sahrens err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj, 86fa9e4066Sahrens propname, intsz, numint, buf); 87fa9e4066Sahrens if (err != ENOENT) { 88fa9e4066Sahrens if (setpoint) 89fa9e4066Sahrens dsl_dir_name(dd, setpoint); 90fa9e4066Sahrens break; 91fa9e4066Sahrens } 92e9dbad6fSeschrock 93e9dbad6fSeschrock /* 94e9dbad6fSeschrock * Break out of this loop for non-inheritable properties. 95e9dbad6fSeschrock */ 96*990b4856Slling if (prop != ZPROP_INVAL && 97e9dbad6fSeschrock !zfs_prop_inheritable(prop)) 98e9dbad6fSeschrock break; 99fa9e4066Sahrens } 100fa9e4066Sahrens if (err == ENOENT) 101fa9e4066Sahrens err = dodefault(propname, intsz, numint, buf); 102fa9e4066Sahrens 103fa9e4066Sahrens return (err); 104fa9e4066Sahrens } 105fa9e4066Sahrens 106fa9e4066Sahrens /* 107fa9e4066Sahrens * Register interest in the named property. We'll call the callback 108fa9e4066Sahrens * once to notify it of the current property value, and again each time 109fa9e4066Sahrens * the property changes, until this callback is unregistered. 110fa9e4066Sahrens * 111fa9e4066Sahrens * Return 0 on success, errno if the prop is not an integer value. 112fa9e4066Sahrens */ 113fa9e4066Sahrens int 114fa9e4066Sahrens dsl_prop_register(dsl_dataset_t *ds, const char *propname, 115fa9e4066Sahrens dsl_prop_changed_cb_t *callback, void *cbarg) 116fa9e4066Sahrens { 11799653d4eSeschrock dsl_dir_t *dd = ds->ds_dir; 118fa9e4066Sahrens uint64_t value; 119fa9e4066Sahrens dsl_prop_cb_record_t *cbr; 120fa9e4066Sahrens int err; 1211d452cf5Sahrens int need_rwlock; 122fa9e4066Sahrens 1231d452cf5Sahrens need_rwlock = !RW_WRITE_HELD(&dd->dd_pool->dp_config_rwlock); 1241d452cf5Sahrens if (need_rwlock) 1251d452cf5Sahrens rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 126fa9e4066Sahrens 12799653d4eSeschrock err = dsl_prop_get_impl(dd, propname, 8, 1, &value, NULL); 128fa9e4066Sahrens if (err != 0) { 129fa9e4066Sahrens rw_exit(&dd->dd_pool->dp_config_rwlock); 130fa9e4066Sahrens return (err); 131fa9e4066Sahrens } 132fa9e4066Sahrens 133fa9e4066Sahrens cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP); 13499653d4eSeschrock cbr->cbr_ds = ds; 135fa9e4066Sahrens cbr->cbr_propname = kmem_alloc(strlen(propname)+1, KM_SLEEP); 136fa9e4066Sahrens (void) strcpy((char *)cbr->cbr_propname, propname); 137fa9e4066Sahrens cbr->cbr_func = callback; 138fa9e4066Sahrens cbr->cbr_arg = cbarg; 139fa9e4066Sahrens mutex_enter(&dd->dd_lock); 140fa9e4066Sahrens list_insert_head(&dd->dd_prop_cbs, cbr); 141fa9e4066Sahrens mutex_exit(&dd->dd_lock); 142fa9e4066Sahrens 143fa9e4066Sahrens cbr->cbr_func(cbr->cbr_arg, value); 144fa9e4066Sahrens 145ea8dc4b6Seschrock VERIFY(0 == dsl_dir_open_obj(dd->dd_pool, dd->dd_object, 146ea8dc4b6Seschrock NULL, cbr, &dd)); 1471d452cf5Sahrens if (need_rwlock) 1481d452cf5Sahrens rw_exit(&dd->dd_pool->dp_config_rwlock); 149fa9e4066Sahrens /* Leave dataset open until this callback is unregistered */ 150fa9e4066Sahrens return (0); 151fa9e4066Sahrens } 152fa9e4066Sahrens 153fa9e4066Sahrens int 154fa9e4066Sahrens dsl_prop_get_ds(dsl_dir_t *dd, const char *propname, 155fa9e4066Sahrens int intsz, int numints, void *buf, char *setpoint) 156fa9e4066Sahrens { 157fa9e4066Sahrens int err; 158fa9e4066Sahrens 159fa9e4066Sahrens rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 16099653d4eSeschrock err = dsl_prop_get_impl(dd, propname, intsz, numints, buf, setpoint); 161fa9e4066Sahrens rw_exit(&dd->dd_pool->dp_config_rwlock); 162fa9e4066Sahrens 163fa9e4066Sahrens return (err); 164fa9e4066Sahrens } 165fa9e4066Sahrens 166ecd6cf80Smarks /* 167ecd6cf80Smarks * Get property when config lock is already held. 168ecd6cf80Smarks */ 169ecd6cf80Smarks int dsl_prop_get_ds_locked(dsl_dir_t *dd, const char *propname, 170ecd6cf80Smarks int intsz, int numints, void *buf, char *setpoint) 171ecd6cf80Smarks { 172ecd6cf80Smarks ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock)); 173ecd6cf80Smarks return (dsl_prop_get_impl(dd, propname, intsz, numints, buf, setpoint)); 174ecd6cf80Smarks } 175ecd6cf80Smarks 176fa9e4066Sahrens int 177fa9e4066Sahrens dsl_prop_get(const char *ddname, const char *propname, 178fa9e4066Sahrens int intsz, int numints, void *buf, char *setpoint) 179fa9e4066Sahrens { 180fa9e4066Sahrens dsl_dir_t *dd; 181fa9e4066Sahrens const char *tail; 182fa9e4066Sahrens int err; 183fa9e4066Sahrens 184ea8dc4b6Seschrock err = dsl_dir_open(ddname, FTAG, &dd, &tail); 185ea8dc4b6Seschrock if (err) 186ea8dc4b6Seschrock return (err); 187fa9e4066Sahrens if (tail && tail[0] != '@') { 188fa9e4066Sahrens dsl_dir_close(dd, FTAG); 189fa9e4066Sahrens return (ENOENT); 190fa9e4066Sahrens } 191fa9e4066Sahrens 192fa9e4066Sahrens err = dsl_prop_get_ds(dd, propname, intsz, numints, buf, setpoint); 193fa9e4066Sahrens 194fa9e4066Sahrens dsl_dir_close(dd, FTAG); 195fa9e4066Sahrens return (err); 196fa9e4066Sahrens } 197fa9e4066Sahrens 198fa9e4066Sahrens /* 199fa9e4066Sahrens * Get the current property value. It may have changed by the time this 200fa9e4066Sahrens * function returns, so it is NOT safe to follow up with 201fa9e4066Sahrens * dsl_prop_register() and assume that the value has not changed in 202fa9e4066Sahrens * between. 203fa9e4066Sahrens * 204fa9e4066Sahrens * Return 0 on success, ENOENT if ddname is invalid. 205fa9e4066Sahrens */ 206fa9e4066Sahrens int 207fa9e4066Sahrens dsl_prop_get_integer(const char *ddname, const char *propname, 208fa9e4066Sahrens uint64_t *valuep, char *setpoint) 209fa9e4066Sahrens { 210fa9e4066Sahrens return (dsl_prop_get(ddname, propname, 8, 1, valuep, setpoint)); 211fa9e4066Sahrens } 212fa9e4066Sahrens 213fa9e4066Sahrens /* 214fa9e4066Sahrens * Unregister this callback. Return 0 on success, ENOENT if ddname is 215fa9e4066Sahrens * invalid, ENOMSG if no matching callback registered. 216fa9e4066Sahrens */ 217fa9e4066Sahrens int 218fa9e4066Sahrens dsl_prop_unregister(dsl_dataset_t *ds, const char *propname, 219fa9e4066Sahrens dsl_prop_changed_cb_t *callback, void *cbarg) 220fa9e4066Sahrens { 22199653d4eSeschrock dsl_dir_t *dd = ds->ds_dir; 222fa9e4066Sahrens dsl_prop_cb_record_t *cbr; 223fa9e4066Sahrens 224fa9e4066Sahrens mutex_enter(&dd->dd_lock); 225fa9e4066Sahrens for (cbr = list_head(&dd->dd_prop_cbs); 226fa9e4066Sahrens cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { 22799653d4eSeschrock if (cbr->cbr_ds == ds && 228fa9e4066Sahrens cbr->cbr_func == callback && 22999653d4eSeschrock cbr->cbr_arg == cbarg && 23099653d4eSeschrock strcmp(cbr->cbr_propname, propname) == 0) 231fa9e4066Sahrens break; 232fa9e4066Sahrens } 233fa9e4066Sahrens 234fa9e4066Sahrens if (cbr == NULL) { 235fa9e4066Sahrens mutex_exit(&dd->dd_lock); 236fa9e4066Sahrens return (ENOMSG); 237fa9e4066Sahrens } 238fa9e4066Sahrens 239fa9e4066Sahrens list_remove(&dd->dd_prop_cbs, cbr); 240fa9e4066Sahrens mutex_exit(&dd->dd_lock); 241fa9e4066Sahrens kmem_free((void*)cbr->cbr_propname, strlen(cbr->cbr_propname)+1); 242fa9e4066Sahrens kmem_free(cbr, sizeof (dsl_prop_cb_record_t)); 243fa9e4066Sahrens 244fa9e4066Sahrens /* Clean up from dsl_prop_register */ 245fa9e4066Sahrens dsl_dir_close(dd, cbr); 246fa9e4066Sahrens return (0); 247fa9e4066Sahrens } 248fa9e4066Sahrens 24999653d4eSeschrock /* 25099653d4eSeschrock * Return the number of callbacks that are registered for this dataset. 25199653d4eSeschrock */ 25299653d4eSeschrock int 25399653d4eSeschrock dsl_prop_numcb(dsl_dataset_t *ds) 25499653d4eSeschrock { 25599653d4eSeschrock dsl_dir_t *dd = ds->ds_dir; 25699653d4eSeschrock dsl_prop_cb_record_t *cbr; 25799653d4eSeschrock int num = 0; 25899653d4eSeschrock 25999653d4eSeschrock mutex_enter(&dd->dd_lock); 26099653d4eSeschrock for (cbr = list_head(&dd->dd_prop_cbs); 26199653d4eSeschrock cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { 26299653d4eSeschrock if (cbr->cbr_ds == ds) 26399653d4eSeschrock num++; 26499653d4eSeschrock } 26599653d4eSeschrock mutex_exit(&dd->dd_lock); 26699653d4eSeschrock 26799653d4eSeschrock return (num); 26899653d4eSeschrock } 26999653d4eSeschrock 270fa9e4066Sahrens static void 271fa9e4066Sahrens dsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj, 272fa9e4066Sahrens const char *propname, uint64_t value, int first) 273fa9e4066Sahrens { 274fa9e4066Sahrens dsl_dir_t *dd; 275fa9e4066Sahrens dsl_prop_cb_record_t *cbr; 276fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 2771d452cf5Sahrens zap_cursor_t zc; 2781d452cf5Sahrens zap_attribute_t za; 279fa9e4066Sahrens int err; 280fa9e4066Sahrens 281fa9e4066Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 282ea8dc4b6Seschrock err = dsl_dir_open_obj(dp, ddobj, NULL, FTAG, &dd); 283ea8dc4b6Seschrock if (err) 284ea8dc4b6Seschrock return; 285fa9e4066Sahrens 286fa9e4066Sahrens if (!first) { 287fa9e4066Sahrens /* 288fa9e4066Sahrens * If the prop is set here, then this change is not 289fa9e4066Sahrens * being inherited here or below; stop the recursion. 290fa9e4066Sahrens */ 291fa9e4066Sahrens err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj, propname, 292fa9e4066Sahrens 8, 1, &value); 293fa9e4066Sahrens if (err == 0) { 294fa9e4066Sahrens dsl_dir_close(dd, FTAG); 295fa9e4066Sahrens return; 296fa9e4066Sahrens } 297fa9e4066Sahrens ASSERT3U(err, ==, ENOENT); 298fa9e4066Sahrens } 299fa9e4066Sahrens 300fa9e4066Sahrens mutex_enter(&dd->dd_lock); 301fa9e4066Sahrens for (cbr = list_head(&dd->dd_prop_cbs); 302fa9e4066Sahrens cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { 303fa9e4066Sahrens if (strcmp(cbr->cbr_propname, propname) == 0) { 304fa9e4066Sahrens cbr->cbr_func(cbr->cbr_arg, value); 305fa9e4066Sahrens } 306fa9e4066Sahrens } 307fa9e4066Sahrens mutex_exit(&dd->dd_lock); 308fa9e4066Sahrens 3091d452cf5Sahrens for (zap_cursor_init(&zc, mos, 3101d452cf5Sahrens dd->dd_phys->dd_child_dir_zapobj); 3111d452cf5Sahrens zap_cursor_retrieve(&zc, &za) == 0; 3121d452cf5Sahrens zap_cursor_advance(&zc)) { 3131d452cf5Sahrens /* XXX recursion could blow stack; esp. za! */ 3141d452cf5Sahrens dsl_prop_changed_notify(dp, za.za_first_integer, 3151d452cf5Sahrens propname, value, FALSE); 316fa9e4066Sahrens } 3171d452cf5Sahrens zap_cursor_fini(&zc); 318fa9e4066Sahrens dsl_dir_close(dd, FTAG); 319fa9e4066Sahrens } 320fa9e4066Sahrens 321fa9e4066Sahrens struct prop_set_arg { 322fa9e4066Sahrens const char *name; 323fa9e4066Sahrens int intsz; 324fa9e4066Sahrens int numints; 325fa9e4066Sahrens const void *buf; 326fa9e4066Sahrens }; 327fa9e4066Sahrens 3281d452cf5Sahrens 3291d452cf5Sahrens static void 330ecd6cf80Smarks dsl_prop_set_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 331fa9e4066Sahrens { 3321d452cf5Sahrens dsl_dir_t *dd = arg1; 3331d452cf5Sahrens struct prop_set_arg *psa = arg2; 334fa9e4066Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 335fa9e4066Sahrens uint64_t zapobj = dd->dd_phys->dd_props_zapobj; 336fa9e4066Sahrens uint64_t intval; 3371d452cf5Sahrens int isint; 338ecd6cf80Smarks char valbuf[32]; 339ecd6cf80Smarks char *valstr; 340fa9e4066Sahrens 341fa9e4066Sahrens isint = (dodefault(psa->name, 8, 1, &intval) == 0); 342fa9e4066Sahrens 343fa9e4066Sahrens if (psa->numints == 0) { 3441d452cf5Sahrens int err = zap_remove(mos, zapobj, psa->name, tx); 3451d452cf5Sahrens ASSERT(err == 0 || err == ENOENT); 3461d452cf5Sahrens if (isint) { 3471d452cf5Sahrens VERIFY(0 == dsl_prop_get_impl(dd->dd_parent, 3481d452cf5Sahrens psa->name, 8, 1, &intval, NULL)); 349fa9e4066Sahrens } 350fa9e4066Sahrens } else { 3511d452cf5Sahrens VERIFY(0 == zap_update(mos, zapobj, psa->name, 3521d452cf5Sahrens psa->intsz, psa->numints, psa->buf, tx)); 353fa9e4066Sahrens if (isint) 354fa9e4066Sahrens intval = *(uint64_t *)psa->buf; 355fa9e4066Sahrens } 356fa9e4066Sahrens 3571d452cf5Sahrens if (isint) { 358fa9e4066Sahrens dsl_prop_changed_notify(dd->dd_pool, 359fa9e4066Sahrens dd->dd_object, psa->name, intval, TRUE); 360fa9e4066Sahrens } 361ecd6cf80Smarks if (isint) { 362ecd6cf80Smarks (void) snprintf(valbuf, sizeof (valbuf), 363ecd6cf80Smarks "%lld", (longlong_t)intval); 364ecd6cf80Smarks valstr = valbuf; 365ecd6cf80Smarks } else { 366ecd6cf80Smarks valstr = (char *)psa->buf; 367ecd6cf80Smarks } 368ecd6cf80Smarks spa_history_internal_log((psa->numints == 0) ? LOG_DS_INHERIT : 369ecd6cf80Smarks LOG_DS_PROPSET, dd->dd_pool->dp_spa, tx, cr, 370ecd6cf80Smarks "%s=%s dataset = %llu", psa->name, valstr, 371ecd6cf80Smarks dd->dd_phys->dd_head_dataset_obj); 372fa9e4066Sahrens } 373fa9e4066Sahrens 374a2eea2e1Sahrens int 375a2eea2e1Sahrens dsl_prop_set_dd(dsl_dir_t *dd, const char *propname, 376a2eea2e1Sahrens int intsz, int numints, const void *buf) 377a2eea2e1Sahrens { 378a2eea2e1Sahrens struct prop_set_arg psa; 379a2eea2e1Sahrens 380a2eea2e1Sahrens psa.name = propname; 381a2eea2e1Sahrens psa.intsz = intsz; 382a2eea2e1Sahrens psa.numints = numints; 383a2eea2e1Sahrens psa.buf = buf; 384a2eea2e1Sahrens 385a2eea2e1Sahrens return (dsl_sync_task_do(dd->dd_pool, 386a2eea2e1Sahrens NULL, dsl_prop_set_sync, dd, &psa, 2)); 387a2eea2e1Sahrens } 388a2eea2e1Sahrens 389fa9e4066Sahrens int 390fa9e4066Sahrens dsl_prop_set(const char *ddname, const char *propname, 391fa9e4066Sahrens int intsz, int numints, const void *buf) 392fa9e4066Sahrens { 393fa9e4066Sahrens dsl_dir_t *dd; 394fa9e4066Sahrens int err; 395fa9e4066Sahrens 396455d5089Sahrens /* 397455d5089Sahrens * We must do these checks before we get to the syncfunc, since 398455d5089Sahrens * it can't fail. 399455d5089Sahrens */ 400455d5089Sahrens if (strlen(propname) >= ZAP_MAXNAMELEN) 401455d5089Sahrens return (ENAMETOOLONG); 402455d5089Sahrens if (intsz * numints >= ZAP_MAXVALUELEN) 403455d5089Sahrens return (E2BIG); 404455d5089Sahrens 405ea8dc4b6Seschrock err = dsl_dir_open(ddname, FTAG, &dd, NULL); 406ea8dc4b6Seschrock if (err) 407ea8dc4b6Seschrock return (err); 408a2eea2e1Sahrens err = dsl_prop_set_dd(dd, propname, intsz, numints, buf); 409fa9e4066Sahrens dsl_dir_close(dd, FTAG); 410fa9e4066Sahrens return (err); 411fa9e4066Sahrens } 4127f7322feSeschrock 4137f7322feSeschrock /* 4147f7322feSeschrock * Iterate over all properties for this dataset and return them in an nvlist. 4157f7322feSeschrock */ 4167f7322feSeschrock int 4177f7322feSeschrock dsl_prop_get_all(objset_t *os, nvlist_t **nvp) 4187f7322feSeschrock { 4197f7322feSeschrock dsl_dataset_t *ds = os->os->os_dsl_dataset; 42099653d4eSeschrock dsl_dir_t *dd = ds->ds_dir; 4217f7322feSeschrock int err = 0; 4227f7322feSeschrock dsl_pool_t *dp; 4237f7322feSeschrock objset_t *mos; 4247f7322feSeschrock 4257f7322feSeschrock if (dsl_dataset_is_snapshot(ds)) { 4267f7322feSeschrock VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); 4277f7322feSeschrock return (0); 4287f7322feSeschrock } 4297f7322feSeschrock 4307f7322feSeschrock VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); 4317f7322feSeschrock 4327f7322feSeschrock dp = dd->dd_pool; 4337f7322feSeschrock mos = dp->dp_meta_objset; 4347f7322feSeschrock 4357f7322feSeschrock rw_enter(&dp->dp_config_rwlock, RW_READER); 43699653d4eSeschrock for (; dd != NULL; dd = dd->dd_parent) { 437a2eea2e1Sahrens char setpoint[MAXNAMELEN]; 438a2eea2e1Sahrens zap_cursor_t zc; 439a2eea2e1Sahrens zap_attribute_t za; 440a2eea2e1Sahrens 4417f7322feSeschrock dsl_dir_name(dd, setpoint); 4427f7322feSeschrock 4437f7322feSeschrock for (zap_cursor_init(&zc, mos, dd->dd_phys->dd_props_zapobj); 4447f7322feSeschrock (err = zap_cursor_retrieve(&zc, &za)) == 0; 4457f7322feSeschrock zap_cursor_advance(&zc)) { 446a2eea2e1Sahrens nvlist_t *propval; 447a2eea2e1Sahrens zfs_prop_t prop; 448e9dbad6fSeschrock /* 449e9dbad6fSeschrock * Skip non-inheritable properties. 450e9dbad6fSeschrock */ 451e9dbad6fSeschrock if ((prop = zfs_name_to_prop(za.za_name)) != 452*990b4856Slling ZPROP_INVAL && !zfs_prop_inheritable(prop) && 453e9dbad6fSeschrock dd != ds->ds_dir) 454e9dbad6fSeschrock continue; 455e9dbad6fSeschrock 456e9dbad6fSeschrock if (nvlist_lookup_nvlist(*nvp, za.za_name, 457e9dbad6fSeschrock &propval) == 0) 4587f7322feSeschrock continue; 4597f7322feSeschrock 460e9dbad6fSeschrock VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, 4617f7322feSeschrock KM_SLEEP) == 0); 4627f7322feSeschrock if (za.za_integer_length == 1) { 4637f7322feSeschrock /* 4647f7322feSeschrock * String property 4657f7322feSeschrock */ 466a2eea2e1Sahrens char *tmp = kmem_alloc(za.za_num_integers, 467a2eea2e1Sahrens KM_SLEEP); 4687f7322feSeschrock err = zap_lookup(mos, 4697f7322feSeschrock dd->dd_phys->dd_props_zapobj, 4707f7322feSeschrock za.za_name, 1, za.za_num_integers, 4717f7322feSeschrock tmp); 4727f7322feSeschrock if (err != 0) { 4737f7322feSeschrock kmem_free(tmp, za.za_num_integers); 4747f7322feSeschrock break; 4757f7322feSeschrock } 476*990b4856Slling VERIFY(nvlist_add_string(propval, ZPROP_VALUE, 477*990b4856Slling tmp) == 0); 4787f7322feSeschrock kmem_free(tmp, za.za_num_integers); 4797f7322feSeschrock } else { 4807f7322feSeschrock /* 4817f7322feSeschrock * Integer property 4827f7322feSeschrock */ 4837f7322feSeschrock ASSERT(za.za_integer_length == 8); 484*990b4856Slling (void) nvlist_add_uint64(propval, ZPROP_VALUE, 485*990b4856Slling za.za_first_integer); 4867f7322feSeschrock } 4877f7322feSeschrock 488*990b4856Slling VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, 489*990b4856Slling setpoint) == 0); 4907f7322feSeschrock VERIFY(nvlist_add_nvlist(*nvp, za.za_name, 491e9dbad6fSeschrock propval) == 0); 492e9dbad6fSeschrock nvlist_free(propval); 4937f7322feSeschrock } 4947f7322feSeschrock zap_cursor_fini(&zc); 4957f7322feSeschrock 49699653d4eSeschrock if (err != ENOENT) 4977f7322feSeschrock break; 49899653d4eSeschrock err = 0; 4997f7322feSeschrock } 5007f7322feSeschrock rw_exit(&dp->dp_config_rwlock); 5017f7322feSeschrock 5027f7322feSeschrock return (err); 5037f7322feSeschrock } 504a2eea2e1Sahrens 505a2eea2e1Sahrens void 506a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nvlist_t *nv, zfs_prop_t prop, uint64_t value) 507a2eea2e1Sahrens { 508a2eea2e1Sahrens nvlist_t *propval; 509a2eea2e1Sahrens 510a2eea2e1Sahrens VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 511*990b4856Slling VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0); 512a2eea2e1Sahrens VERIFY(nvlist_add_nvlist(nv, zfs_prop_to_name(prop), propval) == 0); 513a2eea2e1Sahrens nvlist_free(propval); 514a2eea2e1Sahrens } 515a2eea2e1Sahrens 516a2eea2e1Sahrens void 517a2eea2e1Sahrens dsl_prop_nvlist_add_string(nvlist_t *nv, zfs_prop_t prop, const char *value) 518a2eea2e1Sahrens { 519a2eea2e1Sahrens nvlist_t *propval; 520a2eea2e1Sahrens 521a2eea2e1Sahrens VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 522*990b4856Slling VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0); 523a2eea2e1Sahrens VERIFY(nvlist_add_nvlist(nv, zfs_prop_to_name(prop), propval) == 0); 524a2eea2e1Sahrens nvlist_free(propval); 525a2eea2e1Sahrens } 526