int ma_lmv_size;
int ma_default_lmv_size;
int ma_acl_size;
+ int ma_enable_chprojid_gid;
};
/** Additional parameters for create */
RETURN(rc);
}
+
+static bool is_project_state_change(const struct lu_attr *oattr,
+ struct lu_attr *la)
+{
+ if (la->la_valid & LA_PROJID &&
+ oattr->la_projid != la->la_projid)
+ return true;
+
+ if ((la->la_valid & LA_FLAGS) &&
+ (la->la_flags & LUSTRE_PROJINHERIT_FL) !=
+ (oattr->la_flags & LUSTRE_PROJINHERIT_FL))
+ return true;
+
+ return false;
+}
+
/*
* This gives the same functionality as the code between
* sys_chmod and inode_setattr
*/
static int mdd_fix_attr(const struct lu_env *env, struct mdd_object *obj,
const struct lu_attr *oattr, struct lu_attr *la,
- const unsigned long flags)
+ const struct md_attr *ma)
{
struct lu_ucred *uc;
int rc = 0;
+ const unsigned long flags = ma->ma_attr_flags;
+
ENTRY;
if (!la->la_valid)
if (uc == NULL)
RETURN(0);
+ if (is_project_state_change(oattr, la)) {
+ if (!md_capable(uc, CFS_CAP_SYS_RESOURCE) &&
+ !lustre_in_group_p(uc, ma->ma_enable_chprojid_gid) &&
+ !(ma->ma_enable_chprojid_gid == -1 &&
+ mdd_permission_internal(env, obj, oattr, MAY_WRITE)))
+ RETURN(-EPERM);
+ }
+
if (la->la_valid == LA_CTIME) {
if (!(flags & MDS_PERM_BYPASS))
/* This is only for set ctime when rename's source is
RETURN(rc);
*la_copy = ma->ma_attr;
- rc = mdd_fix_attr(env, mdd_obj, attr, la_copy, ma->ma_attr_flags);
+ rc = mdd_fix_attr(env, mdd_obj, attr, la_copy, ma);
if (rc)
RETURN(rc);
m->mdt_enable_striped_dir = 1;
m->mdt_enable_dir_migration = 1;
m->mdt_enable_remote_dir_gid = 0;
+ m->mdt_enable_chprojid_gid = 0;
m->mdt_enable_remote_rename = 1;
atomic_set(&m->mdt_mds_mds_conns, 0);
/* user with gid can create remote/striped
* dir, and set default dir stripe */
gid_t mdt_enable_remote_dir_gid;
+ /* user with this gid can change projid */
+ gid_t mdt_enable_chprojid_gid;
/* lock for osfs and md_root */
spinlock_t mdt_lock;
}
LUSTRE_RW_ATTR(enable_remote_dir_gid);
+static ssize_t enable_chprojid_gid_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ struct obd_device *obd = container_of(kobj, struct obd_device,
+ obd_kset.kobj);
+ struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n",
+ (int)mdt->mdt_enable_chprojid_gid);
+}
+
+static ssize_t enable_chprojid_gid_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buffer, size_t count)
+{
+ struct obd_device *obd = container_of(kobj, struct obd_device,
+ obd_kset.kobj);
+ struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
+ int val;
+ int rc;
+
+ rc = kstrtoint(buffer, 0, &val);
+ if (rc)
+ return rc;
+
+ mdt->mdt_enable_chprojid_gid = val;
+ return count;
+}
+LUSTRE_RW_ATTR(enable_chprojid_gid);
+
static ssize_t enable_striped_dir_show(struct kobject *kobj,
struct attribute *attr, char *buf)
{
&lustre_attr_evict_tgt_nids.attr,
&lustre_attr_enable_remote_dir.attr,
&lustre_attr_enable_remote_dir_gid.attr,
+ &lustre_attr_enable_chprojid_gid.attr,
&lustre_attr_enable_striped_dir.attr,
&lustre_attr_enable_dir_migration.attr,
&lustre_attr_enable_remote_rename.attr,
if (mdt_object_remote(mo))
GOTO(out_put, rc = -EREMOTE);
+ ma->ma_enable_chprojid_gid = mdt->mdt_enable_chprojid_gid;
/* revoke lease lock if size is going to be changed */
if (unlikely(ma->ma_attr.la_valid & LA_SIZE &&
!(ma->ma_attr_flags & MDS_TRUNC_KEEP_LEASE) &&
}
run_test 65 "Check lfs quota result"
+test_66() {
+ ! is_project_quota_supported &&
+ skip "Project quota is not supported"
+ setup_quota_test || error "setup quota failed with $?"
+ stack_trap cleanup_quota_test EXIT
+ local old=$(do_facet mds1 $LCTL get_param -n \
+ mdt.*.enable_chprojid_gid | head -1)
+ local testdir=$DIR/$tdir/foo
+
+ do_facet mds1 $LCTL set_param mdt.*.enable_chprojid_gid=0
+ stack_trap "do_facet mds1 $LCTL set_param mdt.*.enable_chprojid_gid=0" \
+ EXIT
+
+ test_mkdir -i 0 -c 1 $testdir || error "failed to mkdir"
+ chown -R $TSTID:$TSTID $testdir
+ change_project -sp $TSTPRJID $testdir
+ $RUNAS mkdir $testdir/foo || error "failed to mkdir foo"
+
+ $RUNAS lfs project -p 0 $testdir/foo &&
+ error "nonroot user should fail to set projid"
+
+ $RUNAS lfs project -C $testdir/foo &&
+ error "nonroot user should fail to clear projid"
+
+ change_project -C $testdir/foo || error "failed to clear project"
+
+ do_facet mds1 $LCTL set_param mdt.*.enable_chprojid_gid=-1
+ $RUNAS lfs project -p $TSTPRJID $testdir/foo || error \
+ "failed to set projid with normal user when enable_chprojid_gid=-1"
+
+ $RUNAS lfs project -rC $testdir/ || error \
+"failed to clear project state with normal user when enable_chprojid_gid=-1"
+
+ touch $testdir/bar || error "failed touch $testdir/bar"
+ $RUNAS lfs project -p $TSTPRJID $testdir/bar && error \
+ "normal user should not be able to set projid on root owned file"
+
+ change_project -p $TSTPRJID $testdir/bar || error \
+ "root should be able to change its own file's projid"
+
+ cleanup_quota_test
+}
+run_test 66 "nonroot user can not change project state in default"
+
quota_fini()
{
do_nodes $(comma_list $(nodes_list)) "lctl set_param debug=-quota"