From: yangerkun yangerkun@huawei.com
hulk inclusion category: bugfix bugzilla: 188870, https://gitee.com/openeuler/kernel/issues/I76JSK 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 | 9 ++++++++- fs/xfs/xfs_trans.c | 14 +++++++++++--- 3 files changed, 20 insertions(+), 5 deletions(-)
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c index 3a9e006b7220..245d8d1899dd 100644 --- a/fs/xfs/xfs_buf_item.c +++ b/fs/xfs/xfs_buf_item.c @@ -715,7 +715,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 50aa0f5ef959..d890fcef4543 100644 --- a/fs/xfs/xfs_buf_item.h +++ b/fs/xfs/xfs_buf_item.h @@ -17,6 +17,12 @@ #define XFS_BLI_STALE_INODE 0x20 #define XFS_BLI_INODE_BUF 0x40 #define XFS_BLI_ORDERED 0x80 +#define XFS_BLI_GROW_SB_BUF 0x100 + +#define XFS_BLI_KEEP_LSN \ + (XFS_BLI_INODE_ALLOC_BUF | \ + XFS_BLI_GROW_SB_BUF) +
#define XFS_BLI_FLAGS \ { XFS_BLI_HOLD, "HOLD" }, \ @@ -26,7 +32,8 @@ { 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" }
struct xfs_buf; diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index 8b6617833c58..12b0163d321c 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"
kmem_zone_t *xfs_trans_zone;
@@ -478,11 +479,14 @@ STATIC void xfs_trans_apply_sb_deltas( xfs_trans_t *tp) { - xfs_dsb_t *sbp; - xfs_buf_t *bp; - int whole = 0; + xfs_dsb_t *sbp; + xfs_buf_t *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;
/* @@ -507,10 +511,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; @@ -538,6 +544,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.