From 00d22a1c367d03f469f8e1e924b062b09b0545e8 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Fri, 10 Aug 2018 17:55:56 -0700 Subject: [PATCH 1/3] xfs: recalculate summary counters at mount time if icount is bad Since the sb write verifier trips on bad icounts, we should also force a mount time recalculation of the summary counters if the icount is bad. This helps us avoid blowing up at freeze/unmount time when the bad counter gets written back out. Signed-off-by: Darrick J. Wong Reviewed-by: Allison Henderson Reviewed-by: Carlos Maiolino --- fs/xfs/xfs_mount.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 99db27d6ac8a..02d15098dbee 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -637,6 +637,7 @@ xfs_check_summary_counts( */ 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; From 1fc25f51d7c18e07e8cf935cbdd4603adfc7b3ad Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Fri, 10 Aug 2018 17:55:57 -0700 Subject: [PATCH 2/3] xfs: sanity check ag header values in xrep_calc_ag_resblks Check the values we read in from the AG headers when calculating the block reservations for a repair transaction. If they're obviously wrong, substitute worst case assumptions (rather than ENOSPC on a bogus reservation request). Signed-off-by: Darrick J. Wong Reviewed-by: Allison Henderson Reviewed-by: Carlos Maiolino --- fs/xfs/scrub/repair.c | 46 +++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c index 17cf48564390..9f08dd9bf1d5 100644 --- a/fs/xfs/scrub/repair.c +++ b/fs/xfs/scrub/repair.c @@ -195,8 +195,8 @@ xrep_calc_ag_resblks( struct xfs_scrub_metadata *sm = sc->sm; struct xfs_perag *pag; struct xfs_buf *bp; - xfs_agino_t icount = 0; - xfs_extlen_t aglen = 0; + xfs_agino_t icount = NULLAGINO; + xfs_extlen_t aglen = NULLAGBLOCK; xfs_extlen_t usedlen; xfs_extlen_t freelen; xfs_extlen_t bnobt_sz; @@ -208,20 +208,14 @@ xrep_calc_ag_resblks( if (!(sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR)) return 0; - /* Use in-core counters if possible. */ pag = xfs_perag_get(mp, sm->sm_agno); - if (pag->pagi_init) + if (pag->pagi_init) { + /* Use in-core icount if possible. */ icount = pag->pagi_count; - - /* - * Otherwise try to get the actual counters from disk; if not, make - * some worst case assumptions. - */ - if (icount == 0) { + } else { + /* Try to get the actual counters from disk. */ error = xfs_ialloc_read_agi(mp, NULL, sm->sm_agno, &bp); - if (error) { - icount = mp->m_sb.sb_agblocks / mp->m_sb.sb_inopblock; - } else { + if (!error) { icount = pag->pagi_count; xfs_buf_relse(bp); } @@ -229,18 +223,32 @@ xrep_calc_ag_resblks( /* Now grab the block counters from the AGF. */ error = xfs_alloc_read_agf(mp, NULL, sm->sm_agno, 0, &bp); - if (error) { - aglen = mp->m_sb.sb_agblocks; - freelen = aglen; - usedlen = aglen; - } else { + if (!error) { aglen = be32_to_cpu(XFS_BUF_TO_AGF(bp)->agf_length); - freelen = pag->pagf_freeblks; + freelen = be32_to_cpu(XFS_BUF_TO_AGF(bp)->agf_freeblks); usedlen = aglen - freelen; xfs_buf_relse(bp); } xfs_perag_put(pag); + /* If the icount is impossible, make some worst-case assumptions. */ + if (icount == NULLAGINO || + !xfs_verify_agino(mp, sm->sm_agno, icount)) { + xfs_agino_t first, last; + + xfs_agino_range(mp, sm->sm_agno, &first, &last); + icount = last - first + 1; + } + + /* If the block counts are impossible, make worst-case assumptions. */ + if (aglen == NULLAGBLOCK || + aglen != xfs_ag_block_count(mp, sm->sm_agno) || + freelen >= aglen) { + aglen = xfs_ag_block_count(mp, sm->sm_agno); + freelen = aglen; + usedlen = aglen; + } + trace_xrep_calc_ag_resblks(mp, sm->sm_agno, icount, aglen, freelen, usedlen); From 7d5e049e72c4cb933b557c78cbd63285dd8102ce Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Fri, 10 Aug 2018 17:55:57 -0700 Subject: [PATCH 3/3] iomap: fix WARN_ON_ONCE on uninitialized variable In commit 9dc55f1389f9569 ("iomap: add support for sub-pagesize buffered I/O without buffer heads") we moved the initialization of poff (it's computed from pos) into a separate helper function. Inline data only ever deals with pos == 0, hence the WARN_ON_ONCE, but now we're testing an uninitialized variable. Therefore, change the test to check the parameter directly. Signed-off-by: Darrick J. Wong Reviewed-by: Allison Henderson Reviewed-by: Carlos Maiolino --- fs/iomap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/iomap.c b/fs/iomap.c index 8bd54c08deee..8a18163dc432 100644 --- a/fs/iomap.c +++ b/fs/iomap.c @@ -290,7 +290,7 @@ iomap_readpage_actor(struct inode *inode, loff_t pos, loff_t length, void *data, sector_t sector; if (iomap->type == IOMAP_INLINE) { - WARN_ON_ONCE(poff); + WARN_ON_ONCE(pos); iomap_read_inline_data(inode, page, iomap); return PAGE_SIZE; }