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