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