dsl_prop.c revision 219089
1168404Spjd/* 2168404Spjd * CDDL HEADER START 3168404Spjd * 4168404Spjd * The contents of this file are subject to the terms of the 5168404Spjd * Common Development and Distribution License (the "License"). 6168404Spjd * You may not use this file except in compliance with the License. 7168404Spjd * 8168404Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9168404Spjd * or http://www.opensolaris.org/os/licensing. 10168404Spjd * See the License for the specific language governing permissions 11168404Spjd * and limitations under the License. 12168404Spjd * 13168404Spjd * When distributing Covered Code, include this CDDL HEADER in each 14168404Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15168404Spjd * If applicable, add the following below this CDDL HEADER, with the 16168404Spjd * fields enclosed by brackets "[]" replaced with your own identifying 17168404Spjd * information: Portions Copyright [yyyy] [name of copyright owner] 18168404Spjd * 19168404Spjd * CDDL HEADER END 20168404Spjd */ 21168404Spjd/* 22219089Spjd * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23168404Spjd */ 24168404Spjd 25219089Spjd#include <sys/zfs_context.h> 26168404Spjd#include <sys/dmu.h> 27168404Spjd#include <sys/dmu_objset.h> 28168404Spjd#include <sys/dmu_tx.h> 29168404Spjd#include <sys/dsl_dataset.h> 30168404Spjd#include <sys/dsl_dir.h> 31168404Spjd#include <sys/dsl_prop.h> 32168404Spjd#include <sys/dsl_synctask.h> 33168404Spjd#include <sys/spa.h> 34168404Spjd#include <sys/zap.h> 35168404Spjd#include <sys/fs/zfs.h> 36168404Spjd 37168404Spjd#include "zfs_prop.h" 38168404Spjd 39219089Spjd#define ZPROP_INHERIT_SUFFIX "$inherit" 40219089Spjd#define ZPROP_RECVD_SUFFIX "$recvd" 41219089Spjd 42168404Spjdstatic int 43219089Spjddodefault(const char *propname, int intsz, int numints, void *buf) 44168404Spjd{ 45168404Spjd zfs_prop_t prop; 46168404Spjd 47185029Spjd /* 48185029Spjd * The setonce properties are read-only, BUT they still 49185029Spjd * have a default value that can be used as the initial 50185029Spjd * value. 51185029Spjd */ 52185029Spjd if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL || 53185029Spjd (zfs_prop_readonly(prop) && !zfs_prop_setonce(prop))) 54168404Spjd return (ENOENT); 55168404Spjd 56185029Spjd if (zfs_prop_get_type(prop) == PROP_TYPE_STRING) { 57168404Spjd if (intsz != 1) 58168404Spjd return (EOVERFLOW); 59185029Spjd (void) strncpy(buf, zfs_prop_default_string(prop), 60219089Spjd numints); 61168404Spjd } else { 62219089Spjd if (intsz != 8 || numints < 1) 63168404Spjd return (EOVERFLOW); 64168404Spjd 65168404Spjd *(uint64_t *)buf = zfs_prop_default_numeric(prop); 66168404Spjd } 67168404Spjd 68168404Spjd return (0); 69168404Spjd} 70168404Spjd 71185029Spjdint 72185029Spjddsl_prop_get_dd(dsl_dir_t *dd, const char *propname, 73219089Spjd int intsz, int numints, void *buf, char *setpoint, boolean_t snapshot) 74168404Spjd{ 75168404Spjd int err = ENOENT; 76219089Spjd dsl_dir_t *target = dd; 77185029Spjd objset_t *mos = dd->dd_pool->dp_meta_objset; 78168404Spjd zfs_prop_t prop; 79219089Spjd boolean_t inheritable; 80219089Spjd boolean_t inheriting = B_FALSE; 81219089Spjd char *inheritstr; 82219089Spjd char *recvdstr; 83168404Spjd 84185029Spjd ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock)); 85185029Spjd 86168404Spjd if (setpoint) 87168404Spjd setpoint[0] = '\0'; 88168404Spjd 89168404Spjd prop = zfs_name_to_prop(propname); 90219089Spjd inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop)); 91219089Spjd inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX); 92219089Spjd recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX); 93168404Spjd 94168404Spjd /* 95219089Spjd * Note: dd may become NULL, therefore we shouldn't dereference it 96219089Spjd * after this loop. 97168404Spjd */ 98168404Spjd for (; dd != NULL; dd = dd->dd_parent) { 99168404Spjd ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock)); 100219089Spjd 101219089Spjd if (dd != target || snapshot) { 102219089Spjd if (!inheritable) 103219089Spjd break; 104219089Spjd inheriting = B_TRUE; 105219089Spjd } 106219089Spjd 107219089Spjd /* Check for a local value. */ 108219089Spjd err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj, propname, 109219089Spjd intsz, numints, buf); 110168404Spjd if (err != ENOENT) { 111219089Spjd if (setpoint != NULL && err == 0) 112168404Spjd dsl_dir_name(dd, setpoint); 113168404Spjd break; 114168404Spjd } 115168404Spjd 116168404Spjd /* 117219089Spjd * Skip the check for a received value if there is an explicit 118219089Spjd * inheritance entry. 119168404Spjd */ 120219089Spjd err = zap_contains(mos, dd->dd_phys->dd_props_zapobj, 121219089Spjd inheritstr); 122219089Spjd if (err != 0 && err != ENOENT) 123168404Spjd break; 124219089Spjd 125219089Spjd if (err == ENOENT) { 126219089Spjd /* Check for a received value. */ 127219089Spjd err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj, 128219089Spjd recvdstr, intsz, numints, buf); 129219089Spjd if (err != ENOENT) { 130219089Spjd if (setpoint != NULL && err == 0) { 131219089Spjd if (inheriting) { 132219089Spjd dsl_dir_name(dd, setpoint); 133219089Spjd } else { 134219089Spjd (void) strcpy(setpoint, 135219089Spjd ZPROP_SOURCE_VAL_RECVD); 136219089Spjd } 137219089Spjd } 138219089Spjd break; 139219089Spjd } 140219089Spjd } 141219089Spjd 142219089Spjd /* 143219089Spjd * If we found an explicit inheritance entry, err is zero even 144219089Spjd * though we haven't yet found the value, so reinitializing err 145219089Spjd * at the end of the loop (instead of at the beginning) ensures 146219089Spjd * that err has a valid post-loop value. 147219089Spjd */ 148219089Spjd err = ENOENT; 149168404Spjd } 150219089Spjd 151168404Spjd if (err == ENOENT) 152219089Spjd err = dodefault(propname, intsz, numints, buf); 153168404Spjd 154219089Spjd strfree(inheritstr); 155219089Spjd strfree(recvdstr); 156219089Spjd 157168404Spjd return (err); 158168404Spjd} 159168404Spjd 160185029Spjdint 161185029Spjddsl_prop_get_ds(dsl_dataset_t *ds, const char *propname, 162219089Spjd int intsz, int numints, void *buf, char *setpoint) 163185029Spjd{ 164219089Spjd zfs_prop_t prop = zfs_name_to_prop(propname); 165219089Spjd boolean_t inheritable; 166219089Spjd boolean_t snapshot; 167219089Spjd uint64_t zapobj; 168219089Spjd 169185029Spjd ASSERT(RW_LOCK_HELD(&ds->ds_dir->dd_pool->dp_config_rwlock)); 170219089Spjd inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop)); 171219089Spjd snapshot = (ds->ds_phys != NULL && dsl_dataset_is_snapshot(ds)); 172219089Spjd zapobj = (ds->ds_phys == NULL ? 0 : ds->ds_phys->ds_props_obj); 173185029Spjd 174219089Spjd if (zapobj != 0) { 175219089Spjd objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 176219089Spjd int err; 177219089Spjd 178219089Spjd ASSERT(snapshot); 179219089Spjd 180219089Spjd /* Check for a local value. */ 181219089Spjd err = zap_lookup(mos, zapobj, propname, intsz, numints, buf); 182185029Spjd if (err != ENOENT) { 183219089Spjd if (setpoint != NULL && err == 0) 184185029Spjd dsl_dataset_name(ds, setpoint); 185185029Spjd return (err); 186185029Spjd } 187219089Spjd 188219089Spjd /* 189219089Spjd * Skip the check for a received value if there is an explicit 190219089Spjd * inheritance entry. 191219089Spjd */ 192219089Spjd if (inheritable) { 193219089Spjd char *inheritstr = kmem_asprintf("%s%s", propname, 194219089Spjd ZPROP_INHERIT_SUFFIX); 195219089Spjd err = zap_contains(mos, zapobj, inheritstr); 196219089Spjd strfree(inheritstr); 197219089Spjd if (err != 0 && err != ENOENT) 198219089Spjd return (err); 199219089Spjd } 200219089Spjd 201219089Spjd if (err == ENOENT) { 202219089Spjd /* Check for a received value. */ 203219089Spjd char *recvdstr = kmem_asprintf("%s%s", propname, 204219089Spjd ZPROP_RECVD_SUFFIX); 205219089Spjd err = zap_lookup(mos, zapobj, recvdstr, 206219089Spjd intsz, numints, buf); 207219089Spjd strfree(recvdstr); 208219089Spjd if (err != ENOENT) { 209219089Spjd if (setpoint != NULL && err == 0) 210219089Spjd (void) strcpy(setpoint, 211219089Spjd ZPROP_SOURCE_VAL_RECVD); 212219089Spjd return (err); 213219089Spjd } 214219089Spjd } 215185029Spjd } 216185029Spjd 217185029Spjd return (dsl_prop_get_dd(ds->ds_dir, propname, 218219089Spjd intsz, numints, buf, setpoint, snapshot)); 219185029Spjd} 220185029Spjd 221168404Spjd/* 222168404Spjd * Register interest in the named property. We'll call the callback 223168404Spjd * once to notify it of the current property value, and again each time 224168404Spjd * the property changes, until this callback is unregistered. 225168404Spjd * 226168404Spjd * Return 0 on success, errno if the prop is not an integer value. 227168404Spjd */ 228168404Spjdint 229168404Spjddsl_prop_register(dsl_dataset_t *ds, const char *propname, 230168404Spjd dsl_prop_changed_cb_t *callback, void *cbarg) 231168404Spjd{ 232168404Spjd dsl_dir_t *dd = ds->ds_dir; 233185029Spjd dsl_pool_t *dp = dd->dd_pool; 234168404Spjd uint64_t value; 235168404Spjd dsl_prop_cb_record_t *cbr; 236168404Spjd int err; 237168404Spjd int need_rwlock; 238168404Spjd 239185029Spjd need_rwlock = !RW_WRITE_HELD(&dp->dp_config_rwlock); 240168404Spjd if (need_rwlock) 241185029Spjd rw_enter(&dp->dp_config_rwlock, RW_READER); 242168404Spjd 243185029Spjd err = dsl_prop_get_ds(ds, propname, 8, 1, &value, NULL); 244168404Spjd if (err != 0) { 245185029Spjd if (need_rwlock) 246185029Spjd rw_exit(&dp->dp_config_rwlock); 247168404Spjd return (err); 248168404Spjd } 249168404Spjd 250168404Spjd cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP); 251168404Spjd cbr->cbr_ds = ds; 252168404Spjd cbr->cbr_propname = kmem_alloc(strlen(propname)+1, KM_SLEEP); 253168404Spjd (void) strcpy((char *)cbr->cbr_propname, propname); 254168404Spjd cbr->cbr_func = callback; 255168404Spjd cbr->cbr_arg = cbarg; 256168404Spjd mutex_enter(&dd->dd_lock); 257168404Spjd list_insert_head(&dd->dd_prop_cbs, cbr); 258168404Spjd mutex_exit(&dd->dd_lock); 259168404Spjd 260168404Spjd cbr->cbr_func(cbr->cbr_arg, value); 261168404Spjd 262168404Spjd if (need_rwlock) 263185029Spjd rw_exit(&dp->dp_config_rwlock); 264168404Spjd return (0); 265168404Spjd} 266168404Spjd 267168404Spjdint 268185029Spjddsl_prop_get(const char *dsname, const char *propname, 269168404Spjd int intsz, int numints, void *buf, char *setpoint) 270168404Spjd{ 271185029Spjd dsl_dataset_t *ds; 272168404Spjd int err; 273168404Spjd 274185029Spjd err = dsl_dataset_hold(dsname, FTAG, &ds); 275168404Spjd if (err) 276168404Spjd return (err); 277168404Spjd 278185029Spjd rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); 279185029Spjd err = dsl_prop_get_ds(ds, propname, intsz, numints, buf, setpoint); 280185029Spjd rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 281168404Spjd 282185029Spjd dsl_dataset_rele(ds, FTAG); 283168404Spjd return (err); 284168404Spjd} 285168404Spjd 286168404Spjd/* 287168404Spjd * Get the current property value. It may have changed by the time this 288168404Spjd * function returns, so it is NOT safe to follow up with 289168404Spjd * dsl_prop_register() and assume that the value has not changed in 290168404Spjd * between. 291168404Spjd * 292168404Spjd * Return 0 on success, ENOENT if ddname is invalid. 293168404Spjd */ 294168404Spjdint 295168404Spjddsl_prop_get_integer(const char *ddname, const char *propname, 296168404Spjd uint64_t *valuep, char *setpoint) 297168404Spjd{ 298168404Spjd return (dsl_prop_get(ddname, propname, 8, 1, valuep, setpoint)); 299168404Spjd} 300168404Spjd 301219089Spjdvoid 302219089Spjddsl_prop_setarg_init_uint64(dsl_prop_setarg_t *psa, const char *propname, 303219089Spjd zprop_source_t source, uint64_t *value) 304219089Spjd{ 305219089Spjd psa->psa_name = propname; 306219089Spjd psa->psa_source = source; 307219089Spjd psa->psa_intsz = 8; 308219089Spjd psa->psa_numints = 1; 309219089Spjd psa->psa_value = value; 310219089Spjd 311219089Spjd psa->psa_effective_value = -1ULL; 312219089Spjd} 313219089Spjd 314168404Spjd/* 315219089Spjd * Predict the effective value of the given special property if it were set with 316219089Spjd * the given value and source. This is not a general purpose function. It exists 317219089Spjd * only to handle the special requirements of the quota and reservation 318219089Spjd * properties. The fact that these properties are non-inheritable greatly 319219089Spjd * simplifies the prediction logic. 320219089Spjd * 321219089Spjd * Returns 0 on success, a positive error code on failure, or -1 if called with 322219089Spjd * a property not handled by this function. 323219089Spjd */ 324219089Spjdint 325219089Spjddsl_prop_predict_sync(dsl_dir_t *dd, dsl_prop_setarg_t *psa) 326219089Spjd{ 327219089Spjd const char *propname = psa->psa_name; 328219089Spjd zfs_prop_t prop = zfs_name_to_prop(propname); 329219089Spjd zprop_source_t source = psa->psa_source; 330219089Spjd objset_t *mos; 331219089Spjd uint64_t zapobj; 332219089Spjd uint64_t version; 333219089Spjd char *recvdstr; 334219089Spjd int err = 0; 335219089Spjd 336219089Spjd switch (prop) { 337219089Spjd case ZFS_PROP_QUOTA: 338219089Spjd case ZFS_PROP_RESERVATION: 339219089Spjd case ZFS_PROP_REFQUOTA: 340219089Spjd case ZFS_PROP_REFRESERVATION: 341219089Spjd break; 342219089Spjd default: 343219089Spjd return (-1); 344219089Spjd } 345219089Spjd 346219089Spjd mos = dd->dd_pool->dp_meta_objset; 347219089Spjd zapobj = dd->dd_phys->dd_props_zapobj; 348219089Spjd recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX); 349219089Spjd 350219089Spjd version = spa_version(dd->dd_pool->dp_spa); 351219089Spjd if (version < SPA_VERSION_RECVD_PROPS) { 352219089Spjd if (source & ZPROP_SRC_NONE) 353219089Spjd source = ZPROP_SRC_NONE; 354219089Spjd else if (source & ZPROP_SRC_RECEIVED) 355219089Spjd source = ZPROP_SRC_LOCAL; 356219089Spjd } 357219089Spjd 358219089Spjd switch (source) { 359219089Spjd case ZPROP_SRC_NONE: 360219089Spjd /* Revert to the received value, if any. */ 361219089Spjd err = zap_lookup(mos, zapobj, recvdstr, 8, 1, 362219089Spjd &psa->psa_effective_value); 363219089Spjd if (err == ENOENT) 364219089Spjd psa->psa_effective_value = 0; 365219089Spjd break; 366219089Spjd case ZPROP_SRC_LOCAL: 367219089Spjd psa->psa_effective_value = *(uint64_t *)psa->psa_value; 368219089Spjd break; 369219089Spjd case ZPROP_SRC_RECEIVED: 370219089Spjd /* 371219089Spjd * If there's no local setting, then the new received value will 372219089Spjd * be the effective value. 373219089Spjd */ 374219089Spjd err = zap_lookup(mos, zapobj, propname, 8, 1, 375219089Spjd &psa->psa_effective_value); 376219089Spjd if (err == ENOENT) 377219089Spjd psa->psa_effective_value = *(uint64_t *)psa->psa_value; 378219089Spjd break; 379219089Spjd case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED): 380219089Spjd /* 381219089Spjd * We're clearing the received value, so the local setting (if 382219089Spjd * it exists) remains the effective value. 383219089Spjd */ 384219089Spjd err = zap_lookup(mos, zapobj, propname, 8, 1, 385219089Spjd &psa->psa_effective_value); 386219089Spjd if (err == ENOENT) 387219089Spjd psa->psa_effective_value = 0; 388219089Spjd break; 389219089Spjd default: 390219089Spjd cmn_err(CE_PANIC, "unexpected property source: %d", source); 391219089Spjd } 392219089Spjd 393219089Spjd strfree(recvdstr); 394219089Spjd 395219089Spjd if (err == ENOENT) 396219089Spjd return (0); 397219089Spjd 398219089Spjd return (err); 399219089Spjd} 400219089Spjd 401219089Spjd#ifdef ZFS_DEBUG 402219089Spjdvoid 403219089Spjddsl_prop_check_prediction(dsl_dir_t *dd, dsl_prop_setarg_t *psa) 404219089Spjd{ 405219089Spjd zfs_prop_t prop = zfs_name_to_prop(psa->psa_name); 406219089Spjd uint64_t intval; 407219089Spjd char setpoint[MAXNAMELEN]; 408219089Spjd uint64_t version = spa_version(dd->dd_pool->dp_spa); 409219089Spjd int err; 410219089Spjd 411219089Spjd if (version < SPA_VERSION_RECVD_PROPS) { 412219089Spjd switch (prop) { 413219089Spjd case ZFS_PROP_QUOTA: 414219089Spjd case ZFS_PROP_RESERVATION: 415219089Spjd return; 416219089Spjd } 417219089Spjd } 418219089Spjd 419219089Spjd err = dsl_prop_get_dd(dd, psa->psa_name, 8, 1, &intval, 420219089Spjd setpoint, B_FALSE); 421219089Spjd if (err == 0 && intval != psa->psa_effective_value) { 422219089Spjd cmn_err(CE_PANIC, "%s property, source: %x, " 423219089Spjd "predicted effective value: %llu, " 424219089Spjd "actual effective value: %llu (setpoint: %s)", 425219089Spjd psa->psa_name, psa->psa_source, 426219089Spjd (unsigned long long)psa->psa_effective_value, 427219089Spjd (unsigned long long)intval, setpoint); 428219089Spjd } 429219089Spjd} 430219089Spjd#endif 431219089Spjd 432219089Spjd/* 433168404Spjd * Unregister this callback. Return 0 on success, ENOENT if ddname is 434168404Spjd * invalid, ENOMSG if no matching callback registered. 435168404Spjd */ 436168404Spjdint 437168404Spjddsl_prop_unregister(dsl_dataset_t *ds, const char *propname, 438168404Spjd dsl_prop_changed_cb_t *callback, void *cbarg) 439168404Spjd{ 440168404Spjd dsl_dir_t *dd = ds->ds_dir; 441168404Spjd dsl_prop_cb_record_t *cbr; 442168404Spjd 443168404Spjd mutex_enter(&dd->dd_lock); 444168404Spjd for (cbr = list_head(&dd->dd_prop_cbs); 445168404Spjd cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { 446168404Spjd if (cbr->cbr_ds == ds && 447168404Spjd cbr->cbr_func == callback && 448168404Spjd cbr->cbr_arg == cbarg && 449168404Spjd strcmp(cbr->cbr_propname, propname) == 0) 450168404Spjd break; 451168404Spjd } 452168404Spjd 453168404Spjd if (cbr == NULL) { 454168404Spjd mutex_exit(&dd->dd_lock); 455168404Spjd return (ENOMSG); 456168404Spjd } 457168404Spjd 458168404Spjd list_remove(&dd->dd_prop_cbs, cbr); 459168404Spjd mutex_exit(&dd->dd_lock); 460168404Spjd kmem_free((void*)cbr->cbr_propname, strlen(cbr->cbr_propname)+1); 461168404Spjd kmem_free(cbr, sizeof (dsl_prop_cb_record_t)); 462168404Spjd 463168404Spjd return (0); 464168404Spjd} 465168404Spjd 466168404Spjd/* 467168404Spjd * Return the number of callbacks that are registered for this dataset. 468168404Spjd */ 469168404Spjdint 470168404Spjddsl_prop_numcb(dsl_dataset_t *ds) 471168404Spjd{ 472168404Spjd dsl_dir_t *dd = ds->ds_dir; 473168404Spjd dsl_prop_cb_record_t *cbr; 474168404Spjd int num = 0; 475168404Spjd 476168404Spjd mutex_enter(&dd->dd_lock); 477168404Spjd for (cbr = list_head(&dd->dd_prop_cbs); 478168404Spjd cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { 479168404Spjd if (cbr->cbr_ds == ds) 480168404Spjd num++; 481168404Spjd } 482168404Spjd mutex_exit(&dd->dd_lock); 483168404Spjd 484168404Spjd return (num); 485168404Spjd} 486168404Spjd 487168404Spjdstatic void 488168404Spjddsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj, 489168404Spjd const char *propname, uint64_t value, int first) 490168404Spjd{ 491168404Spjd dsl_dir_t *dd; 492168404Spjd dsl_prop_cb_record_t *cbr; 493168404Spjd objset_t *mos = dp->dp_meta_objset; 494168404Spjd zap_cursor_t zc; 495185029Spjd zap_attribute_t *za; 496168404Spjd int err; 497168404Spjd 498168404Spjd ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 499168404Spjd err = dsl_dir_open_obj(dp, ddobj, NULL, FTAG, &dd); 500168404Spjd if (err) 501168404Spjd return; 502168404Spjd 503168404Spjd if (!first) { 504168404Spjd /* 505168404Spjd * If the prop is set here, then this change is not 506168404Spjd * being inherited here or below; stop the recursion. 507168404Spjd */ 508219089Spjd err = zap_contains(mos, dd->dd_phys->dd_props_zapobj, propname); 509168404Spjd if (err == 0) { 510168404Spjd dsl_dir_close(dd, FTAG); 511168404Spjd return; 512168404Spjd } 513168404Spjd ASSERT3U(err, ==, ENOENT); 514168404Spjd } 515168404Spjd 516168404Spjd mutex_enter(&dd->dd_lock); 517185029Spjd for (cbr = list_head(&dd->dd_prop_cbs); cbr; 518185029Spjd cbr = list_next(&dd->dd_prop_cbs, cbr)) { 519185029Spjd uint64_t propobj = cbr->cbr_ds->ds_phys->ds_props_obj; 520185029Spjd 521185029Spjd if (strcmp(cbr->cbr_propname, propname) != 0) 522185029Spjd continue; 523185029Spjd 524185029Spjd /* 525185029Spjd * If the property is set on this ds, then it is not 526185029Spjd * inherited here; don't call the callback. 527185029Spjd */ 528219089Spjd if (propobj && 0 == zap_contains(mos, propobj, propname)) 529185029Spjd continue; 530185029Spjd 531185029Spjd cbr->cbr_func(cbr->cbr_arg, value); 532168404Spjd } 533168404Spjd mutex_exit(&dd->dd_lock); 534168404Spjd 535185029Spjd za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP); 536168404Spjd for (zap_cursor_init(&zc, mos, 537168404Spjd dd->dd_phys->dd_child_dir_zapobj); 538185029Spjd zap_cursor_retrieve(&zc, za) == 0; 539168404Spjd zap_cursor_advance(&zc)) { 540185029Spjd dsl_prop_changed_notify(dp, za->za_first_integer, 541168404Spjd propname, value, FALSE); 542168404Spjd } 543185029Spjd kmem_free(za, sizeof (zap_attribute_t)); 544168404Spjd zap_cursor_fini(&zc); 545168404Spjd dsl_dir_close(dd, FTAG); 546168404Spjd} 547168404Spjd 548219089Spjdvoid 549219089Spjddsl_prop_set_sync(void *arg1, void *arg2, dmu_tx_t *tx) 550168404Spjd{ 551185029Spjd dsl_dataset_t *ds = arg1; 552219089Spjd dsl_prop_setarg_t *psa = arg2; 553185029Spjd objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 554219089Spjd uint64_t zapobj, intval, dummy; 555168404Spjd int isint; 556185029Spjd char valbuf[32]; 557219089Spjd char *valstr = NULL; 558219089Spjd char *inheritstr; 559219089Spjd char *recvdstr; 560219089Spjd char *tbuf = NULL; 561219089Spjd int err; 562219089Spjd uint64_t version = spa_version(ds->ds_dir->dd_pool->dp_spa); 563219089Spjd const char *propname = psa->psa_name; 564219089Spjd zprop_source_t source = psa->psa_source; 565168404Spjd 566219089Spjd isint = (dodefault(propname, 8, 1, &intval) == 0); 567168404Spjd 568219089Spjd if (ds->ds_phys != NULL && dsl_dataset_is_snapshot(ds)) { 569219089Spjd ASSERT(version >= SPA_VERSION_SNAP_PROPS); 570185029Spjd if (ds->ds_phys->ds_props_obj == 0) { 571185029Spjd dmu_buf_will_dirty(ds->ds_dbuf, tx); 572185029Spjd ds->ds_phys->ds_props_obj = 573185029Spjd zap_create(mos, 574185029Spjd DMU_OT_DSL_PROPS, DMU_OT_NONE, 0, tx); 575185029Spjd } 576185029Spjd zapobj = ds->ds_phys->ds_props_obj; 577185029Spjd } else { 578185029Spjd zapobj = ds->ds_dir->dd_phys->dd_props_zapobj; 579185029Spjd } 580185029Spjd 581219089Spjd if (version < SPA_VERSION_RECVD_PROPS) { 582219089Spjd zfs_prop_t prop = zfs_name_to_prop(propname); 583219089Spjd if (prop == ZFS_PROP_QUOTA || prop == ZFS_PROP_RESERVATION) 584219089Spjd return; 585219089Spjd 586219089Spjd if (source & ZPROP_SRC_NONE) 587219089Spjd source = ZPROP_SRC_NONE; 588219089Spjd else if (source & ZPROP_SRC_RECEIVED) 589219089Spjd source = ZPROP_SRC_LOCAL; 590219089Spjd } 591219089Spjd 592219089Spjd inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX); 593219089Spjd recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX); 594219089Spjd 595219089Spjd switch (source) { 596219089Spjd case ZPROP_SRC_NONE: 597219089Spjd /* 598219089Spjd * revert to received value, if any (inherit -S) 599219089Spjd * - remove propname 600219089Spjd * - remove propname$inherit 601219089Spjd */ 602219089Spjd err = zap_remove(mos, zapobj, propname, tx); 603168404Spjd ASSERT(err == 0 || err == ENOENT); 604219089Spjd err = zap_remove(mos, zapobj, inheritstr, tx); 605219089Spjd ASSERT(err == 0 || err == ENOENT); 606219089Spjd break; 607219089Spjd case ZPROP_SRC_LOCAL: 608219089Spjd /* 609219089Spjd * remove propname$inherit 610219089Spjd * set propname -> value 611219089Spjd */ 612219089Spjd err = zap_remove(mos, zapobj, inheritstr, tx); 613219089Spjd ASSERT(err == 0 || err == ENOENT); 614219089Spjd VERIFY(0 == zap_update(mos, zapobj, propname, 615219089Spjd psa->psa_intsz, psa->psa_numints, psa->psa_value, tx)); 616219089Spjd break; 617219089Spjd case ZPROP_SRC_INHERITED: 618219089Spjd /* 619219089Spjd * explicitly inherit 620219089Spjd * - remove propname 621219089Spjd * - set propname$inherit 622219089Spjd */ 623219089Spjd err = zap_remove(mos, zapobj, propname, tx); 624219089Spjd ASSERT(err == 0 || err == ENOENT); 625219089Spjd if (version >= SPA_VERSION_RECVD_PROPS && 626219089Spjd dsl_prop_get_ds(ds, ZPROP_HAS_RECVD, 8, 1, &dummy, 627219089Spjd NULL) == 0) { 628219089Spjd dummy = 0; 629219089Spjd err = zap_update(mos, zapobj, inheritstr, 630219089Spjd 8, 1, &dummy, tx); 631219089Spjd ASSERT(err == 0); 632168404Spjd } 633219089Spjd break; 634219089Spjd case ZPROP_SRC_RECEIVED: 635219089Spjd /* 636219089Spjd * set propname$recvd -> value 637219089Spjd */ 638219089Spjd err = zap_update(mos, zapobj, recvdstr, 639219089Spjd psa->psa_intsz, psa->psa_numints, psa->psa_value, tx); 640219089Spjd ASSERT(err == 0); 641219089Spjd break; 642219089Spjd case (ZPROP_SRC_NONE | ZPROP_SRC_LOCAL | ZPROP_SRC_RECEIVED): 643219089Spjd /* 644219089Spjd * clear local and received settings 645219089Spjd * - remove propname 646219089Spjd * - remove propname$inherit 647219089Spjd * - remove propname$recvd 648219089Spjd */ 649219089Spjd err = zap_remove(mos, zapobj, propname, tx); 650219089Spjd ASSERT(err == 0 || err == ENOENT); 651219089Spjd err = zap_remove(mos, zapobj, inheritstr, tx); 652219089Spjd ASSERT(err == 0 || err == ENOENT); 653219089Spjd /* FALLTHRU */ 654219089Spjd case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED): 655219089Spjd /* 656219089Spjd * remove propname$recvd 657219089Spjd */ 658219089Spjd err = zap_remove(mos, zapobj, recvdstr, tx); 659219089Spjd ASSERT(err == 0 || err == ENOENT); 660219089Spjd break; 661219089Spjd default: 662219089Spjd cmn_err(CE_PANIC, "unexpected property source: %d", source); 663168404Spjd } 664168404Spjd 665219089Spjd strfree(inheritstr); 666219089Spjd strfree(recvdstr); 667219089Spjd 668168404Spjd if (isint) { 669219089Spjd VERIFY(0 == dsl_prop_get_ds(ds, propname, 8, 1, &intval, NULL)); 670219089Spjd 671219089Spjd if (ds->ds_phys != NULL && dsl_dataset_is_snapshot(ds)) { 672185029Spjd dsl_prop_cb_record_t *cbr; 673185029Spjd /* 674185029Spjd * It's a snapshot; nothing can inherit this 675185029Spjd * property, so just look for callbacks on this 676185029Spjd * ds here. 677185029Spjd */ 678185029Spjd mutex_enter(&ds->ds_dir->dd_lock); 679185029Spjd for (cbr = list_head(&ds->ds_dir->dd_prop_cbs); cbr; 680185029Spjd cbr = list_next(&ds->ds_dir->dd_prop_cbs, cbr)) { 681185029Spjd if (cbr->cbr_ds == ds && 682219089Spjd strcmp(cbr->cbr_propname, propname) == 0) 683185029Spjd cbr->cbr_func(cbr->cbr_arg, intval); 684185029Spjd } 685185029Spjd mutex_exit(&ds->ds_dir->dd_lock); 686185029Spjd } else { 687185029Spjd dsl_prop_changed_notify(ds->ds_dir->dd_pool, 688219089Spjd ds->ds_dir->dd_object, propname, intval, TRUE); 689185029Spjd } 690219089Spjd 691185029Spjd (void) snprintf(valbuf, sizeof (valbuf), 692185029Spjd "%lld", (longlong_t)intval); 693185029Spjd valstr = valbuf; 694185029Spjd } else { 695219089Spjd if (source == ZPROP_SRC_LOCAL) { 696219089Spjd valstr = (char *)psa->psa_value; 697219089Spjd } else { 698219089Spjd tbuf = kmem_alloc(ZAP_MAXVALUELEN, KM_SLEEP); 699219089Spjd if (dsl_prop_get_ds(ds, propname, 1, 700219089Spjd ZAP_MAXVALUELEN, tbuf, NULL) == 0) 701219089Spjd valstr = tbuf; 702219089Spjd } 703185029Spjd } 704219089Spjd 705219089Spjd spa_history_log_internal((source == ZPROP_SRC_NONE || 706219089Spjd source == ZPROP_SRC_INHERITED) ? LOG_DS_INHERIT : 707219089Spjd LOG_DS_PROPSET, ds->ds_dir->dd_pool->dp_spa, tx, 708219089Spjd "%s=%s dataset = %llu", propname, 709219089Spjd (valstr == NULL ? "" : valstr), ds->ds_object); 710219089Spjd 711219089Spjd if (tbuf != NULL) 712219089Spjd kmem_free(tbuf, ZAP_MAXVALUELEN); 713168404Spjd} 714168404Spjd 715185029Spjdvoid 716219089Spjddsl_props_set_sync(void *arg1, void *arg2, dmu_tx_t *tx) 717209962Smm{ 718209962Smm dsl_dataset_t *ds = arg1; 719219089Spjd dsl_props_arg_t *pa = arg2; 720219089Spjd nvlist_t *props = pa->pa_props; 721219089Spjd dsl_prop_setarg_t psa; 722209962Smm nvpair_t *elem = NULL; 723209962Smm 724219089Spjd psa.psa_source = pa->pa_source; 725209962Smm 726219089Spjd while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 727219089Spjd nvpair_t *pair = elem; 728209962Smm 729219089Spjd psa.psa_name = nvpair_name(pair); 730219089Spjd 731219089Spjd if (nvpair_type(pair) == DATA_TYPE_NVLIST) { 732219089Spjd /* 733219089Spjd * dsl_prop_get_all_impl() returns properties in this 734219089Spjd * format. 735219089Spjd */ 736219089Spjd nvlist_t *attrs; 737219089Spjd VERIFY(nvpair_value_nvlist(pair, &attrs) == 0); 738219089Spjd VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 739219089Spjd &pair) == 0); 740219089Spjd } 741219089Spjd 742219089Spjd if (nvpair_type(pair) == DATA_TYPE_STRING) { 743219089Spjd VERIFY(nvpair_value_string(pair, 744219089Spjd (char **)&psa.psa_value) == 0); 745219089Spjd psa.psa_intsz = 1; 746219089Spjd psa.psa_numints = strlen(psa.psa_value) + 1; 747209962Smm } else { 748209962Smm uint64_t intval; 749219089Spjd VERIFY(nvpair_value_uint64(pair, &intval) == 0); 750219089Spjd psa.psa_intsz = sizeof (intval); 751219089Spjd psa.psa_numints = 1; 752219089Spjd psa.psa_value = &intval; 753209962Smm } 754219089Spjd dsl_prop_set_sync(ds, &psa, tx); 755209962Smm } 756209962Smm} 757209962Smm 758209962Smmvoid 759219089Spjddsl_dir_prop_set_uint64_sync(dsl_dir_t *dd, const char *name, uint64_t val, 760219089Spjd dmu_tx_t *tx) 761168404Spjd{ 762185029Spjd objset_t *mos = dd->dd_pool->dp_meta_objset; 763185029Spjd uint64_t zapobj = dd->dd_phys->dd_props_zapobj; 764168404Spjd 765185029Spjd ASSERT(dmu_tx_is_syncing(tx)); 766168404Spjd 767185029Spjd VERIFY(0 == zap_update(mos, zapobj, name, sizeof (val), 1, &val, tx)); 768185029Spjd 769185029Spjd dsl_prop_changed_notify(dd->dd_pool, dd->dd_object, name, val, TRUE); 770185029Spjd 771219089Spjd spa_history_log_internal(LOG_DS_PROPSET, dd->dd_pool->dp_spa, tx, 772185029Spjd "%s=%llu dataset = %llu", name, (u_longlong_t)val, 773185029Spjd dd->dd_phys->dd_head_dataset_obj); 774168404Spjd} 775168404Spjd 776168404Spjdint 777219089Spjddsl_prop_set(const char *dsname, const char *propname, zprop_source_t source, 778168404Spjd int intsz, int numints, const void *buf) 779168404Spjd{ 780185029Spjd dsl_dataset_t *ds; 781219089Spjd uint64_t version; 782168404Spjd int err; 783219089Spjd dsl_prop_setarg_t psa; 784168404Spjd 785168404Spjd /* 786168404Spjd * We must do these checks before we get to the syncfunc, since 787168404Spjd * it can't fail. 788168404Spjd */ 789168404Spjd if (strlen(propname) >= ZAP_MAXNAMELEN) 790168404Spjd return (ENAMETOOLONG); 791168404Spjd 792185029Spjd err = dsl_dataset_hold(dsname, FTAG, &ds); 793168404Spjd if (err) 794168404Spjd return (err); 795185029Spjd 796219089Spjd version = spa_version(ds->ds_dir->dd_pool->dp_spa); 797219089Spjd if (intsz * numints >= (version < SPA_VERSION_STMF_PROP ? 798219089Spjd ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) { 799219089Spjd dsl_dataset_rele(ds, FTAG); 800219089Spjd return (E2BIG); 801219089Spjd } 802185029Spjd if (dsl_dataset_is_snapshot(ds) && 803219089Spjd version < SPA_VERSION_SNAP_PROPS) { 804185029Spjd dsl_dataset_rele(ds, FTAG); 805185029Spjd return (ENOTSUP); 806185029Spjd } 807185029Spjd 808219089Spjd psa.psa_name = propname; 809219089Spjd psa.psa_source = source; 810219089Spjd psa.psa_intsz = intsz; 811219089Spjd psa.psa_numints = numints; 812219089Spjd psa.psa_value = buf; 813219089Spjd psa.psa_effective_value = -1ULL; 814219089Spjd 815185029Spjd err = dsl_sync_task_do(ds->ds_dir->dd_pool, 816185029Spjd NULL, dsl_prop_set_sync, ds, &psa, 2); 817185029Spjd 818185029Spjd dsl_dataset_rele(ds, FTAG); 819168404Spjd return (err); 820168404Spjd} 821168404Spjd 822209962Smmint 823219089Spjddsl_props_set(const char *dsname, zprop_source_t source, nvlist_t *props) 824209962Smm{ 825209962Smm dsl_dataset_t *ds; 826219089Spjd uint64_t version; 827209962Smm nvpair_t *elem = NULL; 828219089Spjd dsl_props_arg_t pa; 829209962Smm int err; 830209962Smm 831219089Spjd if (err = dsl_dataset_hold(dsname, FTAG, &ds)) 832219089Spjd return (err); 833209962Smm /* 834209962Smm * Do these checks before the syncfunc, since it can't fail. 835209962Smm */ 836219089Spjd version = spa_version(ds->ds_dir->dd_pool->dp_spa); 837219089Spjd while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 838219089Spjd if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) { 839219089Spjd dsl_dataset_rele(ds, FTAG); 840209962Smm return (ENAMETOOLONG); 841219089Spjd } 842209962Smm if (nvpair_type(elem) == DATA_TYPE_STRING) { 843209962Smm char *valstr; 844209962Smm VERIFY(nvpair_value_string(elem, &valstr) == 0); 845219089Spjd if (strlen(valstr) >= (version < 846219089Spjd SPA_VERSION_STMF_PROP ? 847219089Spjd ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) { 848219089Spjd dsl_dataset_rele(ds, FTAG); 849209962Smm return (E2BIG); 850219089Spjd } 851209962Smm } 852209962Smm } 853209962Smm 854209962Smm if (dsl_dataset_is_snapshot(ds) && 855219089Spjd version < SPA_VERSION_SNAP_PROPS) { 856209962Smm dsl_dataset_rele(ds, FTAG); 857209962Smm return (ENOTSUP); 858209962Smm } 859209962Smm 860219089Spjd pa.pa_props = props; 861219089Spjd pa.pa_source = source; 862219089Spjd 863209962Smm err = dsl_sync_task_do(ds->ds_dir->dd_pool, 864219089Spjd NULL, dsl_props_set_sync, ds, &pa, 2); 865209962Smm 866209962Smm dsl_dataset_rele(ds, FTAG); 867209962Smm return (err); 868209962Smm} 869209962Smm 870219089Spjdtypedef enum dsl_prop_getflags { 871219089Spjd DSL_PROP_GET_INHERITING = 0x1, /* searching parent of target ds */ 872219089Spjd DSL_PROP_GET_SNAPSHOT = 0x2, /* snapshot dataset */ 873219089Spjd DSL_PROP_GET_LOCAL = 0x4, /* local properties */ 874219089Spjd DSL_PROP_GET_RECEIVED = 0x8 /* received properties */ 875219089Spjd} dsl_prop_getflags_t; 876219089Spjd 877219089Spjdstatic int 878219089Spjddsl_prop_get_all_impl(objset_t *mos, uint64_t propobj, 879219089Spjd const char *setpoint, dsl_prop_getflags_t flags, nvlist_t *nv) 880219089Spjd{ 881219089Spjd zap_cursor_t zc; 882219089Spjd zap_attribute_t za; 883219089Spjd int err = 0; 884219089Spjd 885219089Spjd for (zap_cursor_init(&zc, mos, propobj); 886219089Spjd (err = zap_cursor_retrieve(&zc, &za)) == 0; 887219089Spjd zap_cursor_advance(&zc)) { 888219089Spjd nvlist_t *propval; 889219089Spjd zfs_prop_t prop; 890219089Spjd char buf[ZAP_MAXNAMELEN]; 891219089Spjd char *valstr; 892219089Spjd const char *suffix; 893219089Spjd const char *propname; 894219089Spjd const char *source; 895219089Spjd 896219089Spjd suffix = strchr(za.za_name, '$'); 897219089Spjd 898219089Spjd if (suffix == NULL) { 899219089Spjd /* 900219089Spjd * Skip local properties if we only want received 901219089Spjd * properties. 902219089Spjd */ 903219089Spjd if (flags & DSL_PROP_GET_RECEIVED) 904219089Spjd continue; 905219089Spjd 906219089Spjd propname = za.za_name; 907219089Spjd source = setpoint; 908219089Spjd } else if (strcmp(suffix, ZPROP_INHERIT_SUFFIX) == 0) { 909219089Spjd /* Skip explicitly inherited entries. */ 910219089Spjd continue; 911219089Spjd } else if (strcmp(suffix, ZPROP_RECVD_SUFFIX) == 0) { 912219089Spjd if (flags & DSL_PROP_GET_LOCAL) 913219089Spjd continue; 914219089Spjd 915219089Spjd (void) strncpy(buf, za.za_name, (suffix - za.za_name)); 916219089Spjd buf[suffix - za.za_name] = '\0'; 917219089Spjd propname = buf; 918219089Spjd 919219089Spjd if (!(flags & DSL_PROP_GET_RECEIVED)) { 920219089Spjd /* Skip if locally overridden. */ 921219089Spjd err = zap_contains(mos, propobj, propname); 922219089Spjd if (err == 0) 923219089Spjd continue; 924219089Spjd if (err != ENOENT) 925219089Spjd break; 926219089Spjd 927219089Spjd /* Skip if explicitly inherited. */ 928219089Spjd valstr = kmem_asprintf("%s%s", propname, 929219089Spjd ZPROP_INHERIT_SUFFIX); 930219089Spjd err = zap_contains(mos, propobj, valstr); 931219089Spjd strfree(valstr); 932219089Spjd if (err == 0) 933219089Spjd continue; 934219089Spjd if (err != ENOENT) 935219089Spjd break; 936219089Spjd } 937219089Spjd 938219089Spjd source = ((flags & DSL_PROP_GET_INHERITING) ? 939219089Spjd setpoint : ZPROP_SOURCE_VAL_RECVD); 940219089Spjd } else { 941219089Spjd /* 942219089Spjd * For backward compatibility, skip suffixes we don't 943219089Spjd * recognize. 944219089Spjd */ 945219089Spjd continue; 946219089Spjd } 947219089Spjd 948219089Spjd prop = zfs_name_to_prop(propname); 949219089Spjd 950219089Spjd /* Skip non-inheritable properties. */ 951219089Spjd if ((flags & DSL_PROP_GET_INHERITING) && prop != ZPROP_INVAL && 952219089Spjd !zfs_prop_inheritable(prop)) 953219089Spjd continue; 954219089Spjd 955219089Spjd /* Skip properties not valid for this type. */ 956219089Spjd if ((flags & DSL_PROP_GET_SNAPSHOT) && prop != ZPROP_INVAL && 957219089Spjd !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT)) 958219089Spjd continue; 959219089Spjd 960219089Spjd /* Skip properties already defined. */ 961219089Spjd if (nvlist_exists(nv, propname)) 962219089Spjd continue; 963219089Spjd 964219089Spjd VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 965219089Spjd if (za.za_integer_length == 1) { 966219089Spjd /* 967219089Spjd * String property 968219089Spjd */ 969219089Spjd char *tmp = kmem_alloc(za.za_num_integers, 970219089Spjd KM_SLEEP); 971219089Spjd err = zap_lookup(mos, propobj, 972219089Spjd za.za_name, 1, za.za_num_integers, tmp); 973219089Spjd if (err != 0) { 974219089Spjd kmem_free(tmp, za.za_num_integers); 975219089Spjd break; 976219089Spjd } 977219089Spjd VERIFY(nvlist_add_string(propval, ZPROP_VALUE, 978219089Spjd tmp) == 0); 979219089Spjd kmem_free(tmp, za.za_num_integers); 980219089Spjd } else { 981219089Spjd /* 982219089Spjd * Integer property 983219089Spjd */ 984219089Spjd ASSERT(za.za_integer_length == 8); 985219089Spjd (void) nvlist_add_uint64(propval, ZPROP_VALUE, 986219089Spjd za.za_first_integer); 987219089Spjd } 988219089Spjd 989219089Spjd VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, source) == 0); 990219089Spjd VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0); 991219089Spjd nvlist_free(propval); 992219089Spjd } 993219089Spjd zap_cursor_fini(&zc); 994219089Spjd if (err == ENOENT) 995219089Spjd err = 0; 996219089Spjd return (err); 997219089Spjd} 998219089Spjd 999168404Spjd/* 1000168404Spjd * Iterate over all properties for this dataset and return them in an nvlist. 1001168404Spjd */ 1002219089Spjdstatic int 1003219089Spjddsl_prop_get_all_ds(dsl_dataset_t *ds, nvlist_t **nvp, 1004219089Spjd dsl_prop_getflags_t flags) 1005168404Spjd{ 1006168404Spjd dsl_dir_t *dd = ds->ds_dir; 1007185029Spjd dsl_pool_t *dp = dd->dd_pool; 1008185029Spjd objset_t *mos = dp->dp_meta_objset; 1009219089Spjd int err = 0; 1010219089Spjd char setpoint[MAXNAMELEN]; 1011168404Spjd 1012168404Spjd VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1013168404Spjd 1014219089Spjd if (dsl_dataset_is_snapshot(ds)) 1015219089Spjd flags |= DSL_PROP_GET_SNAPSHOT; 1016168404Spjd 1017168404Spjd rw_enter(&dp->dp_config_rwlock, RW_READER); 1018168404Spjd 1019219089Spjd if (ds->ds_phys->ds_props_obj != 0) { 1020219089Spjd ASSERT(flags & DSL_PROP_GET_SNAPSHOT); 1021219089Spjd dsl_dataset_name(ds, setpoint); 1022219089Spjd err = dsl_prop_get_all_impl(mos, ds->ds_phys->ds_props_obj, 1023219089Spjd setpoint, flags, *nvp); 1024219089Spjd if (err) 1025219089Spjd goto out; 1026219089Spjd } 1027219089Spjd 1028219089Spjd for (; dd != NULL; dd = dd->dd_parent) { 1029219089Spjd if (dd != ds->ds_dir || (flags & DSL_PROP_GET_SNAPSHOT)) { 1030219089Spjd if (flags & (DSL_PROP_GET_LOCAL | 1031219089Spjd DSL_PROP_GET_RECEIVED)) 1032219089Spjd break; 1033219089Spjd flags |= DSL_PROP_GET_INHERITING; 1034185029Spjd } 1035219089Spjd dsl_dir_name(dd, setpoint); 1036219089Spjd err = dsl_prop_get_all_impl(mos, dd->dd_phys->dd_props_zapobj, 1037219089Spjd setpoint, flags, *nvp); 1038219089Spjd if (err) 1039219089Spjd break; 1040219089Spjd } 1041219089Spjdout: 1042219089Spjd rw_exit(&dp->dp_config_rwlock); 1043219089Spjd return (err); 1044219089Spjd} 1045168404Spjd 1046219089Spjdboolean_t 1047219089Spjddsl_prop_get_hasrecvd(objset_t *os) 1048219089Spjd{ 1049219089Spjd dsl_dataset_t *ds = os->os_dsl_dataset; 1050219089Spjd int rc; 1051219089Spjd uint64_t dummy; 1052185029Spjd 1053219089Spjd rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); 1054219089Spjd rc = dsl_prop_get_ds(ds, ZPROP_HAS_RECVD, 8, 1, &dummy, NULL); 1055219089Spjd rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 1056219089Spjd ASSERT(rc != 0 || spa_version(os->os_spa) >= SPA_VERSION_RECVD_PROPS); 1057219089Spjd return (rc == 0); 1058219089Spjd} 1059168404Spjd 1060219089Spjdstatic void 1061219089Spjddsl_prop_set_hasrecvd_impl(objset_t *os, zprop_source_t source) 1062219089Spjd{ 1063219089Spjd dsl_dataset_t *ds = os->os_dsl_dataset; 1064219089Spjd uint64_t dummy = 0; 1065219089Spjd dsl_prop_setarg_t psa; 1066185029Spjd 1067219089Spjd if (spa_version(os->os_spa) < SPA_VERSION_RECVD_PROPS) 1068219089Spjd return; 1069168404Spjd 1070219089Spjd dsl_prop_setarg_init_uint64(&psa, ZPROP_HAS_RECVD, source, &dummy); 1071168404Spjd 1072219089Spjd (void) dsl_sync_task_do(ds->ds_dir->dd_pool, NULL, 1073219089Spjd dsl_prop_set_sync, ds, &psa, 2); 1074219089Spjd} 1075168404Spjd 1076219089Spjd/* 1077219089Spjd * Call after successfully receiving properties to ensure that only the first 1078219089Spjd * receive on or after SPA_VERSION_RECVD_PROPS blows away local properties. 1079219089Spjd */ 1080219089Spjdvoid 1081219089Spjddsl_prop_set_hasrecvd(objset_t *os) 1082219089Spjd{ 1083219089Spjd if (dsl_prop_get_hasrecvd(os)) { 1084219089Spjd ASSERT(spa_version(os->os_spa) >= SPA_VERSION_RECVD_PROPS); 1085219089Spjd return; 1086168404Spjd } 1087219089Spjd dsl_prop_set_hasrecvd_impl(os, ZPROP_SRC_LOCAL); 1088219089Spjd} 1089168404Spjd 1090219089Spjdvoid 1091219089Spjddsl_prop_unset_hasrecvd(objset_t *os) 1092219089Spjd{ 1093219089Spjd dsl_prop_set_hasrecvd_impl(os, ZPROP_SRC_NONE); 1094168404Spjd} 1095168404Spjd 1096219089Spjdint 1097219089Spjddsl_prop_get_all(objset_t *os, nvlist_t **nvp) 1098219089Spjd{ 1099219089Spjd return (dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, 0)); 1100219089Spjd} 1101219089Spjd 1102219089Spjdint 1103219089Spjddsl_prop_get_received(objset_t *os, nvlist_t **nvp) 1104219089Spjd{ 1105219089Spjd /* 1106219089Spjd * Received properties are not distinguishable from local properties 1107219089Spjd * until the dataset has received properties on or after 1108219089Spjd * SPA_VERSION_RECVD_PROPS. 1109219089Spjd */ 1110219089Spjd dsl_prop_getflags_t flags = (dsl_prop_get_hasrecvd(os) ? 1111219089Spjd DSL_PROP_GET_RECEIVED : DSL_PROP_GET_LOCAL); 1112219089Spjd return (dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, flags)); 1113219089Spjd} 1114219089Spjd 1115168404Spjdvoid 1116168404Spjddsl_prop_nvlist_add_uint64(nvlist_t *nv, zfs_prop_t prop, uint64_t value) 1117168404Spjd{ 1118168404Spjd nvlist_t *propval; 1119219089Spjd const char *propname = zfs_prop_to_name(prop); 1120219089Spjd uint64_t default_value; 1121168404Spjd 1122219089Spjd if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) { 1123219089Spjd VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0); 1124219089Spjd return; 1125219089Spjd } 1126219089Spjd 1127168404Spjd VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1128185029Spjd VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0); 1129219089Spjd /* Indicate the default source if we can. */ 1130219089Spjd if (dodefault(propname, 8, 1, &default_value) == 0 && 1131219089Spjd value == default_value) { 1132219089Spjd VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, "") == 0); 1133219089Spjd } 1134219089Spjd VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0); 1135168404Spjd nvlist_free(propval); 1136168404Spjd} 1137168404Spjd 1138168404Spjdvoid 1139168404Spjddsl_prop_nvlist_add_string(nvlist_t *nv, zfs_prop_t prop, const char *value) 1140168404Spjd{ 1141168404Spjd nvlist_t *propval; 1142219089Spjd const char *propname = zfs_prop_to_name(prop); 1143168404Spjd 1144219089Spjd if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) { 1145219089Spjd VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0); 1146219089Spjd return; 1147219089Spjd } 1148219089Spjd 1149168404Spjd VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1150185029Spjd VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0); 1151219089Spjd VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0); 1152168404Spjd nvlist_free(propval); 1153168404Spjd} 1154