From f15995b8e52bafabe55506ad2e12c8a64a373948 Mon Sep 17 00:00:00 2001 From: Artem Blagodarenko Date: Thu, 23 May 2019 16:10:48 +0300 Subject: [PATCH] LU-12335 ldiskfs: fixed size preallocation table MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Preallocation table read/write code is racy. There is a possibility of accessing memory outside of allocated table. Make preallocation table fixed size. Array with 64 long int values are enough for any configuration and don’t need much memory. With such array races are not possible. Signed-off-by: Artem Blagodarenko Reviewed-by: Alexander Boyko Reviewed-by: Alexander Zarochentsev Tested-by: Elena Gryaznova Cray-bug-id: LUS-7218 Change-Id: Ie089ac47c2610717a00d6cea9121ec08879a159c Reviewed-on: https://review.whamcloud.com/34950 Tested-by: Jenkins Reviewed-by: Alexandr Boyko Reviewed-by: Andreas Dilger Tested-by: Maloo Reviewed-by: Oleg Drokin --- .../patches/rhel7.4/ext4-prealloc.patch | 281 ++++++++++----------- .../patches/rhel7/ext4-projid-quotas.patch | 78 +++--- 2 files changed, 179 insertions(+), 180 deletions(-) diff --git a/ldiskfs/kernel_patches/patches/rhel7.4/ext4-prealloc.patch b/ldiskfs/kernel_patches/patches/rhel7.4/ext4-prealloc.patch index b35e038..cb3e1d0 100644 --- a/ldiskfs/kernel_patches/patches/rhel7.4/ext4-prealloc.patch +++ b/ldiskfs/kernel_patches/patches/rhel7.4/ext4-prealloc.patch @@ -1,8 +1,17 @@ -Index: linux-3.10.0-514.16.1.el7.x86_64/fs/ext4/ext4.h +Index: linux-stage/fs/ext4/ext4.h =================================================================== ---- linux-3.10.0-514.16.1.el7.x86_64.orig/fs/ext4/ext4.h -+++ linux-3.10.0-514.16.1.el7.x86_64/fs/ext4/ext4.h -@@ -1270,11 +1270,14 @@ struct ext4_sb_info { +--- linux-stage.orig/fs/ext4/ext4.h ++++ linux-stage/fs/ext4/ext4.h +@@ -1242,6 +1242,8 @@ struct ext4_super_block { + #define EXT4_MF_MNTDIR_SAMPLED 0x0001 + #define EXT4_MF_FS_ABORTED 0x0002 /* Fatal error detected */ + ++#define EXT4_MAX_PREALLOC_TABLE 64 ++ + /* + * fourth extended-fs super-block data in memory + */ +@@ -1331,11 +1333,13 @@ struct ext4_sb_info { /* tunables */ unsigned long s_stripe; @@ -14,101 +23,84 @@ Index: linux-3.10.0-514.16.1.el7.x86_64/fs/ext4/ext4.h unsigned int s_mb_stats; unsigned int s_mb_order2_reqs; + unsigned long *s_mb_prealloc_table; -+ unsigned long s_mb_prealloc_table_size; unsigned int s_mb_group_prealloc; unsigned int s_max_dir_size_kb; /* where last allocation was done - for stream allocation */ -Index: linux-3.10.0-514.16.1.el7.x86_64/fs/ext4/mballoc.c +Index: linux-stage/fs/ext4/mballoc.c =================================================================== ---- linux-3.10.0-514.16.1.el7.x86_64.orig/fs/ext4/mballoc.c -+++ linux-3.10.0-514.16.1.el7.x86_64/fs/ext4/mballoc.c -@@ -1862,6 +1862,26 @@ int ext4_mb_find_by_goal(struct ext4_all - return 0; - } - -+static int ext4_mb_prealloc_table_add(struct ext4_sb_info *sbi, int value) -+{ -+ int i; -+ -+ if (value > (sbi->s_blocks_per_group - 1 - 1 - sbi->s_itb_per_group)) -+ return -1; -+ -+ for (i = 0; i < sbi->s_mb_prealloc_table_size; i++) { -+ if (sbi->s_mb_prealloc_table[i] == 0) { -+ sbi->s_mb_prealloc_table[i] = value; -+ return 0; -+ } -+ -+ /* they should add values in order */ -+ if (value <= sbi->s_mb_prealloc_table[i]) -+ return -1; -+ } -+ return -1; -+} -+ - /* - * The routine scans buddy structures (not bitmap!) from given order - * to max order and tries to find big enough chunk to satisfy the req -@@ -2301,6 +2321,90 @@ static const struct seq_operations ext4_ +--- linux-stage.orig/fs/ext4/mballoc.c ++++ linux-stage/fs/ext4/mballoc.c +@@ -2303,6 +2303,102 @@ static const struct seq_operations ext4_ .show = ext4_mb_seq_groups_show, }; +#define EXT4_MB_PREALLOC_TABLE "prealloc_table" + -+static ssize_t ext4_mb_prealloc_table_proc_write(struct file *file, -+ const char __user *buf, -+ size_t cnt, loff_t *pos) ++static int ext4_mb_check_and_update_prealloc(struct ext4_sb_info *sbi, ++ char *str, size_t cnt, ++ int update) +{ -+ struct ext4_sb_info *sbi = EXT4_SB(PDE_DATA(file_inode(file))); + unsigned long value; + unsigned long prev = 0; -+ char str[128]; + char *cur; ++ char *next; + char *end; -+ unsigned long *new_table; + int num = 0; -+ int i = 0; -+ -+ if (cnt >= sizeof(str)) -+ return -EINVAL; -+ if (copy_from_user(str, buf, cnt)) -+ return -EFAULT; + -+ num = 0; + cur = str; + end = str + cnt; + while (cur < end) { -+ while ((cur < end) && (*cur == ' ')) -+ cur++; -+ value = simple_strtol(cur, &cur, 0); ++ while ((cur < end) && (*cur == ' ')) cur++; ++ value = simple_strtol(cur, &next, 0); + if (value == 0) + break; ++ if (cur == next) ++ return -EINVAL; ++ ++ cur = next; ++ ++ if (value > (sbi->s_blocks_per_group - 1 - 1 - sbi->s_itb_per_group)) ++ return -EINVAL; ++ ++ /* they should add values in order */ + if (value <= prev) + return -EINVAL; ++ ++ if (update) ++ sbi->s_mb_prealloc_table[num] = value; ++ + prev = value; + num++; + } + -+ new_table = kmalloc(num * sizeof(*new_table), GFP_KERNEL); -+ if (new_table == NULL) -+ return -ENOMEM; -+ kfree(sbi->s_mb_prealloc_table); -+ memset(new_table, 0, num * sizeof(*new_table)); -+ sbi->s_mb_prealloc_table = new_table; -+ sbi->s_mb_prealloc_table_size = num; -+ cur = str; -+ end = str + cnt; -+ while (cur < end && i < num) { -+ while (cur < end && *cur == ' ') -+ cur++; -+ value = simple_strtol(cur, &cur, 0); -+ if (ext4_mb_prealloc_table_add(sbi, value) == 0) -+ ++i; -+ } -+ if (i != num) -+ sbi->s_mb_prealloc_table_size = i; ++ if (num > EXT4_MAX_PREALLOC_TABLE - 1) ++ return -EOVERFLOW; ++ ++ if (update) ++ sbi->s_mb_prealloc_table[num] = 0; + -+ return cnt; ++ return 0; ++} ++ ++static ssize_t ext4_mb_prealloc_table_proc_write(struct file *file, ++ const char __user *buf, ++ size_t cnt, loff_t *pos) ++{ ++ struct ext4_sb_info *sbi = EXT4_SB(PDE_DATA(file_inode(file))); ++ char str[128]; ++ int rc; ++ ++ if (cnt >= sizeof(str)) ++ return -EINVAL; ++ if (copy_from_user(str, buf, cnt)) ++ return -EFAULT; ++ ++ rc = ext4_mb_check_and_update_prealloc(sbi, str, cnt, 0); ++ if (rc) ++ return rc; ++ ++ rc = ext4_mb_check_and_update_prealloc(sbi, str, cnt, 1); ++ return rc ? rc : cnt; +} + +static int mb_prealloc_table_seq_show(struct seq_file *m, void *v) @@ -116,7 +108,8 @@ Index: linux-3.10.0-514.16.1.el7.x86_64/fs/ext4/mballoc.c + struct ext4_sb_info *sbi = EXT4_SB(m->private); + int i; + -+ for (i = 0; i < sbi->s_mb_prealloc_table_size; i++) ++ for (i = 0; i < EXT4_MAX_PREALLOC_TABLE && ++ sbi->s_mb_prealloc_table[i] != 0; i++) + seq_printf(m, "%ld ", sbi->s_mb_prealloc_table[i]); + seq_printf(m, "\n"); + @@ -140,7 +133,7 @@ Index: linux-3.10.0-514.16.1.el7.x86_64/fs/ext4/mballoc.c static int ext4_mb_seq_groups_open(struct inode *inode, struct file *file) { struct super_block *sb = PDE_DATA(inode); -@@ -2550,7 +2657,7 @@ static int ext4_groupinfo_create_slab(si +@@ -2552,7 +2648,7 @@ static int ext4_groupinfo_create_slab(si int ext4_mb_init(struct super_block *sb) { struct ext4_sb_info *sbi = EXT4_SB(sb); @@ -149,7 +142,7 @@ Index: linux-3.10.0-514.16.1.el7.x86_64/fs/ext4/mballoc.c unsigned offset, offset_incr; unsigned max; int ret; -@@ -2595,7 +2702,6 @@ int ext4_mb_init(struct super_block *sb) +@@ -2599,7 +2695,6 @@ int ext4_mb_init(struct super_block *sb) sbi->s_mb_max_to_scan = MB_DEFAULT_MAX_TO_SCAN; sbi->s_mb_min_to_scan = MB_DEFAULT_MIN_TO_SCAN; sbi->s_mb_stats = MB_DEFAULT_STATS; @@ -157,7 +150,7 @@ Index: linux-3.10.0-514.16.1.el7.x86_64/fs/ext4/mballoc.c sbi->s_mb_order2_reqs = MB_DEFAULT_ORDER2_REQS; /* * The default group preallocation is 512, which for 4k block -@@ -2619,9 +2725,47 @@ int ext4_mb_init(struct super_block *sb) +@@ -2623,9 +2718,29 @@ int ext4_mb_init(struct super_block *sb) * RAID stripe size so that preallocations don't fragment * the stripes. */ @@ -165,42 +158,24 @@ Index: linux-3.10.0-514.16.1.el7.x86_64/fs/ext4/mballoc.c - sbi->s_mb_group_prealloc = roundup( - sbi->s_mb_group_prealloc, sbi->s_stripe); + -+ if (sbi->s_stripe == 0) { -+ sbi->s_mb_prealloc_table_size = 10; -+ i = sbi->s_mb_prealloc_table_size * sizeof(unsigned long); -+ sbi->s_mb_prealloc_table = kmalloc(i, GFP_NOFS); -+ if (sbi->s_mb_prealloc_table == NULL) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ memset(sbi->s_mb_prealloc_table, 0, i); ++ /* Allocate table once */ ++ sbi->s_mb_prealloc_table = kzalloc( ++ EXT4_MAX_PREALLOC_TABLE * sizeof(unsigned long), GFP_NOFS); ++ if (sbi->s_mb_prealloc_table == NULL) { ++ ret = -ENOMEM; ++ goto out; ++ } + -+ for (k = 0, l = 4; k <= 9; ++k, l *= 2) { -+ if (ext4_mb_prealloc_table_add(sbi, l) < 0) { -+ sbi->s_mb_prealloc_table_size = k; -+ break; -+ } -+ } ++ if (sbi->s_stripe == 0) { ++ for (k = 0, l = 4; k <= 9; ++k, l *= 2) ++ sbi->s_mb_prealloc_table[k] = l; + + sbi->s_mb_small_req = 256; + sbi->s_mb_large_req = 1024; + sbi->s_mb_group_prealloc = 512; + } else { -+ sbi->s_mb_prealloc_table_size = 3; -+ i = sbi->s_mb_prealloc_table_size * sizeof(unsigned long); -+ sbi->s_mb_prealloc_table = kmalloc(i, GFP_NOFS); -+ if (sbi->s_mb_prealloc_table == NULL) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ memset(sbi->s_mb_prealloc_table, 0, i); -+ -+ for (k = 0, l = sbi->s_stripe; k <= 2; ++k, l *= 2) { -+ if (ext4_mb_prealloc_table_add(sbi, l) < 0) { -+ sbi->s_mb_prealloc_table_size = k; -+ break; -+ } -+ } ++ for (k = 0, l = sbi->s_stripe; k <= 2; ++k, l *= 2) ++ sbi->s_mb_prealloc_table[k] = l; + + sbi->s_mb_small_req = sbi->s_stripe; + sbi->s_mb_large_req = sbi->s_stripe * 8; @@ -208,7 +183,7 @@ Index: linux-3.10.0-514.16.1.el7.x86_64/fs/ext4/mballoc.c } sbi->s_locality_groups = alloc_percpu(struct ext4_locality_group); -@@ -2643,9 +2787,13 @@ int ext4_mb_init(struct super_block *sb) +@@ -2647,9 +2762,13 @@ int ext4_mb_init(struct super_block *sb) if (ret != 0) goto out_free_locality_groups; @@ -223,7 +198,7 @@ Index: linux-3.10.0-514.16.1.el7.x86_64/fs/ext4/mballoc.c return 0; -@@ -2653,6 +2801,7 @@ out_free_locality_groups: +@@ -2657,6 +2776,7 @@ out_free_locality_groups: free_percpu(sbi->s_locality_groups); sbi->s_locality_groups = NULL; out: @@ -231,7 +206,7 @@ Index: linux-3.10.0-514.16.1.el7.x86_64/fs/ext4/mballoc.c kfree(sbi->s_mb_offsets); sbi->s_mb_offsets = NULL; kfree(sbi->s_mb_maxs); -@@ -2687,8 +2836,10 @@ int ext4_mb_release(struct super_block * +@@ -2691,8 +2811,10 @@ int ext4_mb_release(struct super_block * struct ext4_sb_info *sbi = EXT4_SB(sb); struct kmem_cache *cachep = get_groupinfo_cache(sb->s_blocksize_bits); @@ -243,7 +218,15 @@ Index: linux-3.10.0-514.16.1.el7.x86_64/fs/ext4/mballoc.c if (sbi->s_group_info) { for (i = 0; i < ngroups; i++) { -@@ -3000,9 +3151,9 @@ ext4_mb_normalize_request(struct ext4_al +@@ -2877,7 +2999,6 @@ ext4_mb_mark_diskspace_used(struct ext4_ + int err, len; + + BUG_ON(ac->ac_status != AC_STATUS_FOUND); +- BUG_ON(ac->ac_b_ex.fe_len <= 0); + + sb = ac->ac_sb; + sbi = EXT4_SB(sb); +@@ -3004,13 +3125,14 @@ ext4_mb_normalize_request(struct ext4_al struct ext4_allocation_request *ar) { struct ext4_sb_info *sbi = EXT4_SB(ac->ac_sb); @@ -255,7 +238,12 @@ Index: linux-3.10.0-514.16.1.el7.x86_64/fs/ext4/mballoc.c loff_t orig_size __maybe_unused; ext4_lblk_t start; struct ext4_inode_info *ei = EXT4_I(ac->ac_inode); -@@ -3035,51 +3186,34 @@ ext4_mb_normalize_request(struct ext4_al + struct ext4_prealloc_space *pa; ++ unsigned long value, last_non_zero; + + /* do normalize only data requests, metadata requests + do not need preallocation */ +@@ -3039,51 +3161,46 @@ ext4_mb_normalize_request(struct ext4_al size = size << bsbits; if (size < i_size_read(ac->ac_inode)) size = i_size_read(ac->ac_inode); @@ -265,17 +253,17 @@ Index: linux-3.10.0-514.16.1.el7.x86_64/fs/ext4/mballoc.c - /* max size of free chunks */ - max = 2 << bsbits; + start = wind = 0; ++ value = last_non_zero = 0; -#define NRL_CHECK_SIZE(req, size, max, chunk_size) \ - (req <= (size) || max <= (chunk_size)) + /* let's choose preallocation window depending on file size */ -+ for (i = 0; i < sbi->s_mb_prealloc_table_size; i++) { -+ if (size <= sbi->s_mb_prealloc_table[i]) { -+ wind = sbi->s_mb_prealloc_table[i]; ++ for (i = 0; i < EXT4_MAX_PREALLOC_TABLE; i++) { ++ value = sbi->s_mb_prealloc_table[i]; ++ if (value == 0) + break; -+ } -+ } -+ size = wind; ++ else ++ last_non_zero = value; - /* first, try to predict filesize */ - /* XXX: should this table be tunable? */ @@ -307,31 +295,42 @@ Index: linux-3.10.0-514.16.1.el7.x86_64/fs/ext4/mballoc.c - start_off = ((loff_t)ac->ac_o_ex.fe_logical >> - (23 - bsbits)) << 23; - size = 8 * 1024 * 1024; -- } else { ++ if (size <= value) { ++ wind = value; ++ break; ++ } ++ } ++ ++ if (wind == 0) { ++ if (last_non_zero != 0) { ++ __u64 tstart, tend; ++ /* file is quite large, we now preallocate with ++ * the biggest configured window with regart to ++ * logical offset */ ++ wind = last_non_zero; ++ tstart = ac->ac_o_ex.fe_logical; ++ do_div(tstart, wind); ++ start = tstart * wind; ++ tend = ac->ac_o_ex.fe_logical + ac->ac_o_ex.fe_len - 1; ++ do_div(tend, wind); ++ tend = tend * wind + wind; ++ size = tend - start; ++ } + } else { - start_off = (loff_t) ac->ac_o_ex.fe_logical << bsbits; - size = (loff_t) EXT4_C2B(EXT4_SB(ac->ac_sb), - ac->ac_o_ex.fe_len) << bsbits; -+ if (wind == 0) { -+ __u64 tstart, tend; -+ /* file is quite large, we now preallocate with -+ * the biggest configured window with regart to -+ * logical offset */ -+ wind = sbi->s_mb_prealloc_table[i - 1]; -+ tstart = ac->ac_o_ex.fe_logical; -+ do_div(tstart, wind); -+ start = tstart * wind; -+ tend = ac->ac_o_ex.fe_logical + ac->ac_o_ex.fe_len - 1; -+ do_div(tend, wind); -+ tend = tend * wind + wind; -+ size = tend - start; ++ size = wind; } - size = size >> bsbits; - start = start_off >> bsbits; ++ ++ + orig_size = size; /* don't cover already allocated blocks in selected range */ if (ar->pleft && start <= ar->lleft) { -@@ -3154,7 +3288,6 @@ ext4_mb_normalize_request(struct ext4_al +@@ -3165,7 +3282,6 @@ ext4_mb_normalize_request(struct ext4_al (unsigned long) ac->ac_o_ex.fe_logical); BUG(); } @@ -339,7 +338,7 @@ Index: linux-3.10.0-514.16.1.el7.x86_64/fs/ext4/mballoc.c /* now prepare goal request */ -@@ -4119,11 +4252,19 @@ static void ext4_mb_group_or_file(struct +@@ -4130,11 +4246,19 @@ static void ext4_mb_group_or_file(struct /* don't use group allocation for large files */ size = max(size, isize); @@ -360,11 +359,11 @@ Index: linux-3.10.0-514.16.1.el7.x86_64/fs/ext4/mballoc.c BUG_ON(ac->ac_lg != NULL); /* * locality group prealloc space are per cpu. The reason for having -Index: linux-3.10.0-514.16.1.el7.x86_64/fs/ext4/super.c +Index: linux-stage/fs/ext4/super.c =================================================================== ---- linux-3.10.0-514.16.1.el7.x86_64.orig/fs/ext4/super.c -+++ linux-3.10.0-514.16.1.el7.x86_64/fs/ext4/super.c -@@ -2672,7 +2672,8 @@ EXT4_RW_ATTR_SBI_UI(mb_stats, s_mb_stats +--- linux-stage.orig/fs/ext4/super.c ++++ linux-stage/fs/ext4/super.c +@@ -2708,7 +2708,8 @@ EXT4_RW_ATTR_SBI_UI(mb_stats, s_mb_stats EXT4_RW_ATTR_SBI_UI(mb_max_to_scan, s_mb_max_to_scan); EXT4_RW_ATTR_SBI_UI(mb_min_to_scan, s_mb_min_to_scan); EXT4_RW_ATTR_SBI_UI(mb_order2_req, s_mb_order2_reqs); @@ -374,7 +373,7 @@ Index: linux-3.10.0-514.16.1.el7.x86_64/fs/ext4/super.c EXT4_RW_ATTR_SBI_UI(mb_group_prealloc, s_mb_group_prealloc); EXT4_DEPRECATED_ATTR(max_writeback_mb_bump, 128); EXT4_RW_ATTR_SBI_UI(extent_max_zeroout_kb, s_extent_max_zeroout_kb); -@@ -2698,7 +2699,8 @@ static struct attribute *ext4_attrs[] = +@@ -2734,7 +2735,8 @@ static struct attribute *ext4_attrs[] = ATTR_LIST(mb_max_to_scan), ATTR_LIST(mb_min_to_scan), ATTR_LIST(mb_order2_req), @@ -384,11 +383,11 @@ Index: linux-3.10.0-514.16.1.el7.x86_64/fs/ext4/super.c ATTR_LIST(mb_group_prealloc), ATTR_LIST(max_writeback_mb_bump), ATTR_LIST(extent_max_zeroout_kb), -Index: linux-3.10.0-514.16.1.el7.x86_64/fs/ext4/inode.c +Index: linux-stage/fs/ext4/inode.c =================================================================== ---- linux-3.10.0-514.16.1.el7.x86_64.orig/fs/ext4/inode.c -+++ linux-3.10.0-514.16.1.el7.x86_64/fs/ext4/inode.c -@@ -2399,6 +2399,9 @@ static int ext4_writepages(struct addres +--- linux-stage.orig/fs/ext4/inode.c ++++ linux-stage/fs/ext4/inode.c +@@ -2457,6 +2457,9 @@ static int ext4_writepages(struct addres ext4_journal_stop(handle); } diff --git a/ldiskfs/kernel_patches/patches/rhel7/ext4-projid-quotas.patch b/ldiskfs/kernel_patches/patches/rhel7/ext4-projid-quotas.patch index d0b3cef..d0b7b25 100644 --- a/ldiskfs/kernel_patches/patches/rhel7/ext4-projid-quotas.patch +++ b/ldiskfs/kernel_patches/patches/rhel7/ext4-projid-quotas.patch @@ -1,32 +1,8 @@ -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, +Index: linux-stage/fs/ext4/inode.c +=================================================================== +--- linux-stage.orig/fs/ext4/inode.c ++++ linux-stage/fs/ext4/inode.c +@@ -4195,7 +4195,10 @@ static inline void ext4_iget_extra_inode int ext4_get_projid(struct inode *inode, kprojid_t *projid) { @@ -38,11 +14,11 @@ index 34877ac..9f38b3f 100644 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, +Index: linux-stage/fs/ext4/super.c +=================================================================== +--- linux-stage.orig/fs/ext4/super.c ++++ linux-stage/fs/ext4/super.c +@@ -1085,8 +1085,8 @@ static int bdev_try_to_free_page(struct } #ifdef CONFIG_QUOTA @@ -53,7 +29,7 @@ index 8189081..6a9d397 100644 static int ext4_write_dquot(struct dquot *dquot); static int ext4_acquire_dquot(struct dquot *dquot); -@@ -5101,6 +5101,48 @@ restore_opts: +@@ -5234,6 +5234,48 @@ restore_opts: return err; } @@ -102,7 +78,7 @@ index 8189081..6a9d397 100644 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) +@@ -5242,6 +5284,7 @@ static int ext4_statfs(struct dentry *de ext4_fsblk_t overhead = 0, resv_blocks; u64 fsid; s64 bfree; @@ -110,7 +86,7 @@ index 8189081..6a9d397 100644 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) +@@ -5266,6 +5309,11 @@ static int ext4_statfs(struct dentry *de buf->f_fsid.val[0] = fsid & 0xFFFFFFFFUL; buf->f_fsid.val[1] = (fsid >> 32) & 0xFFFFFFFFUL; @@ -122,7 +98,7 @@ index 8189081..6a9d397 100644 return 0; } -@@ -5297,7 +5345,8 @@ static int ext4_quota_enable(struct super_block *sb, int type, int format_id, +@@ -5448,7 +5496,8 @@ static int ext4_quota_enable(struct supe struct inode *qf_inode; unsigned long qf_inums[EXT4_MAXQUOTAS] = { le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum), @@ -132,7 +108,7 @@ index 8189081..6a9d397 100644 }; 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) +@@ -5479,7 +5528,8 @@ static int ext4_enable_quotas(struct sup int type, err = 0; unsigned long qf_inums[EXT4_MAXQUOTAS] = { le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum), @@ -142,3 +118,27 @@ index 8189081..6a9d397 100644 }; sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE; +Index: linux-stage/fs/ext4/ext4.h +=================================================================== +--- linux-stage.orig/fs/ext4/ext4.h ++++ linux-stage/fs/ext4/ext4.h +@@ -1138,7 +1138,7 @@ extern void ext4_set_bits(void *bm, int + #define EXT4_CRC32C_CHKSUM 1 + + /* Number of quota types we support */ +-#define EXT4_MAXQUOTAS 2 ++#define EXT4_MAXQUOTAS 3 + + /* + * Structure of the super block +@@ -1253,7 +1253,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) */ + }; + -- 1.8.3.1