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