Whamcloud - gitweb
LU-14491 ldiskfs: do not corrupt journal with bh change rh7.6 64/45164/2
authorAndrew Perepechko <andrew.perepechko@hpe.com>
Fri, 8 Oct 2021 10:05:50 +0000 (17:05 +0700)
committerOleg Drokin <green@whamcloud.com>
Tue, 30 Nov 2021 03:45:48 +0000 (03:45 +0000)
Currently, ldiskfs_xattr_delete_inode() zeroes xattr inode
references in cached buffers that haven't been prepared by
get_write_access().

When using journal checksums, it is possible that these buffers
are modified after the checksum is calculated but before the
buffer has been written to journal. Journal replay will fail
with a journal checksum error message if this transaction needs
to be replayed.

This is a port of:

Lustre-commit: d563f5140ffa183d0854cf7cd493ad884e314e3d
Lustre-change: https://review.whamcloud.com/41896

Test-Parameters: trivial
HPE-bug-id: LUS-9483
Signed-off-by: Shaun Tancheff <shaun.tancheff@hpe.com>
Change-Id: I5ce1016737a16ddf74811c43ae74296d4f3e03b0
Reviewed-on: https://review.whamcloud.com/45164
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Andrew Perepechko <andrew.perepechko@hpe.com>
Reviewed-by: Alexander Zarochentsev <alexander.zarochentsev@hpe.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
ldiskfs/kernel_patches/patches/rhel7.6/ext4-large-eas.patch

index 2ed1b57..9703ad1 100644 (file)
@@ -1,14 +1,25 @@
-This patch implements the large EA support in ext4. If the size of
-an EA value is larger than the blocksize, then the EA value would
-not be saved in the external EA block, instead it would be saved
-in an external EA inode. So, the patch also helps support a larger
-number of EAs.
+Date: Fri, 8 Oct 2021 12:28:37 +0700
+Subject: [PATCH] This patch implements the large EA support in ext4. If the
+ size of an EA value is larger than the blocksize, then the EA value would not
+ be saved in the external EA block, instead it would be saved in an external
+ EA inode. So, the patch also helps support a larger number of EAs.
 
-Index: linux-stage/fs/ext4/ext4.h
-===================================================================
---- linux-stage.orig/fs/ext4/ext4.h
-+++ linux-stage/fs/ext4/ext4.h
-@@ -1617,6 +1617,7 @@ static inline void ext4_clear_state_flag
+---
+ fs/ext4/ext4.h     |   6 +
+ fs/ext4/extents.c  |   3 +-
+ fs/ext4/ialloc.c   |   1 -
+ fs/ext4/indirect.c |   3 +-
+ fs/ext4/inline.c   |   2 +-
+ fs/ext4/inode.c    |  45 +++-
+ fs/ext4/xattr.c    | 605 ++++++++++++++++++++++++++++++++++++++++++---
+ fs/ext4/xattr.h    |  33 ++-
+ 8 files changed, 645 insertions(+), 53 deletions(-)
+
+diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
+index ba54a96..e28bcdb 100644
+--- a/fs/ext4/ext4.h
++++ b/fs/ext4/ext4.h
+@@ -1617,6 +1617,7 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
                                         EXT4_FEATURE_INCOMPAT_EXTENTS| \
                                         EXT4_FEATURE_INCOMPAT_64BIT| \
                                         EXT4_FEATURE_INCOMPAT_FLEX_BG| \
