From a23aac2219047cb04ed1fa555f31fa39e5c499dc Mon Sep 17 00:00:00 2001 From: Alexey Lyashkov Date: Mon, 20 Apr 2020 12:45:52 +0300 Subject: [PATCH] LU-13416 ldiskfs: don't corrupt data on journal replay MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Journalled write want a special attention on blocks release, revoke records must added to avoid replace a new write blocks with stale data. Mark inode as “journal write” generate a right revoke records. Large EA inode updates affected with this bug also. large ea fix is commit ddfa17e4adc4bd19c32216aaa6250dc38b0579df Author: Tahsin Erdogan Date: Wed Jun 21 21:36:51 2017 -0400 ext4: call journal revoke when freeing ea_inode blocks Change-Id: I605128c4ba70331a48715dc95546430909efb893 Signed-off-by: Alexey Lyashkov Reviewed-on: https://review.whamcloud.com/38281 Reviewed-by: Andreas Dilger Reviewed-by: Alex Zhuravlev Tested-by: jenkins Tested-by: Maloo Reviewed-by: Oleg Drokin --- .../patches/rhel7.6/ext4-large-eas.patch | 54 +++++-- .../patches/rhel7.7/ext4-large-eas.patch | 54 +++++-- .../patches/suse15/ext4-large-eas.patch | 167 ++++++++++++--------- lustre/osd-ldiskfs/osd_handler.c | 3 + lustre/osd-ldiskfs/osd_io.c | 12 +- lustre/osd-ldiskfs/osd_scrub.c | 1 + 6 files changed, 189 insertions(+), 102 deletions(-) diff --git a/ldiskfs/kernel_patches/patches/rhel7.6/ext4-large-eas.patch b/ldiskfs/kernel_patches/patches/rhel7.6/ext4-large-eas.patch index e86a32bd..2ed1b57 100644 --- a/ldiskfs/kernel_patches/patches/rhel7.6/ext4-large-eas.patch +++ b/ldiskfs/kernel_patches/patches/rhel7.6/ext4-large-eas.patch @@ -8,7 +8,7 @@ Index: linux-stage/fs/ext4/ext4.h =================================================================== --- linux-stage.orig/fs/ext4/ext4.h +++ linux-stage/fs/ext4/ext4.h -@@ -1579,6 +1579,7 @@ static inline void ext4_clear_state_flag +@@ -1617,6 +1617,7 @@ static inline void ext4_clear_state_flag EXT4_FEATURE_INCOMPAT_EXTENTS| \ EXT4_FEATURE_INCOMPAT_64BIT| \ EXT4_FEATURE_INCOMPAT_FLEX_BG| \ @@ -16,7 +16,7 @@ Index: linux-stage/fs/ext4/ext4.h EXT4_FEATURE_INCOMPAT_MMP | \ EXT4_FEATURE_INCOMPAT_DIRDATA| \ EXT4_FEATURE_INCOMPAT_INLINE_DATA) -@@ -1990,6 +1997,10 @@ struct mmpd_data { +@@ -2028,6 +2029,10 @@ struct mmpd_data { # define ATTRIB_NORET __attribute__((noreturn)) # define NORET_AND noreturn, @@ -27,7 +27,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, -@@ -2194,6 +2205,7 @@ extern void ext4_set_inode_flags(struct +@@ -2233,6 +2238,7 @@ extern void ext4_set_inode_flags(struct 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); @@ -39,7 +39,7 @@ Index: linux-stage/fs/ext4/inode.c =================================================================== --- linux-stage.orig/fs/ext4/inode.c +++ linux-stage/fs/ext4/inode.c -@@ -134,8 +134,6 @@ static void ext4_invalidatepage(struct p +@@ -136,8 +136,6 @@ static void ext4_invalidatepage(struct p 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 +48,7 @@ Index: linux-stage/fs/ext4/inode.c /* * Test whether an inode is a fast symlink. -@@ -184,6 +182,8 @@ void ext4_evict_inode(struct inode *inod +@@ -186,6 +184,8 @@ void ext4_evict_inode(struct inode *inod { handle_t *handle; int err; @@ -57,7 +57,7 @@ Index: linux-stage/fs/ext4/inode.c trace_ext4_evict_inode(inode); -@@ -236,8 +236,8 @@ void ext4_evict_inode(struct inode *inod +@@ -235,8 +235,8 @@ void ext4_evict_inode(struct inode *inod * protection against it */ sb_start_intwrite(inode->i_sb); @@ -68,7 +68,7 @@ Index: linux-stage/fs/ext4/inode.c if (IS_ERR(handle)) { ext4_std_error(inode->i_sb, PTR_ERR(handle)); /* -@@ -252,6 +252,32 @@ void ext4_evict_inode(struct inode *inod +@@ -251,6 +251,32 @@ void ext4_evict_inode(struct inode *inod if (IS_SYNC(inode)) ext4_handle_sync(handle); @@ -101,7 +101,7 @@ Index: linux-stage/fs/ext4/inode.c inode->i_size = 0; err = ext4_mark_inode_dirty(handle, inode); if (err) { -@@ -269,10 +296,10 @@ void ext4_evict_inode(struct inode *inod +@@ -267,10 +293,10 @@ void ext4_evict_inode(struct inode *inod * enough credits left in the handle to remove the inode from * the orphan list and set the dtime field. */ @@ -115,7 +115,7 @@ Index: linux-stage/fs/ext4/inode.c if (err != 0) { ext4_warning(inode->i_sb, "couldn't extend journal (err %d)", err); -@@ -308,6 +335,9 @@ void ext4_evict_inode(struct inode *inod +@@ -307,6 +333,9 @@ void ext4_evict_inode(struct inode *inod ext4_free_inode(handle, inode); ext4_journal_stop(handle); sb_end_intwrite(inode->i_sb); @@ -125,7 +125,7 @@ Index: linux-stage/fs/ext4/inode.c return; no_delete: ext4_clear_inode(inode); /* We must guarantee clearing of inode... */ -@@ -4681,7 +4711,7 @@ static int ext4_index_trans_blocks(struc +@@ -5132,7 +5161,7 @@ static int ext4_index_trans_blocks(struc * * Also account for superblock, inode, quota and xattr blocks */ @@ -1032,7 +1032,7 @@ Index: linux-stage/fs/ext4/xattr.h #define BHDR(bh) ((struct ext4_xattr_header *)((bh)->b_data)) #define ENTRY(ptr) ((struct ext4_xattr_entry *)(ptr)) #define BFIRST(bh) ENTRY(BHDR(bh)+1) -@@ -75,10 +84,11 @@ struct ext4_xattr_entry { +@@ -75,10 +95,11 @@ struct ext4_xattr_entry { #define EXT4_ZERO_XATTR_VALUE ((void *)-1) struct ext4_xattr_info { @@ -1045,7 +1045,7 @@ Index: linux-stage/fs/ext4/xattr.h }; struct ext4_xattr_search { -@@ -106,7 +116,13 @@ extern int ext4_xattr_get(struct inode * +@@ -106,7 +127,13 @@ extern int ext4_xattr_get(struct inode * 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); @@ -1064,7 +1064,7 @@ Index: linux-stage/fs/ext4/ialloc.c =================================================================== --- linux-stage.orig/fs/ext4/ialloc.c +++ linux-stage/fs/ext4/ialloc.c -@@ -269,7 +269,6 @@ void ext4_free_inode(handle_t *handle, s +@@ -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); @@ -1085,3 +1085,31 @@ Index: linux-stage/fs/ext4/inline.c 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; diff --git a/ldiskfs/kernel_patches/patches/rhel7.7/ext4-large-eas.patch b/ldiskfs/kernel_patches/patches/rhel7.7/ext4-large-eas.patch index 3dbbb18..b9ae354 100644 --- a/ldiskfs/kernel_patches/patches/rhel7.7/ext4-large-eas.patch +++ b/ldiskfs/kernel_patches/patches/rhel7.7/ext4-large-eas.patch @@ -8,7 +8,7 @@ Index: linux-stage/fs/ext4/ext4.h =================================================================== --- linux-stage.orig/fs/ext4/ext4.h +++ linux-stage/fs/ext4/ext4.h -@@ -1579,6 +1579,7 @@ static inline void ext4_clear_state_flag +@@ -1620,6 +1620,7 @@ static inline void ext4_clear_state_flag EXT4_FEATURE_INCOMPAT_EXTENTS| \ EXT4_FEATURE_INCOMPAT_64BIT| \ EXT4_FEATURE_INCOMPAT_FLEX_BG| \ @@ -16,7 +16,7 @@ Index: linux-stage/fs/ext4/ext4.h EXT4_FEATURE_INCOMPAT_MMP | \ EXT4_FEATURE_INCOMPAT_DIRDATA| \ EXT4_FEATURE_INCOMPAT_INLINE_DATA) -@@ -1990,6 +1997,10 @@ struct mmpd_data { +@@ -2033,6 +2034,10 @@ struct mmpd_data { # define ATTRIB_NORET __attribute__((noreturn)) # define NORET_AND noreturn, @@ -27,7 +27,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, -@@ -2194,6 +2205,7 @@ extern void ext4_set_inode_flags(struct +@@ -2238,6 +2243,7 @@ extern void ext4_set_inode_flags(struct 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); @@ -39,7 +39,7 @@ Index: linux-stage/fs/ext4/inode.c =================================================================== --- linux-stage.orig/fs/ext4/inode.c +++ linux-stage/fs/ext4/inode.c -@@ -134,8 +134,6 @@ static void ext4_invalidatepage(struct p +@@ -136,8 +136,6 @@ static void ext4_invalidatepage(struct p 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 +48,7 @@ Index: linux-stage/fs/ext4/inode.c /* * Test whether an inode is a fast symlink. -@@ -184,6 +182,8 @@ void ext4_evict_inode(struct inode *inod +@@ -186,6 +184,8 @@ void ext4_evict_inode(struct inode *inod { handle_t *handle; int err; @@ -57,7 +57,7 @@ Index: linux-stage/fs/ext4/inode.c trace_ext4_evict_inode(inode); -@@ -236,8 +236,8 @@ void ext4_evict_inode(struct inode *inod +@@ -235,8 +235,8 @@ void ext4_evict_inode(struct inode *inod * protection against it */ sb_start_intwrite(inode->i_sb); @@ -68,7 +68,7 @@ Index: linux-stage/fs/ext4/inode.c if (IS_ERR(handle)) { ext4_std_error(inode->i_sb, PTR_ERR(handle)); /* -@@ -252,6 +252,32 @@ void ext4_evict_inode(struct inode *inod +@@ -251,6 +251,32 @@ void ext4_evict_inode(struct inode *inod if (IS_SYNC(inode)) ext4_handle_sync(handle); @@ -101,7 +101,7 @@ Index: linux-stage/fs/ext4/inode.c inode->i_size = 0; err = ext4_mark_inode_dirty(handle, inode); if (err) { -@@ -269,10 +296,10 @@ void ext4_evict_inode(struct inode *inod +@@ -267,10 +293,10 @@ void ext4_evict_inode(struct inode *inod * enough credits left in the handle to remove the inode from * the orphan list and set the dtime field. */ @@ -115,7 +115,7 @@ Index: linux-stage/fs/ext4/inode.c if (err != 0) { ext4_warning(inode->i_sb, "couldn't extend journal (err %d)", err); -@@ -308,6 +335,9 @@ void ext4_evict_inode(struct inode *inod +@@ -307,6 +333,9 @@ void ext4_evict_inode(struct inode *inod ext4_free_inode(handle, inode); ext4_journal_stop(handle); sb_end_intwrite(inode->i_sb); @@ -125,7 +125,7 @@ Index: linux-stage/fs/ext4/inode.c return; no_delete: ext4_clear_inode(inode); /* We must guarantee clearing of inode... */ -@@ -4681,7 +4711,7 @@ static int ext4_index_trans_blocks(struc +@@ -5140,7 +5169,7 @@ static int ext4_index_trans_blocks(struc * * Also account for superblock, inode, quota and xattr blocks */ @@ -1055,7 +1055,7 @@ Index: linux-stage/fs/ext4/xattr.h #define BHDR(bh) ((struct ext4_xattr_header *)((bh)->b_data)) #define ENTRY(ptr) ((struct ext4_xattr_entry *)(ptr)) #define BFIRST(bh) ENTRY(BHDR(bh)+1) -@@ -75,10 +84,11 @@ struct ext4_xattr_entry { +@@ -75,10 +95,11 @@ struct ext4_xattr_entry { #define EXT4_ZERO_XATTR_VALUE ((void *)-1) struct ext4_xattr_info { @@ -1068,7 +1068,7 @@ Index: linux-stage/fs/ext4/xattr.h }; struct ext4_xattr_search { -@@ -106,7 +116,13 @@ extern int ext4_xattr_get(struct inode * +@@ -106,7 +127,13 @@ extern int ext4_xattr_get(struct inode * 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); @@ -1087,7 +1087,7 @@ Index: linux-stage/fs/ext4/ialloc.c =================================================================== --- linux-stage.orig/fs/ext4/ialloc.c +++ linux-stage/fs/ext4/ialloc.c -@@ -269,7 +269,6 @@ void ext4_free_inode(handle_t *handle, s +@@ -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); @@ -1108,3 +1108,31 @@ Index: linux-stage/fs/ext4/inline.c 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 +@@ -2474,7 +2474,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 +@@ -967,7 +967,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; diff --git a/ldiskfs/kernel_patches/patches/suse15/ext4-large-eas.patch b/ldiskfs/kernel_patches/patches/suse15/ext4-large-eas.patch index 3dba254..9f013fb 100644 --- a/ldiskfs/kernel_patches/patches/suse15/ext4-large-eas.patch +++ b/ldiskfs/kernel_patches/patches/suse15/ext4-large-eas.patch @@ -47,11 +47,11 @@ Signed-off-by: Dan Carpenter fs/ext4/xattr.h | 33 ++- 6 files changed, 603 insertions(+), 55 deletions(-) -diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h -index ca73d33..6796a8b 100644 ---- a/fs/ext4/ext4.h -+++ b/fs/ext4/ext4.h -@@ -1811,6 +1811,7 @@ EXT4_FEATURE_INCOMPAT_FUNCS(encrypt, ENCRYPT) +Index: linux-stage/fs/ext4/ext4.h +=================================================================== +--- linux-stage.orig/fs/ext4/ext4.h ++++ linux-stage/fs/ext4/ext4.h +@@ -1811,6 +1811,7 @@ EXT4_FEATURE_INCOMPAT_FUNCS(encrypt, EN EXT4_FEATURE_INCOMPAT_EXTENTS| \ EXT4_FEATURE_INCOMPAT_64BIT| \ EXT4_FEATURE_INCOMPAT_FLEX_BG| \ @@ -59,19 +59,19 @@ index ca73d33..6796a8b 100644 EXT4_FEATURE_INCOMPAT_MMP | \ EXT4_FEATURE_INCOMPAT_DIRDATA| \ EXT4_FEATURE_INCOMPAT_INLINE_DATA | \ -@@ -2304,6 +2305,12 @@ struct mmpd_data { - */ +@@ -2305,6 +2306,12 @@ struct mmpd_data { #define EXT4_MMP_MAX_CHECK_INTERVAL 300UL -+/* + /* + * Maximum size of xattr attributes for FEATURE_INCOMPAT_EA_INODE 1Mb + * This limit is arbitrary, but is reasonable for the xattr API. + */ +#define EXT4_XATTR_MAX_LARGE_EA_SIZE (1024 * 1024) + - /* ++/* * Function prototypes */ + @@ -2316,6 +2323,10 @@ struct mmpd_data { # define ATTRIB_NORET __attribute__((noreturn)) # define NORET_AND noreturn, @@ -83,7 +83,7 @@ index ca73d33..6796a8b 100644 /* 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, -@@ -2572,6 +2583,7 @@ extern int ext4_truncate_restart_trans(handle_t *, struct inode *, int nblocks); +@@ -2572,6 +2583,7 @@ extern int ext4_truncate_restart_trans(h extern void ext4_set_inode_flags(struct inode *); extern int ext4_alloc_da_blocks(struct inode *inode); extern void ext4_set_aops(struct inode *inode); @@ -91,11 +91,11 @@ index ca73d33..6796a8b 100644 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, -diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c -index 7f9b8a5..0f284fb 100644 ---- a/fs/ext4/ialloc.c -+++ b/fs/ext4/ialloc.c -@@ -273,7 +273,6 @@ void ext4_free_inode(handle_t *handle, struct inode *inode) +Index: linux-stage/fs/ext4/ialloc.c +=================================================================== +--- linux-stage.orig/fs/ext4/ialloc.c ++++ linux-stage/fs/ext4/ialloc.c +@@ -273,7 +273,6 @@ void ext4_free_inode(handle_t *handle, s * as writing the quota to disk may need the lock as well. */ dquot_initialize(inode); @@ -103,11 +103,11 @@ index 7f9b8a5..0f284fb 100644 dquot_free_inode(inode); dquot_drop(inode); -diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c -index b27a736..69e46f9 100644 ---- a/fs/ext4/inline.c -+++ b/fs/ext4/inline.c -@@ -62,7 +62,7 @@ static int get_max_inline_xattr_value_size(struct inode *inode, +Index: linux-stage/fs/ext4/inline.c +=================================================================== +--- linux-stage.orig/fs/ext4/inline.c ++++ linux-stage/fs/ext4/inline.c +@@ -62,7 +62,7 @@ static int get_max_inline_xattr_value_si /* Compute min_offs. */ for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) { @@ -116,11 +116,11 @@ index b27a736..69e46f9 100644 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 19f38c4..c701c45 100644 ---- a/fs/ext4/inode.c -+++ b/fs/ext4/inode.c -@@ -140,8 +140,6 @@ static void ext4_invalidatepage(struct page *page, unsigned int offset, +Index: linux-stage/fs/ext4/inode.c +=================================================================== +--- linux-stage.orig/fs/ext4/inode.c ++++ linux-stage/fs/ext4/inode.c +@@ -140,8 +140,6 @@ static void ext4_invalidatepage(struct p 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); @@ -129,7 +129,7 @@ index 19f38c4..c701c45 100644 /* * Test whether an inode is a fast symlink. -@@ -190,6 +188,8 @@ void ext4_evict_inode(struct inode *inode) +@@ -190,6 +188,8 @@ void ext4_evict_inode(struct inode *inod { handle_t *handle; int err; @@ -138,7 +138,7 @@ index 19f38c4..c701c45 100644 trace_ext4_evict_inode(inode); -@@ -240,8 +240,8 @@ void ext4_evict_inode(struct inode *inode) +@@ -240,8 +240,8 @@ void ext4_evict_inode(struct inode *inod * protection against it */ sb_start_intwrite(inode->i_sb); @@ -149,7 +149,7 @@ index 19f38c4..c701c45 100644 if (IS_ERR(handle)) { ext4_std_error(inode->i_sb, PTR_ERR(handle)); /* -@@ -253,9 +253,36 @@ void ext4_evict_inode(struct inode *inode) +@@ -253,9 +253,36 @@ void ext4_evict_inode(struct inode *inod sb_end_intwrite(inode->i_sb); goto no_delete; } @@ -187,7 +187,7 @@ index 19f38c4..c701c45 100644 inode->i_size = 0; err = ext4_mark_inode_dirty(handle, inode); if (err) { -@@ -279,10 +306,10 @@ void ext4_evict_inode(struct inode *inode) +@@ -279,10 +306,10 @@ void ext4_evict_inode(struct inode *inod * enough credits left in the handle to remove the inode from * the orphan list and set the dtime field. */ @@ -201,7 +201,7 @@ index 19f38c4..c701c45 100644 if (err != 0) { ext4_warning(inode->i_sb, "couldn't extend journal (err %d)", err); -@@ -317,8 +344,12 @@ void ext4_evict_inode(struct inode *inode) +@@ -317,8 +344,12 @@ void ext4_evict_inode(struct inode *inod ext4_clear_inode(inode); else ext4_free_inode(handle, inode); @@ -214,7 +214,7 @@ index 19f38c4..c701c45 100644 return; no_delete: ext4_clear_inode(inode); /* We must guarantee clearing of inode... */ -@@ -5624,7 +5655,7 @@ static int ext4_index_trans_blocks(struct inode *inode, int lblocks, +@@ -5627,7 +5658,7 @@ static int ext4_index_trans_blocks(struc * * Also account for superblock, inode, quota and xattr blocks */ @@ -223,11 +223,11 @@ index 19f38c4..c701c45 100644 int pextents) { ext4_group_t groups, ngroups = ext4_get_groups_count(inode->i_sb); -diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c -index 45accaa..8f16071 100644 ---- a/fs/ext4/xattr.c -+++ b/fs/ext4/xattr.c -@@ -180,9 +180,8 @@ ext4_xattr_check_entries(struct ext4_xattr_entry *entry, void *end, +Index: linux-stage/fs/ext4/xattr.c +=================================================================== +--- linux-stage.orig/fs/ext4/xattr.c ++++ linux-stage/fs/ext4/xattr.c +@@ -180,9 +180,8 @@ ext4_xattr_check_entries(struct ext4_xat /* Check the values */ while (!IS_LAST_ENTRY(entry)) { @@ -239,7 +239,7 @@ index 45accaa..8f16071 100644 u16 offs = le16_to_cpu(entry->e_value_offs); u32 size = le32_to_cpu(entry->e_value_size); void *value; -@@ -287,6 +286,99 @@ xattr_find_entry(struct inode *inode, struct ext4_xattr_entry **pentry, +@@ -287,6 +286,99 @@ xattr_find_entry(struct inode *inode, st return cmp ? -ENODATA : 0; } @@ -339,7 +339,7 @@ index 45accaa..8f16071 100644 static int ext4_xattr_block_get(struct inode *inode, int name_index, const char *name, void *buffer, size_t buffer_size) -@@ -325,8 +417,16 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name, +@@ -325,8 +417,16 @@ ext4_xattr_block_get(struct inode *inode error = -ERANGE; if (size > buffer_size) goto cleanup; @@ -358,7 +358,7 @@ index 45accaa..8f16071 100644 } error = size; -@@ -367,8 +467,16 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name, +@@ -367,8 +467,16 @@ ext4_xattr_ibody_get(struct inode *inode error = -ERANGE; if (size > buffer_size) goto cleanup; @@ -377,7 +377,7 @@ index 45accaa..8f16071 100644 } error = size; -@@ -634,7 +742,7 @@ static size_t ext4_xattr_free_space(struct ext4_xattr_entry *last, +@@ -634,7 +742,7 @@ static size_t ext4_xattr_free_space(stru size_t *min_offs, void *base, int *total) { for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) { @@ -386,7 +386,7 @@ index 45accaa..8f16071 100644 size_t offs = le16_to_cpu(last->e_value_offs); if (offs < *min_offs) *min_offs = offs; -@@ -645,11 +753,166 @@ static size_t ext4_xattr_free_space(struct ext4_xattr_entry *last, +@@ -645,11 +753,166 @@ static size_t ext4_xattr_free_space(stru return (*min_offs - ((void *)last - base) - sizeof(__u32)); } @@ -555,7 +555,7 @@ index 45accaa..8f16071 100644 /* Compute min_offs and last. */ last = s->first; -@@ -657,7 +920,7 @@ ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s) +@@ -657,7 +920,7 @@ ext4_xattr_set_entry(struct ext4_xattr_i next = EXT4_XATTR_NEXT(last); if ((void *)next >= s->end) return -EFSCORRUPTED; @@ -564,7 +564,7 @@ index 45accaa..8f16071 100644 size_t offs = le16_to_cpu(last->e_value_offs); if (offs < min_offs) min_offs = offs; -@@ -665,15 +928,20 @@ ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s) +@@ -665,15 +928,20 @@ ext4_xattr_set_entry(struct ext4_xattr_i } free = min_offs - ((void *)last - s->base) - sizeof(__u32); if (!s->not_found) { @@ -588,7 +588,7 @@ index 45accaa..8f16071 100644 return -ENOSPC; } -@@ -687,7 +955,8 @@ ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s) +@@ -687,7 +955,8 @@ ext4_xattr_set_entry(struct ext4_xattr_i s->here->e_name_len = name_len; memcpy(s->here->e_name, i->name, name_len); } else { @@ -598,7 +598,7 @@ index 45accaa..8f16071 100644 void *first_val = s->base + min_offs; size_t offs = le16_to_cpu(s->here->e_value_offs); void *val = s->base + offs; -@@ -721,12 +990,18 @@ ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s) +@@ -721,12 +990,18 @@ ext4_xattr_set_entry(struct ext4_xattr_i last = s->first; while (!IS_LAST_ENTRY(last)) { size_t o = le16_to_cpu(last->e_value_offs); @@ -618,7 +618,7 @@ index 45accaa..8f16071 100644 if (!i->value) { /* Remove the old name. */ size_t size = EXT4_XATTR_LEN(name_len); -@@ -739,11 +1014,20 @@ ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s) +@@ -739,11 +1014,20 @@ ext4_xattr_set_entry(struct ext4_xattr_i if (i->value) { /* Insert the new value. */ @@ -641,7 +641,7 @@ index 45accaa..8f16071 100644 if (i->value == EXT4_ZERO_XATTR_VALUE) { memset(val, 0, size); } else { -@@ -753,8 +1037,11 @@ ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s) +@@ -753,8 +1037,11 @@ ext4_xattr_set_entry(struct ext4_xattr_i memcpy(val, i->value, i->value_len); } } @@ -654,7 +654,7 @@ index 45accaa..8f16071 100644 } struct ext4_xattr_block_find { -@@ -815,8 +1102,6 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, +@@ -815,8 +1102,6 @@ ext4_xattr_block_set(handle_t *handle, s #define header(x) ((struct ext4_xattr_header *)(x)) @@ -663,7 +663,7 @@ index 45accaa..8f16071 100644 if (s->base) { BUFFER_TRACE(bs->bh, "get_write_access"); error = ext4_journal_get_write_access(handle, bs->bh); -@@ -835,7 +1120,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, +@@ -835,7 +1120,7 @@ ext4_xattr_block_set(handle_t *handle, s mb_cache_entry_delete_block(ext4_mb_cache, hash, bs->bh->b_blocknr); ea_bdebug(bs->bh, "modifying in-place"); @@ -672,7 +672,7 @@ index 45accaa..8f16071 100644 if (!error) { if (!IS_LAST_ENTRY(s->first)) ext4_xattr_rehash(header(s->base), -@@ -884,7 +1169,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, +@@ -884,7 +1169,7 @@ ext4_xattr_block_set(handle_t *handle, s s->end = s->base + sb->s_blocksize; } @@ -681,7 +681,7 @@ index 45accaa..8f16071 100644 if (error == -EFSCORRUPTED) goto bad_block; if (error) -@@ -1084,7 +1369,7 @@ int ext4_xattr_ibody_inline_set(handle_t *handle, struct inode *inode, +@@ -1084,7 +1369,7 @@ int ext4_xattr_ibody_inline_set(handle_t if (EXT4_I(inode)->i_extra_isize == 0) return -ENOSPC; @@ -690,7 +690,7 @@ index 45accaa..8f16071 100644 if (error) return error; header = IHDR(inode, ext4_raw_inode(&is->iloc)); -@@ -1098,7 +1383,7 @@ int ext4_xattr_ibody_inline_set(handle_t *handle, struct inode *inode, +@@ -1098,7 +1383,7 @@ int ext4_xattr_ibody_inline_set(handle_t return 0; } @@ -699,7 +699,7 @@ index 45accaa..8f16071 100644 struct ext4_xattr_info *i, struct ext4_xattr_ibody_find *is) { -@@ -1108,7 +1393,7 @@ static int ext4_xattr_ibody_set(struct inode *inode, +@@ -1108,7 +1393,7 @@ static int ext4_xattr_ibody_set(struct i if (EXT4_I(inode)->i_extra_isize == 0) return -ENOSPC; @@ -708,7 +708,7 @@ index 45accaa..8f16071 100644 if (error) return error; header = IHDR(inode, ext4_raw_inode(&is->iloc)); -@@ -1155,7 +1440,7 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, +@@ -1155,7 +1440,7 @@ ext4_xattr_set_handle(handle_t *handle, .name = name, .value = value, .value_len = value_len, @@ -717,7 +717,7 @@ index 45accaa..8f16071 100644 }; struct ext4_xattr_ibody_find is = { .s = { .not_found = -ENODATA, }, -@@ -1204,7 +1489,7 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, +@@ -1204,7 +1489,7 @@ ext4_xattr_set_handle(handle_t *handle, } if (!value) { if (!is.s.not_found) @@ -726,7 +726,7 @@ index 45accaa..8f16071 100644 else if (!bs.s.not_found) error = ext4_xattr_block_set(handle, inode, &i, &bs); } else { -@@ -1215,7 +1500,7 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, +@@ -1215,7 +1500,7 @@ ext4_xattr_set_handle(handle_t *handle, if (!bs.s.not_found && ext4_xattr_value_same(&bs.s, &i)) goto cleanup; @@ -735,7 +735,7 @@ index 45accaa..8f16071 100644 if (!error && !bs.s.not_found) { i.value = NULL; error = ext4_xattr_block_set(handle, inode, &i, &bs); -@@ -1228,11 +1513,20 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, +@@ -1228,11 +1513,20 @@ ext4_xattr_set_handle(handle_t *handle, goto cleanup; } error = ext4_xattr_block_set(handle, inode, &i, &bs); @@ -757,7 +757,7 @@ index 45accaa..8f16071 100644 } } } -@@ -1271,12 +1565,26 @@ ext4_xattr_set(struct inode *inode, int name_index, const char *name, +@@ -1271,12 +1565,26 @@ ext4_xattr_set(struct inode *inode, int const void *value, size_t value_len, int flags) { handle_t *handle; @@ -793,7 +793,7 @@ index 45accaa..8f16071 100644 goto retry; if (error == 0) error = error2; -@@ -1313,7 +1621,7 @@ static void ext4_xattr_shift_entries(struct ext4_xattr_entry *entry, +@@ -1313,7 +1621,7 @@ static void ext4_xattr_shift_entries(str /* Adjust the value offsets of the entries */ for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) { @@ -802,7 +802,7 @@ index 45accaa..8f16071 100644 new_offs = le16_to_cpu(last->e_value_offs) + value_offs_shift; last->e_value_offs = cpu_to_le16(new_offs); -@@ -1374,7 +1682,7 @@ static int ext4_xattr_move_to_block(handle_t *handle, struct inode *inode, +@@ -1374,7 +1682,7 @@ static int ext4_xattr_move_to_block(hand goto out; /* Remove the chosen entry from the inode */ @@ -952,7 +952,7 @@ index 45accaa..8f16071 100644 bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl); if (!bh) { EXT4_ERROR_INODE(inode, "block %llu read error", -@@ -1605,11 +2027,69 @@ ext4_xattr_delete_inode(handle_t *handle, struct inode *inode) +@@ -1605,11 +2027,69 @@ ext4_xattr_delete_inode(handle_t *handle EXT4_I(inode)->i_file_acl); goto cleanup; } @@ -1022,7 +1022,7 @@ index 45accaa..8f16071 100644 } /* -@@ -1661,10 +2141,9 @@ ext4_xattr_cmp(struct ext4_xattr_header *header1, +@@ -1661,10 +2141,9 @@ ext4_xattr_cmp(struct ext4_xattr_header entry1->e_name_index != entry2->e_name_index || entry1->e_name_len != entry2->e_name_len || entry1->e_value_size != entry2->e_value_size || @@ -1034,7 +1034,7 @@ index 45accaa..8f16071 100644 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))) -@@ -1736,7 +2215,7 @@ static inline void ext4_xattr_hash_entry(struct ext4_xattr_header *header, +@@ -1736,7 +2215,7 @@ static inline void ext4_xattr_hash_entry *name++; } @@ -1043,10 +1043,10 @@ index 45accaa..8f16071 100644 __le32 *value = (__le32 *)((char *)header + le16_to_cpu(entry->e_value_offs)); for (n = (le32_to_cpu(entry->e_value_size) + -diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h -index 099c8b6..6e10ff9 100644 ---- a/fs/ext4/xattr.h -+++ b/fs/ext4/xattr.h +Index: linux-stage/fs/ext4/xattr.h +=================================================================== +--- linux-stage.orig/fs/ext4/xattr.h ++++ linux-stage/fs/ext4/xattr.h @@ -44,7 +44,7 @@ struct ext4_xattr_entry { __u8 e_name_len; /* length of name */ __u8 e_name_index; /* attribute name index */ @@ -1096,7 +1096,7 @@ index 099c8b6..6e10ff9 100644 }; struct ext4_xattr_search { -@@ -140,7 +161,13 @@ extern int ext4_xattr_get(struct inode *, int, const char *, void *, size_t); +@@ -140,7 +161,13 @@ extern int ext4_xattr_get(struct inode * 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); @@ -1111,6 +1111,31 @@ index 099c8b6..6e10ff9 100644 extern int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize, struct ext4_inode *raw_inode, handle_t *handle); --- -2.20.1 - +Index: linux-stage/fs/ext4/extents.c +=================================================================== +--- linux-stage.orig/fs/ext4/extents.c ++++ linux-stage/fs/ext4/extents.c +@@ -2494,7 +2494,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 +@@ -835,7 +835,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; diff --git a/lustre/osd-ldiskfs/osd_handler.c b/lustre/osd-ldiskfs/osd_handler.c index 8337dd2..2f62ce5 100644 --- a/lustre/osd-ldiskfs/osd_handler.c +++ b/lustre/osd-ldiskfs/osd_handler.c @@ -2109,6 +2109,9 @@ static void osd_object_delete(const struct lu_env *env, struct lu_object *l) if (!inode) return; + if (osd_has_index(obj) && obj->oo_dt.do_index_ops == &osd_index_iam_ops) + ldiskfs_set_inode_flag(inode, LDISKFS_INODE_JOURNAL_DATA); + uid = i_uid_read(inode); gid = i_gid_read(inode); projid = i_projid_read(inode); diff --git a/lustre/osd-ldiskfs/osd_io.c b/lustre/osd-ldiskfs/osd_io.c index 4623053..0cf03c4 100644 --- a/lustre/osd-ldiskfs/osd_io.c +++ b/lustre/osd-ldiskfs/osd_io.c @@ -1689,11 +1689,11 @@ static int osd_ldiskfs_write_record(struct dt_object *dt, void *buf, loff_t new_size = i_size_read(inode); unsigned long block; int blocksize = 1 << inode->i_blkbits; + struct ldiskfs_inode_info *ei = LDISKFS_I(inode); int err = 0; int size; int boffs; int dirty_inode = 0; - struct ldiskfs_inode_info *ei = LDISKFS_I(inode); bool create, sparse, sync = false; if (write_NUL) { @@ -1706,6 +1706,8 @@ static int osd_ldiskfs_write_record(struct dt_object *dt, void *buf, ++bufsize; } + dirty_inode = test_and_set_bit(LDISKFS_INODE_JOURNAL_DATA, &ei->i_flags); + /* sparse checking is racy, but sparse is very rare case, leave as is */ sparse = (new_size > 0 && (inode->i_blocks >> (inode->i_blkbits - 9)) < ((new_size - 1) >> inode->i_blkbits) + 1); @@ -1809,14 +1811,14 @@ static int osd_ldiskfs_write_record(struct dt_object *dt, void *buf, spin_lock(&inode->i_lock); if (new_size > i_size_read(inode)) i_size_write(inode, new_size); - if (i_size_read(inode) > LDISKFS_I(inode)->i_disksize) { - LDISKFS_I(inode)->i_disksize = i_size_read(inode); + if (i_size_read(inode) > ei->i_disksize) { + ei->i_disksize = i_size_read(inode); dirty_inode = 1; } spin_unlock(&inode->i_lock); - if (dirty_inode) - osd_dirty_inode(inode, I_DIRTY_DATASYNC); } + if (dirty_inode) + osd_dirty_inode(inode, I_DIRTY_DATASYNC); if (err == 0) *offs = offset; diff --git a/lustre/osd-ldiskfs/osd_scrub.c b/lustre/osd-ldiskfs/osd_scrub.c index 7ad1f8d..5130fe7 100644 --- a/lustre/osd-ldiskfs/osd_scrub.c +++ b/lustre/osd-ldiskfs/osd_scrub.c @@ -2601,6 +2601,7 @@ int osd_scrub_setup(const struct lu_env *env, struct osd_device *dev) } inode = file_inode(filp); + ldiskfs_set_inode_flag(inode, LDISKFS_INODE_JOURNAL_DATA); if (!dev->od_dt_dev.dd_rdonly) { /* 'What the @fid is' is not imporatant, because the object * has no OI mapping, and only is visible inside the OSD.*/ -- 1.8.3.1