From: Zheng Bin zhengbin13@huawei.com
hulk inclusion category: bugfix bugzilla: 31088 CVE: NA
---------------------------
Use fuzz(hydra) to test XFS and automatically generate tmp.img(XFS v5 format, but some metadata is wrong)
xfs_repair information(just one AG): agf_freeblks 0, counted 3224 in ag 0 agf_longest 0, counted 3224 in ag 0 sb_fdblocks 3228, counted 3224
Test as follows: mount tmp.img tmpdir cp file1M tmpdir sync
In 4.19-stable, sync will stuck, while in linux-next, sync not stuck. The reason is same to commit d0c7feaf8767 ("xfs: add agf freeblocks verify in xfs_agf_verify"), cause agf_longest is 0, we can not block this in xfs_agf_verify.
Make sure fdblocks is always inited in mount(also init ifree, icount).
xfs_mountfs xfs_check_summary_counts xfs_initialize_perag_data
Signed-off-by: Zheng Bin zhengbin13@huawei.com Reviewed-by: Hou Tao houtao1@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- fs/xfs/libxfs/xfs_ag_resv.c | 11 +++++++---- fs/xfs/xfs_mount.c | 33 --------------------------------- 2 files changed, 7 insertions(+), 37 deletions(-)
diff --git a/fs/xfs/libxfs/xfs_ag_resv.c b/fs/xfs/libxfs/xfs_ag_resv.c index e2ba2a3..4f099fc 100644 --- a/fs/xfs/libxfs/xfs_ag_resv.c +++ b/fs/xfs/libxfs/xfs_ag_resv.c @@ -309,10 +309,13 @@ }
#ifdef DEBUG - /* need to read in the AGF for the ASSERT below to work */ - error = xfs_alloc_pagf_init(pag->pag_mount, tp, pag->pag_agno, 0); - if (error) - return error; + if (!pag->pagf_init) { + /* need to read in the AGF for the ASSERT below to work */ + error = xfs_alloc_pagf_init(pag->pag_mount, tp, + pag->pag_agno, 0); + if (error) + return error; + }
ASSERT(xfs_perag_resv(pag, XFS_AG_RESV_METADATA)->ar_reserved + xfs_perag_resv(pag, XFS_AG_RESV_RMAPBT)->ar_reserved <= diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 02d1509..3af91e2 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -624,39 +624,6 @@ return -EFSCORRUPTED; }
- /* - * Now the log is mounted, we know if it was an unclean shutdown or - * not. If it was, with the first phase of recovery has completed, we - * have consistent AG blocks on disk. We have not recovered EFIs yet, - * but they are recovered transactionally in the second recovery phase - * later. - * - * If the log was clean when we mounted, we can check the summary - * counters. If any of them are obviously incorrect, we can recompute - * them from the AGF headers in the next step. - */ - if (XFS_LAST_UNMOUNT_WAS_CLEAN(mp) && - (mp->m_sb.sb_fdblocks > mp->m_sb.sb_dblocks || - !xfs_verify_icount(mp, mp->m_sb.sb_icount) || - mp->m_sb.sb_ifree > mp->m_sb.sb_icount)) - mp->m_flags |= XFS_MOUNT_BAD_SUMMARY; - - /* - * We can safely re-initialise incore superblock counters from the - * per-ag data. These may not be correct if the filesystem was not - * cleanly unmounted, so we waited for recovery to finish before doing - * this. - * - * If the filesystem was cleanly unmounted or the previous check did - * not flag anything weird, then we can trust the values in the - * superblock to be correct and we don't need to do anything here. - * Otherwise, recalculate the summary counters. - */ - if ((!xfs_sb_version_haslazysbcount(&mp->m_sb) || - XFS_LAST_UNMOUNT_WAS_CLEAN(mp)) && - !(mp->m_flags & XFS_MOUNT_BAD_SUMMARY)) - return 0; - return xfs_initialize_perag_data(mp, mp->m_sb.sb_agcount); }
From: Zheng Bin zhengbin13@huawei.com
hulk inclusion category: bugfix bugzilla: 31088 CVE: NA
---------------------------
If fdblocks < mp->m_alloc_set_aside, statp->f_bfree will overflow. When we df -h /mnt(xfs mount point), will show this: Filesystem Size Used Avail Use% Mounted on /dev/loop0 17M -64Z -32K 100% /mnt
We can construct an img like this:
dd if=/dev/zero of=xfs.img bs=1M count=20 mkfs.xfs -d agcount=1 xfs.img xfs_db -x xfs.img sb 0 write fdblocks 0 agf 0 write freeblks 0 write longest 0 quit
Make sure statp->f_bfree does not underflow.
Signed-off-by: Zheng Bin zhengbin13@huawei.com Reviewed-by: Hou Tao houtao1@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- fs/xfs/xfs_super.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index dce8114..e126bc6 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -1114,7 +1114,8 @@ struct proc_xfs_info { statp->f_blocks = sbp->sb_dblocks - lsize; spin_unlock(&mp->m_sb_lock);
- statp->f_bfree = fdblocks - mp->m_alloc_set_aside; + /* make sure statp->f_bfree does not underflow */ + statp->f_bfree = max_t(int64_t, fdblocks - mp->m_alloc_set_aside, 0); statp->f_bavail = statp->f_bfree;
fakeinos = statp->f_bfree << sbp->sb_inopblog;