xref: /titanic_44/usr/src/uts/common/fs/zfs/dsl_prop.c (revision 8339b41da2395f0525c46ceedfeb01961893ec44)
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 		    zap_contains(mos, zapobj, ZPROP_HAS_RECVD) == 0) {
627 			dummy = 0;
628 			err = zap_update(mos, zapobj, inheritstr,
629 			    8, 1, &dummy, tx);
630 			ASSERT(err == 0);
631 		}
632 		break;
633 	case ZPROP_SRC_RECEIVED:
634 		/*
635 		 * set propname$recvd -> value
636 		 */
637 		err = zap_update(mos, zapobj, recvdstr,
638 		    psa->psa_intsz, psa->psa_numints, psa->psa_value, tx);
639 		ASSERT(err == 0);
640 		break;
641 	case (ZPROP_SRC_NONE | ZPROP_SRC_LOCAL | ZPROP_SRC_RECEIVED):
642 		/*
643 		 * clear local and received settings
644 		 * - remove propname
645 		 * - remove propname$inherit
646 		 * - remove propname$recvd
647 		 */
648 		err = zap_remove(mos, zapobj, propname, tx);
649 		ASSERT(err == 0 || err == ENOENT);
650 		err = zap_remove(mos, zapobj, inheritstr, tx);
651 		ASSERT(err == 0 || err == ENOENT);
652 		/* FALLTHRU */
653 	case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED):
654 		/*
655 		 * remove propname$recvd
656 		 */
657 		err = zap_remove(mos, zapobj, recvdstr, tx);
658 		ASSERT(err == 0 || err == ENOENT);
659 		break;
660 	default:
661 		cmn_err(CE_PANIC, "unexpected property source: %d", source);
662 	}
663 
664 	strfree(inheritstr);
665 	strfree(recvdstr);
666 
667 	if (isint) {
668 		VERIFY(0 == dsl_prop_get_ds(ds, propname, 8, 1, &intval, NULL));
669 
670 		if (ds->ds_phys != NULL && dsl_dataset_is_snapshot(ds)) {
671 			dsl_prop_cb_record_t *cbr;
672 			/*
673 			 * It's a snapshot; nothing can inherit this
674 			 * property, so just look for callbacks on this
675 			 * ds here.
676 			 */
677 			mutex_enter(&ds->ds_dir->dd_lock);
678 			for (cbr = list_head(&ds->ds_dir->dd_prop_cbs); cbr;
679 			    cbr = list_next(&ds->ds_dir->dd_prop_cbs, cbr)) {
680 				if (cbr->cbr_ds == ds &&
681 				    strcmp(cbr->cbr_propname, propname) == 0)
682 					cbr->cbr_func(cbr->cbr_arg, intval);
683 			}
684 			mutex_exit(&ds->ds_dir->dd_lock);
685 		} else {
686 			dsl_prop_changed_notify(ds->ds_dir->dd_pool,
687 			    ds->ds_dir->dd_object, propname, intval, TRUE);
688 		}
689 
690 		(void) snprintf(valbuf, sizeof (valbuf),
691 		    "%lld", (longlong_t)intval);
692 		valstr = valbuf;
693 	} else {
694 		if (source == ZPROP_SRC_LOCAL) {
695 			valstr = (char *)psa->psa_value;
696 		} else {
697 			tbuf = kmem_alloc(ZAP_MAXVALUELEN, KM_SLEEP);
698 			if (dsl_prop_get_ds(ds, propname, 1,
699 			    ZAP_MAXVALUELEN, tbuf, NULL) == 0)
700 				valstr = tbuf;
701 		}
702 	}
703 
704 	spa_history_log_internal((source == ZPROP_SRC_NONE ||
705 	    source == ZPROP_SRC_INHERITED) ? LOG_DS_INHERIT :
706 	    LOG_DS_PROPSET, ds->ds_dir->dd_pool->dp_spa, tx,
707 	    "%s=%s dataset = %llu", propname,
708 	    (valstr == NULL ? "" : valstr), ds->ds_object);
709 
710 	if (tbuf != NULL)
711 		kmem_free(tbuf, ZAP_MAXVALUELEN);
712 }
713 
714 void
715 dsl_props_set_sync(void *arg1, void *arg2, dmu_tx_t *tx)
716 {
717 	dsl_dataset_t *ds = arg1;
718 	dsl_props_arg_t *pa = arg2;
719 	nvlist_t *props = pa->pa_props;
720 	dsl_prop_setarg_t psa;
721 	nvpair_t *elem = NULL;
722 
723 	psa.psa_source = pa->pa_source;
724 
725 	while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
726 		nvpair_t *pair = elem;
727 
728 		psa.psa_name = nvpair_name(pair);
729 
730 		if (nvpair_type(pair) == DATA_TYPE_NVLIST) {
731 			/*
732 			 * dsl_prop_get_all_impl() returns properties in this
733 			 * format.
734 			 */
735 			nvlist_t *attrs;
736 			VERIFY(nvpair_value_nvlist(pair, &attrs) == 0);
737 			VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE,
738 			    &pair) == 0);
739 		}
740 
741 		if (nvpair_type(pair) == DATA_TYPE_STRING) {
742 			VERIFY(nvpair_value_string(pair,
743 			    (char **)&psa.psa_value) == 0);
744 			psa.psa_intsz = 1;
745 			psa.psa_numints = strlen(psa.psa_value) + 1;
746 		} else {
747 			uint64_t intval;
748 			VERIFY(nvpair_value_uint64(pair, &intval) == 0);
749 			psa.psa_intsz = sizeof (intval);
750 			psa.psa_numints = 1;
751 			psa.psa_value = &intval;
752 		}
753 		dsl_prop_set_sync(ds, &psa, tx);
754 	}
755 }
756 
757 void
758 dsl_dir_prop_set_uint64_sync(dsl_dir_t *dd, const char *name, uint64_t val,
759     dmu_tx_t *tx)
760 {
761 	objset_t *mos = dd->dd_pool->dp_meta_objset;
762 	uint64_t zapobj = dd->dd_phys->dd_props_zapobj;
763 
764 	ASSERT(dmu_tx_is_syncing(tx));
765 
766 	VERIFY(0 == zap_update(mos, zapobj, name, sizeof (val), 1, &val, tx));
767 
768 	dsl_prop_changed_notify(dd->dd_pool, dd->dd_object, name, val, TRUE);
769 
770 	spa_history_log_internal(LOG_DS_PROPSET, dd->dd_pool->dp_spa, tx,
771 	    "%s=%llu dataset = %llu", name, (u_longlong_t)val,
772 	    dd->dd_phys->dd_head_dataset_obj);
773 }
774 
775 int
776 dsl_prop_set(const char *dsname, const char *propname, zprop_source_t source,
777     int intsz, int numints, const void *buf)
778 {
779 	dsl_dataset_t *ds;
780 	uint64_t version;
781 	int err;
782 	dsl_prop_setarg_t psa;
783 
784 	/*
785 	 * We must do these checks before we get to the syncfunc, since
786 	 * it can't fail.
787 	 */
788 	if (strlen(propname) >= ZAP_MAXNAMELEN)
789 		return (ENAMETOOLONG);
790 
791 	err = dsl_dataset_hold(dsname, FTAG, &ds);
792 	if (err)
793 		return (err);
794 
795 	version = spa_version(ds->ds_dir->dd_pool->dp_spa);
796 	if (intsz * numints >= (version < SPA_VERSION_STMF_PROP ?
797 	    ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) {
798 		dsl_dataset_rele(ds, FTAG);
799 		return (E2BIG);
800 	}
801 	if (dsl_dataset_is_snapshot(ds) &&
802 	    version < SPA_VERSION_SNAP_PROPS) {
803 		dsl_dataset_rele(ds, FTAG);
804 		return (ENOTSUP);
805 	}
806 
807 	psa.psa_name = propname;
808 	psa.psa_source = source;
809 	psa.psa_intsz = intsz;
810 	psa.psa_numints = numints;
811 	psa.psa_value = buf;
812 	psa.psa_effective_value = -1ULL;
813 
814 	err = dsl_sync_task_do(ds->ds_dir->dd_pool,
815 	    NULL, dsl_prop_set_sync, ds, &psa, 2);
816 
817 	dsl_dataset_rele(ds, FTAG);
818 	return (err);
819 }
820 
821 int
822 dsl_props_set(const char *dsname, zprop_source_t source, nvlist_t *props)
823 {
824 	dsl_dataset_t *ds;
825 	uint64_t version;
826 	nvpair_t *elem = NULL;
827 	dsl_props_arg_t pa;
828 	int err;
829 
830 	if (err = dsl_dataset_hold(dsname, FTAG, &ds))
831 		return (err);
832 	/*
833 	 * Do these checks before the syncfunc, since it can't fail.
834 	 */
835 	version = spa_version(ds->ds_dir->dd_pool->dp_spa);
836 	while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
837 		if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) {
838 			dsl_dataset_rele(ds, FTAG);
839 			return (ENAMETOOLONG);
840 		}
841 		if (nvpair_type(elem) == DATA_TYPE_STRING) {
842 			char *valstr;
843 			VERIFY(nvpair_value_string(elem, &valstr) == 0);
844 			if (strlen(valstr) >= (version <
845 			    SPA_VERSION_STMF_PROP ?
846 			    ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) {
847 				dsl_dataset_rele(ds, FTAG);
848 				return (E2BIG);
849 			}
850 		}
851 	}
852 
853 	if (dsl_dataset_is_snapshot(ds) &&
854 	    version < SPA_VERSION_SNAP_PROPS) {
855 		dsl_dataset_rele(ds, FTAG);
856 		return (ENOTSUP);
857 	}
858 
859 	pa.pa_props = props;
860 	pa.pa_source = source;
861 
862 	err = dsl_sync_task_do(ds->ds_dir->dd_pool,
863 	    NULL, dsl_props_set_sync, ds, &pa, 2);
864 
865 	dsl_dataset_rele(ds, FTAG);
866 	return (err);
867 }
868 
869 typedef enum dsl_prop_getflags {
870 	DSL_PROP_GET_INHERITING = 0x1,	/* searching parent of target ds */
871 	DSL_PROP_GET_SNAPSHOT = 0x2,	/* snapshot dataset */
872 	DSL_PROP_GET_LOCAL = 0x4,	/* local properties */
873 	DSL_PROP_GET_RECEIVED = 0x8	/* received properties */
874 } dsl_prop_getflags_t;
875 
876 static int
877 dsl_prop_get_all_impl(objset_t *mos, uint64_t propobj,
878     const char *setpoint, dsl_prop_getflags_t flags, nvlist_t *nv)
879 {
880 	zap_cursor_t zc;
881 	zap_attribute_t za;
882 	int err = 0;
883 
884 	for (zap_cursor_init(&zc, mos, propobj);
885 	    (err = zap_cursor_retrieve(&zc, &za)) == 0;
886 	    zap_cursor_advance(&zc)) {
887 		nvlist_t *propval;
888 		zfs_prop_t prop;
889 		char buf[ZAP_MAXNAMELEN];
890 		char *valstr;
891 		const char *suffix;
892 		const char *propname;
893 		const char *source;
894 
895 		suffix = strchr(za.za_name, '$');
896 
897 		if (suffix == NULL) {
898 			/*
899 			 * Skip local properties if we only want received
900 			 * properties.
901 			 */
902 			if (flags & DSL_PROP_GET_RECEIVED)
903 				continue;
904 
905 			propname = za.za_name;
906 			source = setpoint;
907 		} else if (strcmp(suffix, ZPROP_INHERIT_SUFFIX) == 0) {
908 			/* Skip explicitly inherited entries. */
909 			continue;
910 		} else if (strcmp(suffix, ZPROP_RECVD_SUFFIX) == 0) {
911 			if (flags & DSL_PROP_GET_LOCAL)
912 				continue;
913 
914 			(void) strncpy(buf, za.za_name, (suffix - za.za_name));
915 			buf[suffix - za.za_name] = '\0';
916 			propname = buf;
917 
918 			if (!(flags & DSL_PROP_GET_RECEIVED)) {
919 				/* Skip if locally overridden. */
920 				err = zap_contains(mos, propobj, propname);
921 				if (err == 0)
922 					continue;
923 				if (err != ENOENT)
924 					break;
925 
926 				/* Skip if explicitly inherited. */
927 				valstr = kmem_asprintf("%s%s", propname,
928 				    ZPROP_INHERIT_SUFFIX);
929 				err = zap_contains(mos, propobj, valstr);
930 				strfree(valstr);
931 				if (err == 0)
932 					continue;
933 				if (err != ENOENT)
934 					break;
935 			}
936 
937 			source = ((flags & DSL_PROP_GET_INHERITING) ?
938 			    setpoint : ZPROP_SOURCE_VAL_RECVD);
939 		} else {
940 			/*
941 			 * For backward compatibility, skip suffixes we don't
942 			 * recognize.
943 			 */
944 			continue;
945 		}
946 
947 		prop = zfs_name_to_prop(propname);
948 
949 		/* Skip non-inheritable properties. */
950 		if ((flags & DSL_PROP_GET_INHERITING) && prop != ZPROP_INVAL &&
951 		    !zfs_prop_inheritable(prop))
952 			continue;
953 
954 		/* Skip properties not valid for this type. */
955 		if ((flags & DSL_PROP_GET_SNAPSHOT) && prop != ZPROP_INVAL &&
956 		    !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT))
957 			continue;
958 
959 		/* Skip properties already defined. */
960 		if (nvlist_exists(nv, propname))
961 			continue;
962 
963 		VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
964 		if (za.za_integer_length == 1) {
965 			/*
966 			 * String property
967 			 */
968 			char *tmp = kmem_alloc(za.za_num_integers,
969 			    KM_SLEEP);
970 			err = zap_lookup(mos, propobj,
971 			    za.za_name, 1, za.za_num_integers, tmp);
972 			if (err != 0) {
973 				kmem_free(tmp, za.za_num_integers);
974 				break;
975 			}
976 			VERIFY(nvlist_add_string(propval, ZPROP_VALUE,
977 			    tmp) == 0);
978 			kmem_free(tmp, za.za_num_integers);
979 		} else {
980 			/*
981 			 * Integer property
982 			 */
983 			ASSERT(za.za_integer_length == 8);
984 			(void) nvlist_add_uint64(propval, ZPROP_VALUE,
985 			    za.za_first_integer);
986 		}
987 
988 		VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, source) == 0);
989 		VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
990 		nvlist_free(propval);
991 	}
992 	zap_cursor_fini(&zc);
993 	if (err == ENOENT)
994 		err = 0;
995 	return (err);
996 }
997 
998 /*
999  * Iterate over all properties for this dataset and return them in an nvlist.
1000  */
1001 static int
1002 dsl_prop_get_all_ds(dsl_dataset_t *ds, nvlist_t **nvp,
1003     dsl_prop_getflags_t flags)
1004 {
1005 	dsl_dir_t *dd = ds->ds_dir;
1006 	dsl_pool_t *dp = dd->dd_pool;
1007 	objset_t *mos = dp->dp_meta_objset;
1008 	int err = 0;
1009 	char setpoint[MAXNAMELEN];
1010 
1011 	VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1012 
1013 	if (dsl_dataset_is_snapshot(ds))
1014 		flags |= DSL_PROP_GET_SNAPSHOT;
1015 
1016 	rw_enter(&dp->dp_config_rwlock, RW_READER);
1017 
1018 	if (ds->ds_phys->ds_props_obj != 0) {
1019 		ASSERT(flags & DSL_PROP_GET_SNAPSHOT);
1020 		dsl_dataset_name(ds, setpoint);
1021 		err = dsl_prop_get_all_impl(mos, ds->ds_phys->ds_props_obj,
1022 		    setpoint, flags, *nvp);
1023 		if (err)
1024 			goto out;
1025 	}
1026 
1027 	for (; dd != NULL; dd = dd->dd_parent) {
1028 		if (dd != ds->ds_dir || (flags & DSL_PROP_GET_SNAPSHOT)) {
1029 			if (flags & (DSL_PROP_GET_LOCAL |
1030 			    DSL_PROP_GET_RECEIVED))
1031 				break;
1032 			flags |= DSL_PROP_GET_INHERITING;
1033 		}
1034 		dsl_dir_name(dd, setpoint);
1035 		err = dsl_prop_get_all_impl(mos, dd->dd_phys->dd_props_zapobj,
1036 		    setpoint, flags, *nvp);
1037 		if (err)
1038 			break;
1039 	}
1040 out:
1041 	rw_exit(&dp->dp_config_rwlock);
1042 	return (err);
1043 }
1044 
1045 boolean_t
1046 dsl_prop_get_hasrecvd(objset_t *os)
1047 {
1048 	dsl_dataset_t *ds = os->os_dsl_dataset;
1049 	int rc;
1050 	uint64_t dummy;
1051 
1052 	rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER);
1053 	rc = dsl_prop_get_ds(ds, ZPROP_HAS_RECVD, 8, 1, &dummy, NULL);
1054 	rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock);
1055 	ASSERT(rc != 0 || spa_version(os->os_spa) >= SPA_VERSION_RECVD_PROPS);
1056 	return (rc == 0);
1057 }
1058 
1059 static void
1060 dsl_prop_set_hasrecvd_impl(objset_t *os, zprop_source_t source)
1061 {
1062 	dsl_dataset_t *ds = os->os_dsl_dataset;
1063 	uint64_t dummy = 0;
1064 	dsl_prop_setarg_t psa;
1065 
1066 	if (spa_version(os->os_spa) < SPA_VERSION_RECVD_PROPS)
1067 		return;
1068 
1069 	dsl_prop_setarg_init_uint64(&psa, ZPROP_HAS_RECVD, source, &dummy);
1070 
1071 	(void) dsl_sync_task_do(ds->ds_dir->dd_pool, NULL,
1072 	    dsl_prop_set_sync, ds, &psa, 2);
1073 }
1074 
1075 /*
1076  * Call after successfully receiving properties to ensure that only the first
1077  * receive on or after SPA_VERSION_RECVD_PROPS blows away local properties.
1078  */
1079 void
1080 dsl_prop_set_hasrecvd(objset_t *os)
1081 {
1082 	if (dsl_prop_get_hasrecvd(os)) {
1083 		ASSERT(spa_version(os->os_spa) >= SPA_VERSION_RECVD_PROPS);
1084 		return;
1085 	}
1086 	dsl_prop_set_hasrecvd_impl(os, ZPROP_SRC_LOCAL);
1087 }
1088 
1089 void
1090 dsl_prop_unset_hasrecvd(objset_t *os)
1091 {
1092 	dsl_prop_set_hasrecvd_impl(os, ZPROP_SRC_NONE);
1093 }
1094 
1095 int
1096 dsl_prop_get_all(objset_t *os, nvlist_t **nvp)
1097 {
1098 	return (dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, 0));
1099 }
1100 
1101 int
1102 dsl_prop_get_received(objset_t *os, nvlist_t **nvp)
1103 {
1104 	/*
1105 	 * Received properties are not distinguishable from local properties
1106 	 * until the dataset has received properties on or after
1107 	 * SPA_VERSION_RECVD_PROPS.
1108 	 */
1109 	dsl_prop_getflags_t flags = (dsl_prop_get_hasrecvd(os) ?
1110 	    DSL_PROP_GET_RECEIVED : DSL_PROP_GET_LOCAL);
1111 	return (dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, flags));
1112 }
1113 
1114 void
1115 dsl_prop_nvlist_add_uint64(nvlist_t *nv, zfs_prop_t prop, uint64_t value)
1116 {
1117 	nvlist_t *propval;
1118 	const char *propname = zfs_prop_to_name(prop);
1119 	uint64_t default_value;
1120 
1121 	if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) {
1122 		VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0);
1123 		return;
1124 	}
1125 
1126 	VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1127 	VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0);
1128 	/* Indicate the default source if we can. */
1129 	if (dodefault(propname, 8, 1, &default_value) == 0 &&
1130 	    value == default_value) {
1131 		VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, "") == 0);
1132 	}
1133 	VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
1134 	nvlist_free(propval);
1135 }
1136 
1137 void
1138 dsl_prop_nvlist_add_string(nvlist_t *nv, zfs_prop_t prop, const char *value)
1139 {
1140 	nvlist_t *propval;
1141 	const char *propname = zfs_prop_to_name(prop);
1142 
1143 	if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) {
1144 		VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0);
1145 		return;
1146 	}
1147 
1148 	VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1149 	VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0);
1150 	VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
1151 	nvlist_free(propval);
1152 }
1153