Whamcloud - gitweb
LU-4017 ldiskfs: add project quota support 70/17770/27
authorWang Shilong <wshilong@ddn.com>
Thu, 31 Dec 2015 11:51:05 +0000 (19:51 +0800)
committerOleg Drokin <oleg.drokin@intel.com>
Thu, 13 Apr 2017 06:19:23 +0000 (06:19 +0000)
Pick following patchs from upstream:

commit 847aac644e92e5624f2c153bab409bf713d5ff9a
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>
commit 334e580a6f97e2e84d1c19a8679603956acaa622
fs: XFS_IOC_FS[SG]SETXATTR to FS_IOC_FS[SG]ETXATTR promotion
Hoist the ioctl definitions for the XFS_IOC_FS[SG]SETXATTR
API from fs/xfs/libxfs/xfs_fs.h to include/uapi/linux/fs.h
so that the ioctls can be used by all filesystems,
not just XFS. This enables (initially) ext4 to use
the ioctl to set project IDs on inodes.

Based-on-patch-from: Li Xi <lixi@ddn.com>
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Above two chages are wrapped into vfs-project-quotas-rhel7.patch

commit 040cb3786d9b25293b8b0b05b90da0f871e1eb9b
ext4: adds project ID support

Signed-off-by: Li Xi <lixi@ddn.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Reviewed-by: Andreas Dilger <adilger@dilger.ca>
Reviewed-by: Jan Kara <jack@suse.cz>
commit 689c958cbe6be4f211b40747951a3ba2c73b6715
ext4: add project quota support
This patch adds mount options for enabling/disabling project quota
accounting and enforcement. A new specific inode is also used for
project quota accounting.

[Includes fix from Dan Carpenter to correct error checking from dqget(). ]

Signed-off-by: Li Xi <lixi@ddn.com>
Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Reviewed-by: Andreas Dilger <adilger@dilger.ca>
Reviewed-by: Jan Kara <jack@suse.cz>
commit 9b7365fc1c82038faa52d56173b20221cf422cbe
ext4: add FS_IOC_FSSETXATTR/FS_IOC_FSGETXATTR interface support
This patch adds FS_IOC_FSSETXATTR/FS_IOC_FSGETXATTR ioctl interface
support for ext4. The interface is kept consistent with
XFS_IOC_FSGETXATTR/XFS_IOC_FSGETXATTR.

Signed-off-by: Li Xi <lixi@ddn.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Reviewed-by: Andreas Dilger <adilger@dilger.ca>
Reviewed-by: Jan Kara <jack@suse.cz>
This patch add ldiskfs project quota support
Did following adjustment from original patches:

1.adds padding structure to superblock, so that @s_prj_num is
in the same position of superblock from upstream.

2.Patch aslo disable kabi check for rhel7, since
any of vfs patch's include files change will break the check

Also fix conf-sanity: test_55, because now debugfs output
Project ID, we should output file size.

Signed-off-by: Li Xi <lixi@ddn.com>
Signed-off-by: Wang Shilong <wshilong@ddn.com>
Change-Id: I2392f402d9853af969e4cd37318a83f2c4941c3e
Reviewed-on: https://review.whamcloud.com/17770
Reviewed-by: Niu Yawei <yawei.niu@intel.com>
Tested-by: Jenkins
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: Oleg Drokin <oleg.drokin@intel.com>
contrib/lbuild/lbuild-rhel7
ldiskfs/kernel_patches/patches/rhel7/ext4-projid-feature-support.patch [new file with mode: 0644]
ldiskfs/kernel_patches/patches/rhel7/ext4-projid-ignore-maxquotas.patch [new file with mode: 0644]
ldiskfs/kernel_patches/patches/rhel7/ext4-projid-quotas.patch [new file with mode: 0644]
ldiskfs/kernel_patches/patches/rhel7/ext4-projid-xfs-ioctls.patch [new file with mode: 0644]
ldiskfs/kernel_patches/series/ldiskfs-3.10-rhel7.2.series
ldiskfs/kernel_patches/series/ldiskfs-3.10-rhel7.3.series
ldiskfs/kernel_patches/series/ldiskfs-3.10-rhel7.series
lustre/kernel_patches/patches/vfs-project-quotas-rhel7.patch [new file with mode: 0644]
lustre/kernel_patches/series/3.10-rhel7.series
lustre/tests/conf-sanity.sh

index d831430..68c2400 100644 (file)
@@ -8,7 +8,7 @@ BUILD_GEN+=".0"
 
 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"
diff --git a/ldiskfs/kernel_patches/patches/rhel7/ext4-projid-feature-support.patch b/ldiskfs/kernel_patches/patches/rhel7/ext4-projid-feature-support.patch
new file mode 100644 (file)
index 0000000..66708f7
--- /dev/null
@@ -0,0 +1,238 @@
+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 = {
diff --git a/ldiskfs/kernel_patches/patches/rhel7/ext4-projid-ignore-maxquotas.patch b/ldiskfs/kernel_patches/patches/rhel7/ext4-projid-ignore-maxquotas.patch
new file mode 100644 (file)
index 0000000..dfde66f
--- /dev/null
@@ -0,0 +1,141 @@
+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);
diff --git a/ldiskfs/kernel_patches/patches/rhel7/ext4-projid-quotas.patch b/ldiskfs/kernel_patches/patches/rhel7/ext4-projid-quotas.patch
new file mode 100644 (file)
index 0000000..d0b3cef
--- /dev/null
@@ -0,0 +1,144 @@
+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;
diff --git a/ldiskfs/kernel_patches/patches/rhel7/ext4-projid-xfs-ioctls.patch b/ldiskfs/kernel_patches/patches/rhel7/ext4-projid-xfs-ioctls.patch
new file mode 100644 (file)
index 0000000..dd9e8cb
--- /dev/null
@@ -0,0 +1,446 @@
+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;
index 5784db2..5b728e3 100644 (file)
@@ -25,3 +25,7 @@ rhel7.2/ext4-release-bh-in-makeinxdir.patch
 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
index 4ce3c64..3103ded 100644 (file)
@@ -23,3 +23,7 @@ rhel7/ext4-jcb-optimization.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
index 926f63a..86476d2 100644 (file)
@@ -21,3 +21,7 @@ rhel7/ext4-give-warning-with-dir-htree-growing.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
diff --git a/lustre/kernel_patches/patches/vfs-project-quotas-rhel7.patch b/lustre/kernel_patches/patches/vfs-project-quotas-rhel7.patch
new file mode 100644 (file)
index 0000000..493fc92
--- /dev/null
@@ -0,0 +1,199 @@
+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", \
+ };
index f6a19d4..0cdbc20 100644 (file)
@@ -2,4 +2,4 @@ raid5-mmp-unplug-dev-3.7.patch
 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
index 9d28eaf..2b70ab4 100755 (executable)
@@ -4133,7 +4133,8 @@ test_55() {
                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