FreeBSD ZFS
The Zettabyte File System
|
00001 /* 00002 * CDDL HEADER START 00003 * 00004 * The contents of this file are subject to the terms of the 00005 * Common Development and Distribution License (the "License"). 00006 * You may not use this file except in compliance with the License. 00007 * 00008 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 00009 * or http://www.opensolaris.org/os/licensing. 00010 * See the License for the specific language governing permissions 00011 * and limitations under the License. 00012 * 00013 * When distributing Covered Code, include this CDDL HEADER in each 00014 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 00015 * If applicable, add the following below this CDDL HEADER, with the 00016 * fields enclosed by brackets "[]" replaced with your own identifying 00017 * information: Portions Copyright [yyyy] [name of copyright owner] 00018 * 00019 * CDDL HEADER END 00020 */ 00021 /* 00022 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 00023 */ 00024 00025 #include <sys/zfs_context.h> 00026 #include <sys/dmu.h> 00027 #include <sys/dmu_objset.h> 00028 #include <sys/dmu_tx.h> 00029 #include <sys/dsl_dataset.h> 00030 #include <sys/dsl_dir.h> 00031 #include <sys/dsl_prop.h> 00032 #include <sys/dsl_synctask.h> 00033 #include <sys/spa.h> 00034 #include <sys/zap.h> 00035 #include <sys/fs/zfs.h> 00036 00037 #include "zfs_prop.h" 00038 00039 #define ZPROP_INHERIT_SUFFIX "$inherit" 00040 #define ZPROP_RECVD_SUFFIX "$recvd" 00041 00042 static int 00043 dodefault(const char *propname, int intsz, int numints, void *buf) 00044 { 00045 zfs_prop_t prop; 00046 00047 /* 00048 * The setonce properties are read-only, BUT they still 00049 * have a default value that can be used as the initial 00050 * value. 00051 */ 00052 if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL || 00053 (zfs_prop_readonly(prop) && !zfs_prop_setonce(prop))) 00054 return (ENOENT); 00055 00056 if (zfs_prop_get_type(prop) == PROP_TYPE_STRING) { 00057 if (intsz != 1) 00058 return (EOVERFLOW); 00059 (void) strncpy(buf, zfs_prop_default_string(prop), 00060 numints); 00061 } else { 00062 if (intsz != 8 || numints < 1) 00063 return (EOVERFLOW); 00064 00065 *(uint64_t *)buf = zfs_prop_default_numeric(prop); 00066 } 00067 00068 return (0); 00069 } 00070 00071 int 00072 dsl_prop_get_dd(dsl_dir_t *dd, const char *propname, 00073 int intsz, int numints, void *buf, char *setpoint, boolean_t snapshot) 00074 { 00075 int err = ENOENT; 00076 dsl_dir_t *target = dd; 00077 objset_t *mos = dd->dd_pool->dp_meta_objset; 00078 zfs_prop_t prop; 00079 boolean_t inheritable; 00080 boolean_t inheriting = B_FALSE; 00081 char *inheritstr; 00082 char *recvdstr; 00083 00084 ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock)); 00085 00086 if (setpoint) 00087 setpoint[0] = '\0'; 00088 00089 prop = zfs_name_to_prop(propname); 00090 inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop)); 00091 inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX); 00092 recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX); 00093 00094 /* 00095 * Note: dd may become NULL, therefore we shouldn't dereference it 00096 * after this loop. 00097 */ 00098 for (; dd != NULL; dd = dd->dd_parent) { 00099 ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock)); 00100 00101 if (dd != target || snapshot) { 00102 if (!inheritable) 00103 break; 00104 inheriting = B_TRUE; 00105 } 00106 00107 /* Check for a local value. */ 00108 err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj, propname, 00109 intsz, numints, buf); 00110 if (err != ENOENT) { 00111 if (setpoint != NULL && err == 0) 00112 dsl_dir_name(dd, setpoint); 00113 break; 00114 } 00115 00116 /* 00117 * Skip the check for a received value if there is an explicit 00118 * inheritance entry. 00119 */ 00120 err = zap_contains(mos, dd->dd_phys->dd_props_zapobj, 00121 inheritstr); 00122 if (err != 0 && err != ENOENT) 00123 break; 00124 00125 if (err == ENOENT) { 00126 /* Check for a received value. */ 00127 err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj, 00128 recvdstr, intsz, numints, buf); 00129 if (err != ENOENT) { 00130 if (setpoint != NULL && err == 0) { 00131 if (inheriting) { 00132 dsl_dir_name(dd, setpoint); 00133 } else { 00134 (void) strcpy(setpoint, 00135 ZPROP_SOURCE_VAL_RECVD); 00136 } 00137 } 00138 break; 00139 } 00140 } 00141 00142 /* 00143 * If we found an explicit inheritance entry, err is zero even 00144 * though we haven't yet found the value, so reinitializing err 00145 * at the end of the loop (instead of at the beginning) ensures 00146 * that err has a valid post-loop value. 00147 */ 00148 err = ENOENT; 00149 } 00150 00151 if (err == ENOENT) 00152 err = dodefault(propname, intsz, numints, buf); 00153 00154 strfree(inheritstr); 00155 strfree(recvdstr); 00156 00157 return (err); 00158 } 00159 00160 int 00161 dsl_prop_get_ds(dsl_dataset_t *ds, const char *propname, 00162 int intsz, int numints, void *buf, char *setpoint) 00163 { 00164 zfs_prop_t prop = zfs_name_to_prop(propname); 00165 boolean_t inheritable; 00166 boolean_t snapshot; 00167 uint64_t zapobj; 00168 00169 ASSERT(RW_LOCK_HELD(&ds->ds_dir->dd_pool->dp_config_rwlock)); 00170 inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop)); 00171 snapshot = (ds->ds_phys != NULL && dsl_dataset_is_snapshot(ds)); 00172 zapobj = (ds->ds_phys == NULL ? 0 : ds->ds_phys->ds_props_obj); 00173 00174 if (zapobj != 0) { 00175 objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 00176 int err; 00177 00178 ASSERT(snapshot); 00179 00180 /* Check for a local value. */ 00181 err = zap_lookup(mos, zapobj, propname, intsz, numints, buf); 00182 if (err != ENOENT) { 00183 if (setpoint != NULL && err == 0) 00184 dsl_dataset_name(ds, setpoint); 00185 return (err); 00186 } 00187 00188 /* 00189 * Skip the check for a received value if there is an explicit 00190 * inheritance entry. 00191 */ 00192 if (inheritable) { 00193 char *inheritstr = kmem_asprintf("%s%s", propname, 00194 ZPROP_INHERIT_SUFFIX); 00195 err = zap_contains(mos, zapobj, inheritstr); 00196 strfree(inheritstr); 00197 if (err != 0 && err != ENOENT) 00198 return (err); 00199 } 00200 00201 if (err == ENOENT) { 00202 /* Check for a received value. */ 00203 char *recvdstr = kmem_asprintf("%s%s", propname, 00204 ZPROP_RECVD_SUFFIX); 00205 err = zap_lookup(mos, zapobj, recvdstr, 00206 intsz, numints, buf); 00207 strfree(recvdstr); 00208 if (err != ENOENT) { 00209 if (setpoint != NULL && err == 0) 00210 (void) strcpy(setpoint, 00211 ZPROP_SOURCE_VAL_RECVD); 00212 return (err); 00213 } 00214 } 00215 } 00216 00217 return (dsl_prop_get_dd(ds->ds_dir, propname, 00218 intsz, numints, buf, setpoint, snapshot)); 00219 } 00220 00228 int 00229 dsl_prop_register(dsl_dataset_t *ds, const char *propname, 00230 dsl_prop_changed_cb_t *callback, void *cbarg) 00231 { 00232 dsl_dir_t *dd = ds->ds_dir; 00233 dsl_pool_t *dp = dd->dd_pool; 00234 uint64_t value; 00235 dsl_prop_cb_record_t *cbr; 00236 int err; 00237 int need_rwlock; 00238 00239 need_rwlock = !RW_WRITE_HELD(&dp->dp_config_rwlock); 00240 if (need_rwlock) 00241 rw_enter(&dp->dp_config_rwlock, RW_READER); 00242 00243 err = dsl_prop_get_ds(ds, propname, 8, 1, &value, NULL); 00244 if (err != 0) { 00245 if (need_rwlock) 00246 rw_exit(&dp->dp_config_rwlock); 00247 return (err); 00248 } 00249 00250 cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP); 00251 cbr->cbr_ds = ds; 00252 cbr->cbr_propname = kmem_alloc(strlen(propname)+1, KM_SLEEP); 00253 (void) strcpy((char *)cbr->cbr_propname, propname); 00254 cbr->cbr_func = callback; 00255 cbr->cbr_arg = cbarg; 00256 mutex_enter(&dd->dd_lock); 00257 list_insert_head(&dd->dd_prop_cbs, cbr); 00258 mutex_exit(&dd->dd_lock); 00259 00260 cbr->cbr_func(cbr->cbr_arg, value); 00261 00262 if (need_rwlock) 00263 rw_exit(&dp->dp_config_rwlock); 00264 return (0); 00265 } 00266 00267 int 00268 dsl_prop_get(const char *dsname, const char *propname, 00269 int intsz, int numints, void *buf, char *setpoint) 00270 { 00271 dsl_dataset_t *ds; 00272 int err; 00273 00274 err = dsl_dataset_hold(dsname, FTAG, &ds); 00275 if (err) 00276 return (err); 00277 00278 rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); 00279 err = dsl_prop_get_ds(ds, propname, intsz, numints, buf, setpoint); 00280 rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 00281 00282 dsl_dataset_rele(ds, FTAG); 00283 return (err); 00284 } 00285 00294 int 00295 dsl_prop_get_integer(const char *ddname, const char *propname, 00296 uint64_t *valuep, char *setpoint) 00297 { 00298 return (dsl_prop_get(ddname, propname, 8, 1, valuep, setpoint)); 00299 } 00300 00301 void 00302 dsl_prop_setarg_init_uint64(dsl_prop_setarg_t *psa, const char *propname, 00303 zprop_source_t source, uint64_t *value) 00304 { 00305 psa->psa_name = propname; 00306 psa->psa_source = source; 00307 psa->psa_intsz = 8; 00308 psa->psa_numints = 1; 00309 psa->psa_value = value; 00310 00311 psa->psa_effective_value = -1ULL; 00312 } 00313 00324 int 00325 dsl_prop_predict_sync(dsl_dir_t *dd, dsl_prop_setarg_t *psa) 00326 { 00327 const char *propname = psa->psa_name; 00328 zfs_prop_t prop = zfs_name_to_prop(propname); 00329 zprop_source_t source = psa->psa_source; 00330 objset_t *mos; 00331 uint64_t zapobj; 00332 uint64_t version; 00333 char *recvdstr; 00334 int err = 0; 00335 00336 switch (prop) { 00337 case ZFS_PROP_QUOTA: 00338 case ZFS_PROP_RESERVATION: 00339 case ZFS_PROP_REFQUOTA: 00340 case ZFS_PROP_REFRESERVATION: 00341 break; 00342 default: 00343 return (-1); 00344 } 00345 00346 mos = dd->dd_pool->dp_meta_objset; 00347 zapobj = dd->dd_phys->dd_props_zapobj; 00348 recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX); 00349 00350 version = spa_version(dd->dd_pool->dp_spa); 00351 if (version < SPA_VERSION_RECVD_PROPS) { 00352 if (source & ZPROP_SRC_NONE) 00353 source = ZPROP_SRC_NONE; 00354 else if (source & ZPROP_SRC_RECEIVED) 00355 source = ZPROP_SRC_LOCAL; 00356 } 00357 00358 switch (source) { 00359 case ZPROP_SRC_NONE: 00360 /* Revert to the received value, if any. */ 00361 err = zap_lookup(mos, zapobj, recvdstr, 8, 1, 00362 &psa->psa_effective_value); 00363 if (err == ENOENT) 00364 psa->psa_effective_value = 0; 00365 break; 00366 case ZPROP_SRC_LOCAL: 00367 psa->psa_effective_value = *(uint64_t *)psa->psa_value; 00368 break; 00369 case ZPROP_SRC_RECEIVED: 00370 /* 00371 * If there's no local setting, then the new received value will 00372 * be the effective value. 00373 */ 00374 err = zap_lookup(mos, zapobj, propname, 8, 1, 00375 &psa->psa_effective_value); 00376 if (err == ENOENT) 00377 psa->psa_effective_value = *(uint64_t *)psa->psa_value; 00378 break; 00379 case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED): 00380 /* 00381 * We're clearing the received value, so the local setting (if 00382 * it exists) remains the effective value. 00383 */ 00384 err = zap_lookup(mos, zapobj, propname, 8, 1, 00385 &psa->psa_effective_value); 00386 if (err == ENOENT) 00387 psa->psa_effective_value = 0; 00388 break; 00389 default: 00390 cmn_err(CE_PANIC, "unexpected property source: %d", source); 00391 } 00392 00393 strfree(recvdstr); 00394 00395 if (err == ENOENT) 00396 return (0); 00397 00398 return (err); 00399 } 00400 00401 #ifdef ZFS_DEBUG 00402 void 00403 dsl_prop_check_prediction(dsl_dir_t *dd, dsl_prop_setarg_t *psa) 00404 { 00405 zfs_prop_t prop = zfs_name_to_prop(psa->psa_name); 00406 uint64_t intval; 00407 char setpoint[MAXNAMELEN]; 00408 uint64_t version = spa_version(dd->dd_pool->dp_spa); 00409 int err; 00410 00411 if (version < SPA_VERSION_RECVD_PROPS) { 00412 switch (prop) { 00413 case ZFS_PROP_QUOTA: 00414 case ZFS_PROP_RESERVATION: 00415 return; 00416 } 00417 } 00418 00419 err = dsl_prop_get_dd(dd, psa->psa_name, 8, 1, &intval, 00420 setpoint, B_FALSE); 00421 if (err == 0 && intval != psa->psa_effective_value) { 00422 cmn_err(CE_PANIC, "%s property, source: %x, " 00423 "predicted effective value: %llu, " 00424 "actual effective value: %llu (setpoint: %s)", 00425 psa->psa_name, psa->psa_source, 00426 (unsigned long long)psa->psa_effective_value, 00427 (unsigned long long)intval, setpoint); 00428 } 00429 } 00430 #endif 00431 00438 int 00439 dsl_prop_unregister(dsl_dataset_t *ds, const char *propname, 00440 dsl_prop_changed_cb_t *callback, void *cbarg) 00441 { 00442 dsl_dir_t *dd = ds->ds_dir; 00443 dsl_prop_cb_record_t *cbr; 00444 00445 mutex_enter(&dd->dd_lock); 00446 for (cbr = list_head(&dd->dd_prop_cbs); 00447 cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { 00448 if (cbr->cbr_ds == ds && 00449 cbr->cbr_func == callback && 00450 cbr->cbr_arg == cbarg && 00451 strcmp(cbr->cbr_propname, propname) == 0) 00452 break; 00453 } 00454 00455 if (cbr == NULL) { 00456 mutex_exit(&dd->dd_lock); 00457 return (ENOMSG); 00458 } 00459 00460 list_remove(&dd->dd_prop_cbs, cbr); 00461 mutex_exit(&dd->dd_lock); 00462 kmem_free((void*)cbr->cbr_propname, strlen(cbr->cbr_propname)+1); 00463 kmem_free(cbr, sizeof (dsl_prop_cb_record_t)); 00464 00465 return (0); 00466 } 00467 00471 int 00472 dsl_prop_numcb(dsl_dataset_t *ds) 00473 { 00474 dsl_dir_t *dd = ds->ds_dir; 00475 dsl_prop_cb_record_t *cbr; 00476 int num = 0; 00477 00478 mutex_enter(&dd->dd_lock); 00479 for (cbr = list_head(&dd->dd_prop_cbs); 00480 cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { 00481 if (cbr->cbr_ds == ds) 00482 num++; 00483 } 00484 mutex_exit(&dd->dd_lock); 00485 00486 return (num); 00487 } 00488 00489 static void 00490 dsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj, 00491 const char *propname, uint64_t value, int first) 00492 { 00493 dsl_dir_t *dd; 00494 dsl_prop_cb_record_t *cbr; 00495 objset_t *mos = dp->dp_meta_objset; 00496 zap_cursor_t zc; 00497 zap_attribute_t *za; 00498 int err; 00499 00500 ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 00501 err = dsl_dir_open_obj(dp, ddobj, NULL, FTAG, &dd); 00502 if (err) 00503 return; 00504 00505 if (!first) { 00506 /* 00507 * If the prop is set here, then this change is not 00508 * being inherited here or below; stop the recursion. 00509 */ 00510 err = zap_contains(mos, dd->dd_phys->dd_props_zapobj, propname); 00511 if (err == 0) { 00512 dsl_dir_close(dd, FTAG); 00513 return; 00514 } 00515 ASSERT3U(err, ==, ENOENT); 00516 } 00517 00518 mutex_enter(&dd->dd_lock); 00519 for (cbr = list_head(&dd->dd_prop_cbs); cbr; 00520 cbr = list_next(&dd->dd_prop_cbs, cbr)) { 00521 uint64_t propobj = cbr->cbr_ds->ds_phys->ds_props_obj; 00522 00523 if (strcmp(cbr->cbr_propname, propname) != 0) 00524 continue; 00525 00526 /* 00527 * If the property is set on this ds, then it is not 00528 * inherited here; don't call the callback. 00529 */ 00530 if (propobj && 0 == zap_contains(mos, propobj, propname)) 00531 continue; 00532 00533 cbr->cbr_func(cbr->cbr_arg, value); 00534 } 00535 mutex_exit(&dd->dd_lock); 00536 00537 za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP); 00538 for (zap_cursor_init(&zc, mos, 00539 dd->dd_phys->dd_child_dir_zapobj); 00540 zap_cursor_retrieve(&zc, za) == 0; 00541 zap_cursor_advance(&zc)) { 00542 dsl_prop_changed_notify(dp, za->za_first_integer, 00543 propname, value, FALSE); 00544 } 00545 kmem_free(za, sizeof (zap_attribute_t)); 00546 zap_cursor_fini(&zc); 00547 dsl_dir_close(dd, FTAG); 00548 } 00549 00550 void 00551 dsl_prop_set_sync(void *arg1, void *arg2, dmu_tx_t *tx) 00552 { 00553 dsl_dataset_t *ds = arg1; 00554 dsl_prop_setarg_t *psa = arg2; 00555 objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 00556 uint64_t zapobj, intval, dummy; 00557 int isint; 00558 char valbuf[32]; 00559 char *valstr = NULL; 00560 char *inheritstr; 00561 char *recvdstr; 00562 char *tbuf = NULL; 00563 int err; 00564 uint64_t version = spa_version(ds->ds_dir->dd_pool->dp_spa); 00565 const char *propname = psa->psa_name; 00566 zprop_source_t source = psa->psa_source; 00567 00568 isint = (dodefault(propname, 8, 1, &intval) == 0); 00569 00570 if (ds->ds_phys != NULL && dsl_dataset_is_snapshot(ds)) { 00571 ASSERT(version >= SPA_VERSION_SNAP_PROPS); 00572 if (ds->ds_phys->ds_props_obj == 0) { 00573 dmu_buf_will_dirty(ds->ds_dbuf, tx); 00574 ds->ds_phys->ds_props_obj = 00575 zap_create(mos, 00576 DMU_OT_DSL_PROPS, DMU_OT_NONE, 0, tx); 00577 } 00578 zapobj = ds->ds_phys->ds_props_obj; 00579 } else { 00580 zapobj = ds->ds_dir->dd_phys->dd_props_zapobj; 00581 } 00582 00583 if (version < SPA_VERSION_RECVD_PROPS) { 00584 zfs_prop_t prop = zfs_name_to_prop(propname); 00585 if (prop == ZFS_PROP_QUOTA || prop == ZFS_PROP_RESERVATION) 00586 return; 00587 00588 if (source & ZPROP_SRC_NONE) 00589 source = ZPROP_SRC_NONE; 00590 else if (source & ZPROP_SRC_RECEIVED) 00591 source = ZPROP_SRC_LOCAL; 00592 } 00593 00594 inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX); 00595 recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX); 00596 00597 switch (source) { 00598 case ZPROP_SRC_NONE: 00599 /* 00600 * revert to received value, if any (inherit -S) 00601 * - remove propname 00602 * - remove propname$inherit 00603 */ 00604 err = zap_remove(mos, zapobj, propname, tx); 00605 ASSERT(err == 0 || err == ENOENT); 00606 err = zap_remove(mos, zapobj, inheritstr, tx); 00607 ASSERT(err == 0 || err == ENOENT); 00608 break; 00609 case ZPROP_SRC_LOCAL: 00610 /* 00611 * remove propname$inherit 00612 * set propname -> value 00613 */ 00614 err = zap_remove(mos, zapobj, inheritstr, tx); 00615 ASSERT(err == 0 || err == ENOENT); 00616 VERIFY(0 == zap_update(mos, zapobj, propname, 00617 psa->psa_intsz, psa->psa_numints, psa->psa_value, tx)); 00618 break; 00619 case ZPROP_SRC_INHERITED: 00620 /* 00621 * explicitly inherit 00622 * - remove propname 00623 * - set propname$inherit 00624 */ 00625 err = zap_remove(mos, zapobj, propname, tx); 00626 ASSERT(err == 0 || err == ENOENT); 00627 if (version >= SPA_VERSION_RECVD_PROPS && 00628 dsl_prop_get_ds(ds, ZPROP_HAS_RECVD, 8, 1, &dummy, 00629 NULL) == 0) { 00630 dummy = 0; 00631 err = zap_update(mos, zapobj, inheritstr, 00632 8, 1, &dummy, tx); 00633 ASSERT(err == 0); 00634 } 00635 break; 00636 case ZPROP_SRC_RECEIVED: 00637 /* 00638 * set propname$recvd -> value 00639 */ 00640 err = zap_update(mos, zapobj, recvdstr, 00641 psa->psa_intsz, psa->psa_numints, psa->psa_value, tx); 00642 ASSERT(err == 0); 00643 break; 00644 case (ZPROP_SRC_NONE | ZPROP_SRC_LOCAL | ZPROP_SRC_RECEIVED): 00645 /* 00646 * clear local and received settings 00647 * - remove propname 00648 * - remove propname$inherit 00649 * - remove propname$recvd 00650 */ 00651 err = zap_remove(mos, zapobj, propname, tx); 00652 ASSERT(err == 0 || err == ENOENT); 00653 err = zap_remove(mos, zapobj, inheritstr, tx); 00654 ASSERT(err == 0 || err == ENOENT); 00655 /* FALLTHRU */ 00656 case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED): 00657 /* 00658 * remove propname$recvd 00659 */ 00660 err = zap_remove(mos, zapobj, recvdstr, tx); 00661 ASSERT(err == 0 || err == ENOENT); 00662 break; 00663 default: 00664 cmn_err(CE_PANIC, "unexpected property source: %d", source); 00665 } 00666 00667 strfree(inheritstr); 00668 strfree(recvdstr); 00669 00670 if (isint) { 00671 VERIFY(0 == dsl_prop_get_ds(ds, propname, 8, 1, &intval, NULL)); 00672 00673 if (ds->ds_phys != NULL && dsl_dataset_is_snapshot(ds)) { 00674 dsl_prop_cb_record_t *cbr; 00675 /* 00676 * It's a snapshot; nothing can inherit this 00677 * property, so just look for callbacks on this 00678 * ds here. 00679 */ 00680 mutex_enter(&ds->ds_dir->dd_lock); 00681 for (cbr = list_head(&ds->ds_dir->dd_prop_cbs); cbr; 00682 cbr = list_next(&ds->ds_dir->dd_prop_cbs, cbr)) { 00683 if (cbr->cbr_ds == ds && 00684 strcmp(cbr->cbr_propname, propname) == 0) 00685 cbr->cbr_func(cbr->cbr_arg, intval); 00686 } 00687 mutex_exit(&ds->ds_dir->dd_lock); 00688 } else { 00689 dsl_prop_changed_notify(ds->ds_dir->dd_pool, 00690 ds->ds_dir->dd_object, propname, intval, TRUE); 00691 } 00692 00693 (void) snprintf(valbuf, sizeof (valbuf), 00694 "%lld", (longlong_t)intval); 00695 valstr = valbuf; 00696 } else { 00697 if (source == ZPROP_SRC_LOCAL) { 00698 valstr = (char *)psa->psa_value; 00699 } else { 00700 tbuf = kmem_alloc(ZAP_MAXVALUELEN, KM_SLEEP); 00701 if (dsl_prop_get_ds(ds, propname, 1, 00702 ZAP_MAXVALUELEN, tbuf, NULL) == 0) 00703 valstr = tbuf; 00704 } 00705 } 00706 00707 spa_history_log_internal((source == ZPROP_SRC_NONE || 00708 source == ZPROP_SRC_INHERITED) ? LOG_DS_INHERIT : 00709 LOG_DS_PROPSET, ds->ds_dir->dd_pool->dp_spa, tx, 00710 "%s=%s dataset = %llu", propname, 00711 (valstr == NULL ? "" : valstr), ds->ds_object); 00712 00713 if (tbuf != NULL) 00714 kmem_free(tbuf, ZAP_MAXVALUELEN); 00715 } 00716 00717 void 00718 dsl_props_set_sync(void *arg1, void *arg2, dmu_tx_t *tx) 00719 { 00720 dsl_dataset_t *ds = arg1; 00721 dsl_props_arg_t *pa = arg2; 00722 nvlist_t *props = pa->pa_props; 00723 dsl_prop_setarg_t psa; 00724 nvpair_t *elem = NULL; 00725 00726 psa.psa_source = pa->pa_source; 00727 00728 while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 00729 nvpair_t *pair = elem; 00730 00731 psa.psa_name = nvpair_name(pair); 00732 00733 if (nvpair_type(pair) == DATA_TYPE_NVLIST) { 00734 /* 00735 * dsl_prop_get_all_impl() returns properties in this 00736 * format. 00737 */ 00738 nvlist_t *attrs; 00739 VERIFY(nvpair_value_nvlist(pair, &attrs) == 0); 00740 VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 00741 &pair) == 0); 00742 } 00743 00744 if (nvpair_type(pair) == DATA_TYPE_STRING) { 00745 VERIFY(nvpair_value_string(pair, 00746 (char **)&psa.psa_value) == 0); 00747 psa.psa_intsz = 1; 00748 psa.psa_numints = strlen(psa.psa_value) + 1; 00749 } else { 00750 uint64_t intval; 00751 VERIFY(nvpair_value_uint64(pair, &intval) == 0); 00752 psa.psa_intsz = sizeof (intval); 00753 psa.psa_numints = 1; 00754 psa.psa_value = &intval; 00755 } 00756 dsl_prop_set_sync(ds, &psa, tx); 00757 } 00758 } 00759 00760 void 00761 dsl_dir_prop_set_uint64_sync(dsl_dir_t *dd, const char *name, uint64_t val, 00762 dmu_tx_t *tx) 00763 { 00764 objset_t *mos = dd->dd_pool->dp_meta_objset; 00765 uint64_t zapobj = dd->dd_phys->dd_props_zapobj; 00766 00767 ASSERT(dmu_tx_is_syncing(tx)); 00768 00769 VERIFY(0 == zap_update(mos, zapobj, name, sizeof (val), 1, &val, tx)); 00770 00771 dsl_prop_changed_notify(dd->dd_pool, dd->dd_object, name, val, TRUE); 00772 00773 spa_history_log_internal(LOG_DS_PROPSET, dd->dd_pool->dp_spa, tx, 00774 "%s=%llu dataset = %llu", name, (u_longlong_t)val, 00775 dd->dd_phys->dd_head_dataset_obj); 00776 } 00777 00778 int 00779 dsl_prop_set(const char *dsname, const char *propname, zprop_source_t source, 00780 int intsz, int numints, const void *buf) 00781 { 00782 dsl_dataset_t *ds; 00783 uint64_t version; 00784 int err; 00785 dsl_prop_setarg_t psa; 00786 00787 /* 00788 * We must do these checks before we get to the syncfunc, since 00789 * it can't fail. 00790 */ 00791 if (strlen(propname) >= ZAP_MAXNAMELEN) 00792 return (ENAMETOOLONG); 00793 00794 err = dsl_dataset_hold(dsname, FTAG, &ds); 00795 if (err) 00796 return (err); 00797 00798 version = spa_version(ds->ds_dir->dd_pool->dp_spa); 00799 if (intsz * numints >= (version < SPA_VERSION_STMF_PROP ? 00800 ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) { 00801 dsl_dataset_rele(ds, FTAG); 00802 return (E2BIG); 00803 } 00804 if (dsl_dataset_is_snapshot(ds) && 00805 version < SPA_VERSION_SNAP_PROPS) { 00806 dsl_dataset_rele(ds, FTAG); 00807 return (ENOTSUP); 00808 } 00809 00810 psa.psa_name = propname; 00811 psa.psa_source = source; 00812 psa.psa_intsz = intsz; 00813 psa.psa_numints = numints; 00814 psa.psa_value = buf; 00815 psa.psa_effective_value = -1ULL; 00816 00817 err = dsl_sync_task_do(ds->ds_dir->dd_pool, 00818 NULL, dsl_prop_set_sync, ds, &psa, 2); 00819 00820 dsl_dataset_rele(ds, FTAG); 00821 return (err); 00822 } 00823 00824 int 00825 dsl_props_set(const char *dsname, zprop_source_t source, nvlist_t *props) 00826 { 00827 dsl_dataset_t *ds; 00828 uint64_t version; 00829 nvpair_t *elem = NULL; 00830 dsl_props_arg_t pa; 00831 int err; 00832 00833 if (err = dsl_dataset_hold(dsname, FTAG, &ds)) 00834 return (err); 00835 /* 00836 * Do these checks before the syncfunc, since it can't fail. 00837 */ 00838 version = spa_version(ds->ds_dir->dd_pool->dp_spa); 00839 while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 00840 if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) { 00841 dsl_dataset_rele(ds, FTAG); 00842 return (ENAMETOOLONG); 00843 } 00844 if (nvpair_type(elem) == DATA_TYPE_STRING) { 00845 char *valstr; 00846 VERIFY(nvpair_value_string(elem, &valstr) == 0); 00847 if (strlen(valstr) >= (version < 00848 SPA_VERSION_STMF_PROP ? 00849 ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) { 00850 dsl_dataset_rele(ds, FTAG); 00851 return (E2BIG); 00852 } 00853 } 00854 } 00855 00856 if (dsl_dataset_is_snapshot(ds) && 00857 version < SPA_VERSION_SNAP_PROPS) { 00858 dsl_dataset_rele(ds, FTAG); 00859 return (ENOTSUP); 00860 } 00861 00862 pa.pa_props = props; 00863 pa.pa_source = source; 00864 00865 err = dsl_sync_task_do(ds->ds_dir->dd_pool, 00866 NULL, dsl_props_set_sync, ds, &pa, 2); 00867 00868 dsl_dataset_rele(ds, FTAG); 00869 return (err); 00870 } 00871 00872 typedef enum dsl_prop_getflags { 00873 DSL_PROP_GET_INHERITING = 0x1, /* searching parent of target ds */ 00874 DSL_PROP_GET_SNAPSHOT = 0x2, /* snapshot dataset */ 00875 DSL_PROP_GET_LOCAL = 0x4, /* local properties */ 00876 DSL_PROP_GET_RECEIVED = 0x8 /* received properties */ 00877 } dsl_prop_getflags_t; 00878 00879 static int 00880 dsl_prop_get_all_impl(objset_t *mos, uint64_t propobj, 00881 const char *setpoint, dsl_prop_getflags_t flags, nvlist_t *nv) 00882 { 00883 zap_cursor_t zc; 00884 zap_attribute_t za; 00885 int err = 0; 00886 00887 for (zap_cursor_init(&zc, mos, propobj); 00888 (err = zap_cursor_retrieve(&zc, &za)) == 0; 00889 zap_cursor_advance(&zc)) { 00890 nvlist_t *propval; 00891 zfs_prop_t prop; 00892 char buf[ZAP_MAXNAMELEN]; 00893 char *valstr; 00894 const char *suffix; 00895 const char *propname; 00896 const char *source; 00897 00898 suffix = strchr(za.za_name, '$'); 00899 00900 if (suffix == NULL) { 00901 /* 00902 * Skip local properties if we only want received 00903 * properties. 00904 */ 00905 if (flags & DSL_PROP_GET_RECEIVED) 00906 continue; 00907 00908 propname = za.za_name; 00909 source = setpoint; 00910 } else if (strcmp(suffix, ZPROP_INHERIT_SUFFIX) == 0) { 00911 /* Skip explicitly inherited entries. */ 00912 continue; 00913 } else if (strcmp(suffix, ZPROP_RECVD_SUFFIX) == 0) { 00914 if (flags & DSL_PROP_GET_LOCAL) 00915 continue; 00916 00917 (void) strncpy(buf, za.za_name, (suffix - za.za_name)); 00918 buf[suffix - za.za_name] = '\0'; 00919 propname = buf; 00920 00921 if (!(flags & DSL_PROP_GET_RECEIVED)) { 00922 /* Skip if locally overridden. */ 00923 err = zap_contains(mos, propobj, propname); 00924 if (err == 0) 00925 continue; 00926 if (err != ENOENT) 00927 break; 00928 00929 /* Skip if explicitly inherited. */ 00930 valstr = kmem_asprintf("%s%s", propname, 00931 ZPROP_INHERIT_SUFFIX); 00932 err = zap_contains(mos, propobj, valstr); 00933 strfree(valstr); 00934 if (err == 0) 00935 continue; 00936 if (err != ENOENT) 00937 break; 00938 } 00939 00940 source = ((flags & DSL_PROP_GET_INHERITING) ? 00941 setpoint : ZPROP_SOURCE_VAL_RECVD); 00942 } else { 00943 /* 00944 * For backward compatibility, skip suffixes we don't 00945 * recognize. 00946 */ 00947 continue; 00948 } 00949 00950 prop = zfs_name_to_prop(propname); 00951 00952 /* Skip non-inheritable properties. */ 00953 if ((flags & DSL_PROP_GET_INHERITING) && prop != ZPROP_INVAL && 00954 !zfs_prop_inheritable(prop)) 00955 continue; 00956 00957 /* Skip properties not valid for this type. */ 00958 if ((flags & DSL_PROP_GET_SNAPSHOT) && prop != ZPROP_INVAL && 00959 !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT)) 00960 continue; 00961 00962 /* Skip properties already defined. */ 00963 if (nvlist_exists(nv, propname)) 00964 continue; 00965 00966 VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 00967 if (za.za_integer_length == 1) { 00968 /* 00969 * String property 00970 */ 00971 char *tmp = kmem_alloc(za.za_num_integers, 00972 KM_SLEEP); 00973 err = zap_lookup(mos, propobj, 00974 za.za_name, 1, za.za_num_integers, tmp); 00975 if (err != 0) { 00976 kmem_free(tmp, za.za_num_integers); 00977 break; 00978 } 00979 VERIFY(nvlist_add_string(propval, ZPROP_VALUE, 00980 tmp) == 0); 00981 kmem_free(tmp, za.za_num_integers); 00982 } else { 00983 /* 00984 * Integer property 00985 */ 00986 ASSERT(za.za_integer_length == 8); 00987 (void) nvlist_add_uint64(propval, ZPROP_VALUE, 00988 za.za_first_integer); 00989 } 00990 00991 VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, source) == 0); 00992 VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0); 00993 nvlist_free(propval); 00994 } 00995 zap_cursor_fini(&zc); 00996 if (err == ENOENT) 00997 err = 0; 00998 return (err); 00999 } 01000 01004 static int 01005 dsl_prop_get_all_ds(dsl_dataset_t *ds, nvlist_t **nvp, 01006 dsl_prop_getflags_t flags) 01007 { 01008 dsl_dir_t *dd = ds->ds_dir; 01009 dsl_pool_t *dp = dd->dd_pool; 01010 objset_t *mos = dp->dp_meta_objset; 01011 int err = 0; 01012 char setpoint[MAXNAMELEN]; 01013 01014 VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); 01015 01016 if (dsl_dataset_is_snapshot(ds)) 01017 flags |= DSL_PROP_GET_SNAPSHOT; 01018 01019 rw_enter(&dp->dp_config_rwlock, RW_READER); 01020 01021 if (ds->ds_phys->ds_props_obj != 0) { 01022 ASSERT(flags & DSL_PROP_GET_SNAPSHOT); 01023 dsl_dataset_name(ds, setpoint); 01024 err = dsl_prop_get_all_impl(mos, ds->ds_phys->ds_props_obj, 01025 setpoint, flags, *nvp); 01026 if (err) 01027 goto out; 01028 } 01029 01030 for (; dd != NULL; dd = dd->dd_parent) { 01031 if (dd != ds->ds_dir || (flags & DSL_PROP_GET_SNAPSHOT)) { 01032 if (flags & (DSL_PROP_GET_LOCAL | 01033 DSL_PROP_GET_RECEIVED)) 01034 break; 01035 flags |= DSL_PROP_GET_INHERITING; 01036 } 01037 dsl_dir_name(dd, setpoint); 01038 err = dsl_prop_get_all_impl(mos, dd->dd_phys->dd_props_zapobj, 01039 setpoint, flags, *nvp); 01040 if (err) 01041 break; 01042 } 01043 out: 01044 rw_exit(&dp->dp_config_rwlock); 01045 return (err); 01046 } 01047 01048 boolean_t 01049 dsl_prop_get_hasrecvd(objset_t *os) 01050 { 01051 dsl_dataset_t *ds = os->os_dsl_dataset; 01052 int rc; 01053 uint64_t dummy; 01054 01055 rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); 01056 rc = dsl_prop_get_ds(ds, ZPROP_HAS_RECVD, 8, 1, &dummy, NULL); 01057 rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 01058 ASSERT(rc != 0 || spa_version(os->os_spa) >= SPA_VERSION_RECVD_PROPS); 01059 return (rc == 0); 01060 } 01061 01062 static void 01063 dsl_prop_set_hasrecvd_impl(objset_t *os, zprop_source_t source) 01064 { 01065 dsl_dataset_t *ds = os->os_dsl_dataset; 01066 uint64_t dummy = 0; 01067 dsl_prop_setarg_t psa; 01068 01069 if (spa_version(os->os_spa) < SPA_VERSION_RECVD_PROPS) 01070 return; 01071 01072 dsl_prop_setarg_init_uint64(&psa, ZPROP_HAS_RECVD, source, &dummy); 01073 01074 (void) dsl_sync_task_do(ds->ds_dir->dd_pool, NULL, 01075 dsl_prop_set_sync, ds, &psa, 2); 01076 } 01077 01082 void 01083 dsl_prop_set_hasrecvd(objset_t *os) 01084 { 01085 if (dsl_prop_get_hasrecvd(os)) { 01086 ASSERT(spa_version(os->os_spa) >= SPA_VERSION_RECVD_PROPS); 01087 return; 01088 } 01089 dsl_prop_set_hasrecvd_impl(os, ZPROP_SRC_LOCAL); 01090 } 01091 01092 void 01093 dsl_prop_unset_hasrecvd(objset_t *os) 01094 { 01095 dsl_prop_set_hasrecvd_impl(os, ZPROP_SRC_NONE); 01096 } 01097 01098 int 01099 dsl_prop_get_all(objset_t *os, nvlist_t **nvp) 01100 { 01101 return (dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, 0)); 01102 } 01103 01104 int 01105 dsl_prop_get_received(objset_t *os, nvlist_t **nvp) 01106 { 01107 /* 01108 * Received properties are not distinguishable from local properties 01109 * until the dataset has received properties on or after 01110 * SPA_VERSION_RECVD_PROPS. 01111 */ 01112 dsl_prop_getflags_t flags = (dsl_prop_get_hasrecvd(os) ? 01113 DSL_PROP_GET_RECEIVED : DSL_PROP_GET_LOCAL); 01114 return (dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, flags)); 01115 } 01116 01117 void 01118 dsl_prop_nvlist_add_uint64(nvlist_t *nv, zfs_prop_t prop, uint64_t value) 01119 { 01120 nvlist_t *propval; 01121 const char *propname = zfs_prop_to_name(prop); 01122 uint64_t default_value; 01123 01124 if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) { 01125 VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0); 01126 return; 01127 } 01128 01129 VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 01130 VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0); 01131 /* Indicate the default source if we can. */ 01132 if (dodefault(propname, 8, 1, &default_value) == 0 && 01133 value == default_value) { 01134 VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, "") == 0); 01135 } 01136 VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0); 01137 nvlist_free(propval); 01138 } 01139 01140 void 01141 dsl_prop_nvlist_add_string(nvlist_t *nv, zfs_prop_t prop, const char *value) 01142 { 01143 nvlist_t *propval; 01144 const char *propname = zfs_prop_to_name(prop); 01145 01146 if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) { 01147 VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0); 01148 return; 01149 } 01150 01151 VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 01152 VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0); 01153 VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0); 01154 nvlist_free(propval); 01155 }