From 01d7ddd0edc1517b05136cb36314d7a39dbfeff3 Mon Sep 17 00:00:00 2001 From: Yang Sheng Date: Tue, 23 May 2017 11:54:57 +0800 Subject: [PATCH] LU-9384 ldiskfs: port extra isize patches to sles12sp2 Port 3 extra isize patches for sles12sp2 as below: commit e3014d14a81edde488d9a6758eea8afc41752d2d "ext4: fixup free space calculations when expanding inodes" commit 94405713889d4a9d341b4ad92956e4e2ec8ec2c2 "ext4: replace bogus assertion in ext4_xattr_shift_entries()" commit 887a9730614727c4fff7cb756711b190593fc1df "ext4: keep existing extra fields when inode expands" Signed-off-by: Yang Sheng Change-Id: Iab0914d0010436aa26d99b78b2ae4acea783fb7d Reviewed-on: https://review.whamcloud.com/27244 Tested-by: Jenkins Reviewed-by: Bob Glossman Reviewed-by: Andreas Dilger Tested-by: Maloo --- ...-fix-xattr-shifting-when-expanding-inodes.patch | 210 +++++++++++++++++++++ .../series/ldiskfs-4.4-sles12sp2.series | 1 + 2 files changed, 211 insertions(+) create mode 100644 ldiskfs/kernel_patches/patches/sles12sp2/ext4-fix-xattr-shifting-when-expanding-inodes.patch diff --git a/ldiskfs/kernel_patches/patches/sles12sp2/ext4-fix-xattr-shifting-when-expanding-inodes.patch b/ldiskfs/kernel_patches/patches/sles12sp2/ext4-fix-xattr-shifting-when-expanding-inodes.patch new file mode 100644 index 0000000..51a6cda --- /dev/null +++ b/ldiskfs/kernel_patches/patches/sles12sp2/ext4-fix-xattr-shifting-when-expanding-inodes.patch @@ -0,0 +1,210 @@ +From e3014d14a81edde488d9a6758eea8afc41752d2d Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Mon, 29 Aug 2016 15:38:11 -0400 +Subject: [PATCH] ext4: fixup free space calculations when expanding inodes + +Conditions checking whether there is enough free space in an xattr block +and when xattr is large enough to make enough space in the inode forgot +to account for the fact that inode need not be completely filled up with +xattrs. Thus we could move unnecessarily many xattrs out of inode or +even falsely claim there is not enough space to expand the inode. We +also forgot to update the amount of free space in xattr block when moving +more xattrs and thus could decide to move too big xattr resulting in +unexpected failure. + +Fix these problems by properly updating free space in the inode and +xattr block as we move xattrs. To simplify the math, avoid shifting +xattrs after removing each one xattr and instead just shift xattrs only +once there is enough free space in the inode. + +Signed-off-by: Jan Kara +Signed-off-by: Theodore Ts'o +--- + fs/ext4/xattr.c | 58 ++++++++++++++++++++++++--------------------------------- + 1 file changed, 24 insertions(+), 34 deletions(-) + +Index: linux-4.4.49-92.14_lustre-vanilla/fs/ext4/xattr.c +=================================================================== +--- linux-4.4.49-92.14_lustre-vanilla.orig/fs/ext4/xattr.c ++++ linux-4.4.49-92.14_lustre-vanilla/fs/ext4/xattr.c +@@ -1619,18 +1619,19 @@ retry: + */ + static void ext4_xattr_shift_entries(struct ext4_xattr_entry *entry, + int value_offs_shift, void *to, +- void *from, size_t n, int blocksize) ++ void *from, size_t n) + { + struct ext4_xattr_entry *last = entry; + int new_offs; + ++ /* We always shift xattr headers further thus offsets get lower */ ++ BUG_ON(value_offs_shift > 0); ++ + /* Adjust the value offsets of the entries */ + for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) { + if (!last->e_value_inum && last->e_value_size) { + new_offs = le16_to_cpu(last->e_value_offs) + + value_offs_shift; +- BUG_ON(new_offs + le32_to_cpu(last->e_value_size) +- > blocksize); + last->e_value_offs = cpu_to_le16(new_offs); + } + } +@@ -1651,7 +1652,8 @@ int ext4_expand_extra_isize_ea(struct in + struct ext4_xattr_ibody_find *is = NULL; + struct ext4_xattr_block_find *bs = NULL; + char *buffer = NULL, *b_entry_name = NULL; +- size_t min_offs, free; ++ size_t min_offs; ++ size_t ifree, bfree; + int total_ino; + void *base, *start, *end; + int error = 0, tried_min_extra_isize = 0; +@@ -1682,17 +1684,9 @@ retry: + last = entry; + total_ino = sizeof(struct ext4_xattr_ibody_header); + +- free = ext4_xattr_free_space(last, &min_offs, base, &total_ino); +- if (free >= isize_diff) { +- entry = IFIRST(header); +- ext4_xattr_shift_entries(entry, EXT4_I(inode)->i_extra_isize +- - new_extra_isize, (void *)raw_inode + +- EXT4_GOOD_OLD_INODE_SIZE + new_extra_isize, +- (void *)header, total_ino, +- inode->i_sb->s_blocksize); +- EXT4_I(inode)->i_extra_isize = new_extra_isize; +- goto out; +- } ++ ifree = ext4_xattr_free_space(last, &min_offs, base, &total_ino); ++ if (ifree >= isize_diff) ++ goto shift; + + /* + * Enough free space isn't available in the inode, check if +@@ -1713,8 +1707,8 @@ retry: + first = BFIRST(bh); + end = bh->b_data + bh->b_size; + min_offs = end - base; +- free = ext4_xattr_free_space(first, &min_offs, base, NULL); +- if (free < isize_diff) { ++ bfree = ext4_xattr_free_space(first, &min_offs, base, NULL); ++ if (bfree + ifree < isize_diff) { + if (!tried_min_extra_isize && s_min_extra_isize) { + tried_min_extra_isize++; + new_extra_isize = s_min_extra_isize; +@@ -1725,10 +1719,10 @@ retry: + goto cleanup; + } + } else { +- free = inode->i_sb->s_blocksize; ++ bfree = inode->i_sb->s_blocksize; + } + +- while (isize_diff > 0) { ++ while (isize_diff > ifree) { + size_t offs, size, entry_size; + struct ext4_xattr_entry *small_entry = NULL; + struct ext4_xattr_info i = { +@@ -1736,7 +1730,6 @@ retry: + .value_len = 0, + }; + unsigned int total_size; /* EA entry size + value size */ +- unsigned int shift_bytes; /* No. of bytes to shift EAs by? */ + unsigned int min_total_size = ~0U; + + is = kzalloc(sizeof(struct ext4_xattr_ibody_find), GFP_NOFS); +@@ -1758,8 +1751,9 @@ retry: + total_size = + EXT4_XATTR_SIZE(le32_to_cpu(last->e_value_size)) + + EXT4_XATTR_LEN(last->e_name_len); +- if (total_size <= free && total_size < min_total_size) { +- if (total_size < isize_diff) { ++ if (total_size <= bfree && ++ total_size < min_total_size) { ++ if (total_size + ifree < isize_diff) { + small_entry = last; + } else { + entry = last; +@@ -1788,6 +1782,7 @@ retry: + offs = le16_to_cpu(entry->e_value_offs); + size = le32_to_cpu(entry->e_value_size); + entry_size = EXT4_XATTR_LEN(entry->e_name_len); ++ total_size = entry_size + EXT4_XATTR_SIZE(size); + i.name_index = entry->e_name_index, + buffer = kmalloc(EXT4_XATTR_SIZE(size), GFP_NOFS); + b_entry_name = kmalloc(entry->e_name_len + 1, GFP_NOFS); +@@ -1815,21 +1810,8 @@ retry: + if (error) + goto cleanup; + total_ino -= entry_size; +- +- entry = IFIRST(header); +- if (entry_size + EXT4_XATTR_SIZE(size) >= isize_diff) +- shift_bytes = isize_diff; +- else +- shift_bytes = entry_size + EXT4_XATTR_SIZE(size); +- /* Adjust the offsets and shift the remaining entries ahead */ +- ext4_xattr_shift_entries(entry, -shift_bytes, +- (void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE + +- EXT4_I(inode)->i_extra_isize + shift_bytes, +- (void *)header, total_ino, inode->i_sb->s_blocksize); +- +- isize_diff -= shift_bytes; +- EXT4_I(inode)->i_extra_isize += shift_bytes; +- header = IHDR(inode, raw_inode); ++ ifree += total_size; ++ bfree -= total_size; + + i.name = b_entry_name; + i.value = buffer; +@@ -1850,6 +1832,15 @@ retry: + kfree(is); + kfree(bs); + } ++ ++shift: ++ /* Adjust the offsets and shift the remaining entries ahead */ ++ entry = IFIRST(header); ++ ext4_xattr_shift_entries(entry, EXT4_I(inode)->i_extra_isize ++ - new_extra_isize, (void *)raw_inode + ++ EXT4_GOOD_OLD_INODE_SIZE + new_extra_isize, ++ (void *)header, total_ino); ++ EXT4_I(inode)->i_extra_isize = new_extra_isize; + brelse(bh); + out: + ext4_clear_inode_state(inode, EXT4_STATE_NO_EXPAND); +From 887a9730614727c4fff7cb756711b190593fc1df Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Sun, 21 May 2017 22:36:23 -0400 +Subject: [PATCH] ext4: keep existing extra fields when inode expands + +ext4_expand_extra_isize() should clear only space between old and new +size. + +Fixes: 6dd4ee7cab7e # v2.6.23 +Cc: stable@vger.kernel.org +Signed-off-by: Konstantin Khlebnikov +Signed-off-by: Theodore Ts'o +--- + fs/ext4/inode.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index 1bd0bfa..7cd99de 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -5637,8 +5637,9 @@ static int ext4_expand_extra_isize(struct inode *inode, + /* No extended attributes present */ + if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR) || + header->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC)) { +- memset((void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE, 0, +- new_extra_isize); ++ memset((void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE + ++ EXT4_I(inode)->i_extra_isize, 0, ++ new_extra_isize - EXT4_I(inode)->i_extra_isize); + EXT4_I(inode)->i_extra_isize = new_extra_isize; + return 0; + } +-- +2.9.3 + diff --git a/ldiskfs/kernel_patches/series/ldiskfs-4.4-sles12sp2.series b/ldiskfs/kernel_patches/series/ldiskfs-4.4-sles12sp2.series index 546b30d..5261894 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-4.4-sles12sp2.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-4.4-sles12sp2.series @@ -23,3 +23,4 @@ rhel7/ext4-jcb-optimization.patch sles12sp2/ext4-attach-jinode-in-writepages.patch sles12sp2/ext4-dont-check-before-replay.patch rhel7.2/ext4-dont-check-in-ro.patch +sles12sp2/ext4-fix-xattr-shifting-when-expanding-inodes.patch -- 1.8.3.1