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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/dmu.h> 29 #include <sys/dmu_objset.h> 30 #include <sys/dmu_tx.h> 31 #include <sys/dsl_dataset.h> 32 #include <sys/dsl_dir.h> 33 #include <sys/dsl_prop.h> 34 #include <sys/dsl_synctask.h> 35 #include <sys/spa.h> 36 #include <sys/zio_checksum.h> /* for the default checksum value */ 37 #include <sys/zap.h> 38 #include <sys/fs/zfs.h> 39 40 #include "zfs_prop.h" 41 42 static int 43 dodefault(const char *propname, int intsz, int numint, 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 numint); 61 } else { 62 if (intsz != 8 || numint < 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 numint, void *buf, char *setpoint) 74 { 75 int err = ENOENT; 76 objset_t *mos = dd->dd_pool->dp_meta_objset; 77 zfs_prop_t prop; 78 79 ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock)); 80 81 if (setpoint) 82 setpoint[0] = '\0'; 83 84 prop = zfs_name_to_prop(propname); 85 86 /* 87 * Note: dd may be NULL, therefore we shouldn't dereference it 88 * ouside this loop. 89 */ 90 for (; dd != NULL; dd = dd->dd_parent) { 91 ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock)); 92 err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj, 93 propname, intsz, numint, buf); 94 if (err != ENOENT) { 95 if (setpoint) 96 dsl_dir_name(dd, setpoint); 97 break; 98 } 99 100 /* 101 * Break out of this loop for non-inheritable properties. 102 */ 103 if (prop != ZPROP_INVAL && !zfs_prop_inheritable(prop)) 104 break; 105 } 106 if (err == ENOENT) 107 err = dodefault(propname, intsz, numint, buf); 108 109 return (err); 110 } 111 112 int 113 dsl_prop_get_ds(dsl_dataset_t *ds, const char *propname, 114 int intsz, int numint, void *buf, char *setpoint) 115 { 116 ASSERT(RW_LOCK_HELD(&ds->ds_dir->dd_pool->dp_config_rwlock)); 117 118 if (ds->ds_phys->ds_props_obj) { 119 int err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset, 120 ds->ds_phys->ds_props_obj, propname, intsz, numint, buf); 121 if (err != ENOENT) { 122 if (setpoint) 123 dsl_dataset_name(ds, setpoint); 124 return (err); 125 } 126 } 127 128 return (dsl_prop_get_dd(ds->ds_dir, propname, 129 intsz, numint, buf, setpoint)); 130 } 131 132 /* 133 * Register interest in the named property. We'll call the callback 134 * once to notify it of the current property value, and again each time 135 * the property changes, until this callback is unregistered. 136 * 137 * Return 0 on success, errno if the prop is not an integer value. 138 */ 139 int 140 dsl_prop_register(dsl_dataset_t *ds, const char *propname, 141 dsl_prop_changed_cb_t *callback, void *cbarg) 142 { 143 dsl_dir_t *dd = ds->ds_dir; 144 dsl_pool_t *dp = dd->dd_pool; 145 uint64_t value; 146 dsl_prop_cb_record_t *cbr; 147 int err; 148 int need_rwlock; 149 150 need_rwlock = !RW_WRITE_HELD(&dp->dp_config_rwlock); 151 if (need_rwlock) 152 rw_enter(&dp->dp_config_rwlock, RW_READER); 153 154 err = dsl_prop_get_ds(ds, propname, 8, 1, &value, NULL); 155 if (err != 0) { 156 if (need_rwlock) 157 rw_exit(&dp->dp_config_rwlock); 158 return (err); 159 } 160 161 cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP); 162 cbr->cbr_ds = ds; 163 cbr->cbr_propname = kmem_alloc(strlen(propname)+1, KM_SLEEP); 164 (void) strcpy((char *)cbr->cbr_propname, propname); 165 cbr->cbr_func = callback; 166 cbr->cbr_arg = cbarg; 167 mutex_enter(&dd->dd_lock); 168 list_insert_head(&dd->dd_prop_cbs, cbr); 169 mutex_exit(&dd->dd_lock); 170 171 cbr->cbr_func(cbr->cbr_arg, value); 172 173 VERIFY(0 == dsl_dir_open_obj(dp, dd->dd_object, 174 NULL, cbr, &dd)); 175 if (need_rwlock) 176 rw_exit(&dp->dp_config_rwlock); 177 /* Leave dir open until this callback is unregistered */ 178 return (0); 179 } 180 181 int 182 dsl_prop_get(const char *dsname, const char *propname, 183 int intsz, int numints, void *buf, char *setpoint) 184 { 185 dsl_dataset_t *ds; 186 int err; 187 188 err = dsl_dataset_hold(dsname, FTAG, &ds); 189 if (err) 190 return (err); 191 192 rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); 193 err = dsl_prop_get_ds(ds, propname, intsz, numints, buf, setpoint); 194 rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 195 196 dsl_dataset_rele(ds, FTAG); 197 return (err); 198 } 199 200 /* 201 * Get the current property value. It may have changed by the time this 202 * function returns, so it is NOT safe to follow up with 203 * dsl_prop_register() and assume that the value has not changed in 204 * between. 205 * 206 * Return 0 on success, ENOENT if ddname is invalid. 207 */ 208 int 209 dsl_prop_get_integer(const char *ddname, const char *propname, 210 uint64_t *valuep, char *setpoint) 211 { 212 return (dsl_prop_get(ddname, propname, 8, 1, valuep, setpoint)); 213 } 214 215 /* 216 * Unregister this callback. Return 0 on success, ENOENT if ddname is 217 * invalid, ENOMSG if no matching callback registered. 218 */ 219 int 220 dsl_prop_unregister(dsl_dataset_t *ds, const char *propname, 221 dsl_prop_changed_cb_t *callback, void *cbarg) 222 { 223 dsl_dir_t *dd = ds->ds_dir; 224 dsl_prop_cb_record_t *cbr; 225 226 mutex_enter(&dd->dd_lock); 227 for (cbr = list_head(&dd->dd_prop_cbs); 228 cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { 229 if (cbr->cbr_ds == ds && 230 cbr->cbr_func == callback && 231 cbr->cbr_arg == cbarg && 232 strcmp(cbr->cbr_propname, propname) == 0) 233 break; 234 } 235 236 if (cbr == NULL) { 237 mutex_exit(&dd->dd_lock); 238 return (ENOMSG); 239 } 240 241 list_remove(&dd->dd_prop_cbs, cbr); 242 mutex_exit(&dd->dd_lock); 243 kmem_free((void*)cbr->cbr_propname, strlen(cbr->cbr_propname)+1); 244 kmem_free(cbr, sizeof (dsl_prop_cb_record_t)); 245 246 /* Clean up from dsl_prop_register */ 247 dsl_dir_close(dd, cbr); 248 return (0); 249 } 250 251 /* 252 * Return the number of callbacks that are registered for this dataset. 253 */ 254 int 255 dsl_prop_numcb(dsl_dataset_t *ds) 256 { 257 dsl_dir_t *dd = ds->ds_dir; 258 dsl_prop_cb_record_t *cbr; 259 int num = 0; 260 261 mutex_enter(&dd->dd_lock); 262 for (cbr = list_head(&dd->dd_prop_cbs); 263 cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { 264 if (cbr->cbr_ds == ds) 265 num++; 266 } 267 mutex_exit(&dd->dd_lock); 268 269 return (num); 270 } 271 272 static void 273 dsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj, 274 const char *propname, uint64_t value, int first) 275 { 276 dsl_dir_t *dd; 277 dsl_prop_cb_record_t *cbr; 278 objset_t *mos = dp->dp_meta_objset; 279 zap_cursor_t zc; 280 zap_attribute_t *za; 281 int err; 282 uint64_t dummyval; 283 284 ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 285 err = dsl_dir_open_obj(dp, ddobj, NULL, FTAG, &dd); 286 if (err) 287 return; 288 289 if (!first) { 290 /* 291 * If the prop is set here, then this change is not 292 * being inherited here or below; stop the recursion. 293 */ 294 err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj, propname, 295 8, 1, &dummyval); 296 if (err == 0) { 297 dsl_dir_close(dd, FTAG); 298 return; 299 } 300 ASSERT3U(err, ==, ENOENT); 301 } 302 303 mutex_enter(&dd->dd_lock); 304 for (cbr = list_head(&dd->dd_prop_cbs); cbr; 305 cbr = list_next(&dd->dd_prop_cbs, cbr)) { 306 uint64_t propobj = cbr->cbr_ds->ds_phys->ds_props_obj; 307 308 if (strcmp(cbr->cbr_propname, propname) != 0) 309 continue; 310 311 /* 312 * If the property is set on this ds, then it is not 313 * inherited here; don't call the callback. 314 */ 315 if (propobj && 0 == zap_lookup(mos, propobj, propname, 316 8, 1, &dummyval)) 317 continue; 318 319 cbr->cbr_func(cbr->cbr_arg, value); 320 } 321 mutex_exit(&dd->dd_lock); 322 323 za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP); 324 for (zap_cursor_init(&zc, mos, 325 dd->dd_phys->dd_child_dir_zapobj); 326 zap_cursor_retrieve(&zc, za) == 0; 327 zap_cursor_advance(&zc)) { 328 dsl_prop_changed_notify(dp, za->za_first_integer, 329 propname, value, FALSE); 330 } 331 kmem_free(za, sizeof (zap_attribute_t)); 332 zap_cursor_fini(&zc); 333 dsl_dir_close(dd, FTAG); 334 } 335 336 struct prop_set_arg { 337 const char *name; 338 int intsz; 339 int numints; 340 const void *buf; 341 }; 342 343 344 static void 345 dsl_prop_set_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 346 { 347 dsl_dataset_t *ds = arg1; 348 struct prop_set_arg *psa = arg2; 349 objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 350 uint64_t zapobj, intval; 351 int isint; 352 char valbuf[32]; 353 char *valstr; 354 355 isint = (dodefault(psa->name, 8, 1, &intval) == 0); 356 357 if (dsl_dataset_is_snapshot(ds)) { 358 ASSERT(spa_version(ds->ds_dir->dd_pool->dp_spa) >= 359 SPA_VERSION_SNAP_PROPS); 360 if (ds->ds_phys->ds_props_obj == 0) { 361 dmu_buf_will_dirty(ds->ds_dbuf, tx); 362 ds->ds_phys->ds_props_obj = 363 zap_create(mos, 364 DMU_OT_DSL_PROPS, DMU_OT_NONE, 0, tx); 365 } 366 zapobj = ds->ds_phys->ds_props_obj; 367 } else { 368 zapobj = ds->ds_dir->dd_phys->dd_props_zapobj; 369 } 370 371 if (psa->numints == 0) { 372 int err = zap_remove(mos, zapobj, psa->name, tx); 373 ASSERT(err == 0 || err == ENOENT); 374 if (isint) { 375 VERIFY(0 == dsl_prop_get_ds(ds, 376 psa->name, 8, 1, &intval, NULL)); 377 } 378 } else { 379 VERIFY(0 == zap_update(mos, zapobj, psa->name, 380 psa->intsz, psa->numints, psa->buf, tx)); 381 if (isint) 382 intval = *(uint64_t *)psa->buf; 383 } 384 385 if (isint) { 386 if (dsl_dataset_is_snapshot(ds)) { 387 dsl_prop_cb_record_t *cbr; 388 /* 389 * It's a snapshot; nothing can inherit this 390 * property, so just look for callbacks on this 391 * ds here. 392 */ 393 mutex_enter(&ds->ds_dir->dd_lock); 394 for (cbr = list_head(&ds->ds_dir->dd_prop_cbs); cbr; 395 cbr = list_next(&ds->ds_dir->dd_prop_cbs, cbr)) { 396 if (cbr->cbr_ds == ds && 397 strcmp(cbr->cbr_propname, psa->name) == 0) 398 cbr->cbr_func(cbr->cbr_arg, intval); 399 } 400 mutex_exit(&ds->ds_dir->dd_lock); 401 } else { 402 dsl_prop_changed_notify(ds->ds_dir->dd_pool, 403 ds->ds_dir->dd_object, psa->name, intval, TRUE); 404 } 405 } 406 if (isint) { 407 (void) snprintf(valbuf, sizeof (valbuf), 408 "%lld", (longlong_t)intval); 409 valstr = valbuf; 410 } else { 411 valstr = (char *)psa->buf; 412 } 413 spa_history_internal_log((psa->numints == 0) ? LOG_DS_INHERIT : 414 LOG_DS_PROPSET, ds->ds_dir->dd_pool->dp_spa, tx, cr, 415 "%s=%s dataset = %llu", psa->name, valstr, ds->ds_object); 416 } 417 418 void 419 dsl_prop_set_uint64_sync(dsl_dir_t *dd, const char *name, uint64_t val, 420 cred_t *cr, dmu_tx_t *tx) 421 { 422 objset_t *mos = dd->dd_pool->dp_meta_objset; 423 uint64_t zapobj = dd->dd_phys->dd_props_zapobj; 424 425 ASSERT(dmu_tx_is_syncing(tx)); 426 427 VERIFY(0 == zap_update(mos, zapobj, name, sizeof (val), 1, &val, tx)); 428 429 dsl_prop_changed_notify(dd->dd_pool, dd->dd_object, name, val, TRUE); 430 431 spa_history_internal_log(LOG_DS_PROPSET, dd->dd_pool->dp_spa, tx, cr, 432 "%s=%llu dataset = %llu", name, (u_longlong_t)val, 433 dd->dd_phys->dd_head_dataset_obj); 434 } 435 436 int 437 dsl_prop_set(const char *dsname, const char *propname, 438 int intsz, int numints, const void *buf) 439 { 440 dsl_dataset_t *ds; 441 int err; 442 struct prop_set_arg psa; 443 444 /* 445 * We must do these checks before we get to the syncfunc, since 446 * it can't fail. 447 */ 448 if (strlen(propname) >= ZAP_MAXNAMELEN) 449 return (ENAMETOOLONG); 450 if (intsz * numints >= ZAP_MAXVALUELEN) 451 return (E2BIG); 452 453 err = dsl_dataset_hold(dsname, FTAG, &ds); 454 if (err) 455 return (err); 456 457 if (dsl_dataset_is_snapshot(ds) && 458 spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_SNAP_PROPS) { 459 dsl_dataset_rele(ds, FTAG); 460 return (ENOTSUP); 461 } 462 463 psa.name = propname; 464 psa.intsz = intsz; 465 psa.numints = numints; 466 psa.buf = buf; 467 err = dsl_sync_task_do(ds->ds_dir->dd_pool, 468 NULL, dsl_prop_set_sync, ds, &psa, 2); 469 470 dsl_dataset_rele(ds, FTAG); 471 return (err); 472 } 473 474 /* 475 * Iterate over all properties for this dataset and return them in an nvlist. 476 */ 477 int 478 dsl_prop_get_all(objset_t *os, nvlist_t **nvp, boolean_t local) 479 { 480 dsl_dataset_t *ds = os->os->os_dsl_dataset; 481 dsl_dir_t *dd = ds->ds_dir; 482 boolean_t snapshot = dsl_dataset_is_snapshot(ds); 483 int err = 0; 484 dsl_pool_t *dp = dd->dd_pool; 485 objset_t *mos = dp->dp_meta_objset; 486 uint64_t propobj = ds->ds_phys->ds_props_obj; 487 488 VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); 489 490 if (local && snapshot && !propobj) 491 return (0); 492 493 rw_enter(&dp->dp_config_rwlock, RW_READER); 494 while (dd != NULL) { 495 char setpoint[MAXNAMELEN]; 496 zap_cursor_t zc; 497 zap_attribute_t za; 498 dsl_dir_t *dd_next; 499 500 if (propobj) { 501 dsl_dataset_name(ds, setpoint); 502 dd_next = dd; 503 } else { 504 dsl_dir_name(dd, setpoint); 505 propobj = dd->dd_phys->dd_props_zapobj; 506 dd_next = dd->dd_parent; 507 } 508 509 for (zap_cursor_init(&zc, mos, propobj); 510 (err = zap_cursor_retrieve(&zc, &za)) == 0; 511 zap_cursor_advance(&zc)) { 512 nvlist_t *propval; 513 zfs_prop_t prop = zfs_name_to_prop(za.za_name); 514 515 /* Skip non-inheritable properties. */ 516 if (prop != ZPROP_INVAL && 517 !zfs_prop_inheritable(prop) && 518 (dd != ds->ds_dir || (snapshot && dd != dd_next))) 519 continue; 520 521 /* Skip properties not valid for this type. */ 522 if (snapshot && prop != ZPROP_INVAL && 523 !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT)) 524 continue; 525 526 /* Skip properties already defined */ 527 if (nvlist_lookup_nvlist(*nvp, za.za_name, 528 &propval) == 0) 529 continue; 530 531 VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, 532 KM_SLEEP) == 0); 533 if (za.za_integer_length == 1) { 534 /* 535 * String property 536 */ 537 char *tmp = kmem_alloc(za.za_num_integers, 538 KM_SLEEP); 539 err = zap_lookup(mos, propobj, 540 za.za_name, 1, za.za_num_integers, tmp); 541 if (err != 0) { 542 kmem_free(tmp, za.za_num_integers); 543 break; 544 } 545 VERIFY(nvlist_add_string(propval, ZPROP_VALUE, 546 tmp) == 0); 547 kmem_free(tmp, za.za_num_integers); 548 } else { 549 /* 550 * Integer property 551 */ 552 ASSERT(za.za_integer_length == 8); 553 (void) nvlist_add_uint64(propval, ZPROP_VALUE, 554 za.za_first_integer); 555 } 556 557 VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, 558 setpoint) == 0); 559 VERIFY(nvlist_add_nvlist(*nvp, za.za_name, 560 propval) == 0); 561 nvlist_free(propval); 562 } 563 zap_cursor_fini(&zc); 564 565 if (err != ENOENT) 566 break; 567 err = 0; 568 /* 569 * If we are just after the props that have been set 570 * locally, then we are done after the first iteration. 571 */ 572 if (local) 573 break; 574 dd = dd_next; 575 propobj = 0; 576 } 577 rw_exit(&dp->dp_config_rwlock); 578 579 return (err); 580 } 581 582 void 583 dsl_prop_nvlist_add_uint64(nvlist_t *nv, zfs_prop_t prop, uint64_t value) 584 { 585 nvlist_t *propval; 586 587 VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 588 VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0); 589 VERIFY(nvlist_add_nvlist(nv, zfs_prop_to_name(prop), propval) == 0); 590 nvlist_free(propval); 591 } 592 593 void 594 dsl_prop_nvlist_add_string(nvlist_t *nv, zfs_prop_t prop, const char *value) 595 { 596 nvlist_t *propval; 597 598 VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 599 VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0); 600 VERIFY(nvlist_add_nvlist(nv, zfs_prop_to_name(prop), propval) == 0); 601 nvlist_free(propval); 602 } 603