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