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*da6c28aaSamw /* 48*da6c28aaSamw * The setonce properties are read-only, BUT they still 49*da6c28aaSamw * have a default value that can be used as the initial 50*da6c28aaSamw * value. 51*da6c28aaSamw */ 52990b4856Slling if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL || 53*da6c28aaSamw (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 71fa9e4066Sahrens static int 7299653d4eSeschrock dsl_prop_get_impl(dsl_dir_t *dd, const char *propname, 73fa9e4066Sahrens int intsz, int numint, void *buf, char *setpoint) 74fa9e4066Sahrens { 7599653d4eSeschrock int err = ENOENT; 76e9dbad6fSeschrock zfs_prop_t prop; 77fa9e4066Sahrens 78fa9e4066Sahrens if (setpoint) 79fa9e4066Sahrens setpoint[0] = '\0'; 80fa9e4066Sahrens 81e9dbad6fSeschrock prop = zfs_name_to_prop(propname); 82e9dbad6fSeschrock 8399653d4eSeschrock /* 8499653d4eSeschrock * Note: dd may be NULL, therefore we shouldn't dereference it 8599653d4eSeschrock * ouside this loop. 8699653d4eSeschrock */ 8799653d4eSeschrock for (; dd != NULL; dd = dd->dd_parent) { 8899653d4eSeschrock objset_t *mos = dd->dd_pool->dp_meta_objset; 8999653d4eSeschrock ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock)); 90fa9e4066Sahrens err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj, 91fa9e4066Sahrens propname, intsz, numint, buf); 92fa9e4066Sahrens if (err != ENOENT) { 93fa9e4066Sahrens if (setpoint) 94fa9e4066Sahrens dsl_dir_name(dd, setpoint); 95fa9e4066Sahrens break; 96fa9e4066Sahrens } 97e9dbad6fSeschrock 98e9dbad6fSeschrock /* 99e9dbad6fSeschrock * Break out of this loop for non-inheritable properties. 100e9dbad6fSeschrock */ 101*da6c28aaSamw if (prop != ZPROP_INVAL && !zfs_prop_inheritable(prop)) 102e9dbad6fSeschrock break; 103fa9e4066Sahrens } 104fa9e4066Sahrens if (err == ENOENT) 105fa9e4066Sahrens err = dodefault(propname, intsz, numint, buf); 106fa9e4066Sahrens 107fa9e4066Sahrens return (err); 108fa9e4066Sahrens } 109fa9e4066Sahrens 110fa9e4066Sahrens /* 111fa9e4066Sahrens * Register interest in the named property. We'll call the callback 112fa9e4066Sahrens * once to notify it of the current property value, and again each time 113fa9e4066Sahrens * the property changes, until this callback is unregistered. 114fa9e4066Sahrens * 115fa9e4066Sahrens * Return 0 on success, errno if the prop is not an integer value. 116fa9e4066Sahrens */ 117fa9e4066Sahrens int 118fa9e4066Sahrens dsl_prop_register(dsl_dataset_t *ds, const char *propname, 119fa9e4066Sahrens dsl_prop_changed_cb_t *callback, void *cbarg) 120fa9e4066Sahrens { 12199653d4eSeschrock dsl_dir_t *dd = ds->ds_dir; 122fa9e4066Sahrens uint64_t value; 123fa9e4066Sahrens dsl_prop_cb_record_t *cbr; 124fa9e4066Sahrens int err; 1251d452cf5Sahrens int need_rwlock; 126fa9e4066Sahrens 1271d452cf5Sahrens need_rwlock = !RW_WRITE_HELD(&dd->dd_pool->dp_config_rwlock); 1281d452cf5Sahrens if (need_rwlock) 1291d452cf5Sahrens rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 130fa9e4066Sahrens 13199653d4eSeschrock err = dsl_prop_get_impl(dd, propname, 8, 1, &value, NULL); 132fa9e4066Sahrens if (err != 0) { 133fa9e4066Sahrens rw_exit(&dd->dd_pool->dp_config_rwlock); 134fa9e4066Sahrens return (err); 135fa9e4066Sahrens } 136fa9e4066Sahrens 137fa9e4066Sahrens cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP); 13899653d4eSeschrock cbr->cbr_ds = ds; 139fa9e4066Sahrens cbr->cbr_propname = kmem_alloc(strlen(propname)+1, KM_SLEEP); 140fa9e4066Sahrens (void) strcpy((char *)cbr->cbr_propname, propname); 141fa9e4066Sahrens cbr->cbr_func = callback; 142fa9e4066Sahrens cbr->cbr_arg = cbarg; 143fa9e4066Sahrens mutex_enter(&dd->dd_lock); 144fa9e4066Sahrens list_insert_head(&dd->dd_prop_cbs, cbr); 145fa9e4066Sahrens mutex_exit(&dd->dd_lock); 146fa9e4066Sahrens 147fa9e4066Sahrens cbr->cbr_func(cbr->cbr_arg, value); 148fa9e4066Sahrens 149ea8dc4b6Seschrock VERIFY(0 == dsl_dir_open_obj(dd->dd_pool, dd->dd_object, 150ea8dc4b6Seschrock NULL, cbr, &dd)); 1511d452cf5Sahrens if (need_rwlock) 1521d452cf5Sahrens rw_exit(&dd->dd_pool->dp_config_rwlock); 153fa9e4066Sahrens /* Leave dataset open until this callback is unregistered */ 154fa9e4066Sahrens return (0); 155fa9e4066Sahrens } 156fa9e4066Sahrens 157fa9e4066Sahrens int 158fa9e4066Sahrens dsl_prop_get_ds(dsl_dir_t *dd, const char *propname, 159fa9e4066Sahrens int intsz, int numints, void *buf, char *setpoint) 160fa9e4066Sahrens { 161fa9e4066Sahrens int err; 162fa9e4066Sahrens 163fa9e4066Sahrens rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 16499653d4eSeschrock err = dsl_prop_get_impl(dd, propname, intsz, numints, buf, setpoint); 165fa9e4066Sahrens rw_exit(&dd->dd_pool->dp_config_rwlock); 166fa9e4066Sahrens 167fa9e4066Sahrens return (err); 168fa9e4066Sahrens } 169fa9e4066Sahrens 170ecd6cf80Smarks /* 171ecd6cf80Smarks * Get property when config lock is already held. 172ecd6cf80Smarks */ 173ecd6cf80Smarks int dsl_prop_get_ds_locked(dsl_dir_t *dd, const char *propname, 174ecd6cf80Smarks int intsz, int numints, void *buf, char *setpoint) 175ecd6cf80Smarks { 176ecd6cf80Smarks ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock)); 177ecd6cf80Smarks return (dsl_prop_get_impl(dd, propname, intsz, numints, buf, setpoint)); 178ecd6cf80Smarks } 179ecd6cf80Smarks 180fa9e4066Sahrens int 181fa9e4066Sahrens dsl_prop_get(const char *ddname, const char *propname, 182fa9e4066Sahrens int intsz, int numints, void *buf, char *setpoint) 183fa9e4066Sahrens { 184fa9e4066Sahrens dsl_dir_t *dd; 185fa9e4066Sahrens const char *tail; 186fa9e4066Sahrens int err; 187fa9e4066Sahrens 188ea8dc4b6Seschrock err = dsl_dir_open(ddname, FTAG, &dd, &tail); 189ea8dc4b6Seschrock if (err) 190ea8dc4b6Seschrock return (err); 191fa9e4066Sahrens if (tail && tail[0] != '@') { 192fa9e4066Sahrens dsl_dir_close(dd, FTAG); 193fa9e4066Sahrens return (ENOENT); 194fa9e4066Sahrens } 195fa9e4066Sahrens 196fa9e4066Sahrens err = dsl_prop_get_ds(dd, propname, intsz, numints, buf, setpoint); 197fa9e4066Sahrens 198fa9e4066Sahrens dsl_dir_close(dd, FTAG); 199fa9e4066Sahrens return (err); 200fa9e4066Sahrens } 201fa9e4066Sahrens 202fa9e4066Sahrens /* 203fa9e4066Sahrens * Get the current property value. It may have changed by the time this 204fa9e4066Sahrens * function returns, so it is NOT safe to follow up with 205fa9e4066Sahrens * dsl_prop_register() and assume that the value has not changed in 206fa9e4066Sahrens * between. 207fa9e4066Sahrens * 208fa9e4066Sahrens * Return 0 on success, ENOENT if ddname is invalid. 209fa9e4066Sahrens */ 210fa9e4066Sahrens int 211fa9e4066Sahrens dsl_prop_get_integer(const char *ddname, const char *propname, 212fa9e4066Sahrens uint64_t *valuep, char *setpoint) 213fa9e4066Sahrens { 214fa9e4066Sahrens return (dsl_prop_get(ddname, propname, 8, 1, valuep, setpoint)); 215fa9e4066Sahrens } 216fa9e4066Sahrens 217fa9e4066Sahrens /* 218fa9e4066Sahrens * Unregister this callback. Return 0 on success, ENOENT if ddname is 219fa9e4066Sahrens * invalid, ENOMSG if no matching callback registered. 220fa9e4066Sahrens */ 221fa9e4066Sahrens int 222fa9e4066Sahrens dsl_prop_unregister(dsl_dataset_t *ds, const char *propname, 223fa9e4066Sahrens dsl_prop_changed_cb_t *callback, void *cbarg) 224fa9e4066Sahrens { 22599653d4eSeschrock dsl_dir_t *dd = ds->ds_dir; 226fa9e4066Sahrens dsl_prop_cb_record_t *cbr; 227fa9e4066Sahrens 228fa9e4066Sahrens mutex_enter(&dd->dd_lock); 229fa9e4066Sahrens for (cbr = list_head(&dd->dd_prop_cbs); 230fa9e4066Sahrens cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { 23199653d4eSeschrock if (cbr->cbr_ds == ds && 232fa9e4066Sahrens cbr->cbr_func == callback && 23399653d4eSeschrock cbr->cbr_arg == cbarg && 23499653d4eSeschrock strcmp(cbr->cbr_propname, propname) == 0) 235fa9e4066Sahrens break; 236fa9e4066Sahrens } 237fa9e4066Sahrens 238fa9e4066Sahrens if (cbr == NULL) { 239fa9e4066Sahrens mutex_exit(&dd->dd_lock); 240fa9e4066Sahrens return (ENOMSG); 241fa9e4066Sahrens } 242fa9e4066Sahrens 243fa9e4066Sahrens list_remove(&dd->dd_prop_cbs, cbr); 244fa9e4066Sahrens mutex_exit(&dd->dd_lock); 245fa9e4066Sahrens kmem_free((void*)cbr->cbr_propname, strlen(cbr->cbr_propname)+1); 246fa9e4066Sahrens kmem_free(cbr, sizeof (dsl_prop_cb_record_t)); 247fa9e4066Sahrens 248fa9e4066Sahrens /* Clean up from dsl_prop_register */ 249fa9e4066Sahrens dsl_dir_close(dd, cbr); 250fa9e4066Sahrens return (0); 251fa9e4066Sahrens } 252fa9e4066Sahrens 25399653d4eSeschrock /* 25499653d4eSeschrock * Return the number of callbacks that are registered for this dataset. 25599653d4eSeschrock */ 25699653d4eSeschrock int 25799653d4eSeschrock dsl_prop_numcb(dsl_dataset_t *ds) 25899653d4eSeschrock { 25999653d4eSeschrock dsl_dir_t *dd = ds->ds_dir; 26099653d4eSeschrock dsl_prop_cb_record_t *cbr; 26199653d4eSeschrock int num = 0; 26299653d4eSeschrock 26399653d4eSeschrock mutex_enter(&dd->dd_lock); 26499653d4eSeschrock for (cbr = list_head(&dd->dd_prop_cbs); 26599653d4eSeschrock cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { 26699653d4eSeschrock if (cbr->cbr_ds == ds) 26799653d4eSeschrock num++; 26899653d4eSeschrock } 26999653d4eSeschrock mutex_exit(&dd->dd_lock); 27099653d4eSeschrock 27199653d4eSeschrock return (num); 27299653d4eSeschrock } 27399653d4eSeschrock 274fa9e4066Sahrens static void 275fa9e4066Sahrens dsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj, 276fa9e4066Sahrens const char *propname, uint64_t value, int first) 277fa9e4066Sahrens { 278fa9e4066Sahrens dsl_dir_t *dd; 279fa9e4066Sahrens dsl_prop_cb_record_t *cbr; 280fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 2811d452cf5Sahrens zap_cursor_t zc; 2821d452cf5Sahrens zap_attribute_t za; 283fa9e4066Sahrens int err; 284fa9e4066Sahrens 285fa9e4066Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 286ea8dc4b6Seschrock err = dsl_dir_open_obj(dp, ddobj, NULL, FTAG, &dd); 287ea8dc4b6Seschrock if (err) 288ea8dc4b6Seschrock return; 289fa9e4066Sahrens 290fa9e4066Sahrens if (!first) { 291fa9e4066Sahrens /* 292fa9e4066Sahrens * If the prop is set here, then this change is not 293fa9e4066Sahrens * being inherited here or below; stop the recursion. 294fa9e4066Sahrens */ 295fa9e4066Sahrens err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj, propname, 296fa9e4066Sahrens 8, 1, &value); 297fa9e4066Sahrens if (err == 0) { 298fa9e4066Sahrens dsl_dir_close(dd, FTAG); 299fa9e4066Sahrens return; 300fa9e4066Sahrens } 301fa9e4066Sahrens ASSERT3U(err, ==, ENOENT); 302fa9e4066Sahrens } 303fa9e4066Sahrens 304fa9e4066Sahrens mutex_enter(&dd->dd_lock); 305fa9e4066Sahrens for (cbr = list_head(&dd->dd_prop_cbs); 306fa9e4066Sahrens cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { 307fa9e4066Sahrens if (strcmp(cbr->cbr_propname, propname) == 0) { 308fa9e4066Sahrens cbr->cbr_func(cbr->cbr_arg, value); 309fa9e4066Sahrens } 310fa9e4066Sahrens } 311fa9e4066Sahrens mutex_exit(&dd->dd_lock); 312fa9e4066Sahrens 3131d452cf5Sahrens for (zap_cursor_init(&zc, mos, 3141d452cf5Sahrens dd->dd_phys->dd_child_dir_zapobj); 3151d452cf5Sahrens zap_cursor_retrieve(&zc, &za) == 0; 3161d452cf5Sahrens zap_cursor_advance(&zc)) { 3171d452cf5Sahrens /* XXX recursion could blow stack; esp. za! */ 3181d452cf5Sahrens dsl_prop_changed_notify(dp, za.za_first_integer, 3191d452cf5Sahrens propname, value, FALSE); 320fa9e4066Sahrens } 3211d452cf5Sahrens zap_cursor_fini(&zc); 322fa9e4066Sahrens dsl_dir_close(dd, FTAG); 323fa9e4066Sahrens } 324fa9e4066Sahrens 325fa9e4066Sahrens struct prop_set_arg { 326fa9e4066Sahrens const char *name; 327fa9e4066Sahrens int intsz; 328fa9e4066Sahrens int numints; 329fa9e4066Sahrens const void *buf; 330fa9e4066Sahrens }; 331fa9e4066Sahrens 3321d452cf5Sahrens 3331d452cf5Sahrens static void 334ecd6cf80Smarks dsl_prop_set_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 335fa9e4066Sahrens { 3361d452cf5Sahrens dsl_dir_t *dd = arg1; 3371d452cf5Sahrens struct prop_set_arg *psa = arg2; 338fa9e4066Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 339fa9e4066Sahrens uint64_t zapobj = dd->dd_phys->dd_props_zapobj; 340fa9e4066Sahrens uint64_t intval; 3411d452cf5Sahrens int isint; 342ecd6cf80Smarks char valbuf[32]; 343ecd6cf80Smarks char *valstr; 344fa9e4066Sahrens 345fa9e4066Sahrens isint = (dodefault(psa->name, 8, 1, &intval) == 0); 346fa9e4066Sahrens 347fa9e4066Sahrens if (psa->numints == 0) { 3481d452cf5Sahrens int err = zap_remove(mos, zapobj, psa->name, tx); 3491d452cf5Sahrens ASSERT(err == 0 || err == ENOENT); 3501d452cf5Sahrens if (isint) { 3511d452cf5Sahrens VERIFY(0 == dsl_prop_get_impl(dd->dd_parent, 3521d452cf5Sahrens psa->name, 8, 1, &intval, NULL)); 353fa9e4066Sahrens } 354fa9e4066Sahrens } else { 3551d452cf5Sahrens VERIFY(0 == zap_update(mos, zapobj, psa->name, 3561d452cf5Sahrens psa->intsz, psa->numints, psa->buf, tx)); 357fa9e4066Sahrens if (isint) 358fa9e4066Sahrens intval = *(uint64_t *)psa->buf; 359fa9e4066Sahrens } 360fa9e4066Sahrens 3611d452cf5Sahrens if (isint) { 362fa9e4066Sahrens dsl_prop_changed_notify(dd->dd_pool, 363fa9e4066Sahrens dd->dd_object, psa->name, intval, TRUE); 364fa9e4066Sahrens } 365ecd6cf80Smarks if (isint) { 366ecd6cf80Smarks (void) snprintf(valbuf, sizeof (valbuf), 367ecd6cf80Smarks "%lld", (longlong_t)intval); 368ecd6cf80Smarks valstr = valbuf; 369ecd6cf80Smarks } else { 370ecd6cf80Smarks valstr = (char *)psa->buf; 371ecd6cf80Smarks } 372ecd6cf80Smarks spa_history_internal_log((psa->numints == 0) ? LOG_DS_INHERIT : 373ecd6cf80Smarks LOG_DS_PROPSET, dd->dd_pool->dp_spa, tx, cr, 374ecd6cf80Smarks "%s=%s dataset = %llu", psa->name, valstr, 375ecd6cf80Smarks dd->dd_phys->dd_head_dataset_obj); 376fa9e4066Sahrens } 377fa9e4066Sahrens 378a2eea2e1Sahrens int 379a2eea2e1Sahrens dsl_prop_set_dd(dsl_dir_t *dd, const char *propname, 380a2eea2e1Sahrens int intsz, int numints, const void *buf) 381a2eea2e1Sahrens { 382a2eea2e1Sahrens struct prop_set_arg psa; 383a2eea2e1Sahrens 384a2eea2e1Sahrens psa.name = propname; 385a2eea2e1Sahrens psa.intsz = intsz; 386a2eea2e1Sahrens psa.numints = numints; 387a2eea2e1Sahrens psa.buf = buf; 388a2eea2e1Sahrens 389a2eea2e1Sahrens return (dsl_sync_task_do(dd->dd_pool, 390a2eea2e1Sahrens NULL, dsl_prop_set_sync, dd, &psa, 2)); 391a2eea2e1Sahrens } 392a2eea2e1Sahrens 393fa9e4066Sahrens int 394fa9e4066Sahrens dsl_prop_set(const char *ddname, const char *propname, 395fa9e4066Sahrens int intsz, int numints, const void *buf) 396fa9e4066Sahrens { 397fa9e4066Sahrens dsl_dir_t *dd; 398fa9e4066Sahrens int err; 399fa9e4066Sahrens 400455d5089Sahrens /* 401455d5089Sahrens * We must do these checks before we get to the syncfunc, since 402455d5089Sahrens * it can't fail. 403455d5089Sahrens */ 404455d5089Sahrens if (strlen(propname) >= ZAP_MAXNAMELEN) 405455d5089Sahrens return (ENAMETOOLONG); 406455d5089Sahrens if (intsz * numints >= ZAP_MAXVALUELEN) 407455d5089Sahrens return (E2BIG); 408455d5089Sahrens 409ea8dc4b6Seschrock err = dsl_dir_open(ddname, FTAG, &dd, NULL); 410ea8dc4b6Seschrock if (err) 411ea8dc4b6Seschrock return (err); 412a2eea2e1Sahrens err = dsl_prop_set_dd(dd, propname, intsz, numints, buf); 413fa9e4066Sahrens dsl_dir_close(dd, FTAG); 414fa9e4066Sahrens return (err); 415fa9e4066Sahrens } 4167f7322feSeschrock 4177f7322feSeschrock /* 4187f7322feSeschrock * Iterate over all properties for this dataset and return them in an nvlist. 4197f7322feSeschrock */ 4207f7322feSeschrock int 4217f7322feSeschrock dsl_prop_get_all(objset_t *os, nvlist_t **nvp) 4227f7322feSeschrock { 4237f7322feSeschrock dsl_dataset_t *ds = os->os->os_dsl_dataset; 42499653d4eSeschrock dsl_dir_t *dd = ds->ds_dir; 425*da6c28aaSamw boolean_t snapshot; 4267f7322feSeschrock int err = 0; 4277f7322feSeschrock dsl_pool_t *dp; 4287f7322feSeschrock objset_t *mos; 4297f7322feSeschrock 430*da6c28aaSamw snapshot = dsl_dataset_is_snapshot(ds); 4317f7322feSeschrock 4327f7322feSeschrock VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); 4337f7322feSeschrock 4347f7322feSeschrock dp = dd->dd_pool; 4357f7322feSeschrock mos = dp->dp_meta_objset; 4367f7322feSeschrock 4377f7322feSeschrock rw_enter(&dp->dp_config_rwlock, RW_READER); 43899653d4eSeschrock for (; dd != NULL; dd = dd->dd_parent) { 439a2eea2e1Sahrens char setpoint[MAXNAMELEN]; 440a2eea2e1Sahrens zap_cursor_t zc; 441a2eea2e1Sahrens zap_attribute_t za; 442a2eea2e1Sahrens 4437f7322feSeschrock dsl_dir_name(dd, setpoint); 4447f7322feSeschrock 4457f7322feSeschrock for (zap_cursor_init(&zc, mos, dd->dd_phys->dd_props_zapobj); 4467f7322feSeschrock (err = zap_cursor_retrieve(&zc, &za)) == 0; 4477f7322feSeschrock zap_cursor_advance(&zc)) { 448a2eea2e1Sahrens nvlist_t *propval; 449a2eea2e1Sahrens zfs_prop_t prop; 450e9dbad6fSeschrock /* 451e9dbad6fSeschrock * Skip non-inheritable properties. 452e9dbad6fSeschrock */ 453e9dbad6fSeschrock if ((prop = zfs_name_to_prop(za.za_name)) != 454990b4856Slling ZPROP_INVAL && !zfs_prop_inheritable(prop) && 455e9dbad6fSeschrock dd != ds->ds_dir) 456e9dbad6fSeschrock continue; 457e9dbad6fSeschrock 458*da6c28aaSamw if (snapshot && 459*da6c28aaSamw !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT)) 460*da6c28aaSamw continue; 461*da6c28aaSamw 462e9dbad6fSeschrock if (nvlist_lookup_nvlist(*nvp, za.za_name, 463e9dbad6fSeschrock &propval) == 0) 4647f7322feSeschrock continue; 4657f7322feSeschrock 466e9dbad6fSeschrock VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, 4677f7322feSeschrock KM_SLEEP) == 0); 4687f7322feSeschrock if (za.za_integer_length == 1) { 4697f7322feSeschrock /* 4707f7322feSeschrock * String property 4717f7322feSeschrock */ 472a2eea2e1Sahrens char *tmp = kmem_alloc(za.za_num_integers, 473a2eea2e1Sahrens KM_SLEEP); 4747f7322feSeschrock err = zap_lookup(mos, 4757f7322feSeschrock dd->dd_phys->dd_props_zapobj, 4767f7322feSeschrock za.za_name, 1, za.za_num_integers, 4777f7322feSeschrock tmp); 4787f7322feSeschrock if (err != 0) { 4797f7322feSeschrock kmem_free(tmp, za.za_num_integers); 4807f7322feSeschrock break; 4817f7322feSeschrock } 482990b4856Slling VERIFY(nvlist_add_string(propval, ZPROP_VALUE, 483990b4856Slling tmp) == 0); 4847f7322feSeschrock kmem_free(tmp, za.za_num_integers); 4857f7322feSeschrock } else { 4867f7322feSeschrock /* 4877f7322feSeschrock * Integer property 4887f7322feSeschrock */ 4897f7322feSeschrock ASSERT(za.za_integer_length == 8); 490990b4856Slling (void) nvlist_add_uint64(propval, ZPROP_VALUE, 491990b4856Slling za.za_first_integer); 4927f7322feSeschrock } 4937f7322feSeschrock 494990b4856Slling VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, 495990b4856Slling setpoint) == 0); 4967f7322feSeschrock VERIFY(nvlist_add_nvlist(*nvp, za.za_name, 497e9dbad6fSeschrock propval) == 0); 498e9dbad6fSeschrock nvlist_free(propval); 4997f7322feSeschrock } 5007f7322feSeschrock zap_cursor_fini(&zc); 5017f7322feSeschrock 50299653d4eSeschrock if (err != ENOENT) 5037f7322feSeschrock break; 50499653d4eSeschrock err = 0; 5057f7322feSeschrock } 5067f7322feSeschrock rw_exit(&dp->dp_config_rwlock); 5077f7322feSeschrock 5087f7322feSeschrock return (err); 5097f7322feSeschrock } 510a2eea2e1Sahrens 511a2eea2e1Sahrens void 512a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nvlist_t *nv, zfs_prop_t prop, uint64_t value) 513a2eea2e1Sahrens { 514a2eea2e1Sahrens nvlist_t *propval; 515a2eea2e1Sahrens 516a2eea2e1Sahrens VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 517990b4856Slling VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0); 518a2eea2e1Sahrens VERIFY(nvlist_add_nvlist(nv, zfs_prop_to_name(prop), propval) == 0); 519a2eea2e1Sahrens nvlist_free(propval); 520a2eea2e1Sahrens } 521a2eea2e1Sahrens 522a2eea2e1Sahrens void 523a2eea2e1Sahrens dsl_prop_nvlist_add_string(nvlist_t *nv, zfs_prop_t prop, const char *value) 524a2eea2e1Sahrens { 525a2eea2e1Sahrens nvlist_t *propval; 526a2eea2e1Sahrens 527a2eea2e1Sahrens VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 528990b4856Slling VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0); 529a2eea2e1Sahrens VERIFY(nvlist_add_nvlist(nv, zfs_prop_to_name(prop), propval) == 0); 530a2eea2e1Sahrens nvlist_free(propval); 531a2eea2e1Sahrens } 532