Whamcloud - gitweb
LU-14491 ldiskfs: do not corrupt journal with bh change rh7.6
[fs/lustre-release.git] / 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
+