@@ -27,7 +38,7 @@ Index: linux-stage/fs/ext4/ext4.h
  /* bitmap.c */
  extern unsigned int ext4_count_free(char *bitmap, unsigned numchars);
  void ext4_inode_bitmap_csum_set(struct super_block *sb, ext4_group_t group,
-@@ -2233,6 +2238,7 @@ extern void ext4_set_inode_flags(struct
+@@ -2233,6 +2238,7 @@ extern void ext4_set_inode_flags(struct inode *);
  extern void ext4_get_inode_flags(struct ext4_inode_info *);
  extern int ext4_alloc_da_blocks(struct inode *inode);
  extern void ext4_set_aops(struct inode *inode);
@@ -35,11 +46,64 @@ Index: linux-stage/fs/ext4/ext4.h
  extern int ext4_writepage_trans_blocks(struct inode *);
  extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks);
  extern int ext4_zero_partial_blocks(handle_t *handle, struct inode *inode,
-Index: linux-stage/fs/ext4/inode.c
-===================================================================
---- linux-stage.orig/fs/ext4/inode.c
-+++ linux-stage/fs/ext4/inode.c
-@@ -136,8 +136,6 @@ static void ext4_invalidatepage(struct p
+diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
+index d8434f2..8263aa4 100644
+--- a/fs/ext4/extents.c
++++ b/fs/ext4/extents.c
+@@ -2461,7 +2461,8 @@ int ext4_ext_index_trans_blocks(struct inode *inode, int extents)
+ static inline int get_default_free_blocks_flags(struct inode *inode)
+ {
+-      if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
++      if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode) ||
++              ext4_test_inode_flag(inode, EXT4_INODE_EA_INODE))
+               return EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET;
+       else if (ext4_should_journal_data(inode))
+               return EXT4_FREE_BLOCKS_FORGET;
+diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
+index a739f71..472bb41 100644
+--- a/fs/ext4/ialloc.c
++++ b/fs/ext4/ialloc.c
+@@ -247,7 +247,6 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
+        * as writing the quota to disk may need the lock as well.
+        */
+       dquot_initialize(inode);
+-      ext4_xattr_delete_inode(handle, inode);
+       dquot_free_inode(inode);
+       dquot_drop(inode);
+diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c
+index 68163c3..b7cf6e0 100644
+--- a/fs/ext4/indirect.c
++++ b/fs/ext4/indirect.c
+@@ -959,7 +959,8 @@ static int ext4_clear_blocks(handle_t *handle, struct inode *inode,
+       int     flags = EXT4_FREE_BLOCKS_VALIDATED;
+       int     err;
+-      if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
++      if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode) ||
++              ext4_test_inode_flag(inode, EXT4_INODE_EA_INODE))
+               flags |= EXT4_FREE_BLOCKS_FORGET | EXT4_FREE_BLOCKS_METADATA;
+       else if (ext4_should_journal_data(inode))
+               flags |= EXT4_FREE_BLOCKS_FORGET;
+diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
+index 0e7433b..b1295be 100644
+--- a/fs/ext4/inline.c
++++ b/fs/ext4/inline.c
+@@ -59,7 +59,7 @@ static int get_max_inline_xattr_value_size(struct inode *inode,
+       /* Compute min_offs. */
+       for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) {
+-              if (!entry->e_value_block && entry->e_value_size) {
++              if (!entry->e_value_inum && entry->e_value_size) {
+                       size_t offs = le16_to_cpu(entry->e_value_offs);
+                       if (offs < min_offs)
+                               min_offs = offs;
+diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
+index 6c6ac63..2086792 100644
+--- a/fs/ext4/inode.c
++++ b/fs/ext4/inode.c
+@@ -136,8 +136,6 @@ static void ext4_invalidatepage(struct page *page, unsigned int offset,
                                unsigned int length);
  static int __ext4_journalled_writepage(struct page *page, unsigned int len);
  static int ext4_bh_delay_or_unwritten(handle_t *handle, struct buffer_head *bh);
@@ -48,7 +112,7 @@ Index: linux-stage/fs/ext4/inode.c
  
  /*
   * Test whether an inode is a fast symlink.
-@@ -186,6 +184,8 @@ void ext4_evict_inode(struct inode *inod
+@@ -186,6 +184,8 @@ void ext4_evict_inode(struct inode *inode)
  {
        handle_t *handle;
        int err;
@@ -57,7 +121,7 @@ Index: linux-stage/fs/ext4/inode.c
  
        trace_ext4_evict_inode(inode);
  
-@@ -235,8 +235,8 @@ void ext4_evict_inode(struct inode *inod
+@@ -235,8 +235,8 @@ void ext4_evict_inode(struct inode *inode)
         * protection against it
         */
        sb_start_intwrite(inode->i_sb);
@@ -68,7 +132,7 @@ Index: linux-stage/fs/ext4/inode.c
        if (IS_ERR(handle)) {
                ext4_std_error(inode->i_sb, PTR_ERR(handle));
                /*
-@@ -251,6 +251,32 @@ void ext4_evict_inode(struct inode *inod
+@@ -251,6 +251,32 @@ void ext4_evict_inode(struct inode *inode)
  
        if (IS_SYNC(inode))
                ext4_handle_sync(handle);
@@ -101,7 +165,7 @@ Index: linux-stage/fs/ext4/inode.c
        inode->i_size = 0;
        err = ext4_mark_inode_dirty(handle, inode);
        if (err) {
-@@ -267,10 +293,10 @@ void ext4_evict_inode(struct inode *inod
+@@ -267,10 +293,10 @@ void ext4_evict_inode(struct inode *inode)
         * enough credits left in the handle to remove the inode from
         * the orphan list and set the dtime field.
         */
@@ -115,7 +179,7 @@ Index: linux-stage/fs/ext4/inode.c
                if (err != 0) {
                        ext4_warning(inode->i_sb,
                                     "couldn't extend journal (err %d)", err);
-@@ -307,6 +333,9 @@ void ext4_evict_inode(struct inode *inod
+@@ -307,6 +333,9 @@ void ext4_evict_inode(struct inode *inode)
                ext4_free_inode(handle, inode);
        ext4_journal_stop(handle);
        sb_end_intwrite(inode->i_sb);
@@ -125,7 +189,7 @@ Index: linux-stage/fs/ext4/inode.c
        return;
  no_delete:
        ext4_clear_inode(inode);        /* We must guarantee clearing of inode... */
-@@ -5132,7 +5161,7 @@ static int ext4_index_trans_blocks(struc
+@@ -5132,7 +5161,7 @@ static int ext4_index_trans_blocks(struct inode *inode, int lblocks,
   *
   * Also account for superblock, inode, quota and xattr blocks
   */
@@ -134,11 +198,11 @@ Index: linux-stage/fs/ext4/inode.c
                                  int pextents)
  {
        ext4_group_t groups, ngroups = ext4_get_groups_count(inode->i_sb);
-Index: linux-stage/fs/ext4/xattr.c
-===================================================================
---- linux-stage.orig/fs/ext4/xattr.c
-+++ linux-stage/fs/ext4/xattr.c
-@@ -201,6 +201,7 @@ ext4_xattr_check_names(struct ext4_xattr
+diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
+index c10e37f..2288410 100644
+--- a/fs/ext4/xattr.c
++++ b/fs/ext4/xattr.c
+@@ -201,6 +201,7 @@ ext4_xattr_check_names(struct ext4_xattr_entry *entry, void *end,
  
        while (!IS_LAST_ENTRY(entry)) {
                if (entry->e_value_size != 0 &&
@@ -146,7 +210,7 @@ Index: linux-stage/fs/ext4/xattr.c
                    (value_start + le16_to_cpu(entry->e_value_offs) <
                     (void *)e + sizeof(__u32) ||
                     value_start + le16_to_cpu(entry->e_value_offs) +
-@@ -233,19 +234,26 @@ ext4_xattr_check_block(struct inode *ino
+@@ -233,19 +234,26 @@ ext4_xattr_check_block(struct inode *inode, struct buffer_head *bh)
  }
  
  static inline int
@@ -176,7 +240,7 @@ Index: linux-stage/fs/ext4/xattr.c
  {
        struct ext4_xattr_entry *entry;
        size_t name_len;
-@@ -265,11 +273,109 @@ ext4_xattr_find_entry(struct ext4_xattr_
+@@ -265,11 +273,109 @@ ext4_xattr_find_entry(struct ext4_xattr_entry **pentry, int name_index,
                        break;
        }
        *pentry = entry;
@@ -316,7 +380,7 @@ Index: linux-stage/fs/ext4/xattr.c
        }
        error = size;
  
-@@ -346,7 +461,7 @@ ext4_xattr_ibody_get(struct inode *inode
+@@ -346,7 +461,7 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
        if (error)
                goto cleanup;
        error = ext4_xattr_find_entry(&entry, name_index, name,
@@ -325,7 +389,7 @@ Index: linux-stage/fs/ext4/xattr.c
        if (error)
                goto cleanup;
        size = le32_to_cpu(entry->e_value_size);
-@@ -354,8 +469,16 @@ ext4_xattr_ibody_get(struct inode *inode
+@@ -354,8 +469,16 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
                error = -ERANGE;
                if (size > buffer_size)
                        goto cleanup;
@@ -344,7 +408,7 @@ Index: linux-stage/fs/ext4/xattr.c
        }
        error = size;
  
-@@ -600,7 +723,7 @@ static size_t ext4_xattr_free_space(stru
+@@ -600,7 +723,7 @@ static size_t ext4_xattr_free_space(struct ext4_xattr_entry *last,
                                    size_t *min_offs, void *base, int *total)
  {
        for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
@@ -353,7 +417,7 @@ Index: linux-stage/fs/ext4/xattr.c
                        size_t offs = le16_to_cpu(last->e_value_offs);
                        if (offs < *min_offs)
                                *min_offs = offs;
-@@ -611,11 +734,193 @@ static size_t ext4_xattr_free_space(stru
+@@ -611,11 +734,193 @@ static size_t ext4_xattr_free_space(struct ext4_xattr_entry *last,
        return (*min_offs - ((void *)last - base) - sizeof(__u32));
  }
  
@@ -548,7 +612,7 @@ Index: linux-stage/fs/ext4/xattr.c
  
        /* Compute min_offs and last. */
        last = s->first;
-@@ -624,7 +929,7 @@ ext4_xattr_set_entry(struct ext4_xattr_i
+@@ -624,7 +929,7 @@ ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s)
                if ((void *)next >= s->end) {
                        return -EIO;
                }
@@ -557,7 +621,7 @@ Index: linux-stage/fs/ext4/xattr.c
                        size_t offs = le16_to_cpu(last->e_value_offs);
                        if (offs < min_offs)
                                min_offs = offs;
-@@ -632,15 +937,21 @@ ext4_xattr_set_entry(struct ext4_xattr_i
+@@ -632,15 +937,21 @@ ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s)
        }
        free = min_offs - ((void *)last - s->base) - sizeof(__u32);
        if (!s->not_found) {
@@ -582,7 +646,7 @@ Index: linux-stage/fs/ext4/xattr.c
                        return -ENOSPC;
        }
  
-@@ -654,7 +965,8 @@ ext4_xattr_set_entry(struct ext4_xattr_i
+@@ -654,7 +965,8 @@ ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s)
                s->here->e_name_len = name_len;
                memcpy(s->here->e_name, i->name, name_len);
        } else {
@@ -592,7 +656,7 @@ Index: linux-stage/fs/ext4/xattr.c
                        void *first_val = s->base + min_offs;
                        size_t offs = le16_to_cpu(s->here->e_value_offs);
                        void *val = s->base + offs;
-@@ -688,13 +1000,18 @@ ext4_xattr_set_entry(struct ext4_xattr_i
+@@ -688,13 +1000,18 @@ ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s)
                        last = s->first;
                        while (!IS_LAST_ENTRY(last)) {
                                size_t o = le16_to_cpu(last->e_value_offs);
@@ -612,7 +676,7 @@ Index: linux-stage/fs/ext4/xattr.c
                if (!i->value) {
                        /* Remove the old name. */
                        size_t size = EXT4_XATTR_LEN(name_len);
-@@ -708,10 +1025,17 @@ ext4_xattr_set_entry(struct ext4_xattr_i
+@@ -708,10 +1025,17 @@ ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s)
        if (i->value) {
                /* Insert the new value. */
                s->here->e_value_size = cpu_to_le32(i->value_len);
@@ -631,7 +695,7 @@ Index: linux-stage/fs/ext4/xattr.c
                        if (i->value == EXT4_ZERO_XATTR_VALUE) {
                                memset(val, 0, size);
                        } else {
-@@ -761,7 +1085,7 @@ ext4_xattr_block_find(struct inode *inod
+@@ -761,7 +1085,7 @@ ext4_xattr_block_find(struct inode *inode, struct ext4_xattr_info *i,
                bs->s.end = bs->bh->b_data + bs->bh->b_size;
                bs->s.here = bs->s.first;
                error = ext4_xattr_find_entry(&bs->s.here, i->name_index,
@@ -640,7 +704,7 @@ Index: linux-stage/fs/ext4/xattr.c
                if (error && error != -ENODATA)
                        goto cleanup;
                bs->s.not_found = error;
-@@ -785,8 +1109,6 @@ ext4_xattr_block_set(handle_t *handle, s
+@@ -785,8 +1109,6 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
  
  #define header(x) ((struct ext4_xattr_header *)(x))
  
@@ -649,7 +713,7 @@ Index: linux-stage/fs/ext4/xattr.c
        if (s->base) {
                ce = mb_cache_entry_get(ext4_xattr_cache, bs->bh->b_bdev,
                                        bs->bh->b_blocknr);
-@@ -802,7 +1124,7 @@ ext4_xattr_block_set(handle_t *handle, s
+@@ -802,7 +1124,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
                                ce = NULL;
                        }
                        ea_bdebug(bs->bh, "modifying in-place");
@@ -658,7 +722,7 @@ Index: linux-stage/fs/ext4/xattr.c
                        if (!error) {
                                if (!IS_LAST_ENTRY(s->first))
                                        ext4_xattr_rehash(header(s->base),
-@@ -853,7 +1175,7 @@ ext4_xattr_block_set(handle_t *handle, s
+@@ -853,7 +1175,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
                s->end = s->base + sb->s_blocksize;
        }
  
@@ -667,7 +731,7 @@ Index: linux-stage/fs/ext4/xattr.c
        if (error == -EIO)
                goto bad_block;
        if (error)
-@@ -997,7 +1319,7 @@ int ext4_xattr_ibody_find(struct inode *
+@@ -997,7 +1319,7 @@ int ext4_xattr_ibody_find(struct inode *inode, struct ext4_xattr_info *i,
                /* Find the named attribute. */
                error = ext4_xattr_find_entry(&is->s.here, i->name_index,
                                              i->name, is->s.end -
@@ -676,7 +740,7 @@ Index: linux-stage/fs/ext4/xattr.c
                if (error && error != -ENODATA)
                        return error;
                is->s.not_found = error;
-@@ -1015,7 +1337,7 @@ int ext4_xattr_ibody_inline_set(handle_t
+@@ -1015,7 +1337,7 @@ int ext4_xattr_ibody_inline_set(handle_t *handle, struct inode *inode,
  
        if (EXT4_I(inode)->i_extra_isize == 0)
                return -ENOSPC;
@@ -685,7 +749,7 @@ Index: linux-stage/fs/ext4/xattr.c
        if (error)
                return error;
        header = IHDR(inode, ext4_raw_inode(&is->iloc));
-@@ -1039,7 +1361,7 @@ static int ext4_xattr_ibody_set(handle_t
+@@ -1039,7 +1361,7 @@ static int ext4_xattr_ibody_set(handle_t *handle, struct inode *inode,
  
        if (EXT4_I(inode)->i_extra_isize == 0)
                return -ENOSPC;
@@ -694,7 +758,7 @@ Index: linux-stage/fs/ext4/xattr.c
        if (error)
                return error;
        header = IHDR(inode, ext4_raw_inode(&is->iloc));
-@@ -1075,7 +1397,7 @@ ext4_xattr_set_handle(handle_t *handle,
+@@ -1075,7 +1397,7 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
                .name = name,
                .value = value,
                .value_len = value_len,
@@ -703,7 +767,7 @@ Index: linux-stage/fs/ext4/xattr.c
        };
        struct ext4_xattr_ibody_find is = {
                .s = { .not_found = -ENODATA, },
-@@ -1140,6 +1462,15 @@ ext4_xattr_set_handle(handle_t *handle,
+@@ -1140,6 +1462,15 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
                                        goto cleanup;
                        }
                        error = ext4_xattr_block_set(handle, inode, &i, &bs);
@@ -719,7 +783,7 @@ Index: linux-stage/fs/ext4/xattr.c
                        if (error)
                                goto cleanup;
                        if (!is.s.not_found) {
-@@ -1186,9 +1517,22 @@ ext4_xattr_set(struct inode *inode, int
+@@ -1186,9 +1517,22 @@ ext4_xattr_set(struct inode *inode, int name_index, const char *name,
               const void *value, size_t value_len, int flags)
  {
        handle_t *handle;
@@ -751,7 +815,7 @@ Index: linux-stage/fs/ext4/xattr.c
                        goto retry;
                if (error == 0)
                        error = error2;
-@@ -1222,7 +1566,7 @@ static void ext4_xattr_shift_entries(str
+@@ -1222,7 +1566,7 @@ static void ext4_xattr_shift_entries(struct ext4_xattr_entry *entry,
  
        /* Adjust the value offsets of the entries */
        for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
@@ -760,7 +824,7 @@ Index: linux-stage/fs/ext4/xattr.c
                        new_offs = le16_to_cpu(last->e_value_offs) +
                                                        value_offs_shift;
                        BUG_ON(new_offs + le32_to_cpu(last->e_value_size)
-@@ -1469,21 +1813,135 @@ cleanup:
+@@ -1469,21 +1813,140 @@ cleanup:
  }
  
  
@@ -865,7 +929,7 @@ Index: linux-stage/fs/ext4/xattr.c
        struct buffer_head *bh = NULL;
 +      struct ext4_xattr_ibody_header *header;
 +      struct ext4_inode *raw_inode;
-+      struct ext4_iloc iloc;
++      struct ext4_iloc iloc = { .bh = NULL };
 +      struct ext4_xattr_entry *entry;
 +      int credits = 3, error = 0;
  
@@ -875,7 +939,7 @@ Index: linux-stage/fs/ext4/xattr.c
 +
 +      error = ext4_get_inode_loc(inode, &iloc);
 +      if (error)
-+              goto cleanup;
+               goto cleanup;
 +      raw_inode = ext4_raw_inode(&iloc);
 +      header = IHDR(inode, raw_inode);
 +      for (entry = IFIRST(header); !IS_LAST_ENTRY(entry);
@@ -883,25 +947,30 @@ Index: linux-stage/fs/ext4/xattr.c
 +              if (!entry->e_value_inum)
 +                      continue;
 +              if (ext4_expand_ino_array(lea_ino_array,
-+                                        entry->e_value_inum) != 0) {
-+                      brelse(iloc.bh);
++                                        entry->e_value_inum) != 0)
++                      goto cleanup;
++
++              error = ext4_journal_get_write_access(handle, iloc.bh);
++              if (error)
 +                      goto cleanup;
-+              }
 +              entry->e_value_inum = 0;
++              entry->e_value_size = 0;
++              error = ext4_handle_dirty_metadata(handle, inode, iloc.bh);
++              if (error)
++                      goto cleanup;
 +      }
-+      brelse(iloc.bh);
 +
 +delete_external_ea:
 +      if (!EXT4_I(inode)->i_file_acl) {
 +              /* add xattr inode to orphan list */
 +              ext4_xattr_inode_orphan_add(handle, inode, credits,
 +                                              *lea_ino_array);
-               goto cleanup;
++              goto cleanup;
 +      }
        bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl);
        if (!bh) {
                EXT4_ERROR_INODE(inode, "block %llu read error",
-@@ -1496,11 +1954,69 @@ ext4_xattr_delete_inode(handle_t *handle
+@@ -1496,11 +1959,78 @@ ext4_xattr_delete_inode(handle_t *handle, struct inode *inode)
                                 EXT4_I(inode)->i_file_acl);
                goto cleanup;
        }
@@ -913,7 +982,15 @@ Index: linux-stage/fs/ext4/xattr.c
 +              if (ext4_expand_ino_array(lea_ino_array,
 +                                        entry->e_value_inum) != 0)
 +                      goto cleanup;
++
++              error = ext4_journal_get_write_access(handle, bh);
++              if (error)
++                      goto cleanup;
 +              entry->e_value_inum = 0;
++              entry->e_value_size = 0;
++              error = ext4_handle_dirty_metadata(handle, inode, bh);
++              if (error)
++                      goto cleanup;
 +      }
 +
 +      /* add xattr inode to orphan list */
@@ -941,6 +1018,7 @@ Index: linux-stage/fs/ext4/xattr.c
  
  cleanup:
        brelse(bh);
++      brelse(iloc.bh);
 +
 +      return error;
 +}
@@ -971,7 +1049,7 @@ Index: linux-stage/fs/ext4/xattr.c
  }
  
  /*
-@@ -1570,10 +2086,9 @@ ext4_xattr_cmp(struct ext4_xattr_header
+@@ -1570,10 +2100,9 @@ ext4_xattr_cmp(struct ext4_xattr_header *header1,
                    entry1->e_name_index != entry2->e_name_index ||
                    entry1->e_name_len != entry2->e_name_len ||
                    entry1->e_value_size != entry2->e_value_size ||
@@ -983,7 +1061,7 @@ Index: linux-stage/fs/ext4/xattr.c
                if (memcmp((char *)header1 + le16_to_cpu(entry1->e_value_offs),
                           (char *)header2 + le16_to_cpu(entry2->e_value_offs),
                           le32_to_cpu(entry1->e_value_size)))
-@@ -1657,7 +2172,7 @@ static inline void ext4_xattr_hash_entry
+@@ -1657,7 +2186,7 @@ static inline void ext4_xattr_hash_entry(struct ext4_xattr_header *header,
                       *name++;
        }
  
@@ -992,10 +1070,10 @@ Index: linux-stage/fs/ext4/xattr.c
                __le32 *value = (__le32 *)((char *)header +
                        le16_to_cpu(entry->e_value_offs));
                for (n = (le32_to_cpu(entry->e_value_size) +
-Index: linux-stage/fs/ext4/xattr.h
-===================================================================
---- linux-stage.orig/fs/ext4/xattr.h
-+++ linux-stage/fs/ext4/xattr.h
+diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h
+index c767dbd..8312412 100644
+--- a/fs/ext4/xattr.h
++++ b/fs/ext4/xattr.h
 @@ -42,7 +42,7 @@ struct ext4_xattr_entry {
        __u8    e_name_len;     /* length of name */
        __u8    e_name_index;   /* attribute name index */
@@ -1045,7 +1123,7 @@ Index: linux-stage/fs/ext4/xattr.h
  };
  
  struct ext4_xattr_search {
-@@ -106,7 +127,13 @@ extern int ext4_xattr_get(struct inode *
+@@ -106,7 +127,13 @@ extern int ext4_xattr_get(struct inode *, int, const char *, void *, size_t);
  extern int ext4_xattr_set(struct inode *, int, const char *, const void *, size_t, int);
  extern int ext4_xattr_set_handle(handle_t *, struct inode *, int, const char *, const void *, size_t, int);
  
@@ -1060,56 +1138,6 @@ Index: linux-stage/fs/ext4/xattr.h
  extern void ext4_xattr_put_super(struct super_block *);
  
  extern int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
-Index: linux-stage/fs/ext4/ialloc.c
-===================================================================
---- linux-stage.orig/fs/ext4/ialloc.c
-+++ linux-stage/fs/ext4/ialloc.c
-@@ -247,7 +247,6 @@ void ext4_free_inode(handle_t *handle, s
-        * as writing the quota to disk may need the lock as well.
-        */
-       dquot_initialize(inode);
--      ext4_xattr_delete_inode(handle, inode);
-       dquot_free_inode(inode);
-       dquot_drop(inode);
-Index: linux-stage/fs/ext4/inline.c
-===================================================================
---- linux-stage.orig/fs/ext4/inline.c
-+++ linux-stage/fs/ext4/inline.c
-@@ -59,7 +59,7 @@ static int get_max_inline_xattr_value_si
-       /* Compute min_offs. */
-       for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) {
--              if (!entry->e_value_block && entry->e_value_size) {
-+              if (!entry->e_value_inum && entry->e_value_size) {
-                       size_t offs = le16_to_cpu(entry->e_value_offs);
-                       if (offs < min_offs)
-                               min_offs = offs;
-Index: linux-stage/fs/ext4/extents.c
-===================================================================
---- linux-stage.orig/fs/ext4/extents.c
-+++ linux-stage/fs/ext4/extents.c
-@@ -2461,7 +2461,8 @@ int ext4_ext_index_trans_blocks(struct i
- static inline int get_default_free_blocks_flags(struct inode *inode)
- {
--      if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
-+      if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode) ||
-+              ext4_test_inode_flag(inode, EXT4_INODE_EA_INODE))
-               return EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET;
-       else if (ext4_should_journal_data(inode))
-               return EXT4_FREE_BLOCKS_FORGET;
-Index: linux-stage/fs/ext4/indirect.c
-===================================================================
---- linux-stage.orig/fs/ext4/indirect.c
-+++ linux-stage/fs/ext4/indirect.c
-@@ -959,7 +959,8 @@ static int ext4_clear_blocks(handle_t *h
-       int     flags = EXT4_FREE_BLOCKS_VALIDATED;
-       int     err;
--      if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
-+      if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode) ||
-+              ext4_test_inode_flag(inode, EXT4_INODE_EA_INODE))
-               flags |= EXT4_FREE_BLOCKS_FORGET | EXT4_FREE_BLOCKS_METADATA;
-       else if (ext4_should_journal_data(inode))
-               flags |= EXT4_FREE_BLOCKS_FORGET;
+-- 
+2.30.2
+