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 zap_contains(mos, zapobj, ZPROP_HAS_RECVD) == 0) { 627 dummy = 0; 628 err = zap_update(mos, zapobj, inheritstr, 629 8, 1, &dummy, tx); 630 ASSERT(err == 0); 631 } 632 break; 633 case ZPROP_SRC_RECEIVED: 634 /* 635 * set propname$recvd -> value 636 */ 637 err = zap_update(mos, zapobj, recvdstr, 638 psa->psa_intsz, psa->psa_numints, psa->psa_value, tx); 639 ASSERT(err == 0); 640 break; 641 case (ZPROP_SRC_NONE | ZPROP_SRC_LOCAL | ZPROP_SRC_RECEIVED): 642 /* 643 * clear local and received settings 644 * - remove propname 645 * - remove propname$inherit 646 * - remove propname$recvd 647 */ 648 err = zap_remove(mos, zapobj, propname, tx); 649 ASSERT(err == 0 || err == ENOENT); 650 err = zap_remove(mos, zapobj, inheritstr, tx); 651 ASSERT(err == 0 || err == ENOENT); 652 /* FALLTHRU */ 653 case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED): 654 /* 655 * remove propname$recvd 656 */ 657 err = zap_remove(mos, zapobj, recvdstr, tx); 658 ASSERT(err == 0 || err == ENOENT); 659 break; 660 default: 661 cmn_err(CE_PANIC, "unexpected property source: %d", source); 662 } 663 664 strfree(inheritstr); 665 strfree(recvdstr); 666 667 if (isint) { 668 VERIFY(0 == dsl_prop_get_ds(ds, propname, 8, 1, &intval, NULL)); 669 670 if (ds->ds_phys != NULL && dsl_dataset_is_snapshot(ds)) { 671 dsl_prop_cb_record_t *cbr; 672 /* 673 * It's a snapshot; nothing can inherit this 674 * property, so just look for callbacks on this 675 * ds here. 676 */ 677 mutex_enter(&ds->ds_dir->dd_lock); 678 for (cbr = list_head(&ds->ds_dir->dd_prop_cbs); cbr; 679 cbr = list_next(&ds->ds_dir->dd_prop_cbs, cbr)) { 680 if (cbr->cbr_ds == ds && 681 strcmp(cbr->cbr_propname, propname) == 0) 682 cbr->cbr_func(cbr->cbr_arg, intval); 683 } 684 mutex_exit(&ds->ds_dir->dd_lock); 685 } else { 686 dsl_prop_changed_notify(ds->ds_dir->dd_pool, 687 ds->ds_dir->dd_object, propname, intval, TRUE); 688 } 689 690 (void) snprintf(valbuf, sizeof (valbuf), 691 "%lld", (longlong_t)intval); 692 valstr = valbuf; 693 } else { 694 if (source == ZPROP_SRC_LOCAL) { 695 valstr = (char *)psa->psa_value; 696 } else { 697 tbuf = kmem_alloc(ZAP_MAXVALUELEN, KM_SLEEP); 698 if (dsl_prop_get_ds(ds, propname, 1, 699 ZAP_MAXVALUELEN, tbuf, NULL) == 0) 700 valstr = tbuf; 701 } 702 } 703 704 spa_history_log_internal((source == ZPROP_SRC_NONE || 705 source == ZPROP_SRC_INHERITED) ? LOG_DS_INHERIT : 706 LOG_DS_PROPSET, ds->ds_dir->dd_pool->dp_spa, tx, 707 "%s=%s dataset = %llu", propname, 708 (valstr == NULL ? "" : valstr), ds->ds_object); 709 710 if (tbuf != NULL) 711 kmem_free(tbuf, ZAP_MAXVALUELEN); 712 } 713 714 void 715 dsl_props_set_sync(void *arg1, void *arg2, dmu_tx_t *tx) 716 { 717 dsl_dataset_t *ds = arg1; 718 dsl_props_arg_t *pa = arg2; 719 nvlist_t *props = pa->pa_props; 720 dsl_prop_setarg_t psa; 721 nvpair_t *elem = NULL; 722 723 psa.psa_source = pa->pa_source; 724 725 while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 726 nvpair_t *pair = elem; 727 728 psa.psa_name = nvpair_name(pair); 729 730 if (nvpair_type(pair) == DATA_TYPE_NVLIST) { 731 /* 732 * dsl_prop_get_all_impl() returns properties in this 733 * format. 734 */ 735 nvlist_t *attrs; 736 VERIFY(nvpair_value_nvlist(pair, &attrs) == 0); 737 VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 738 &pair) == 0); 739 } 740 741 if (nvpair_type(pair) == DATA_TYPE_STRING) { 742 VERIFY(nvpair_value_string(pair, 743 (char **)&psa.psa_value) == 0); 744 psa.psa_intsz = 1; 745 psa.psa_numints = strlen(psa.psa_value) + 1; 746 } else { 747 uint64_t intval; 748 VERIFY(nvpair_value_uint64(pair, &intval) == 0); 749 psa.psa_intsz = sizeof (intval); 750 psa.psa_numints = 1; 751 psa.psa_value = &intval; 752 } 753 dsl_prop_set_sync(ds, &psa, tx); 754 } 755 } 756 757 void 758 dsl_dir_prop_set_uint64_sync(dsl_dir_t *dd, const char *name, uint64_t val, 759 dmu_tx_t *tx) 760 { 761 objset_t *mos = dd->dd_pool->dp_meta_objset; 762 uint64_t zapobj = dd->dd_phys->dd_props_zapobj; 763 764 ASSERT(dmu_tx_is_syncing(tx)); 765 766 VERIFY(0 == zap_update(mos, zapobj, name, sizeof (val), 1, &val, tx)); 767 768 dsl_prop_changed_notify(dd->dd_pool, dd->dd_object, name, val, TRUE); 769 770 spa_history_log_internal(LOG_DS_PROPSET, dd->dd_pool->dp_spa, tx, 771 "%s=%llu dataset = %llu", name, (u_longlong_t)val, 772 dd->dd_phys->dd_head_dataset_obj); 773 } 774 775 int 776 dsl_prop_set(const char *dsname, const char *propname, zprop_source_t source, 777 int intsz, int numints, const void *buf) 778 { 779 dsl_dataset_t *ds; 780 uint64_t version; 781 int err; 782 dsl_prop_setarg_t psa; 783 784 /* 785 * We must do these checks before we get to the syncfunc, since 786 * it can't fail. 787 */ 788 if (strlen(propname) >= ZAP_MAXNAMELEN) 789 return (ENAMETOOLONG); 790 791 err = dsl_dataset_hold(dsname, FTAG, &ds); 792 if (err) 793 return (err); 794 795 version = spa_version(ds->ds_dir->dd_pool->dp_spa); 796 if (intsz * numints >= (version < SPA_VERSION_STMF_PROP ? 797 ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) { 798 dsl_dataset_rele(ds, FTAG); 799 return (E2BIG); 800 } 801 if (dsl_dataset_is_snapshot(ds) && 802 version < SPA_VERSION_SNAP_PROPS) { 803 dsl_dataset_rele(ds, FTAG); 804 return (ENOTSUP); 805 } 806 807 psa.psa_name = propname; 808 psa.psa_source = source; 809 psa.psa_intsz = intsz; 810 psa.psa_numints = numints; 811 psa.psa_value = buf; 812 psa.psa_effective_value = -1ULL; 813 814 err = dsl_sync_task_do(ds->ds_dir->dd_pool, 815 NULL, dsl_prop_set_sync, ds, &psa, 2); 816 817 dsl_dataset_rele(ds, FTAG); 818 return (err); 819 } 820 821 int 822 dsl_props_set(const char *dsname, zprop_source_t source, nvlist_t *props) 823 { 824 dsl_dataset_t *ds; 825 uint64_t version; 826 nvpair_t *elem = NULL; 827 dsl_props_arg_t pa; 828 int err; 829 830 if (err = dsl_dataset_hold(dsname, FTAG, &ds)) 831 return (err); 832 /* 833 * Do these checks before the syncfunc, since it can't fail. 834 */ 835 version = spa_version(ds->ds_dir->dd_pool->dp_spa); 836 while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 837 if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) { 838 dsl_dataset_rele(ds, FTAG); 839 return (ENAMETOOLONG); 840 } 841 if (nvpair_type(elem) == DATA_TYPE_STRING) { 842 char *valstr; 843 VERIFY(nvpair_value_string(elem, &valstr) == 0); 844 if (strlen(valstr) >= (version < 845 SPA_VERSION_STMF_PROP ? 846 ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) { 847 dsl_dataset_rele(ds, FTAG); 848 return (E2BIG); 849 } 850 } 851 } 852 853 if (dsl_dataset_is_snapshot(ds) && 854 version < SPA_VERSION_SNAP_PROPS) { 855 dsl_dataset_rele(ds, FTAG); 856 return (ENOTSUP); 857 } 858 859 pa.pa_props = props; 860 pa.pa_source = source; 861 862 err = dsl_sync_task_do(ds->ds_dir->dd_pool, 863 NULL, dsl_props_set_sync, ds, &pa, 2); 864 865 dsl_dataset_rele(ds, FTAG); 866 return (err); 867 } 868 869 typedef enum dsl_prop_getflags { 870 DSL_PROP_GET_INHERITING = 0x1, /* searching parent of target ds */ 871 DSL_PROP_GET_SNAPSHOT = 0x2, /* snapshot dataset */ 872 DSL_PROP_GET_LOCAL = 0x4, /* local properties */ 873 DSL_PROP_GET_RECEIVED = 0x8 /* received properties */ 874 } dsl_prop_getflags_t; 875 876 static int 877 dsl_prop_get_all_impl(objset_t *mos, uint64_t propobj, 878 const char *setpoint, dsl_prop_getflags_t flags, nvlist_t *nv) 879 { 880 zap_cursor_t zc; 881 zap_attribute_t za; 882 int err = 0; 883 884 for (zap_cursor_init(&zc, mos, propobj); 885 (err = zap_cursor_retrieve(&zc, &za)) == 0; 886 zap_cursor_advance(&zc)) { 887 nvlist_t *propval; 888 zfs_prop_t prop; 889 char buf[ZAP_MAXNAMELEN]; 890 char *valstr; 891 const char *suffix; 892 const char *propname; 893 const char *source; 894 895 suffix = strchr(za.za_name, '$'); 896 897 if (suffix == NULL) { 898 /* 899 * Skip local properties if we only want received 900 * properties. 901 */ 902 if (flags & DSL_PROP_GET_RECEIVED) 903 continue; 904 905 propname = za.za_name; 906 source = setpoint; 907 } else if (strcmp(suffix, ZPROP_INHERIT_SUFFIX) == 0) { 908 /* Skip explicitly inherited entries. */ 909 continue; 910 } else if (strcmp(suffix, ZPROP_RECVD_SUFFIX) == 0) { 911 if (flags & DSL_PROP_GET_LOCAL) 912 continue; 913 914 (void) strncpy(buf, za.za_name, (suffix - za.za_name)); 915 buf[suffix - za.za_name] = '\0'; 916 propname = buf; 917 918 if (!(flags & DSL_PROP_GET_RECEIVED)) { 919 /* Skip if locally overridden. */ 920 err = zap_contains(mos, propobj, propname); 921 if (err == 0) 922 continue; 923 if (err != ENOENT) 924 break; 925 926 /* Skip if explicitly inherited. */ 927 valstr = kmem_asprintf("%s%s", propname, 928 ZPROP_INHERIT_SUFFIX); 929 err = zap_contains(mos, propobj, valstr); 930 strfree(valstr); 931 if (err == 0) 932 continue; 933 if (err != ENOENT) 934 break; 935 } 936 937 source = ((flags & DSL_PROP_GET_INHERITING) ? 938 setpoint : ZPROP_SOURCE_VAL_RECVD); 939 } else { 940 /* 941 * For backward compatibility, skip suffixes we don't 942 * recognize. 943 */ 944 continue; 945 } 946 947 prop = zfs_name_to_prop(propname); 948 949 /* Skip non-inheritable properties. */ 950 if ((flags & DSL_PROP_GET_INHERITING) && prop != ZPROP_INVAL && 951 !zfs_prop_inheritable(prop)) 952 continue; 953 954 /* Skip properties not valid for this type. */ 955 if ((flags & DSL_PROP_GET_SNAPSHOT) && prop != ZPROP_INVAL && 956 !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT)) 957 continue; 958 959 /* Skip properties already defined. */ 960 if (nvlist_exists(nv, propname)) 961 continue; 962 963 VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 964 if (za.za_integer_length == 1) { 965 /* 966 * String property 967 */ 968 char *tmp = kmem_alloc(za.za_num_integers, 969 KM_SLEEP); 970 err = zap_lookup(mos, propobj, 971 za.za_name, 1, za.za_num_integers, tmp); 972 if (err != 0) { 973 kmem_free(tmp, za.za_num_integers); 974 break; 975 } 976 VERIFY(nvlist_add_string(propval, ZPROP_VALUE, 977 tmp) == 0); 978 kmem_free(tmp, za.za_num_integers); 979 } else { 980 /* 981 * Integer property 982 */ 983 ASSERT(za.za_integer_length == 8); 984 (void) nvlist_add_uint64(propval, ZPROP_VALUE, 985 za.za_first_integer); 986 } 987 988 VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, source) == 0); 989 VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0); 990 nvlist_free(propval); 991 } 992 zap_cursor_fini(&zc); 993 if (err == ENOENT) 994 err = 0; 995 return (err); 996 } 997 998 /* 999 * Iterate over all properties for this dataset and return them in an nvlist. 1000 */ 1001 static int 1002 dsl_prop_get_all_ds(dsl_dataset_t *ds, nvlist_t **nvp, 1003 dsl_prop_getflags_t flags) 1004 { 1005 dsl_dir_t *dd = ds->ds_dir; 1006 dsl_pool_t *dp = dd->dd_pool; 1007 objset_t *mos = dp->dp_meta_objset; 1008 int err = 0; 1009 char setpoint[MAXNAMELEN]; 1010 1011 VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1012 1013 if (dsl_dataset_is_snapshot(ds)) 1014 flags |= DSL_PROP_GET_SNAPSHOT; 1015 1016 rw_enter(&dp->dp_config_rwlock, RW_READER); 1017 1018 if (ds->ds_phys->ds_props_obj != 0) { 1019 ASSERT(flags & DSL_PROP_GET_SNAPSHOT); 1020 dsl_dataset_name(ds, setpoint); 1021 err = dsl_prop_get_all_impl(mos, ds->ds_phys->ds_props_obj, 1022 setpoint, flags, *nvp); 1023 if (err) 1024 goto out; 1025 } 1026 1027 for (; dd != NULL; dd = dd->dd_parent) { 1028 if (dd != ds->ds_dir || (flags & DSL_PROP_GET_SNAPSHOT)) { 1029 if (flags & (DSL_PROP_GET_LOCAL | 1030 DSL_PROP_GET_RECEIVED)) 1031 break; 1032 flags |= DSL_PROP_GET_INHERITING; 1033 } 1034 dsl_dir_name(dd, setpoint); 1035 err = dsl_prop_get_all_impl(mos, dd->dd_phys->dd_props_zapobj, 1036 setpoint, flags, *nvp); 1037 if (err) 1038 break; 1039 } 1040 out: 1041 rw_exit(&dp->dp_config_rwlock); 1042 return (err); 1043 } 1044 1045 boolean_t 1046 dsl_prop_get_hasrecvd(objset_t *os) 1047 { 1048 dsl_dataset_t *ds = os->os_dsl_dataset; 1049 int rc; 1050 uint64_t dummy; 1051 1052 rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); 1053 rc = dsl_prop_get_ds(ds, ZPROP_HAS_RECVD, 8, 1, &dummy, NULL); 1054 rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 1055 ASSERT(rc != 0 || spa_version(os->os_spa) >= SPA_VERSION_RECVD_PROPS); 1056 return (rc == 0); 1057 } 1058 1059 static void 1060 dsl_prop_set_hasrecvd_impl(objset_t *os, zprop_source_t source) 1061 { 1062 dsl_dataset_t *ds = os->os_dsl_dataset; 1063 uint64_t dummy = 0; 1064 dsl_prop_setarg_t psa; 1065 1066 if (spa_version(os->os_spa) < SPA_VERSION_RECVD_PROPS) 1067 return; 1068 1069 dsl_prop_setarg_init_uint64(&psa, ZPROP_HAS_RECVD, source, &dummy); 1070 1071 (void) dsl_sync_task_do(ds->ds_dir->dd_pool, NULL, 1072 dsl_prop_set_sync, ds, &psa, 2); 1073 } 1074 1075 /* 1076 * Call after successfully receiving properties to ensure that only the first 1077 * receive on or after SPA_VERSION_RECVD_PROPS blows away local properties. 1078 */ 1079 void 1080 dsl_prop_set_hasrecvd(objset_t *os) 1081 { 1082 if (dsl_prop_get_hasrecvd(os)) { 1083 ASSERT(spa_version(os->os_spa) >= SPA_VERSION_RECVD_PROPS); 1084 return; 1085 } 1086 dsl_prop_set_hasrecvd_impl(os, ZPROP_SRC_LOCAL); 1087 } 1088 1089 void 1090 dsl_prop_unset_hasrecvd(objset_t *os) 1091 { 1092 dsl_prop_set_hasrecvd_impl(os, ZPROP_SRC_NONE); 1093 } 1094 1095 int 1096 dsl_prop_get_all(objset_t *os, nvlist_t **nvp) 1097 { 1098 return (dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, 0)); 1099 } 1100 1101 int 1102 dsl_prop_get_received(objset_t *os, nvlist_t **nvp) 1103 { 1104 /* 1105 * Received properties are not distinguishable from local properties 1106 * until the dataset has received properties on or after 1107 * SPA_VERSION_RECVD_PROPS. 1108 */ 1109 dsl_prop_getflags_t flags = (dsl_prop_get_hasrecvd(os) ? 1110 DSL_PROP_GET_RECEIVED : DSL_PROP_GET_LOCAL); 1111 return (dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, flags)); 1112 } 1113 1114 void 1115 dsl_prop_nvlist_add_uint64(nvlist_t *nv, zfs_prop_t prop, uint64_t value) 1116 { 1117 nvlist_t *propval; 1118 const char *propname = zfs_prop_to_name(prop); 1119 uint64_t default_value; 1120 1121 if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) { 1122 VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0); 1123 return; 1124 } 1125 1126 VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1127 VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0); 1128 /* Indicate the default source if we can. */ 1129 if (dodefault(propname, 8, 1, &default_value) == 0 && 1130 value == default_value) { 1131 VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, "") == 0); 1132 } 1133 VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0); 1134 nvlist_free(propval); 1135 } 1136 1137 void 1138 dsl_prop_nvlist_add_string(nvlist_t *nv, zfs_prop_t prop, const char *value) 1139 { 1140 nvlist_t *propval; 1141 const char *propname = zfs_prop_to_name(prop); 1142 1143 if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) { 1144 VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0); 1145 return; 1146 } 1147 1148 VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1149 VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0); 1150 VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0); 1151 nvlist_free(propval); 1152 } 1153