1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5fa9e4066Sahrens * Common Development and Distribution License, Version 1.0 only 6fa9e4066Sahrens * (the "License"). You may not use this file except in compliance 7fa9e4066Sahrens * with the License. 8fa9e4066Sahrens * 9fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 11fa9e4066Sahrens * See the License for the specific language governing permissions 12fa9e4066Sahrens * and limitations under the License. 13fa9e4066Sahrens * 14fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 15fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 17fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 18fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 19fa9e4066Sahrens * 20fa9e4066Sahrens * CDDL HEADER END 21fa9e4066Sahrens */ 22fa9e4066Sahrens /* 23*7f7322feSeschrock * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24fa9e4066Sahrens * Use is subject to license terms. 25fa9e4066Sahrens */ 26fa9e4066Sahrens 27fa9e4066Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 28fa9e4066Sahrens 29fa9e4066Sahrens #include <sys/dmu.h> 30*7f7322feSeschrock #include <sys/dmu_objset.h> 31fa9e4066Sahrens #include <sys/dmu_tx.h> 32fa9e4066Sahrens #include <sys/dsl_dataset.h> 33fa9e4066Sahrens #include <sys/dsl_dir.h> 34fa9e4066Sahrens #include <sys/dsl_prop.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 51fa9e4066Sahrens if (zfs_prop_get_type(prop) == prop_type_string) { 52fa9e4066Sahrens if (intsz != 1) 53fa9e4066Sahrens return (EOVERFLOW); 54*7f7322feSeschrock (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 66fa9e4066Sahrens dsl_prop_get_impl(dsl_pool_t *dp, uint64_t ddobj, const char *propname, 67fa9e4066Sahrens int intsz, int numint, void *buf, char *setpoint) 68fa9e4066Sahrens { 69fa9e4066Sahrens int err = 0; 70fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 71fa9e4066Sahrens 72fa9e4066Sahrens if (setpoint) 73fa9e4066Sahrens setpoint[0] = '\0'; 74fa9e4066Sahrens 75fa9e4066Sahrens ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock)); 76fa9e4066Sahrens 77fa9e4066Sahrens while (ddobj != 0) { 78fa9e4066Sahrens dsl_dir_t *dd = dsl_dir_open_obj(dp, ddobj, NULL, FTAG); 79fa9e4066Sahrens err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj, 80fa9e4066Sahrens propname, intsz, numint, buf); 81fa9e4066Sahrens if (err != ENOENT) { 82fa9e4066Sahrens if (setpoint) 83fa9e4066Sahrens dsl_dir_name(dd, setpoint); 84fa9e4066Sahrens dsl_dir_close(dd, FTAG); 85fa9e4066Sahrens break; 86fa9e4066Sahrens } 87fa9e4066Sahrens ASSERT3U(err, ==, ENOENT); 88fa9e4066Sahrens ddobj = dd->dd_phys->dd_parent_obj; 89fa9e4066Sahrens dsl_dir_close(dd, FTAG); 90fa9e4066Sahrens } 91fa9e4066Sahrens if (err == ENOENT) 92fa9e4066Sahrens err = dodefault(propname, intsz, numint, buf); 93fa9e4066Sahrens 94fa9e4066Sahrens return (err); 95fa9e4066Sahrens } 96fa9e4066Sahrens 97fa9e4066Sahrens /* 98fa9e4066Sahrens * Register interest in the named property. We'll call the callback 99fa9e4066Sahrens * once to notify it of the current property value, and again each time 100fa9e4066Sahrens * the property changes, until this callback is unregistered. 101fa9e4066Sahrens * 102fa9e4066Sahrens * Return 0 on success, errno if the prop is not an integer value. 103fa9e4066Sahrens */ 104fa9e4066Sahrens int 105fa9e4066Sahrens dsl_prop_register(dsl_dataset_t *ds, const char *propname, 106fa9e4066Sahrens dsl_prop_changed_cb_t *callback, void *cbarg) 107fa9e4066Sahrens { 108fa9e4066Sahrens dsl_dir_t *dd; 109fa9e4066Sahrens uint64_t value; 110fa9e4066Sahrens dsl_prop_cb_record_t *cbr; 111fa9e4066Sahrens int err; 112fa9e4066Sahrens 113fa9e4066Sahrens dd = ds->ds_dir; 114fa9e4066Sahrens 115fa9e4066Sahrens rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 116fa9e4066Sahrens 117fa9e4066Sahrens err = dsl_prop_get_impl(dd->dd_pool, dd->dd_object, propname, 118fa9e4066Sahrens 8, 1, &value, NULL); 119fa9e4066Sahrens if (err == ENOENT) { 120fa9e4066Sahrens err = 0; 121fa9e4066Sahrens value = DSL_PROP_VALUE_UNDEFINED; 122fa9e4066Sahrens } 123fa9e4066Sahrens if (err != 0) { 124fa9e4066Sahrens rw_exit(&dd->dd_pool->dp_config_rwlock); 125fa9e4066Sahrens return (err); 126fa9e4066Sahrens } 127fa9e4066Sahrens 128fa9e4066Sahrens cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP); 129fa9e4066Sahrens cbr->cbr_propname = kmem_alloc(strlen(propname)+1, KM_SLEEP); 130fa9e4066Sahrens (void) strcpy((char *)cbr->cbr_propname, propname); 131fa9e4066Sahrens cbr->cbr_func = callback; 132fa9e4066Sahrens cbr->cbr_arg = cbarg; 133fa9e4066Sahrens mutex_enter(&dd->dd_lock); 134fa9e4066Sahrens list_insert_head(&dd->dd_prop_cbs, cbr); 135fa9e4066Sahrens mutex_exit(&dd->dd_lock); 136fa9e4066Sahrens 137fa9e4066Sahrens cbr->cbr_func(cbr->cbr_arg, value); 138fa9e4066Sahrens 139fa9e4066Sahrens (void) dsl_dir_open_obj(dd->dd_pool, dd->dd_object, NULL, cbr); 140fa9e4066Sahrens rw_exit(&dd->dd_pool->dp_config_rwlock); 141fa9e4066Sahrens /* Leave dataset open until this callback is unregistered */ 142fa9e4066Sahrens return (0); 143fa9e4066Sahrens } 144fa9e4066Sahrens 145fa9e4066Sahrens int 146fa9e4066Sahrens dsl_prop_get_ds(dsl_dir_t *dd, const char *propname, 147fa9e4066Sahrens int intsz, int numints, void *buf, char *setpoint) 148fa9e4066Sahrens { 149fa9e4066Sahrens int err; 150fa9e4066Sahrens 151fa9e4066Sahrens rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 152fa9e4066Sahrens err = dsl_prop_get_impl(dd->dd_pool, dd->dd_object, 153fa9e4066Sahrens propname, intsz, numints, buf, setpoint); 154fa9e4066Sahrens rw_exit(&dd->dd_pool->dp_config_rwlock); 155fa9e4066Sahrens 156fa9e4066Sahrens return (err); 157fa9e4066Sahrens } 158fa9e4066Sahrens 159fa9e4066Sahrens int 160fa9e4066Sahrens dsl_prop_get(const char *ddname, const char *propname, 161fa9e4066Sahrens int intsz, int numints, void *buf, char *setpoint) 162fa9e4066Sahrens { 163fa9e4066Sahrens dsl_dir_t *dd; 164fa9e4066Sahrens const char *tail; 165fa9e4066Sahrens int err; 166fa9e4066Sahrens 167fa9e4066Sahrens dd = dsl_dir_open(ddname, FTAG, &tail); 168fa9e4066Sahrens if (dd == NULL) 169fa9e4066Sahrens return (ENOENT); 170fa9e4066Sahrens if (tail && tail[0] != '@') { 171fa9e4066Sahrens dsl_dir_close(dd, FTAG); 172fa9e4066Sahrens return (ENOENT); 173fa9e4066Sahrens } 174fa9e4066Sahrens 175fa9e4066Sahrens err = dsl_prop_get_ds(dd, propname, intsz, numints, buf, setpoint); 176fa9e4066Sahrens 177fa9e4066Sahrens dsl_dir_close(dd, FTAG); 178fa9e4066Sahrens return (err); 179fa9e4066Sahrens } 180fa9e4066Sahrens 181fa9e4066Sahrens /* 182fa9e4066Sahrens * Return 0 on success, ENOENT if ddname is invalid, EOVERFLOW if 183fa9e4066Sahrens * valuelen not big enough. 184fa9e4066Sahrens */ 185fa9e4066Sahrens int 186fa9e4066Sahrens dsl_prop_get_string(const char *ddname, const char *propname, 187fa9e4066Sahrens char *value, int valuelen, char *setpoint) 188fa9e4066Sahrens { 189fa9e4066Sahrens return (dsl_prop_get(ddname, propname, 1, valuelen, value, setpoint)); 190fa9e4066Sahrens } 191fa9e4066Sahrens 192fa9e4066Sahrens /* 193fa9e4066Sahrens * Get the current property value. It may have changed by the time this 194fa9e4066Sahrens * function returns, so it is NOT safe to follow up with 195fa9e4066Sahrens * dsl_prop_register() and assume that the value has not changed in 196fa9e4066Sahrens * between. 197fa9e4066Sahrens * 198fa9e4066Sahrens * Return 0 on success, ENOENT if ddname is invalid. 199fa9e4066Sahrens */ 200fa9e4066Sahrens int 201fa9e4066Sahrens dsl_prop_get_integer(const char *ddname, const char *propname, 202fa9e4066Sahrens uint64_t *valuep, char *setpoint) 203fa9e4066Sahrens { 204fa9e4066Sahrens return (dsl_prop_get(ddname, propname, 8, 1, valuep, setpoint)); 205fa9e4066Sahrens } 206fa9e4066Sahrens 207fa9e4066Sahrens int 208fa9e4066Sahrens dsl_prop_get_ds_integer(dsl_dir_t *dd, const char *propname, 209fa9e4066Sahrens uint64_t *valuep, char *setpoint) 210fa9e4066Sahrens { 211fa9e4066Sahrens return (dsl_prop_get_ds(dd, propname, 8, 1, valuep, setpoint)); 212fa9e4066Sahrens } 213fa9e4066Sahrens 214fa9e4066Sahrens /* 215fa9e4066Sahrens * Unregister this callback. Return 0 on success, ENOENT if ddname is 216fa9e4066Sahrens * invalid, ENOMSG if no matching callback registered. 217fa9e4066Sahrens */ 218fa9e4066Sahrens int 219fa9e4066Sahrens dsl_prop_unregister(dsl_dataset_t *ds, const char *propname, 220fa9e4066Sahrens dsl_prop_changed_cb_t *callback, void *cbarg) 221fa9e4066Sahrens { 222fa9e4066Sahrens dsl_dir_t *dd; 223fa9e4066Sahrens dsl_prop_cb_record_t *cbr; 224fa9e4066Sahrens 225fa9e4066Sahrens dd = ds->ds_dir; 226fa9e4066Sahrens 227fa9e4066Sahrens mutex_enter(&dd->dd_lock); 228fa9e4066Sahrens for (cbr = list_head(&dd->dd_prop_cbs); 229fa9e4066Sahrens cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { 230fa9e4066Sahrens if (strcmp(cbr->cbr_propname, propname) == 0 && 231fa9e4066Sahrens cbr->cbr_func == callback && 232fa9e4066Sahrens cbr->cbr_arg == cbarg) 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 251fa9e4066Sahrens static void 252fa9e4066Sahrens dsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj, 253fa9e4066Sahrens const char *propname, uint64_t value, int first) 254fa9e4066Sahrens { 255fa9e4066Sahrens dsl_dir_t *dd; 256fa9e4066Sahrens dsl_prop_cb_record_t *cbr; 257fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 258fa9e4066Sahrens int err; 259fa9e4066Sahrens 260fa9e4066Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 261fa9e4066Sahrens dd = dsl_dir_open_obj(dp, ddobj, NULL, FTAG); 262fa9e4066Sahrens 263fa9e4066Sahrens if (!first) { 264fa9e4066Sahrens /* 265fa9e4066Sahrens * If the prop is set here, then this change is not 266fa9e4066Sahrens * being inherited here or below; stop the recursion. 267fa9e4066Sahrens */ 268fa9e4066Sahrens err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj, propname, 269fa9e4066Sahrens 8, 1, &value); 270fa9e4066Sahrens if (err == 0) { 271fa9e4066Sahrens dsl_dir_close(dd, FTAG); 272fa9e4066Sahrens return; 273fa9e4066Sahrens } 274fa9e4066Sahrens ASSERT3U(err, ==, ENOENT); 275fa9e4066Sahrens } 276fa9e4066Sahrens 277fa9e4066Sahrens mutex_enter(&dd->dd_lock); 278fa9e4066Sahrens for (cbr = list_head(&dd->dd_prop_cbs); 279fa9e4066Sahrens cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { 280fa9e4066Sahrens if (strcmp(cbr->cbr_propname, propname) == 0) { 281fa9e4066Sahrens cbr->cbr_func(cbr->cbr_arg, value); 282fa9e4066Sahrens } 283fa9e4066Sahrens } 284fa9e4066Sahrens mutex_exit(&dd->dd_lock); 285fa9e4066Sahrens 286fa9e4066Sahrens if (dd->dd_phys->dd_child_dir_zapobj) { 287fa9e4066Sahrens zap_cursor_t zc; 288fa9e4066Sahrens zap_attribute_t za; 289fa9e4066Sahrens 290fa9e4066Sahrens for (zap_cursor_init(&zc, mos, 291fa9e4066Sahrens dd->dd_phys->dd_child_dir_zapobj); 292fa9e4066Sahrens zap_cursor_retrieve(&zc, &za) == 0; 293fa9e4066Sahrens zap_cursor_advance(&zc)) { 294fa9e4066Sahrens /* XXX recursion could blow stack; esp. za! */ 295fa9e4066Sahrens dsl_prop_changed_notify(dp, za.za_first_integer, 296fa9e4066Sahrens propname, value, FALSE); 297fa9e4066Sahrens } 29887e5029aSahrens zap_cursor_fini(&zc); 299fa9e4066Sahrens } 300fa9e4066Sahrens dsl_dir_close(dd, FTAG); 301fa9e4066Sahrens } 302fa9e4066Sahrens 303fa9e4066Sahrens struct prop_set_arg { 304fa9e4066Sahrens const char *name; 305fa9e4066Sahrens int intsz; 306fa9e4066Sahrens int numints; 307fa9e4066Sahrens const void *buf; 308fa9e4066Sahrens }; 309fa9e4066Sahrens 310fa9e4066Sahrens static int 311fa9e4066Sahrens dsl_prop_set_sync(dsl_dir_t *dd, void *arg, dmu_tx_t *tx) 312fa9e4066Sahrens { 313fa9e4066Sahrens struct prop_set_arg *psa = arg; 314fa9e4066Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 315fa9e4066Sahrens uint64_t zapobj = dd->dd_phys->dd_props_zapobj; 316fa9e4066Sahrens uint64_t intval; 317fa9e4066Sahrens int err, isint; 318fa9e4066Sahrens 319fa9e4066Sahrens rw_enter(&dd->dd_pool->dp_config_rwlock, RW_WRITER); 320fa9e4066Sahrens 321fa9e4066Sahrens isint = (dodefault(psa->name, 8, 1, &intval) == 0); 322fa9e4066Sahrens 323fa9e4066Sahrens if (psa->numints == 0) { 324fa9e4066Sahrens err = zap_remove(mos, zapobj, psa->name, tx); 325fa9e4066Sahrens if (err == ENOENT) /* that's fine. */ 326fa9e4066Sahrens err = 0; 327fa9e4066Sahrens if (err == 0 && isint) { 328fa9e4066Sahrens err = dsl_prop_get_impl(dd->dd_pool, 329fa9e4066Sahrens dd->dd_phys->dd_parent_obj, psa->name, 330fa9e4066Sahrens 8, 1, &intval, NULL); 331fa9e4066Sahrens } 332fa9e4066Sahrens } else { 333fa9e4066Sahrens err = zap_update(mos, zapobj, psa->name, 334fa9e4066Sahrens psa->intsz, psa->numints, psa->buf, tx); 335fa9e4066Sahrens if (isint) 336fa9e4066Sahrens intval = *(uint64_t *)psa->buf; 337fa9e4066Sahrens } 338fa9e4066Sahrens 339fa9e4066Sahrens if (err == 0 && isint) { 340fa9e4066Sahrens dsl_prop_changed_notify(dd->dd_pool, 341fa9e4066Sahrens dd->dd_object, psa->name, intval, TRUE); 342fa9e4066Sahrens } 343fa9e4066Sahrens rw_exit(&dd->dd_pool->dp_config_rwlock); 344fa9e4066Sahrens 345fa9e4066Sahrens return (err); 346fa9e4066Sahrens } 347fa9e4066Sahrens 348fa9e4066Sahrens int 349fa9e4066Sahrens dsl_prop_set(const char *ddname, const char *propname, 350fa9e4066Sahrens int intsz, int numints, const void *buf) 351fa9e4066Sahrens { 352fa9e4066Sahrens dsl_dir_t *dd; 353fa9e4066Sahrens int err; 354fa9e4066Sahrens struct prop_set_arg psa; 355fa9e4066Sahrens 356fa9e4066Sahrens dd = dsl_dir_open(ddname, FTAG, NULL); 357fa9e4066Sahrens if (dd == NULL) 358fa9e4066Sahrens return (ENOENT); 359fa9e4066Sahrens 360fa9e4066Sahrens psa.name = propname; 361fa9e4066Sahrens psa.intsz = intsz; 362fa9e4066Sahrens psa.numints = numints; 363fa9e4066Sahrens psa.buf = buf; 364fa9e4066Sahrens err = dsl_dir_sync_task(dd, dsl_prop_set_sync, &psa, 0); 365fa9e4066Sahrens 366fa9e4066Sahrens dsl_dir_close(dd, FTAG); 367fa9e4066Sahrens 368fa9e4066Sahrens return (err); 369fa9e4066Sahrens } 370*7f7322feSeschrock 371*7f7322feSeschrock /* 372*7f7322feSeschrock * Iterate over all properties for this dataset and return them in an nvlist. 373*7f7322feSeschrock */ 374*7f7322feSeschrock int 375*7f7322feSeschrock dsl_prop_get_all(objset_t *os, nvlist_t **nvp) 376*7f7322feSeschrock { 377*7f7322feSeschrock dsl_dataset_t *ds = os->os->os_dsl_dataset; 378*7f7322feSeschrock dsl_dir_t *dd, *parent; 379*7f7322feSeschrock int err = 0; 380*7f7322feSeschrock dsl_pool_t *dp; 381*7f7322feSeschrock objset_t *mos; 382*7f7322feSeschrock zap_cursor_t zc; 383*7f7322feSeschrock zap_attribute_t za; 384*7f7322feSeschrock char setpoint[MAXNAMELEN]; 385*7f7322feSeschrock char *tmp; 386*7f7322feSeschrock nvlist_t *prop; 387*7f7322feSeschrock 388*7f7322feSeschrock if (dsl_dataset_is_snapshot(ds)) { 389*7f7322feSeschrock VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); 390*7f7322feSeschrock return (0); 391*7f7322feSeschrock } 392*7f7322feSeschrock 393*7f7322feSeschrock dd = ds->ds_dir; 394*7f7322feSeschrock 395*7f7322feSeschrock VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); 396*7f7322feSeschrock 397*7f7322feSeschrock dp = dd->dd_pool; 398*7f7322feSeschrock mos = dp->dp_meta_objset; 399*7f7322feSeschrock 400*7f7322feSeschrock rw_enter(&dp->dp_config_rwlock, RW_READER); 401*7f7322feSeschrock while (dd != NULL) { 402*7f7322feSeschrock dsl_dir_name(dd, setpoint); 403*7f7322feSeschrock 404*7f7322feSeschrock for (zap_cursor_init(&zc, mos, dd->dd_phys->dd_props_zapobj); 405*7f7322feSeschrock (err = zap_cursor_retrieve(&zc, &za)) == 0; 406*7f7322feSeschrock zap_cursor_advance(&zc)) { 407*7f7322feSeschrock if (nvlist_lookup_nvlist(*nvp, za.za_name, &prop) == 0) 408*7f7322feSeschrock continue; 409*7f7322feSeschrock 410*7f7322feSeschrock VERIFY(nvlist_alloc(&prop, NV_UNIQUE_NAME, 411*7f7322feSeschrock KM_SLEEP) == 0); 412*7f7322feSeschrock if (za.za_integer_length == 1) { 413*7f7322feSeschrock /* 414*7f7322feSeschrock * String property 415*7f7322feSeschrock */ 416*7f7322feSeschrock 417*7f7322feSeschrock tmp = kmem_alloc(za.za_num_integers, KM_SLEEP); 418*7f7322feSeschrock err = zap_lookup(mos, 419*7f7322feSeschrock dd->dd_phys->dd_props_zapobj, 420*7f7322feSeschrock za.za_name, 1, za.za_num_integers, 421*7f7322feSeschrock tmp); 422*7f7322feSeschrock if (err != 0) { 423*7f7322feSeschrock kmem_free(tmp, za.za_num_integers); 424*7f7322feSeschrock break; 425*7f7322feSeschrock } 426*7f7322feSeschrock VERIFY(nvlist_add_string(prop, 427*7f7322feSeschrock ZFS_PROP_VALUE, tmp) == 0); 428*7f7322feSeschrock kmem_free(tmp, za.za_num_integers); 429*7f7322feSeschrock } else { 430*7f7322feSeschrock /* 431*7f7322feSeschrock * Integer property 432*7f7322feSeschrock */ 433*7f7322feSeschrock ASSERT(za.za_integer_length == 8); 434*7f7322feSeschrock (void) nvlist_add_uint64(prop, ZFS_PROP_VALUE, 435*7f7322feSeschrock za.za_first_integer); 436*7f7322feSeschrock } 437*7f7322feSeschrock 438*7f7322feSeschrock VERIFY(nvlist_add_string(prop, 439*7f7322feSeschrock ZFS_PROP_SOURCE, setpoint) == 0); 440*7f7322feSeschrock VERIFY(nvlist_add_nvlist(*nvp, za.za_name, 441*7f7322feSeschrock prop) == 0); 442*7f7322feSeschrock nvlist_free(prop); 443*7f7322feSeschrock } 444*7f7322feSeschrock zap_cursor_fini(&zc); 445*7f7322feSeschrock 446*7f7322feSeschrock if (err != ENOENT) { 447*7f7322feSeschrock if (dd != ds->ds_dir) 448*7f7322feSeschrock dsl_dir_close(dd, FTAG); 449*7f7322feSeschrock break; 450*7f7322feSeschrock } else { 451*7f7322feSeschrock err = 0; 452*7f7322feSeschrock } 453*7f7322feSeschrock 454*7f7322feSeschrock /* 455*7f7322feSeschrock * Continue to parent. 456*7f7322feSeschrock */ 457*7f7322feSeschrock if (dd->dd_phys->dd_parent_obj == 0) 458*7f7322feSeschrock parent = NULL; 459*7f7322feSeschrock else 460*7f7322feSeschrock parent = dsl_dir_open_obj(dp, 461*7f7322feSeschrock dd->dd_phys->dd_parent_obj, NULL, FTAG); 462*7f7322feSeschrock if (dd != ds->ds_dir) 463*7f7322feSeschrock dsl_dir_close(dd, FTAG); 464*7f7322feSeschrock dd = parent; 465*7f7322feSeschrock } 466*7f7322feSeschrock rw_exit(&dp->dp_config_rwlock); 467*7f7322feSeschrock 468*7f7322feSeschrock return (err); 469*7f7322feSeschrock } 470