1*eda14cbcSMatt Macy /* 2*eda14cbcSMatt Macy * CDDL HEADER START 3*eda14cbcSMatt Macy * 4*eda14cbcSMatt Macy * The contents of this file are subject to the terms of the 5*eda14cbcSMatt Macy * Common Development and Distribution License (the "License"). 6*eda14cbcSMatt Macy * You may not use this file except in compliance with the License. 7*eda14cbcSMatt Macy * 8*eda14cbcSMatt Macy * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*eda14cbcSMatt Macy * or http://www.opensolaris.org/os/licensing. 10*eda14cbcSMatt Macy * See the License for the specific language governing permissions 11*eda14cbcSMatt Macy * and limitations under the License. 12*eda14cbcSMatt Macy * 13*eda14cbcSMatt Macy * When distributing Covered Code, include this CDDL HEADER in each 14*eda14cbcSMatt Macy * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*eda14cbcSMatt Macy * If applicable, add the following below this CDDL HEADER, with the 16*eda14cbcSMatt Macy * fields enclosed by brackets "[]" replaced with your own identifying 17*eda14cbcSMatt Macy * information: Portions Copyright [yyyy] [name of copyright owner] 18*eda14cbcSMatt Macy * 19*eda14cbcSMatt Macy * CDDL HEADER END 20*eda14cbcSMatt Macy */ 21*eda14cbcSMatt Macy /* 22*eda14cbcSMatt Macy * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23*eda14cbcSMatt Macy * Copyright (c) 2012, 2015 by Delphix. All rights reserved. 24*eda14cbcSMatt Macy * Copyright (c) 2013 Martin Matuska. All rights reserved. 25*eda14cbcSMatt Macy * Copyright 2019 Joyent, Inc. 26*eda14cbcSMatt Macy */ 27*eda14cbcSMatt Macy 28*eda14cbcSMatt Macy #include <sys/zfs_context.h> 29*eda14cbcSMatt Macy #include <sys/dmu.h> 30*eda14cbcSMatt Macy #include <sys/dmu_objset.h> 31*eda14cbcSMatt Macy #include <sys/dmu_tx.h> 32*eda14cbcSMatt Macy #include <sys/dsl_dataset.h> 33*eda14cbcSMatt Macy #include <sys/dsl_dir.h> 34*eda14cbcSMatt Macy #include <sys/dsl_prop.h> 35*eda14cbcSMatt Macy #include <sys/dsl_synctask.h> 36*eda14cbcSMatt Macy #include <sys/spa.h> 37*eda14cbcSMatt Macy #include <sys/zap.h> 38*eda14cbcSMatt Macy #include <sys/fs/zfs.h> 39*eda14cbcSMatt Macy 40*eda14cbcSMatt Macy #include "zfs_prop.h" 41*eda14cbcSMatt Macy 42*eda14cbcSMatt Macy #define ZPROP_INHERIT_SUFFIX "$inherit" 43*eda14cbcSMatt Macy #define ZPROP_RECVD_SUFFIX "$recvd" 44*eda14cbcSMatt Macy 45*eda14cbcSMatt Macy static int 46*eda14cbcSMatt Macy dodefault(zfs_prop_t prop, int intsz, int numints, void *buf) 47*eda14cbcSMatt Macy { 48*eda14cbcSMatt Macy /* 49*eda14cbcSMatt Macy * The setonce properties are read-only, BUT they still 50*eda14cbcSMatt Macy * have a default value that can be used as the initial 51*eda14cbcSMatt Macy * value. 52*eda14cbcSMatt Macy */ 53*eda14cbcSMatt Macy if (prop == ZPROP_INVAL || 54*eda14cbcSMatt Macy (zfs_prop_readonly(prop) && !zfs_prop_setonce(prop))) 55*eda14cbcSMatt Macy return (SET_ERROR(ENOENT)); 56*eda14cbcSMatt Macy 57*eda14cbcSMatt Macy if (zfs_prop_get_type(prop) == PROP_TYPE_STRING) { 58*eda14cbcSMatt Macy if (intsz != 1) 59*eda14cbcSMatt Macy return (SET_ERROR(EOVERFLOW)); 60*eda14cbcSMatt Macy (void) strncpy(buf, zfs_prop_default_string(prop), 61*eda14cbcSMatt Macy numints); 62*eda14cbcSMatt Macy } else { 63*eda14cbcSMatt Macy if (intsz != 8 || numints < 1) 64*eda14cbcSMatt Macy return (SET_ERROR(EOVERFLOW)); 65*eda14cbcSMatt Macy 66*eda14cbcSMatt Macy *(uint64_t *)buf = zfs_prop_default_numeric(prop); 67*eda14cbcSMatt Macy } 68*eda14cbcSMatt Macy 69*eda14cbcSMatt Macy return (0); 70*eda14cbcSMatt Macy } 71*eda14cbcSMatt Macy 72*eda14cbcSMatt Macy int 73*eda14cbcSMatt Macy dsl_prop_get_dd(dsl_dir_t *dd, const char *propname, 74*eda14cbcSMatt Macy int intsz, int numints, void *buf, char *setpoint, boolean_t snapshot) 75*eda14cbcSMatt Macy { 76*eda14cbcSMatt Macy int err; 77*eda14cbcSMatt Macy dsl_dir_t *target = dd; 78*eda14cbcSMatt Macy objset_t *mos = dd->dd_pool->dp_meta_objset; 79*eda14cbcSMatt Macy zfs_prop_t prop; 80*eda14cbcSMatt Macy boolean_t inheritable; 81*eda14cbcSMatt Macy boolean_t inheriting = B_FALSE; 82*eda14cbcSMatt Macy char *inheritstr; 83*eda14cbcSMatt Macy char *recvdstr; 84*eda14cbcSMatt Macy 85*eda14cbcSMatt Macy ASSERT(dsl_pool_config_held(dd->dd_pool)); 86*eda14cbcSMatt Macy 87*eda14cbcSMatt Macy if (setpoint) 88*eda14cbcSMatt Macy setpoint[0] = '\0'; 89*eda14cbcSMatt Macy 90*eda14cbcSMatt Macy prop = zfs_name_to_prop(propname); 91*eda14cbcSMatt Macy inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop)); 92*eda14cbcSMatt Macy inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX); 93*eda14cbcSMatt Macy recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX); 94*eda14cbcSMatt Macy 95*eda14cbcSMatt Macy /* 96*eda14cbcSMatt Macy * Note: dd may become NULL, therefore we shouldn't dereference it 97*eda14cbcSMatt Macy * after this loop. 98*eda14cbcSMatt Macy */ 99*eda14cbcSMatt Macy for (; dd != NULL; dd = dd->dd_parent) { 100*eda14cbcSMatt Macy if (dd != target || snapshot) { 101*eda14cbcSMatt Macy if (!inheritable) { 102*eda14cbcSMatt Macy err = SET_ERROR(ENOENT); 103*eda14cbcSMatt Macy break; 104*eda14cbcSMatt Macy } 105*eda14cbcSMatt Macy inheriting = B_TRUE; 106*eda14cbcSMatt Macy } 107*eda14cbcSMatt Macy 108*eda14cbcSMatt Macy /* Check for a local value. */ 109*eda14cbcSMatt Macy err = zap_lookup(mos, dsl_dir_phys(dd)->dd_props_zapobj, 110*eda14cbcSMatt Macy propname, intsz, numints, buf); 111*eda14cbcSMatt Macy if (err != ENOENT) { 112*eda14cbcSMatt Macy if (setpoint != NULL && err == 0) 113*eda14cbcSMatt Macy dsl_dir_name(dd, setpoint); 114*eda14cbcSMatt Macy break; 115*eda14cbcSMatt Macy } 116*eda14cbcSMatt Macy 117*eda14cbcSMatt Macy /* 118*eda14cbcSMatt Macy * Skip the check for a received value if there is an explicit 119*eda14cbcSMatt Macy * inheritance entry. 120*eda14cbcSMatt Macy */ 121*eda14cbcSMatt Macy err = zap_contains(mos, dsl_dir_phys(dd)->dd_props_zapobj, 122*eda14cbcSMatt Macy inheritstr); 123*eda14cbcSMatt Macy if (err != 0 && err != ENOENT) 124*eda14cbcSMatt Macy break; 125*eda14cbcSMatt Macy 126*eda14cbcSMatt Macy if (err == ENOENT) { 127*eda14cbcSMatt Macy /* Check for a received value. */ 128*eda14cbcSMatt Macy err = zap_lookup(mos, dsl_dir_phys(dd)->dd_props_zapobj, 129*eda14cbcSMatt Macy recvdstr, intsz, numints, buf); 130*eda14cbcSMatt Macy if (err != ENOENT) { 131*eda14cbcSMatt Macy if (setpoint != NULL && err == 0) { 132*eda14cbcSMatt Macy if (inheriting) { 133*eda14cbcSMatt Macy dsl_dir_name(dd, setpoint); 134*eda14cbcSMatt Macy } else { 135*eda14cbcSMatt Macy (void) strlcpy(setpoint, 136*eda14cbcSMatt Macy ZPROP_SOURCE_VAL_RECVD, 137*eda14cbcSMatt Macy MAXNAMELEN); 138*eda14cbcSMatt Macy } 139*eda14cbcSMatt Macy } 140*eda14cbcSMatt Macy break; 141*eda14cbcSMatt Macy } 142*eda14cbcSMatt Macy } 143*eda14cbcSMatt Macy 144*eda14cbcSMatt Macy /* 145*eda14cbcSMatt Macy * If we found an explicit inheritance entry, err is zero even 146*eda14cbcSMatt Macy * though we haven't yet found the value, so reinitializing err 147*eda14cbcSMatt Macy * at the end of the loop (instead of at the beginning) ensures 148*eda14cbcSMatt Macy * that err has a valid post-loop value. 149*eda14cbcSMatt Macy */ 150*eda14cbcSMatt Macy err = SET_ERROR(ENOENT); 151*eda14cbcSMatt Macy } 152*eda14cbcSMatt Macy 153*eda14cbcSMatt Macy if (err == ENOENT) 154*eda14cbcSMatt Macy err = dodefault(prop, intsz, numints, buf); 155*eda14cbcSMatt Macy 156*eda14cbcSMatt Macy kmem_strfree(inheritstr); 157*eda14cbcSMatt Macy kmem_strfree(recvdstr); 158*eda14cbcSMatt Macy 159*eda14cbcSMatt Macy return (err); 160*eda14cbcSMatt Macy } 161*eda14cbcSMatt Macy 162*eda14cbcSMatt Macy int 163*eda14cbcSMatt Macy dsl_prop_get_ds(dsl_dataset_t *ds, const char *propname, 164*eda14cbcSMatt Macy int intsz, int numints, void *buf, char *setpoint) 165*eda14cbcSMatt Macy { 166*eda14cbcSMatt Macy zfs_prop_t prop = zfs_name_to_prop(propname); 167*eda14cbcSMatt Macy boolean_t inheritable; 168*eda14cbcSMatt Macy uint64_t zapobj; 169*eda14cbcSMatt Macy 170*eda14cbcSMatt Macy ASSERT(dsl_pool_config_held(ds->ds_dir->dd_pool)); 171*eda14cbcSMatt Macy inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop)); 172*eda14cbcSMatt Macy zapobj = dsl_dataset_phys(ds)->ds_props_obj; 173*eda14cbcSMatt Macy 174*eda14cbcSMatt Macy if (zapobj != 0) { 175*eda14cbcSMatt Macy objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 176*eda14cbcSMatt Macy int err; 177*eda14cbcSMatt Macy 178*eda14cbcSMatt Macy ASSERT(ds->ds_is_snapshot); 179*eda14cbcSMatt Macy 180*eda14cbcSMatt Macy /* Check for a local value. */ 181*eda14cbcSMatt Macy err = zap_lookup(mos, zapobj, propname, intsz, numints, buf); 182*eda14cbcSMatt Macy if (err != ENOENT) { 183*eda14cbcSMatt Macy if (setpoint != NULL && err == 0) 184*eda14cbcSMatt Macy dsl_dataset_name(ds, setpoint); 185*eda14cbcSMatt Macy return (err); 186*eda14cbcSMatt Macy } 187*eda14cbcSMatt Macy 188*eda14cbcSMatt Macy /* 189*eda14cbcSMatt Macy * Skip the check for a received value if there is an explicit 190*eda14cbcSMatt Macy * inheritance entry. 191*eda14cbcSMatt Macy */ 192*eda14cbcSMatt Macy if (inheritable) { 193*eda14cbcSMatt Macy char *inheritstr = kmem_asprintf("%s%s", propname, 194*eda14cbcSMatt Macy ZPROP_INHERIT_SUFFIX); 195*eda14cbcSMatt Macy err = zap_contains(mos, zapobj, inheritstr); 196*eda14cbcSMatt Macy kmem_strfree(inheritstr); 197*eda14cbcSMatt Macy if (err != 0 && err != ENOENT) 198*eda14cbcSMatt Macy return (err); 199*eda14cbcSMatt Macy } 200*eda14cbcSMatt Macy 201*eda14cbcSMatt Macy if (err == ENOENT) { 202*eda14cbcSMatt Macy /* Check for a received value. */ 203*eda14cbcSMatt Macy char *recvdstr = kmem_asprintf("%s%s", propname, 204*eda14cbcSMatt Macy ZPROP_RECVD_SUFFIX); 205*eda14cbcSMatt Macy err = zap_lookup(mos, zapobj, recvdstr, 206*eda14cbcSMatt Macy intsz, numints, buf); 207*eda14cbcSMatt Macy kmem_strfree(recvdstr); 208*eda14cbcSMatt Macy if (err != ENOENT) { 209*eda14cbcSMatt Macy if (setpoint != NULL && err == 0) 210*eda14cbcSMatt Macy (void) strlcpy(setpoint, 211*eda14cbcSMatt Macy ZPROP_SOURCE_VAL_RECVD, 212*eda14cbcSMatt Macy MAXNAMELEN); 213*eda14cbcSMatt Macy return (err); 214*eda14cbcSMatt Macy } 215*eda14cbcSMatt Macy } 216*eda14cbcSMatt Macy } 217*eda14cbcSMatt Macy 218*eda14cbcSMatt Macy return (dsl_prop_get_dd(ds->ds_dir, propname, 219*eda14cbcSMatt Macy intsz, numints, buf, setpoint, ds->ds_is_snapshot)); 220*eda14cbcSMatt Macy } 221*eda14cbcSMatt Macy 222*eda14cbcSMatt Macy static dsl_prop_record_t * 223*eda14cbcSMatt Macy dsl_prop_record_find(dsl_dir_t *dd, const char *propname) 224*eda14cbcSMatt Macy { 225*eda14cbcSMatt Macy dsl_prop_record_t *pr = NULL; 226*eda14cbcSMatt Macy 227*eda14cbcSMatt Macy ASSERT(MUTEX_HELD(&dd->dd_lock)); 228*eda14cbcSMatt Macy 229*eda14cbcSMatt Macy for (pr = list_head(&dd->dd_props); 230*eda14cbcSMatt Macy pr != NULL; pr = list_next(&dd->dd_props, pr)) { 231*eda14cbcSMatt Macy if (strcmp(pr->pr_propname, propname) == 0) 232*eda14cbcSMatt Macy break; 233*eda14cbcSMatt Macy } 234*eda14cbcSMatt Macy 235*eda14cbcSMatt Macy return (pr); 236*eda14cbcSMatt Macy } 237*eda14cbcSMatt Macy 238*eda14cbcSMatt Macy static dsl_prop_record_t * 239*eda14cbcSMatt Macy dsl_prop_record_create(dsl_dir_t *dd, const char *propname) 240*eda14cbcSMatt Macy { 241*eda14cbcSMatt Macy dsl_prop_record_t *pr; 242*eda14cbcSMatt Macy 243*eda14cbcSMatt Macy ASSERT(MUTEX_HELD(&dd->dd_lock)); 244*eda14cbcSMatt Macy 245*eda14cbcSMatt Macy pr = kmem_alloc(sizeof (dsl_prop_record_t), KM_SLEEP); 246*eda14cbcSMatt Macy pr->pr_propname = spa_strdup(propname); 247*eda14cbcSMatt Macy list_create(&pr->pr_cbs, sizeof (dsl_prop_cb_record_t), 248*eda14cbcSMatt Macy offsetof(dsl_prop_cb_record_t, cbr_pr_node)); 249*eda14cbcSMatt Macy list_insert_head(&dd->dd_props, pr); 250*eda14cbcSMatt Macy 251*eda14cbcSMatt Macy return (pr); 252*eda14cbcSMatt Macy } 253*eda14cbcSMatt Macy 254*eda14cbcSMatt Macy void 255*eda14cbcSMatt Macy dsl_prop_init(dsl_dir_t *dd) 256*eda14cbcSMatt Macy { 257*eda14cbcSMatt Macy list_create(&dd->dd_props, sizeof (dsl_prop_record_t), 258*eda14cbcSMatt Macy offsetof(dsl_prop_record_t, pr_node)); 259*eda14cbcSMatt Macy } 260*eda14cbcSMatt Macy 261*eda14cbcSMatt Macy void 262*eda14cbcSMatt Macy dsl_prop_fini(dsl_dir_t *dd) 263*eda14cbcSMatt Macy { 264*eda14cbcSMatt Macy dsl_prop_record_t *pr; 265*eda14cbcSMatt Macy 266*eda14cbcSMatt Macy while ((pr = list_remove_head(&dd->dd_props)) != NULL) { 267*eda14cbcSMatt Macy list_destroy(&pr->pr_cbs); 268*eda14cbcSMatt Macy spa_strfree((char *)pr->pr_propname); 269*eda14cbcSMatt Macy kmem_free(pr, sizeof (dsl_prop_record_t)); 270*eda14cbcSMatt Macy } 271*eda14cbcSMatt Macy list_destroy(&dd->dd_props); 272*eda14cbcSMatt Macy } 273*eda14cbcSMatt Macy 274*eda14cbcSMatt Macy /* 275*eda14cbcSMatt Macy * Register interest in the named property. We'll call the callback 276*eda14cbcSMatt Macy * once to notify it of the current property value, and again each time 277*eda14cbcSMatt Macy * the property changes, until this callback is unregistered. 278*eda14cbcSMatt Macy * 279*eda14cbcSMatt Macy * Return 0 on success, errno if the prop is not an integer value. 280*eda14cbcSMatt Macy */ 281*eda14cbcSMatt Macy int 282*eda14cbcSMatt Macy dsl_prop_register(dsl_dataset_t *ds, const char *propname, 283*eda14cbcSMatt Macy dsl_prop_changed_cb_t *callback, void *cbarg) 284*eda14cbcSMatt Macy { 285*eda14cbcSMatt Macy dsl_dir_t *dd = ds->ds_dir; 286*eda14cbcSMatt Macy uint64_t value; 287*eda14cbcSMatt Macy dsl_prop_record_t *pr; 288*eda14cbcSMatt Macy dsl_prop_cb_record_t *cbr; 289*eda14cbcSMatt Macy int err; 290*eda14cbcSMatt Macy dsl_pool_t *dp __maybe_unused = dd->dd_pool; 291*eda14cbcSMatt Macy 292*eda14cbcSMatt Macy ASSERT(dsl_pool_config_held(dp)); 293*eda14cbcSMatt Macy 294*eda14cbcSMatt Macy err = dsl_prop_get_int_ds(ds, propname, &value); 295*eda14cbcSMatt Macy if (err != 0) 296*eda14cbcSMatt Macy return (err); 297*eda14cbcSMatt Macy 298*eda14cbcSMatt Macy cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP); 299*eda14cbcSMatt Macy cbr->cbr_ds = ds; 300*eda14cbcSMatt Macy cbr->cbr_func = callback; 301*eda14cbcSMatt Macy cbr->cbr_arg = cbarg; 302*eda14cbcSMatt Macy 303*eda14cbcSMatt Macy mutex_enter(&dd->dd_lock); 304*eda14cbcSMatt Macy pr = dsl_prop_record_find(dd, propname); 305*eda14cbcSMatt Macy if (pr == NULL) 306*eda14cbcSMatt Macy pr = dsl_prop_record_create(dd, propname); 307*eda14cbcSMatt Macy cbr->cbr_pr = pr; 308*eda14cbcSMatt Macy list_insert_head(&pr->pr_cbs, cbr); 309*eda14cbcSMatt Macy list_insert_head(&ds->ds_prop_cbs, cbr); 310*eda14cbcSMatt Macy mutex_exit(&dd->dd_lock); 311*eda14cbcSMatt Macy 312*eda14cbcSMatt Macy cbr->cbr_func(cbr->cbr_arg, value); 313*eda14cbcSMatt Macy return (0); 314*eda14cbcSMatt Macy } 315*eda14cbcSMatt Macy 316*eda14cbcSMatt Macy int 317*eda14cbcSMatt Macy dsl_prop_get(const char *dsname, const char *propname, 318*eda14cbcSMatt Macy int intsz, int numints, void *buf, char *setpoint) 319*eda14cbcSMatt Macy { 320*eda14cbcSMatt Macy objset_t *os; 321*eda14cbcSMatt Macy int error; 322*eda14cbcSMatt Macy 323*eda14cbcSMatt Macy error = dmu_objset_hold(dsname, FTAG, &os); 324*eda14cbcSMatt Macy if (error != 0) 325*eda14cbcSMatt Macy return (error); 326*eda14cbcSMatt Macy 327*eda14cbcSMatt Macy error = dsl_prop_get_ds(dmu_objset_ds(os), propname, 328*eda14cbcSMatt Macy intsz, numints, buf, setpoint); 329*eda14cbcSMatt Macy 330*eda14cbcSMatt Macy dmu_objset_rele(os, FTAG); 331*eda14cbcSMatt Macy return (error); 332*eda14cbcSMatt Macy } 333*eda14cbcSMatt Macy 334*eda14cbcSMatt Macy /* 335*eda14cbcSMatt Macy * Get the current property value. It may have changed by the time this 336*eda14cbcSMatt Macy * function returns, so it is NOT safe to follow up with 337*eda14cbcSMatt Macy * dsl_prop_register() and assume that the value has not changed in 338*eda14cbcSMatt Macy * between. 339*eda14cbcSMatt Macy * 340*eda14cbcSMatt Macy * Return 0 on success, ENOENT if ddname is invalid. 341*eda14cbcSMatt Macy */ 342*eda14cbcSMatt Macy int 343*eda14cbcSMatt Macy dsl_prop_get_integer(const char *ddname, const char *propname, 344*eda14cbcSMatt Macy uint64_t *valuep, char *setpoint) 345*eda14cbcSMatt Macy { 346*eda14cbcSMatt Macy return (dsl_prop_get(ddname, propname, 8, 1, valuep, setpoint)); 347*eda14cbcSMatt Macy } 348*eda14cbcSMatt Macy 349*eda14cbcSMatt Macy int 350*eda14cbcSMatt Macy dsl_prop_get_int_ds(dsl_dataset_t *ds, const char *propname, 351*eda14cbcSMatt Macy uint64_t *valuep) 352*eda14cbcSMatt Macy { 353*eda14cbcSMatt Macy return (dsl_prop_get_ds(ds, propname, 8, 1, valuep, NULL)); 354*eda14cbcSMatt Macy } 355*eda14cbcSMatt Macy 356*eda14cbcSMatt Macy /* 357*eda14cbcSMatt Macy * Predict the effective value of the given special property if it were set with 358*eda14cbcSMatt Macy * the given value and source. This is not a general purpose function. It exists 359*eda14cbcSMatt Macy * only to handle the special requirements of the quota and reservation 360*eda14cbcSMatt Macy * properties. The fact that these properties are non-inheritable greatly 361*eda14cbcSMatt Macy * simplifies the prediction logic. 362*eda14cbcSMatt Macy * 363*eda14cbcSMatt Macy * Returns 0 on success, a positive error code on failure, or -1 if called with 364*eda14cbcSMatt Macy * a property not handled by this function. 365*eda14cbcSMatt Macy */ 366*eda14cbcSMatt Macy int 367*eda14cbcSMatt Macy dsl_prop_predict(dsl_dir_t *dd, const char *propname, 368*eda14cbcSMatt Macy zprop_source_t source, uint64_t value, uint64_t *newvalp) 369*eda14cbcSMatt Macy { 370*eda14cbcSMatt Macy zfs_prop_t prop = zfs_name_to_prop(propname); 371*eda14cbcSMatt Macy objset_t *mos; 372*eda14cbcSMatt Macy uint64_t zapobj; 373*eda14cbcSMatt Macy uint64_t version; 374*eda14cbcSMatt Macy char *recvdstr; 375*eda14cbcSMatt Macy int err = 0; 376*eda14cbcSMatt Macy 377*eda14cbcSMatt Macy switch (prop) { 378*eda14cbcSMatt Macy case ZFS_PROP_QUOTA: 379*eda14cbcSMatt Macy case ZFS_PROP_RESERVATION: 380*eda14cbcSMatt Macy case ZFS_PROP_REFQUOTA: 381*eda14cbcSMatt Macy case ZFS_PROP_REFRESERVATION: 382*eda14cbcSMatt Macy break; 383*eda14cbcSMatt Macy default: 384*eda14cbcSMatt Macy return (-1); 385*eda14cbcSMatt Macy } 386*eda14cbcSMatt Macy 387*eda14cbcSMatt Macy mos = dd->dd_pool->dp_meta_objset; 388*eda14cbcSMatt Macy zapobj = dsl_dir_phys(dd)->dd_props_zapobj; 389*eda14cbcSMatt Macy recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX); 390*eda14cbcSMatt Macy 391*eda14cbcSMatt Macy version = spa_version(dd->dd_pool->dp_spa); 392*eda14cbcSMatt Macy if (version < SPA_VERSION_RECVD_PROPS) { 393*eda14cbcSMatt Macy if (source & ZPROP_SRC_NONE) 394*eda14cbcSMatt Macy source = ZPROP_SRC_NONE; 395*eda14cbcSMatt Macy else if (source & ZPROP_SRC_RECEIVED) 396*eda14cbcSMatt Macy source = ZPROP_SRC_LOCAL; 397*eda14cbcSMatt Macy } 398*eda14cbcSMatt Macy 399*eda14cbcSMatt Macy switch ((int)source) { 400*eda14cbcSMatt Macy case ZPROP_SRC_NONE: 401*eda14cbcSMatt Macy /* Revert to the received value, if any. */ 402*eda14cbcSMatt Macy err = zap_lookup(mos, zapobj, recvdstr, 8, 1, newvalp); 403*eda14cbcSMatt Macy if (err == ENOENT) 404*eda14cbcSMatt Macy *newvalp = 0; 405*eda14cbcSMatt Macy break; 406*eda14cbcSMatt Macy case ZPROP_SRC_LOCAL: 407*eda14cbcSMatt Macy *newvalp = value; 408*eda14cbcSMatt Macy break; 409*eda14cbcSMatt Macy case ZPROP_SRC_RECEIVED: 410*eda14cbcSMatt Macy /* 411*eda14cbcSMatt Macy * If there's no local setting, then the new received value will 412*eda14cbcSMatt Macy * be the effective value. 413*eda14cbcSMatt Macy */ 414*eda14cbcSMatt Macy err = zap_lookup(mos, zapobj, propname, 8, 1, newvalp); 415*eda14cbcSMatt Macy if (err == ENOENT) 416*eda14cbcSMatt Macy *newvalp = value; 417*eda14cbcSMatt Macy break; 418*eda14cbcSMatt Macy case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED): 419*eda14cbcSMatt Macy /* 420*eda14cbcSMatt Macy * We're clearing the received value, so the local setting (if 421*eda14cbcSMatt Macy * it exists) remains the effective value. 422*eda14cbcSMatt Macy */ 423*eda14cbcSMatt Macy err = zap_lookup(mos, zapobj, propname, 8, 1, newvalp); 424*eda14cbcSMatt Macy if (err == ENOENT) 425*eda14cbcSMatt Macy *newvalp = 0; 426*eda14cbcSMatt Macy break; 427*eda14cbcSMatt Macy default: 428*eda14cbcSMatt Macy panic("unexpected property source: %d", source); 429*eda14cbcSMatt Macy } 430*eda14cbcSMatt Macy 431*eda14cbcSMatt Macy kmem_strfree(recvdstr); 432*eda14cbcSMatt Macy 433*eda14cbcSMatt Macy if (err == ENOENT) 434*eda14cbcSMatt Macy return (0); 435*eda14cbcSMatt Macy 436*eda14cbcSMatt Macy return (err); 437*eda14cbcSMatt Macy } 438*eda14cbcSMatt Macy 439*eda14cbcSMatt Macy /* 440*eda14cbcSMatt Macy * Unregister this callback. Return 0 on success, ENOENT if ddname is 441*eda14cbcSMatt Macy * invalid, or ENOMSG if no matching callback registered. 442*eda14cbcSMatt Macy * 443*eda14cbcSMatt Macy * NOTE: This function is no longer used internally but has been preserved 444*eda14cbcSMatt Macy * to prevent breaking external consumers (Lustre, etc). 445*eda14cbcSMatt Macy */ 446*eda14cbcSMatt Macy int 447*eda14cbcSMatt Macy dsl_prop_unregister(dsl_dataset_t *ds, const char *propname, 448*eda14cbcSMatt Macy dsl_prop_changed_cb_t *callback, void *cbarg) 449*eda14cbcSMatt Macy { 450*eda14cbcSMatt Macy dsl_dir_t *dd = ds->ds_dir; 451*eda14cbcSMatt Macy dsl_prop_cb_record_t *cbr; 452*eda14cbcSMatt Macy 453*eda14cbcSMatt Macy mutex_enter(&dd->dd_lock); 454*eda14cbcSMatt Macy for (cbr = list_head(&ds->ds_prop_cbs); 455*eda14cbcSMatt Macy cbr; cbr = list_next(&ds->ds_prop_cbs, cbr)) { 456*eda14cbcSMatt Macy if (cbr->cbr_ds == ds && 457*eda14cbcSMatt Macy cbr->cbr_func == callback && 458*eda14cbcSMatt Macy cbr->cbr_arg == cbarg && 459*eda14cbcSMatt Macy strcmp(cbr->cbr_pr->pr_propname, propname) == 0) 460*eda14cbcSMatt Macy break; 461*eda14cbcSMatt Macy } 462*eda14cbcSMatt Macy 463*eda14cbcSMatt Macy if (cbr == NULL) { 464*eda14cbcSMatt Macy mutex_exit(&dd->dd_lock); 465*eda14cbcSMatt Macy return (SET_ERROR(ENOMSG)); 466*eda14cbcSMatt Macy } 467*eda14cbcSMatt Macy 468*eda14cbcSMatt Macy list_remove(&ds->ds_prop_cbs, cbr); 469*eda14cbcSMatt Macy list_remove(&cbr->cbr_pr->pr_cbs, cbr); 470*eda14cbcSMatt Macy mutex_exit(&dd->dd_lock); 471*eda14cbcSMatt Macy kmem_free(cbr, sizeof (dsl_prop_cb_record_t)); 472*eda14cbcSMatt Macy 473*eda14cbcSMatt Macy return (0); 474*eda14cbcSMatt Macy } 475*eda14cbcSMatt Macy 476*eda14cbcSMatt Macy /* 477*eda14cbcSMatt Macy * Unregister all callbacks that are registered with the 478*eda14cbcSMatt Macy * given callback argument. 479*eda14cbcSMatt Macy */ 480*eda14cbcSMatt Macy void 481*eda14cbcSMatt Macy dsl_prop_unregister_all(dsl_dataset_t *ds, void *cbarg) 482*eda14cbcSMatt Macy { 483*eda14cbcSMatt Macy dsl_prop_cb_record_t *cbr, *next_cbr; 484*eda14cbcSMatt Macy 485*eda14cbcSMatt Macy dsl_dir_t *dd = ds->ds_dir; 486*eda14cbcSMatt Macy 487*eda14cbcSMatt Macy mutex_enter(&dd->dd_lock); 488*eda14cbcSMatt Macy next_cbr = list_head(&ds->ds_prop_cbs); 489*eda14cbcSMatt Macy while (next_cbr != NULL) { 490*eda14cbcSMatt Macy cbr = next_cbr; 491*eda14cbcSMatt Macy next_cbr = list_next(&ds->ds_prop_cbs, cbr); 492*eda14cbcSMatt Macy if (cbr->cbr_arg == cbarg) { 493*eda14cbcSMatt Macy list_remove(&ds->ds_prop_cbs, cbr); 494*eda14cbcSMatt Macy list_remove(&cbr->cbr_pr->pr_cbs, cbr); 495*eda14cbcSMatt Macy kmem_free(cbr, sizeof (dsl_prop_cb_record_t)); 496*eda14cbcSMatt Macy } 497*eda14cbcSMatt Macy } 498*eda14cbcSMatt Macy mutex_exit(&dd->dd_lock); 499*eda14cbcSMatt Macy } 500*eda14cbcSMatt Macy 501*eda14cbcSMatt Macy boolean_t 502*eda14cbcSMatt Macy dsl_prop_hascb(dsl_dataset_t *ds) 503*eda14cbcSMatt Macy { 504*eda14cbcSMatt Macy return (!list_is_empty(&ds->ds_prop_cbs)); 505*eda14cbcSMatt Macy } 506*eda14cbcSMatt Macy 507*eda14cbcSMatt Macy /* ARGSUSED */ 508*eda14cbcSMatt Macy static int 509*eda14cbcSMatt Macy dsl_prop_notify_all_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg) 510*eda14cbcSMatt Macy { 511*eda14cbcSMatt Macy dsl_dir_t *dd = ds->ds_dir; 512*eda14cbcSMatt Macy dsl_prop_record_t *pr; 513*eda14cbcSMatt Macy dsl_prop_cb_record_t *cbr; 514*eda14cbcSMatt Macy 515*eda14cbcSMatt Macy mutex_enter(&dd->dd_lock); 516*eda14cbcSMatt Macy for (pr = list_head(&dd->dd_props); 517*eda14cbcSMatt Macy pr; pr = list_next(&dd->dd_props, pr)) { 518*eda14cbcSMatt Macy for (cbr = list_head(&pr->pr_cbs); cbr; 519*eda14cbcSMatt Macy cbr = list_next(&pr->pr_cbs, cbr)) { 520*eda14cbcSMatt Macy uint64_t value; 521*eda14cbcSMatt Macy 522*eda14cbcSMatt Macy /* 523*eda14cbcSMatt Macy * Callback entries do not have holds on their 524*eda14cbcSMatt Macy * datasets so that datasets with registered 525*eda14cbcSMatt Macy * callbacks are still eligible for eviction. 526*eda14cbcSMatt Macy * Unlike operations to update properties on a 527*eda14cbcSMatt Macy * single dataset, we are performing a recursive 528*eda14cbcSMatt Macy * descent of related head datasets. The caller 529*eda14cbcSMatt Macy * of this function only has a dataset hold on 530*eda14cbcSMatt Macy * the passed in head dataset, not the snapshots 531*eda14cbcSMatt Macy * associated with this dataset. Without a hold, 532*eda14cbcSMatt Macy * the dataset pointer within callback records 533*eda14cbcSMatt Macy * for snapshots can be invalidated by eviction 534*eda14cbcSMatt Macy * at any time. 535*eda14cbcSMatt Macy * 536*eda14cbcSMatt Macy * Use dsl_dataset_try_add_ref() to verify 537*eda14cbcSMatt Macy * that the dataset for a snapshot has not 538*eda14cbcSMatt Macy * begun eviction processing and to prevent 539*eda14cbcSMatt Macy * eviction from occurring for the duration of 540*eda14cbcSMatt Macy * the callback. If the hold attempt fails, 541*eda14cbcSMatt Macy * this object is already being evicted and the 542*eda14cbcSMatt Macy * callback can be safely ignored. 543*eda14cbcSMatt Macy */ 544*eda14cbcSMatt Macy if (ds != cbr->cbr_ds && 545*eda14cbcSMatt Macy !dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG)) 546*eda14cbcSMatt Macy continue; 547*eda14cbcSMatt Macy 548*eda14cbcSMatt Macy if (dsl_prop_get_ds(cbr->cbr_ds, 549*eda14cbcSMatt Macy cbr->cbr_pr->pr_propname, sizeof (value), 1, 550*eda14cbcSMatt Macy &value, NULL) == 0) 551*eda14cbcSMatt Macy cbr->cbr_func(cbr->cbr_arg, value); 552*eda14cbcSMatt Macy 553*eda14cbcSMatt Macy if (ds != cbr->cbr_ds) 554*eda14cbcSMatt Macy dsl_dataset_rele(cbr->cbr_ds, FTAG); 555*eda14cbcSMatt Macy } 556*eda14cbcSMatt Macy } 557*eda14cbcSMatt Macy mutex_exit(&dd->dd_lock); 558*eda14cbcSMatt Macy 559*eda14cbcSMatt Macy return (0); 560*eda14cbcSMatt Macy } 561*eda14cbcSMatt Macy 562*eda14cbcSMatt Macy /* 563*eda14cbcSMatt Macy * Update all property values for ddobj & its descendants. This is used 564*eda14cbcSMatt Macy * when renaming the dir. 565*eda14cbcSMatt Macy */ 566*eda14cbcSMatt Macy void 567*eda14cbcSMatt Macy dsl_prop_notify_all(dsl_dir_t *dd) 568*eda14cbcSMatt Macy { 569*eda14cbcSMatt Macy dsl_pool_t *dp = dd->dd_pool; 570*eda14cbcSMatt Macy ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock)); 571*eda14cbcSMatt Macy (void) dmu_objset_find_dp(dp, dd->dd_object, dsl_prop_notify_all_cb, 572*eda14cbcSMatt Macy NULL, DS_FIND_CHILDREN); 573*eda14cbcSMatt Macy } 574*eda14cbcSMatt Macy 575*eda14cbcSMatt Macy static void 576*eda14cbcSMatt Macy dsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj, 577*eda14cbcSMatt Macy const char *propname, uint64_t value, int first) 578*eda14cbcSMatt Macy { 579*eda14cbcSMatt Macy dsl_dir_t *dd; 580*eda14cbcSMatt Macy dsl_prop_record_t *pr; 581*eda14cbcSMatt Macy dsl_prop_cb_record_t *cbr; 582*eda14cbcSMatt Macy objset_t *mos = dp->dp_meta_objset; 583*eda14cbcSMatt Macy zap_cursor_t zc; 584*eda14cbcSMatt Macy zap_attribute_t *za; 585*eda14cbcSMatt Macy int err; 586*eda14cbcSMatt Macy 587*eda14cbcSMatt Macy ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock)); 588*eda14cbcSMatt Macy err = dsl_dir_hold_obj(dp, ddobj, NULL, FTAG, &dd); 589*eda14cbcSMatt Macy if (err) 590*eda14cbcSMatt Macy return; 591*eda14cbcSMatt Macy 592*eda14cbcSMatt Macy if (!first) { 593*eda14cbcSMatt Macy /* 594*eda14cbcSMatt Macy * If the prop is set here, then this change is not 595*eda14cbcSMatt Macy * being inherited here or below; stop the recursion. 596*eda14cbcSMatt Macy */ 597*eda14cbcSMatt Macy err = zap_contains(mos, dsl_dir_phys(dd)->dd_props_zapobj, 598*eda14cbcSMatt Macy propname); 599*eda14cbcSMatt Macy if (err == 0) { 600*eda14cbcSMatt Macy dsl_dir_rele(dd, FTAG); 601*eda14cbcSMatt Macy return; 602*eda14cbcSMatt Macy } 603*eda14cbcSMatt Macy ASSERT3U(err, ==, ENOENT); 604*eda14cbcSMatt Macy } 605*eda14cbcSMatt Macy 606*eda14cbcSMatt Macy mutex_enter(&dd->dd_lock); 607*eda14cbcSMatt Macy pr = dsl_prop_record_find(dd, propname); 608*eda14cbcSMatt Macy if (pr != NULL) { 609*eda14cbcSMatt Macy for (cbr = list_head(&pr->pr_cbs); cbr; 610*eda14cbcSMatt Macy cbr = list_next(&pr->pr_cbs, cbr)) { 611*eda14cbcSMatt Macy uint64_t propobj; 612*eda14cbcSMatt Macy 613*eda14cbcSMatt Macy /* 614*eda14cbcSMatt Macy * cbr->cbr_ds may be invalidated due to eviction, 615*eda14cbcSMatt Macy * requiring the use of dsl_dataset_try_add_ref(). 616*eda14cbcSMatt Macy * See comment block in dsl_prop_notify_all_cb() 617*eda14cbcSMatt Macy * for details. 618*eda14cbcSMatt Macy */ 619*eda14cbcSMatt Macy if (!dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG)) 620*eda14cbcSMatt Macy continue; 621*eda14cbcSMatt Macy 622*eda14cbcSMatt Macy propobj = dsl_dataset_phys(cbr->cbr_ds)->ds_props_obj; 623*eda14cbcSMatt Macy 624*eda14cbcSMatt Macy /* 625*eda14cbcSMatt Macy * If the property is not set on this ds, then it is 626*eda14cbcSMatt Macy * inherited here; call the callback. 627*eda14cbcSMatt Macy */ 628*eda14cbcSMatt Macy if (propobj == 0 || 629*eda14cbcSMatt Macy zap_contains(mos, propobj, propname) != 0) 630*eda14cbcSMatt Macy cbr->cbr_func(cbr->cbr_arg, value); 631*eda14cbcSMatt Macy 632*eda14cbcSMatt Macy dsl_dataset_rele(cbr->cbr_ds, FTAG); 633*eda14cbcSMatt Macy } 634*eda14cbcSMatt Macy } 635*eda14cbcSMatt Macy mutex_exit(&dd->dd_lock); 636*eda14cbcSMatt Macy 637*eda14cbcSMatt Macy za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP); 638*eda14cbcSMatt Macy for (zap_cursor_init(&zc, mos, 639*eda14cbcSMatt Macy dsl_dir_phys(dd)->dd_child_dir_zapobj); 640*eda14cbcSMatt Macy zap_cursor_retrieve(&zc, za) == 0; 641*eda14cbcSMatt Macy zap_cursor_advance(&zc)) { 642*eda14cbcSMatt Macy dsl_prop_changed_notify(dp, za->za_first_integer, 643*eda14cbcSMatt Macy propname, value, FALSE); 644*eda14cbcSMatt Macy } 645*eda14cbcSMatt Macy kmem_free(za, sizeof (zap_attribute_t)); 646*eda14cbcSMatt Macy zap_cursor_fini(&zc); 647*eda14cbcSMatt Macy dsl_dir_rele(dd, FTAG); 648*eda14cbcSMatt Macy } 649*eda14cbcSMatt Macy 650*eda14cbcSMatt Macy void 651*eda14cbcSMatt Macy dsl_prop_set_sync_impl(dsl_dataset_t *ds, const char *propname, 652*eda14cbcSMatt Macy zprop_source_t source, int intsz, int numints, const void *value, 653*eda14cbcSMatt Macy dmu_tx_t *tx) 654*eda14cbcSMatt Macy { 655*eda14cbcSMatt Macy objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 656*eda14cbcSMatt Macy uint64_t zapobj, intval, dummy, count; 657*eda14cbcSMatt Macy int isint; 658*eda14cbcSMatt Macy char valbuf[32]; 659*eda14cbcSMatt Macy const char *valstr = NULL; 660*eda14cbcSMatt Macy char *inheritstr; 661*eda14cbcSMatt Macy char *recvdstr; 662*eda14cbcSMatt Macy char *tbuf = NULL; 663*eda14cbcSMatt Macy int err; 664*eda14cbcSMatt Macy uint64_t version = spa_version(ds->ds_dir->dd_pool->dp_spa); 665*eda14cbcSMatt Macy 666*eda14cbcSMatt Macy isint = (dodefault(zfs_name_to_prop(propname), 8, 1, &intval) == 0); 667*eda14cbcSMatt Macy 668*eda14cbcSMatt Macy if (ds->ds_is_snapshot) { 669*eda14cbcSMatt Macy ASSERT(version >= SPA_VERSION_SNAP_PROPS); 670*eda14cbcSMatt Macy if (dsl_dataset_phys(ds)->ds_props_obj == 0 && 671*eda14cbcSMatt Macy (source & ZPROP_SRC_NONE) == 0) { 672*eda14cbcSMatt Macy dmu_buf_will_dirty(ds->ds_dbuf, tx); 673*eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_props_obj = 674*eda14cbcSMatt Macy zap_create(mos, 675*eda14cbcSMatt Macy DMU_OT_DSL_PROPS, DMU_OT_NONE, 0, tx); 676*eda14cbcSMatt Macy } 677*eda14cbcSMatt Macy zapobj = dsl_dataset_phys(ds)->ds_props_obj; 678*eda14cbcSMatt Macy } else { 679*eda14cbcSMatt Macy zapobj = dsl_dir_phys(ds->ds_dir)->dd_props_zapobj; 680*eda14cbcSMatt Macy } 681*eda14cbcSMatt Macy 682*eda14cbcSMatt Macy /* If we are removing objects from a non-existent ZAP just return */ 683*eda14cbcSMatt Macy if (zapobj == 0) 684*eda14cbcSMatt Macy return; 685*eda14cbcSMatt Macy 686*eda14cbcSMatt Macy if (version < SPA_VERSION_RECVD_PROPS) { 687*eda14cbcSMatt Macy if (source & ZPROP_SRC_NONE) 688*eda14cbcSMatt Macy source = ZPROP_SRC_NONE; 689*eda14cbcSMatt Macy else if (source & ZPROP_SRC_RECEIVED) 690*eda14cbcSMatt Macy source = ZPROP_SRC_LOCAL; 691*eda14cbcSMatt Macy } 692*eda14cbcSMatt Macy 693*eda14cbcSMatt Macy inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX); 694*eda14cbcSMatt Macy recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX); 695*eda14cbcSMatt Macy 696*eda14cbcSMatt Macy switch ((int)source) { 697*eda14cbcSMatt Macy case ZPROP_SRC_NONE: 698*eda14cbcSMatt Macy /* 699*eda14cbcSMatt Macy * revert to received value, if any (inherit -S) 700*eda14cbcSMatt Macy * - remove propname 701*eda14cbcSMatt Macy * - remove propname$inherit 702*eda14cbcSMatt Macy */ 703*eda14cbcSMatt Macy err = zap_remove(mos, zapobj, propname, tx); 704*eda14cbcSMatt Macy ASSERT(err == 0 || err == ENOENT); 705*eda14cbcSMatt Macy err = zap_remove(mos, zapobj, inheritstr, tx); 706*eda14cbcSMatt Macy ASSERT(err == 0 || err == ENOENT); 707*eda14cbcSMatt Macy break; 708*eda14cbcSMatt Macy case ZPROP_SRC_LOCAL: 709*eda14cbcSMatt Macy /* 710*eda14cbcSMatt Macy * remove propname$inherit 711*eda14cbcSMatt Macy * set propname -> value 712*eda14cbcSMatt Macy */ 713*eda14cbcSMatt Macy err = zap_remove(mos, zapobj, inheritstr, tx); 714*eda14cbcSMatt Macy ASSERT(err == 0 || err == ENOENT); 715*eda14cbcSMatt Macy VERIFY0(zap_update(mos, zapobj, propname, 716*eda14cbcSMatt Macy intsz, numints, value, tx)); 717*eda14cbcSMatt Macy break; 718*eda14cbcSMatt Macy case ZPROP_SRC_INHERITED: 719*eda14cbcSMatt Macy /* 720*eda14cbcSMatt Macy * explicitly inherit 721*eda14cbcSMatt Macy * - remove propname 722*eda14cbcSMatt Macy * - set propname$inherit 723*eda14cbcSMatt Macy */ 724*eda14cbcSMatt Macy err = zap_remove(mos, zapobj, propname, tx); 725*eda14cbcSMatt Macy ASSERT(err == 0 || err == ENOENT); 726*eda14cbcSMatt Macy if (version >= SPA_VERSION_RECVD_PROPS && 727*eda14cbcSMatt Macy dsl_prop_get_int_ds(ds, ZPROP_HAS_RECVD, &dummy) == 0) { 728*eda14cbcSMatt Macy dummy = 0; 729*eda14cbcSMatt Macy VERIFY0(zap_update(mos, zapobj, inheritstr, 730*eda14cbcSMatt Macy 8, 1, &dummy, tx)); 731*eda14cbcSMatt Macy } 732*eda14cbcSMatt Macy break; 733*eda14cbcSMatt Macy case ZPROP_SRC_RECEIVED: 734*eda14cbcSMatt Macy /* 735*eda14cbcSMatt Macy * set propname$recvd -> value 736*eda14cbcSMatt Macy */ 737*eda14cbcSMatt Macy err = zap_update(mos, zapobj, recvdstr, 738*eda14cbcSMatt Macy intsz, numints, value, tx); 739*eda14cbcSMatt Macy ASSERT(err == 0); 740*eda14cbcSMatt Macy break; 741*eda14cbcSMatt Macy case (ZPROP_SRC_NONE | ZPROP_SRC_LOCAL | ZPROP_SRC_RECEIVED): 742*eda14cbcSMatt Macy /* 743*eda14cbcSMatt Macy * clear local and received settings 744*eda14cbcSMatt Macy * - remove propname 745*eda14cbcSMatt Macy * - remove propname$inherit 746*eda14cbcSMatt Macy * - remove propname$recvd 747*eda14cbcSMatt Macy */ 748*eda14cbcSMatt Macy err = zap_remove(mos, zapobj, propname, tx); 749*eda14cbcSMatt Macy ASSERT(err == 0 || err == ENOENT); 750*eda14cbcSMatt Macy err = zap_remove(mos, zapobj, inheritstr, tx); 751*eda14cbcSMatt Macy ASSERT(err == 0 || err == ENOENT); 752*eda14cbcSMatt Macy /* FALLTHRU */ 753*eda14cbcSMatt Macy case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED): 754*eda14cbcSMatt Macy /* 755*eda14cbcSMatt Macy * remove propname$recvd 756*eda14cbcSMatt Macy */ 757*eda14cbcSMatt Macy err = zap_remove(mos, zapobj, recvdstr, tx); 758*eda14cbcSMatt Macy ASSERT(err == 0 || err == ENOENT); 759*eda14cbcSMatt Macy break; 760*eda14cbcSMatt Macy default: 761*eda14cbcSMatt Macy cmn_err(CE_PANIC, "unexpected property source: %d", source); 762*eda14cbcSMatt Macy } 763*eda14cbcSMatt Macy 764*eda14cbcSMatt Macy kmem_strfree(inheritstr); 765*eda14cbcSMatt Macy kmem_strfree(recvdstr); 766*eda14cbcSMatt Macy 767*eda14cbcSMatt Macy /* 768*eda14cbcSMatt Macy * If we are left with an empty snap zap we can destroy it. 769*eda14cbcSMatt Macy * This will prevent unnecessary calls to zap_lookup() in 770*eda14cbcSMatt Macy * the "zfs list" and "zfs get" code paths. 771*eda14cbcSMatt Macy */ 772*eda14cbcSMatt Macy if (ds->ds_is_snapshot && 773*eda14cbcSMatt Macy zap_count(mos, zapobj, &count) == 0 && count == 0) { 774*eda14cbcSMatt Macy dmu_buf_will_dirty(ds->ds_dbuf, tx); 775*eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_props_obj = 0; 776*eda14cbcSMatt Macy zap_destroy(mos, zapobj, tx); 777*eda14cbcSMatt Macy } 778*eda14cbcSMatt Macy 779*eda14cbcSMatt Macy if (isint) { 780*eda14cbcSMatt Macy VERIFY0(dsl_prop_get_int_ds(ds, propname, &intval)); 781*eda14cbcSMatt Macy 782*eda14cbcSMatt Macy if (ds->ds_is_snapshot) { 783*eda14cbcSMatt Macy dsl_prop_cb_record_t *cbr; 784*eda14cbcSMatt Macy /* 785*eda14cbcSMatt Macy * It's a snapshot; nothing can inherit this 786*eda14cbcSMatt Macy * property, so just look for callbacks on this 787*eda14cbcSMatt Macy * ds here. 788*eda14cbcSMatt Macy */ 789*eda14cbcSMatt Macy mutex_enter(&ds->ds_dir->dd_lock); 790*eda14cbcSMatt Macy for (cbr = list_head(&ds->ds_prop_cbs); cbr; 791*eda14cbcSMatt Macy cbr = list_next(&ds->ds_prop_cbs, cbr)) { 792*eda14cbcSMatt Macy if (strcmp(cbr->cbr_pr->pr_propname, 793*eda14cbcSMatt Macy propname) == 0) 794*eda14cbcSMatt Macy cbr->cbr_func(cbr->cbr_arg, intval); 795*eda14cbcSMatt Macy } 796*eda14cbcSMatt Macy mutex_exit(&ds->ds_dir->dd_lock); 797*eda14cbcSMatt Macy } else { 798*eda14cbcSMatt Macy dsl_prop_changed_notify(ds->ds_dir->dd_pool, 799*eda14cbcSMatt Macy ds->ds_dir->dd_object, propname, intval, TRUE); 800*eda14cbcSMatt Macy } 801*eda14cbcSMatt Macy 802*eda14cbcSMatt Macy (void) snprintf(valbuf, sizeof (valbuf), 803*eda14cbcSMatt Macy "%lld", (longlong_t)intval); 804*eda14cbcSMatt Macy valstr = valbuf; 805*eda14cbcSMatt Macy } else { 806*eda14cbcSMatt Macy if (source == ZPROP_SRC_LOCAL) { 807*eda14cbcSMatt Macy valstr = value; 808*eda14cbcSMatt Macy } else { 809*eda14cbcSMatt Macy tbuf = kmem_alloc(ZAP_MAXVALUELEN, KM_SLEEP); 810*eda14cbcSMatt Macy if (dsl_prop_get_ds(ds, propname, 1, 811*eda14cbcSMatt Macy ZAP_MAXVALUELEN, tbuf, NULL) == 0) 812*eda14cbcSMatt Macy valstr = tbuf; 813*eda14cbcSMatt Macy } 814*eda14cbcSMatt Macy } 815*eda14cbcSMatt Macy 816*eda14cbcSMatt Macy spa_history_log_internal_ds(ds, (source == ZPROP_SRC_NONE || 817*eda14cbcSMatt Macy source == ZPROP_SRC_INHERITED) ? "inherit" : "set", tx, 818*eda14cbcSMatt Macy "%s=%s", propname, (valstr == NULL ? "" : valstr)); 819*eda14cbcSMatt Macy 820*eda14cbcSMatt Macy if (tbuf != NULL) 821*eda14cbcSMatt Macy kmem_free(tbuf, ZAP_MAXVALUELEN); 822*eda14cbcSMatt Macy } 823*eda14cbcSMatt Macy 824*eda14cbcSMatt Macy int 825*eda14cbcSMatt Macy dsl_prop_set_int(const char *dsname, const char *propname, 826*eda14cbcSMatt Macy zprop_source_t source, uint64_t value) 827*eda14cbcSMatt Macy { 828*eda14cbcSMatt Macy nvlist_t *nvl = fnvlist_alloc(); 829*eda14cbcSMatt Macy int error; 830*eda14cbcSMatt Macy 831*eda14cbcSMatt Macy fnvlist_add_uint64(nvl, propname, value); 832*eda14cbcSMatt Macy error = dsl_props_set(dsname, source, nvl); 833*eda14cbcSMatt Macy fnvlist_free(nvl); 834*eda14cbcSMatt Macy return (error); 835*eda14cbcSMatt Macy } 836*eda14cbcSMatt Macy 837*eda14cbcSMatt Macy int 838*eda14cbcSMatt Macy dsl_prop_set_string(const char *dsname, const char *propname, 839*eda14cbcSMatt Macy zprop_source_t source, const char *value) 840*eda14cbcSMatt Macy { 841*eda14cbcSMatt Macy nvlist_t *nvl = fnvlist_alloc(); 842*eda14cbcSMatt Macy int error; 843*eda14cbcSMatt Macy 844*eda14cbcSMatt Macy fnvlist_add_string(nvl, propname, value); 845*eda14cbcSMatt Macy error = dsl_props_set(dsname, source, nvl); 846*eda14cbcSMatt Macy fnvlist_free(nvl); 847*eda14cbcSMatt Macy return (error); 848*eda14cbcSMatt Macy } 849*eda14cbcSMatt Macy 850*eda14cbcSMatt Macy int 851*eda14cbcSMatt Macy dsl_prop_inherit(const char *dsname, const char *propname, 852*eda14cbcSMatt Macy zprop_source_t source) 853*eda14cbcSMatt Macy { 854*eda14cbcSMatt Macy nvlist_t *nvl = fnvlist_alloc(); 855*eda14cbcSMatt Macy int error; 856*eda14cbcSMatt Macy 857*eda14cbcSMatt Macy fnvlist_add_boolean(nvl, propname); 858*eda14cbcSMatt Macy error = dsl_props_set(dsname, source, nvl); 859*eda14cbcSMatt Macy fnvlist_free(nvl); 860*eda14cbcSMatt Macy return (error); 861*eda14cbcSMatt Macy } 862*eda14cbcSMatt Macy 863*eda14cbcSMatt Macy int 864*eda14cbcSMatt Macy dsl_props_set_check(void *arg, dmu_tx_t *tx) 865*eda14cbcSMatt Macy { 866*eda14cbcSMatt Macy dsl_props_set_arg_t *dpsa = arg; 867*eda14cbcSMatt Macy dsl_pool_t *dp = dmu_tx_pool(tx); 868*eda14cbcSMatt Macy dsl_dataset_t *ds; 869*eda14cbcSMatt Macy uint64_t version; 870*eda14cbcSMatt Macy nvpair_t *elem = NULL; 871*eda14cbcSMatt Macy int err; 872*eda14cbcSMatt Macy 873*eda14cbcSMatt Macy err = dsl_dataset_hold(dp, dpsa->dpsa_dsname, FTAG, &ds); 874*eda14cbcSMatt Macy if (err != 0) 875*eda14cbcSMatt Macy return (err); 876*eda14cbcSMatt Macy 877*eda14cbcSMatt Macy version = spa_version(ds->ds_dir->dd_pool->dp_spa); 878*eda14cbcSMatt Macy while ((elem = nvlist_next_nvpair(dpsa->dpsa_props, elem)) != NULL) { 879*eda14cbcSMatt Macy if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) { 880*eda14cbcSMatt Macy dsl_dataset_rele(ds, FTAG); 881*eda14cbcSMatt Macy return (SET_ERROR(ENAMETOOLONG)); 882*eda14cbcSMatt Macy } 883*eda14cbcSMatt Macy if (nvpair_type(elem) == DATA_TYPE_STRING) { 884*eda14cbcSMatt Macy char *valstr = fnvpair_value_string(elem); 885*eda14cbcSMatt Macy if (strlen(valstr) >= (version < 886*eda14cbcSMatt Macy SPA_VERSION_STMF_PROP ? 887*eda14cbcSMatt Macy ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) { 888*eda14cbcSMatt Macy dsl_dataset_rele(ds, FTAG); 889*eda14cbcSMatt Macy return (SET_ERROR(E2BIG)); 890*eda14cbcSMatt Macy } 891*eda14cbcSMatt Macy } 892*eda14cbcSMatt Macy } 893*eda14cbcSMatt Macy 894*eda14cbcSMatt Macy if (ds->ds_is_snapshot && version < SPA_VERSION_SNAP_PROPS) { 895*eda14cbcSMatt Macy dsl_dataset_rele(ds, FTAG); 896*eda14cbcSMatt Macy return (SET_ERROR(ENOTSUP)); 897*eda14cbcSMatt Macy } 898*eda14cbcSMatt Macy dsl_dataset_rele(ds, FTAG); 899*eda14cbcSMatt Macy return (0); 900*eda14cbcSMatt Macy } 901*eda14cbcSMatt Macy 902*eda14cbcSMatt Macy void 903*eda14cbcSMatt Macy dsl_props_set_sync_impl(dsl_dataset_t *ds, zprop_source_t source, 904*eda14cbcSMatt Macy nvlist_t *props, dmu_tx_t *tx) 905*eda14cbcSMatt Macy { 906*eda14cbcSMatt Macy nvpair_t *elem = NULL; 907*eda14cbcSMatt Macy 908*eda14cbcSMatt Macy while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 909*eda14cbcSMatt Macy nvpair_t *pair = elem; 910*eda14cbcSMatt Macy const char *name = nvpair_name(pair); 911*eda14cbcSMatt Macy 912*eda14cbcSMatt Macy if (nvpair_type(pair) == DATA_TYPE_NVLIST) { 913*eda14cbcSMatt Macy /* 914*eda14cbcSMatt Macy * This usually happens when we reuse the nvlist_t data 915*eda14cbcSMatt Macy * returned by the counterpart dsl_prop_get_all_impl(). 916*eda14cbcSMatt Macy * For instance we do this to restore the original 917*eda14cbcSMatt Macy * received properties when an error occurs in the 918*eda14cbcSMatt Macy * zfs_ioc_recv() codepath. 919*eda14cbcSMatt Macy */ 920*eda14cbcSMatt Macy nvlist_t *attrs = fnvpair_value_nvlist(pair); 921*eda14cbcSMatt Macy pair = fnvlist_lookup_nvpair(attrs, ZPROP_VALUE); 922*eda14cbcSMatt Macy } 923*eda14cbcSMatt Macy 924*eda14cbcSMatt Macy if (nvpair_type(pair) == DATA_TYPE_STRING) { 925*eda14cbcSMatt Macy const char *value = fnvpair_value_string(pair); 926*eda14cbcSMatt Macy dsl_prop_set_sync_impl(ds, name, 927*eda14cbcSMatt Macy source, 1, strlen(value) + 1, value, tx); 928*eda14cbcSMatt Macy } else if (nvpair_type(pair) == DATA_TYPE_UINT64) { 929*eda14cbcSMatt Macy uint64_t intval = fnvpair_value_uint64(pair); 930*eda14cbcSMatt Macy dsl_prop_set_sync_impl(ds, name, 931*eda14cbcSMatt Macy source, sizeof (intval), 1, &intval, tx); 932*eda14cbcSMatt Macy } else if (nvpair_type(pair) == DATA_TYPE_BOOLEAN) { 933*eda14cbcSMatt Macy dsl_prop_set_sync_impl(ds, name, 934*eda14cbcSMatt Macy source, 0, 0, NULL, tx); 935*eda14cbcSMatt Macy } else { 936*eda14cbcSMatt Macy panic("invalid nvpair type"); 937*eda14cbcSMatt Macy } 938*eda14cbcSMatt Macy } 939*eda14cbcSMatt Macy } 940*eda14cbcSMatt Macy 941*eda14cbcSMatt Macy void 942*eda14cbcSMatt Macy dsl_props_set_sync(void *arg, dmu_tx_t *tx) 943*eda14cbcSMatt Macy { 944*eda14cbcSMatt Macy dsl_props_set_arg_t *dpsa = arg; 945*eda14cbcSMatt Macy dsl_pool_t *dp = dmu_tx_pool(tx); 946*eda14cbcSMatt Macy dsl_dataset_t *ds; 947*eda14cbcSMatt Macy 948*eda14cbcSMatt Macy VERIFY0(dsl_dataset_hold(dp, dpsa->dpsa_dsname, FTAG, &ds)); 949*eda14cbcSMatt Macy dsl_props_set_sync_impl(ds, dpsa->dpsa_source, dpsa->dpsa_props, tx); 950*eda14cbcSMatt Macy dsl_dataset_rele(ds, FTAG); 951*eda14cbcSMatt Macy } 952*eda14cbcSMatt Macy 953*eda14cbcSMatt Macy /* 954*eda14cbcSMatt Macy * All-or-nothing; if any prop can't be set, nothing will be modified. 955*eda14cbcSMatt Macy */ 956*eda14cbcSMatt Macy int 957*eda14cbcSMatt Macy dsl_props_set(const char *dsname, zprop_source_t source, nvlist_t *props) 958*eda14cbcSMatt Macy { 959*eda14cbcSMatt Macy dsl_props_set_arg_t dpsa; 960*eda14cbcSMatt Macy int nblks = 0; 961*eda14cbcSMatt Macy 962*eda14cbcSMatt Macy dpsa.dpsa_dsname = dsname; 963*eda14cbcSMatt Macy dpsa.dpsa_source = source; 964*eda14cbcSMatt Macy dpsa.dpsa_props = props; 965*eda14cbcSMatt Macy 966*eda14cbcSMatt Macy /* 967*eda14cbcSMatt Macy * If the source includes NONE, then we will only be removing entries 968*eda14cbcSMatt Macy * from the ZAP object. In that case don't check for ENOSPC. 969*eda14cbcSMatt Macy */ 970*eda14cbcSMatt Macy if ((source & ZPROP_SRC_NONE) == 0) 971*eda14cbcSMatt Macy nblks = 2 * fnvlist_num_pairs(props); 972*eda14cbcSMatt Macy 973*eda14cbcSMatt Macy return (dsl_sync_task(dsname, dsl_props_set_check, dsl_props_set_sync, 974*eda14cbcSMatt Macy &dpsa, nblks, ZFS_SPACE_CHECK_RESERVED)); 975*eda14cbcSMatt Macy } 976*eda14cbcSMatt Macy 977*eda14cbcSMatt Macy typedef enum dsl_prop_getflags { 978*eda14cbcSMatt Macy DSL_PROP_GET_INHERITING = 0x1, /* searching parent of target ds */ 979*eda14cbcSMatt Macy DSL_PROP_GET_SNAPSHOT = 0x2, /* snapshot dataset */ 980*eda14cbcSMatt Macy DSL_PROP_GET_LOCAL = 0x4, /* local properties */ 981*eda14cbcSMatt Macy DSL_PROP_GET_RECEIVED = 0x8, /* received properties */ 982*eda14cbcSMatt Macy } dsl_prop_getflags_t; 983*eda14cbcSMatt Macy 984*eda14cbcSMatt Macy static int 985*eda14cbcSMatt Macy dsl_prop_get_all_impl(objset_t *mos, uint64_t propobj, 986*eda14cbcSMatt Macy const char *setpoint, dsl_prop_getflags_t flags, nvlist_t *nv) 987*eda14cbcSMatt Macy { 988*eda14cbcSMatt Macy zap_cursor_t zc; 989*eda14cbcSMatt Macy zap_attribute_t za; 990*eda14cbcSMatt Macy int err = 0; 991*eda14cbcSMatt Macy 992*eda14cbcSMatt Macy for (zap_cursor_init(&zc, mos, propobj); 993*eda14cbcSMatt Macy (err = zap_cursor_retrieve(&zc, &za)) == 0; 994*eda14cbcSMatt Macy zap_cursor_advance(&zc)) { 995*eda14cbcSMatt Macy nvlist_t *propval; 996*eda14cbcSMatt Macy zfs_prop_t prop; 997*eda14cbcSMatt Macy char buf[ZAP_MAXNAMELEN]; 998*eda14cbcSMatt Macy char *valstr; 999*eda14cbcSMatt Macy const char *suffix; 1000*eda14cbcSMatt Macy const char *propname; 1001*eda14cbcSMatt Macy const char *source; 1002*eda14cbcSMatt Macy 1003*eda14cbcSMatt Macy suffix = strchr(za.za_name, '$'); 1004*eda14cbcSMatt Macy 1005*eda14cbcSMatt Macy if (suffix == NULL) { 1006*eda14cbcSMatt Macy /* 1007*eda14cbcSMatt Macy * Skip local properties if we only want received 1008*eda14cbcSMatt Macy * properties. 1009*eda14cbcSMatt Macy */ 1010*eda14cbcSMatt Macy if (flags & DSL_PROP_GET_RECEIVED) 1011*eda14cbcSMatt Macy continue; 1012*eda14cbcSMatt Macy 1013*eda14cbcSMatt Macy propname = za.za_name; 1014*eda14cbcSMatt Macy source = setpoint; 1015*eda14cbcSMatt Macy } else if (strcmp(suffix, ZPROP_INHERIT_SUFFIX) == 0) { 1016*eda14cbcSMatt Macy /* Skip explicitly inherited entries. */ 1017*eda14cbcSMatt Macy continue; 1018*eda14cbcSMatt Macy } else if (strcmp(suffix, ZPROP_RECVD_SUFFIX) == 0) { 1019*eda14cbcSMatt Macy if (flags & DSL_PROP_GET_LOCAL) 1020*eda14cbcSMatt Macy continue; 1021*eda14cbcSMatt Macy 1022*eda14cbcSMatt Macy (void) strncpy(buf, za.za_name, (suffix - za.za_name)); 1023*eda14cbcSMatt Macy buf[suffix - za.za_name] = '\0'; 1024*eda14cbcSMatt Macy propname = buf; 1025*eda14cbcSMatt Macy 1026*eda14cbcSMatt Macy if (!(flags & DSL_PROP_GET_RECEIVED)) { 1027*eda14cbcSMatt Macy /* Skip if locally overridden. */ 1028*eda14cbcSMatt Macy err = zap_contains(mos, propobj, propname); 1029*eda14cbcSMatt Macy if (err == 0) 1030*eda14cbcSMatt Macy continue; 1031*eda14cbcSMatt Macy if (err != ENOENT) 1032*eda14cbcSMatt Macy break; 1033*eda14cbcSMatt Macy 1034*eda14cbcSMatt Macy /* Skip if explicitly inherited. */ 1035*eda14cbcSMatt Macy valstr = kmem_asprintf("%s%s", propname, 1036*eda14cbcSMatt Macy ZPROP_INHERIT_SUFFIX); 1037*eda14cbcSMatt Macy err = zap_contains(mos, propobj, valstr); 1038*eda14cbcSMatt Macy kmem_strfree(valstr); 1039*eda14cbcSMatt Macy if (err == 0) 1040*eda14cbcSMatt Macy continue; 1041*eda14cbcSMatt Macy if (err != ENOENT) 1042*eda14cbcSMatt Macy break; 1043*eda14cbcSMatt Macy } 1044*eda14cbcSMatt Macy 1045*eda14cbcSMatt Macy source = ((flags & DSL_PROP_GET_INHERITING) ? 1046*eda14cbcSMatt Macy setpoint : ZPROP_SOURCE_VAL_RECVD); 1047*eda14cbcSMatt Macy } else { 1048*eda14cbcSMatt Macy /* 1049*eda14cbcSMatt Macy * For backward compatibility, skip suffixes we don't 1050*eda14cbcSMatt Macy * recognize. 1051*eda14cbcSMatt Macy */ 1052*eda14cbcSMatt Macy continue; 1053*eda14cbcSMatt Macy } 1054*eda14cbcSMatt Macy 1055*eda14cbcSMatt Macy prop = zfs_name_to_prop(propname); 1056*eda14cbcSMatt Macy 1057*eda14cbcSMatt Macy /* Skip non-inheritable properties. */ 1058*eda14cbcSMatt Macy if ((flags & DSL_PROP_GET_INHERITING) && prop != ZPROP_INVAL && 1059*eda14cbcSMatt Macy !zfs_prop_inheritable(prop)) 1060*eda14cbcSMatt Macy continue; 1061*eda14cbcSMatt Macy 1062*eda14cbcSMatt Macy /* Skip properties not valid for this type. */ 1063*eda14cbcSMatt Macy if ((flags & DSL_PROP_GET_SNAPSHOT) && prop != ZPROP_INVAL && 1064*eda14cbcSMatt Macy !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT, B_FALSE)) 1065*eda14cbcSMatt Macy continue; 1066*eda14cbcSMatt Macy 1067*eda14cbcSMatt Macy /* Skip properties already defined. */ 1068*eda14cbcSMatt Macy if (nvlist_exists(nv, propname)) 1069*eda14cbcSMatt Macy continue; 1070*eda14cbcSMatt Macy 1071*eda14cbcSMatt Macy VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1072*eda14cbcSMatt Macy if (za.za_integer_length == 1) { 1073*eda14cbcSMatt Macy /* 1074*eda14cbcSMatt Macy * String property 1075*eda14cbcSMatt Macy */ 1076*eda14cbcSMatt Macy char *tmp = kmem_alloc(za.za_num_integers, 1077*eda14cbcSMatt Macy KM_SLEEP); 1078*eda14cbcSMatt Macy err = zap_lookup(mos, propobj, 1079*eda14cbcSMatt Macy za.za_name, 1, za.za_num_integers, tmp); 1080*eda14cbcSMatt Macy if (err != 0) { 1081*eda14cbcSMatt Macy kmem_free(tmp, za.za_num_integers); 1082*eda14cbcSMatt Macy break; 1083*eda14cbcSMatt Macy } 1084*eda14cbcSMatt Macy VERIFY(nvlist_add_string(propval, ZPROP_VALUE, 1085*eda14cbcSMatt Macy tmp) == 0); 1086*eda14cbcSMatt Macy kmem_free(tmp, za.za_num_integers); 1087*eda14cbcSMatt Macy } else { 1088*eda14cbcSMatt Macy /* 1089*eda14cbcSMatt Macy * Integer property 1090*eda14cbcSMatt Macy */ 1091*eda14cbcSMatt Macy ASSERT(za.za_integer_length == 8); 1092*eda14cbcSMatt Macy (void) nvlist_add_uint64(propval, ZPROP_VALUE, 1093*eda14cbcSMatt Macy za.za_first_integer); 1094*eda14cbcSMatt Macy } 1095*eda14cbcSMatt Macy 1096*eda14cbcSMatt Macy VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, source) == 0); 1097*eda14cbcSMatt Macy VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0); 1098*eda14cbcSMatt Macy nvlist_free(propval); 1099*eda14cbcSMatt Macy } 1100*eda14cbcSMatt Macy zap_cursor_fini(&zc); 1101*eda14cbcSMatt Macy if (err == ENOENT) 1102*eda14cbcSMatt Macy err = 0; 1103*eda14cbcSMatt Macy return (err); 1104*eda14cbcSMatt Macy } 1105*eda14cbcSMatt Macy 1106*eda14cbcSMatt Macy /* 1107*eda14cbcSMatt Macy * Iterate over all properties for this dataset and return them in an nvlist. 1108*eda14cbcSMatt Macy */ 1109*eda14cbcSMatt Macy static int 1110*eda14cbcSMatt Macy dsl_prop_get_all_ds(dsl_dataset_t *ds, nvlist_t **nvp, 1111*eda14cbcSMatt Macy dsl_prop_getflags_t flags) 1112*eda14cbcSMatt Macy { 1113*eda14cbcSMatt Macy dsl_dir_t *dd = ds->ds_dir; 1114*eda14cbcSMatt Macy dsl_pool_t *dp = dd->dd_pool; 1115*eda14cbcSMatt Macy objset_t *mos = dp->dp_meta_objset; 1116*eda14cbcSMatt Macy int err = 0; 1117*eda14cbcSMatt Macy char setpoint[ZFS_MAX_DATASET_NAME_LEN]; 1118*eda14cbcSMatt Macy 1119*eda14cbcSMatt Macy VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1120*eda14cbcSMatt Macy 1121*eda14cbcSMatt Macy if (ds->ds_is_snapshot) 1122*eda14cbcSMatt Macy flags |= DSL_PROP_GET_SNAPSHOT; 1123*eda14cbcSMatt Macy 1124*eda14cbcSMatt Macy ASSERT(dsl_pool_config_held(dp)); 1125*eda14cbcSMatt Macy 1126*eda14cbcSMatt Macy if (dsl_dataset_phys(ds)->ds_props_obj != 0) { 1127*eda14cbcSMatt Macy ASSERT(flags & DSL_PROP_GET_SNAPSHOT); 1128*eda14cbcSMatt Macy dsl_dataset_name(ds, setpoint); 1129*eda14cbcSMatt Macy err = dsl_prop_get_all_impl(mos, 1130*eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_props_obj, setpoint, flags, *nvp); 1131*eda14cbcSMatt Macy if (err) 1132*eda14cbcSMatt Macy goto out; 1133*eda14cbcSMatt Macy } 1134*eda14cbcSMatt Macy 1135*eda14cbcSMatt Macy for (; dd != NULL; dd = dd->dd_parent) { 1136*eda14cbcSMatt Macy if (dd != ds->ds_dir || (flags & DSL_PROP_GET_SNAPSHOT)) { 1137*eda14cbcSMatt Macy if (flags & (DSL_PROP_GET_LOCAL | 1138*eda14cbcSMatt Macy DSL_PROP_GET_RECEIVED)) 1139*eda14cbcSMatt Macy break; 1140*eda14cbcSMatt Macy flags |= DSL_PROP_GET_INHERITING; 1141*eda14cbcSMatt Macy } 1142*eda14cbcSMatt Macy dsl_dir_name(dd, setpoint); 1143*eda14cbcSMatt Macy err = dsl_prop_get_all_impl(mos, 1144*eda14cbcSMatt Macy dsl_dir_phys(dd)->dd_props_zapobj, setpoint, flags, *nvp); 1145*eda14cbcSMatt Macy if (err) 1146*eda14cbcSMatt Macy break; 1147*eda14cbcSMatt Macy } 1148*eda14cbcSMatt Macy 1149*eda14cbcSMatt Macy out: 1150*eda14cbcSMatt Macy if (err) { 1151*eda14cbcSMatt Macy nvlist_free(*nvp); 1152*eda14cbcSMatt Macy *nvp = NULL; 1153*eda14cbcSMatt Macy } 1154*eda14cbcSMatt Macy return (err); 1155*eda14cbcSMatt Macy } 1156*eda14cbcSMatt Macy 1157*eda14cbcSMatt Macy boolean_t 1158*eda14cbcSMatt Macy dsl_prop_get_hasrecvd(const char *dsname) 1159*eda14cbcSMatt Macy { 1160*eda14cbcSMatt Macy uint64_t dummy; 1161*eda14cbcSMatt Macy 1162*eda14cbcSMatt Macy return (0 == 1163*eda14cbcSMatt Macy dsl_prop_get_integer(dsname, ZPROP_HAS_RECVD, &dummy, NULL)); 1164*eda14cbcSMatt Macy } 1165*eda14cbcSMatt Macy 1166*eda14cbcSMatt Macy static int 1167*eda14cbcSMatt Macy dsl_prop_set_hasrecvd_impl(const char *dsname, zprop_source_t source) 1168*eda14cbcSMatt Macy { 1169*eda14cbcSMatt Macy uint64_t version; 1170*eda14cbcSMatt Macy spa_t *spa; 1171*eda14cbcSMatt Macy int error = 0; 1172*eda14cbcSMatt Macy 1173*eda14cbcSMatt Macy VERIFY0(spa_open(dsname, &spa, FTAG)); 1174*eda14cbcSMatt Macy version = spa_version(spa); 1175*eda14cbcSMatt Macy spa_close(spa, FTAG); 1176*eda14cbcSMatt Macy 1177*eda14cbcSMatt Macy if (version >= SPA_VERSION_RECVD_PROPS) 1178*eda14cbcSMatt Macy error = dsl_prop_set_int(dsname, ZPROP_HAS_RECVD, source, 0); 1179*eda14cbcSMatt Macy return (error); 1180*eda14cbcSMatt Macy } 1181*eda14cbcSMatt Macy 1182*eda14cbcSMatt Macy /* 1183*eda14cbcSMatt Macy * Call after successfully receiving properties to ensure that only the first 1184*eda14cbcSMatt Macy * receive on or after SPA_VERSION_RECVD_PROPS blows away local properties. 1185*eda14cbcSMatt Macy */ 1186*eda14cbcSMatt Macy int 1187*eda14cbcSMatt Macy dsl_prop_set_hasrecvd(const char *dsname) 1188*eda14cbcSMatt Macy { 1189*eda14cbcSMatt Macy int error = 0; 1190*eda14cbcSMatt Macy if (!dsl_prop_get_hasrecvd(dsname)) 1191*eda14cbcSMatt Macy error = dsl_prop_set_hasrecvd_impl(dsname, ZPROP_SRC_LOCAL); 1192*eda14cbcSMatt Macy return (error); 1193*eda14cbcSMatt Macy } 1194*eda14cbcSMatt Macy 1195*eda14cbcSMatt Macy void 1196*eda14cbcSMatt Macy dsl_prop_unset_hasrecvd(const char *dsname) 1197*eda14cbcSMatt Macy { 1198*eda14cbcSMatt Macy VERIFY0(dsl_prop_set_hasrecvd_impl(dsname, ZPROP_SRC_NONE)); 1199*eda14cbcSMatt Macy } 1200*eda14cbcSMatt Macy 1201*eda14cbcSMatt Macy int 1202*eda14cbcSMatt Macy dsl_prop_get_all(objset_t *os, nvlist_t **nvp) 1203*eda14cbcSMatt Macy { 1204*eda14cbcSMatt Macy return (dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, 0)); 1205*eda14cbcSMatt Macy } 1206*eda14cbcSMatt Macy 1207*eda14cbcSMatt Macy int 1208*eda14cbcSMatt Macy dsl_prop_get_received(const char *dsname, nvlist_t **nvp) 1209*eda14cbcSMatt Macy { 1210*eda14cbcSMatt Macy objset_t *os; 1211*eda14cbcSMatt Macy int error; 1212*eda14cbcSMatt Macy 1213*eda14cbcSMatt Macy /* 1214*eda14cbcSMatt Macy * Received properties are not distinguishable from local properties 1215*eda14cbcSMatt Macy * until the dataset has received properties on or after 1216*eda14cbcSMatt Macy * SPA_VERSION_RECVD_PROPS. 1217*eda14cbcSMatt Macy */ 1218*eda14cbcSMatt Macy dsl_prop_getflags_t flags = (dsl_prop_get_hasrecvd(dsname) ? 1219*eda14cbcSMatt Macy DSL_PROP_GET_RECEIVED : DSL_PROP_GET_LOCAL); 1220*eda14cbcSMatt Macy 1221*eda14cbcSMatt Macy error = dmu_objset_hold(dsname, FTAG, &os); 1222*eda14cbcSMatt Macy if (error != 0) 1223*eda14cbcSMatt Macy return (error); 1224*eda14cbcSMatt Macy error = dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, flags); 1225*eda14cbcSMatt Macy dmu_objset_rele(os, FTAG); 1226*eda14cbcSMatt Macy return (error); 1227*eda14cbcSMatt Macy } 1228*eda14cbcSMatt Macy 1229*eda14cbcSMatt Macy void 1230*eda14cbcSMatt Macy dsl_prop_nvlist_add_uint64(nvlist_t *nv, zfs_prop_t prop, uint64_t value) 1231*eda14cbcSMatt Macy { 1232*eda14cbcSMatt Macy nvlist_t *propval; 1233*eda14cbcSMatt Macy const char *propname = zfs_prop_to_name(prop); 1234*eda14cbcSMatt Macy uint64_t default_value; 1235*eda14cbcSMatt Macy 1236*eda14cbcSMatt Macy if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) { 1237*eda14cbcSMatt Macy VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0); 1238*eda14cbcSMatt Macy return; 1239*eda14cbcSMatt Macy } 1240*eda14cbcSMatt Macy 1241*eda14cbcSMatt Macy VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1242*eda14cbcSMatt Macy VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0); 1243*eda14cbcSMatt Macy /* Indicate the default source if we can. */ 1244*eda14cbcSMatt Macy if (dodefault(prop, 8, 1, &default_value) == 0 && 1245*eda14cbcSMatt Macy value == default_value) { 1246*eda14cbcSMatt Macy VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, "") == 0); 1247*eda14cbcSMatt Macy } 1248*eda14cbcSMatt Macy VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0); 1249*eda14cbcSMatt Macy nvlist_free(propval); 1250*eda14cbcSMatt Macy } 1251*eda14cbcSMatt Macy 1252*eda14cbcSMatt Macy void 1253*eda14cbcSMatt Macy dsl_prop_nvlist_add_string(nvlist_t *nv, zfs_prop_t prop, const char *value) 1254*eda14cbcSMatt Macy { 1255*eda14cbcSMatt Macy nvlist_t *propval; 1256*eda14cbcSMatt Macy const char *propname = zfs_prop_to_name(prop); 1257*eda14cbcSMatt Macy 1258*eda14cbcSMatt Macy if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) { 1259*eda14cbcSMatt Macy VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0); 1260*eda14cbcSMatt Macy return; 1261*eda14cbcSMatt Macy } 1262*eda14cbcSMatt Macy 1263*eda14cbcSMatt Macy VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1264*eda14cbcSMatt Macy VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0); 1265*eda14cbcSMatt Macy VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0); 1266*eda14cbcSMatt Macy nvlist_free(propval); 1267*eda14cbcSMatt Macy } 1268*eda14cbcSMatt Macy 1269*eda14cbcSMatt Macy #if defined(_KERNEL) 1270*eda14cbcSMatt Macy EXPORT_SYMBOL(dsl_prop_register); 1271*eda14cbcSMatt Macy EXPORT_SYMBOL(dsl_prop_unregister); 1272*eda14cbcSMatt Macy EXPORT_SYMBOL(dsl_prop_unregister_all); 1273*eda14cbcSMatt Macy EXPORT_SYMBOL(dsl_prop_get); 1274*eda14cbcSMatt Macy EXPORT_SYMBOL(dsl_prop_get_integer); 1275*eda14cbcSMatt Macy EXPORT_SYMBOL(dsl_prop_get_all); 1276*eda14cbcSMatt Macy EXPORT_SYMBOL(dsl_prop_get_received); 1277*eda14cbcSMatt Macy EXPORT_SYMBOL(dsl_prop_get_ds); 1278*eda14cbcSMatt Macy EXPORT_SYMBOL(dsl_prop_get_int_ds); 1279*eda14cbcSMatt Macy EXPORT_SYMBOL(dsl_prop_get_dd); 1280*eda14cbcSMatt Macy EXPORT_SYMBOL(dsl_props_set); 1281*eda14cbcSMatt Macy EXPORT_SYMBOL(dsl_prop_set_int); 1282*eda14cbcSMatt Macy EXPORT_SYMBOL(dsl_prop_set_string); 1283*eda14cbcSMatt Macy EXPORT_SYMBOL(dsl_prop_inherit); 1284*eda14cbcSMatt Macy EXPORT_SYMBOL(dsl_prop_predict); 1285*eda14cbcSMatt Macy EXPORT_SYMBOL(dsl_prop_nvlist_add_uint64); 1286*eda14cbcSMatt Macy EXPORT_SYMBOL(dsl_prop_nvlist_add_string); 1287*eda14cbcSMatt Macy #endif 1288