diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
-index 31317c9..39b31aa 100644
+index ce3b85f..29db502 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
-@@ -398,6 +398,13 @@ struct flex_groups {
+@@ -395,6 +395,13 @@ struct flex_groups {
#define EXT4_FL_USER_VISIBLE 0x304BDFFF /* User visible flags */
#define EXT4_FL_USER_MODIFIABLE 0x204380FF /* User modifiable flags */
/* Flags that should be inherited by new inodes from their parent. */
#define EXT4_FL_INHERITED (EXT4_SECRM_FL | EXT4_UNRM_FL | EXT4_COMPR_FL |\
EXT4_SYNC_FL | EXT4_NODUMP_FL | EXT4_NOATIME_FL |\
-@@ -621,6 +628,44 @@ enum {
+@@ -620,6 +627,44 @@ enum {
#define EXT4_IOC_SWAP_BOOT _IO('f', 17)
#define EXT4_IOC_PRECACHE_EXTENTS _IO('f', 18)
#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
/*
* ioctl commands in 32 bit emulation
-@@ -2336,6 +2381,7 @@ extern int ext4_ind_remove_space(handle_t *handle, struct inode *inode,
+@@ -2347,6 +2392,7 @@ extern int ext4_ind_remove_space(handle_t *handle, struct inode *inode,
/* ioctl.c */
extern long ext4_ioctl(struct file *, unsigned int, unsigned long);
extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long);
-+extern int __ext4_ioctl_setproject(struct inode *inode, __u32 projid);
++extern int ext4_transfer_project(struct inode *inode, __u32 projid);
/* migrate.c */
extern int ext4_ext_migrate(struct inode *);
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
-index bfda18a..a4443e9 100644
+index 70c66d3..276d33d 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -15,6 +15,7 @@
#include "ext4_jbd2.h"
#include "ext4.h"
-@@ -198,6 +199,251 @@ journal_err_out:
+@@ -198,6 +199,294 @@ journal_err_out:
return err;
}
+}
+
+#ifdef CONFIG_QUOTA
-+int __ext4_ioctl_setproject(struct inode *inode, __u32 projid)
++static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
+{
++ struct inode *inode = file_inode(filp);
+ struct super_block *sb = inode->i_sb;
+ struct ext4_inode_info *ei = EXT4_I(inode);
+ int err, rc;
+ }
+
+ if (EXT4_INODE_SIZE(sb) <= EXT4_GOOD_OLD_INODE_SIZE)
-+ return -EOPNOTSUPP;
++ return -EOPNOTSUPP;
+
+ kprojid = make_kprojid(&init_user_ns, (projid_t)projid);
+
+ if (projid_eq(kprojid, EXT4_I(inode)->i_projid))
+ return 0;
+
++ err = mnt_want_write_file(filp);
++ if (err)
++ return err;
++
+ err = -EPERM;
+ mutex_lock(&inode->i_mutex);
+ /* Is it quota file? Do not allow user to mess with it */
+
+ raw_inode = ext4_raw_inode(&iloc);
+ if (!EXT4_FITS_IN_INODE(raw_inode, ei, i_projid)) {
-+ err = -EOVERFLOW;
-+ brelse(iloc.bh);
-+ goto out_unlock;
++ err = -EOVERFLOW;
++ brelse(iloc.bh);
++ goto out_unlock;
+ }
+ brelse(iloc.bh);
+
+ ext4_journal_stop(handle);
+out_unlock:
+ mutex_unlock(&inode->i_mutex);
++ mnt_drop_write_file(filp);
+ return err;
+
+
+}
-+EXPORT_SYMBOL(__ext4_ioctl_setproject);
+
-+static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
++int ext4_transfer_project(struct inode *inode, __u32 projid)
+{
++ struct super_block *sb = inode->i_sb;
++ struct ext4_inode_info *ei = EXT4_I(inode);
+ int err;
-+ struct inode *inode = file_inode(filp);
++ kprojid_t kprojid;
++ struct ext4_iloc iloc;
++ struct ext4_inode *raw_inode;
++ struct dquot *transfer_to[EXT4_MAXQUOTAS] = { };
+
-+ err = mnt_want_write_file(filp);
++ if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
++ EXT4_FEATURE_RO_COMPAT_PROJECT)) {
++ BUG_ON(__kprojid_val(EXT4_I(inode)->i_projid)
++ != EXT4_DEF_PROJID);
++ if (projid != EXT4_DEF_PROJID)
++ return -EOPNOTSUPP;
++ else
++ return 0;
++ }
++
++ if (EXT4_INODE_SIZE(sb) <= EXT4_GOOD_OLD_INODE_SIZE)
++ return -EOPNOTSUPP;
++
++ kprojid = make_kprojid(&init_user_ns, (projid_t)projid);
++ if (projid_eq(kprojid, EXT4_I(inode)->i_projid))
++ return 0;
++
++ err = ext4_get_inode_loc(inode, &iloc);
+ if (err)
+ return err;
+
-+ err = __ext4_ioctl_setproject(inode, projid);
++ raw_inode = ext4_raw_inode(&iloc);
++ if (!EXT4_FITS_IN_INODE(raw_inode, ei, i_projid)) {
++ err = -EOVERFLOW;
++ brelse(iloc.bh);
++ return err;
++ }
++ brelse(iloc.bh);
++
++ dquot_initialize(inode);
++ transfer_to[PRJQUOTA] = dqget(sb, make_kqid_projid(kprojid));
++ if (transfer_to[PRJQUOTA]) {
++ err = __dquot_transfer(inode, transfer_to);
++ dqput(transfer_to[PRJQUOTA]);
++ if (err)
++ return err;
++ }
+
-+ mnt_drop_write_file(filp);
+ return err;
+}
++EXPORT_SYMBOL(ext4_transfer_project);
++
+#else
+static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
+{
long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct inode *inode = file_inode(filp);
-@@ -213,11 +459,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+@@ -213,11 +502,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
return put_user(flags, (int __user *) arg);
case EXT4_IOC_SETFLAGS: {
if (!inode_owner_or_capable(inode))
return -EACCES;
-@@ -231,89 +473,8 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+@@ -231,89 +516,8 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
flags = ext4_mask_flags(inode->i_mode, flags);
mutex_unlock(&inode->i_mutex);
mnt_drop_write_file(filp);
return err;
-@@ -617,6 +778,62 @@ resizefs_out:
+@@ -622,6 +826,62 @@ resizefs_out:
}
case EXT4_IOC_PRECACHE_EXTENTS:
return ext4_ext_precache(inode);
}
}
-#ifdef HAVE_PROJECT_QUOTA
/* Handle project id transfer here properly */
if (attr->la_valid & LA_PROJID &&
attr->la_projid != i_projid_read(inode)) {
- rc = __ldiskfs_ioctl_setproject(inode, attr->la_projid);
+#ifdef HAVE_PROJECT_QUOTA
+ rc = ldiskfs_transfer_project(inode, attr->la_projid);
+#else
+ rc = -ENOTSUPP;
+#endif
if (rc) {
- CERROR("%s: quota transfer failed: rc = %d. Is quota "
+ CERROR("%s: quota transfer failed: rc = %d. Is project "
"enforcement enabled on the ldiskfs "
"filesystem?\n", inode->i_sb->s_id, rc);
return rc;
}
}
-#endif
return 0;
}
/* Agent inode should not have project ID */
#ifdef HAVE_PROJECT_QUOTA
- if (LDISKFS_I(pobj->oo_inode)->i_flags & LUSTRE_PROJINHERIT_FL) {
- rc = __ldiskfs_ioctl_setproject(local, 0);
+ if (LDISKFS_I(pobj->oo_inode)->i_flags & LUSTRE_PROJINHERIT_FL &&
+ i_projid_read(pobj->oo_inode) != 0) {
+ rc = ldiskfs_transfer_project(local, 0);
if (rc) {
CERROR("%s: quota transfer failed: rc = %d. Is project "
"quota enforcement enabled on the ldiskfs "
i_projid_read(inode), 0,
oh, osd_dt_obj(dt), NULL,
OSD_QID_BLK);
+ if (rc)
+ RETURN(rc);
+
+#ifdef HAVE_PROJECT_QUOTA
+ /* Reserve credits for local agent inode to transfer
+ * to 0, quota enforcement is ignored in this case.
+ */
+ if (idc->oic_remote &&
+ LDISKFS_I(inode)->i_flags & LUSTRE_PROJINHERIT_FL &&
+ i_projid_read(inode) != 0)
+ rc = osd_declare_attr_qid(env, osd_dt_obj(dt), oh,
+ 0, i_projid_read(inode),
+ 0, false, PRJQUOTA);
+#endif
}
+
RETURN(rc);
}