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