Whamcloud - gitweb
LU-9384 ldiskfs: port extra isize patches to sles12sp2 44/27244/4
authorYang Sheng <yang.sheng@intel.com>
Tue, 23 May 2017 03:54:57 +0000 (11:54 +0800)
committerOleg Drokin <oleg.drokin@intel.com>
Sat, 3 Jun 2017 03:56:39 +0000 (03:56 +0000)
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 <yang.sheng@intel.com>
Change-Id: Iab0914d0010436aa26d99b78b2ae4acea783fb7d
Reviewed-on: https://review.whamcloud.com/27244
Tested-by: Jenkins
Reviewed-by: Bob Glossman <bob.glossman@intel.com>
Reviewed-by: Andreas Dilger <andreas.dilger@intel.com>
Tested-by: Maloo <hpdd-maloo@intel.com>
ldiskfs/kernel_patches/patches/sles12sp2/ext4-fix-xattr-shifting-when-expanding-inodes.patch [new file with mode: 0644]
ldiskfs/kernel_patches/series/ldiskfs-4.4-sles12sp2.series

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 (file)
index 0000000..51a6cda
--- /dev/null
@@ -0,0 +1,210 @@
+From e3014d14a81edde488d9a6758eea8afc41752d2d Mon Sep 17 00:00:00 2001
+From: Jan Kara <jack@suse.cz>
+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 <jack@suse.cz>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+---
+ 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 <khlebnikov@yandex-team.ru>
+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 <khlebnikov@yandex-team.ru>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+---
+ 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
+
index 546b30d..5261894 100644 (file)
@@ -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-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