From: yangerkun yangerkun@huawei.com
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I8LHTR CVE: NA
--------------------------------
Our growfs test trigger mount error show as below:
[ 40.100164] ------------[ cut here ]------------ [ 40.101808] WARNING: CPU: 5 PID: 769 at fs/xfs/xfs_buf.c:615 xfs_buf_find+0x40d/0x510 ... [ 40.127061] Call Trace: [ 40.127502] xfs_buf_get_map+0x45/0x240 [ 40.128205] xfs_buf_read_map+0x54/0x230 [ 40.129854] xlog_recover_buf_commit_pass2+0x14e/0x490 [ 40.131743] xlog_recover_items_pass2+0x4d/0xa0 [ 40.132605] xlog_recover_commit_trans+0x325/0x350 [ 40.133496] xlog_recovery_process_trans+0xa7/0xe0 [ 40.134408] xlog_recover_process_data+0x8e/0x130 [ 40.135288] xlog_do_recovery_pass+0x3a4/0x730 [ 40.136874] xlog_do_log_recovery+0x62/0xb0 [ 40.137672] xlog_do_recover+0x34/0x1b0 [ 40.138392] xlog_recover+0xd9/0x170 [ 40.139072] xfs_log_mount+0x17f/0x2e0 [ 40.139790] xfs_mountfs+0x3de/0x8a0 [ 40.140473] xfs_fc_fill_super+0x485/0x7f0 [ 40.142095] get_tree_bdev+0x169/0x260 [ 40.142771] vfs_get_tree+0x1f/0xb0 [ 40.143438] do_new_mount+0x15e/0x2d0 [ 40.144141] __x64_sys_mount+0x101/0x140 [ 40.144900] do_syscall_64+0x2d/0x40 [ 40.145591] entry_SYSCALL_64_after_hwframe+0x61/0xc6 ... [ 40.158456] ---[ end trace 0fa38b12a77950ba ]--- [ 40.159354] XFS (loop0): log mount/recovery failed: error -117 [ 40.160956] XFS (loop0): log mount failed
---------------------------> time line +-------------------+----------------+------------------+ | growfs sb item ...|new agi item ...|growfs sb item ...| SHUTDOWN +-------------------+----------------+------------------+ CTX1 CTX2 CTX3
The testcase do multi growfs and then fail the IO which shutdown the xfs. Like the upper order, CTX1 add a new ag, CTX2 may log the agi, CTX3 will do another gorwfs. The sb item may still exist in ail after CTX3 iclog bio success, then the item lsn will change, which may change the tail_lsn.
Then, when we mount the img, and when we recover CTX2, the read for new agi will fail since the ag number still keep invalid.
Fix it by pin the sb lsn as CTX1, and then mount will first replay CTX1.
Signed-off-by: yangerkun yangerkun@huawei.com Signed-off-by: Long Li leo.lilong@huawei.com --- fs/xfs/xfs_buf_item.c | 2 +- fs/xfs/xfs_buf_item.h | 8 +++++++- fs/xfs/xfs_trans.c | 8 ++++++++ 3 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c index 023d4e0385dd..f782363cdb38 100644 --- a/fs/xfs/xfs_buf_item.c +++ b/fs/xfs/xfs_buf_item.c @@ -776,7 +776,7 @@ xfs_buf_item_committed(
trace_xfs_buf_item_committed(bip);
- if ((bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF) && lip->li_lsn != 0) + if ((bip->bli_flags & XFS_BLI_KEEP_LSN) && lip->li_lsn != 0) return lip->li_lsn; return lsn; } diff --git a/fs/xfs/xfs_buf_item.h b/fs/xfs/xfs_buf_item.h index 4d8a6aece995..51e8ec085786 100644 --- a/fs/xfs/xfs_buf_item.h +++ b/fs/xfs/xfs_buf_item.h @@ -20,6 +20,11 @@ struct xfs_mount; #define XFS_BLI_STALE_INODE (1u << 5) #define XFS_BLI_INODE_BUF (1u << 6) #define XFS_BLI_ORDERED (1u << 7) +#define XFS_BLI_GROW_SB_BUF (1u << 8) + +#define XFS_BLI_KEEP_LSN \ + (XFS_BLI_INODE_ALLOC_BUF | \ + XFS_BLI_GROW_SB_BUF)
#define XFS_BLI_FLAGS \ { XFS_BLI_HOLD, "HOLD" }, \ @@ -29,7 +34,8 @@ struct xfs_mount; { XFS_BLI_INODE_ALLOC_BUF, "INODE_ALLOC" }, \ { XFS_BLI_STALE_INODE, "STALE_INODE" }, \ { XFS_BLI_INODE_BUF, "INODE_BUF" }, \ - { XFS_BLI_ORDERED, "ORDERED" } + { XFS_BLI_ORDERED, "ORDERED" }, \ + { XFS_BLI_GROW_SB_BUF, "GROW_SB" }
/* * This is the in core log item structure used to track information diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index 8c0bfc9a33b1..1ec339ca5053 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c @@ -24,6 +24,7 @@ #include "xfs_dquot_item.h" #include "xfs_dquot.h" #include "xfs_icache.h" +#include "xfs_buf_item.h"
struct kmem_cache *xfs_trans_cache;
@@ -476,9 +477,12 @@ xfs_trans_apply_sb_deltas( { struct xfs_dsb *sbp; struct xfs_buf *bp; + struct xfs_buf_log_item *bip; int whole = 0; + int grow = 0;
bp = xfs_trans_getsb(tp); + bip = bp->b_log_item; sbp = bp->b_addr;
/* @@ -524,10 +528,12 @@ xfs_trans_apply_sb_deltas( if (tp->t_dblocks_delta) { be64_add_cpu(&sbp->sb_dblocks, tp->t_dblocks_delta); whole = 1; + grow = 1; } if (tp->t_agcount_delta) { be32_add_cpu(&sbp->sb_agcount, tp->t_agcount_delta); whole = 1; + grow = 1; } if (tp->t_imaxpct_delta) { sbp->sb_imax_pct += tp->t_imaxpct_delta; @@ -555,6 +561,8 @@ xfs_trans_apply_sb_deltas( }
xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SB_BUF); + if (grow) + bip->bli_flags |= XFS_BLI_GROW_SB_BUF; if (whole) /* * Log the whole thing, the fields are noncontiguous.