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