int dsl_prop_get_ds(dsl_dataset_t *ds, const char *propname, int intsz, int numints, void *buf, char *setpoint) { zfs_prop_t prop = zfs_name_to_prop(propname); boolean_t inheritable; boolean_t snapshot; uint64_t zapobj; ASSERT(dsl_pool_config_held(ds->ds_dir->dd_pool)); inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop)); snapshot = (ds->ds_phys != NULL && dsl_dataset_is_snapshot(ds)); zapobj = (ds->ds_phys == NULL ? 0 : ds->ds_phys->ds_props_obj); if (zapobj != 0) { objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; int err; ASSERT(snapshot); /* Check for a local value. */ err = zap_lookup(mos, zapobj, propname, intsz, numints, buf); if (err != ENOENT) { if (setpoint != NULL && err == 0) dsl_dataset_name(ds, setpoint); return (err); } /* * Skip the check for a received value if there is an explicit * inheritance entry. */ if (inheritable) { char *inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX); err = zap_contains(mos, zapobj, inheritstr); strfree(inheritstr); if (err != 0 && err != ENOENT) return (err); } if (err == ENOENT) { /* Check for a received value. */ char *recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX); err = zap_lookup(mos, zapobj, recvdstr, intsz, numints, buf); strfree(recvdstr); if (err != ENOENT) { if (setpoint != NULL && err == 0) (void) strcpy(setpoint, ZPROP_SOURCE_VAL_RECVD); return (err); } } } return (dsl_prop_get_dd(ds->ds_dir, propname, intsz, numints, buf, setpoint, snapshot)); }
void dsl_prop_check_prediction(dsl_dir_t *dd, dsl_prop_setarg_t *psa) { zfs_prop_t prop = zfs_name_to_prop(psa->psa_name); uint64_t intval; char setpoint[MAXNAMELEN]; uint64_t version = spa_version(dd->dd_pool->dp_spa); int err; if (version < SPA_VERSION_RECVD_PROPS) { switch (prop) { case ZFS_PROP_QUOTA: case ZFS_PROP_RESERVATION: return; default: break; } } err = dsl_prop_get_dd(dd, psa->psa_name, 8, 1, &intval, setpoint, B_FALSE); if (err == 0 && intval != psa->psa_effective_value) { cmn_err(CE_PANIC, "%s property, source: %x, " "predicted effective value: %llu, " "actual effective value: %llu (setpoint: %s)", psa->psa_name, psa->psa_source, (unsigned long long)psa->psa_effective_value, (unsigned long long)intval, setpoint); } }
int dsl_prop_get_ds(dsl_dataset_t *ds, const char *propname, int intsz, int numint, void *buf, char *setpoint) { ASSERT(RW_LOCK_HELD(&ds->ds_dir->dd_pool->dp_config_rwlock)); if (ds->ds_phys->ds_props_obj) { int err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset, ds->ds_phys->ds_props_obj, propname, intsz, numint, buf); if (err != ENOENT) { if (setpoint) dsl_dataset_name(ds, setpoint); return (err); } } return (dsl_prop_get_dd(ds->ds_dir, propname, intsz, numint, buf, setpoint)); }
/* * Check if user has requested permission. */ int dsl_deleg_access(const char *dsname, const char *perm, cred_t *cr) { dsl_dataset_t *ds; dsl_dir_t *dd; dsl_pool_t *dp; void *cookie; int error; char checkflag; objset_t *mos; avl_tree_t permsets; perm_set_t *setnode; error = dsl_dataset_hold(dsname, FTAG, &ds); if (error) return (error); dp = ds->ds_dir->dd_pool; mos = dp->dp_meta_objset; if (dsl_delegation_on(mos) == B_FALSE) { dsl_dataset_rele(ds, FTAG); return (ECANCELED); } if (spa_version(dmu_objset_spa(dp->dp_meta_objset)) < SPA_VERSION_DELEGATED_PERMS) { dsl_dataset_rele(ds, FTAG); return (EPERM); } if (dsl_dataset_is_snapshot(ds)) { /* * Snapshots are treated as descendents only, * local permissions do not apply. */ checkflag = ZFS_DELEG_DESCENDENT; } else { checkflag = ZFS_DELEG_LOCAL; } avl_create(&permsets, perm_set_compare, sizeof (perm_set_t), offsetof(perm_set_t, p_node)); rw_enter(&dp->dp_config_rwlock, RW_READER); for (dd = ds->ds_dir; dd != NULL; dd = dd->dd_parent, checkflag = ZFS_DELEG_DESCENDENT) { uint64_t zapobj; boolean_t expanded; /* * If not in global zone then make sure * the zoned property is set */ if (!INGLOBALZONE(curproc)) { uint64_t zoned; if (dsl_prop_get_dd(dd, zfs_prop_to_name(ZFS_PROP_ZONED), 8, 1, &zoned, NULL) != 0) break; if (!zoned) break; } zapobj = dd->dd_phys->dd_deleg_zapobj; if (zapobj == 0) continue; dsl_load_user_sets(mos, zapobj, &permsets, checkflag, cr); again: expanded = B_FALSE; for (setnode = avl_first(&permsets); setnode; setnode = AVL_NEXT(&permsets, setnode)) { if (setnode->p_matched == B_TRUE) continue; /* See if this set directly grants this permission */ error = dsl_check_access(mos, zapobj, ZFS_DELEG_NAMED_SET, 0, setnode->p_setname, perm); if (error == 0) goto success; if (error == EPERM) setnode->p_matched = B_TRUE; /* See if this set includes other sets */ error = dsl_load_sets(mos, zapobj, ZFS_DELEG_NAMED_SET_SETS, 0, setnode->p_setname, &permsets); if (error == 0) setnode->p_matched = expanded = B_TRUE; } /* * If we expanded any sets, that will define more sets, * which we need to check. */ if (expanded) goto again; error = dsl_check_user_access(mos, zapobj, perm, checkflag, cr); if (error == 0) goto success; } error = EPERM; success: rw_exit(&dp->dp_config_rwlock); dsl_dataset_rele(ds, FTAG); cookie = NULL; while ((setnode = avl_destroy_nodes(&permsets, &cookie)) != NULL) kmem_free(setnode, sizeof (perm_set_t)); return (error); }