Home | History | Annotate | Line # | Download | only in zfs
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
     23  * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
     24  * Copyright 2015, Joyent, Inc.
     25  */
     26 
     27 #include <sys/zfs_context.h>
     28 #include <sys/dmu.h>
     29 #include <sys/dmu_objset.h>
     30 #include <sys/dmu_tx.h>
     31 #include <sys/dsl_dataset.h>
     32 #include <sys/dsl_dir.h>
     33 #include <sys/dsl_prop.h>
     34 #include <sys/dsl_synctask.h>
     35 #include <sys/spa.h>
     36 #include <sys/zap.h>
     37 #include <sys/fs/zfs.h>
     38 
     39 #include "zfs_prop.h"
     40 
     41 #define	ZPROP_INHERIT_SUFFIX "$inherit"
     42 #define	ZPROP_RECVD_SUFFIX "$recvd"
     43 
     44 static int
     45 dodefault(zfs_prop_t prop, int intsz, int numints, void *buf)
     46 {
     47 	/*
     48 	 * The setonce properties are read-only, BUT they still
     49 	 * have a default value that can be used as the initial
     50 	 * value.
     51 	 */
     52 	if (prop == ZPROP_INVAL ||
     53 	    (zfs_prop_readonly(prop) && !zfs_prop_setonce(prop)))
     54 		return (SET_ERROR(ENOENT));
     55 
     56 	if (zfs_prop_get_type(prop) == PROP_TYPE_STRING) {
     57 		if (zfs_prop_default_string(prop) == NULL)
     58 			return (SET_ERROR(ENOENT));
     59 		if (intsz != 1)
     60 			return (SET_ERROR(EOVERFLOW));
     61 		(void) strncpy(buf, zfs_prop_default_string(prop),
     62 		    numints);
     63 	} else {
     64 		if (intsz != 8 || numints < 1)
     65 			return (SET_ERROR(EOVERFLOW));
     66 
     67 		*(uint64_t *)buf = zfs_prop_default_numeric(prop);
     68 	}
     69 
     70 	return (0);
     71 }
     72 
     73 int
     74 dsl_prop_get_dd(dsl_dir_t *dd, const char *propname,
     75     int intsz, int numints, void *buf, char *setpoint, boolean_t snapshot)
     76 {
     77 	int err = ENOENT;
     78 	dsl_dir_t *target = dd;
     79 	objset_t *mos = dd->dd_pool->dp_meta_objset;
     80 	zfs_prop_t prop;
     81 	boolean_t inheritable;
     82 	boolean_t inheriting = B_FALSE;
     83 	char *inheritstr;
     84 	char *recvdstr;
     85 
     86 	ASSERT(dsl_pool_config_held(dd->dd_pool));
     87 
     88 	if (setpoint)
     89 		setpoint[0] = '\0';
     90 
     91 	prop = zfs_name_to_prop(propname);
     92 	inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop));
     93 	inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX);
     94 	recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX);
     95 
     96 	/*
     97 	 * Note: dd may become NULL, therefore we shouldn't dereference it
     98 	 * after this loop.
     99 	 */
    100 	for (; dd != NULL; dd = dd->dd_parent) {
    101 		if (dd != target || snapshot) {
    102 			if (!inheritable)
    103 				break;
    104 			inheriting = B_TRUE;
    105 		}
    106 
    107 		/* Check for a local value. */
    108 		err = zap_lookup(mos, dsl_dir_phys(dd)->dd_props_zapobj,
    109 		    propname, intsz, numints, buf);
    110 		if (err != ENOENT) {
    111 			if (setpoint != NULL && err == 0)
    112 				dsl_dir_name(dd, setpoint);
    113 			break;
    114 		}
    115 
    116 		/*
    117 		 * Skip the check for a received value if there is an explicit
    118 		 * inheritance entry.
    119 		 */
    120 		err = zap_contains(mos, dsl_dir_phys(dd)->dd_props_zapobj,
    121 		    inheritstr);
    122 		if (err != 0 && err != ENOENT)
    123 			break;
    124 
    125 		if (err == ENOENT) {
    126 			/* Check for a received value. */
    127 			err = zap_lookup(mos, dsl_dir_phys(dd)->dd_props_zapobj,
    128 			    recvdstr, intsz, numints, buf);
    129 			if (err != ENOENT) {
    130 				if (setpoint != NULL && err == 0) {
    131 					if (inheriting) {
    132 						dsl_dir_name(dd, setpoint);
    133 					} else {
    134 						(void) strcpy(setpoint,
    135 						    ZPROP_SOURCE_VAL_RECVD);
    136 					}
    137 				}
    138 				break;
    139 			}
    140 		}
    141 
    142 		/*
    143 		 * If we found an explicit inheritance entry, err is zero even
    144 		 * though we haven't yet found the value, so reinitializing err
    145 		 * at the end of the loop (instead of at the beginning) ensures
    146 		 * that err has a valid post-loop value.
    147 		 */
    148 		err = SET_ERROR(ENOENT);
    149 	}
    150 
    151 	if (err == ENOENT)
    152 		err = dodefault(prop, intsz, numints, buf);
    153 
    154 	strfree(inheritstr);
    155 	strfree(recvdstr);
    156 
    157 	return (err);
    158 }
    159 
    160 int
    161 dsl_prop_get_ds(dsl_dataset_t *ds, const char *propname,
    162     int intsz, int numints, void *buf, char *setpoint)
    163 {
    164 	zfs_prop_t prop = zfs_name_to_prop(propname);
    165 	boolean_t inheritable;
    166 	uint64_t zapobj;
    167 
    168 	ASSERT(dsl_pool_config_held(ds->ds_dir->dd_pool));
    169 	inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop));
    170 	zapobj = dsl_dataset_phys(ds)->ds_props_obj;
    171 
    172 	if (zapobj != 0) {
    173 		objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
    174 		int err;
    175 
    176 		ASSERT(ds->ds_is_snapshot);
    177 
    178 		/* Check for a local value. */
    179 		err = zap_lookup(mos, zapobj, propname, intsz, numints, buf);
    180 		if (err != ENOENT) {
    181 			if (setpoint != NULL && err == 0)
    182 				dsl_dataset_name(ds, setpoint);
    183 			return (err);
    184 		}
    185 
    186 		/*
    187 		 * Skip the check for a received value if there is an explicit
    188 		 * inheritance entry.
    189 		 */
    190 		if (inheritable) {
    191 			char *inheritstr = kmem_asprintf("%s%s", propname,
    192 			    ZPROP_INHERIT_SUFFIX);
    193 			err = zap_contains(mos, zapobj, inheritstr);
    194 			strfree(inheritstr);
    195 			if (err != 0 && err != ENOENT)
    196 				return (err);
    197 		}
    198 
    199 		if (err == ENOENT) {
    200 			/* Check for a received value. */
    201 			char *recvdstr = kmem_asprintf("%s%s", propname,
    202 			    ZPROP_RECVD_SUFFIX);
    203 			err = zap_lookup(mos, zapobj, recvdstr,
    204 			    intsz, numints, buf);
    205 			strfree(recvdstr);
    206 			if (err != ENOENT) {
    207 				if (setpoint != NULL && err == 0)
    208 					(void) strcpy(setpoint,
    209 					    ZPROP_SOURCE_VAL_RECVD);
    210 				return (err);
    211 			}
    212 		}
    213 	}
    214 
    215 	return (dsl_prop_get_dd(ds->ds_dir, propname,
    216 	    intsz, numints, buf, setpoint, ds->ds_is_snapshot));
    217 }
    218 
    219 static dsl_prop_record_t *
    220 dsl_prop_record_find(dsl_dir_t *dd, const char *propname)
    221 {
    222 	dsl_prop_record_t *pr = NULL;
    223 
    224 	ASSERT(MUTEX_HELD(&dd->dd_lock));
    225 
    226 	for (pr = list_head(&dd->dd_props);
    227 	    pr != NULL; pr = list_next(&dd->dd_props, pr)) {
    228 		if (strcmp(pr->pr_propname, propname) == 0)
    229 			break;
    230 	}
    231 
    232 	return (pr);
    233 }
    234 
    235 static dsl_prop_record_t *
    236 dsl_prop_record_create(dsl_dir_t *dd, const char *propname)
    237 {
    238 	dsl_prop_record_t *pr;
    239 
    240 	ASSERT(MUTEX_HELD(&dd->dd_lock));
    241 
    242 	pr = kmem_alloc(sizeof (dsl_prop_record_t), KM_SLEEP);
    243 	pr->pr_propname = spa_strdup(propname);
    244 	list_create(&pr->pr_cbs, sizeof (dsl_prop_cb_record_t),
    245 	    offsetof(dsl_prop_cb_record_t, cbr_pr_node));
    246 	list_insert_head(&dd->dd_props, pr);
    247 
    248 	return (pr);
    249 }
    250 
    251 void
    252 dsl_prop_init(dsl_dir_t *dd)
    253 {
    254 	list_create(&dd->dd_props, sizeof (dsl_prop_record_t),
    255 	    offsetof(dsl_prop_record_t, pr_node));
    256 }
    257 
    258 void
    259 dsl_prop_fini(dsl_dir_t *dd)
    260 {
    261 	dsl_prop_record_t *pr;
    262 
    263 	while ((pr = list_remove_head(&dd->dd_props)) != NULL) {
    264 		list_destroy(&pr->pr_cbs);
    265 		strfree((char *)pr->pr_propname);
    266 		kmem_free(pr, sizeof (dsl_prop_record_t));
    267 	}
    268 	list_destroy(&dd->dd_props);
    269 }
    270 
    271 /*
    272  * Register interest in the named property.  We'll call the callback
    273  * once to notify it of the current property value, and again each time
    274  * the property changes, until this callback is unregistered.
    275  *
    276  * Return 0 on success, errno if the prop is not an integer value.
    277  */
    278 int
    279 dsl_prop_register(dsl_dataset_t *ds, const char *propname,
    280     dsl_prop_changed_cb_t *callback, void *cbarg)
    281 {
    282 	dsl_dir_t *dd = ds->ds_dir;
    283 	dsl_pool_t *dp = dd->dd_pool;
    284 	uint64_t value;
    285 	dsl_prop_record_t *pr;
    286 	dsl_prop_cb_record_t *cbr;
    287 	int err;
    288 
    289 	ASSERT(dsl_pool_config_held(dp));
    290 
    291 	err = dsl_prop_get_int_ds(ds, propname, &value);
    292 	if (err != 0)
    293 		return (err);
    294 
    295 	cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP);
    296 	cbr->cbr_ds = ds;
    297 	cbr->cbr_func = callback;
    298 	cbr->cbr_arg = cbarg;
    299 
    300 	mutex_enter(&dd->dd_lock);
    301 	pr = dsl_prop_record_find(dd, propname);
    302 	if (pr == NULL)
    303 		pr = dsl_prop_record_create(dd, propname);
    304 	cbr->cbr_pr = pr;
    305 	list_insert_head(&pr->pr_cbs, cbr);
    306 	list_insert_head(&ds->ds_prop_cbs, cbr);
    307 	mutex_exit(&dd->dd_lock);
    308 
    309 	cbr->cbr_func(cbr->cbr_arg, value);
    310 	return (0);
    311 }
    312 
    313 int
    314 dsl_prop_get(const char *dsname, const char *propname,
    315     int intsz, int numints, void *buf, char *setpoint)
    316 {
    317 	objset_t *os;
    318 	int error;
    319 
    320 	error = dmu_objset_hold(dsname, FTAG, &os);
    321 	if (error != 0)
    322 		return (error);
    323 
    324 	error = dsl_prop_get_ds(dmu_objset_ds(os), propname,
    325 	    intsz, numints, buf, setpoint);
    326 
    327 	dmu_objset_rele(os, FTAG);
    328 	return (error);
    329 }
    330 
    331 /*
    332  * Get the current property value.  It may have changed by the time this
    333  * function returns, so it is NOT safe to follow up with
    334  * dsl_prop_register() and assume that the value has not changed in
    335  * between.
    336  *
    337  * Return 0 on success, ENOENT if ddname is invalid.
    338  */
    339 int
    340 dsl_prop_get_integer(const char *ddname, const char *propname,
    341     uint64_t *valuep, char *setpoint)
    342 {
    343 	return (dsl_prop_get(ddname, propname, 8, 1, valuep, setpoint));
    344 }
    345 
    346 int
    347 dsl_prop_get_int_ds(dsl_dataset_t *ds, const char *propname,
    348     uint64_t *valuep)
    349 {
    350 	return (dsl_prop_get_ds(ds, propname, 8, 1, valuep, NULL));
    351 }
    352 
    353 /*
    354  * Predict the effective value of the given special property if it were set with
    355  * the given value and source. This is not a general purpose function. It exists
    356  * only to handle the special requirements of the quota and reservation
    357  * properties. The fact that these properties are non-inheritable greatly
    358  * simplifies the prediction logic.
    359  *
    360  * Returns 0 on success, a positive error code on failure, or -1 if called with
    361  * a property not handled by this function.
    362  */
    363 int
    364 dsl_prop_predict(dsl_dir_t *dd, const char *propname,
    365     zprop_source_t source, uint64_t value, uint64_t *newvalp)
    366 {
    367 	zfs_prop_t prop = zfs_name_to_prop(propname);
    368 	objset_t *mos;
    369 	uint64_t zapobj;
    370 	uint64_t version;
    371 	char *recvdstr;
    372 	int err = 0;
    373 
    374 	switch (prop) {
    375 	case ZFS_PROP_QUOTA:
    376 	case ZFS_PROP_RESERVATION:
    377 	case ZFS_PROP_REFQUOTA:
    378 	case ZFS_PROP_REFRESERVATION:
    379 		break;
    380 	default:
    381 		return (-1);
    382 	}
    383 
    384 	mos = dd->dd_pool->dp_meta_objset;
    385 	zapobj = dsl_dir_phys(dd)->dd_props_zapobj;
    386 	recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX);
    387 
    388 	version = spa_version(dd->dd_pool->dp_spa);
    389 	if (version < SPA_VERSION_RECVD_PROPS) {
    390 		if (source & ZPROP_SRC_NONE)
    391 			source = ZPROP_SRC_NONE;
    392 		else if (source & ZPROP_SRC_RECEIVED)
    393 			source = ZPROP_SRC_LOCAL;
    394 	}
    395 
    396 	switch (source) {
    397 	case ZPROP_SRC_NONE:
    398 		/* Revert to the received value, if any. */
    399 		err = zap_lookup(mos, zapobj, recvdstr, 8, 1, newvalp);
    400 		if (err == ENOENT)
    401 			*newvalp = 0;
    402 		break;
    403 	case ZPROP_SRC_LOCAL:
    404 		*newvalp = value;
    405 		break;
    406 	case ZPROP_SRC_RECEIVED:
    407 		/*
    408 		 * If there's no local setting, then the new received value will
    409 		 * be the effective value.
    410 		 */
    411 		err = zap_lookup(mos, zapobj, propname, 8, 1, newvalp);
    412 		if (err == ENOENT)
    413 			*newvalp = value;
    414 		break;
    415 	case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED):
    416 		/*
    417 		 * We're clearing the received value, so the local setting (if
    418 		 * it exists) remains the effective value.
    419 		 */
    420 		err = zap_lookup(mos, zapobj, propname, 8, 1, newvalp);
    421 		if (err == ENOENT)
    422 			*newvalp = 0;
    423 		break;
    424 	default:
    425 		panic("unexpected property source: %d", source);
    426 	}
    427 
    428 	strfree(recvdstr);
    429 
    430 	if (err == ENOENT)
    431 		return (0);
    432 
    433 	return (err);
    434 }
    435 
    436 /*
    437  * Unregister all callbacks that are registered with the
    438  * given callback argument.
    439  */
    440 void
    441 dsl_prop_unregister_all(dsl_dataset_t *ds, void *cbarg)
    442 {
    443 	dsl_prop_cb_record_t *cbr, *next_cbr;
    444 
    445 	dsl_dir_t *dd = ds->ds_dir;
    446 
    447 	mutex_enter(&dd->dd_lock);
    448 	next_cbr = list_head(&ds->ds_prop_cbs);
    449 	while (next_cbr != NULL) {
    450 		cbr = next_cbr;
    451 		next_cbr = list_next(&ds->ds_prop_cbs, cbr);
    452 		if (cbr->cbr_arg == cbarg) {
    453 			list_remove(&ds->ds_prop_cbs, cbr);
    454 			list_remove(&cbr->cbr_pr->pr_cbs, cbr);
    455 			kmem_free(cbr, sizeof (dsl_prop_cb_record_t));
    456 		}
    457 	}
    458 	mutex_exit(&dd->dd_lock);
    459 }
    460 
    461 boolean_t
    462 dsl_prop_hascb(dsl_dataset_t *ds)
    463 {
    464 	return (!list_is_empty(&ds->ds_prop_cbs));
    465 }
    466 
    467 /* ARGSUSED */
    468 static int
    469 dsl_prop_notify_all_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg)
    470 {
    471 	dsl_dir_t *dd = ds->ds_dir;
    472 	dsl_prop_record_t *pr;
    473 	dsl_prop_cb_record_t *cbr;
    474 
    475 	mutex_enter(&dd->dd_lock);
    476 	for (pr = list_head(&dd->dd_props);
    477 	    pr; pr = list_next(&dd->dd_props, pr)) {
    478 		for (cbr = list_head(&pr->pr_cbs); cbr;
    479 		    cbr = list_next(&pr->pr_cbs, cbr)) {
    480 			uint64_t value;
    481 
    482 			/*
    483 			 * Callback entries do not have holds on their
    484 			 * datasets so that datasets with registered
    485 			 * callbacks are still eligible for eviction.
    486 			 * Unlike operations to update properties on a
    487 			 * single dataset, we are performing a recursive
    488 			 * descent of related head datasets.  The caller
    489 			 * of this function only has a dataset hold on
    490 			 * the passed in head dataset, not the snapshots
    491 			 * associated with this dataset.  Without a hold,
    492 			 * the dataset pointer within callback records
    493 			 * for snapshots can be invalidated by eviction
    494 			 * at any time.
    495 			 *
    496 			 * Use dsl_dataset_try_add_ref() to verify
    497 			 * that the dataset for a snapshot has not
    498 			 * begun eviction processing and to prevent
    499 			 * eviction from occurring for the duration of
    500 			 * the callback.  If the hold attempt fails,
    501 			 * this object is already being evicted and the
    502 			 * callback can be safely ignored.
    503 			 */
    504 			if (ds != cbr->cbr_ds &&
    505 			    !dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG))
    506 				continue;
    507 
    508 			if (dsl_prop_get_ds(cbr->cbr_ds,
    509 			    cbr->cbr_pr->pr_propname, sizeof (value), 1,
    510 			    &value, NULL) == 0)
    511 				cbr->cbr_func(cbr->cbr_arg, value);
    512 
    513 			if (ds != cbr->cbr_ds)
    514 				dsl_dataset_rele(cbr->cbr_ds, FTAG);
    515 		}
    516 	}
    517 	mutex_exit(&dd->dd_lock);
    518 
    519 	return (0);
    520 }
    521 
    522 /*
    523  * Update all property values for ddobj & its descendants.  This is used
    524  * when renaming the dir.
    525  */
    526 void
    527 dsl_prop_notify_all(dsl_dir_t *dd)
    528 {
    529 	dsl_pool_t *dp = dd->dd_pool;
    530 	ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock));
    531 	(void) dmu_objset_find_dp(dp, dd->dd_object, dsl_prop_notify_all_cb,
    532 	    NULL, DS_FIND_CHILDREN);
    533 }
    534 
    535 static void
    536 dsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj,
    537     const char *propname, uint64_t value, int first)
    538 {
    539 	dsl_dir_t *dd;
    540 	dsl_prop_record_t *pr;
    541 	dsl_prop_cb_record_t *cbr;
    542 	objset_t *mos = dp->dp_meta_objset;
    543 	zap_cursor_t zc;
    544 	zap_attribute_t *za;
    545 	int err;
    546 
    547 	ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock));
    548 	err = dsl_dir_hold_obj(dp, ddobj, NULL, FTAG, &dd);
    549 	if (err)
    550 		return;
    551 
    552 	if (!first) {
    553 		/*
    554 		 * If the prop is set here, then this change is not
    555 		 * being inherited here or below; stop the recursion.
    556 		 */
    557 		err = zap_contains(mos, dsl_dir_phys(dd)->dd_props_zapobj,
    558 		    propname);
    559 		if (err == 0) {
    560 			dsl_dir_rele(dd, FTAG);
    561 			return;
    562 		}
    563 		ASSERT3U(err, ==, ENOENT);
    564 	}
    565 
    566 	mutex_enter(&dd->dd_lock);
    567 	pr = dsl_prop_record_find(dd, propname);
    568 	if (pr != NULL) {
    569 		for (cbr = list_head(&pr->pr_cbs); cbr;
    570 		    cbr = list_next(&pr->pr_cbs, cbr)) {
    571 			uint64_t propobj;
    572 
    573 			/*
    574 			 * cbr->cbr_ds may be invalidated due to eviction,
    575 			 * requiring the use of dsl_dataset_try_add_ref().
    576 			 * See comment block in dsl_prop_notify_all_cb()
    577 			 * for details.
    578 			 */
    579 			if (!dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG))
    580 				continue;
    581 
    582 			propobj = dsl_dataset_phys(cbr->cbr_ds)->ds_props_obj;
    583 
    584 			/*
    585 			 * If the property is not set on this ds, then it is
    586 			 * inherited here; call the callback.
    587 			 */
    588 			if (propobj == 0 ||
    589 			    zap_contains(mos, propobj, propname) != 0)
    590 				cbr->cbr_func(cbr->cbr_arg, value);
    591 
    592 			dsl_dataset_rele(cbr->cbr_ds, FTAG);
    593 		}
    594 	}
    595 	mutex_exit(&dd->dd_lock);
    596 
    597 	za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
    598 	for (zap_cursor_init(&zc, mos,
    599 	    dsl_dir_phys(dd)->dd_child_dir_zapobj);
    600 	    zap_cursor_retrieve(&zc, za) == 0;
    601 	    zap_cursor_advance(&zc)) {
    602 		dsl_prop_changed_notify(dp, za->za_first_integer,
    603 		    propname, value, FALSE);
    604 	}
    605 	kmem_free(za, sizeof (zap_attribute_t));
    606 	zap_cursor_fini(&zc);
    607 	dsl_dir_rele(dd, FTAG);
    608 }
    609 
    610 void
    611 dsl_prop_set_sync_impl(dsl_dataset_t *ds, const char *propname,
    612     zprop_source_t source, int intsz, int numints, const void *value,
    613     dmu_tx_t *tx)
    614 {
    615 	objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
    616 	uint64_t zapobj, intval, dummy;
    617 	int isint;
    618 	char valbuf[32];
    619 	const char *valstr = NULL;
    620 	char *inheritstr;
    621 	char *recvdstr;
    622 	char *tbuf = NULL;
    623 	int err;
    624 	uint64_t version = spa_version(ds->ds_dir->dd_pool->dp_spa);
    625 
    626 	isint = (dodefault(zfs_name_to_prop(propname), 8, 1, &intval) == 0);
    627 
    628 	if (ds->ds_is_snapshot) {
    629 		ASSERT(version >= SPA_VERSION_SNAP_PROPS);
    630 		if (dsl_dataset_phys(ds)->ds_props_obj == 0) {
    631 			dmu_buf_will_dirty(ds->ds_dbuf, tx);
    632 			dsl_dataset_phys(ds)->ds_props_obj =
    633 			    zap_create(mos,
    634 			    DMU_OT_DSL_PROPS, DMU_OT_NONE, 0, tx);
    635 		}
    636 		zapobj = dsl_dataset_phys(ds)->ds_props_obj;
    637 	} else {
    638 		zapobj = dsl_dir_phys(ds->ds_dir)->dd_props_zapobj;
    639 	}
    640 
    641 	if (version < SPA_VERSION_RECVD_PROPS) {
    642 		if (source & ZPROP_SRC_NONE)
    643 			source = ZPROP_SRC_NONE;
    644 		else if (source & ZPROP_SRC_RECEIVED)
    645 			source = ZPROP_SRC_LOCAL;
    646 	}
    647 
    648 	inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX);
    649 	recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX);
    650 
    651 	switch (source) {
    652 	case ZPROP_SRC_NONE:
    653 		/*
    654 		 * revert to received value, if any (inherit -S)
    655 		 * - remove propname
    656 		 * - remove propname$inherit
    657 		 */
    658 		err = zap_remove(mos, zapobj, propname, tx);
    659 		ASSERT(err == 0 || err == ENOENT);
    660 		err = zap_remove(mos, zapobj, inheritstr, tx);
    661 		ASSERT(err == 0 || err == ENOENT);
    662 		break;
    663 	case ZPROP_SRC_LOCAL:
    664 		/*
    665 		 * remove propname$inherit
    666 		 * set propname -> value
    667 		 */
    668 		err = zap_remove(mos, zapobj, inheritstr, tx);
    669 		ASSERT(err == 0 || err == ENOENT);
    670 		VERIFY0(zap_update(mos, zapobj, propname,
    671 		    intsz, numints, value, tx));
    672 		break;
    673 	case ZPROP_SRC_INHERITED:
    674 		/*
    675 		 * explicitly inherit
    676 		 * - remove propname
    677 		 * - set propname$inherit
    678 		 */
    679 		err = zap_remove(mos, zapobj, propname, tx);
    680 		ASSERT(err == 0 || err == ENOENT);
    681 		if (version >= SPA_VERSION_RECVD_PROPS &&
    682 		    dsl_prop_get_int_ds(ds, ZPROP_HAS_RECVD, &dummy) == 0) {
    683 			dummy = 0;
    684 			VERIFY0(zap_update(mos, zapobj, inheritstr,
    685 			    8, 1, &dummy, tx));
    686 		}
    687 		break;
    688 	case ZPROP_SRC_RECEIVED:
    689 		/*
    690 		 * set propname$recvd -> value
    691 		 */
    692 		err = zap_update(mos, zapobj, recvdstr,
    693 		    intsz, numints, value, tx);
    694 		ASSERT(err == 0);
    695 		break;
    696 	case (ZPROP_SRC_NONE | ZPROP_SRC_LOCAL | ZPROP_SRC_RECEIVED):
    697 		/*
    698 		 * clear local and received settings
    699 		 * - remove propname
    700 		 * - remove propname$inherit
    701 		 * - remove propname$recvd
    702 		 */
    703 		err = zap_remove(mos, zapobj, propname, tx);
    704 		ASSERT(err == 0 || err == ENOENT);
    705 		err = zap_remove(mos, zapobj, inheritstr, tx);
    706 		ASSERT(err == 0 || err == ENOENT);
    707 		/* FALLTHRU */
    708 	case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED):
    709 		/*
    710 		 * remove propname$recvd
    711 		 */
    712 		err = zap_remove(mos, zapobj, recvdstr, tx);
    713 		ASSERT(err == 0 || err == ENOENT);
    714 		break;
    715 	default:
    716 		cmn_err(CE_PANIC, "unexpected property source: %d", source);
    717 	}
    718 
    719 	strfree(inheritstr);
    720 	strfree(recvdstr);
    721 
    722 	if (isint) {
    723 		VERIFY0(dsl_prop_get_int_ds(ds, propname, &intval));
    724 
    725 		if (ds->ds_is_snapshot) {
    726 			dsl_prop_cb_record_t *cbr;
    727 			/*
    728 			 * It's a snapshot; nothing can inherit this
    729 			 * property, so just look for callbacks on this
    730 			 * ds here.
    731 			 */
    732 			mutex_enter(&ds->ds_dir->dd_lock);
    733 			for (cbr = list_head(&ds->ds_prop_cbs); cbr;
    734 			    cbr = list_next(&ds->ds_prop_cbs, cbr)) {
    735 				if (strcmp(cbr->cbr_pr->pr_propname,
    736 				    propname) == 0)
    737 					cbr->cbr_func(cbr->cbr_arg, intval);
    738 			}
    739 			mutex_exit(&ds->ds_dir->dd_lock);
    740 		} else {
    741 			dsl_prop_changed_notify(ds->ds_dir->dd_pool,
    742 			    ds->ds_dir->dd_object, propname, intval, TRUE);
    743 		}
    744 
    745 		(void) snprintf(valbuf, sizeof (valbuf),
    746 		    "%lld", (longlong_t)intval);
    747 		valstr = valbuf;
    748 	} else {
    749 		if (source == ZPROP_SRC_LOCAL) {
    750 			valstr = value;
    751 		} else {
    752 			tbuf = kmem_alloc(ZAP_MAXVALUELEN, KM_SLEEP);
    753 			if (dsl_prop_get_ds(ds, propname, 1,
    754 			    ZAP_MAXVALUELEN, tbuf, NULL) == 0)
    755 				valstr = tbuf;
    756 		}
    757 	}
    758 
    759 	spa_history_log_internal_ds(ds, (source == ZPROP_SRC_NONE ||
    760 	    source == ZPROP_SRC_INHERITED) ? "inherit" : "set", tx,
    761 	    "%s=%s", propname, (valstr == NULL ? "" : valstr));
    762 
    763 	if (tbuf != NULL)
    764 		kmem_free(tbuf, ZAP_MAXVALUELEN);
    765 }
    766 
    767 int
    768 dsl_prop_set_int(const char *dsname, const char *propname,
    769     zprop_source_t source, uint64_t value)
    770 {
    771 	nvlist_t *nvl = fnvlist_alloc();
    772 	int error;
    773 
    774 	fnvlist_add_uint64(nvl, propname, value);
    775 	error = dsl_props_set(dsname, source, nvl);
    776 	fnvlist_free(nvl);
    777 	return (error);
    778 }
    779 
    780 int
    781 dsl_prop_set_string(const char *dsname, const char *propname,
    782     zprop_source_t source, const char *value)
    783 {
    784 	nvlist_t *nvl = fnvlist_alloc();
    785 	int error;
    786 
    787 	fnvlist_add_string(nvl, propname, value);
    788 	error = dsl_props_set(dsname, source, nvl);
    789 	fnvlist_free(nvl);
    790 	return (error);
    791 }
    792 
    793 int
    794 dsl_prop_inherit(const char *dsname, const char *propname,
    795     zprop_source_t source)
    796 {
    797 	nvlist_t *nvl = fnvlist_alloc();
    798 	int error;
    799 
    800 	fnvlist_add_boolean(nvl, propname);
    801 	error = dsl_props_set(dsname, source, nvl);
    802 	fnvlist_free(nvl);
    803 	return (error);
    804 }
    805 
    806 typedef struct dsl_props_set_arg {
    807 	const char *dpsa_dsname;
    808 	zprop_source_t dpsa_source;
    809 	nvlist_t *dpsa_props;
    810 } dsl_props_set_arg_t;
    811 
    812 static int
    813 dsl_props_set_check(void *arg, dmu_tx_t *tx)
    814 {
    815 	dsl_props_set_arg_t *dpsa = arg;
    816 	dsl_pool_t *dp = dmu_tx_pool(tx);
    817 	dsl_dataset_t *ds;
    818 	uint64_t version;
    819 	nvpair_t *elem = NULL;
    820 	int err;
    821 
    822 	err = dsl_dataset_hold(dp, dpsa->dpsa_dsname, FTAG, &ds);
    823 	if (err != 0)
    824 		return (err);
    825 
    826 	version = spa_version(ds->ds_dir->dd_pool->dp_spa);
    827 	while ((elem = nvlist_next_nvpair(dpsa->dpsa_props, elem)) != NULL) {
    828 		if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) {
    829 			dsl_dataset_rele(ds, FTAG);
    830 			return (SET_ERROR(ENAMETOOLONG));
    831 		}
    832 		if (nvpair_type(elem) == DATA_TYPE_STRING) {
    833 			char *valstr = fnvpair_value_string(elem);
    834 			if (strlen(valstr) >= (version <
    835 			    SPA_VERSION_STMF_PROP ?
    836 			    ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) {
    837 				dsl_dataset_rele(ds, FTAG);
    838 				return (E2BIG);
    839 			}
    840 		}
    841 	}
    842 
    843 	if (ds->ds_is_snapshot && version < SPA_VERSION_SNAP_PROPS) {
    844 		dsl_dataset_rele(ds, FTAG);
    845 		return (SET_ERROR(ENOTSUP));
    846 	}
    847 	dsl_dataset_rele(ds, FTAG);
    848 	return (0);
    849 }
    850 
    851 void
    852 dsl_props_set_sync_impl(dsl_dataset_t *ds, zprop_source_t source,
    853     nvlist_t *props, dmu_tx_t *tx)
    854 {
    855 	nvpair_t *elem = NULL;
    856 
    857 	while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
    858 		nvpair_t *pair = elem;
    859 
    860 		if (nvpair_type(pair) == DATA_TYPE_NVLIST) {
    861 			/*
    862 			 * dsl_prop_get_all_impl() returns properties in this
    863 			 * format.
    864 			 */
    865 			nvlist_t *attrs = fnvpair_value_nvlist(pair);
    866 			pair = fnvlist_lookup_nvpair(attrs, ZPROP_VALUE);
    867 		}
    868 
    869 		if (nvpair_type(pair) == DATA_TYPE_STRING) {
    870 			const char *value = fnvpair_value_string(pair);
    871 			dsl_prop_set_sync_impl(ds, nvpair_name(pair),
    872 			    source, 1, strlen(value) + 1, value, tx);
    873 		} else if (nvpair_type(pair) == DATA_TYPE_UINT64) {
    874 			uint64_t intval = fnvpair_value_uint64(pair);
    875 			dsl_prop_set_sync_impl(ds, nvpair_name(pair),
    876 			    source, sizeof (intval), 1, &intval, tx);
    877 		} else if (nvpair_type(pair) == DATA_TYPE_BOOLEAN) {
    878 			dsl_prop_set_sync_impl(ds, nvpair_name(pair),
    879 			    source, 0, 0, NULL, tx);
    880 		} else {
    881 			panic("invalid nvpair type");
    882 		}
    883 	}
    884 }
    885 
    886 static void
    887 dsl_props_set_sync(void *arg, dmu_tx_t *tx)
    888 {
    889 	dsl_props_set_arg_t *dpsa = arg;
    890 	dsl_pool_t *dp = dmu_tx_pool(tx);
    891 	dsl_dataset_t *ds;
    892 
    893 	VERIFY0(dsl_dataset_hold(dp, dpsa->dpsa_dsname, FTAG, &ds));
    894 	dsl_props_set_sync_impl(ds, dpsa->dpsa_source, dpsa->dpsa_props, tx);
    895 	dsl_dataset_rele(ds, FTAG);
    896 }
    897 
    898 /*
    899  * All-or-nothing; if any prop can't be set, nothing will be modified.
    900  */
    901 int
    902 dsl_props_set(const char *dsname, zprop_source_t source, nvlist_t *props)
    903 {
    904 	dsl_props_set_arg_t dpsa;
    905 	int nblks = 0;
    906 
    907 	dpsa.dpsa_dsname = dsname;
    908 	dpsa.dpsa_source = source;
    909 	dpsa.dpsa_props = props;
    910 
    911 	/*
    912 	 * If the source includes NONE, then we will only be removing entries
    913 	 * from the ZAP object.  In that case don't check for ENOSPC.
    914 	 */
    915 	if ((source & ZPROP_SRC_NONE) == 0)
    916 		nblks = 2 * fnvlist_num_pairs(props);
    917 
    918 	return (dsl_sync_task(dsname, dsl_props_set_check, dsl_props_set_sync,
    919 	    &dpsa, nblks, ZFS_SPACE_CHECK_RESERVED));
    920 }
    921 
    922 typedef enum dsl_prop_getflags {
    923 	DSL_PROP_GET_INHERITING = 0x1,	/* searching parent of target ds */
    924 	DSL_PROP_GET_SNAPSHOT = 0x2,	/* snapshot dataset */
    925 	DSL_PROP_GET_LOCAL = 0x4,	/* local properties */
    926 	DSL_PROP_GET_RECEIVED = 0x8	/* received properties */
    927 } dsl_prop_getflags_t;
    928 
    929 static int
    930 dsl_prop_get_all_impl(objset_t *mos, uint64_t propobj,
    931     const char *setpoint, dsl_prop_getflags_t flags, nvlist_t *nv)
    932 {
    933 	zap_cursor_t zc;
    934 	zap_attribute_t za;
    935 	int err = 0;
    936 
    937 	for (zap_cursor_init(&zc, mos, propobj);
    938 	    (err = zap_cursor_retrieve(&zc, &za)) == 0;
    939 	    zap_cursor_advance(&zc)) {
    940 		nvlist_t *propval;
    941 		zfs_prop_t prop;
    942 		char buf[ZAP_MAXNAMELEN];
    943 		char *valstr;
    944 		const char *suffix;
    945 		const char *propname;
    946 		const char *source;
    947 
    948 		suffix = strchr(za.za_name, '$');
    949 
    950 		if (suffix == NULL) {
    951 			/*
    952 			 * Skip local properties if we only want received
    953 			 * properties.
    954 			 */
    955 			if (flags & DSL_PROP_GET_RECEIVED)
    956 				continue;
    957 
    958 			propname = za.za_name;
    959 			source = setpoint;
    960 		} else if (strcmp(suffix, ZPROP_INHERIT_SUFFIX) == 0) {
    961 			/* Skip explicitly inherited entries. */
    962 			continue;
    963 		} else if (strcmp(suffix, ZPROP_RECVD_SUFFIX) == 0) {
    964 			if (flags & DSL_PROP_GET_LOCAL)
    965 				continue;
    966 
    967 			(void) strncpy(buf, za.za_name, (suffix - za.za_name));
    968 			buf[suffix - za.za_name] = '\0';
    969 			propname = buf;
    970 
    971 			if (!(flags & DSL_PROP_GET_RECEIVED)) {
    972 				/* Skip if locally overridden. */
    973 				err = zap_contains(mos, propobj, propname);
    974 				if (err == 0)
    975 					continue;
    976 				if (err != ENOENT)
    977 					break;
    978 
    979 				/* Skip if explicitly inherited. */
    980 				valstr = kmem_asprintf("%s%s", propname,
    981 				    ZPROP_INHERIT_SUFFIX);
    982 				err = zap_contains(mos, propobj, valstr);
    983 				strfree(valstr);
    984 				if (err == 0)
    985 					continue;
    986 				if (err != ENOENT)
    987 					break;
    988 			}
    989 
    990 			source = ((flags & DSL_PROP_GET_INHERITING) ?
    991 			    setpoint : ZPROP_SOURCE_VAL_RECVD);
    992 		} else {
    993 			/*
    994 			 * For backward compatibility, skip suffixes we don't
    995 			 * recognize.
    996 			 */
    997 			continue;
    998 		}
    999 
   1000 		prop = zfs_name_to_prop(propname);
   1001 
   1002 		/* Skip non-inheritable properties. */
   1003 		if ((flags & DSL_PROP_GET_INHERITING) && prop != ZPROP_INVAL &&
   1004 		    !zfs_prop_inheritable(prop))
   1005 			continue;
   1006 
   1007 		/* Skip properties not valid for this type. */
   1008 		if ((flags & DSL_PROP_GET_SNAPSHOT) && prop != ZPROP_INVAL &&
   1009 		    !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT))
   1010 			continue;
   1011 
   1012 		/* Skip properties already defined. */
   1013 		if (nvlist_exists(nv, propname))
   1014 			continue;
   1015 
   1016 		VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
   1017 		if (za.za_integer_length == 1) {
   1018 			/*
   1019 			 * String property
   1020 			 */
   1021 			char *tmp = kmem_alloc(za.za_num_integers,
   1022 			    KM_SLEEP);
   1023 			err = zap_lookup(mos, propobj,
   1024 			    za.za_name, 1, za.za_num_integers, tmp);
   1025 			if (err != 0) {
   1026 				kmem_free(tmp, za.za_num_integers);
   1027 				break;
   1028 			}
   1029 			VERIFY(nvlist_add_string(propval, ZPROP_VALUE,
   1030 			    tmp) == 0);
   1031 			kmem_free(tmp, za.za_num_integers);
   1032 		} else {
   1033 			/*
   1034 			 * Integer property
   1035 			 */
   1036 			ASSERT(za.za_integer_length == 8);
   1037 			(void) nvlist_add_uint64(propval, ZPROP_VALUE,
   1038 			    za.za_first_integer);
   1039 		}
   1040 
   1041 		VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, source) == 0);
   1042 		VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
   1043 		nvlist_free(propval);
   1044 	}
   1045 	zap_cursor_fini(&zc);
   1046 	if (err == ENOENT)
   1047 		err = 0;
   1048 	return (err);
   1049 }
   1050 
   1051 /*
   1052  * Iterate over all properties for this dataset and return them in an nvlist.
   1053  */
   1054 static int
   1055 dsl_prop_get_all_ds(dsl_dataset_t *ds, nvlist_t **nvp,
   1056     dsl_prop_getflags_t flags)
   1057 {
   1058 	dsl_dir_t *dd = ds->ds_dir;
   1059 	dsl_pool_t *dp = dd->dd_pool;
   1060 	objset_t *mos = dp->dp_meta_objset;
   1061 	int err = 0;
   1062 	char setpoint[ZFS_MAX_DATASET_NAME_LEN];
   1063 
   1064 	VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
   1065 
   1066 	if (ds->ds_is_snapshot)
   1067 		flags |= DSL_PROP_GET_SNAPSHOT;
   1068 
   1069 	ASSERT(dsl_pool_config_held(dp));
   1070 
   1071 	if (dsl_dataset_phys(ds)->ds_props_obj != 0) {
   1072 		ASSERT(flags & DSL_PROP_GET_SNAPSHOT);
   1073 		dsl_dataset_name(ds, setpoint);
   1074 		err = dsl_prop_get_all_impl(mos,
   1075 		    dsl_dataset_phys(ds)->ds_props_obj, setpoint, flags, *nvp);
   1076 		if (err)
   1077 			goto out;
   1078 	}
   1079 
   1080 	for (; dd != NULL; dd = dd->dd_parent) {
   1081 		if (dd != ds->ds_dir || (flags & DSL_PROP_GET_SNAPSHOT)) {
   1082 			if (flags & (DSL_PROP_GET_LOCAL |
   1083 			    DSL_PROP_GET_RECEIVED))
   1084 				break;
   1085 			flags |= DSL_PROP_GET_INHERITING;
   1086 		}
   1087 		dsl_dir_name(dd, setpoint);
   1088 		err = dsl_prop_get_all_impl(mos,
   1089 		    dsl_dir_phys(dd)->dd_props_zapobj, setpoint, flags, *nvp);
   1090 		if (err)
   1091 			break;
   1092 	}
   1093 out:
   1094 	return (err);
   1095 }
   1096 
   1097 boolean_t
   1098 dsl_prop_get_hasrecvd(const char *dsname)
   1099 {
   1100 	uint64_t dummy;
   1101 
   1102 	return (0 ==
   1103 	    dsl_prop_get_integer(dsname, ZPROP_HAS_RECVD, &dummy, NULL));
   1104 }
   1105 
   1106 static int
   1107 dsl_prop_set_hasrecvd_impl(const char *dsname, zprop_source_t source)
   1108 {
   1109 	uint64_t version;
   1110 	spa_t *spa;
   1111 	int error = 0;
   1112 
   1113 	VERIFY0(spa_open(dsname, &spa, FTAG));
   1114 	version = spa_version(spa);
   1115 	spa_close(spa, FTAG);
   1116 
   1117 	if (version >= SPA_VERSION_RECVD_PROPS)
   1118 		error = dsl_prop_set_int(dsname, ZPROP_HAS_RECVD, source, 0);
   1119 	return (error);
   1120 }
   1121 
   1122 /*
   1123  * Call after successfully receiving properties to ensure that only the first
   1124  * receive on or after SPA_VERSION_RECVD_PROPS blows away local properties.
   1125  */
   1126 int
   1127 dsl_prop_set_hasrecvd(const char *dsname)
   1128 {
   1129 	int error = 0;
   1130 	if (!dsl_prop_get_hasrecvd(dsname))
   1131 		error = dsl_prop_set_hasrecvd_impl(dsname, ZPROP_SRC_LOCAL);
   1132 	return (error);
   1133 }
   1134 
   1135 void
   1136 dsl_prop_unset_hasrecvd(const char *dsname)
   1137 {
   1138 	VERIFY0(dsl_prop_set_hasrecvd_impl(dsname, ZPROP_SRC_NONE));
   1139 }
   1140 
   1141 int
   1142 dsl_prop_get_all(objset_t *os, nvlist_t **nvp)
   1143 {
   1144 	return (dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, 0));
   1145 }
   1146 
   1147 int
   1148 dsl_prop_get_received(const char *dsname, nvlist_t **nvp)
   1149 {
   1150 	objset_t *os;
   1151 	int error;
   1152 
   1153 	/*
   1154 	 * Received properties are not distinguishable from local properties
   1155 	 * until the dataset has received properties on or after
   1156 	 * SPA_VERSION_RECVD_PROPS.
   1157 	 */
   1158 	dsl_prop_getflags_t flags = (dsl_prop_get_hasrecvd(dsname) ?
   1159 	    DSL_PROP_GET_RECEIVED : DSL_PROP_GET_LOCAL);
   1160 
   1161 	error = dmu_objset_hold(dsname, FTAG, &os);
   1162 	if (error != 0)
   1163 		return (error);
   1164 	error = dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, flags);
   1165 	dmu_objset_rele(os, FTAG);
   1166 	return (error);
   1167 }
   1168 
   1169 void
   1170 dsl_prop_nvlist_add_uint64(nvlist_t *nv, zfs_prop_t prop, uint64_t value)
   1171 {
   1172 	nvlist_t *propval;
   1173 	const char *propname = zfs_prop_to_name(prop);
   1174 	uint64_t default_value;
   1175 
   1176 	if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) {
   1177 		VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0);
   1178 		return;
   1179 	}
   1180 
   1181 	VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
   1182 	VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0);
   1183 	/* Indicate the default source if we can. */
   1184 	if (dodefault(prop, 8, 1, &default_value) == 0 &&
   1185 	    value == default_value) {
   1186 		VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, "") == 0);
   1187 	}
   1188 	VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
   1189 	nvlist_free(propval);
   1190 }
   1191 
   1192 void
   1193 dsl_prop_nvlist_add_string(nvlist_t *nv, zfs_prop_t prop, const char *value)
   1194 {
   1195 	nvlist_t *propval;
   1196 	const char *propname = zfs_prop_to_name(prop);
   1197 
   1198 	if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) {
   1199 		VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0);
   1200 		return;
   1201 	}
   1202 
   1203 	VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
   1204 	VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0);
   1205 	VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
   1206 	nvlist_free(propval);
   1207 }
   1208