xref: /titanic_41/usr/src/uts/common/fs/zfs/dsl_prop.c (revision c10c16dec587a0662068f6e2991c29ed3a9db943)
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  */
24 
25 #include <sys/zfs_context.h>
26 #include <sys/dmu.h>
27 #include <sys/dmu_objset.h>
28 #include <sys/dmu_tx.h>
29 #include <sys/dsl_dataset.h>
30 #include <sys/dsl_dir.h>
31 #include <sys/dsl_prop.h>
32 #include <sys/dsl_synctask.h>
33 #include <sys/spa.h>
34 #include <sys/zap.h>
35 #include <sys/fs/zfs.h>
36 
37 #include "zfs_prop.h"
38 
39 #define	ZPROP_INHERIT_SUFFIX "$inherit"
40 #define	ZPROP_RECVD_SUFFIX "$recvd"
41 
42 static int
43 dodefault(const char *propname, int intsz, int numints, void *buf)
44 {
45 	zfs_prop_t prop;
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 = zfs_name_to_prop(propname)) == ZPROP_INVAL ||
53 	    (zfs_prop_readonly(prop) && !zfs_prop_setonce(prop)))
54 		return (ENOENT);
55 
56 	if (zfs_prop_get_type(prop) == PROP_TYPE_STRING) {
57 		if (intsz != 1)
58 			return (EOVERFLOW);
59 		(void) strncpy(buf, zfs_prop_default_string(prop),
60 		    numints);
61 	} else {
62 		if (intsz != 8 || numints < 1)
63 			return (EOVERFLOW);
64 
65 		*(uint64_t *)buf = zfs_prop_default_numeric(prop);
66 	}
67 
68 	return (0);
69 }
70 
71 int
72 dsl_prop_get_dd(dsl_dir_t *dd, const char *propname,
73     int intsz, int numints, void *buf, char *setpoint, boolean_t snapshot)
74 {
75 	int err = ENOENT;
76 	dsl_dir_t *target = dd;
77 	objset_t *mos = dd->dd_pool->dp_meta_objset;
78 	zfs_prop_t prop;
79 	boolean_t inheritable;
80 	boolean_t inheriting = B_FALSE;
81 	char *inheritstr;
82 	char *recvdstr;
83 
84 	ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock));
85 
86 	if (setpoint)
87 		setpoint[0] = '\0';
88 
89 	prop = zfs_name_to_prop(propname);
90 	inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop));
91 	inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX);
92 	recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX);
93 
94 	/*
95 	 * Note: dd may become NULL, therefore we shouldn't dereference it
96 	 * after this loop.
97 	 */
98 	for (; dd != NULL; dd = dd->dd_parent) {
99 		ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock));
100 
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, dd->dd_phys->dd_props_zapobj, propname,
109 		    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, dd->dd_phys->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, dd->dd_phys->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 = ENOENT;
149 	}
150 
151 	if (err == ENOENT)
152 		err = dodefault(propname, 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 	boolean_t snapshot;
167 	uint64_t zapobj;
168 
169 	ASSERT(RW_LOCK_HELD(&ds->ds_dir->dd_pool->dp_config_rwlock));
170 	inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop));
171 	snapshot = (ds->ds_phys != NULL && dsl_dataset_is_snapshot(ds));
172 	zapobj = (ds->ds_phys == NULL ? 0 : ds->ds_phys->ds_props_obj);
173 
174 	if (zapobj != 0) {
175 		objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
176 		int err;
177 
178 		ASSERT(snapshot);
179 
180 		/* Check for a local value. */
181 		err = zap_lookup(mos, zapobj, propname, intsz, numints, buf);
182 		if (err != ENOENT) {
183 			if (setpoint != NULL && err == 0)
184 				dsl_dataset_name(ds, setpoint);
185 			return (err);
186 		}
187 
188 		/*
189 		 * Skip the check for a received value if there is an explicit
190 		 * inheritance entry.
191 		 */
192 		if (inheritable) {
193 			char *inheritstr = kmem_asprintf("%s%s", propname,
194 			    ZPROP_INHERIT_SUFFIX);
195 			err = zap_contains(mos, zapobj, inheritstr);
196 			strfree(inheritstr);
197 			if (err != 0 && err != ENOENT)
198 				return (err);
199 		}
200 
201 		if (err == ENOENT) {
202 			/* Check for a received value. */
203 			char *recvdstr = kmem_asprintf("%s%s", propname,
204 			    ZPROP_RECVD_SUFFIX);
205 			err = zap_lookup(mos, zapobj, recvdstr,
206 			    intsz, numints, buf);
207 			strfree(recvdstr);
208 			if (err != ENOENT) {
209 				if (setpoint != NULL && err == 0)
210 					(void) strcpy(setpoint,
211 					    ZPROP_SOURCE_VAL_RECVD);
212 				return (err);
213 			}
214 		}
215 	}
216 
217 	return (dsl_prop_get_dd(ds->ds_dir, propname,
218 	    intsz, numints, buf, setpoint, snapshot));
219 }
220 
221 /*
222  * Register interest in the named property.  We'll call the callback
223  * once to notify it of the current property value, and again each time
224  * the property changes, until this callback is unregistered.
225  *
226  * Return 0 on success, errno if the prop is not an integer value.
227  */
228 int
229 dsl_prop_register(dsl_dataset_t *ds, const char *propname,
230     dsl_prop_changed_cb_t *callback, void *cbarg)
231 {
232 	dsl_dir_t *dd = ds->ds_dir;
233 	dsl_pool_t *dp = dd->dd_pool;
234 	uint64_t value;
235 	dsl_prop_cb_record_t *cbr;
236 	int err;
237 	int need_rwlock;
238 
239 	need_rwlock = !RW_WRITE_HELD(&dp->dp_config_rwlock);
240 	if (need_rwlock)
241 		rw_enter(&dp->dp_config_rwlock, RW_READER);
242 
243 	err = dsl_prop_get_ds(ds, propname, 8, 1, &value, NULL);
244 	if (err != 0) {
245 		if (need_rwlock)
246 			rw_exit(&dp->dp_config_rwlock);
247 		return (err);
248 	}
249 
250 	cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP);
251 	cbr->cbr_ds = ds;
252 	cbr->cbr_propname = kmem_alloc(strlen(propname)+1, KM_SLEEP);
253 	(void) strcpy((char *)cbr->cbr_propname, propname);
254 	cbr->cbr_func = callback;
255 	cbr->cbr_arg = cbarg;
256 	mutex_enter(&dd->dd_lock);
257 	list_insert_head(&dd->dd_prop_cbs, cbr);
258 	mutex_exit(&dd->dd_lock);
259 
260 	cbr->cbr_func(cbr->cbr_arg, value);
261 
262 	if (need_rwlock)
263 		rw_exit(&dp->dp_config_rwlock);
264 	return (0);
265 }
266 
267 int
268 dsl_prop_get(const char *dsname, const char *propname,
269     int intsz, int numints, void *buf, char *setpoint)
270 {
271 	dsl_dataset_t *ds;
272 	int err;
273 
274 	err = dsl_dataset_hold(dsname, FTAG, &ds);
275 	if (err)
276 		return (err);
277 
278 	rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER);
279 	err = dsl_prop_get_ds(ds, propname, intsz, numints, buf, setpoint);
280 	rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock);
281 
282 	dsl_dataset_rele(ds, FTAG);
283 	return (err);
284 }
285 
286 /*
287  * Get the current property value.  It may have changed by the time this
288  * function returns, so it is NOT safe to follow up with
289  * dsl_prop_register() and assume that the value has not changed in
290  * between.
291  *
292  * Return 0 on success, ENOENT if ddname is invalid.
293  */
294 int
295 dsl_prop_get_integer(const char *ddname, const char *propname,
296     uint64_t *valuep, char *setpoint)
297 {
298 	return (dsl_prop_get(ddname, propname, 8, 1, valuep, setpoint));
299 }
300 
301 void
302 dsl_prop_setarg_init_uint64(dsl_prop_setarg_t *psa, const char *propname,
303     zprop_source_t source, uint64_t *value)
304 {
305 	psa->psa_name = propname;
306 	psa->psa_source = source;
307 	psa->psa_intsz = 8;
308 	psa->psa_numints = 1;
309 	psa->psa_value = value;
310 
311 	psa->psa_effective_value = -1ULL;
312 }
313 
314 /*
315  * Predict the effective value of the given special property if it were set with
316  * the given value and source. This is not a general purpose function. It exists
317  * only to handle the special requirements of the quota and reservation
318  * properties. The fact that these properties are non-inheritable greatly
319  * simplifies the prediction logic.
320  *
321  * Returns 0 on success, a positive error code on failure, or -1 if called with
322  * a property not handled by this function.
323  */
324 int
325 dsl_prop_predict_sync(dsl_dir_t *dd, dsl_prop_setarg_t *psa)
326 {
327 	const char *propname = psa->psa_name;
328 	zfs_prop_t prop = zfs_name_to_prop(propname);
329 	zprop_source_t source = psa->psa_source;
330 	objset_t *mos;
331 	uint64_t zapobj;
332 	uint64_t version;
333 	char *recvdstr;
334 	int err = 0;
335 
336 	switch (prop) {
337 	case ZFS_PROP_QUOTA:
338 	case ZFS_PROP_RESERVATION:
339 	case ZFS_PROP_REFQUOTA:
340 	case ZFS_PROP_REFRESERVATION:
341 		break;
342 	default:
343 		return (-1);
344 	}
345 
346 	mos = dd->dd_pool->dp_meta_objset;
347 	zapobj = dd->dd_phys->dd_props_zapobj;
348 	recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX);
349 
350 	version = spa_version(dd->dd_pool->dp_spa);
351 	if (version < SPA_VERSION_RECVD_PROPS) {
352 		if (source & ZPROP_SRC_NONE)
353 			source = ZPROP_SRC_NONE;
354 		else if (source & ZPROP_SRC_RECEIVED)
355 			source = ZPROP_SRC_LOCAL;
356 	}
357 
358 	switch (source) {
359 	case ZPROP_SRC_NONE:
360 		/* Revert to the received value, if any. */
361 		err = zap_lookup(mos, zapobj, recvdstr, 8, 1,
362 		    &psa->psa_effective_value);
363 		if (err == ENOENT)
364 			psa->psa_effective_value = 0;
365 		break;
366 	case ZPROP_SRC_LOCAL:
367 		psa->psa_effective_value = *(uint64_t *)psa->psa_value;
368 		break;
369 	case ZPROP_SRC_RECEIVED:
370 		/*
371 		 * If there's no local setting, then the new received value will
372 		 * be the effective value.
373 		 */
374 		err = zap_lookup(mos, zapobj, propname, 8, 1,
375 		    &psa->psa_effective_value);
376 		if (err == ENOENT)
377 			psa->psa_effective_value = *(uint64_t *)psa->psa_value;
378 		break;
379 	case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED):
380 		/*
381 		 * We're clearing the received value, so the local setting (if
382 		 * it exists) remains the effective value.
383 		 */
384 		err = zap_lookup(mos, zapobj, propname, 8, 1,
385 		    &psa->psa_effective_value);
386 		if (err == ENOENT)
387 			psa->psa_effective_value = 0;
388 		break;
389 	default:
390 		cmn_err(CE_PANIC, "unexpected property source: %d", source);
391 	}
392 
393 	strfree(recvdstr);
394 
395 	if (err == ENOENT)
396 		return (0);
397 
398 	return (err);
399 }
400 
401 #ifdef	ZFS_DEBUG
402 void
403 dsl_prop_check_prediction(dsl_dir_t *dd, dsl_prop_setarg_t *psa)
404 {
405 	zfs_prop_t prop = zfs_name_to_prop(psa->psa_name);
406 	uint64_t intval;
407 	char setpoint[MAXNAMELEN];
408 	uint64_t version = spa_version(dd->dd_pool->dp_spa);
409 	int err;
410 
411 	if (version < SPA_VERSION_RECVD_PROPS) {
412 		switch (prop) {
413 		case ZFS_PROP_QUOTA:
414 		case ZFS_PROP_RESERVATION:
415 			return;
416 		}
417 	}
418 
419 	err = dsl_prop_get_dd(dd, psa->psa_name, 8, 1, &intval,
420 	    setpoint, B_FALSE);
421 	if (err == 0 && intval != psa->psa_effective_value) {
422 		cmn_err(CE_PANIC, "%s property, source: %x, "
423 		    "predicted effective value: %llu, "
424 		    "actual effective value: %llu (setpoint: %s)",
425 		    psa->psa_name, psa->psa_source,
426 		    (unsigned long long)psa->psa_effective_value,
427 		    (unsigned long long)intval, setpoint);
428 	}
429 }
430 #endif
431 
432 /*
433  * Unregister this callback.  Return 0 on success, ENOENT if ddname is
434  * invalid, ENOMSG if no matching callback registered.
435  */
436 int
437 dsl_prop_unregister(dsl_dataset_t *ds, const char *propname,
438     dsl_prop_changed_cb_t *callback, void *cbarg)
439 {
440 	dsl_dir_t *dd = ds->ds_dir;
441 	dsl_prop_cb_record_t *cbr;
442 
443 	mutex_enter(&dd->dd_lock);
444 	for (cbr = list_head(&dd->dd_prop_cbs);
445 	    cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) {
446 		if (cbr->cbr_ds == ds &&
447 		    cbr->cbr_func == callback &&
448 		    cbr->cbr_arg == cbarg &&
449 		    strcmp(cbr->cbr_propname, propname) == 0)
450 			break;
451 	}
452 
453 	if (cbr == NULL) {
454 		mutex_exit(&dd->dd_lock);
455 		return (ENOMSG);
456 	}
457 
458 	list_remove(&dd->dd_prop_cbs, cbr);
459 	mutex_exit(&dd->dd_lock);
460 	kmem_free((void*)cbr->cbr_propname, strlen(cbr->cbr_propname)+1);
461 	kmem_free(cbr, sizeof (dsl_prop_cb_record_t));
462 
463 	return (0);
464 }
465 
466 /*
467  * Return the number of callbacks that are registered for this dataset.
468  */
469 int
470 dsl_prop_numcb(dsl_dataset_t *ds)
471 {
472 	dsl_dir_t *dd = ds->ds_dir;
473 	dsl_prop_cb_record_t *cbr;
474 	int num = 0;
475 
476 	mutex_enter(&dd->dd_lock);
477 	for (cbr = list_head(&dd->dd_prop_cbs);
478 	    cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) {
479 		if (cbr->cbr_ds == ds)
480 			num++;
481 	}
482 	mutex_exit(&dd->dd_lock);
483 
484 	return (num);
485 }
486 
487 static void
488 dsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj,
489     const char *propname, uint64_t value, int first)
490 {
491 	dsl_dir_t *dd;
492 	dsl_prop_cb_record_t *cbr;
493 	objset_t *mos = dp->dp_meta_objset;
494 	zap_cursor_t zc;
495 	zap_attribute_t *za;
496 	int err;
497 
498 	ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock));
499 	err = dsl_dir_open_obj(dp, ddobj, NULL, FTAG, &dd);
500 	if (err)
501 		return;
502 
503 	if (!first) {
504 		/*
505 		 * If the prop is set here, then this change is not
506 		 * being inherited here or below; stop the recursion.
507 		 */
508 		err = zap_contains(mos, dd->dd_phys->dd_props_zapobj, propname);
509 		if (err == 0) {
510 			dsl_dir_close(dd, FTAG);
511 			return;
512 		}
513 		ASSERT3U(err, ==, ENOENT);
514 	}
515 
516 	mutex_enter(&dd->dd_lock);
517 	for (cbr = list_head(&dd->dd_prop_cbs); cbr;
518 	    cbr = list_next(&dd->dd_prop_cbs, cbr)) {
519 		uint64_t propobj = cbr->cbr_ds->ds_phys->ds_props_obj;
520 
521 		if (strcmp(cbr->cbr_propname, propname) != 0)
522 			continue;
523 
524 		/*
525 		 * If the property is set on this ds, then it is not
526 		 * inherited here; don't call the callback.
527 		 */
528 		if (propobj && 0 == zap_contains(mos, propobj, propname))
529 			continue;
530 
531 		cbr->cbr_func(cbr->cbr_arg, value);
532 	}
533 	mutex_exit(&dd->dd_lock);
534 
535 	za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
536 	for (zap_cursor_init(&zc, mos,
537 	    dd->dd_phys->dd_child_dir_zapobj);
538 	    zap_cursor_retrieve(&zc, za) == 0;
539 	    zap_cursor_advance(&zc)) {
540 		dsl_prop_changed_notify(dp, za->za_first_integer,
541 		    propname, value, FALSE);
542 	}
543 	kmem_free(za, sizeof (zap_attribute_t));
544 	zap_cursor_fini(&zc);
545 	dsl_dir_close(dd, FTAG);
546 }
547 
548 void
549 dsl_prop_set_sync(void *arg1, void *arg2, dmu_tx_t *tx)
550 {
551 	dsl_dataset_t *ds = arg1;
552 	dsl_prop_setarg_t *psa = arg2;
553 	objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
554 	uint64_t zapobj, intval, dummy;
555 	int isint;
556 	char valbuf[32];
557 	char *valstr = NULL;
558 	char *inheritstr;
559 	char *recvdstr;
560 	char *tbuf = NULL;
561 	int err;
562 	uint64_t version = spa_version(ds->ds_dir->dd_pool->dp_spa);
563 	const char *propname = psa->psa_name;
564 	zprop_source_t source = psa->psa_source;
565 
566 	isint = (dodefault(propname, 8, 1, &intval) == 0);
567 
568 	if (ds->ds_phys != NULL && dsl_dataset_is_snapshot(ds)) {
569 		ASSERT(version >= SPA_VERSION_SNAP_PROPS);
570 		if (ds->ds_phys->ds_props_obj == 0) {
571 			dmu_buf_will_dirty(ds->ds_dbuf, tx);
572 			ds->ds_phys->ds_props_obj =
573 			    zap_create(mos,
574 			    DMU_OT_DSL_PROPS, DMU_OT_NONE, 0, tx);
575 		}
576 		zapobj = ds->ds_phys->ds_props_obj;
577 	} else {
578 		zapobj = ds->ds_dir->dd_phys->dd_props_zapobj;
579 	}
580 
581 	if (version < SPA_VERSION_RECVD_PROPS) {
582 		zfs_prop_t prop = zfs_name_to_prop(propname);
583 		if (prop == ZFS_PROP_QUOTA || prop == ZFS_PROP_RESERVATION)
584 			return;
585 
586 		if (source & ZPROP_SRC_NONE)
587 			source = ZPROP_SRC_NONE;
588 		else if (source & ZPROP_SRC_RECEIVED)
589 			source = ZPROP_SRC_LOCAL;
590 	}
591 
592 	inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX);
593 	recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX);
594 
595 	switch (source) {
596 	case ZPROP_SRC_NONE:
597 		/*
598 		 * revert to received value, if any (inherit -S)
599 		 * - remove propname
600 		 * - remove propname$inherit
601 		 */
602 		err = zap_remove(mos, zapobj, propname, tx);
603 		ASSERT(err == 0 || err == ENOENT);
604 		err = zap_remove(mos, zapobj, inheritstr, tx);
605 		ASSERT(err == 0 || err == ENOENT);
606 		break;
607 	case ZPROP_SRC_LOCAL:
608 		/*
609 		 * remove propname$inherit
610 		 * set propname -> value
611 		 */
612 		err = zap_remove(mos, zapobj, inheritstr, tx);
613 		ASSERT(err == 0 || err == ENOENT);
614 		VERIFY(0 == zap_update(mos, zapobj, propname,
615 		    psa->psa_intsz, psa->psa_numints, psa->psa_value, tx));
616 		break;
617 	case ZPROP_SRC_INHERITED:
618 		/*
619 		 * explicitly inherit
620 		 * - remove propname
621 		 * - set propname$inherit
622 		 */
623 		err = zap_remove(mos, zapobj, propname, tx);
624 		ASSERT(err == 0 || err == ENOENT);
625 		if (version >= SPA_VERSION_RECVD_PROPS &&
626 		    dsl_prop_get_ds(ds, ZPROP_HAS_RECVD, 8, 1, &dummy,
627 		    NULL) == 0) {
628 			dummy = 0;
629 			err = zap_update(mos, zapobj, inheritstr,
630 			    8, 1, &dummy, tx);
631 			ASSERT(err == 0);
632 		}
633 		break;
634 	case ZPROP_SRC_RECEIVED:
635 		/*
636 		 * set propname$recvd -> value
637 		 */
638 		err = zap_update(mos, zapobj, recvdstr,
639 		    psa->psa_intsz, psa->psa_numints, psa->psa_value, tx);
640 		ASSERT(err == 0);
641 		break;
642 	case (ZPROP_SRC_NONE | ZPROP_SRC_LOCAL | ZPROP_SRC_RECEIVED):
643 		/*
644 		 * clear local and received settings
645 		 * - remove propname
646 		 * - remove propname$inherit
647 		 * - remove propname$recvd
648 		 */
649 		err = zap_remove(mos, zapobj, propname, tx);
650 		ASSERT(err == 0 || err == ENOENT);
651 		err = zap_remove(mos, zapobj, inheritstr, tx);
652 		ASSERT(err == 0 || err == ENOENT);
653 		/* FALLTHRU */
654 	case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED):
655 		/*
656 		 * remove propname$recvd
657 		 */
658 		err = zap_remove(mos, zapobj, recvdstr, tx);
659 		ASSERT(err == 0 || err == ENOENT);
660 		break;
661 	default:
662 		cmn_err(CE_PANIC, "unexpected property source: %d", source);
663 	}
664 
665 	strfree(inheritstr);
666 	strfree(recvdstr);
667 
668 	if (isint) {
669 		VERIFY(0 == dsl_prop_get_ds(ds, propname, 8, 1, &intval, NULL));
670 
671 		if (ds->ds_phys != NULL && dsl_dataset_is_snapshot(ds)) {
672 			dsl_prop_cb_record_t *cbr;
673 			/*
674 			 * It's a snapshot; nothing can inherit this
675 			 * property, so just look for callbacks on this
676 			 * ds here.
677 			 */
678 			mutex_enter(&ds->ds_dir->dd_lock);
679 			for (cbr = list_head(&ds->ds_dir->dd_prop_cbs); cbr;
680 			    cbr = list_next(&ds->ds_dir->dd_prop_cbs, cbr)) {
681 				if (cbr->cbr_ds == ds &&
682 				    strcmp(cbr->cbr_propname, propname) == 0)
683 					cbr->cbr_func(cbr->cbr_arg, intval);
684 			}
685 			mutex_exit(&ds->ds_dir->dd_lock);
686 		} else {
687 			dsl_prop_changed_notify(ds->ds_dir->dd_pool,
688 			    ds->ds_dir->dd_object, propname, intval, TRUE);
689 		}
690 
691 		(void) snprintf(valbuf, sizeof (valbuf),
692 		    "%lld", (longlong_t)intval);
693 		valstr = valbuf;
694 	} else {
695 		if (source == ZPROP_SRC_LOCAL) {
696 			valstr = (char *)psa->psa_value;
697 		} else {
698 			tbuf = kmem_alloc(ZAP_MAXVALUELEN, KM_SLEEP);
699 			if (dsl_prop_get_ds(ds, propname, 1,
700 			    ZAP_MAXVALUELEN, tbuf, NULL) == 0)
701 				valstr = tbuf;
702 		}
703 	}
704 
705 	spa_history_log_internal((source == ZPROP_SRC_NONE ||
706 	    source == ZPROP_SRC_INHERITED) ? LOG_DS_INHERIT :
707 	    LOG_DS_PROPSET, ds->ds_dir->dd_pool->dp_spa, tx,
708 	    "%s=%s dataset = %llu", propname,
709 	    (valstr == NULL ? "" : valstr), ds->ds_object);
710 
711 	if (tbuf != NULL)
712 		kmem_free(tbuf, ZAP_MAXVALUELEN);
713 }
714 
715 void
716 dsl_props_set_sync(void *arg1, void *arg2, dmu_tx_t *tx)
717 {
718 	dsl_dataset_t *ds = arg1;
719 	dsl_props_arg_t *pa = arg2;
720 	nvlist_t *props = pa->pa_props;
721 	dsl_prop_setarg_t psa;
722 	nvpair_t *elem = NULL;
723 
724 	psa.psa_source = pa->pa_source;
725 
726 	while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
727 		nvpair_t *pair = elem;
728 
729 		psa.psa_name = nvpair_name(pair);
730 
731 		if (nvpair_type(pair) == DATA_TYPE_NVLIST) {
732 			/*
733 			 * dsl_prop_get_all_impl() returns properties in this
734 			 * format.
735 			 */
736 			nvlist_t *attrs;
737 			VERIFY(nvpair_value_nvlist(pair, &attrs) == 0);
738 			VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE,
739 			    &pair) == 0);
740 		}
741 
742 		if (nvpair_type(pair) == DATA_TYPE_STRING) {
743 			VERIFY(nvpair_value_string(pair,
744 			    (char **)&psa.psa_value) == 0);
745 			psa.psa_intsz = 1;
746 			psa.psa_numints = strlen(psa.psa_value) + 1;
747 		} else {
748 			uint64_t intval;
749 			VERIFY(nvpair_value_uint64(pair, &intval) == 0);
750 			psa.psa_intsz = sizeof (intval);
751 			psa.psa_numints = 1;
752 			psa.psa_value = &intval;
753 		}
754 		dsl_prop_set_sync(ds, &psa, tx);
755 	}
756 }
757 
758 void
759 dsl_dir_prop_set_uint64_sync(dsl_dir_t *dd, const char *name, uint64_t val,
760     dmu_tx_t *tx)
761 {
762 	objset_t *mos = dd->dd_pool->dp_meta_objset;
763 	uint64_t zapobj = dd->dd_phys->dd_props_zapobj;
764 
765 	ASSERT(dmu_tx_is_syncing(tx));
766 
767 	VERIFY(0 == zap_update(mos, zapobj, name, sizeof (val), 1, &val, tx));
768 
769 	dsl_prop_changed_notify(dd->dd_pool, dd->dd_object, name, val, TRUE);
770 
771 	spa_history_log_internal(LOG_DS_PROPSET, dd->dd_pool->dp_spa, tx,
772 	    "%s=%llu dataset = %llu", name, (u_longlong_t)val,
773 	    dd->dd_phys->dd_head_dataset_obj);
774 }
775 
776 int
777 dsl_prop_set(const char *dsname, const char *propname, zprop_source_t source,
778     int intsz, int numints, const void *buf)
779 {
780 	dsl_dataset_t *ds;
781 	uint64_t version;
782 	int err;
783 	dsl_prop_setarg_t psa;
784 
785 	/*
786 	 * We must do these checks before we get to the syncfunc, since
787 	 * it can't fail.
788 	 */
789 	if (strlen(propname) >= ZAP_MAXNAMELEN)
790 		return (ENAMETOOLONG);
791 
792 	err = dsl_dataset_hold(dsname, FTAG, &ds);
793 	if (err)
794 		return (err);
795 
796 	version = spa_version(ds->ds_dir->dd_pool->dp_spa);
797 	if (intsz * numints >= (version < SPA_VERSION_STMF_PROP ?
798 	    ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) {
799 		dsl_dataset_rele(ds, FTAG);
800 		return (E2BIG);
801 	}
802 	if (dsl_dataset_is_snapshot(ds) &&
803 	    version < SPA_VERSION_SNAP_PROPS) {
804 		dsl_dataset_rele(ds, FTAG);
805 		return (ENOTSUP);
806 	}
807 
808 	psa.psa_name = propname;
809 	psa.psa_source = source;
810 	psa.psa_intsz = intsz;
811 	psa.psa_numints = numints;
812 	psa.psa_value = buf;
813 	psa.psa_effective_value = -1ULL;
814 
815 	err = dsl_sync_task_do(ds->ds_dir->dd_pool,
816 	    NULL, dsl_prop_set_sync, ds, &psa, 2);
817 
818 	dsl_dataset_rele(ds, FTAG);
819 	return (err);
820 }
821 
822 int
823 dsl_props_set(const char *dsname, zprop_source_t source, nvlist_t *props)
824 {
825 	dsl_dataset_t *ds;
826 	uint64_t version;
827 	nvpair_t *elem = NULL;
828 	dsl_props_arg_t pa;
829 	int err;
830 
831 	if (err = dsl_dataset_hold(dsname, FTAG, &ds))
832 		return (err);
833 	/*
834 	 * Do these checks before the syncfunc, since it can't fail.
835 	 */
836 	version = spa_version(ds->ds_dir->dd_pool->dp_spa);
837 	while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
838 		if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) {
839 			dsl_dataset_rele(ds, FTAG);
840 			return (ENAMETOOLONG);
841 		}
842 		if (nvpair_type(elem) == DATA_TYPE_STRING) {
843 			char *valstr;
844 			VERIFY(nvpair_value_string(elem, &valstr) == 0);
845 			if (strlen(valstr) >= (version <
846 			    SPA_VERSION_STMF_PROP ?
847 			    ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) {
848 				dsl_dataset_rele(ds, FTAG);
849 				return (E2BIG);
850 			}
851 		}
852 	}
853 
854 	if (dsl_dataset_is_snapshot(ds) &&
855 	    version < SPA_VERSION_SNAP_PROPS) {
856 		dsl_dataset_rele(ds, FTAG);
857 		return (ENOTSUP);
858 	}
859 
860 	pa.pa_props = props;
861 	pa.pa_source = source;
862 
863 	err = dsl_sync_task_do(ds->ds_dir->dd_pool,
864 	    NULL, dsl_props_set_sync, ds, &pa, 2);
865 
866 	dsl_dataset_rele(ds, FTAG);
867 	return (err);
868 }
869 
870 typedef enum dsl_prop_getflags {
871 	DSL_PROP_GET_INHERITING = 0x1,	/* searching parent of target ds */
872 	DSL_PROP_GET_SNAPSHOT = 0x2,	/* snapshot dataset */
873 	DSL_PROP_GET_LOCAL = 0x4,	/* local properties */
874 	DSL_PROP_GET_RECEIVED = 0x8	/* received properties */
875 } dsl_prop_getflags_t;
876 
877 static int
878 dsl_prop_get_all_impl(objset_t *mos, uint64_t propobj,
879     const char *setpoint, dsl_prop_getflags_t flags, nvlist_t *nv)
880 {
881 	zap_cursor_t zc;
882 	zap_attribute_t za;
883 	int err = 0;
884 
885 	for (zap_cursor_init(&zc, mos, propobj);
886 	    (err = zap_cursor_retrieve(&zc, &za)) == 0;
887 	    zap_cursor_advance(&zc)) {
888 		nvlist_t *propval;
889 		zfs_prop_t prop;
890 		char buf[ZAP_MAXNAMELEN];
891 		char *valstr;
892 		const char *suffix;
893 		const char *propname;
894 		const char *source;
895 
896 		suffix = strchr(za.za_name, '$');
897 
898 		if (suffix == NULL) {
899 			/*
900 			 * Skip local properties if we only want received
901 			 * properties.
902 			 */
903 			if (flags & DSL_PROP_GET_RECEIVED)
904 				continue;
905 
906 			propname = za.za_name;
907 			source = setpoint;
908 		} else if (strcmp(suffix, ZPROP_INHERIT_SUFFIX) == 0) {
909 			/* Skip explicitly inherited entries. */
910 			continue;
911 		} else if (strcmp(suffix, ZPROP_RECVD_SUFFIX) == 0) {
912 			if (flags & DSL_PROP_GET_LOCAL)
913 				continue;
914 
915 			(void) strncpy(buf, za.za_name, (suffix - za.za_name));
916 			buf[suffix - za.za_name] = '\0';
917 			propname = buf;
918 
919 			if (!(flags & DSL_PROP_GET_RECEIVED)) {
920 				/* Skip if locally overridden. */
921 				err = zap_contains(mos, propobj, propname);
922 				if (err == 0)
923 					continue;
924 				if (err != ENOENT)
925 					break;
926 
927 				/* Skip if explicitly inherited. */
928 				valstr = kmem_asprintf("%s%s", propname,
929 				    ZPROP_INHERIT_SUFFIX);
930 				err = zap_contains(mos, propobj, valstr);
931 				strfree(valstr);
932 				if (err == 0)
933 					continue;
934 				if (err != ENOENT)
935 					break;
936 			}
937 
938 			source = ((flags & DSL_PROP_GET_INHERITING) ?
939 			    setpoint : ZPROP_SOURCE_VAL_RECVD);
940 		} else {
941 			/*
942 			 * For backward compatibility, skip suffixes we don't
943 			 * recognize.
944 			 */
945 			continue;
946 		}
947 
948 		prop = zfs_name_to_prop(propname);
949 
950 		/* Skip non-inheritable properties. */
951 		if ((flags & DSL_PROP_GET_INHERITING) && prop != ZPROP_INVAL &&
952 		    !zfs_prop_inheritable(prop))
953 			continue;
954 
955 		/* Skip properties not valid for this type. */
956 		if ((flags & DSL_PROP_GET_SNAPSHOT) && prop != ZPROP_INVAL &&
957 		    !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT))
958 			continue;
959 
960 		/* Skip properties already defined. */
961 		if (nvlist_exists(nv, propname))
962 			continue;
963 
964 		VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
965 		if (za.za_integer_length == 1) {
966 			/*
967 			 * String property
968 			 */
969 			char *tmp = kmem_alloc(za.za_num_integers,
970 			    KM_SLEEP);
971 			err = zap_lookup(mos, propobj,
972 			    za.za_name, 1, za.za_num_integers, tmp);
973 			if (err != 0) {
974 				kmem_free(tmp, za.za_num_integers);
975 				break;
976 			}
977 			VERIFY(nvlist_add_string(propval, ZPROP_VALUE,
978 			    tmp) == 0);
979 			kmem_free(tmp, za.za_num_integers);
980 		} else {
981 			/*
982 			 * Integer property
983 			 */
984 			ASSERT(za.za_integer_length == 8);
985 			(void) nvlist_add_uint64(propval, ZPROP_VALUE,
986 			    za.za_first_integer);
987 		}
988 
989 		VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, source) == 0);
990 		VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
991 		nvlist_free(propval);
992 	}
993 	zap_cursor_fini(&zc);
994 	if (err == ENOENT)
995 		err = 0;
996 	return (err);
997 }
998 
999 /*
1000  * Iterate over all properties for this dataset and return them in an nvlist.
1001  */
1002 static int
1003 dsl_prop_get_all_ds(dsl_dataset_t *ds, nvlist_t **nvp,
1004     dsl_prop_getflags_t flags)
1005 {
1006 	dsl_dir_t *dd = ds->ds_dir;
1007 	dsl_pool_t *dp = dd->dd_pool;
1008 	objset_t *mos = dp->dp_meta_objset;
1009 	int err = 0;
1010 	char setpoint[MAXNAMELEN];
1011 
1012 	VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1013 
1014 	if (dsl_dataset_is_snapshot(ds))
1015 		flags |= DSL_PROP_GET_SNAPSHOT;
1016 
1017 	rw_enter(&dp->dp_config_rwlock, RW_READER);
1018 
1019 	if (ds->ds_phys->ds_props_obj != 0) {
1020 		ASSERT(flags & DSL_PROP_GET_SNAPSHOT);
1021 		dsl_dataset_name(ds, setpoint);
1022 		err = dsl_prop_get_all_impl(mos, ds->ds_phys->ds_props_obj,
1023 		    setpoint, flags, *nvp);
1024 		if (err)
1025 			goto out;
1026 	}
1027 
1028 	for (; dd != NULL; dd = dd->dd_parent) {
1029 		if (dd != ds->ds_dir || (flags & DSL_PROP_GET_SNAPSHOT)) {
1030 			if (flags & (DSL_PROP_GET_LOCAL |
1031 			    DSL_PROP_GET_RECEIVED))
1032 				break;
1033 			flags |= DSL_PROP_GET_INHERITING;
1034 		}
1035 		dsl_dir_name(dd, setpoint);
1036 		err = dsl_prop_get_all_impl(mos, dd->dd_phys->dd_props_zapobj,
1037 		    setpoint, flags, *nvp);
1038 		if (err)
1039 			break;
1040 	}
1041 out:
1042 	rw_exit(&dp->dp_config_rwlock);
1043 	return (err);
1044 }
1045 
1046 boolean_t
1047 dsl_prop_get_hasrecvd(objset_t *os)
1048 {
1049 	dsl_dataset_t *ds = os->os_dsl_dataset;
1050 	int rc;
1051 	uint64_t dummy;
1052 
1053 	rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER);
1054 	rc = dsl_prop_get_ds(ds, ZPROP_HAS_RECVD, 8, 1, &dummy, NULL);
1055 	rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock);
1056 	ASSERT(rc != 0 || spa_version(os->os_spa) >= SPA_VERSION_RECVD_PROPS);
1057 	return (rc == 0);
1058 }
1059 
1060 static void
1061 dsl_prop_set_hasrecvd_impl(objset_t *os, zprop_source_t source)
1062 {
1063 	dsl_dataset_t *ds = os->os_dsl_dataset;
1064 	uint64_t dummy = 0;
1065 	dsl_prop_setarg_t psa;
1066 
1067 	if (spa_version(os->os_spa) < SPA_VERSION_RECVD_PROPS)
1068 		return;
1069 
1070 	dsl_prop_setarg_init_uint64(&psa, ZPROP_HAS_RECVD, source, &dummy);
1071 
1072 	(void) dsl_sync_task_do(ds->ds_dir->dd_pool, NULL,
1073 	    dsl_prop_set_sync, ds, &psa, 2);
1074 }
1075 
1076 /*
1077  * Call after successfully receiving properties to ensure that only the first
1078  * receive on or after SPA_VERSION_RECVD_PROPS blows away local properties.
1079  */
1080 void
1081 dsl_prop_set_hasrecvd(objset_t *os)
1082 {
1083 	if (dsl_prop_get_hasrecvd(os)) {
1084 		ASSERT(spa_version(os->os_spa) >= SPA_VERSION_RECVD_PROPS);
1085 		return;
1086 	}
1087 	dsl_prop_set_hasrecvd_impl(os, ZPROP_SRC_LOCAL);
1088 }
1089 
1090 void
1091 dsl_prop_unset_hasrecvd(objset_t *os)
1092 {
1093 	dsl_prop_set_hasrecvd_impl(os, ZPROP_SRC_NONE);
1094 }
1095 
1096 int
1097 dsl_prop_get_all(objset_t *os, nvlist_t **nvp)
1098 {
1099 	return (dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, 0));
1100 }
1101 
1102 int
1103 dsl_prop_get_received(objset_t *os, nvlist_t **nvp)
1104 {
1105 	/*
1106 	 * Received properties are not distinguishable from local properties
1107 	 * until the dataset has received properties on or after
1108 	 * SPA_VERSION_RECVD_PROPS.
1109 	 */
1110 	dsl_prop_getflags_t flags = (dsl_prop_get_hasrecvd(os) ?
1111 	    DSL_PROP_GET_RECEIVED : DSL_PROP_GET_LOCAL);
1112 	return (dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, flags));
1113 }
1114 
1115 void
1116 dsl_prop_nvlist_add_uint64(nvlist_t *nv, zfs_prop_t prop, uint64_t value)
1117 {
1118 	nvlist_t *propval;
1119 	const char *propname = zfs_prop_to_name(prop);
1120 	uint64_t default_value;
1121 
1122 	if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) {
1123 		VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0);
1124 		return;
1125 	}
1126 
1127 	VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1128 	VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0);
1129 	/* Indicate the default source if we can. */
1130 	if (dodefault(propname, 8, 1, &default_value) == 0 &&
1131 	    value == default_value) {
1132 		VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, "") == 0);
1133 	}
1134 	VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
1135 	nvlist_free(propval);
1136 }
1137 
1138 void
1139 dsl_prop_nvlist_add_string(nvlist_t *nv, zfs_prop_t prop, const char *value)
1140 {
1141 	nvlist_t *propval;
1142 	const char *propname = zfs_prop_to_name(prop);
1143 
1144 	if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) {
1145 		VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0);
1146 		return;
1147 	}
1148 
1149 	VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1150 	VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0);
1151 	VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
1152 	nvlist_free(propval);
1153 }
1154