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