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