diff --git a/patches.suse/ext4-Support-for-checksumming-from-journal-triggers.patch b/patches.suse/ext4-Support-for-checksumming-from-journal-triggers.patch new file mode 100644 index 0000000..bf5477d --- /dev/null +++ b/patches.suse/ext4-Support-for-checksumming-from-journal-triggers.patch @@ -0,0 +1,1202 @@ +From f9130c5a68e56ebbfc745fc1dbd02ec0d74f2c3f Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Mon, 16 Aug 2021 11:57:04 +0200 +Subject: [PATCH] ext4: Support for checksumming from journal triggers +Git-commit: 188c299e2a26cc33747187f87c9e044dfd85a782 +Patch-mainline: v5.15-rc1 +References: bsc#1194163 + +JBD2 layer support triggers which are called when journaling layer moves +buffer to a certain state. We can use the frozen trigger, which gets +called when buffer data is frozen and about to be written out to the +journal, to compute block checksums for some buffer types (similarly as +does ocfs2). This avoids unnecessary repeated recomputation of the +checksum (at the cost of larger window where memory corruption won't be +caught by checksumming) and is even necessary when there are +unsynchronized updaters of the checksummed data. + +So add superblock and journal trigger type arguments to +ext4_journal_get_write_access() and ext4_journal_get_create_access() so +that frozen triggers can be set accordingly. Also add inode argument to +ext4_walk_page_buffers() and all the callbacks used with that function +for the same purpose. This patch is mostly only a change of prototype of +the above mentioned functions and a few small helpers. Real checksumming +will come later. + +Reviewed-by: Theodore Ts'o +Signed-off-by: Jan Kara +Link: https://lore.kernel.org/r/20210816095713.16537-1-jack@suse.cz +Signed-off-by: Theodore Ts'o +[ddiss: flag ext4_setup_csum_trigger() __always_unused] +Acked-by: David Disseldorp + +--- + fs/ext4/ext4.h | 26 ++++++++++++++- + fs/ext4/ext4_jbd2.c | 43 ++++++++++++++++++------- + fs/ext4/ext4_jbd2.h | 18 +++++++--- + fs/ext4/extents.c | 12 ++++--- + fs/ext4/file.c | 3 + + fs/ext4/ialloc.c | 19 +++++++---- + fs/ext4/indirect.c | 15 +++++--- + fs/ext4/inline.c | 26 ++++++++++----- + fs/ext4/inode.c | 84 +++++++++++++++++++++++++++++--------------------- + fs/ext4/ioctl.c | 4 +- + fs/ext4/mballoc.c | 15 +++++--- + fs/ext4/namei.c | 40 +++++++++++++++-------- + fs/ext4/resize.c | 38 +++++++++++++--------- + fs/ext4/super.c | 16 ++++++++- + fs/ext4/xattr.c | 26 ++++++++++----- + fs/jbd2/transaction.c | 2 - + 16 files changed, 259 insertions(+), 128 deletions(-) + +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -1447,6 +1447,24 @@ struct ext4_super_block { + + #define EXT4_ENC_UTF8_12_1 1 + ++/* Types of ext4 journal triggers */ ++enum ext4_journal_trigger_type { ++ EXT4_JTR_NONE /* This must be the last entry for indexing to work! */ ++}; ++ ++#define EXT4_JOURNAL_TRIGGER_COUNT EXT4_JTR_NONE ++ ++struct ext4_journal_trigger { ++ struct jbd2_buffer_trigger_type tr_triggers; ++ struct super_block *sb; ++}; ++ ++static inline struct ext4_journal_trigger *EXT4_TRIGGER( ++ struct jbd2_buffer_trigger_type *trigger) ++{ ++ return container_of(trigger, struct ext4_journal_trigger, tr_triggers); ++} ++ + /* + * fourth extended-fs super-block data in memory + */ +@@ -1625,6 +1643,9 @@ struct ext4_sb_info { + struct mb_cache *s_ea_inode_cache; + spinlock_t s_es_lock ____cacheline_aligned_in_smp; + ++ /* Journal triggers for checksum computation */ ++ struct ext4_journal_trigger s_journal_triggers[EXT4_JOURNAL_TRIGGER_COUNT]; ++ + /* Ratelimit ext4 messages. */ + struct ratelimit_state s_err_ratelimit_state; + struct ratelimit_state s_warning_ratelimit_state; +@@ -2920,13 +2941,14 @@ int ext4_get_block(struct inode *inode, + int ext4_da_get_block_prep(struct inode *inode, sector_t iblock, + struct buffer_head *bh, int create); + int ext4_walk_page_buffers(handle_t *handle, ++ struct inode *inode, + struct buffer_head *head, + unsigned from, + unsigned to, + int *partial, +- int (*fn)(handle_t *handle, ++ int (*fn)(handle_t *handle, struct inode *inode, + struct buffer_head *bh)); +-int do_journal_get_write_access(handle_t *handle, ++int do_journal_get_write_access(handle_t *handle, struct inode *inode, + struct buffer_head *bh); + #define FALL_BACK_TO_NONDELALLOC 1 + #define CONVERT_INLINE_DATA 2 +--- a/fs/ext4/ext4_jbd2.c ++++ b/fs/ext4/ext4_jbd2.c +@@ -218,9 +218,11 @@ static void ext4_check_bdev_write_error( + } + + int __ext4_journal_get_write_access(const char *where, unsigned int line, +- handle_t *handle, struct buffer_head *bh) ++ handle_t *handle, struct super_block *sb, ++ struct buffer_head *bh, ++ enum ext4_journal_trigger_type trigger_type) + { +- int err = 0; ++ int err; + + might_sleep(); + +@@ -229,11 +231,18 @@ int __ext4_journal_get_write_access(cons + + if (ext4_handle_valid(handle)) { + err = jbd2_journal_get_write_access(handle, bh); +- if (err) ++ if (err) { + ext4_journal_abort_handle(where, line, __func__, bh, + handle, err); ++ return err; ++ } + } +- return err; ++ if (trigger_type == EXT4_JTR_NONE || !ext4_has_metadata_csum(sb)) ++ return 0; ++ BUG_ON(trigger_type >= EXT4_JOURNAL_TRIGGER_COUNT); ++ jbd2_journal_set_triggers(bh, ++ &EXT4_SB(sb)->s_journal_triggers[trigger_type].tr_triggers); ++ return 0; + } + + /* +@@ -301,17 +310,27 @@ int __ext4_forget(const char *where, uns + } + + int __ext4_journal_get_create_access(const char *where, unsigned int line, +- handle_t *handle, struct buffer_head *bh) ++ handle_t *handle, struct super_block *sb, ++ struct buffer_head *bh, ++ enum ext4_journal_trigger_type trigger_type) + { +- int err = 0; ++ int err; + +- if (ext4_handle_valid(handle)) { +- err = jbd2_journal_get_create_access(handle, bh); +- if (err) +- ext4_journal_abort_handle(where, line, __func__, +- bh, handle, err); ++ if (!ext4_handle_valid(handle)) ++ return 0; ++ ++ err = jbd2_journal_get_create_access(handle, bh); ++ if (err) { ++ ext4_journal_abort_handle(where, line, __func__, bh, handle, ++ err); ++ return err; + } +- return err; ++ if (trigger_type == EXT4_JTR_NONE || !ext4_has_metadata_csum(sb)) ++ return 0; ++ BUG_ON(trigger_type >= EXT4_JOURNAL_TRIGGER_COUNT); ++ jbd2_journal_set_triggers(bh, ++ &EXT4_SB(sb)->s_journal_triggers[trigger_type].tr_triggers); ++ return 0; + } + + int __ext4_handle_dirty_metadata(const char *where, unsigned int line, +--- a/fs/ext4/ext4_jbd2.h ++++ b/fs/ext4/ext4_jbd2.h +@@ -231,26 +231,32 @@ int ext4_expand_extra_isize(struct inode + * Wrapper functions with which ext4 calls into JBD. + */ + int __ext4_journal_get_write_access(const char *where, unsigned int line, +- handle_t *handle, struct buffer_head *bh); ++ handle_t *handle, struct super_block *sb, ++ struct buffer_head *bh, ++ enum ext4_journal_trigger_type trigger_type); + + int __ext4_forget(const char *where, unsigned int line, handle_t *handle, + int is_metadata, struct inode *inode, + struct buffer_head *bh, ext4_fsblk_t blocknr); + + int __ext4_journal_get_create_access(const char *where, unsigned int line, +- handle_t *handle, struct buffer_head *bh); ++ handle_t *handle, struct super_block *sb, ++ struct buffer_head *bh, ++ enum ext4_journal_trigger_type trigger_type); + + int __ext4_handle_dirty_metadata(const char *where, unsigned int line, + handle_t *handle, struct inode *inode, + struct buffer_head *bh); + +-#define ext4_journal_get_write_access(handle, bh) \ +- __ext4_journal_get_write_access(__func__, __LINE__, (handle), (bh)) ++#define ext4_journal_get_write_access(handle, sb, bh, trigger_type) \ ++ __ext4_journal_get_write_access(__func__, __LINE__, (handle), (sb), \ ++ (bh), (trigger_type)) + #define ext4_forget(handle, is_metadata, inode, bh, block_nr) \ + __ext4_forget(__func__, __LINE__, (handle), (is_metadata), (inode), \ + (bh), (block_nr)) +-#define ext4_journal_get_create_access(handle, bh) \ +- __ext4_journal_get_create_access(__func__, __LINE__, (handle), (bh)) ++#define ext4_journal_get_create_access(handle, sb, bh, trigger_type) \ ++ __ext4_journal_get_create_access(__func__, __LINE__, (handle), (sb), \ ++ (bh), (trigger_type)) + #define ext4_handle_dirty_metadata(handle, inode, bh) \ + __ext4_handle_dirty_metadata(__func__, __LINE__, (handle), (inode), \ + (bh)) +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -139,7 +139,8 @@ static int ext4_ext_get_access(handle_t + if (path->p_bh) { + /* path points to block */ + BUFFER_TRACE(path->p_bh, "get_write_access"); +- return ext4_journal_get_write_access(handle, path->p_bh); ++ return ext4_journal_get_write_access(handle, inode->i_sb, ++ path->p_bh, EXT4_JTR_NONE); + } + /* path points to leaf/index in inode body */ + /* we use in-core data, no need to protect them */ +@@ -1082,7 +1083,8 @@ static int ext4_ext_split(handle_t *hand + } + lock_buffer(bh); + +- err = ext4_journal_get_create_access(handle, bh); ++ err = ext4_journal_get_create_access(handle, inode->i_sb, bh, ++ EXT4_JTR_NONE); + if (err) + goto cleanup; + +@@ -1160,7 +1162,8 @@ static int ext4_ext_split(handle_t *hand + } + lock_buffer(bh); + +- err = ext4_journal_get_create_access(handle, bh); ++ err = ext4_journal_get_create_access(handle, inode->i_sb, bh, ++ EXT4_JTR_NONE); + if (err) + goto cleanup; + +@@ -1286,7 +1289,8 @@ static int ext4_ext_grow_indepth(handle_ + return -ENOMEM; + lock_buffer(bh); + +- err = ext4_journal_get_create_access(handle, bh); ++ err = ext4_journal_get_create_access(handle, inode->i_sb, bh, ++ EXT4_JTR_NONE); + if (err) { + unlock_buffer(bh); + goto out; +--- a/fs/ext4/file.c ++++ b/fs/ext4/file.c +@@ -822,7 +822,8 @@ static int ext4_sample_last_mounted(stru + if (IS_ERR(handle)) + goto out; + BUFFER_TRACE(sbi->s_sbh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, sbi->s_sbh); ++ err = ext4_journal_get_write_access(handle, sb, sbi->s_sbh, ++ EXT4_JTR_NONE); + if (err) + goto out_journal; + lock_buffer(sbi->s_sbh); +--- a/fs/ext4/ialloc.c ++++ b/fs/ext4/ialloc.c +@@ -300,7 +300,8 @@ void ext4_free_inode(handle_t *handle, s + } + + BUFFER_TRACE(bitmap_bh, "get_write_access"); +- fatal = ext4_journal_get_write_access(handle, bitmap_bh); ++ fatal = ext4_journal_get_write_access(handle, sb, bitmap_bh, ++ EXT4_JTR_NONE); + if (fatal) + goto error_return; + +@@ -308,7 +309,8 @@ void ext4_free_inode(handle_t *handle, s + gdp = ext4_get_group_desc(sb, block_group, &bh2); + if (gdp) { + BUFFER_TRACE(bh2, "get_write_access"); +- fatal = ext4_journal_get_write_access(handle, bh2); ++ fatal = ext4_journal_get_write_access(handle, sb, bh2, ++ EXT4_JTR_NONE); + } + ext4_lock_group(sb, block_group); + cleared = ext4_test_and_clear_bit(bit, bitmap_bh->b_data); +@@ -1085,7 +1087,8 @@ repeat_in_this_group: + } + } + BUFFER_TRACE(inode_bitmap_bh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, inode_bitmap_bh); ++ err = ext4_journal_get_write_access(handle, sb, inode_bitmap_bh, ++ EXT4_JTR_NONE); + if (err) { + ext4_std_error(sb, err); + goto out; +@@ -1127,7 +1130,8 @@ got: + } + + BUFFER_TRACE(group_desc_bh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, group_desc_bh); ++ err = ext4_journal_get_write_access(handle, sb, group_desc_bh, ++ EXT4_JTR_NONE); + if (err) { + ext4_std_error(sb, err); + goto out; +@@ -1144,7 +1148,8 @@ got: + goto out; + } + BUFFER_TRACE(block_bitmap_bh, "get block bitmap access"); +- err = ext4_journal_get_write_access(handle, block_bitmap_bh); ++ err = ext4_journal_get_write_access(handle, sb, block_bitmap_bh, ++ EXT4_JTR_NONE); + if (err) { + brelse(block_bitmap_bh); + ext4_std_error(sb, err); +@@ -1583,8 +1588,8 @@ int ext4_init_inode_table(struct super_b + num = sbi->s_itb_per_group - used_blks; + + BUFFER_TRACE(group_desc_bh, "get_write_access"); +- ret = ext4_journal_get_write_access(handle, +- group_desc_bh); ++ ret = ext4_journal_get_write_access(handle, sb, group_desc_bh, ++ EXT4_JTR_NONE); + if (ret) + goto err_out; + +--- a/fs/ext4/indirect.c ++++ b/fs/ext4/indirect.c +@@ -354,7 +354,8 @@ static int ext4_alloc_branch(handle_t *h + } + lock_buffer(bh); + BUFFER_TRACE(bh, "call get_create_access"); +- err = ext4_journal_get_create_access(handle, bh); ++ err = ext4_journal_get_create_access(handle, ar->inode->i_sb, ++ bh, EXT4_JTR_NONE); + if (err) { + unlock_buffer(bh); + goto failed; +@@ -429,7 +430,8 @@ static int ext4_splice_branch(handle_t * + */ + if (where->bh) { + BUFFER_TRACE(where->bh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, where->bh); ++ err = ext4_journal_get_write_access(handle, ar->inode->i_sb, ++ where->bh, EXT4_JTR_NONE); + if (err) + goto err_out; + } +@@ -728,7 +730,8 @@ static int ext4_ind_truncate_ensure_cred + return ret; + if (bh) { + BUFFER_TRACE(bh, "retaking write access"); +- ret = ext4_journal_get_write_access(handle, bh); ++ ret = ext4_journal_get_write_access(handle, inode->i_sb, bh, ++ EXT4_JTR_NONE); + if (unlikely(ret)) + return ret; + } +@@ -916,7 +919,8 @@ static void ext4_free_data(handle_t *han + + if (this_bh) { /* For indirect block */ + BUFFER_TRACE(this_bh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, this_bh); ++ err = ext4_journal_get_write_access(handle, inode->i_sb, ++ this_bh, EXT4_JTR_NONE); + /* Important: if we can't update the indirect pointers + * to the blocks, we can't free them. */ + if (err) +@@ -1079,7 +1083,8 @@ static void ext4_free_branches(handle_t + */ + BUFFER_TRACE(parent_bh, "get_write_access"); + if (!ext4_journal_get_write_access(handle, +- parent_bh)){ ++ inode->i_sb, parent_bh, ++ EXT4_JTR_NONE)) { + *p = 0; + BUFFER_TRACE(parent_bh, + "call ext4_handle_dirty_metadata"); +--- a/fs/ext4/inline.c ++++ b/fs/ext4/inline.c +@@ -264,7 +264,8 @@ static int ext4_create_inline_data(handl + return error; + + BUFFER_TRACE(is.iloc.bh, "get_write_access"); +- error = ext4_journal_get_write_access(handle, is.iloc.bh); ++ error = ext4_journal_get_write_access(handle, inode->i_sb, is.iloc.bh, ++ EXT4_JTR_NONE); + if (error) + goto out; + +@@ -350,7 +351,8 @@ static int ext4_update_inline_data(handl + goto out; + + BUFFER_TRACE(is.iloc.bh, "get_write_access"); +- error = ext4_journal_get_write_access(handle, is.iloc.bh); ++ error = ext4_journal_get_write_access(handle, inode->i_sb, is.iloc.bh, ++ EXT4_JTR_NONE); + if (error) + goto out; + +@@ -427,7 +429,8 @@ static int ext4_destroy_inline_data_nolo + goto out; + + BUFFER_TRACE(is.iloc.bh, "get_write_access"); +- error = ext4_journal_get_write_access(handle, is.iloc.bh); ++ error = ext4_journal_get_write_access(handle, inode->i_sb, is.iloc.bh, ++ EXT4_JTR_NONE); + if (error) + goto out; + +@@ -593,7 +596,7 @@ retry: + ret = __block_write_begin(page, from, to, ext4_get_block); + + if (!ret && ext4_should_journal_data(inode)) { +- ret = ext4_walk_page_buffers(handle, page_buffers(page), ++ ret = ext4_walk_page_buffers(handle, inode, page_buffers(page), + from, to, NULL, + do_journal_get_write_access); + } +@@ -682,7 +685,8 @@ int ext4_try_to_write_inline_data(struct + goto convert; + } + +- ret = ext4_journal_get_write_access(handle, iloc.bh); ++ ret = ext4_journal_get_write_access(handle, inode->i_sb, iloc.bh, ++ EXT4_JTR_NONE); + if (ret) + goto out; + +@@ -929,7 +933,8 @@ retry_journal: + if (ret < 0) + goto out_release_page; + } +- ret = ext4_journal_get_write_access(handle, iloc.bh); ++ ret = ext4_journal_get_write_access(handle, inode->i_sb, iloc.bh, ++ EXT4_JTR_NONE); + if (ret) + goto out_release_page; + +@@ -1034,7 +1039,8 @@ static int ext4_add_dirent_to_inline(han + return err; + + BUFFER_TRACE(iloc->bh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, iloc->bh); ++ err = ext4_journal_get_write_access(handle, dir->i_sb, iloc->bh, ++ EXT4_JTR_NONE); + if (err) + return err; + ext4_insert_dentry(dir, inode, de, inline_size, fname); +@@ -1229,7 +1235,8 @@ static int ext4_convert_inline_data_nolo + } + + lock_buffer(data_bh); +- error = ext4_journal_get_create_access(handle, data_bh); ++ error = ext4_journal_get_create_access(handle, inode->i_sb, data_bh, ++ EXT4_JTR_NONE); + if (error) { + unlock_buffer(data_bh); + error = -EIO; +@@ -1713,7 +1720,8 @@ int ext4_delete_inline_entry(handle_t *h + } + + BUFFER_TRACE(bh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, bh); ++ err = ext4_journal_get_write_access(handle, dir->i_sb, bh, ++ EXT4_JTR_NONE); + if (err) + goto out; + +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -139,7 +139,6 @@ static inline int ext4_begin_ordered_tru + 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); + static int ext4_meta_trans_blocks(struct inode *inode, int lblocks, + int pextents); + +@@ -869,7 +868,8 @@ struct buffer_head *ext4_getblk(handle_t + */ + lock_buffer(bh); + BUFFER_TRACE(bh, "call get_create_access"); +- err = ext4_journal_get_create_access(handle, bh); ++ err = ext4_journal_get_create_access(handle, inode->i_sb, bh, ++ EXT4_JTR_NONE); + if (unlikely(err)) { + unlock_buffer(bh); + goto errout; +@@ -954,12 +954,12 @@ out_brelse: + return err; + } + +-int ext4_walk_page_buffers(handle_t *handle, ++int ext4_walk_page_buffers(handle_t *handle, struct inode *inode, + struct buffer_head *head, + unsigned from, + unsigned to, + int *partial, +- int (*fn)(handle_t *handle, ++ int (*fn)(handle_t *handle, struct inode *inode, + struct buffer_head *bh)) + { + struct buffer_head *bh; +@@ -978,7 +978,7 @@ int ext4_walk_page_buffers(handle_t *han + *partial = 1; + continue; + } +- err = (*fn)(handle, bh); ++ err = (*fn)(handle, inode, bh); + if (!ret) + ret = err; + } +@@ -1009,7 +1009,7 @@ int ext4_walk_page_buffers(handle_t *han + * is elevated. We'll still have enough credits for the tiny quotafile + * write. + */ +-int do_journal_get_write_access(handle_t *handle, ++int do_journal_get_write_access(handle_t *handle, struct inode *inode, + struct buffer_head *bh) + { + int dirty = buffer_dirty(bh); +@@ -1028,7 +1028,8 @@ int do_journal_get_write_access(handle_t + if (dirty) + clear_buffer_dirty(bh); + BUFFER_TRACE(bh, "get write access"); +- ret = ext4_journal_get_write_access(handle, bh); ++ ret = ext4_journal_get_write_access(handle, inode->i_sb, bh, ++ EXT4_JTR_NONE); + if (!ret && dirty) + ret = ext4_handle_dirty_metadata(handle, NULL, bh); + return ret; +@@ -1208,8 +1209,8 @@ retry_journal: + ret = __block_write_begin(page, pos, len, ext4_get_block); + #endif + if (!ret && ext4_should_journal_data(inode)) { +- ret = ext4_walk_page_buffers(handle, page_buffers(page), +- from, to, NULL, ++ ret = ext4_walk_page_buffers(handle, inode, ++ page_buffers(page), from, to, NULL, + do_journal_get_write_access); + } + +@@ -1253,7 +1254,8 @@ retry_journal: + } + + /* For write_end() in data=journal mode */ +-static int write_end_fn(handle_t *handle, struct buffer_head *bh) ++static int write_end_fn(handle_t *handle, struct inode *inode, ++ struct buffer_head *bh) + { + int ret; + if (!buffer_mapped(bh) || buffer_freed(bh)) +@@ -1352,6 +1354,7 @@ errout: + * to call ext4_handle_dirty_metadata() instead. + */ + static void ext4_journalled_zero_new_buffers(handle_t *handle, ++ struct inode *inode, + struct page *page, + unsigned from, unsigned to) + { +@@ -1370,7 +1373,7 @@ static void ext4_journalled_zero_new_buf + size = min(to, block_end) - start; + + zero_user(page, start, size); +- write_end_fn(handle, bh); ++ write_end_fn(handle, inode, bh); + } + clear_buffer_new(bh); + } +@@ -1412,13 +1415,13 @@ static int ext4_journalled_write_end(str + copied = ret; + } else if (unlikely(copied < len) && !PageUptodate(page)) { + copied = 0; +- ext4_journalled_zero_new_buffers(handle, page, from, to); ++ ext4_journalled_zero_new_buffers(handle, inode, page, from, to); + } else { + if (unlikely(copied < len)) +- ext4_journalled_zero_new_buffers(handle, page, ++ ext4_journalled_zero_new_buffers(handle, inode, page, + from + copied, to); +- ret = ext4_walk_page_buffers(handle, page_buffers(page), from, +- from + copied, &partial, ++ ret = ext4_walk_page_buffers(handle, inode, page_buffers(page), ++ from, from + copied, &partial, + write_end_fn); + if (!partial) + SetPageUptodate(page); +@@ -1619,7 +1622,8 @@ static void ext4_print_free_blocks(struc + return; + } + +-static int ext4_bh_delay_or_unwritten(handle_t *handle, struct buffer_head *bh) ++static int ext4_bh_delay_or_unwritten(handle_t *handle, struct inode *inode, ++ struct buffer_head *bh) + { + return (buffer_delay(bh) || buffer_unwritten(bh)) && buffer_dirty(bh); + } +@@ -1851,13 +1855,15 @@ int ext4_da_get_block_prep(struct inode + return 0; + } + +-static int bget_one(handle_t *handle, struct buffer_head *bh) ++static int bget_one(handle_t *handle, struct inode *inode, ++ struct buffer_head *bh) + { + get_bh(bh); + return 0; + } + +-static int bput_one(handle_t *handle, struct buffer_head *bh) ++static int bput_one(handle_t *handle, struct inode *inode, ++ struct buffer_head *bh) + { + put_bh(bh); + return 0; +@@ -1888,7 +1894,7 @@ static int __ext4_journalled_writepage(s + BUG(); + goto out; + } +- ext4_walk_page_buffers(handle, page_bufs, 0, len, ++ ext4_walk_page_buffers(handle, inode, page_bufs, 0, len, + NULL, bget_one); + } + /* +@@ -1920,11 +1926,11 @@ static int __ext4_journalled_writepage(s + if (inline_data) { + ret = ext4_mark_inode_dirty(handle, inode); + } else { +- ret = ext4_walk_page_buffers(handle, page_bufs, 0, len, NULL, +- do_journal_get_write_access); ++ ret = ext4_walk_page_buffers(handle, inode, page_bufs, 0, len, ++ NULL, do_journal_get_write_access); + +- err = ext4_walk_page_buffers(handle, page_bufs, 0, len, NULL, +- write_end_fn); ++ err = ext4_walk_page_buffers(handle, inode, page_bufs, 0, len, ++ NULL, write_end_fn); + } + if (ret == 0) + ret = err; +@@ -1941,7 +1947,7 @@ out: + unlock_page(page); + out_no_pagelock: + if (!inline_data && page_bufs) +- ext4_walk_page_buffers(NULL, page_bufs, 0, len, ++ ext4_walk_page_buffers(NULL, inode, page_bufs, 0, len, + NULL, bput_one); + brelse(inode_bh); + return ret; +@@ -2031,7 +2037,7 @@ static int ext4_writepage(struct page *p + * for the extremely common case, this is an optimization that + * skips a useless round trip through ext4_bio_write_page(). + */ +- if (ext4_walk_page_buffers(NULL, page_bufs, 0, len, NULL, ++ if (ext4_walk_page_buffers(NULL, inode, page_bufs, 0, len, NULL, + ext4_bh_delay_or_unwritten)) { + redirty_page_for_writepage(wbc, page); + if ((current->flags & PF_MEMALLOC) || +@@ -3794,7 +3800,8 @@ static int __ext4_block_zero_page_range( + } + if (ext4_should_journal_data(inode)) { + BUFFER_TRACE(bh, "get write access"); +- err = ext4_journal_get_write_access(handle, bh); ++ err = ext4_journal_get_write_access(handle, inode->i_sb, bh, ++ EXT4_JTR_NONE); + if (err) + goto unlock; + } +@@ -5142,7 +5149,9 @@ static int ext4_do_update_inode(handle_t + ext4_clear_inode_state(inode, EXT4_STATE_NEW); + if (set_large_file) { + BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get write access"); +- err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh); ++ err = ext4_journal_get_write_access(handle, sb, ++ EXT4_SB(sb)->s_sbh, ++ EXT4_JTR_NONE); + if (err) + goto out_brelse; + lock_buffer(EXT4_SB(sb)->s_sbh); +@@ -5743,7 +5752,8 @@ ext4_reserve_inode_write(handle_t *handl + err = ext4_get_inode_loc(inode, iloc); + if (!err) { + BUFFER_TRACE(iloc->bh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, iloc->bh); ++ err = ext4_journal_get_write_access(handle, inode->i_sb, ++ iloc->bh, EXT4_JTR_NONE); + if (err) { + brelse(iloc->bh); + iloc->bh = NULL; +@@ -5866,7 +5876,8 @@ int ext4_expand_extra_isize(struct inode + ext4_write_lock_xattr(inode, &no_expand); + + BUFFER_TRACE(iloc->bh, "get_write_access"); +- error = ext4_journal_get_write_access(handle, iloc->bh); ++ error = ext4_journal_get_write_access(handle, inode->i_sb, iloc->bh, ++ EXT4_JTR_NONE); + if (error) { + brelse(iloc->bh); + goto out_unlock; +@@ -6037,7 +6048,8 @@ int ext4_change_inode_journal_flag(struc + return err; + } + +-static int ext4_bh_unmapped(handle_t *handle, struct buffer_head *bh) ++static int ext4_bh_unmapped(handle_t *handle, struct inode *inode, ++ struct buffer_head *bh) + { + return !buffer_mapped(bh); + } +@@ -6110,7 +6122,7 @@ vm_fault_t ext4_page_mkwrite(struct vm_f + * inode to the transaction's list to writeprotect pages on commit. + */ + if (page_has_buffers(page)) { +- if (!ext4_walk_page_buffers(NULL, page_buffers(page), ++ if (!ext4_walk_page_buffers(NULL, inode, page_buffers(page), + 0, len, NULL, + ext4_bh_unmapped)) { + /* Wait so that we don't change page under IO */ +@@ -6156,11 +6168,13 @@ retry_alloc: + err = __block_write_begin(page, 0, len, ext4_get_block); + if (!err) { + ret = VM_FAULT_SIGBUS; +- if (ext4_walk_page_buffers(handle, page_buffers(page), +- 0, len, NULL, do_journal_get_write_access)) ++ if (ext4_walk_page_buffers(handle, inode, ++ page_buffers(page), 0, len, NULL, ++ do_journal_get_write_access)) + goto out_error; +- if (ext4_walk_page_buffers(handle, page_buffers(page), +- 0, len, NULL, write_end_fn)) ++ if (ext4_walk_page_buffers(handle, inode, ++ page_buffers(page), 0, len, NULL, ++ write_end_fn)) + goto out_error; + if (ext4_jbd2_inode_add_write(handle, inode, + page_offset(page), len)) +--- a/fs/ext4/ioctl.c ++++ b/fs/ext4/ioctl.c +@@ -1154,7 +1154,9 @@ resizefs_out: + err = PTR_ERR(handle); + goto pwsalt_err_exit; + } +- err = ext4_journal_get_write_access(handle, sbi->s_sbh); ++ err = ext4_journal_get_write_access(handle, sb, ++ sbi->s_sbh, ++ EXT4_JTR_NONE); + if (err) + goto pwsalt_err_journal; + lock_buffer(sbi->s_sbh); +--- a/fs/ext4/mballoc.c ++++ b/fs/ext4/mballoc.c +@@ -3726,7 +3726,8 @@ ext4_mb_mark_diskspace_used(struct ext4_ + } + + BUFFER_TRACE(bitmap_bh, "getting write access"); +- err = ext4_journal_get_write_access(handle, bitmap_bh); ++ err = ext4_journal_get_write_access(handle, sb, bitmap_bh, ++ EXT4_JTR_NONE); + if (err) + goto out_err; + +@@ -3739,7 +3740,7 @@ ext4_mb_mark_diskspace_used(struct ext4_ + ext4_free_group_clusters(sb, gdp)); + + BUFFER_TRACE(gdp_bh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, gdp_bh); ++ err = ext4_journal_get_write_access(handle, sb, gdp_bh, EXT4_JTR_NONE); + if (err) + goto out_err; + +@@ -5916,7 +5917,8 @@ do_more: + } + + BUFFER_TRACE(bitmap_bh, "getting write access"); +- err = ext4_journal_get_write_access(handle, bitmap_bh); ++ err = ext4_journal_get_write_access(handle, sb, bitmap_bh, ++ EXT4_JTR_NONE); + if (err) + goto error_return; + +@@ -5926,7 +5928,7 @@ do_more: + * using it + */ + BUFFER_TRACE(gd_bh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, gd_bh); ++ err = ext4_journal_get_write_access(handle, sb, gd_bh, EXT4_JTR_NONE); + if (err) + goto error_return; + #ifdef AGGRESSIVE_CHECK +@@ -6107,7 +6109,8 @@ int ext4_group_add_blocks(handle_t *hand + } + + BUFFER_TRACE(bitmap_bh, "getting write access"); +- err = ext4_journal_get_write_access(handle, bitmap_bh); ++ err = ext4_journal_get_write_access(handle, sb, bitmap_bh, ++ EXT4_JTR_NONE); + if (err) + goto error_return; + +@@ -6117,7 +6120,7 @@ int ext4_group_add_blocks(handle_t *hand + * using it + */ + BUFFER_TRACE(gd_bh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, gd_bh); ++ err = ext4_journal_get_write_access(handle, sb, gd_bh, EXT4_JTR_NONE); + if (err) + goto error_return; + +--- a/fs/ext4/namei.c ++++ b/fs/ext4/namei.c +@@ -70,7 +70,8 @@ static struct buffer_head *ext4_append(h + inode->i_size += inode->i_sb->s_blocksize; + EXT4_I(inode)->i_disksize = inode->i_size; + BUFFER_TRACE(bh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, bh); ++ err = ext4_journal_get_write_access(handle, inode->i_sb, bh, ++ EXT4_JTR_NONE); + if (err) { + brelse(bh); + ext4_std_error(inode->i_sb, err); +@@ -1927,12 +1928,14 @@ static struct ext4_dir_entry_2 *do_split + } + + BUFFER_TRACE(*bh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, *bh); ++ err = ext4_journal_get_write_access(handle, dir->i_sb, *bh, ++ EXT4_JTR_NONE); + if (err) + goto journal_error; + + BUFFER_TRACE(frame->bh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, frame->bh); ++ err = ext4_journal_get_write_access(handle, dir->i_sb, frame->bh, ++ EXT4_JTR_NONE); + if (err) + goto journal_error; + +@@ -2109,7 +2112,8 @@ static int add_dirent_to_buf(handle_t *h + return err; + } + BUFFER_TRACE(bh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, bh); ++ err = ext4_journal_get_write_access(handle, dir->i_sb, bh, ++ EXT4_JTR_NONE); + if (err) { + ext4_std_error(dir->i_sb, err); + return err; +@@ -2167,7 +2171,8 @@ static int make_indexed_dir(handle_t *ha + blocksize = dir->i_sb->s_blocksize; + dxtrace(printk(KERN_DEBUG "Creating index: inode %lu\n", dir->i_ino)); + BUFFER_TRACE(bh, "get_write_access"); +- retval = ext4_journal_get_write_access(handle, bh); ++ retval = ext4_journal_get_write_access(handle, dir->i_sb, bh, ++ EXT4_JTR_NONE); + if (retval) { + ext4_std_error(dir->i_sb, retval); + brelse(bh); +@@ -2419,7 +2424,7 @@ again: + } + + BUFFER_TRACE(bh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, bh); ++ err = ext4_journal_get_write_access(handle, sb, bh, EXT4_JTR_NONE); + if (err) + goto journal_error; + +@@ -2476,7 +2481,8 @@ again: + node2->fake.rec_len = ext4_rec_len_to_disk(sb->s_blocksize, + sb->s_blocksize); + BUFFER_TRACE(frame->bh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, frame->bh); ++ err = ext4_journal_get_write_access(handle, sb, frame->bh, ++ EXT4_JTR_NONE); + if (err) + goto journal_error; + if (!add_level) { +@@ -2486,8 +2492,9 @@ again: + icount1, icount2)); + + BUFFER_TRACE(frame->bh, "get_write_access"); /* index root */ +- err = ext4_journal_get_write_access(handle, +- (frame - 1)->bh); ++ err = ext4_journal_get_write_access(handle, sb, ++ (frame - 1)->bh, ++ EXT4_JTR_NONE); + if (err) + goto journal_error; + +@@ -2636,7 +2643,8 @@ static int ext4_delete_entry(handle_t *h + csum_size = sizeof(struct ext4_dir_entry_tail); + + BUFFER_TRACE(bh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, bh); ++ err = ext4_journal_get_write_access(handle, dir->i_sb, bh, ++ EXT4_JTR_NONE); + if (unlikely(err)) + goto out; + +@@ -3088,7 +3096,8 @@ int ext4_orphan_add(handle_t *handle, st + S_ISLNK(inode->i_mode)) || inode->i_nlink == 0); + + BUFFER_TRACE(sbi->s_sbh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, sbi->s_sbh); ++ err = ext4_journal_get_write_access(handle, sb, sbi->s_sbh, ++ EXT4_JTR_NONE); + if (err) + goto out; + +@@ -3186,7 +3195,8 @@ int ext4_orphan_del(handle_t *handle, st + if (prev == &sbi->s_orphan) { + jbd_debug(4, "superblock will point to %u\n", ino_next); + BUFFER_TRACE(sbi->s_sbh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, sbi->s_sbh); ++ err = ext4_journal_get_write_access(handle, inode->i_sb, ++ sbi->s_sbh, EXT4_JTR_NONE); + if (err) { + mutex_unlock(&sbi->s_orphan_lock); + goto out_brelse; +@@ -3675,7 +3685,8 @@ static int ext4_rename_dir_prepare(handl + if (le32_to_cpu(ent->parent_de->inode) != ent->dir->i_ino) + return -EFSCORRUPTED; + BUFFER_TRACE(ent->dir_bh, "get_write_access"); +- return ext4_journal_get_write_access(handle, ent->dir_bh); ++ return ext4_journal_get_write_access(handle, ent->dir->i_sb, ++ ent->dir_bh, EXT4_JTR_NONE); + } + + static int ext4_rename_dir_finish(handle_t *handle, struct ext4_renament *ent, +@@ -3710,7 +3721,8 @@ static int ext4_setent(handle_t *handle, + int retval, retval2; + + BUFFER_TRACE(ent->bh, "get write access"); +- retval = ext4_journal_get_write_access(handle, ent->bh); ++ retval = ext4_journal_get_write_access(handle, ent->dir->i_sb, ent->bh, ++ EXT4_JTR_NONE); + if (retval) + return retval; + ent->de->inode = cpu_to_le32(ino); +--- a/fs/ext4/resize.c ++++ b/fs/ext4/resize.c +@@ -409,7 +409,8 @@ static struct buffer_head *bclean(handle + if (unlikely(!bh)) + return ERR_PTR(-ENOMEM); + BUFFER_TRACE(bh, "get_write_access"); +- if ((err = ext4_journal_get_write_access(handle, bh))) { ++ err = ext4_journal_get_write_access(handle, sb, bh, EXT4_JTR_NONE); ++ if (err) { + brelse(bh); + bh = ERR_PTR(err); + } else { +@@ -474,7 +475,8 @@ static int set_flexbg_block_bitmap(struc + return -ENOMEM; + + BUFFER_TRACE(bh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, bh); ++ err = ext4_journal_get_write_access(handle, sb, bh, ++ EXT4_JTR_NONE); + if (err) { + brelse(bh); + return err; +@@ -569,7 +571,8 @@ static int setup_new_flex_group_blocks(s + } + + BUFFER_TRACE(gdb, "get_write_access"); +- err = ext4_journal_get_write_access(handle, gdb); ++ err = ext4_journal_get_write_access(handle, sb, gdb, ++ EXT4_JTR_NONE); + if (err) { + brelse(gdb); + goto out; +@@ -837,17 +840,18 @@ static int add_new_gdb(handle_t *handle, + } + + BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh); ++ err = ext4_journal_get_write_access(handle, sb, EXT4_SB(sb)->s_sbh, ++ EXT4_JTR_NONE); + if (unlikely(err)) + goto errout; + + BUFFER_TRACE(gdb_bh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, gdb_bh); ++ err = ext4_journal_get_write_access(handle, sb, gdb_bh, EXT4_JTR_NONE); + if (unlikely(err)) + goto errout; + + BUFFER_TRACE(dind, "get_write_access"); +- err = ext4_journal_get_write_access(handle, dind); ++ err = ext4_journal_get_write_access(handle, sb, dind, EXT4_JTR_NONE); + if (unlikely(err)) { + ext4_std_error(sb, err); + goto errout; +@@ -956,7 +960,7 @@ static int add_new_gdb_meta_bg(struct su + n_group_desc[gdb_num] = gdb_bh; + + BUFFER_TRACE(gdb_bh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, gdb_bh); ++ err = ext4_journal_get_write_access(handle, sb, gdb_bh, EXT4_JTR_NONE); + if (err) { + kvfree(n_group_desc); + brelse(gdb_bh); +@@ -1042,7 +1046,8 @@ static int reserve_backup_gdb(handle_t * + + for (i = 0; i < reserved_gdb; i++) { + BUFFER_TRACE(primary[i], "get_write_access"); +- if ((err = ext4_journal_get_write_access(handle, primary[i]))) ++ if ((err = ext4_journal_get_write_access(handle, sb, primary[i], ++ EXT4_JTR_NONE))) + goto exit_bh; + } + +@@ -1149,10 +1154,9 @@ static void update_backups(struct super_ + backup_block, backup_block - + ext4_group_first_block_no(sb, group)); + BUFFER_TRACE(bh, "get_write_access"); +- if ((err = ext4_journal_get_write_access(handle, bh))) { +- brelse(bh); ++ if ((err = ext4_journal_get_write_access(handle, sb, bh, ++ EXT4_JTR_NONE))) + break; +- } + lock_buffer(bh); + memcpy(bh->b_data, data, size); + if (rest) +@@ -1232,7 +1236,8 @@ static int ext4_add_new_descs(handle_t * + gdb_bh = sbi_array_rcu_deref(sbi, s_group_desc, + gdb_num); + BUFFER_TRACE(gdb_bh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, gdb_bh); ++ err = ext4_journal_get_write_access(handle, sb, gdb_bh, ++ EXT4_JTR_NONE); + + if (!err && reserved_gdb && ext4_bg_num_gdb(sb, group)) + err = reserve_backup_gdb(handle, resize_inode, group); +@@ -1509,7 +1514,8 @@ static int ext4_flex_group_add(struct su + } + + BUFFER_TRACE(sbi->s_sbh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, sbi->s_sbh); ++ err = ext4_journal_get_write_access(handle, sb, sbi->s_sbh, ++ EXT4_JTR_NONE); + if (err) + goto exit_journal; + +@@ -1722,7 +1728,8 @@ static int ext4_group_extend_no_check(st + } + + BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh); ++ err = ext4_journal_get_write_access(handle, sb, EXT4_SB(sb)->s_sbh, ++ EXT4_JTR_NONE); + if (err) { + ext4_warning(sb, "error %d on journal write access", err); + goto errout; +@@ -1884,7 +1891,8 @@ static int ext4_convert_meta_bg(struct s + return PTR_ERR(handle); + + BUFFER_TRACE(sbi->s_sbh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, sbi->s_sbh); ++ err = ext4_journal_get_write_access(handle, sb, sbi->s_sbh, ++ EXT4_JTR_NONE); + if (err) + goto errout; + +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -4014,6 +4014,20 @@ static const char *ext4_quota_mode(struc + #endif + } + ++static void __always_unused ext4_setup_csum_trigger(struct super_block *sb, ++ enum ext4_journal_trigger_type type, ++ void (*trigger)( ++ struct jbd2_buffer_trigger_type *type, ++ struct buffer_head *bh, ++ void *mapped_data, ++ size_t size)) ++{ ++ struct ext4_sb_info *sbi = EXT4_SB(sb); ++ ++ sbi->s_journal_triggers[type].sb = sb; ++ sbi->s_journal_triggers[type].tr_triggers.t_frozen = trigger; ++} ++ + static int ext4_fill_super(struct super_block *sb, void *data, int silent) + { + struct dax_device *dax_dev = fs_dax_get_by_bdev(sb->s_bdev); +@@ -6617,7 +6631,7 @@ static ssize_t ext4_quota_write(struct s + if (!bh) + goto out; + BUFFER_TRACE(bh, "get write access"); +- err = ext4_journal_get_write_access(handle, bh); ++ err = ext4_journal_get_write_access(handle, sb, bh, EXT4_JTR_NONE); + if (err) { + brelse(bh); + return err; +--- a/fs/ext4/xattr.c ++++ b/fs/ext4/xattr.c +@@ -791,7 +791,8 @@ static void ext4_xattr_update_super_bloc + return; + + BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get_write_access"); +- if (ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh) == 0) { ++ if (ext4_journal_get_write_access(handle, sb, EXT4_SB(sb)->s_sbh, ++ EXT4_JTR_NONE) == 0) { + lock_buffer(EXT4_SB(sb)->s_sbh); + ext4_set_feature_xattr(sb); + ext4_superblock_csum_set(sb); +@@ -1169,7 +1170,8 @@ ext4_xattr_inode_dec_ref_all(handle_t *h + continue; + } + if (err > 0) { +- err = ext4_journal_get_write_access(handle, bh); ++ err = ext4_journal_get_write_access(handle, ++ parent->i_sb, bh, EXT4_JTR_NONE); + if (err) { + ext4_warning_inode(ea_inode, + "Re-get write access err=%d", +@@ -1230,7 +1232,8 @@ ext4_xattr_release_block(handle_t *handl + int error = 0; + + BUFFER_TRACE(bh, "get_write_access"); +- error = ext4_journal_get_write_access(handle, bh); ++ error = ext4_journal_get_write_access(handle, inode->i_sb, bh, ++ EXT4_JTR_NONE); + if (error) + goto out; + +@@ -1371,7 +1374,8 @@ retry: + "ext4_getblk() return bh = NULL"); + return -EFSCORRUPTED; + } +- ret = ext4_journal_get_write_access(handle, bh); ++ ret = ext4_journal_get_write_access(handle, ea_inode->i_sb, bh, ++ EXT4_JTR_NONE); + if (ret) + goto out; + +@@ -1855,7 +1859,8 @@ ext4_xattr_block_set(handle_t *handle, s + + if (s->base) { + BUFFER_TRACE(bs->bh, "get_write_access"); +- error = ext4_journal_get_write_access(handle, bs->bh); ++ error = ext4_journal_get_write_access(handle, sb, bs->bh, ++ EXT4_JTR_NONE); + if (error) + goto cleanup; + lock_buffer(bs->bh); +@@ -1987,8 +1992,9 @@ inserted: + if (error) + goto cleanup; + BUFFER_TRACE(new_bh, "get_write_access"); +- error = ext4_journal_get_write_access(handle, +- new_bh); ++ error = ext4_journal_get_write_access( ++ handle, sb, new_bh, ++ EXT4_JTR_NONE); + if (error) + goto cleanup_dquot; + lock_buffer(new_bh); +@@ -2092,7 +2098,8 @@ getblk_failed: + } + + lock_buffer(new_bh); +- error = ext4_journal_get_create_access(handle, new_bh); ++ error = ext4_journal_get_create_access(handle, sb, ++ new_bh, EXT4_JTR_NONE); + if (error) { + unlock_buffer(new_bh); + error = -EIO; +@@ -2848,7 +2855,8 @@ int ext4_xattr_delete_inode(handle_t *ha + goto cleanup; + } + +- error = ext4_journal_get_write_access(handle, iloc.bh); ++ error = ext4_journal_get_write_access(handle, inode->i_sb, ++ iloc.bh, EXT4_JTR_NONE); + if (error) { + EXT4_ERROR_INODE(inode, "write access (error %d)", + error); +--- a/fs/jbd2/transaction.c ++++ b/fs/jbd2/transaction.c +@@ -1404,7 +1404,7 @@ void jbd2_journal_set_triggers(struct bu + { + struct journal_head *jh = jbd2_journal_grab_journal_head(bh); + +- if (WARN_ON(!jh)) ++ if (WARN_ON_ONCE(!jh)) + return; + jh->b_triggers = type; + jbd2_journal_put_journal_head(jh); diff --git a/patches.suse/ext4-check-for-inconsistent-extents-between-index-an.patch b/patches.suse/ext4-check-for-inconsistent-extents-between-index-an.patch new file mode 100644 index 0000000..a6a7b33 --- /dev/null +++ b/patches.suse/ext4-check-for-inconsistent-extents-between-index-an.patch @@ -0,0 +1,205 @@ +From e75c1ad6cab914dbd436f577b2cfc9bdfcb24304 Mon Sep 17 00:00:00 2001 +From: Zhang Yi +Date: Wed, 8 Sep 2021 20:08:49 +0800 +Subject: [PATCH] ext4: check for inconsistent extents between index and leaf + block +Git-commit: 9c6e071913792d80894cd0be98cc3c4b770e26d3 +Patch-mainline: v5.16-rc1 +References: bsc#1194163 + +Now that we can check out overlapping extents in leaf block and +out-of-order index extents in index block. But the .ee_block in the +first extent of one leaf block should equal to the .ei_block in it's +parent index extent entry. This patch add a check to verify such +inconsistent between the index and leaf block. + +Signed-off-by: Zhang Yi +Link: https://lore.kernel.org/r/20210908120850.4012324-3-yi.zhang@huawei.com +Signed-off-by: Theodore Ts'o +Acked-by: David Disseldorp + +--- + fs/ext4/extents.c | 59 +++++++++++++++++++++++++++++------------------ + 1 file changed, 36 insertions(+), 23 deletions(-) + +diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c +index ebe2764584b1..e6224bb96756 100644 +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -367,7 +367,8 @@ static int ext4_valid_extent_idx(struct inode *inode, + + static int ext4_valid_extent_entries(struct inode *inode, + struct ext4_extent_header *eh, +- ext4_fsblk_t *pblk, int depth) ++ ext4_lblk_t lblk, ext4_fsblk_t *pblk, ++ int depth) + { + unsigned short entries; + ext4_lblk_t lblock = 0; +@@ -381,6 +382,14 @@ static int ext4_valid_extent_entries(struct inode *inode, + if (depth == 0) { + /* leaf entries */ + struct ext4_extent *ext = EXT_FIRST_EXTENT(eh); ++ ++ /* ++ * The logical block in the first entry should equal to ++ * the number in the index block. ++ */ ++ if (depth != ext_depth(inode) && ++ lblk != le32_to_cpu(ext->ee_block)) ++ return 0; + while (entries) { + if (!ext4_valid_extent(inode, ext)) + return 0; +@@ -397,6 +406,14 @@ static int ext4_valid_extent_entries(struct inode *inode, + } + } else { + struct ext4_extent_idx *ext_idx = EXT_FIRST_INDEX(eh); ++ ++ /* ++ * The logical block in the first entry should equal to ++ * the number in the parent index block. ++ */ ++ if (depth != ext_depth(inode) && ++ lblk != le32_to_cpu(ext_idx->ei_block)) ++ return 0; + while (entries) { + if (!ext4_valid_extent_idx(inode, ext_idx)) + return 0; +@@ -417,7 +434,7 @@ static int ext4_valid_extent_entries(struct inode *inode, + + static int __ext4_ext_check(const char *function, unsigned int line, + struct inode *inode, struct ext4_extent_header *eh, +- int depth, ext4_fsblk_t pblk) ++ int depth, ext4_fsblk_t pblk, ext4_lblk_t lblk) + { + const char *error_msg; + int max = 0, err = -EFSCORRUPTED; +@@ -443,7 +460,7 @@ static int __ext4_ext_check(const char *function, unsigned int line, + error_msg = "invalid eh_entries"; + goto corrupted; + } +- if (!ext4_valid_extent_entries(inode, eh, &pblk, depth)) { ++ if (!ext4_valid_extent_entries(inode, eh, lblk, &pblk, depth)) { + error_msg = "invalid extent entries"; + goto corrupted; + } +@@ -473,7 +490,7 @@ static int __ext4_ext_check(const char *function, unsigned int line, + } + + #define ext4_ext_check(inode, eh, depth, pblk) \ +- __ext4_ext_check(__func__, __LINE__, (inode), (eh), (depth), (pblk)) ++ __ext4_ext_check(__func__, __LINE__, (inode), (eh), (depth), (pblk), 0) + + int ext4_ext_check_inode(struct inode *inode) + { +@@ -506,16 +523,18 @@ static void ext4_cache_extents(struct inode *inode, + + static struct buffer_head * + __read_extent_tree_block(const char *function, unsigned int line, +- struct inode *inode, ext4_fsblk_t pblk, int depth, +- int flags) ++ struct inode *inode, struct ext4_extent_idx *idx, ++ int depth, int flags) + { + struct buffer_head *bh; + int err; + gfp_t gfp_flags = __GFP_MOVABLE | GFP_NOFS; ++ ext4_fsblk_t pblk; + + if (flags & EXT4_EX_NOFAIL) + gfp_flags |= __GFP_NOFAIL; + ++ pblk = ext4_idx_pblock(idx); + bh = sb_getblk_gfp(inode->i_sb, pblk, gfp_flags); + if (unlikely(!bh)) + return ERR_PTR(-ENOMEM); +@@ -528,8 +547,8 @@ __read_extent_tree_block(const char *function, unsigned int line, + } + if (buffer_verified(bh) && !(flags & EXT4_EX_FORCE_CACHE)) + return bh; +- err = __ext4_ext_check(function, line, inode, +- ext_block_hdr(bh), depth, pblk); ++ err = __ext4_ext_check(function, line, inode, ext_block_hdr(bh), ++ depth, pblk, le32_to_cpu(idx->ei_block)); + if (err) + goto errout; + set_buffer_verified(bh); +@@ -547,8 +566,8 @@ __read_extent_tree_block(const char *function, unsigned int line, + + } + +-#define read_extent_tree_block(inode, pblk, depth, flags) \ +- __read_extent_tree_block(__func__, __LINE__, (inode), (pblk), \ ++#define read_extent_tree_block(inode, idx, depth, flags) \ ++ __read_extent_tree_block(__func__, __LINE__, (inode), (idx), \ + (depth), (flags)) + + /* +@@ -598,8 +617,7 @@ int ext4_ext_precache(struct inode *inode) + i--; + continue; + } +- bh = read_extent_tree_block(inode, +- ext4_idx_pblock(path[i].p_idx++), ++ bh = read_extent_tree_block(inode, path[i].p_idx++, + depth - i - 1, + EXT4_EX_FORCE_CACHE); + if (IS_ERR(bh)) { +@@ -904,8 +922,7 @@ ext4_find_extent(struct inode *inode, ext4_lblk_t block, + path[ppos].p_depth = i; + path[ppos].p_ext = NULL; + +- bh = read_extent_tree_block(inode, path[ppos].p_block, --i, +- flags); ++ bh = read_extent_tree_block(inode, path[ppos].p_idx, --i, flags); + if (IS_ERR(bh)) { + ret = PTR_ERR(bh); + goto err; +@@ -1514,7 +1531,6 @@ static int ext4_ext_search_right(struct inode *inode, + struct ext4_extent_header *eh; + struct ext4_extent_idx *ix; + struct ext4_extent *ex; +- ext4_fsblk_t block; + int depth; /* Note, NOT eh_depth; depth from top of tree */ + int ee_len; + +@@ -1581,20 +1597,17 @@ static int ext4_ext_search_right(struct inode *inode, + * follow it and find the closest allocated + * block to the right */ + ix++; +- block = ext4_idx_pblock(ix); + while (++depth < path->p_depth) { + /* subtract from p_depth to get proper eh_depth */ +- bh = read_extent_tree_block(inode, block, +- path->p_depth - depth, 0); ++ bh = read_extent_tree_block(inode, ix, path->p_depth - depth, 0); + if (IS_ERR(bh)) + return PTR_ERR(bh); + eh = ext_block_hdr(bh); + ix = EXT_FIRST_INDEX(eh); +- block = ext4_idx_pblock(ix); + put_bh(bh); + } + +- bh = read_extent_tree_block(inode, block, path->p_depth - depth, 0); ++ bh = read_extent_tree_block(inode, ix, path->p_depth - depth, 0); + if (IS_ERR(bh)) + return PTR_ERR(bh); + eh = ext_block_hdr(bh); +@@ -2973,9 +2986,9 @@ int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, + ext_debug(inode, "move to level %d (block %llu)\n", + i + 1, ext4_idx_pblock(path[i].p_idx)); + memset(path + i + 1, 0, sizeof(*path)); +- bh = read_extent_tree_block(inode, +- ext4_idx_pblock(path[i].p_idx), depth - i - 1, +- EXT4_EX_NOCACHE); ++ bh = read_extent_tree_block(inode, path[i].p_idx, ++ depth - i - 1, ++ EXT4_EX_NOCACHE); + if (IS_ERR(bh)) { + /* should we reset i_size? */ + err = PTR_ERR(bh); +-- +2.34.1 + diff --git a/patches.suse/ext4-check-for-out-of-order-index-extents-in-ext4_va.patch b/patches.suse/ext4-check-for-out-of-order-index-extents-in-ext4_va.patch new file mode 100644 index 0000000..ce3797a --- /dev/null +++ b/patches.suse/ext4-check-for-out-of-order-index-extents-in-ext4_va.patch @@ -0,0 +1,84 @@ +From d3b73ee452bb8d8ad7c96416e08c7ec712220e30 Mon Sep 17 00:00:00 2001 +From: Zhang Yi +Date: Wed, 8 Sep 2021 20:08:48 +0800 +Subject: [PATCH] ext4: check for out-of-order index extents in + ext4_valid_extent_entries() +Git-commit: 8dd27fecede55e8a4e67eef2878040ecad0f0d33 +Patch-mainline: v5.16-rc1 +References: bsc#1194163 + +After commit 5946d089379a ("ext4: check for overlapping extents in +ext4_valid_extent_entries()"), we can check out the overlapping extent +entry in leaf extent blocks. But the out-of-order extent entry in index +extent blocks could also trigger bad things if the filesystem is +inconsistent. So this patch add a check to figure out the out-of-order +index extents and return error. + +Signed-off-by: Zhang Yi +Reviewed-by: Theodore Ts'o +Link: https://lore.kernel.org/r/20210908120850.4012324-2-yi.zhang@huawei.com +Signed-off-by: Theodore Ts'o +Acked-by: David Disseldorp + +--- + fs/ext4/extents.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c +index 3b27eeaa9c1a..ebe2764584b1 100644 +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -370,6 +370,9 @@ static int ext4_valid_extent_entries(struct inode *inode, + ext4_fsblk_t *pblk, int depth) + { + unsigned short entries; ++ ext4_lblk_t lblock = 0; ++ ext4_lblk_t prev = 0; ++ + if (eh->eh_entries == 0) + return 1; + +@@ -378,31 +381,35 @@ static int ext4_valid_extent_entries(struct inode *inode, + if (depth == 0) { + /* leaf entries */ + struct ext4_extent *ext = EXT_FIRST_EXTENT(eh); +- ext4_lblk_t lblock = 0; +- ext4_lblk_t prev = 0; +- int len = 0; + while (entries) { + if (!ext4_valid_extent(inode, ext)) + return 0; + + /* Check for overlapping extents */ + lblock = le32_to_cpu(ext->ee_block); +- len = ext4_ext_get_actual_len(ext); + if ((lblock <= prev) && prev) { + *pblk = ext4_ext_pblock(ext); + return 0; + } ++ prev = lblock + ext4_ext_get_actual_len(ext) - 1; + ext++; + entries--; +- prev = lblock + len - 1; + } + } else { + struct ext4_extent_idx *ext_idx = EXT_FIRST_INDEX(eh); + while (entries) { + if (!ext4_valid_extent_idx(inode, ext_idx)) + return 0; ++ ++ /* Check for overlapping index extents */ ++ lblock = le32_to_cpu(ext_idx->ei_block); ++ if ((lblock <= prev) && prev) { ++ *pblk = ext4_idx_pblock(ext_idx); ++ return 0; ++ } + ext_idx++; + entries--; ++ prev = lblock; + } + } + return 1; +-- +2.34.1 + diff --git a/patches.suse/ext4-correct-the-error-path-of-ext4_write_inline_dat.patch b/patches.suse/ext4-correct-the-error-path-of-ext4_write_inline_dat.patch index 0a2de36..dfb3a95 100644 --- a/patches.suse/ext4-correct-the-error-path-of-ext4_write_inline_dat.patch +++ b/patches.suse/ext4-correct-the-error-path-of-ext4_write_inline_dat.patch @@ -27,15 +27,13 @@ Signed-off-by: Sasha Levin Acked-by: Takashi Iwai --- - fs/ext4/inline.c | 15 +++++---------- - fs/ext4/inode.c | 7 +++++-- + fs/ext4/inline.c | 15 +++++---------- + fs/ext4/inode.c | 7 +++++-- 2 files changed, 10 insertions(+), 12 deletions(-) -diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c -index 24e994e75f5c..8049448476a6 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c -@@ -733,18 +733,13 @@ int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len, +@@ -737,18 +737,13 @@ int ext4_write_inline_data_end(struct in void *kaddr; struct ext4_iloc iloc; @@ -57,7 +55,7 @@ index 24e994e75f5c..8049448476a6 100644 } ext4_write_lock_xattr(inode, &no_expand); -@@ -757,7 +752,7 @@ int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len, +@@ -761,7 +756,7 @@ int ext4_write_inline_data_end(struct in (void) ext4_find_inline_data_nolock(inode); kaddr = kmap_atomic(page); @@ -66,7 +64,7 @@ index 24e994e75f5c..8049448476a6 100644 kunmap_atomic(kaddr); SetPageUptodate(page); /* clear page dirty so that writepages wouldn't work for us. */ -@@ -766,7 +761,7 @@ int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len, +@@ -770,7 +765,7 @@ int ext4_write_inline_data_end(struct in ext4_write_unlock_xattr(inode, &no_expand); brelse(iloc.bh); mark_inode_dirty(inode); @@ -75,11 +73,9 @@ index 24e994e75f5c..8049448476a6 100644 return copied; } -diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c -index a47ff8ce289b..fc6ea56de77c 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c -@@ -1295,6 +1295,7 @@ static int ext4_write_end(struct file *file, +@@ -1297,6 +1297,7 @@ static int ext4_write_end(struct file *f goto errout; } copied = ret; @@ -87,7 +83,7 @@ index a47ff8ce289b..fc6ea56de77c 100644 } else copied = block_write_end(file, mapping, pos, len, copied, page, fsdata); -@@ -1321,13 +1322,14 @@ static int ext4_write_end(struct file *file, +@@ -1323,13 +1324,14 @@ static int ext4_write_end(struct file *f if (i_size_changed || inline_data) ret = ext4_mark_inode_dirty(handle, inode); @@ -103,15 +99,15 @@ index a47ff8ce289b..fc6ea56de77c 100644 ret2 = ext4_journal_stop(handle); if (!ret) ret = ret2; -@@ -1410,6 +1412,7 @@ static int ext4_journalled_write_end(struct file *file, +@@ -1413,6 +1415,7 @@ static int ext4_journalled_write_end(str goto errout; } copied = ret; + ret = 0; } else if (unlikely(copied < len) && !PageUptodate(page)) { copied = 0; - ext4_journalled_zero_new_buffers(handle, page, from, to); -@@ -1439,6 +1442,7 @@ static int ext4_journalled_write_end(struct file *file, + ext4_journalled_zero_new_buffers(handle, inode, page, from, to); +@@ -1442,6 +1445,7 @@ static int ext4_journalled_write_end(str ret = ret2; } @@ -119,7 +115,7 @@ index a47ff8ce289b..fc6ea56de77c 100644 if (pos + len > inode->i_size && !verity && ext4_can_truncate(inode)) /* if we have allocated more blocks and copied * less. We will have blocks allocated outside -@@ -1446,7 +1450,6 @@ static int ext4_journalled_write_end(struct file *file, +@@ -1449,7 +1453,6 @@ static int ext4_journalled_write_end(str */ ext4_orphan_add(handle, inode); @@ -127,6 +123,3 @@ index a47ff8ce289b..fc6ea56de77c 100644 ret2 = ext4_journal_stop(handle); if (!ret) ret = ret2; --- -2.26.2 - diff --git a/patches.suse/ext4-prevent-partial-update-of-the-extent-blocks.patch b/patches.suse/ext4-prevent-partial-update-of-the-extent-blocks.patch new file mode 100644 index 0000000..0c804a3 --- /dev/null +++ b/patches.suse/ext4-prevent-partial-update-of-the-extent-blocks.patch @@ -0,0 +1,75 @@ +From 822c45ea990953e3bd6a2581a54163b53986586e Mon Sep 17 00:00:00 2001 +From: Zhang Yi +Date: Wed, 8 Sep 2021 20:08:50 +0800 +Subject: [PATCH] ext4: prevent partial update of the extent blocks +Git-commit: 0f2f87d51aebcf71a709b52f661d681594c7dffa +Patch-mainline: v5.16-rc1 +References: bsc#1194163 + +In the most error path of current extents updating operations are not +roll back partial updates properly when some bad things happens(.e.g in +ext4_ext_insert_extent()). So we may get an inconsistent extents tree +if journal has been aborted due to IO error, which may probability lead +to BUGON later when we accessing these extent entries in errors=continue +mode. This patch drop extent buffer's verify flag before updatng the +contents in ext4_ext_get_access(), and reset it after updating in +__ext4_ext_dirty(). After this patch we could force to check the extent +buffer if extents tree updating was break off, make sure the extents are +consistent. + +Signed-off-by: Zhang Yi +Reviewed-by: Theodore Ts'o +Link: https://lore.kernel.org/r/20210908120850.4012324-4-yi.zhang@huawei.com +Signed-off-by: Theodore Ts'o +Acked-by: David Disseldorp + +--- + fs/ext4/extents.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c +index 1eb870fd5023..3b27eeaa9c1a 100644 +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -136,15 +136,25 @@ int ext4_datasem_ensure_credits(handle_t *handle, struct inode *inode, + static int ext4_ext_get_access(handle_t *handle, struct inode *inode, + struct ext4_ext_path *path) + { ++ int err = 0; ++ + if (path->p_bh) { + /* path points to block */ + BUFFER_TRACE(path->p_bh, "get_write_access"); +- return ext4_journal_get_write_access(handle, inode->i_sb, +- path->p_bh, EXT4_JTR_NONE); ++ err = ext4_journal_get_write_access(handle, inode->i_sb, ++ path->p_bh, EXT4_JTR_NONE); ++ /* ++ * The extent buffer's verified bit will be set again in ++ * __ext4_ext_dirty(). We could leave an inconsistent ++ * buffer if the extents updating procudure break off du ++ * to some error happens, force to check it again. ++ */ ++ if (!err) ++ clear_buffer_verified(path->p_bh); + } + /* path points to leaf/index in inode body */ + /* we use in-core data, no need to protect them */ +- return 0; ++ return err; + } + + /* +@@ -165,6 +175,9 @@ static int __ext4_ext_dirty(const char *where, unsigned int line, + /* path points to block */ + err = __ext4_handle_dirty_metadata(where, line, handle, + inode, path->p_bh); ++ /* Extents updating done, re-set verified flag */ ++ if (!err) ++ set_buffer_verified(path->p_bh); + } else { + /* path points to leaf/index in inode body */ + err = ext4_mark_inode_dirty(handle, inode); +-- +2.34.1 + diff --git a/patches.suse/powerpc-fadump-Fix-inaccurate-CPU-state-info-in-vmco.patch b/patches.suse/powerpc-fadump-Fix-inaccurate-CPU-state-info-in-vmco.patch new file mode 100644 index 0000000..3cb65be --- /dev/null +++ b/patches.suse/powerpc-fadump-Fix-inaccurate-CPU-state-info-in-vmco.patch @@ -0,0 +1,134 @@ +From 06e629c25daa519be620a8c17359ae8fc7a2e903 Mon Sep 17 00:00:00 2001 +From: Hari Bathini +Date: Tue, 7 Dec 2021 16:07:19 +0530 +Subject: [PATCH] powerpc/fadump: Fix inaccurate CPU state info in vmcore + generated with panic + +References: bsc#1193901 ltc#194976 +Patch-mainline: queued +Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git +Git-commit: 06e629c25daa519be620a8c17359ae8fc7a2e903 + +In panic path, fadump is triggered via a panic notifier function. +Before calling panic notifier functions, smp_send_stop() gets called, +which stops all CPUs except the panic'ing CPU. Commit 8389b37dffdc +("powerpc: stop_this_cpu: remove the cpu from the online map.") and +again commit bab26238bbd4 ("powerpc: Offline CPU in stop_this_cpu()") +started marking CPUs as offline while stopping them. So, if a kernel +has either of the above commits, vmcore captured with fadump via panic +path would not process register data for all CPUs except the panic'ing +CPU. Sample output of crash-utility with such vmcore: + + # crash vmlinux vmcore + ... + KERNEL: vmlinux + DUMPFILE: vmcore [PARTIAL DUMP] + CPUS: 1 + DATE: Wed Nov 10 09:56:34 EST 2021 + UPTIME: 00:00:42 + LOAD AVERAGE: 2.27, 0.69, 0.24 + TASKS: 183 + NODENAME: XXXXXXXXX + RELEASE: 5.15.0+ + VERSION: #974 SMP Wed Nov 10 04:18:19 CST 2021 + MACHINE: ppc64le (2500 Mhz) + MEMORY: 8 GB + PANIC: "Kernel panic - not syncing: sysrq triggered crash" + PID: 3394 + COMMAND: "bash" + TASK: c0000000150a5f80 [THREAD_INFO: c0000000150a5f80] + CPU: 1 + STATE: TASK_RUNNING (PANIC) + + crash> p -x __cpu_online_mask + __cpu_online_mask = $1 = { + bits = {0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} + } + crash> + crash> + crash> p -x __cpu_active_mask + __cpu_active_mask = $2 = { + bits = {0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} + } + crash> + +While this has been the case since fadump was introduced, the issue +was not identified for two probable reasons: + + - In general, the bulk of the vmcores analyzed were from crash + due to exception. + + - The above did change since commit 8341f2f222d7 ("sysrq: Use + panic() to force a crash") started using panic() instead of + deferencing NULL pointer to force a kernel crash. But then + commit de6e5d38417e ("powerpc: smp_send_stop do not offline + stopped CPUs") stopped marking CPUs as offline till kernel + commit bab26238bbd4 ("powerpc: Offline CPU in stop_this_cpu()") + reverted that change. + +To ensure post processing register data of all other CPUs happens +as intended, let panic() function take the crash friendly path (read +crash_smp_send_stop()) with the help of crash_kexec_post_notifiers +option. Also, as register data for all CPUs is captured by f/w, skip +IPI callbacks here for fadump, to avoid any complications in finding +the right backtraces. + +Signed-off-by: Hari Bathini +Signed-off-by: Michael Ellerman +Link: https://lore.kernel.org/r/20211207103719.91117-2-hbathini@linux.ibm.com +Acked-by: Michal Suchanek +--- + arch/powerpc/kernel/fadump.c | 8 ++++++++ + arch/powerpc/kernel/smp.c | 10 ++++++++++ + 2 files changed, 18 insertions(+) + +diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c +index b7ceb041743c..60f5fc14aa23 100644 +--- a/arch/powerpc/kernel/fadump.c ++++ b/arch/powerpc/kernel/fadump.c +@@ -1641,6 +1641,14 @@ int __init setup_fadump(void) + else if (fw_dump.reserve_dump_area_size) + fw_dump.ops->fadump_init_mem_struct(&fw_dump); + ++ /* ++ * In case of panic, fadump is triggered via ppc_panic_event() ++ * panic notifier. Setting crash_kexec_post_notifiers to 'true' ++ * lets panic() function take crash friendly path before panic ++ * notifiers are invoked. ++ */ ++ crash_kexec_post_notifiers = true; ++ + return 1; + } + subsys_initcall(setup_fadump); +diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c +index 7201fdcf02f1..c338f9d8ab37 100644 +--- a/arch/powerpc/kernel/smp.c ++++ b/arch/powerpc/kernel/smp.c +@@ -61,6 +61,7 @@ + #include + #include + #include ++#include + + #ifdef DEBUG + #include +@@ -638,6 +639,15 @@ void crash_smp_send_stop(void) + { + static bool stopped = false; + ++ /* ++ * In case of fadump, register data for all CPUs is captured by f/w ++ * on ibm,os-term rtas call. Skip IPI callbacks to other CPUs before ++ * this rtas call to avoid tricky post processing of those CPUs' ++ * backtraces. ++ */ ++ if (should_fadump_crash()) ++ return; ++ + if (stopped) + return; + +-- +2.31.1 + diff --git a/patches.suse/powerpc-handle-kdump-appropriately-with-crash_kexec_.patch b/patches.suse/powerpc-handle-kdump-appropriately-with-crash_kexec_.patch new file mode 100644 index 0000000..9de2ef9 --- /dev/null +++ b/patches.suse/powerpc-handle-kdump-appropriately-with-crash_kexec_.patch @@ -0,0 +1,77 @@ +From 219572d2fc4135b5ce65c735d881787d48b10e71 Mon Sep 17 00:00:00 2001 +From: Hari Bathini +Date: Tue, 7 Dec 2021 16:07:18 +0530 +Subject: [PATCH] powerpc: handle kdump appropriately with + crash_kexec_post_notifiers option + +References: bsc#1193901 ltc#194976 +Patch-mainline: queued +Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git +Git-commit: 219572d2fc4135b5ce65c735d881787d48b10e71 + +Kdump can be triggered after panic_notifers since commit f06e5153f4ae2 +("kernel/panic.c: add "crash_kexec_post_notifiers" option for kdump +after panic_notifers") introduced crash_kexec_post_notifiers option. +But using this option would mean smp_send_stop(), that marks all other +CPUs as offline, gets called before kdump is triggered. As a result, +kdump routines fail to save other CPUs' registers. To fix this, kdump +friendly crash_smp_send_stop() function was introduced with kernel +commit 0ee59413c967 ("x86/panic: replace smp_send_stop() with kdump +friendly version in panic path"). Override this kdump friendly weak +function to handle crash_kexec_post_notifiers option appropriately +on powerpc. + +Reported-by: kernel test robot +Signed-off-by: Hari Bathini +[Fixed signature of crash_stop_this_cpu() - reported by lkp@intel.com] +Signed-off-by: Michael Ellerman +Link: https://lore.kernel.org/r/20211207103719.91117-1-hbathini@linux.ibm.com +Acked-by: Michal Suchanek +--- + arch/powerpc/kernel/smp.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c +index aee3a7119f97..7201fdcf02f1 100644 +--- a/arch/powerpc/kernel/smp.c ++++ b/arch/powerpc/kernel/smp.c +@@ -620,6 +620,36 @@ void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *)) + } + #endif + ++#ifdef CONFIG_NMI_IPI ++static void crash_stop_this_cpu(struct pt_regs *regs) ++#else ++static void crash_stop_this_cpu(void *dummy) ++#endif ++{ ++ /* ++ * Just busy wait here and avoid marking CPU as offline to ensure ++ * register data is captured appropriately. ++ */ ++ while (1) ++ cpu_relax(); ++} ++ ++void crash_smp_send_stop(void) ++{ ++ static bool stopped = false; ++ ++ if (stopped) ++ return; ++ ++ stopped = true; ++ ++#ifdef CONFIG_NMI_IPI ++ smp_send_nmi_ipi(NMI_IPI_ALL_OTHERS, crash_stop_this_cpu, 1000000); ++#else ++ smp_call_function(crash_stop_this_cpu, NULL, 0); ++#endif /* CONFIG_NMI_IPI */ ++} ++ + #ifdef CONFIG_NMI_IPI + static void nmi_stop_this_cpu(struct pt_regs *regs) + { +-- +2.31.1 + diff --git a/patches.suse/powerpc-xmon-Dump-XIVE-information-for-online-only-p.patch b/patches.suse/powerpc-xmon-Dump-XIVE-information-for-online-only-p.patch new file mode 100644 index 0000000..7a9531a --- /dev/null +++ b/patches.suse/powerpc-xmon-Dump-XIVE-information-for-online-only-p.patch @@ -0,0 +1,47 @@ +From fd3de4b179d22119656b32aeb01e23d409deb3de Mon Sep 17 00:00:00 2001 +From: Sachin Sant +Date: Wed, 5 Jan 2022 19:47:48 +0530 +Subject: [PATCH] powerpc/xmon: Dump XIVE information for online-only + processors. + +References: bsc#1193482 ltc#195600 +Patch-mainline: submitted https://lore.kernel.org/linuxppc-dev/164139226833.12930.272224382183014664.sendpatchset@MacBook-Pro.local/ + +dxa command in XMON debugger iterates through all possible processors. +As a result, empty lines are printed even for processors which are not +online. + +CPU 47:pp=00 CPPR=ff IPI=0x0040002f PQ=-- EQ idx=699 T=0 00000000 00000000 +CPU 48: +CPU 49: + +Restrict XIVE information(dxa) to be displayed for online processors only. + +Signed-off-by: Sachin Sant +Acked-by: Michal Suchanek +--- + arch/powerpc/xmon/xmon.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c +index 8b28ff9d98d1..6617824bc05d 100644 +--- a/arch/powerpc/xmon/xmon.c ++++ b/arch/powerpc/xmon/xmon.c +@@ -2809,12 +2809,12 @@ static void dump_all_xives(void) + { + int cpu; + +- if (num_possible_cpus() == 0) { ++ if (num_online_cpus() == 0) { + printf("No possible cpus, use 'dx #' to dump individual cpus\n"); + return; + } + +- for_each_possible_cpu(cpu) ++ for_each_online_cpu(cpu) + dump_one_xive(cpu); + } + +-- +2.31.1 + diff --git a/scripts/git_sort/git_sort.py b/scripts/git_sort/git_sort.py index 215aca4..764a63d 100755 --- a/scripts/git_sort/git_sort.py +++ b/scripts/git_sort/git_sort.py @@ -210,6 +210,7 @@ remotes = ( Head(RepoURL("git://anongit.freedesktop.org/drm/drm"), "drm-next"), Head(RepoURL("git://anongit.freedesktop.org/drm/drm-misc"), "drm-misc-next"), Head(RepoURL("gregkh/tty.git"), "tty-next"), + Head(RepoURL("gregkh/usb.git"), "usb-testing"), Head(RepoURL("jj/linux-apparmor.git"), "apparmor-next"), Head(RepoURL("pablo/nf.git")), Head(RepoURL("pablo/nf-next.git")), diff --git a/series.conf b/series.conf index 82c1b6b..a149224 100644 --- a/series.conf +++ b/series.conf @@ -2097,6 +2097,7 @@ patches.suse/ovl-fix-BUG_ON-in-may_delete-when-called-from-ovl_cl.patch patches.suse/ext4-fix-e2fsprogs-checksum-failure-for-mounted-file.patch patches.suse/ext4-fix-race-writing-to-an-inline_data-file-while-i.patch + patches.suse/ext4-Support-for-checksumming-from-journal-triggers.patch patches.suse/mm-don-t-allow-oversized-kvmalloc-calls.patch patches.suse/fs-dlm-fix-return-EINTR-on-recovery-stopped.patch patches.suse/dma-debug-fix-debugfs-initialization-order.patch @@ -6208,6 +6209,9 @@ patches.suse/ext4-fix-lazy-initialization-next-schedule-time-comp.patch patches.suse/ext4-ensure-enough-credits-in-ext4_ext_shift_path_ex.patch patches.suse/ext4-refresh-the-ext4_ext_path-struct-after-dropping.patch + patches.suse/ext4-check-for-out-of-order-index-extents-in-ext4_va.patch + patches.suse/ext4-check-for-inconsistent-extents-between-index-an.patch + patches.suse/ext4-prevent-partial-update-of-the-extent-blocks.patch patches.suse/xhci-Fix-USB-3.1-enumeration-issues-by-increasing-ro.patch patches.suse/arm64-cpufeature-Export-this_cpu_has_cap-helper.patch patches.suse/net-davinci_emac-Fix-interrupt-pacing-disable.patch @@ -7046,6 +7050,8 @@ patches.suse/powerpc-watchdog-Avoid-holding-wd_smp_lock-over-prin.patch patches.suse/powerpc-watchdog-read-TB-close-to-where-it-is-used.patch patches.suse/powerpc-watchdog-Fix-wd_smp_last_reset_tb-reporting.patch + patches.suse/powerpc-handle-kdump-appropriately-with-crash_kexec_.patch + patches.suse/powerpc-fadump-Fix-inaccurate-CPU-state-info-in-vmco.patch # tip/tip patches.suse/sched-fair-Fix-detection-of-per-CPU-kthreads-waking-a-task.patch @@ -7130,12 +7136,12 @@ patches.suse/tty-serial-fsl_lpuart-add-timeout-for-wait_event_int.patch patches.suse/ima-Fix-undefined-arch_ima_get_secureboot-and-co.patch patches.suse/media-Revert-media-uvcvideo-Set-unique-vdev-name-bas.patch - patches.suse/static_call-Use-non-function-types-to-refer-to-the-t.patch patches.suse/arm64-implement-support-for-static-call-trampolines.patch patches.suse/sched-preempt-Prepare-for-supporting-CONFIG_GENERIC_.patch patches.suse/arm64-Implement-IRQ-exit-preemption-static-call-for-.patch patches.suse/arm64-Implement-HAVE_PREEMPT_DYNAMIC.patch + patches.suse/powerpc-xmon-Dump-XIVE-information-for-online-only-p.patch ######################################################## # kbuild/module infrastructure fixes