SPEC_NAME="kernel.spec"
DEVEL_PATH_ARCH_DELIMETER="."
-USE_KABI=true
+USE_KABI=false
# force local definition of %dist into ~/.rpmmacros
# to avoid verbose extended strings like ".el7.centos"
--- /dev/null
+diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
+index 9308f35..eeb3d05 100644
+--- a/fs/ext4/ext4.h
++++ b/fs/ext4/ext4.h
+@@ -377,16 +377,18 @@ struct flex_groups {
+ #define EXT4_EA_INODE_FL 0x00200000 /* Inode used for large EA */
+ #define EXT4_EOFBLOCKS_FL 0x00400000 /* Blocks allocated beyond EOF */
+ #define EXT4_INLINE_DATA_FL 0x10000000 /* Inode has inline data. */
++#define EXT4_PROJINHERIT_FL 0x20000000 /* Create with parents projid */
+ #define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */
+
+-#define EXT4_FL_USER_VISIBLE 0x004BDFFF /* User visible flags */
+-#define EXT4_FL_USER_MODIFIABLE 0x004380FF /* User modifiable flags */
++#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 |\
+ EXT4_NOCOMPR_FL | EXT4_JOURNAL_DATA_FL |\
+- EXT4_NOTAIL_FL | EXT4_DIRSYNC_FL)
++ EXT4_NOTAIL_FL | EXT4_DIRSYNC_FL |\
++ EXT4_PROJINHERIT_FL)
+
+ /* Flags that are appropriate for regular files (all but dir-specific ones). */
+ #define EXT4_REG_FLMASK (~(EXT4_DIRSYNC_FL | EXT4_TOPDIR_FL))
+@@ -434,6 +436,7 @@ enum {
+ EXT4_INODE_EA_INODE = 21, /* Inode used for large EA */
+ EXT4_INODE_EOFBLOCKS = 22, /* Blocks allocated beyond EOF */
+ EXT4_INODE_INLINE_DATA = 28, /* Data in inode. */
++ EXT4_INODE_PROJINHERIT = 29, /* Create with parents projid */
+ EXT4_INODE_RESERVED = 31, /* reserved for ext4 lib */
+ };
+
+@@ -685,6 +688,7 @@ struct ext4_inode {
+ __le32 i_crtime; /* File Creation time */
+ __le32 i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */
+ __le32 i_version_hi; /* high 32 bits for 64-bit version */
++ __le32 i_projid; /* Project ID */
+ };
+
+ struct move_extent {
+@@ -942,6 +946,7 @@ struct ext4_inode_info {
+
+ /* Precomputed uuid+inum+igen checksum for seeding inode checksums */
+ __u32 i_csum_seed;
++ kprojid_t i_projid;
+ };
+
+ /*
+@@ -1531,6 +1536,7 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
+ * GDT_CSUM bits are mutually exclusive.
+ */
+ #define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM 0x0400
++#define EXT4_FEATURE_RO_COMPAT_PROJECT 0x2000
+
+ #define EXT4_FEATURE_INCOMPAT_COMPRESSION 0x0001
+ #define EXT4_FEATURE_INCOMPAT_FILETYPE 0x0002
+@@ -1580,7 +1586,8 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
+ EXT4_FEATURE_RO_COMPAT_HUGE_FILE |\
+ EXT4_FEATURE_RO_COMPAT_BIGALLOC |\
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM|\
+- EXT4_FEATURE_RO_COMPAT_QUOTA)
++ EXT4_FEATURE_RO_COMPAT_QUOTA |\
++ EXT4_FEATURE_RO_COMPAT_PROJECT)
+
+ /*
+ * Default values for user and/or group using reserved blocks
+@@ -1588,6 +1595,11 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
+ #define EXT4_DEF_RESUID 0
+ #define EXT4_DEF_RESGID 0
+
++/*
++ * Default project ID
++ */
++#define EXT4_DEF_PROJID 0
++
+ #define EXT4_DEF_INODE_READAHEAD_BLKS 32
+
+ /*
+@@ -2145,6 +2157,7 @@ extern int ext4_zero_partial_blocks(handle_t *handle, struct inode *inode,
+ extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf);
+ extern int ext4_filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
+ extern qsize_t *ext4_get_reserved_space(struct inode *inode);
++extern int ext4_get_projid(struct inode *inode, kprojid_t *projid);
+ extern void ext4_da_update_reserve_space(struct inode *inode,
+ int used, int quota_claim);
+ extern int ext4_issue_zeroout(struct inode *inode, ext4_lblk_t lblk,
+diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
+index ac644c3..10ca9dd 100644
+--- a/fs/ext4/ialloc.c
++++ b/fs/ext4/ialloc.c
+@@ -756,6 +756,11 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
+ inode->i_gid = dir->i_gid;
+ } else
+ inode_init_owner(inode, dir, mode);
++ if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_PROJECT) &&
++ ext4_test_inode_flag(dir, EXT4_INODE_PROJINHERIT))
++ ei->i_projid = EXT4_I(dir)->i_projid;
++ else
++ ei->i_projid = make_kprojid(&init_user_ns, EXT4_DEF_PROJID);
+ dquot_initialize(inode);
+
+ if (!goal)
+diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
+index f094263..34877ac 100644
+--- a/fs/ext4/inode.c
++++ b/fs/ext4/inode.c
+@@ -4099,6 +4099,14 @@ static inline void ext4_iget_extra_inode(struct inode *inode,
+ EXT4_I(inode)->i_inline_off = 0;
+ }
+
++int ext4_get_projid(struct inode *inode, kprojid_t *projid)
++{
++ if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, EXT4_FEATURE_RO_COMPAT_PROJECT))
++ return -EOPNOTSUPP;
++ *projid = EXT4_I(inode)->i_projid;
++ return 0;
++}
++
+ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
+ {
+ struct ext4_iloc iloc;
+@@ -4110,6 +4118,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
+ int block;
+ uid_t i_uid;
+ gid_t i_gid;
++ projid_t i_projid;
+
+ inode = iget_locked(sb, ino);
+ if (!inode)
+@@ -4159,12 +4168,20 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
+ inode->i_mode = le16_to_cpu(raw_inode->i_mode);
+ i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
+ i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
++ if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_PROJECT) &&
++ EXT4_INODE_SIZE(sb) > EXT4_GOOD_OLD_INODE_SIZE &&
++ EXT4_FITS_IN_INODE(raw_inode, ei, i_projid))
++ i_projid = (projid_t)le32_to_cpu(raw_inode->i_projid);
++ else
++ i_projid = EXT4_DEF_PROJID;
++
+ if (!(test_opt(inode->i_sb, NO_UID32))) {
+ i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
+ i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
+ }
+ i_uid_write(inode, i_uid);
+ i_gid_write(inode, i_gid);
++ ei->i_projid = make_kprojid(&init_user_ns, i_projid);;
+ set_nlink(inode, le16_to_cpu(raw_inode->i_links_count));
+
+ ext4_clear_state_flags(ei); /* Only relevant on 32-bit archs */
+@@ -4395,6 +4412,7 @@ static int ext4_do_update_inode(handle_t *handle,
+ int need_datasync = 0, set_large_file = 0;
+ uid_t i_uid;
+ gid_t i_gid;
++ projid_t i_projid;
+
+ spin_lock(&ei->i_raw_lock);
+
+@@ -4407,6 +4425,7 @@ static int ext4_do_update_inode(handle_t *handle,
+ raw_inode->i_mode = cpu_to_le16(inode->i_mode);
+ i_uid = i_uid_read(inode);
+ i_gid = i_gid_read(inode);
++ i_projid = from_kprojid(&init_user_ns, ei->i_projid);
+ if (!(test_opt(inode->i_sb, NO_UID32))) {
+ raw_inode->i_uid_low = cpu_to_le16(low_16_bits(i_uid));
+ raw_inode->i_gid_low = cpu_to_le16(low_16_bits(i_gid));
+@@ -4486,6 +4505,14 @@ static int ext4_do_update_inode(handle_t *handle,
+ }
+ }
+
++ BUG_ON(!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
++ EXT4_FEATURE_RO_COMPAT_PROJECT) &&
++ i_projid != EXT4_DEF_PROJID);
++
++ if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE &&
++ EXT4_FITS_IN_INODE(raw_inode, ei, i_projid))
++ raw_inode->i_projid = cpu_to_le32(i_projid);
++
+ ext4_inode_csum_set(inode, raw_inode, ei);
+
+ spin_unlock(&ei->i_raw_lock);
+diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
+index a43d2f4..aead238 100644
+--- a/fs/ext4/namei.c
++++ b/fs/ext4/namei.c
+@@ -2927,6 +2927,11 @@ static int ext4_link(struct dentry *old_dentry,
+ if (inode->i_nlink >= EXT4_LINK_MAX)
+ return -EMLINK;
+
++ if ((ext4_test_inode_flag(dir, EXT4_INODE_PROJINHERIT)) &&
++ (!projid_eq(EXT4_I(dir)->i_projid,
++ EXT4_I(old_dentry->d_inode)->i_projid)))
++ return -EXDEV;
++
+ dquot_initialize(dir);
+
+ retry:
+@@ -3201,6 +3206,11 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
+ int credits;
+ u8 old_file_type;
+
++ if ((ext4_test_inode_flag(new_dir, EXT4_INODE_PROJINHERIT)) &&
++ (!projid_eq(EXT4_I(new_dir)->i_projid,
++ EXT4_I(old_dentry->d_inode)->i_projid)))
++ return -EXDEV;
++
+ dquot_initialize(old.dir);
+ dquot_initialize(new.dir);
+
+@@ -3385,6 +3395,14 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
+ u8 new_file_type;
+ int retval;
+
++ if ((ext4_test_inode_flag(new_dir, EXT4_INODE_PROJINHERIT) &&
++ !projid_eq(EXT4_I(new_dir)->i_projid,
++ EXT4_I(old_dentry->d_inode)->i_projid)) ||
++ (ext4_test_inode_flag(old_dir, EXT4_INODE_PROJINHERIT) &&
++ !projid_eq(EXT4_I(old_dir)->i_projid,
++ EXT4_I(new_dentry->d_inode)->i_projid)))
++ return -EXDEV;
++
+ dquot_initialize(old.dir);
+ dquot_initialize(new.dir);
+
+diff --git a/fs/ext4/super.c b/fs/ext4/super.c
+index 24ef7b2..8189081 100644
+--- a/fs/ext4/super.c
++++ b/fs/ext4/super.c
+@@ -1075,6 +1075,7 @@ static const struct dquot_operations ext4_quota_operations = {
+ .write_info = ext4_write_info,
+ .alloc_dquot = dquot_alloc,
+ .destroy_dquot = dquot_destroy,
++ .get_projid = ext4_get_projid,
+ };
+
+ static const struct quotactl_ops ext4_qctl_operations = {
--- /dev/null
+diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
+index d00d779..9308f35 100644
+--- a/fs/ext4/ext4.h
++++ b/fs/ext4/ext4.h
+@@ -1179,6 +1179,9 @@ struct ext4_super_block {
+ #define EXT4_MF_MNTDIR_SAMPLED 0x0001
+ #define EXT4_MF_FS_ABORTED 0x0002 /* Fatal error detected */
+
++/* Number of quota types we support */
++#define EXT4_MAXQUOTAS 2
++
+ /*
+ * fourth extended-fs super-block data in memory
+ */
+@@ -1242,7 +1245,7 @@ struct ext4_sb_info {
+ u32 s_min_batch_time;
+ struct block_device *journal_bdev;
+ #ifdef CONFIG_QUOTA
+- char *s_qf_names[MAXQUOTAS]; /* Names of quota files with journalled quota */
++ char *s_qf_names[EXT4_MAXQUOTAS]; /* Names of quota files with journalled quota */
+ int s_jquota_fmt; /* Format of quota to use */
+ #endif
+ unsigned int s_want_extra_isize; /* New inodes should reserve # bytes */
+diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h
+index 17c00ff..9c5b49f 100644
+--- a/fs/ext4/ext4_jbd2.h
++++ b/fs/ext4/ext4_jbd2.h
+@@ -102,9 +102,9 @@
+ #define EXT4_QUOTA_INIT_BLOCKS(sb) 0
+ #define EXT4_QUOTA_DEL_BLOCKS(sb) 0
+ #endif
+-#define EXT4_MAXQUOTAS_TRANS_BLOCKS(sb) (MAXQUOTAS*EXT4_QUOTA_TRANS_BLOCKS(sb))
+-#define EXT4_MAXQUOTAS_INIT_BLOCKS(sb) (MAXQUOTAS*EXT4_QUOTA_INIT_BLOCKS(sb))
+-#define EXT4_MAXQUOTAS_DEL_BLOCKS(sb) (MAXQUOTAS*EXT4_QUOTA_DEL_BLOCKS(sb))
++#define EXT4_MAXQUOTAS_TRANS_BLOCKS(sb) (EXT4_MAXQUOTAS*EXT4_QUOTA_TRANS_BLOCKS(sb))
++#define EXT4_MAXQUOTAS_INIT_BLOCKS(sb) (EXT4_MAXQUOTAS*EXT4_QUOTA_INIT_BLOCKS(sb))
++#define EXT4_MAXQUOTAS_DEL_BLOCKS(sb) (EXT4_MAXQUOTAS*EXT4_QUOTA_DEL_BLOCKS(sb))
+
+ static inline int ext4_jbd2_credits_xattr(struct inode *inode)
+ {
+diff --git a/fs/ext4/super.c b/fs/ext4/super.c
+index 7f2c846..24ef7b2 100644
+--- a/fs/ext4/super.c
++++ b/fs/ext4/super.c
+@@ -820,7 +820,7 @@ static void ext4_put_super(struct super_block *sb)
+ percpu_counter_destroy(&sbi->s_extent_cache_cnt);
+ brelse(sbi->s_sbh);
+ #ifdef CONFIG_QUOTA
+- for (i = 0; i < MAXQUOTAS; i++)
++ for (i = 0; i < EXT4_MAXQUOTAS; i++)
+ kfree(sbi->s_qf_names[i]);
+ #endif
+
+@@ -2224,7 +2224,7 @@ static void ext4_orphan_cleanup(struct super_block *sb,
+ /* Needed for iput() to work correctly and not trash data */
+ sb->s_flags |= MS_ACTIVE;
+ /* Turn on quotas so that they are updated correctly */
+- for (i = 0; i < MAXQUOTAS; i++) {
++ for (i = 0; i < EXT4_MAXQUOTAS; i++) {
+ if (EXT4_SB(sb)->s_qf_names[i]) {
+ int ret = ext4_quota_on_mount(sb, i);
+ if (ret < 0)
+@@ -2280,7 +2280,7 @@ static void ext4_orphan_cleanup(struct super_block *sb,
+ PLURAL(nr_truncates));
+ #ifdef CONFIG_QUOTA
+ /* Turn quotas off */
+- for (i = 0; i < MAXQUOTAS; i++) {
++ for (i = 0; i < EXT4_MAXQUOTAS; i++) {
+ if (sb_dqopt(sb)->files[i])
+ dquot_quota_off(sb, i);
+ }
+@@ -4322,7 +4322,7 @@ failed_mount:
+ remove_proc_entry(sb->s_id, ext4_proc_root);
+ }
+ #ifdef CONFIG_QUOTA
+- for (i = 0; i < MAXQUOTAS; i++)
++ for (i = 0; i < EXT4_MAXQUOTAS; i++)
+ kfree(sbi->s_qf_names[i]);
+ #endif
+ ext4_blkdev_remove(sbi);
+@@ -4858,7 +4858,7 @@ struct ext4_mount_options {
+ u32 s_min_batch_time, s_max_batch_time;
+ #ifdef CONFIG_QUOTA
+ int s_jquota_fmt;
+- char *s_qf_names[MAXQUOTAS];
++ char *s_qf_names[EXT4_MAXQUOTAS];
+ #endif
+ };
+
+@@ -4888,7 +4888,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
+ old_opts.s_max_batch_time = sbi->s_max_batch_time;
+ #ifdef CONFIG_QUOTA
+ old_opts.s_jquota_fmt = sbi->s_jquota_fmt;
+- for (i = 0; i < MAXQUOTAS; i++)
++ for (i = 0; i < EXT4_MAXQUOTAS; i++)
+ if (sbi->s_qf_names[i]) {
+ old_opts.s_qf_names[i] = kstrdup(sbi->s_qf_names[i],
+ GFP_KERNEL);
+@@ -5062,7 +5062,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
+
+ #ifdef CONFIG_QUOTA
+ /* Release old quota file names */
+- for (i = 0; i < MAXQUOTAS; i++)
++ for (i = 0; i < EXT4_MAXQUOTAS; i++)
+ kfree(old_opts.s_qf_names[i]);
+ if (enable_quota) {
+ if (sb_any_quota_suspended(sb))
+@@ -5091,7 +5091,7 @@ restore_opts:
+ sbi->s_max_batch_time = old_opts.s_max_batch_time;
+ #ifdef CONFIG_QUOTA
+ sbi->s_jquota_fmt = old_opts.s_jquota_fmt;
+- for (i = 0; i < MAXQUOTAS; i++) {
++ for (i = 0; i < EXT4_MAXQUOTAS; i++) {
+ kfree(sbi->s_qf_names[i]);
+ sbi->s_qf_names[i] = old_opts.s_qf_names[i];
+ }
+@@ -5294,7 +5294,7 @@ static int ext4_quota_enable(struct super_block *sb, int type, int format_id,
+ {
+ int err;
+ struct inode *qf_inode;
+- unsigned long qf_inums[MAXQUOTAS] = {
++ unsigned long qf_inums[EXT4_MAXQUOTAS] = {
+ le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum),
+ le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum)
+ };
+@@ -5322,13 +5322,13 @@ static int ext4_quota_enable(struct super_block *sb, int type, int format_id,
+ static int ext4_enable_quotas(struct super_block *sb)
+ {
+ int type, err = 0;
+- unsigned long qf_inums[MAXQUOTAS] = {
++ unsigned long qf_inums[EXT4_MAXQUOTAS] = {
+ le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum),
+ le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum)
+ };
+
+ sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE;
+- for (type = 0; type < MAXQUOTAS; type++) {
++ for (type = 0; type < EXT4_MAXQUOTAS; type++) {
+ if (qf_inums[type]) {
+ err = ext4_quota_enable(sb, type, QFMT_VFS_V1,
+ DQUOT_USAGE_ENABLED);
--- /dev/null
+diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
+index eeb3d05..00f317c 100644
+--- a/fs/ext4/ext4.h
++++ b/fs/ext4/ext4.h
+@@ -1170,7 +1170,9 @@ struct ext4_super_block {
+ __le32 s_grp_quota_inum; /* inode for tracking group quota */
+ __le32 s_overhead_clusters; /* overhead blocks/clusters in fs */
+ __le32 s_backup_bgs[2]; /* groups with sparse_super2 SBs */
+- __le32 s_reserved[106]; /* Padding to the end of the block */
++ __le32 s_padding[6]; /* reserved for upstream usage */
++ __le32 s_prj_quota_inum; /* inode for tracking project quota */
++ __le32 s_reserved[99]; /* Padding to the end of the block */
+ __le32 s_checksum; /* crc32c(superblock) */
+ };
+
+@@ -1185,7 +1187,7 @@ struct ext4_super_block {
+ #define EXT4_MF_FS_ABORTED 0x0002 /* Fatal error detected */
+
+ /* Number of quota types we support */
+-#define EXT4_MAXQUOTAS 2
++#define EXT4_MAXQUOTAS 3
+
+ /*
+ * fourth extended-fs super-block data in memory
+diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
+index 34877ac..9f38b3f 100644
+--- a/fs/ext4/inode.c
++++ b/fs/ext4/inode.c
+@@ -4101,7 +4101,10 @@ static inline void ext4_iget_extra_inode(struct inode *inode,
+
+ int ext4_get_projid(struct inode *inode, kprojid_t *projid)
+ {
+- if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, EXT4_FEATURE_RO_COMPAT_PROJECT))
++ struct ext4_super_block *sbi = EXT4_SB(inode->i_sb)->s_es;
++
++ if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, EXT4_FEATURE_RO_COMPAT_PROJECT) &&
++ !sbi->s_prj_quota_inum)
+ return -EOPNOTSUPP;
+ *projid = EXT4_I(inode)->i_projid;
+ return 0;
+diff --git a/fs/ext4/super.c b/fs/ext4/super.c
+index 8189081..6a9d397 100644
+--- a/fs/ext4/super.c
++++ b/fs/ext4/super.c
+@@ -1043,8 +1043,8 @@ static int bdev_try_to_free_page(struct super_block *sb, struct page *page,
+ }
+
+ #ifdef CONFIG_QUOTA
+-#define QTYPE2NAME(t) ((t) == USRQUOTA ? "user" : "group")
+-#define QTYPE2MOPT(on, t) ((t) == USRQUOTA?((on)##USRJQUOTA):((on)##GRPJQUOTA))
++static char *quotatypes[] = INITQFNAMES;
++#define QTYPE2NAME(t) (quotatypes[t])
+
+ static int ext4_write_dquot(struct dquot *dquot);
+ static int ext4_acquire_dquot(struct dquot *dquot);
+@@ -5101,6 +5101,48 @@ restore_opts:
+ return err;
+ }
+
++#ifdef CONFIG_QUOTA
++static int ext4_statfs_project(struct super_block *sb,
++ kprojid_t projid, struct kstatfs *buf)
++{
++ struct kqid qid;
++ struct dquot *dquot;
++ u64 limit;
++ u64 curblock;
++
++ qid = make_kqid_projid(projid);
++ dquot = dqget(sb, qid);
++ if (IS_ERR(dquot))
++ return PTR_ERR(dquot);
++ spin_lock(&dq_data_lock);
++
++ limit = dquot->dq_dqb.dqb_bsoftlimit ?
++ dquot->dq_dqb.dqb_bsoftlimit :
++ dquot->dq_dqb.dqb_bhardlimit;
++ if (limit && buf->f_blocks * buf->f_bsize > limit) {
++ curblock = dquot->dq_dqb.dqb_curspace / buf->f_bsize;
++ buf->f_blocks = limit / buf->f_bsize;
++ buf->f_bfree = buf->f_bavail =
++ (buf->f_blocks > curblock) ?
++ (buf->f_blocks - curblock) : 0;
++ }
++
++ limit = dquot->dq_dqb.dqb_isoftlimit ?
++ dquot->dq_dqb.dqb_isoftlimit :
++ dquot->dq_dqb.dqb_ihardlimit;
++ if (limit && buf->f_files > limit) {
++ buf->f_files = limit;
++ buf->f_ffree =
++ (buf->f_files > dquot->dq_dqb.dqb_curinodes) ?
++ (buf->f_files - dquot->dq_dqb.dqb_curinodes) : 0;
++ }
++
++ spin_unlock(&dq_data_lock);
++ dqput(dquot);
++ return 0;
++}
++#endif
++
+ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
+ {
+ struct super_block *sb = dentry->d_sb;
+@@ -5109,6 +5151,7 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
+ ext4_fsblk_t overhead = 0, resv_blocks;
+ u64 fsid;
+ s64 bfree;
++ struct inode *inode = dentry->d_inode;
+ resv_blocks = EXT4_C2B(sbi, atomic64_read(&sbi->s_resv_clusters));
+
+ if (!test_opt(sb, MINIX_DF))
+@@ -5133,6 +5176,11 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
+ buf->f_fsid.val[0] = fsid & 0xFFFFFFFFUL;
+ buf->f_fsid.val[1] = (fsid >> 32) & 0xFFFFFFFFUL;
+
++#ifdef CONFIG_QUOTA
++ if (ext4_test_inode_flag(inode, EXT4_INODE_PROJINHERIT) &&
++ sb_has_quota_limits_enabled(sb, PRJQUOTA))
++ ext4_statfs_project(sb, EXT4_I(inode)->i_projid, buf);
++#endif
+ return 0;
+ }
+
+@@ -5297,7 +5345,8 @@ static int ext4_quota_enable(struct super_block *sb, int type, int format_id,
+ struct inode *qf_inode;
+ unsigned long qf_inums[EXT4_MAXQUOTAS] = {
+ le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum),
+- le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum)
++ le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum),
++ le32_to_cpu(EXT4_SB(sb)->s_es->s_prj_quota_inum)
+ };
+
+ BUG_ON(!EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA));
+@@ -5325,7 +5374,8 @@ static int ext4_enable_quotas(struct super_block *sb)
+ int type, err = 0;
+ unsigned long qf_inums[EXT4_MAXQUOTAS] = {
+ le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum),
+- le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum)
++ le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum),
++ le32_to_cpu(EXT4_SB(sb)->s_es->s_prj_quota_inum)
+ };
+
+ sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE;
--- /dev/null
+diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
+index 00f317c..312abfd 100644
+--- a/fs/ext4/ext4.h
++++ b/fs/ext4/ext4.h
+@@ -383,6 +383,13 @@ struct flex_groups {
+ #define EXT4_FL_USER_VISIBLE 0x304BDFFF /* User visible flags */
+ #define EXT4_FL_USER_MODIFIABLE 0x204380FF /* User modifiable flags */
+
++#define EXT4_FL_XFLAG_VISIBLE (EXT4_SYNC_FL | \
++ EXT4_IMMUTABLE_FL | \
++ EXT4_APPEND_FL | \
++ EXT4_NODUMP_FL | \
++ EXT4_NOATIME_FL | \
++ EXT4_PROJINHERIT_FL)
++
+ /* 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 |\
+@@ -607,6 +614,8 @@ enum {
+ #define EXT4_IOC_RESIZE_FS _IOW('f', 16, __u64)
+ #define EXT4_IOC_SWAP_BOOT _IO('f', 17)
+ #define EXT4_IOC_PRECACHE_EXTENTS _IO('f', 18)
++#define EXT4_IOC_FSGETXATTR FS_IOC_FSGETXATTR
++#define EXT4_IOC_FSSETXATTR FS_IOC_FSSETXATTR
+
+ #if defined(__KERNEL__) && defined(CONFIG_COMPAT)
+ /*
+diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
+index 70c66d3..5857658 100644
+--- a/fs/ext4/ioctl.c
++++ b/fs/ext4/ioctl.c
+@@ -15,6 +15,7 @@
+ #include <linux/mount.h>
+ #include <linux/file.h>
+ #include <asm/uaccess.h>
++#include <linux/quotaops.h>
+ #include "ext4_jbd2.h"
+ #include "ext4.h"
+
+@@ -198,6 +199,239 @@ journal_err_out:
+ return err;
+ }
+
++static int ext4_ioctl_setflags(struct inode *inode,
++ unsigned int flags)
++{
++ struct ext4_inode_info *ei = EXT4_I(inode);
++ handle_t *handle = NULL;
++ int err = EPERM, migrate = 0;
++ struct ext4_iloc iloc;
++ unsigned int oldflags, mask, i;
++ unsigned int jflag;
++
++ /* Is it quota file? Do not allow user to mess with it */
++ if (IS_NOQUOTA(inode))
++ goto flags_out;
++
++ oldflags = ei->i_flags;
++
++ /* The JOURNAL_DATA flag is modifiable only by root */
++ jflag = flags & EXT4_JOURNAL_DATA_FL;
++
++ /*
++ * The IMMUTABLE and APPEND_ONLY flags can only be changed by
++ * the relevant capability.
++ *
++ * This test looks nicer. Thanks to Pauline Middelink
++ */
++ if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) {
++ if (!capable(CAP_LINUX_IMMUTABLE))
++ goto flags_out;
++ }
++
++ /*
++ * The JOURNAL_DATA flag can only be changed by
++ * the relevant capability.
++ */
++ if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) {
++ if (!capable(CAP_SYS_RESOURCE))
++ goto flags_out;
++ }
++ if ((flags ^ oldflags) & EXT4_EXTENTS_FL)
++ migrate = 1;
++
++ if (flags & EXT4_EOFBLOCKS_FL) {
++ /* we don't support adding EOFBLOCKS flag */
++ if (!(oldflags & EXT4_EOFBLOCKS_FL)) {
++ err = -EOPNOTSUPP;
++ goto flags_out;
++ }
++ } else if (oldflags & EXT4_EOFBLOCKS_FL)
++ ext4_truncate(inode);
++
++ handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
++ if (IS_ERR(handle)) {
++ err = PTR_ERR(handle);
++ goto flags_out;
++ }
++ if (IS_SYNC(inode))
++ ext4_handle_sync(handle);
++ err = ext4_reserve_inode_write(handle, inode, &iloc);
++ if (err)
++ goto flags_err;
++
++ for (i = 0, mask = 1; i < 32; i++, mask <<= 1) {
++ if (!(mask & EXT4_FL_USER_MODIFIABLE))
++ continue;
++ if (mask & flags)
++ ext4_set_inode_flag(inode, i);
++ else
++ ext4_clear_inode_flag(inode, i);
++ }
++
++ ext4_set_inode_flags(inode);
++ inode->i_ctime = ext4_current_time(inode);
++
++ err = ext4_mark_iloc_dirty(handle, inode, &iloc);
++flags_err:
++ ext4_journal_stop(handle);
++ if (err)
++ goto flags_out;
++
++ if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL))
++ err = ext4_change_inode_journal_flag(inode, jflag);
++ if (err)
++ goto flags_out;
++ if (migrate) {
++ if (flags & EXT4_EXTENTS_FL)
++ err = ext4_ext_migrate(inode);
++ else
++ err = ext4_ind_migrate(inode);
++ }
++
++flags_out:
++ return err;
++}
++
++#ifdef CONFIG_QUOTA
++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;
++ handle_t *handle;
++ kprojid_t kprojid;
++ struct ext4_iloc iloc;
++ struct ext4_inode *raw_inode;
++ struct dquot *transfer_to[EXT4_MAXQUOTAS] = { };
++
++ 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 = 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 */
++ if (IS_NOQUOTA(inode))
++ goto out_unlock;
++
++ err = ext4_get_inode_loc(inode, &iloc);
++ if (err)
++ goto out_unlock;
++
++ raw_inode = ext4_raw_inode(&iloc);
++ if (!EXT4_FITS_IN_INODE(raw_inode, ei, i_projid)) {
++ err = -EOVERFLOW;
++ brelse(iloc.bh);
++ goto out_unlock;
++ }
++ brelse(iloc.bh);
++
++ dquot_initialize(inode);
++
++ handle = ext4_journal_start(inode, EXT4_HT_QUOTA,
++ EXT4_QUOTA_INIT_BLOCKS(sb) +
++ EXT4_QUOTA_DEL_BLOCKS(sb) + 3);
++ if (IS_ERR(handle)) {
++ err = PTR_ERR(handle);
++ goto out_unlock;
++ }
++
++ err = ext4_reserve_inode_write(handle, inode, &iloc);
++ if (err)
++ goto out_stop;
++
++ 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)
++ goto out_dirty;
++ }
++
++ EXT4_I(inode)->i_projid = kprojid;
++ inode->i_ctime = ext4_current_time(inode);
++out_dirty:
++ rc = ext4_mark_iloc_dirty(handle, inode, &iloc);
++ if (!err)
++ err = rc;
++out_stop:
++ ext4_journal_stop(handle);
++out_unlock:
++ mutex_unlock(&inode->i_mutex);
++ mnt_drop_write_file(filp);
++ return err;
++}
++#else
++static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
++{
++ if (projid != EXT4_DEF_PROJID)
++ return -EOPNOTSUPP;
++ return 0;
++}
++#endif
++
++
++/* Transfer internal flags to xflags */
++static inline __u32 ext4_iflags_to_xflags(unsigned long iflags)
++{
++ __u32 xflags = 0;
++
++ if (iflags & EXT4_SYNC_FL)
++ xflags |= FS_XFLAG_SYNC;
++ if (iflags & EXT4_IMMUTABLE_FL)
++ xflags |= FS_XFLAG_IMMUTABLE;
++ if (iflags & EXT4_APPEND_FL)
++ xflags |= FS_XFLAG_APPEND;
++ if (iflags & EXT4_NODUMP_FL)
++ xflags |= FS_XFLAG_NODUMP;
++ if (iflags & EXT4_NOATIME_FL)
++ xflags |= FS_XFLAG_NOATIME;
++ if (iflags & EXT4_PROJINHERIT_FL)
++ xflags |= FS_XFLAG_PROJINHERIT;
++ return xflags;
++}
++
++/* Transfer xflags flags to internal */
++static inline unsigned long ext4_xflags_to_iflags(__u32 xflags)
++{
++ unsigned long iflags = 0;
++
++ if (xflags & FS_XFLAG_SYNC)
++ iflags |= EXT4_SYNC_FL;
++ if (xflags & FS_XFLAG_IMMUTABLE)
++ iflags |= EXT4_IMMUTABLE_FL;
++ if (xflags & FS_XFLAG_APPEND)
++ iflags |= EXT4_APPEND_FL;
++ if (xflags & FS_XFLAG_NODUMP)
++ iflags |= EXT4_NODUMP_FL;
++ if (xflags & FS_XFLAG_NOATIME)
++ iflags |= EXT4_NOATIME_FL;
++ if (xflags & FS_XFLAG_PROJINHERIT)
++ iflags |= EXT4_PROJINHERIT_FL;
++
++ return iflags;
++}
++
+ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+ {
+ struct inode *inode = file_inode(filp);
+@@ -213,11 +447,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: {
+- handle_t *handle = NULL;
+- int err, migrate = 0;
+- struct ext4_iloc iloc;
+- unsigned int oldflags, mask, i;
+- unsigned int jflag;
++ int err;
+
+ if (!inode_owner_or_capable(inode))
+ return -EACCES;
+@@ -231,89 +461,8 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+
+ flags = ext4_mask_flags(inode->i_mode, flags);
+
+- err = -EPERM;
+ mutex_lock(&inode->i_mutex);
+- /* Is it quota file? Do not allow user to mess with it */
+- if (IS_NOQUOTA(inode))
+- goto flags_out;
+-
+- oldflags = ei->i_flags;
+-
+- /* The JOURNAL_DATA flag is modifiable only by root */
+- jflag = flags & EXT4_JOURNAL_DATA_FL;
+-
+- /*
+- * The IMMUTABLE and APPEND_ONLY flags can only be changed by
+- * the relevant capability.
+- *
+- * This test looks nicer. Thanks to Pauline Middelink
+- */
+- if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) {
+- if (!capable(CAP_LINUX_IMMUTABLE))
+- goto flags_out;
+- }
+-
+- /*
+- * The JOURNAL_DATA flag can only be changed by
+- * the relevant capability.
+- */
+- if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) {
+- if (!capable(CAP_SYS_RESOURCE))
+- goto flags_out;
+- }
+- if ((flags ^ oldflags) & EXT4_EXTENTS_FL)
+- migrate = 1;
+-
+- if (flags & EXT4_EOFBLOCKS_FL) {
+- /* we don't support adding EOFBLOCKS flag */
+- if (!(oldflags & EXT4_EOFBLOCKS_FL)) {
+- err = -EOPNOTSUPP;
+- goto flags_out;
+- }
+- } else if (oldflags & EXT4_EOFBLOCKS_FL)
+- ext4_truncate(inode);
+-
+- handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
+- if (IS_ERR(handle)) {
+- err = PTR_ERR(handle);
+- goto flags_out;
+- }
+- if (IS_SYNC(inode))
+- ext4_handle_sync(handle);
+- err = ext4_reserve_inode_write(handle, inode, &iloc);
+- if (err)
+- goto flags_err;
+-
+- for (i = 0, mask = 1; i < 32; i++, mask <<= 1) {
+- if (!(mask & EXT4_FL_USER_MODIFIABLE))
+- continue;
+- if (mask & flags)
+- ext4_set_inode_flag(inode, i);
+- else
+- ext4_clear_inode_flag(inode, i);
+- }
+-
+- ext4_set_inode_flags(inode);
+- inode->i_ctime = ext4_current_time(inode);
+-
+- err = ext4_mark_iloc_dirty(handle, inode, &iloc);
+-flags_err:
+- ext4_journal_stop(handle);
+- if (err)
+- goto flags_out;
+-
+- if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL))
+- err = ext4_change_inode_journal_flag(inode, jflag);
+- if (err)
+- goto flags_out;
+- if (migrate) {
+- if (flags & EXT4_EXTENTS_FL)
+- err = ext4_ext_migrate(inode);
+- else
+- err = ext4_ind_migrate(inode);
+- }
+-
+-flags_out:
++ err = ext4_ioctl_setflags(inode, flags);
+ mutex_unlock(&inode->i_mutex);
+ mnt_drop_write_file(filp);
+ return err;
+@@ -622,6 +771,62 @@ resizefs_out:
+ }
+ case EXT4_IOC_PRECACHE_EXTENTS:
+ return ext4_ext_precache(inode);
++ case EXT4_IOC_FSGETXATTR:
++ {
++ struct fsxattr fa;
++ unsigned int flags;
++
++ memset(&fa, 0, sizeof(struct fsxattr));
++ ext4_get_inode_flags(ei);
++ flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
++ fa.fsx_xflags = ext4_iflags_to_xflags(flags);
++
++ if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
++ EXT4_FEATURE_RO_COMPAT_PROJECT)) {
++ fa.fsx_projid = (__u32)from_kprojid(&init_user_ns,
++ EXT4_I(inode)->i_projid);
++ }
++
++ if (copy_to_user((struct fsxattr __user *)arg,
++ &fa, sizeof(fa)))
++ return -EFAULT;
++ return 0;
++ }
++ case EXT4_IOC_FSSETXATTR:
++ {
++ struct fsxattr fa;
++ int err;
++
++ if (copy_from_user(&fa, (struct fsxattr __user *)arg,
++ sizeof(fa)))
++ return -EFAULT;
++
++ /* Make sure caller has proper permission */
++ if (!inode_owner_or_capable(inode))
++ return -EACCES;
++
++ err = mnt_want_write_file(filp);
++ if (err)
++ return err;
++
++ flags = ext4_xflags_to_iflags(fa.fsx_xflags);
++ flags = ext4_mask_flags(inode->i_mode, flags);
++
++ mutex_lock(&inode->i_mutex);
++ flags = (ei->i_flags & ~EXT4_FL_XFLAG_VISIBLE) |
++ (flags & EXT4_FL_XFLAG_VISIBLE);
++ err = ext4_ioctl_setflags(inode, flags);
++ mutex_unlock(&inode->i_mutex);
++ mnt_drop_write_file(filp);
++ if (err)
++ return err;
++
++ err = ext4_ioctl_setproject(filp, fa.fsx_projid);
++ if (err)
++ return err;
++
++ return 0;
++ }
+
+ default:
+ return -ENOTTY;
rhel7.2/ext4-dont-check-in-ro.patch
rhel7.2/ext4-dont-check-before-replay.patch
rhel7.2/ext4-remove-i_data_sem-from-xattr.patch
+rhel7/ext4-projid-ignore-maxquotas.patch
+rhel7/ext4-projid-feature-support.patch
+rhel7/ext4-projid-quotas.patch
+rhel7ext4-projid-xfs-ioctls.patch
rhel7/ext4_s_max_ext_tree_depth.patch
rhel7.2/ext4-release-bh-in-makeinxdir.patch
rhel7.2/ext4-remove-i_data_sem-from-xattr.patch
+rhel7/ext4-projid-ignore-maxquotas.patch
+rhel7/ext4-projid-feature-support.patch
+rhel7/ext4-projid-quotas.patch
+rhel7/ext4-projid-xfs-ioctls.patch
rhel7/ext4-mmp-brelse.patch
rhel7/ext4-jcb-optimization.patch
rhel7/ext4_s_max_ext_tree_depth.patch
+rhel7/ext4-projid-ignore-maxquotas.patch
+rhel7/ext4-projid-feature-support.patch
+rhel7/ext4-projid-quotas.patch
+rhel7/ext4-projid-xfs-ioctls.patch
--- /dev/null
+From 611406e29293c37b4a8771073030ccdaf0bd4fa5 Mon Sep 17 00:00:00 2001
+From: Li Xi <pkuelelixi@gmail.com>
+Subject: [PATCH] vfs: Add general support to enforce project quota limits
+
+This patch adds support for a new quota type PRJQUOTA for project quota
+enforcement. Also a new method get_projid() is added into dquot_operations
+structure.
+
+Signed-off-by: Li Xi <lixi@ddn.com>
+Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Jan Kara <jack@suse.cz>
+----
+
+diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
+index d7d5a0a..6b80f11 100644
+--- a/fs/quota/dquot.c
++++ b/fs/quota/dquot.c
+@@ -1152,8 +1152,8 @@ static int need_print_warning(struct dquot_warn *warn)
+ return uid_eq(current_fsuid(), warn->w_dq_id.uid);
+ case GRPQUOTA:
+ return in_group_p(warn->w_dq_id.gid);
+- case PRJQUOTA: /* Never taken... Just make gcc happy */
+- return 0;
++ case PRJQUOTA:
++ return 1;
+ }
+ return 0;
+ }
+@@ -1392,6 +1392,9 @@ static void __dquot_initialize(struct inode *inode, int type)
+ /* First get references to structures we might need. */
+ for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+ struct kqid qid;
++ kprojid_t projid;
++ int rc;
++
+ got[cnt] = NULL;
+ if (type != -1 && cnt != type)
+ continue;
+@@ -1402,6 +1405,10 @@ static void __dquot_initialize(struct inode *inode, int type)
+ */
+ if (inode->i_dquot[cnt])
+ continue;
++
++ if (!sb_has_quota_active(sb, cnt))
++ continue;
++
+ init_needed = 1;
+
+ switch (cnt) {
+@@ -1411,6 +1418,12 @@ static void __dquot_initialize(struct inode *inode, int type)
+ case GRPQUOTA:
+ qid = make_kqid_gid(inode->i_gid);
+ break;
++ case PRJQUOTA:
++ rc = inode->i_sb->dq_op->get_projid(inode, &projid);
++ if (rc)
++ continue;
++ qid = make_kqid_projid(projid);
++ break;
+ }
+ got[cnt] = dqget(sb, qid);
+ }
+@@ -2154,7 +2167,8 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
+ error = -EROFS;
+ goto out_fmt;
+ }
+- if (!sb->s_op->quota_write || !sb->s_op->quota_read) {
++ if (!sb->s_op->quota_write || !sb->s_op->quota_read ||
++ (type == PRJQUOTA && sb->dq_op->get_projid == NULL)) {
+ error = -EINVAL;
+ goto out_fmt;
+ }
+diff --git a/fs/quota/quotaio_v2.h b/fs/quota/quotaio_v2.h
+index f1966b4..4e95430 100644
+--- a/fs/quota/quotaio_v2.h
++++ b/fs/quota/quotaio_v2.h
+@@ -13,12 +13,14 @@
+ */
+ #define V2_INITQMAGICS {\
+ 0xd9c01f11, /* USRQUOTA */\
+- 0xd9c01927 /* GRPQUOTA */\
++ 0xd9c01927, /* GRPQUOTA */\
++ 0xd9c03f14, /* PRJQUOTA */\
+ }
+
+ #define V2_INITQVERSIONS {\
+ 1, /* USRQUOTA */\
+- 1 /* GRPQUOTA */\
++ 1, /* GRPQUOTA */\
++ 1, /* PRJQUOTA */\
+ }
+
+ /* First generic header */
+diff --git a/include/linux/quota.h b/include/linux/quota.h
+index 99932a5..0d20c39 100644
+--- a/include/linux/quota.h
++++ b/include/linux/quota.h
+@@ -52,6 +52,7 @@
+
+ #undef USRQUOTA
+ #undef GRPQUOTA
++#undef PRJQUOTA
+ enum quota_type {
+ USRQUOTA = 0, /* element used for user quotas */
+ GRPQUOTA = 1, /* element used for group quotas */
+@@ -314,6 +315,7 @@ struct dquot_operations {
+ /* get reserved quota for delayed alloc, value returned is managed by
+ * quota code only */
+ qsize_t *(*get_reserved_space) (struct inode *);
++ int (*get_projid) (struct inode *, kprojid_t *);/* Get project ID */
+ };
+
+ struct path;
+diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
+index 83d19df..418e9dd 100644
+--- a/include/uapi/linux/fs.h
++++ b/include/uapi/linux/fs.h
+@@ -58,6 +58,36 @@ struct inodes_stat_t {
+ int dummy[5]; /* padding for sysctl ABI compatibility */
+ };
+
++/*
++ * Structure for FS_IOC_FSGETXATTR and FS_IOC_FSSETXATTR.
++ */
++struct fsxattr {
++ __u32 fsx_xflags; /* xflags field value (get/set) */
++ __u32 fsx_extsize; /* extsize field value (get/set)*/
++ __u32 fsx_nextents; /* nextents field value (get) */
++ __u32 fsx_projid; /* project identifier (get/set) */
++ unsigned char fsx_pad[12];
++};
++#define HAVE_FSXATTR 1
++
++/*
++ * Flags for the fsx_xflags field
++ */
++#define FS_XFLAG_REALTIME 0x00000001 /* data in realtime volume */
++#define FS_XFLAG_PREALLOC 0x00000002 /* preallocated file extents */
++#define FS_XFLAG_IMMUTABLE 0x00000008 /* file cannot be modified */
++#define FS_XFLAG_APPEND 0x00000010 /* all writes append */
++#define FS_XFLAG_SYNC 0x00000020 /* all writes synchronous */
++#define FS_XFLAG_NOATIME 0x00000040 /* do not update access time */
++#define FS_XFLAG_NODUMP 0x00000080 /* do not include in backups */
++#define FS_XFLAG_RTINHERIT 0x00000100 /* create with rt bit set */
++#define FS_XFLAG_PROJINHERIT 0x00000200 /* create with parents projid */
++#define FS_XFLAG_NOSYMLINKS 0x00000400 /* disallow symlink creation */
++#define FS_XFLAG_EXTSIZE 0x00000800 /* extent size allocator hint */
++#define FS_XFLAG_EXTSZINHERIT 0x00001000 /* inherit inode extent size */
++#define FS_XFLAG_NODEFRAG 0x00002000 /* do not defragment */
++#define FS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */
++#define FS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */
+
+ #define NR_FILE 8192 /* this can well be larger on a larger system */
+
+@@ -163,6 +193,8 @@ struct inodes_stat_t {
+ #define FS_IOC_GETVERSION _IOR('v', 1, long)
+ #define FS_IOC_SETVERSION _IOW('v', 2, long)
+ #define FS_IOC_FIEMAP _IOWR('f', 11, struct fiemap)
++#define FS_IOC_FSGETXATTR _IOR('X', 31, struct fsxattr)
++#define FS_IOC_FSSETXATTR _IOW('X', 32, struct fsxattr)
+ #define FS_IOC32_GETFLAGS _IOR('f', 1, int)
+ #define FS_IOC32_SETFLAGS _IOW('f', 2, int)
+ #define FS_IOC32_GETVERSION _IOR('v', 1, int)
+@@ -195,6 +227,7 @@ struct inodes_stat_t {
+ #define FS_EXTENT_FL 0x00080000 /* Extents */
+ #define FS_DIRECTIO_FL 0x00100000 /* Use direct i/o */
+ #define FS_NOCOW_FL 0x00800000 /* Do not cow file */
++#define FS_PROJINHERIT_FL 0x20000000 /* Create with parents projid */
+ #define FS_RESERVED_FL 0x80000000 /* reserved for ext2 lib */
+
+ #define FS_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */
+diff --git a/include/uapi/linux/quota.h b/include/uapi/linux/quota.h
+index 3b6cfbe..b2d9486 100644
+--- a/include/uapi/linux/quota.h
++++ b/include/uapi/linux/quota.h
+@@ -36,11 +36,12 @@
+ #include <linux/errno.h>
+ #include <linux/types.h>
+
+-#define __DQUOT_VERSION__ "dquot_6.5.2"
++#define __DQUOT_VERSION__ "dquot_6.6.0"
+
+-#define MAXQUOTAS 2
++#define MAXQUOTAS 3
+ #define USRQUOTA 0 /* element used for user quotas */
+ #define GRPQUOTA 1 /* element used for group quotas */
++#define PRJQUOTA 2 /* element used for project quotas */
+
+ /*
+ * Definitions for the default names of the quotas files.
+@@ -48,6 +49,7 @@
+ #define INITQFNAMES { \
+ "user", /* USRQUOTA */ \
+ "group", /* GRPQUOTA */ \
++ "project", /* PRJQUOTA */ \
+ "undefined", \
+ };
+
dev_read_only-3.7.patch
blkdev_tunables-3.8.patch
jbd2-fix-j_list_lock-unlock-3.10-rhel7.patch
-
+vfs-project-quotas-rhel7.patch
sync
echo checking size of lov_objid for ost index $i
- LOV_OBJID_SIZE=$(do_facet mds1 "$DEBUGFS -R 'stat lov_objid' $mdsdev 2>/dev/null" | grep ^User | awk '{print $6}')
+ LOV_OBJID_SIZE=$(do_facet mds1 "$DEBUGFS -R 'stat lov_objid' $mdsdev 2>/dev/null" |
+ grep ^User | awk -F 'Size: ' '{print $2}')
if [ "$LOV_OBJID_SIZE" != $(lov_objid_size $i) ]; then
error "lov_objid size has to be $(lov_objid_size $i), not $LOV_OBJID_SIZE"
else