summaryrefslogtreecommitdiffstats
path: root/module/zfs/dsl_dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'module/zfs/dsl_dir.c')
-rw-r--r--module/zfs/dsl_dir.c29
1 files changed, 20 insertions, 9 deletions
diff --git a/module/zfs/dsl_dir.c b/module/zfs/dsl_dir.c
index 977600116..da6103b4b 100644
--- a/module/zfs/dsl_dir.c
+++ b/module/zfs/dsl_dir.c
@@ -749,7 +749,8 @@ typedef enum {
} enforce_res_t;
static enforce_res_t
-dsl_enforce_ds_ss_limits(dsl_dir_t *dd, zfs_prop_t prop, cred_t *cr)
+dsl_enforce_ds_ss_limits(dsl_dir_t *dd, zfs_prop_t prop,
+ cred_t *cr, proc_t *proc)
{
enforce_res_t enforce = ENFORCE_ALWAYS;
uint64_t obj;
@@ -764,7 +765,13 @@ dsl_enforce_ds_ss_limits(dsl_dir_t *dd, zfs_prop_t prop, cred_t *cr)
if (crgetzoneid(cr) != GLOBAL_ZONEID)
return (ENFORCE_ALWAYS);
- if (secpolicy_zfs(cr) == 0)
+ /*
+ * We are checking the saved credentials of the user process, which is
+ * not the current process. Note that we can't use secpolicy_zfs(),
+ * because it only works if the cred is that of the current process (on
+ * Linux).
+ */
+ if (secpolicy_zfs_proc(cr, proc) == 0)
return (ENFORCE_NEVER);
#endif
@@ -799,7 +806,7 @@ dsl_enforce_ds_ss_limits(dsl_dir_t *dd, zfs_prop_t prop, cred_t *cr)
*/
int
dsl_fs_ss_limit_check(dsl_dir_t *dd, uint64_t delta, zfs_prop_t prop,
- dsl_dir_t *ancestor, cred_t *cr)
+ dsl_dir_t *ancestor, cred_t *cr, proc_t *proc)
{
objset_t *os = dd->dd_pool->dp_meta_objset;
uint64_t limit, count;
@@ -819,7 +826,7 @@ dsl_fs_ss_limit_check(dsl_dir_t *dd, uint64_t delta, zfs_prop_t prop,
* are allowed to change the limit on the current dataset, but there
* is another limit in the tree above.
*/
- enforce = dsl_enforce_ds_ss_limits(dd, prop, cr);
+ enforce = dsl_enforce_ds_ss_limits(dd, prop, cr, proc);
if (enforce == ENFORCE_NEVER)
return (0);
@@ -871,7 +878,7 @@ dsl_fs_ss_limit_check(dsl_dir_t *dd, uint64_t delta, zfs_prop_t prop,
if (dd->dd_parent != NULL)
err = dsl_fs_ss_limit_check(dd->dd_parent, delta, prop,
- ancestor, cr);
+ ancestor, cr, proc);
return (err);
}
@@ -1840,6 +1847,7 @@ typedef struct dsl_dir_rename_arg {
const char *ddra_oldname;
const char *ddra_newname;
cred_t *ddra_cred;
+ proc_t *ddra_proc;
} dsl_dir_rename_arg_t;
typedef struct dsl_valid_rename_arg {
@@ -2018,7 +2026,8 @@ dsl_dir_rename_check(void *arg, dmu_tx_t *tx)
}
error = dsl_dir_transfer_possible(dd->dd_parent,
- newparent, fs_cnt, ss_cnt, myspace, ddra->ddra_cred);
+ newparent, fs_cnt, ss_cnt, myspace,
+ ddra->ddra_cred, ddra->ddra_proc);
if (error != 0) {
dsl_dir_rele(newparent, FTAG);
dsl_dir_rele(dd, FTAG);
@@ -2138,6 +2147,7 @@ dsl_dir_rename(const char *oldname, const char *newname)
ddra.ddra_oldname = oldname;
ddra.ddra_newname = newname;
ddra.ddra_cred = CRED();
+ ddra.ddra_proc = curproc;
return (dsl_sync_task(oldname,
dsl_dir_rename_check, dsl_dir_rename_sync, &ddra,
@@ -2146,7 +2156,8 @@ dsl_dir_rename(const char *oldname, const char *newname)
int
dsl_dir_transfer_possible(dsl_dir_t *sdd, dsl_dir_t *tdd,
- uint64_t fs_cnt, uint64_t ss_cnt, uint64_t space, cred_t *cr)
+ uint64_t fs_cnt, uint64_t ss_cnt, uint64_t space,
+ cred_t *cr, proc_t *proc)
{
dsl_dir_t *ancestor;
int64_t adelta;
@@ -2160,11 +2171,11 @@ dsl_dir_transfer_possible(dsl_dir_t *sdd, dsl_dir_t *tdd,
return (SET_ERROR(ENOSPC));
err = dsl_fs_ss_limit_check(tdd, fs_cnt, ZFS_PROP_FILESYSTEM_LIMIT,
- ancestor, cr);
+ ancestor, cr, proc);
if (err != 0)
return (err);
err = dsl_fs_ss_limit_check(tdd, ss_cnt, ZFS_PROP_SNAPSHOT_LIMIT,
- ancestor, cr);
+ ancestor, cr, proc);
if (err != 0)
return (err);