1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
24 * Copyright (c) 2013 Martin Matuska. All rights reserved.
25 * Copyright 2015, Joyent, Inc.
26 * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
27 */
28
29 #include <sys/zfs_context.h>
30 #include <sys/dmu.h>
31 #include <sys/dmu_objset.h>
32 #include <sys/dmu_tx.h>
33 #include <sys/dsl_dataset.h>
34 #include <sys/dsl_dir.h>
35 #include <sys/dsl_prop.h>
36 #include <sys/dsl_synctask.h>
37 #include <sys/zfeature.h>
38 #include <sys/spa.h>
39 #include <sys/zap.h>
40 #include <sys/fs/zfs.h>
41 #include <sys/wbc.h>
42
43 #include "zfs_prop.h"
44 #include "zfs_errno.h"
45
46 static int
47 dodefault(zfs_prop_t prop, int intsz, int numints, void *buf)
48 {
49 /*
50 * The setonce properties are read-only, BUT they still
51 * have a default value that can be used as the initial
52 * value.
53 */
54 if (prop == ZPROP_INVAL ||
55 (zfs_prop_readonly(prop) && !zfs_prop_setonce(prop)))
56 return (SET_ERROR(ENOENT));
57
58 if (zfs_prop_get_type(prop) == PROP_TYPE_STRING) {
59 if (intsz != 1)
60 return (SET_ERROR(EOVERFLOW));
61 (void) strncpy(buf, zfs_prop_default_string(prop),
62 numints);
63 } else {
64 if (intsz != 8 || numints < 1)
65 return (SET_ERROR(EOVERFLOW));
66
67 *(uint64_t *)buf = zfs_prop_default_numeric(prop);
68 }
69
70 return (0);
71 }
72
73 int
74 dsl_prop_get_dd(dsl_dir_t *dd, const char *propname,
75 int intsz, int numints, void *buf, char *setpoint, boolean_t snapshot)
76 {
77 int err = ENOENT;
78 dsl_dir_t *target = dd;
79 objset_t *mos = dd->dd_pool->dp_meta_objset;
80 zfs_prop_t prop;
81 boolean_t inheritable;
82 boolean_t inheriting = B_FALSE;
83 char *inheritstr;
84 char *recvdstr;
85
86 ASSERT(dsl_pool_config_held(dd->dd_pool));
87
88 if (setpoint)
89 setpoint[0] = '\0';
90
91 prop = zfs_name_to_prop(propname);
92 inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop));
93 inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX);
94 recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX);
95
96 /*
97 * Note: dd may become NULL, therefore we shouldn't dereference it
98 * after this loop.
99 */
100 for (; dd != NULL; dd = dd->dd_parent) {
101 if (dd != target || snapshot) {
102 if (!inheritable)
103 break;
104 inheriting = B_TRUE;
105 }
106
107 /* Check for a local value. */
108 err = zap_lookup(mos, dsl_dir_phys(dd)->dd_props_zapobj,
109 propname, intsz, numints, buf);
110 if (err != ENOENT) {
111 if (setpoint != NULL && err == 0)
112 dsl_dir_name(dd, setpoint);
113 break;
114 }
115
116 /*
117 * Skip the check for a received value if there is an explicit
118 * inheritance entry.
119 */
120 err = zap_contains(mos, dsl_dir_phys(dd)->dd_props_zapobj,
121 inheritstr);
122 if (err != 0 && err != ENOENT)
123 break;
124
125 if (err == ENOENT) {
126 /* Check for a received value. */
127 err = zap_lookup(mos, dsl_dir_phys(dd)->dd_props_zapobj,
128 recvdstr, intsz, numints, buf);
129 if (err != ENOENT) {
130 if (setpoint != NULL && err == 0) {
131 if (inheriting) {
132 dsl_dir_name(dd, setpoint);
133 } else {
134 (void) strcpy(setpoint,
135 ZPROP_SOURCE_VAL_RECVD);
136 }
137 }
138 break;
139 }
140 }
141
142 /*
143 * If we found an explicit inheritance entry, err is zero even
144 * though we haven't yet found the value, so reinitializing err
145 * at the end of the loop (instead of at the beginning) ensures
146 * that err has a valid post-loop value.
147 */
148 err = SET_ERROR(ENOENT);
149 }
150
151 if (err == ENOENT)
152 err = dodefault(prop, intsz, numints, buf);
153
154 strfree(inheritstr);
155 strfree(recvdstr);
156
157 return (err);
158 }
159
160 int
161 dsl_prop_get_ds(dsl_dataset_t *ds, const char *propname,
162 int intsz, int numints, void *buf, char *setpoint)
163 {
164 zfs_prop_t prop = zfs_name_to_prop(propname);
165 boolean_t inheritable;
166 uint64_t zapobj;
167
168 ASSERT(dsl_pool_config_held(ds->ds_dir->dd_pool));
169 inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop));
170 zapobj = dsl_dataset_phys(ds)->ds_props_obj;
171
172 if (zapobj != 0) {
173 objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
174 int err;
175
176 ASSERT(ds->ds_is_snapshot);
177
178 /* Check for a local value. */
179 err = zap_lookup(mos, zapobj, propname, intsz, numints, buf);
180 if (err != ENOENT) {
181 if (setpoint != NULL && err == 0)
182 dsl_dataset_name(ds, setpoint);
183 return (err);
184 }
185
186 /*
187 * Skip the check for a received value if there is an explicit
188 * inheritance entry.
189 */
190 if (inheritable) {
191 char *inheritstr = kmem_asprintf("%s%s", propname,
192 ZPROP_INHERIT_SUFFIX);
193 err = zap_contains(mos, zapobj, inheritstr);
194 strfree(inheritstr);
195 if (err != 0 && err != ENOENT)
196 return (err);
197 }
198
199 if (err == ENOENT) {
200 /* Check for a received value. */
201 char *recvdstr = kmem_asprintf("%s%s", propname,
202 ZPROP_RECVD_SUFFIX);
203 err = zap_lookup(mos, zapobj, recvdstr,
204 intsz, numints, buf);
205 strfree(recvdstr);
206 if (err != ENOENT) {
207 if (setpoint != NULL && err == 0)
208 (void) strcpy(setpoint,
209 ZPROP_SOURCE_VAL_RECVD);
210 return (err);
211 }
212 }
213 }
214
215 return (dsl_prop_get_dd(ds->ds_dir, propname,
216 intsz, numints, buf, setpoint, ds->ds_is_snapshot));
217 }
218
219 static dsl_prop_record_t *
220 dsl_prop_record_find(dsl_dir_t *dd, const char *propname)
221 {
222 dsl_prop_record_t *pr = NULL;
223
224 ASSERT(MUTEX_HELD(&dd->dd_lock));
225
226 for (pr = list_head(&dd->dd_props);
227 pr != NULL; pr = list_next(&dd->dd_props, pr)) {
228 if (strcmp(pr->pr_propname, propname) == 0)
229 break;
230 }
231
232 return (pr);
233 }
234
235 static dsl_prop_record_t *
236 dsl_prop_record_create(dsl_dir_t *dd, const char *propname)
237 {
238 dsl_prop_record_t *pr;
239
240 ASSERT(MUTEX_HELD(&dd->dd_lock));
241
242 pr = kmem_alloc(sizeof (dsl_prop_record_t), KM_SLEEP);
243 pr->pr_propname = spa_strdup(propname);
244 list_create(&pr->pr_cbs, sizeof (dsl_prop_cb_record_t),
245 offsetof(dsl_prop_cb_record_t, cbr_pr_node));
246 list_insert_head(&dd->dd_props, pr);
247
248 return (pr);
249 }
250
251 void
252 dsl_prop_init(dsl_dir_t *dd)
253 {
254 list_create(&dd->dd_props, sizeof (dsl_prop_record_t),
255 offsetof(dsl_prop_record_t, pr_node));
256 }
257
258 void
259 dsl_prop_fini(dsl_dir_t *dd)
260 {
261 dsl_prop_record_t *pr;
262
263 while ((pr = list_remove_head(&dd->dd_props)) != NULL) {
264 list_destroy(&pr->pr_cbs);
265 strfree((char *)pr->pr_propname);
266 kmem_free(pr, sizeof (dsl_prop_record_t));
267 }
268 list_destroy(&dd->dd_props);
269 }
270
271 /*
272 * Register interest in the named property. We'll call the callback
273 * once to notify it of the current property value, and again each time
274 * the property changes, until this callback is unregistered.
275 *
276 * Return 0 on success, errno if the prop is not an integer value.
277 */
278 int
279 dsl_prop_register(dsl_dataset_t *ds, const char *propname,
280 dsl_prop_changed_cb_t *callback, void *cbarg)
281 {
282 dsl_dir_t *dd = ds->ds_dir;
283 dsl_pool_t *dp = dd->dd_pool;
284 uint64_t value;
285 dsl_prop_record_t *pr;
286 dsl_prop_cb_record_t *cbr;
287 int err;
288
289 ASSERT(dsl_pool_config_held(dp));
290
291 if (zfs_name_to_prop(propname) == ZFS_PROP_WBC_MODE) {
292 wbc_mode_prop_val_t val;
293
294 err = dsl_prop_get_ds(ds, propname, 8,
295 WBC_MODE_PROP_VAL_SZ, &val, NULL);
296 if (err == 0)
297 value = (uintptr_t)((void *)&val);
298 } else
299 err = dsl_prop_get_int_ds(ds, propname, &value);
300
301 if (err != 0)
302 return (err);
303
304 cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP);
305 cbr->cbr_ds = ds;
306 cbr->cbr_func = callback;
307 cbr->cbr_arg = cbarg;
308
309 mutex_enter(&dd->dd_lock);
310 pr = dsl_prop_record_find(dd, propname);
311 if (pr == NULL)
312 pr = dsl_prop_record_create(dd, propname);
313 cbr->cbr_pr = pr;
314 list_insert_head(&pr->pr_cbs, cbr);
315 list_insert_head(&ds->ds_prop_cbs, cbr);
316 mutex_exit(&dd->dd_lock);
317
318 cbr->cbr_func(cbr->cbr_arg, value);
319 return (0);
320 }
321
322 int
323 dsl_prop_get(const char *dsname, const char *propname,
324 int intsz, int numints, void *buf, char *setpoint)
325 {
326 objset_t *os;
327 int error;
328
329 error = dmu_objset_hold(dsname, FTAG, &os);
330 if (error != 0)
331 return (error);
332
333 error = dsl_prop_get_ds(dmu_objset_ds(os), propname,
334 intsz, numints, buf, setpoint);
335
336 dmu_objset_rele(os, FTAG);
337 return (error);
338 }
339
340 /*
341 * Get the current property value. It may have changed by the time this
342 * function returns, so it is NOT safe to follow up with
343 * dsl_prop_register() and assume that the value has not changed in
344 * between.
345 *
346 * Return 0 on success, ENOENT if ddname is invalid.
347 */
348 int
349 dsl_prop_get_integer(const char *ddname, const char *propname,
350 uint64_t *valuep, char *setpoint)
351 {
352 return (dsl_prop_get(ddname, propname, 8, 1, valuep, setpoint));
353 }
354
355 int
356 dsl_prop_get_int_ds(dsl_dataset_t *ds, const char *propname,
357 uint64_t *valuep)
358 {
359 return (dsl_prop_get_ds(ds, propname, 8, 1, valuep, NULL));
360 }
361
362 /*
363 * Predict the effective value of the given special property if it were set with
364 * the given value and source. This is not a general purpose function. It exists
365 * only to handle the special requirements of the quota and reservation
366 * properties. The fact that these properties are non-inheritable greatly
367 * simplifies the prediction logic.
368 *
369 * Returns 0 on success, a positive error code on failure, or -1 if called with
370 * a property not handled by this function.
371 */
372 int
373 dsl_prop_predict(dsl_dir_t *dd, const char *propname,
374 zprop_source_t source, uint64_t value, uint64_t *newvalp)
375 {
376 zfs_prop_t prop = zfs_name_to_prop(propname);
377 objset_t *mos;
378 uint64_t zapobj;
379 uint64_t version;
380 char *recvdstr;
381 int err = 0;
382
383 switch (prop) {
384 case ZFS_PROP_QUOTA:
385 case ZFS_PROP_RESERVATION:
386 case ZFS_PROP_REFQUOTA:
387 case ZFS_PROP_REFRESERVATION:
388 break;
389 default:
390 return (-1);
391 }
392
393 mos = dd->dd_pool->dp_meta_objset;
394 zapobj = dsl_dir_phys(dd)->dd_props_zapobj;
395 recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX);
396
397 version = spa_version(dd->dd_pool->dp_spa);
398 if (version < SPA_VERSION_RECVD_PROPS) {
399 if (source & ZPROP_SRC_NONE)
400 source = ZPROP_SRC_NONE;
401 else if (source & ZPROP_SRC_RECEIVED)
402 source = ZPROP_SRC_LOCAL;
403 }
404
405 switch (source) {
406 case ZPROP_SRC_NONE:
407 /* Revert to the received value, if any. */
408 err = zap_lookup(mos, zapobj, recvdstr, 8, 1, newvalp);
409 if (err == ENOENT)
410 *newvalp = 0;
411 break;
412 case ZPROP_SRC_LOCAL:
413 *newvalp = value;
414 break;
415 case ZPROP_SRC_RECEIVED:
416 /*
417 * If there's no local setting, then the new received value will
418 * be the effective value.
419 */
420 err = zap_lookup(mos, zapobj, propname, 8, 1, newvalp);
421 if (err == ENOENT)
422 *newvalp = value;
423 break;
424 case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED):
425 /*
426 * We're clearing the received value, so the local setting (if
427 * it exists) remains the effective value.
428 */
429 err = zap_lookup(mos, zapobj, propname, 8, 1, newvalp);
430 if (err == ENOENT)
431 *newvalp = 0;
432 break;
433 default:
434 panic("unexpected property source: %d", source);
435 }
436
437 strfree(recvdstr);
438
439 if (err == ENOENT)
440 return (0);
441
442 return (err);
443 }
444
445 /*
446 * Unregister all callbacks that are registered with the
447 * given callback argument.
448 */
449 void
450 dsl_prop_unregister_all(dsl_dataset_t *ds, void *cbarg)
451 {
452 dsl_prop_cb_record_t *cbr, *next_cbr;
453
454 dsl_dir_t *dd = ds->ds_dir;
455
456 mutex_enter(&dd->dd_lock);
457 next_cbr = list_head(&ds->ds_prop_cbs);
458 while (next_cbr != NULL) {
459 cbr = next_cbr;
460 next_cbr = list_next(&ds->ds_prop_cbs, cbr);
461 if (cbr->cbr_arg == cbarg) {
462 list_remove(&ds->ds_prop_cbs, cbr);
463 list_remove(&cbr->cbr_pr->pr_cbs, cbr);
464 kmem_free(cbr, sizeof (dsl_prop_cb_record_t));
465 }
466 }
467 mutex_exit(&dd->dd_lock);
468 }
469
470 boolean_t
471 dsl_prop_hascb(dsl_dataset_t *ds)
472 {
473 return (!list_is_empty(&ds->ds_prop_cbs));
474 }
475
476 /* ARGSUSED */
477 static int
478 dsl_prop_notify_all_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg)
479 {
480 dsl_dir_t *dd = ds->ds_dir;
481 dsl_prop_record_t *pr;
482 dsl_prop_cb_record_t *cbr;
483
484 mutex_enter(&dd->dd_lock);
485 for (pr = list_head(&dd->dd_props);
486 pr; pr = list_next(&dd->dd_props, pr)) {
487 for (cbr = list_head(&pr->pr_cbs); cbr;
488 cbr = list_next(&pr->pr_cbs, cbr)) {
489 uint64_t value;
490 const char *propname;
491
492 /*
493 * Callback entries do not have holds on their
494 * datasets so that datasets with registered
495 * callbacks are still eligible for eviction.
496 * Unlike operations to update properties on a
497 * single dataset, we are performing a recursive
498 * descent of related head datasets. The caller
499 * of this function only has a dataset hold on
500 * the passed in head dataset, not the snapshots
501 * associated with this dataset. Without a hold,
502 * the dataset pointer within callback records
503 * for snapshots can be invalidated by eviction
504 * at any time.
505 *
506 * Use dsl_dataset_try_add_ref() to verify
507 * that the dataset for a snapshot has not
508 * begun eviction processing and to prevent
509 * eviction from occurring for the duration of
510 * the callback. If the hold attempt fails,
511 * this object is already being evicted and the
512 * callback can be safely ignored.
513 */
514 if (ds != cbr->cbr_ds &&
515 !dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG))
516 continue;
517
518 propname = cbr->cbr_pr->pr_propname;
519 if (zfs_name_to_prop(propname) == ZFS_PROP_WBC_MODE) {
520 wbc_mode_prop_val_t val;
521
522 if (dsl_prop_get_ds(cbr->cbr_ds, propname, 8,
523 WBC_MODE_PROP_VAL_SZ, &val, NULL) == 0) {
524 value = (uintptr_t)((void *)&val);
525 cbr->cbr_func(cbr->cbr_arg, value);
526 }
527 } else if (dsl_prop_get_ds(cbr->cbr_ds, propname,
528 sizeof (value), 1, &value, NULL) == 0) {
529 cbr->cbr_func(cbr->cbr_arg, value);
530 }
531
532 if (ds != cbr->cbr_ds)
533 dsl_dataset_rele(cbr->cbr_ds, FTAG);
534 }
535 }
536 mutex_exit(&dd->dd_lock);
537
538 return (0);
539 }
540
541 /*
542 * Update all property values for ddobj & its descendants. This is used
543 * when renaming the dir.
544 */
545 void
546 dsl_prop_notify_all(dsl_dir_t *dd)
547 {
548 dsl_pool_t *dp = dd->dd_pool;
549 ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock));
550 (void) dmu_objset_find_dp(dp, dd->dd_object, dsl_prop_notify_all_cb,
551 NULL, DS_FIND_CHILDREN);
552 }
553
554 static void
555 dsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj,
556 const char *propname, uint64_t value, int first)
557 {
558 dsl_dir_t *dd;
559 dsl_prop_record_t *pr;
560 dsl_prop_cb_record_t *cbr;
561 objset_t *mos = dp->dp_meta_objset;
562 zap_cursor_t zc;
563 zap_attribute_t *za;
564 int err;
565
566 ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock));
567 err = dsl_dir_hold_obj(dp, ddobj, NULL, FTAG, &dd);
568 if (err)
569 return;
570
571 if (!first) {
572 /*
573 * If the prop is set here, then this change is not
574 * being inherited here or below; stop the recursion.
575 */
576 err = zap_contains(mos, dsl_dir_phys(dd)->dd_props_zapobj,
577 propname);
578 if (err == 0) {
579 dsl_dir_rele(dd, FTAG);
580 return;
581 }
582 ASSERT3U(err, ==, ENOENT);
583 }
584
585 mutex_enter(&dd->dd_lock);
586 pr = dsl_prop_record_find(dd, propname);
587 if (pr != NULL) {
588 for (cbr = list_head(&pr->pr_cbs); cbr;
589 cbr = list_next(&pr->pr_cbs, cbr)) {
590 uint64_t propobj;
591
592 /*
593 * cbr->cbr_ds may be invalidated due to eviction,
594 * requiring the use of dsl_dataset_try_add_ref().
595 * See comment block in dsl_prop_notify_all_cb()
596 * for details.
597 */
598 if (!dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG))
599 continue;
600
601 propobj = dsl_dataset_phys(cbr->cbr_ds)->ds_props_obj;
602
603 /*
604 * If the property is not set on this ds, then it is
605 * inherited here; call the callback.
606 */
607 if (propobj == 0 ||
608 zap_contains(mos, propobj, propname) != 0)
609 cbr->cbr_func(cbr->cbr_arg, value);
610
611 dsl_dataset_rele(cbr->cbr_ds, FTAG);
612 }
613 }
614 mutex_exit(&dd->dd_lock);
615
616 za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
617 for (zap_cursor_init(&zc, mos,
618 dsl_dir_phys(dd)->dd_child_dir_zapobj);
619 zap_cursor_retrieve(&zc, za) == 0;
620 zap_cursor_advance(&zc)) {
621 dsl_prop_changed_notify(dp, za->za_first_integer,
622 propname, value, FALSE);
623 }
624 kmem_free(za, sizeof (zap_attribute_t));
625 zap_cursor_fini(&zc);
626 dsl_dir_rele(dd, FTAG);
627 }
628
629 void
630 dsl_prop_set_sync_impl(dsl_dataset_t *ds, const char *propname,
631 zprop_source_t source, int intsz, int numints, const void *value,
632 dmu_tx_t *tx)
633 {
634 objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
635 uint64_t zapobj, intval, dummy;
636 int isint;
637 char valbuf[32];
638 const char *valstr = NULL;
639 char *inheritstr;
640 char *recvdstr;
641 char *tbuf = NULL;
642 int err;
643 spa_t *spa = ds->ds_dir->dd_pool->dp_spa;
644 uint64_t version = spa_version(spa);
645
646 isint = (dodefault(zfs_name_to_prop(propname), 8, 1, &intval) == 0);
647
648 if (ds->ds_is_snapshot) {
649 ASSERT(version >= SPA_VERSION_SNAP_PROPS);
650 if (dsl_dataset_phys(ds)->ds_props_obj == 0) {
651 dmu_buf_will_dirty(ds->ds_dbuf, tx);
652 dsl_dataset_phys(ds)->ds_props_obj =
653 zap_create(mos,
654 DMU_OT_DSL_PROPS, DMU_OT_NONE, 0, tx);
655 }
656 zapobj = dsl_dataset_phys(ds)->ds_props_obj;
657 } else {
658 zapobj = dsl_dir_phys(ds->ds_dir)->dd_props_zapobj;
659 }
660
661 if (version < SPA_VERSION_RECVD_PROPS) {
662 if (source & ZPROP_SRC_NONE)
663 source = ZPROP_SRC_NONE;
664 else if (source & ZPROP_SRC_RECEIVED)
665 source = ZPROP_SRC_LOCAL;
666 }
667
668 inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX);
669 recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX);
670
671 switch (source) {
672 case ZPROP_SRC_NONE:
673 /*
674 * revert to received value, if any (inherit -S)
675 * - remove propname
676 * - remove propname$inherit
677 */
678 err = zap_remove(mos, zapobj, propname, tx);
679 ASSERT(err == 0 || err == ENOENT);
680 err = zap_remove(mos, zapobj, inheritstr, tx);
681 ASSERT(err == 0 || err == ENOENT);
682 break;
683 case ZPROP_SRC_LOCAL:
684 /*
685 * remove propname$inherit
686 * set propname -> value
687 */
688 err = zap_remove(mos, zapobj, inheritstr, tx);
689 ASSERT(err == 0 || err == ENOENT);
690 VERIFY0(zap_update(mos, zapobj, propname,
691 intsz, numints, value, tx));
692 break;
693 case ZPROP_SRC_INHERITED:
694 /*
695 * explicitly inherit
696 * - remove propname
697 * - set propname$inherit
698 */
699 err = zap_remove(mos, zapobj, propname, tx);
700 ASSERT(err == 0 || err == ENOENT);
701 if (version >= SPA_VERSION_RECVD_PROPS &&
702 dsl_prop_get_int_ds(ds, ZPROP_HAS_RECVD, &dummy) == 0) {
703 dummy = 0;
704 VERIFY0(zap_update(mos, zapobj, inheritstr,
705 8, 1, &dummy, tx));
706 }
707 break;
708 case ZPROP_SRC_RECEIVED:
709 /*
710 * set propname$recvd -> value
711 */
712 err = zap_update(mos, zapobj, recvdstr,
713 intsz, numints, value, tx);
714 ASSERT(err == 0);
715 break;
716 case (ZPROP_SRC_NONE | ZPROP_SRC_LOCAL | ZPROP_SRC_RECEIVED):
717 /*
718 * clear local and received settings
719 * - remove propname
720 * - remove propname$inherit
721 * - remove propname$recvd
722 */
723 err = zap_remove(mos, zapobj, propname, tx);
724 ASSERT(err == 0 || err == ENOENT);
725 err = zap_remove(mos, zapobj, inheritstr, tx);
726 ASSERT(err == 0 || err == ENOENT);
727 /* FALLTHRU */
728 case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED):
729 /*
730 * remove propname$recvd
731 */
732 err = zap_remove(mos, zapobj, recvdstr, tx);
733 ASSERT(err == 0 || err == ENOENT);
734 break;
735 default:
736 cmn_err(CE_PANIC, "unexpected property source: %d", source);
737 }
738
739 strfree(inheritstr);
740 strfree(recvdstr);
741
742 if (zfs_name_to_prop(propname) == ZFS_PROP_WBC_MODE) {
743 wbc_mode_prop_val_t val;
744
745 VERIFY0(dsl_prop_get_ds(ds, propname, 8,
746 WBC_MODE_PROP_VAL_SZ, &val, NULL));
747
748 dsl_prop_changed_notify(ds->ds_dir->dd_pool,
749 ds->ds_dir->dd_object, propname,
750 (uintptr_t)((void *)&val), TRUE);
751
752 /*
753 * Flow diagram of ZFS_PROP_WBC_MODE states
754 *
755 * off (root_ds_object == 0, txg_off == 0)
756 * (user sees wbc_mode=off, source=default)
757 *
758 * user operation "set on" ==>>
759 *
760 * on (root_ds_object != 0, txg_off == 0)
761 * (user sees wbc_mode=on, source=local)
762 *
763 * user operation "set off" ==>>
764 *
765 * off_delayed (root_ds_object != 0, txg_off != 0)
766 * (user sees wbc_mode=off, source=local)
767 *
768 * internal operation "inherit" ==>>
769 *
770 * off (root_ds_object == 0, txg_off == 0)
771 * (user sees wbc_mode=off, source=default)
772 */
773 if (val.root_ds_object == 0)
774 spa_feature_decr(spa, SPA_FEATURE_WBC, tx);
775 else if (val.txg_off == 0)
776 spa_feature_incr(spa, SPA_FEATURE_WBC, tx);
777
778 (void) snprintf(valbuf, sizeof (valbuf),
779 "%s", (val.root_ds_object != 0 &&
780 val.txg_off == 0) ? "on" : "off");
781 valstr = valbuf;
782 } else if (isint) {
783 VERIFY0(dsl_prop_get_int_ds(ds, propname, &intval));
784
785 if (ds->ds_is_snapshot) {
786 dsl_prop_cb_record_t *cbr;
787 /*
788 * It's a snapshot; nothing can inherit this
789 * property, so just look for callbacks on this
790 * ds here.
791 */
792 mutex_enter(&ds->ds_dir->dd_lock);
793 for (cbr = list_head(&ds->ds_prop_cbs); cbr;
794 cbr = list_next(&ds->ds_prop_cbs, cbr)) {
795 if (strcmp(cbr->cbr_pr->pr_propname,
796 propname) == 0)
797 cbr->cbr_func(cbr->cbr_arg, intval);
798 }
799 mutex_exit(&ds->ds_dir->dd_lock);
800 } else {
801 dsl_prop_changed_notify(ds->ds_dir->dd_pool,
802 ds->ds_dir->dd_object, propname, intval, TRUE);
803 }
804
805 (void) snprintf(valbuf, sizeof (valbuf),
806 "%lld", (longlong_t)intval);
807 valstr = valbuf;
808 } else {
809 if (source == ZPROP_SRC_LOCAL) {
810 valstr = value;
811 } else {
812 tbuf = kmem_alloc(ZAP_MAXVALUELEN, KM_SLEEP);
813 if (dsl_prop_get_ds(ds, propname, 1,
814 ZAP_MAXVALUELEN, tbuf, NULL) == 0)
815 valstr = tbuf;
816 }
817 }
818
819 spa_history_log_internal_ds(ds, (source == ZPROP_SRC_NONE ||
820 source == ZPROP_SRC_INHERITED) ? "inherit" : "set", tx,
821 "%s=%s", propname, (valstr == NULL ? "" : valstr));
822
823 if (tbuf != NULL)
824 kmem_free(tbuf, ZAP_MAXVALUELEN);
825 }
826
827 int
828 dsl_prop_set_int(const char *dsname, const char *propname,
829 zprop_source_t source, uint64_t value)
830 {
831 nvlist_t *nvl = fnvlist_alloc();
832 int error;
833
834 fnvlist_add_uint64(nvl, propname, value);
835 error = dsl_props_set(dsname, source, nvl);
836 fnvlist_free(nvl);
837 return (error);
838 }
839
840 int
841 dsl_prop_set_string(const char *dsname, const char *propname,
842 zprop_source_t source, const char *value)
843 {
844 nvlist_t *nvl = fnvlist_alloc();
845 int error;
846
847 fnvlist_add_string(nvl, propname, value);
848 error = dsl_props_set(dsname, source, nvl);
849 fnvlist_free(nvl);
850 return (error);
851 }
852
853 int
854 dsl_prop_inherit(const char *dsname, const char *propname,
855 zprop_source_t source)
856 {
857 nvlist_t *nvl = fnvlist_alloc();
858 int error;
859
860 fnvlist_add_boolean(nvl, propname);
861 error = dsl_props_set(dsname, source, nvl);
862 fnvlist_free(nvl);
863 return (error);
864 }
865
866 /* ARGSUSED */
867 static int
868 dsl_prop_wbc_mode_check_child_cb(dsl_pool_t *dp,
869 dsl_dataset_t *ds, void *arg)
870 {
871 int err;
872 zfs_prop_t *prop = arg;
873 objset_t *os = NULL;
874
875 err = dmu_objset_from_ds(ds, &os);
876 if (err != 0)
877 return (err);
878
879 if (*prop == ZFS_PROP_DEDUP) {
880 /*
881 * User tries to set ZFS_PROP_DEDUP.
882 * In this case we just check that
883 * the target DS and its children
884 * do not use writecache
885 */
886 if (os->os_wbc_mode != ZFS_WBC_MODE_OFF)
887 return (SET_ERROR(EKZFS_WBCCONFLICT));
888 } else {
889 ASSERT3U(*prop, ==, ZFS_PROP_WBC_MODE);
890
891 /*
892 * User tries to set ZFS_PROP_WBC_MODE.
893 * In this case we need check that
894 * the target DS and its children
895 * do not use writecache and dedup
896 */
897 if (os->os_wbc_mode != ZFS_WBC_MODE_OFF)
898 return (SET_ERROR(EKZFS_WBCCHILD));
899
900 if (os->os_dedup_checksum != ZIO_CHECKSUM_OFF)
901 return (SET_ERROR(EKZFS_WBCCONFLICT));
902 }
903
904 return (0);
905 }
906
907 static int
908 dsl_prop_wbc_mode_check(dsl_dataset_t *ds, objset_t *os)
909 {
910 int err = 0;
911 zfs_prop_t prop = ZFS_PROP_WBC_MODE;
912
913 if (os->os_wbc_mode != ZFS_WBC_MODE_OFF) {
914 /*
915 * ZFS_PROP_WBC_MODE cannot be set for
916 * a child DS if the prop was set for
917 * the parent
918 */
919 if (os->os_wbc_root_ds_obj != ds->ds_object)
920 return (SET_ERROR(EKZFS_WBCPARENT));
921 } else {
922 /*
923 * Is not allowed to change wbc_mode for parent
924 * if its children already have the changed prop
925 */
926 err = dmu_objset_find_dp(ds->ds_dir->dd_pool,
927 ds->ds_dir->dd_object,
928 dsl_prop_wbc_mode_check_child_cb, &prop,
929 DS_FIND_CHILDREN);
930 }
931
932 return (err);
933 }
934
935 typedef struct dsl_props_set_arg {
936 const char *dpsa_dsname;
937 zprop_source_t dpsa_source;
938 nvlist_t *dpsa_props;
939 } dsl_props_set_arg_t;
940
941 static int
942 dsl_props_set_check(void *arg, dmu_tx_t *tx)
943 {
944 dsl_props_set_arg_t *dpsa = arg;
945 dsl_pool_t *dp = dmu_tx_pool(tx);
946 dsl_dataset_t *ds;
947 objset_t *os = NULL;
948 uint64_t version;
949 nvpair_t *elem = NULL;
950 int err;
951
952 err = dsl_dataset_hold(dp, dpsa->dpsa_dsname, FTAG, &ds);
953 if (err != 0)
954 return (err);
955
956 err = dmu_objset_from_ds(ds, &os);
957 if (err != 0) {
958 dsl_dataset_rele(ds, FTAG);
959 return (err);
960 }
961
962 version = spa_version(ds->ds_dir->dd_pool->dp_spa);
963 while ((elem = nvlist_next_nvpair(dpsa->dpsa_props, elem)) != NULL) {
964 const char *prop_name = nvpair_name(elem);
965 zfs_prop_t prop = zfs_name_to_prop(prop_name);
966
967 if (strlen(prop_name) >= ZAP_MAXNAMELEN) {
968 dsl_dataset_rele(ds, FTAG);
969 return (SET_ERROR(ENAMETOOLONG));
970 }
971
972 /*
973 * Deduplication and WBC cannot be used together
974 * This code returns error also for case when
975 * WBC is ON, DEDUP is off and a user tries
976 * to do DEDUP=off, because in this case the code
977 * will be more complex, but benefit is too small
978 */
979 if (prop == ZFS_PROP_DEDUP) {
980 if (os->os_wbc_root_ds_obj != 0) {
981 dsl_dataset_rele(ds, FTAG);
982 return (SET_ERROR(EKZFS_WBCCONFLICT));
983 }
984
985 /*
986 * Need to be sure that children DS
987 * do not use writecache
988 */
989 err = dmu_objset_find_dp(ds->ds_dir->dd_pool,
990 ds->ds_dir->dd_object,
991 dsl_prop_wbc_mode_check_child_cb, &prop,
992 DS_FIND_CHILDREN);
993 if (err != 0) {
994 dsl_dataset_rele(ds, FTAG);
995 return (err);
996 }
997 }
998
999 if (prop == ZFS_PROP_WBC_MODE) {
1000 uint64_t wbc_mode_new = 0;
1001 data_type_t elem_type = nvpair_type(elem);
1002
1003 if (elem_type == DATA_TYPE_UINT64)
1004 wbc_mode_new = fnvpair_value_uint64(elem);
1005
1006 if (os->os_wbc_root_ds_obj == ds->ds_object &&
1007 elem_type == DATA_TYPE_UINT64) {
1008
1009 /*
1010 * ZFS_WBC_MODE_OFF_DELAYED means that
1011 * the coresponding wbc_instance is in
1012 * transition state: from ON to OFF
1013 * so ON/OFF is not permitted
1014 */
1015 if (os->os_wbc_mode ==
1016 ZFS_WBC_MODE_OFF_DELAYED) {
1017 dsl_dataset_rele(ds, FTAG);
1018 return (SET_ERROR(EINPROGRESS));
1019 }
1020
1021 ASSERT3U(os->os_wbc_mode, ==, ZFS_WBC_MODE_ON);
1022
1023 /* Check for double ON */
1024 if (wbc_mode_new == ZFS_WBC_MODE_ON) {
1025 dsl_dataset_rele(ds, FTAG);
1026 return (SET_ERROR(EALREADY));
1027 }
1028 }
1029
1030 err = dsl_prop_wbc_mode_check(ds, os);
1031 if (err != 0) {
1032 dsl_dataset_rele(ds, FTAG);
1033 return (err);
1034 }
1035
1036 /* Check for double OFF */
1037 if (os->os_wbc_root_ds_obj == 0 &&
1038 elem_type == DATA_TYPE_UINT64 &&
1039 wbc_mode_new == ZFS_WBC_MODE_OFF) {
1040 dsl_dataset_rele(ds, FTAG);
1041 return (SET_ERROR(EALREADY));
1042 }
1043
1044 continue;
1045 }
1046
1047 if (nvpair_type(elem) == DATA_TYPE_STRING) {
1048 char *valstr = fnvpair_value_string(elem);
1049 if (strlen(valstr) >= (version <
1050 SPA_VERSION_STMF_PROP ?
1051 ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) {
1052 dsl_dataset_rele(ds, FTAG);
1053 return (SET_ERROR(E2BIG));
1054 }
1055 }
1056
1057 }
1058
1059 if (ds->ds_is_snapshot && version < SPA_VERSION_SNAP_PROPS) {
1060 dsl_dataset_rele(ds, FTAG);
1061 return (SET_ERROR(ENOTSUP));
1062 }
1063 dsl_dataset_rele(ds, FTAG);
1064 return (0);
1065 }
1066
1067 void
1068 dsl_props_set_sync_impl(dsl_dataset_t *ds, zprop_source_t source,
1069 nvlist_t *props, dmu_tx_t *tx)
1070 {
1071 nvpair_t *elem = NULL;
1072
1073 while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
1074 nvpair_t *pair = elem;
1075
1076 if (nvpair_type(pair) == DATA_TYPE_NVLIST) {
1077 /*
1078 * dsl_prop_get_all_impl() returns properties in this
1079 * format.
1080 */
1081 nvlist_t *attrs = fnvpair_value_nvlist(pair);
1082 pair = fnvlist_lookup_nvpair(attrs, ZPROP_VALUE);
1083 }
1084
1085 if (nvpair_type(pair) == DATA_TYPE_STRING) {
1086 const char *value = fnvpair_value_string(pair);
1087 dsl_prop_set_sync_impl(ds, nvpair_name(pair),
1088 source, 1, strlen(value) + 1, value, tx);
1089 } else if (nvpair_type(pair) == DATA_TYPE_UINT64) {
1090 const char *propname = nvpair_name(pair);
1091 zfs_prop_t prop = zfs_name_to_prop(propname);
1092 uint64_t intval = fnvpair_value_uint64(pair);
1093
1094 if (prop == ZFS_PROP_WBC_MODE) {
1095 wbc_mode_prop_val_t val;
1096
1097 /*
1098 * Disabling WBC involves the following:
1099 * 1) all the subsequent data writes will
1100 * stop using special vdev
1101 * 2) already WriteBackCached data blocks
1102 * (with TXG <= txg_off below) will gradually
1103 * migrated from special vdev
1104 *
1105 * To handle this need to remember TXG.
1106 * WBC will be completely disabled for this DS,
1107 * after WBC-window cross this TXG
1108 */
1109 val.txg_off = (intval == 0) ? tx->tx_txg : 0;
1110 val.root_ds_object = ds->ds_object;
1111 val.flags = 0;
1112
1113 dsl_prop_set_sync_impl(ds, nvpair_name(pair),
1114 source, 8, WBC_MODE_PROP_VAL_SZ, &val, tx);
1115 } else {
1116 dsl_prop_set_sync_impl(ds, nvpair_name(pair),
1117 source, sizeof (intval), 1, &intval, tx);
1118 }
1119 } else if (nvpair_type(pair) == DATA_TYPE_BOOLEAN) {
1120 dsl_prop_set_sync_impl(ds, nvpair_name(pair),
1121 source, 0, 0, NULL, tx);
1122 } else {
1123 panic("invalid nvpair type");
1124 }
1125 }
1126 }
1127
1128 static void
1129 dsl_props_set_sync(void *arg, dmu_tx_t *tx)
1130 {
1131 dsl_props_set_arg_t *dpsa = arg;
1132 dsl_pool_t *dp = dmu_tx_pool(tx);
1133 dsl_dataset_t *ds;
1134 objset_t *os = NULL;
1135
1136 VERIFY0(dsl_dataset_hold(dp, dpsa->dpsa_dsname, FTAG, &ds));
1137 /*
1138 * Need to initialize os, to be sure that non-mounted datasets and
1139 * non-exposed zvols will receive notification about modified
1140 * properties.
1141 * During the initialization a property can register its callback
1142 * that will be called if the property is changed.
1143 * dsl_props_set_sync_impl() calls dsl_prop_changed_notify()
1144 * that calls the required callback if it exists.
1145 */
1146 VERIFY0(dmu_objset_from_ds(ds, &os));
1147 dsl_props_set_sync_impl(ds, dpsa->dpsa_source, dpsa->dpsa_props, tx);
1148 dsl_dataset_rele(ds, FTAG);
1149 }
1150
1151 /*
1152 * All-or-nothing; if any prop can't be set, nothing will be modified.
1153 */
1154 int
1155 dsl_props_set(const char *dsname, zprop_source_t source, nvlist_t *props)
1156 {
1157 dsl_props_set_arg_t dpsa;
1158 int nblks = 0;
1159
1160 dpsa.dpsa_dsname = dsname;
1161 dpsa.dpsa_source = source;
1162 dpsa.dpsa_props = props;
1163
1164 /*
1165 * If the source includes NONE, then we will only be removing entries
1166 * from the ZAP object. In that case don't check for ENOSPC.
1167 */
1168 if ((source & ZPROP_SRC_NONE) == 0)
1169 nblks = 2 * fnvlist_num_pairs(props);
1170
1171 return (dsl_sync_task(dsname, dsl_props_set_check, dsl_props_set_sync,
1172 &dpsa, nblks, ZFS_SPACE_CHECK_RESERVED));
1173 }
1174
1175 static void
1176 dsl_props_mds_set_sync(void *arg, dmu_tx_t *tx)
1177 {
1178 dsl_props_set_arg_t *top_dpsa = arg;
1179 dsl_pool_t *dp = dmu_tx_pool(tx);
1180 nvlist_t *dss_props = top_dpsa->dpsa_props;
1181 nvpair_t *pair = NULL;
1182
1183 while ((pair = nvlist_next_nvpair(dss_props, pair)) != NULL) {
1184 dsl_props_set_arg_t dpsa;
1185 dsl_dataset_t *ds = NULL;
1186 const char *ds_name;
1187
1188 ds_name = nvpair_name(pair);
1189 VERIFY0(dsl_dataset_hold(dp, ds_name, FTAG, &ds));
1190
1191 dpsa.dpsa_dsname = ds_name;
1192 dpsa.dpsa_source = ZPROP_SRC_LOCAL;
1193 dpsa.dpsa_props = fnvpair_value_nvlist(pair);
1194
1195 dsl_props_set_sync(&dpsa, tx);
1196 dsl_dataset_rele(ds, FTAG);
1197 }
1198 }
1199
1200 static int
1201 dsl_props_mds_set_check(void *arg, dmu_tx_t *tx)
1202 {
1203 dsl_props_set_arg_t *top_dpsa = arg;
1204 dsl_pool_t *dp = dmu_tx_pool(tx);
1205 nvlist_t *dss_props = top_dpsa->dpsa_props;
1206 nvpair_t *pair = NULL;
1207
1208 while ((pair = nvlist_next_nvpair(dss_props, pair)) != NULL) {
1209 dsl_props_set_arg_t dpsa;
1210 dsl_dataset_t *ds = NULL;
1211 const char *ds_name;
1212 int err;
1213
1214 ds_name = nvpair_name(pair);
1215 err = dsl_dataset_hold(dp, ds_name, FTAG, &ds);
1216 if (err != 0)
1217 return (err);
1218
1219 if (nvpair_type(pair) != DATA_TYPE_NVLIST) {
1220 dsl_dataset_rele(ds, FTAG);
1221 return (SET_ERROR(EINVAL));
1222 }
1223
1224 dpsa.dpsa_dsname = ds_name;
1225 dpsa.dpsa_source = ZPROP_SRC_LOCAL;
1226 dpsa.dpsa_props = fnvpair_value_nvlist(pair);
1227
1228 err = dsl_props_set_check(&dpsa, tx);
1229 dsl_dataset_rele(ds, FTAG);
1230 if (err != 0)
1231 return (err);
1232 }
1233
1234 return (0);
1235 }
1236
1237
1238 /*
1239 * The given 'dss_props' nvlist represents the following struct:
1240 * ds1 -> prop1:value
1241 * -> prop3:value
1242 * ds2 -> prop1:value
1243 * -> prop2:value
1244 *
1245 * All-or-nothing: if any prop can't be set, nothing will be modified.
1246 */
1247 int
1248 dsl_props_set_mds(const char *pool_name, nvlist_t *dss_props,
1249 size_t num_props)
1250 {
1251 dsl_props_set_arg_t dpsa;
1252
1253 dpsa.dpsa_dsname = pool_name;
1254 dpsa.dpsa_source = ZPROP_SRC_LOCAL;
1255 dpsa.dpsa_props = dss_props;
1256
1257 return (dsl_sync_task(pool_name, dsl_props_mds_set_check,
1258 dsl_props_mds_set_sync, &dpsa, 2 * num_props,
1259 ZFS_SPACE_CHECK_RESERVED));
1260 }
1261
1262 typedef enum dsl_prop_getflags {
1263 DSL_PROP_GET_INHERITING = 0x1, /* searching parent of target ds */
1264 DSL_PROP_GET_SNAPSHOT = 0x2, /* snapshot dataset */
1265 DSL_PROP_GET_LOCAL = 0x4, /* local properties */
1266 DSL_PROP_GET_RECEIVED = 0x8 /* received properties */
1267 } dsl_prop_getflags_t;
1268
1269 static int
1270 dsl_prop_get_all_impl(objset_t *mos, uint64_t propobj,
1271 const char *setpoint, dsl_prop_getflags_t flags, nvlist_t *nv)
1272 {
1273 zap_cursor_t zc;
1274 zap_attribute_t za;
1275 int err = 0;
1276
1277 for (zap_cursor_init(&zc, mos, propobj);
1278 (err = zap_cursor_retrieve(&zc, &za)) == 0;
1279 zap_cursor_advance(&zc)) {
1280 nvlist_t *propval;
1281 zfs_prop_t prop;
1282 char buf[ZAP_MAXNAMELEN];
1283 char *valstr;
1284 const char *suffix;
1285 const char *propname;
1286 const char *source;
1287
1288 suffix = strchr(za.za_name, '$');
1289
1290 if (suffix == NULL) {
1291 /*
1292 * Skip local properties if we only want received
1293 * properties.
1294 */
1295 if (flags & DSL_PROP_GET_RECEIVED)
1296 continue;
1297
1298 propname = za.za_name;
1299 source = setpoint;
1300 } else if (strcmp(suffix, ZPROP_INHERIT_SUFFIX) == 0) {
1301 /* Skip explicitly inherited entries. */
1302 continue;
1303 } else if (strcmp(suffix, ZPROP_RECVD_SUFFIX) == 0) {
1304 if (flags & DSL_PROP_GET_LOCAL)
1305 continue;
1306
1307 (void) strncpy(buf, za.za_name, (suffix - za.za_name));
1308 buf[suffix - za.za_name] = '\0';
1309 propname = buf;
1310
1311 if (!(flags & DSL_PROP_GET_RECEIVED)) {
1312 /* Skip if locally overridden. */
1313 err = zap_contains(mos, propobj, propname);
1314 if (err == 0)
1315 continue;
1316 if (err != ENOENT)
1317 break;
1318
1319 /* Skip if explicitly inherited. */
1320 valstr = kmem_asprintf("%s%s", propname,
1321 ZPROP_INHERIT_SUFFIX);
1322 err = zap_contains(mos, propobj, valstr);
1323 strfree(valstr);
1324 if (err == 0)
1325 continue;
1326 if (err != ENOENT)
1327 break;
1328 }
1329
1330 source = ((flags & DSL_PROP_GET_INHERITING) ?
1331 setpoint : ZPROP_SOURCE_VAL_RECVD);
1332 } else {
1333 /*
1334 * For backward compatibility, skip suffixes we don't
1335 * recognize.
1336 */
1337 continue;
1338 }
1339
1340 prop = zfs_name_to_prop(propname);
1341
1342 /* Skip non-inheritable properties. */
1343 if ((flags & DSL_PROP_GET_INHERITING) && prop != ZPROP_INVAL &&
1344 !zfs_prop_inheritable(prop))
1345 continue;
1346
1347 /* Skip properties not valid for this type. */
1348 if ((flags & DSL_PROP_GET_SNAPSHOT) && prop != ZPROP_INVAL &&
1349 !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT))
1350 continue;
1351
1352 /* Skip properties already defined. */
1353 if (nvlist_exists(nv, propname))
1354 continue;
1355
1356 VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1357 if (za.za_integer_length == 1) {
1358 /*
1359 * String property
1360 */
1361 char *tmp = kmem_alloc(za.za_num_integers,
1362 KM_SLEEP);
1363 err = zap_lookup(mos, propobj,
1364 za.za_name, 1, za.za_num_integers, tmp);
1365 if (err != 0) {
1366 kmem_free(tmp, za.za_num_integers);
1367 break;
1368 }
1369
1370 VERIFY(nvlist_add_string(propval, ZPROP_VALUE,
1371 tmp) == 0);
1372 kmem_free(tmp, za.za_num_integers);
1373 } else {
1374 /*
1375 * Integer property
1376 */
1377 ASSERT(za.za_integer_length == 8);
1378
1379 if (prop == ZFS_PROP_WBC_MODE) {
1380 wbc_mode_prop_val_t val;
1381
1382 ASSERT(za.za_num_integers ==
1383 WBC_MODE_PROP_VAL_SZ);
1384
1385 err = zap_lookup(mos, propobj,
1386 za.za_name, 8, za.za_num_integers, &val);
1387 if (err != 0)
1388 break;
1389
1390 if (val.root_ds_object != 0 &&
1391 val.txg_off == 0)
1392 za.za_first_integer = ZFS_WBC_MODE_ON;
1393 else
1394 za.za_first_integer = ZFS_WBC_MODE_OFF;
1395 }
1396
1397 (void) nvlist_add_uint64(propval, ZPROP_VALUE,
1398 za.za_first_integer);
1399 }
1400
1401 VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, source) == 0);
1402 VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
1403 nvlist_free(propval);
1404 }
1405 zap_cursor_fini(&zc);
1406 if (err == ENOENT)
1407 err = 0;
1408 return (err);
1409 }
1410
1411 /*
1412 * Iterate over all properties for this dataset and return them in an nvlist.
1413 */
1414 static int
1415 dsl_prop_get_all_ds(dsl_dataset_t *ds, nvlist_t **nvp,
1416 dsl_prop_getflags_t flags)
1417 {
1418 dsl_dir_t *dd = ds->ds_dir;
1419 dsl_pool_t *dp = dd->dd_pool;
1420 objset_t *mos = dp->dp_meta_objset;
1421 int err = 0;
1422 char setpoint[ZFS_MAX_DATASET_NAME_LEN];
1423
1424 VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1425
1426 if (ds->ds_is_snapshot)
1427 flags |= DSL_PROP_GET_SNAPSHOT;
1428
1429 ASSERT(dsl_pool_config_held(dp));
1430
1431 if (dsl_dataset_phys(ds)->ds_props_obj != 0) {
1432 ASSERT(flags & DSL_PROP_GET_SNAPSHOT);
1433 dsl_dataset_name(ds, setpoint);
1434 err = dsl_prop_get_all_impl(mos,
1435 dsl_dataset_phys(ds)->ds_props_obj, setpoint, flags, *nvp);
1436 if (err)
1437 goto out;
1438 }
1439
1440 for (; dd != NULL; dd = dd->dd_parent) {
1441 if (dd != ds->ds_dir || (flags & DSL_PROP_GET_SNAPSHOT)) {
1442 if (flags & (DSL_PROP_GET_LOCAL |
1443 DSL_PROP_GET_RECEIVED))
1444 break;
1445 flags |= DSL_PROP_GET_INHERITING;
1446 }
1447 dsl_dir_name(dd, setpoint);
1448 err = dsl_prop_get_all_impl(mos,
1449 dsl_dir_phys(dd)->dd_props_zapobj, setpoint, flags, *nvp);
1450 if (err)
1451 break;
1452 }
1453 out:
1454 return (err);
1455 }
1456
1457 boolean_t
1458 dsl_prop_get_hasrecvd(const char *dsname)
1459 {
1460 uint64_t dummy;
1461
1462 return (0 ==
1463 dsl_prop_get_integer(dsname, ZPROP_HAS_RECVD, &dummy, NULL));
1464 }
1465
1466 static int
1467 dsl_prop_set_hasrecvd_impl(const char *dsname, zprop_source_t source)
1468 {
1469 uint64_t version;
1470 spa_t *spa;
1471 int error = 0;
1472
1473 VERIFY0(spa_open(dsname, &spa, FTAG));
1474 version = spa_version(spa);
1475 spa_close(spa, FTAG);
1476
1477 if (version >= SPA_VERSION_RECVD_PROPS)
1478 error = dsl_prop_set_int(dsname, ZPROP_HAS_RECVD, source, 0);
1479 return (error);
1480 }
1481
1482 /*
1483 * Call after successfully receiving properties to ensure that only the first
1484 * receive on or after SPA_VERSION_RECVD_PROPS blows away local properties.
1485 */
1486 int
1487 dsl_prop_set_hasrecvd(const char *dsname)
1488 {
1489 int error = 0;
1490 if (!dsl_prop_get_hasrecvd(dsname))
1491 error = dsl_prop_set_hasrecvd_impl(dsname, ZPROP_SRC_LOCAL);
1492 return (error);
1493 }
1494
1495 void
1496 dsl_prop_unset_hasrecvd(const char *dsname)
1497 {
1498 VERIFY0(dsl_prop_set_hasrecvd_impl(dsname, ZPROP_SRC_NONE));
1499 }
1500
1501 int
1502 dsl_prop_get_all(objset_t *os, nvlist_t **nvp)
1503 {
1504 return (dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, 0));
1505 }
1506
1507 int
1508 dsl_prop_get_received(const char *dsname, nvlist_t **nvp)
1509 {
1510 objset_t *os;
1511 int error;
1512
1513 /*
1514 * Received properties are not distinguishable from local properties
1515 * until the dataset has received properties on or after
1516 * SPA_VERSION_RECVD_PROPS.
1517 */
1518 dsl_prop_getflags_t flags = (dsl_prop_get_hasrecvd(dsname) ?
1519 DSL_PROP_GET_RECEIVED : DSL_PROP_GET_LOCAL);
1520
1521 error = dmu_objset_hold(dsname, FTAG, &os);
1522 if (error != 0)
1523 return (error);
1524 error = dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, flags);
1525 dmu_objset_rele(os, FTAG);
1526 return (error);
1527 }
1528
1529 void
1530 dsl_prop_nvlist_add_uint64(nvlist_t *nv, zfs_prop_t prop, uint64_t value)
1531 {
1532 nvlist_t *propval;
1533 const char *propname = zfs_prop_to_name(prop);
1534 uint64_t default_value;
1535
1536 if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) {
1537 VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0);
1538 return;
1539 }
1540
1541 VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1542 VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0);
1543 /* Indicate the default source if we can. */
1544 if (dodefault(prop, 8, 1, &default_value) == 0 &&
1545 value == default_value) {
1546 VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, "") == 0);
1547 }
1548 VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
1549 nvlist_free(propval);
1550 }
1551
1552 void
1553 dsl_prop_nvlist_add_string(nvlist_t *nv, zfs_prop_t prop, const char *value)
1554 {
1555 nvlist_t *propval;
1556 const char *propname = zfs_prop_to_name(prop);
1557
1558 if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) {
1559 VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0);
1560 return;
1561 }
1562
1563 VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1564 VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0);
1565 VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
1566 nvlist_free(propval);
1567 }