diff --git a/fs/lustre/llite/dir.c b/fs/lustre/llite/dir.c
index fa8e697..9666534 100644
--- a/fs/lustre/llite/dir.c
+++ b/fs/lustre/llite/dir.c
@@ -2098,6 +2098,8 @@ static long ll_dir_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 		return ll_ioctl_fsgetxattr(inode, cmd, arg);
 	case FS_IOC_FSSETXATTR:
 		return ll_ioctl_fssetxattr(inode, cmd, arg);
+	case LL_IOC_PROJECT:
+		return ll_ioctl_project(file, cmd, arg);
 	case LL_IOC_PCC_DETACH_BY_FID: {
 		struct lu_pcc_detach_fid *detach;
 		struct lu_fid *fid;
diff --git a/fs/lustre/llite/file.c b/fs/lustre/llite/file.c
index 54e343f..1ef5fd8 100644
--- a/fs/lustre/llite/file.c
+++ b/fs/lustre/llite/file.c
@@ -3314,7 +3314,8 @@ int ll_ioctl_fsgetxattr(struct inode *inode, unsigned int cmd,
 	return 0;
 }
 
-int ll_ioctl_check_project(struct inode *inode, struct fsxattr *fa)
+int ll_ioctl_check_project(struct inode *inode, u32 xflags,
+			   u32 projid)
 {
 	/*
 	 * Project Quota ID state is only allowed to change from within the init
@@ -3324,36 +3325,29 @@ int ll_ioctl_check_project(struct inode *inode, struct fsxattr *fa)
 	if (current_user_ns() == &init_user_ns)
 		return 0;
 
-	if (ll_i2info(inode)->lli_projid != fa->fsx_projid)
+	if (ll_i2info(inode)->lli_projid != projid)
 		return -EINVAL;
 
 	if (test_bit(LLIF_PROJECT_INHERIT, &ll_i2info(inode)->lli_flags)) {
-		if (!(fa->fsx_xflags & FS_XFLAG_PROJINHERIT))
+		if (!(xflags & FS_XFLAG_PROJINHERIT))
 			return -EINVAL;
 	} else {
-		if (fa->fsx_xflags & FS_XFLAG_PROJINHERIT)
+		if (xflags & FS_XFLAG_PROJINHERIT)
 			return -EINVAL;
 	}
 
 	return 0;
 }
 
-int ll_ioctl_fssetxattr(struct inode *inode, unsigned int cmd,
-			unsigned long arg)
+static int ll_set_project(struct inode *inode, u32 xflags, u32 projid)
 {
 	struct ptlrpc_request *req = NULL;
 	struct md_op_data *op_data;
-	struct fsxattr fsxattr;
 	struct cl_object *obj;
 	unsigned int inode_flags;
 	int rc = 0;
 
-	if (copy_from_user(&fsxattr,
-			   (const struct fsxattr __user *)arg,
-			   sizeof(fsxattr)))
-		return -EFAULT;
-
-	rc = ll_ioctl_check_project(inode, &fsxattr);
+	rc = ll_ioctl_check_project(inode, xflags, projid);
 	if (rc)
 		return rc;
 
@@ -3362,11 +3356,11 @@ int ll_ioctl_fssetxattr(struct inode *inode, unsigned int cmd,
 	if (IS_ERR(op_data))
 		return PTR_ERR(op_data);
 
-	inode_flags = ll_xflags_to_inode_flags(fsxattr.fsx_xflags);
+	inode_flags = ll_xflags_to_inode_flags(xflags);
 	op_data->op_attr_flags = ll_inode_to_ext_flags(inode_flags);
-	if (fsxattr.fsx_xflags & FS_XFLAG_PROJINHERIT)
+	if (xflags & FS_XFLAG_PROJINHERIT)
 		op_data->op_attr_flags |= LUSTRE_PROJINHERIT_FL;
-	op_data->op_projid = fsxattr.fsx_projid;
+	op_data->op_projid = projid;
 	op_data->op_xvalid |= OP_XVALID_PROJID;
 	rc = md_setattr(ll_i2sbi(inode)->ll_md_exp, op_data, NULL,
 			0, &req);
@@ -3377,16 +3371,14 @@ int ll_ioctl_fssetxattr(struct inode *inode, unsigned int cmd,
 	ll_update_inode_flags(inode, op_data->op_attr_flags);
 
 	/* Avoid OST RPC if this is only ioctl setting project inherit flag */
-	if (fsxattr.fsx_xflags == 0 ||
-	    fsxattr.fsx_xflags == FS_XFLAG_PROJINHERIT)
+	if (xflags == 0 || xflags == FS_XFLAG_PROJINHERIT)
 		goto out_fsxattr;
 
 	obj = ll_i2info(inode)->lli_clob;
 	if (obj) {
 		struct iattr attr = { 0 };
 
-		rc = cl_setattr_ost(obj, &attr, OP_XVALID_FLAGS,
-				    fsxattr.fsx_xflags);
+		rc = cl_setattr_ost(obj, &attr, OP_XVALID_FLAGS, xflags);
 	}
 
 out_fsxattr:
@@ -3395,6 +3387,83 @@ int ll_ioctl_fssetxattr(struct inode *inode, unsigned int cmd,
 	return rc;
 }
 
+int ll_ioctl_fssetxattr(struct inode *inode, unsigned int cmd,
+			unsigned long arg)
+{
+	struct fsxattr fsxattr;
+
+	if (copy_from_user(&fsxattr,
+			   (const struct fsxattr __user *)arg,
+			   sizeof(fsxattr)))
+		return -EFAULT;
+
+	return ll_set_project(inode, fsxattr.fsx_xflags,
+			      fsxattr.fsx_projid);
+}
+
+int ll_ioctl_project(struct file *file, unsigned int cmd,
+		     unsigned long arg)
+{
+	struct lu_project lu_project;
+	struct dentry *dentry = file_dentry(file);
+	struct inode *inode = file_inode(file);
+	struct dentry *child_dentry = NULL;
+	int rc = 0, name_len;
+
+	if (copy_from_user(&lu_project,
+			   (const struct lu_project __user *)arg,
+			   sizeof(lu_project)))
+		return -EFAULT;
+
+	/* apply child dentry if name is valid */
+	name_len = strnlen(lu_project.project_name, NAME_MAX);
+	if (name_len > 0 && name_len <= NAME_MAX) {
+		inode_lock(inode);
+		child_dentry = lookup_one_len(lu_project.project_name,
+					      dentry, name_len);
+		inode_unlock(inode);
+		if (IS_ERR(child_dentry)) {
+			rc = PTR_ERR(child_dentry);
+			goto out;
+		}
+		inode = child_dentry->d_inode;
+		if (!inode) {
+			rc = -ENOENT;
+			goto out;
+		}
+	} else if (name_len > NAME_MAX) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	switch (lu_project.project_type) {
+	case LU_PROJECT_SET:
+		rc = ll_set_project(inode, lu_project.project_xflags,
+				    lu_project.project_id);
+		break;
+	case LU_PROJECT_GET:
+		lu_project.project_xflags =
+				ll_inode_flags_to_xflags(inode->i_flags);
+		if (test_bit(LLIF_PROJECT_INHERIT,
+			     &ll_i2info(inode)->lli_flags))
+			lu_project.project_xflags |= FS_XFLAG_PROJINHERIT;
+		lu_project.project_id = ll_i2info(inode)->lli_projid;
+		if (copy_to_user((struct lu_project __user *)arg,
+				 &lu_project, sizeof(lu_project))) {
+			rc = -EFAULT;
+			goto out;
+		}
+		break;
+	default:
+		rc = -EINVAL;
+		break;
+	}
+out:
+	if (!IS_ERR_OR_NULL(child_dentry))
+		dput(child_dentry);
+	return rc;
+}
+
 static long ll_file_unlock_lease(struct file *file, struct ll_ioc_lease *ioc,
 				 unsigned long arg)
 {
@@ -4063,6 +4132,8 @@ static int ll_heat_set(struct inode *inode, enum lu_heat_flag flags)
 		return ll_ioctl_fsgetxattr(inode, cmd, arg);
 	case FS_IOC_FSSETXATTR:
 		return ll_ioctl_fssetxattr(inode, cmd, arg);
+	case LL_IOC_PROJECT:
+		return ll_ioctl_project(file, cmd, arg);
 	case BLKSSZGET:
 		return put_user(PAGE_SIZE, (int __user *)arg);
 	case LL_IOC_HEAT_GET: {
diff --git a/fs/lustre/llite/llite_internal.h b/fs/lustre/llite/llite_internal.h
index 1d5255e..6cae741 100644
--- a/fs/lustre/llite/llite_internal.h
+++ b/fs/lustre/llite/llite_internal.h
@@ -1157,11 +1157,14 @@ int ll_migrate(struct inode *parent, struct file *file,
 int ll_get_fid_by_name(struct inode *parent, const char *name,
 		       int namelen, struct lu_fid *fid, struct inode **inode);
 int ll_inode_permission(struct inode *inode, int mask);
-int ll_ioctl_check_project(struct inode *inode, struct fsxattr *fa);
+int ll_ioctl_check_project(struct inode *inode, u32 xflags, u32 projid);
 int ll_ioctl_fsgetxattr(struct inode *inode, unsigned int cmd,
 			unsigned long arg);
 int ll_ioctl_fssetxattr(struct inode *inode, unsigned int cmd,
 			unsigned long arg);
+int ll_ioctl_project(struct file *file, unsigned int cmd,
+		     unsigned long arg);
+
 int ll_lov_setstripe_ea_info(struct inode *inode, struct dentry *dentry,
 			     u64 flags, struct lov_user_md *lum,
 			     int lum_size);
diff --git a/fs/lustre/llite/llite_lib.c b/fs/lustre/llite/llite_lib.c
index 153d34e..10a9a95 100644
--- a/fs/lustre/llite/llite_lib.c
+++ b/fs/lustre/llite/llite_lib.c
@@ -2615,7 +2615,8 @@ int ll_iocontrol(struct inode *inode, struct file *file,
 		if (flags & LUSTRE_PROJINHERIT_FL)
 			fa.fsx_xflags = FS_XFLAG_PROJINHERIT;
 
-		rc = ll_ioctl_check_project(inode, &fa);
+		rc = ll_ioctl_check_project(inode, fa.fsx_xflags,
+					    fa.fsx_projid);
 		if (rc)
 			return rc;
 
diff --git a/include/uapi/linux/lustre/lustre_user.h b/include/uapi/linux/lustre/lustre_user.h
index 0cd3500..da15ca8 100644
--- a/include/uapi/linux/lustre/lustre_user.h
+++ b/include/uapi/linux/lustre/lustre_user.h
@@ -375,6 +375,7 @@ struct ll_ioc_lease_id {
 #define LL_IOC_PCC_DETACH		_IOW('f', 252, struct lu_pcc_detach)
 #define LL_IOC_PCC_DETACH_BY_FID	_IOW('f', 252, struct lu_pcc_detach_fid)
 #define LL_IOC_PCC_STATE		_IOR('f', 252, struct lu_pcc_state)
+#define LL_IOC_PROJECT			_IOW('f', 253, struct lu_project)
 
 #define LL_STATFS_LMV		1
 #define LL_STATFS_LOV		2
@@ -2311,6 +2312,21 @@ struct lu_pcc_state {
 	char	pccs_path[PATH_MAX];
 };
 
+enum lu_project_type {
+	LU_PROJECT_NONE = 0,
+	LU_PROJECT_SET,
+	LU_PROJECT_GET,
+	LU_PROJECT_MAX
+};
+
+struct lu_project {
+	__u32	project_type; /* enum lu_project_type */
+	__u32	project_id;
+	__u32	project_xflags;
+	__u32	project_reserved;
+	char	project_name[NAME_MAX + 1];
+};
+
 struct fid_array {
 	__u32 fa_nr;
 	/* make header's size equal lu_fid */
