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 /* 227f7322feSeschrock * Copyright 2006 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> 34*1d452cf5Sahrens #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 51fa9e4066Sahrens 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; 70fa9e4066Sahrens 71fa9e4066Sahrens if (setpoint) 72fa9e4066Sahrens setpoint[0] = '\0'; 73fa9e4066Sahrens 7499653d4eSeschrock /* 7599653d4eSeschrock * Note: dd may be NULL, therefore we shouldn't dereference it 7699653d4eSeschrock * ouside this loop. 7799653d4eSeschrock */ 7899653d4eSeschrock for (; dd != NULL; dd = dd->dd_parent) { 7999653d4eSeschrock objset_t *mos = dd->dd_pool->dp_meta_objset; 8099653d4eSeschrock ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock)); 81fa9e4066Sahrens err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj, 82fa9e4066Sahrens propname, intsz, numint, buf); 83fa9e4066Sahrens if (err != ENOENT) { 84fa9e4066Sahrens if (setpoint) 85fa9e4066Sahrens dsl_dir_name(dd, setpoint); 86fa9e4066Sahrens break; 87fa9e4066Sahrens } 88fa9e4066Sahrens } 89fa9e4066Sahrens if (err == ENOENT) 90fa9e4066Sahrens err = dodefault(propname, intsz, numint, buf); 91fa9e4066Sahrens 92fa9e4066Sahrens return (err); 93fa9e4066Sahrens } 94fa9e4066Sahrens 95fa9e4066Sahrens /* 96fa9e4066Sahrens * Register interest in the named property. We'll call the callback 97fa9e4066Sahrens * once to notify it of the current property value, and again each time 98fa9e4066Sahrens * the property changes, until this callback is unregistered. 99fa9e4066Sahrens * 100fa9e4066Sahrens * Return 0 on success, errno if the prop is not an integer value. 101fa9e4066Sahrens */ 102fa9e4066Sahrens int 103fa9e4066Sahrens dsl_prop_register(dsl_dataset_t *ds, const char *propname, 104fa9e4066Sahrens dsl_prop_changed_cb_t *callback, void *cbarg) 105fa9e4066Sahrens { 10699653d4eSeschrock dsl_dir_t *dd = ds->ds_dir; 107fa9e4066Sahrens uint64_t value; 108fa9e4066Sahrens dsl_prop_cb_record_t *cbr; 109fa9e4066Sahrens int err; 110*1d452cf5Sahrens int need_rwlock; 111fa9e4066Sahrens 112*1d452cf5Sahrens need_rwlock = !RW_WRITE_HELD(&dd->dd_pool->dp_config_rwlock); 113*1d452cf5Sahrens if (need_rwlock) 114*1d452cf5Sahrens rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 115fa9e4066Sahrens 11699653d4eSeschrock err = dsl_prop_get_impl(dd, propname, 8, 1, &value, NULL); 117fa9e4066Sahrens if (err != 0) { 118fa9e4066Sahrens rw_exit(&dd->dd_pool->dp_config_rwlock); 119fa9e4066Sahrens return (err); 120fa9e4066Sahrens } 121fa9e4066Sahrens 122fa9e4066Sahrens cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP); 12399653d4eSeschrock cbr->cbr_ds = ds; 124fa9e4066Sahrens cbr->cbr_propname = kmem_alloc(strlen(propname)+1, KM_SLEEP); 125fa9e4066Sahrens (void) strcpy((char *)cbr->cbr_propname, propname); 126fa9e4066Sahrens cbr->cbr_func = callback; 127fa9e4066Sahrens cbr->cbr_arg = cbarg; 128fa9e4066Sahrens mutex_enter(&dd->dd_lock); 129fa9e4066Sahrens list_insert_head(&dd->dd_prop_cbs, cbr); 130fa9e4066Sahrens mutex_exit(&dd->dd_lock); 131fa9e4066Sahrens 132fa9e4066Sahrens cbr->cbr_func(cbr->cbr_arg, value); 133fa9e4066Sahrens 134ea8dc4b6Seschrock VERIFY(0 == dsl_dir_open_obj(dd->dd_pool, dd->dd_object, 135ea8dc4b6Seschrock NULL, cbr, &dd)); 136*1d452cf5Sahrens if (need_rwlock) 137*1d452cf5Sahrens rw_exit(&dd->dd_pool->dp_config_rwlock); 138fa9e4066Sahrens /* Leave dataset open until this callback is unregistered */ 139fa9e4066Sahrens return (0); 140fa9e4066Sahrens } 141fa9e4066Sahrens 142fa9e4066Sahrens int 143fa9e4066Sahrens dsl_prop_get_ds(dsl_dir_t *dd, const char *propname, 144fa9e4066Sahrens int intsz, int numints, void *buf, char *setpoint) 145fa9e4066Sahrens { 146fa9e4066Sahrens int err; 147fa9e4066Sahrens 148fa9e4066Sahrens rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 14999653d4eSeschrock err = dsl_prop_get_impl(dd, propname, intsz, numints, buf, setpoint); 150fa9e4066Sahrens rw_exit(&dd->dd_pool->dp_config_rwlock); 151fa9e4066Sahrens 152fa9e4066Sahrens return (err); 153fa9e4066Sahrens } 154fa9e4066Sahrens 155fa9e4066Sahrens int 156fa9e4066Sahrens dsl_prop_get(const char *ddname, const char *propname, 157fa9e4066Sahrens int intsz, int numints, void *buf, char *setpoint) 158fa9e4066Sahrens { 159fa9e4066Sahrens dsl_dir_t *dd; 160fa9e4066Sahrens const char *tail; 161fa9e4066Sahrens int err; 162fa9e4066Sahrens 163ea8dc4b6Seschrock err = dsl_dir_open(ddname, FTAG, &dd, &tail); 164ea8dc4b6Seschrock if (err) 165ea8dc4b6Seschrock return (err); 166fa9e4066Sahrens if (tail && tail[0] != '@') { 167fa9e4066Sahrens dsl_dir_close(dd, FTAG); 168fa9e4066Sahrens return (ENOENT); 169fa9e4066Sahrens } 170fa9e4066Sahrens 171fa9e4066Sahrens err = dsl_prop_get_ds(dd, propname, intsz, numints, buf, setpoint); 172fa9e4066Sahrens 173fa9e4066Sahrens dsl_dir_close(dd, FTAG); 174fa9e4066Sahrens return (err); 175fa9e4066Sahrens } 176fa9e4066Sahrens 177fa9e4066Sahrens /* 178fa9e4066Sahrens * Return 0 on success, ENOENT if ddname is invalid, EOVERFLOW if 179fa9e4066Sahrens * valuelen not big enough. 180fa9e4066Sahrens */ 181fa9e4066Sahrens int 182fa9e4066Sahrens dsl_prop_get_string(const char *ddname, const char *propname, 183fa9e4066Sahrens char *value, int valuelen, char *setpoint) 184fa9e4066Sahrens { 185fa9e4066Sahrens return (dsl_prop_get(ddname, propname, 1, valuelen, value, setpoint)); 186fa9e4066Sahrens } 187fa9e4066Sahrens 188fa9e4066Sahrens /* 189fa9e4066Sahrens * Get the current property value. It may have changed by the time this 190fa9e4066Sahrens * function returns, so it is NOT safe to follow up with 191fa9e4066Sahrens * dsl_prop_register() and assume that the value has not changed in 192fa9e4066Sahrens * between. 193fa9e4066Sahrens * 194fa9e4066Sahrens * Return 0 on success, ENOENT if ddname is invalid. 195fa9e4066Sahrens */ 196fa9e4066Sahrens int 197fa9e4066Sahrens dsl_prop_get_integer(const char *ddname, const char *propname, 198fa9e4066Sahrens uint64_t *valuep, char *setpoint) 199fa9e4066Sahrens { 200fa9e4066Sahrens return (dsl_prop_get(ddname, propname, 8, 1, valuep, setpoint)); 201fa9e4066Sahrens } 202fa9e4066Sahrens 203fa9e4066Sahrens int 204fa9e4066Sahrens dsl_prop_get_ds_integer(dsl_dir_t *dd, const char *propname, 205fa9e4066Sahrens uint64_t *valuep, char *setpoint) 206fa9e4066Sahrens { 207fa9e4066Sahrens return (dsl_prop_get_ds(dd, propname, 8, 1, valuep, setpoint)); 208fa9e4066Sahrens } 209fa9e4066Sahrens 210fa9e4066Sahrens /* 211fa9e4066Sahrens * Unregister this callback. Return 0 on success, ENOENT if ddname is 212fa9e4066Sahrens * invalid, ENOMSG if no matching callback registered. 213fa9e4066Sahrens */ 214fa9e4066Sahrens int 215fa9e4066Sahrens dsl_prop_unregister(dsl_dataset_t *ds, const char *propname, 216fa9e4066Sahrens dsl_prop_changed_cb_t *callback, void *cbarg) 217fa9e4066Sahrens { 21899653d4eSeschrock dsl_dir_t *dd = ds->ds_dir; 219fa9e4066Sahrens dsl_prop_cb_record_t *cbr; 220fa9e4066Sahrens 221fa9e4066Sahrens mutex_enter(&dd->dd_lock); 222fa9e4066Sahrens for (cbr = list_head(&dd->dd_prop_cbs); 223fa9e4066Sahrens cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { 22499653d4eSeschrock if (cbr->cbr_ds == ds && 225fa9e4066Sahrens cbr->cbr_func == callback && 22699653d4eSeschrock cbr->cbr_arg == cbarg && 22799653d4eSeschrock strcmp(cbr->cbr_propname, propname) == 0) 228fa9e4066Sahrens break; 229fa9e4066Sahrens } 230fa9e4066Sahrens 231fa9e4066Sahrens if (cbr == NULL) { 232fa9e4066Sahrens mutex_exit(&dd->dd_lock); 233fa9e4066Sahrens return (ENOMSG); 234fa9e4066Sahrens } 235fa9e4066Sahrens 236fa9e4066Sahrens list_remove(&dd->dd_prop_cbs, cbr); 237fa9e4066Sahrens mutex_exit(&dd->dd_lock); 238fa9e4066Sahrens kmem_free((void*)cbr->cbr_propname, strlen(cbr->cbr_propname)+1); 239fa9e4066Sahrens kmem_free(cbr, sizeof (dsl_prop_cb_record_t)); 240fa9e4066Sahrens 241fa9e4066Sahrens /* Clean up from dsl_prop_register */ 242fa9e4066Sahrens dsl_dir_close(dd, cbr); 243fa9e4066Sahrens return (0); 244fa9e4066Sahrens } 245fa9e4066Sahrens 24699653d4eSeschrock /* 24799653d4eSeschrock * Return the number of callbacks that are registered for this dataset. 24899653d4eSeschrock */ 24999653d4eSeschrock int 25099653d4eSeschrock dsl_prop_numcb(dsl_dataset_t *ds) 25199653d4eSeschrock { 25299653d4eSeschrock dsl_dir_t *dd = ds->ds_dir; 25399653d4eSeschrock dsl_prop_cb_record_t *cbr; 25499653d4eSeschrock int num = 0; 25599653d4eSeschrock 25699653d4eSeschrock mutex_enter(&dd->dd_lock); 25799653d4eSeschrock for (cbr = list_head(&dd->dd_prop_cbs); 25899653d4eSeschrock cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { 25999653d4eSeschrock if (cbr->cbr_ds == ds) 26099653d4eSeschrock num++; 26199653d4eSeschrock } 26299653d4eSeschrock mutex_exit(&dd->dd_lock); 26399653d4eSeschrock 26499653d4eSeschrock return (num); 26599653d4eSeschrock } 26699653d4eSeschrock 267fa9e4066Sahrens static void 268fa9e4066Sahrens dsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj, 269fa9e4066Sahrens const char *propname, uint64_t value, int first) 270fa9e4066Sahrens { 271fa9e4066Sahrens dsl_dir_t *dd; 272fa9e4066Sahrens dsl_prop_cb_record_t *cbr; 273fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 274*1d452cf5Sahrens zap_cursor_t zc; 275*1d452cf5Sahrens zap_attribute_t za; 276fa9e4066Sahrens int err; 277fa9e4066Sahrens 278fa9e4066Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 279ea8dc4b6Seschrock err = dsl_dir_open_obj(dp, ddobj, NULL, FTAG, &dd); 280ea8dc4b6Seschrock if (err) 281ea8dc4b6Seschrock return; 282fa9e4066Sahrens 283fa9e4066Sahrens if (!first) { 284fa9e4066Sahrens /* 285fa9e4066Sahrens * If the prop is set here, then this change is not 286fa9e4066Sahrens * being inherited here or below; stop the recursion. 287fa9e4066Sahrens */ 288fa9e4066Sahrens err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj, propname, 289fa9e4066Sahrens 8, 1, &value); 290fa9e4066Sahrens if (err == 0) { 291fa9e4066Sahrens dsl_dir_close(dd, FTAG); 292fa9e4066Sahrens return; 293fa9e4066Sahrens } 294fa9e4066Sahrens ASSERT3U(err, ==, ENOENT); 295fa9e4066Sahrens } 296fa9e4066Sahrens 297fa9e4066Sahrens mutex_enter(&dd->dd_lock); 298fa9e4066Sahrens for (cbr = list_head(&dd->dd_prop_cbs); 299fa9e4066Sahrens cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { 300fa9e4066Sahrens if (strcmp(cbr->cbr_propname, propname) == 0) { 301fa9e4066Sahrens cbr->cbr_func(cbr->cbr_arg, value); 302fa9e4066Sahrens } 303fa9e4066Sahrens } 304fa9e4066Sahrens mutex_exit(&dd->dd_lock); 305fa9e4066Sahrens 306*1d452cf5Sahrens for (zap_cursor_init(&zc, mos, 307*1d452cf5Sahrens dd->dd_phys->dd_child_dir_zapobj); 308*1d452cf5Sahrens zap_cursor_retrieve(&zc, &za) == 0; 309*1d452cf5Sahrens zap_cursor_advance(&zc)) { 310*1d452cf5Sahrens /* XXX recursion could blow stack; esp. za! */ 311*1d452cf5Sahrens dsl_prop_changed_notify(dp, za.za_first_integer, 312*1d452cf5Sahrens propname, value, FALSE); 313fa9e4066Sahrens } 314*1d452cf5Sahrens zap_cursor_fini(&zc); 315fa9e4066Sahrens dsl_dir_close(dd, FTAG); 316fa9e4066Sahrens } 317fa9e4066Sahrens 318fa9e4066Sahrens struct prop_set_arg { 319fa9e4066Sahrens const char *name; 320fa9e4066Sahrens int intsz; 321fa9e4066Sahrens int numints; 322fa9e4066Sahrens const void *buf; 323fa9e4066Sahrens }; 324fa9e4066Sahrens 325*1d452cf5Sahrens 326*1d452cf5Sahrens static void 327*1d452cf5Sahrens dsl_prop_set_sync(void *arg1, void *arg2, dmu_tx_t *tx) 328fa9e4066Sahrens { 329*1d452cf5Sahrens dsl_dir_t *dd = arg1; 330*1d452cf5Sahrens struct prop_set_arg *psa = arg2; 331fa9e4066Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 332fa9e4066Sahrens uint64_t zapobj = dd->dd_phys->dd_props_zapobj; 333fa9e4066Sahrens uint64_t intval; 334*1d452cf5Sahrens int isint; 335fa9e4066Sahrens 336fa9e4066Sahrens isint = (dodefault(psa->name, 8, 1, &intval) == 0); 337fa9e4066Sahrens 338fa9e4066Sahrens if (psa->numints == 0) { 339*1d452cf5Sahrens int err = zap_remove(mos, zapobj, psa->name, tx); 340*1d452cf5Sahrens ASSERT(err == 0 || err == ENOENT); 341*1d452cf5Sahrens if (isint) { 342*1d452cf5Sahrens VERIFY(0 == dsl_prop_get_impl(dd->dd_parent, 343*1d452cf5Sahrens psa->name, 8, 1, &intval, NULL)); 344fa9e4066Sahrens } 345fa9e4066Sahrens } else { 346*1d452cf5Sahrens VERIFY(0 == zap_update(mos, zapobj, psa->name, 347*1d452cf5Sahrens psa->intsz, psa->numints, psa->buf, tx)); 348fa9e4066Sahrens if (isint) 349fa9e4066Sahrens intval = *(uint64_t *)psa->buf; 350fa9e4066Sahrens } 351fa9e4066Sahrens 352*1d452cf5Sahrens if (isint) { 353fa9e4066Sahrens dsl_prop_changed_notify(dd->dd_pool, 354fa9e4066Sahrens dd->dd_object, psa->name, intval, TRUE); 355fa9e4066Sahrens } 356fa9e4066Sahrens } 357fa9e4066Sahrens 358fa9e4066Sahrens int 359fa9e4066Sahrens dsl_prop_set(const char *ddname, const char *propname, 360fa9e4066Sahrens int intsz, int numints, const void *buf) 361fa9e4066Sahrens { 362fa9e4066Sahrens dsl_dir_t *dd; 363fa9e4066Sahrens int err; 364fa9e4066Sahrens struct prop_set_arg psa; 365fa9e4066Sahrens 366ea8dc4b6Seschrock err = dsl_dir_open(ddname, FTAG, &dd, NULL); 367ea8dc4b6Seschrock if (err) 368ea8dc4b6Seschrock return (err); 369fa9e4066Sahrens 370fa9e4066Sahrens psa.name = propname; 371fa9e4066Sahrens psa.intsz = intsz; 372fa9e4066Sahrens psa.numints = numints; 373fa9e4066Sahrens psa.buf = buf; 374*1d452cf5Sahrens err = dsl_sync_task_do(dd->dd_pool, 375*1d452cf5Sahrens NULL, dsl_prop_set_sync, dd, &psa, 2); 376fa9e4066Sahrens 377fa9e4066Sahrens dsl_dir_close(dd, FTAG); 378fa9e4066Sahrens 379fa9e4066Sahrens return (err); 380fa9e4066Sahrens } 3817f7322feSeschrock 3827f7322feSeschrock /* 3837f7322feSeschrock * Iterate over all properties for this dataset and return them in an nvlist. 3847f7322feSeschrock */ 3857f7322feSeschrock int 3867f7322feSeschrock dsl_prop_get_all(objset_t *os, nvlist_t **nvp) 3877f7322feSeschrock { 3887f7322feSeschrock dsl_dataset_t *ds = os->os->os_dsl_dataset; 38999653d4eSeschrock dsl_dir_t *dd = ds->ds_dir; 3907f7322feSeschrock int err = 0; 3917f7322feSeschrock dsl_pool_t *dp; 3927f7322feSeschrock objset_t *mos; 3937f7322feSeschrock zap_cursor_t zc; 3947f7322feSeschrock zap_attribute_t za; 3957f7322feSeschrock char setpoint[MAXNAMELEN]; 3967f7322feSeschrock char *tmp; 3977f7322feSeschrock nvlist_t *prop; 3987f7322feSeschrock 3997f7322feSeschrock if (dsl_dataset_is_snapshot(ds)) { 4007f7322feSeschrock VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); 4017f7322feSeschrock return (0); 4027f7322feSeschrock } 4037f7322feSeschrock 4047f7322feSeschrock VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); 4057f7322feSeschrock 4067f7322feSeschrock dp = dd->dd_pool; 4077f7322feSeschrock mos = dp->dp_meta_objset; 4087f7322feSeschrock 4097f7322feSeschrock rw_enter(&dp->dp_config_rwlock, RW_READER); 41099653d4eSeschrock for (; dd != NULL; dd = dd->dd_parent) { 4117f7322feSeschrock dsl_dir_name(dd, setpoint); 4127f7322feSeschrock 4137f7322feSeschrock for (zap_cursor_init(&zc, mos, dd->dd_phys->dd_props_zapobj); 4147f7322feSeschrock (err = zap_cursor_retrieve(&zc, &za)) == 0; 4157f7322feSeschrock zap_cursor_advance(&zc)) { 4167f7322feSeschrock if (nvlist_lookup_nvlist(*nvp, za.za_name, &prop) == 0) 4177f7322feSeschrock continue; 4187f7322feSeschrock 4197f7322feSeschrock VERIFY(nvlist_alloc(&prop, NV_UNIQUE_NAME, 4207f7322feSeschrock KM_SLEEP) == 0); 4217f7322feSeschrock if (za.za_integer_length == 1) { 4227f7322feSeschrock /* 4237f7322feSeschrock * String property 4247f7322feSeschrock */ 4257f7322feSeschrock tmp = kmem_alloc(za.za_num_integers, KM_SLEEP); 4267f7322feSeschrock err = zap_lookup(mos, 4277f7322feSeschrock dd->dd_phys->dd_props_zapobj, 4287f7322feSeschrock za.za_name, 1, za.za_num_integers, 4297f7322feSeschrock tmp); 4307f7322feSeschrock if (err != 0) { 4317f7322feSeschrock kmem_free(tmp, za.za_num_integers); 4327f7322feSeschrock break; 4337f7322feSeschrock } 4347f7322feSeschrock VERIFY(nvlist_add_string(prop, 4357f7322feSeschrock ZFS_PROP_VALUE, tmp) == 0); 4367f7322feSeschrock kmem_free(tmp, za.za_num_integers); 4377f7322feSeschrock } else { 4387f7322feSeschrock /* 4397f7322feSeschrock * Integer property 4407f7322feSeschrock */ 4417f7322feSeschrock ASSERT(za.za_integer_length == 8); 4427f7322feSeschrock (void) nvlist_add_uint64(prop, ZFS_PROP_VALUE, 4437f7322feSeschrock za.za_first_integer); 4447f7322feSeschrock } 4457f7322feSeschrock 4467f7322feSeschrock VERIFY(nvlist_add_string(prop, 4477f7322feSeschrock ZFS_PROP_SOURCE, setpoint) == 0); 4487f7322feSeschrock VERIFY(nvlist_add_nvlist(*nvp, za.za_name, 4497f7322feSeschrock prop) == 0); 4507f7322feSeschrock nvlist_free(prop); 4517f7322feSeschrock } 4527f7322feSeschrock zap_cursor_fini(&zc); 4537f7322feSeschrock 45499653d4eSeschrock if (err != ENOENT) 4557f7322feSeschrock break; 45699653d4eSeschrock err = 0; 4577f7322feSeschrock } 4587f7322feSeschrock rw_exit(&dp->dp_config_rwlock); 4597f7322feSeschrock 4607f7322feSeschrock return (err); 4617f7322feSeschrock } 462