aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_alloc.c
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2012-11-14 01:44:56 -0500
committerBen Myers <bpm@sgi.com>2012-11-15 22:34:10 -0500
commit5d5f527d13369d0047d52b7ac4ddee4f8c0ad173 (patch)
treebe5aa9ed00828ca05ace198a78eed422a5627cc1 /fs/xfs/xfs_alloc.c
parent98021821a502db347bd9c7671beeee6e8ce07ea6 (diff)
xfs: verify AGF blocks as they are read from disk
Add an AGF block verify callback function and pass it into the buffer read functions. This replaces the existing verification that is done after the read completes. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Mark Tinguely <tinguely@sgi.com> Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_alloc.c')
-rw-r--r--fs/xfs/xfs_alloc.c68
1 files changed, 42 insertions, 26 deletions
diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c
index 21c3db08fd01..c9eb955a49c7 100644
--- a/fs/xfs/xfs_alloc.c
+++ b/fs/xfs/xfs_alloc.c
@@ -2091,6 +2091,47 @@ xfs_alloc_put_freelist(
2091 return 0; 2091 return 0;
2092} 2092}
2093 2093
2094static void
2095xfs_agf_read_verify(
2096 struct xfs_buf *bp)
2097 {
2098 struct xfs_mount *mp = bp->b_target->bt_mount;
2099 struct xfs_agf *agf;
2100 int agf_ok;
2101
2102 agf = XFS_BUF_TO_AGF(bp);
2103
2104 agf_ok = agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) &&
2105 XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum)) &&
2106 be32_to_cpu(agf->agf_freeblks) <= be32_to_cpu(agf->agf_length) &&
2107 be32_to_cpu(agf->agf_flfirst) < XFS_AGFL_SIZE(mp) &&
2108 be32_to_cpu(agf->agf_fllast) < XFS_AGFL_SIZE(mp) &&
2109 be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp);
2110
2111 /*
2112 * during growfs operations, the perag is not fully initialised,
2113 * so we can't use it for any useful checking. growfs ensures we can't
2114 * use it by using uncached buffers that don't have the perag attached
2115 * so we can detect and avoid this problem.
2116 */
2117 if (bp->b_pag)
2118 agf_ok = agf_ok && be32_to_cpu(agf->agf_seqno) ==
2119 bp->b_pag->pag_agno;
2120
2121 if (xfs_sb_version_haslazysbcount(&mp->m_sb))
2122 agf_ok = agf_ok && be32_to_cpu(agf->agf_btreeblks) <=
2123 be32_to_cpu(agf->agf_length);
2124
2125 if (unlikely(XFS_TEST_ERROR(!agf_ok, mp, XFS_ERRTAG_ALLOC_READ_AGF,
2126 XFS_RANDOM_ALLOC_READ_AGF))) {
2127 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, agf);
2128 xfs_buf_ioerror(bp, EFSCORRUPTED);
2129 }
2130
2131 bp->b_iodone = NULL;
2132 xfs_buf_ioend(bp, 0);
2133}
2134
2094/* 2135/*
2095 * Read in the allocation group header (free/alloc section). 2136 * Read in the allocation group header (free/alloc section).
2096 */ 2137 */
@@ -2102,44 +2143,19 @@ xfs_read_agf(
2102 int flags, /* XFS_BUF_ */ 2143 int flags, /* XFS_BUF_ */
2103 struct xfs_buf **bpp) /* buffer for the ag freelist header */ 2144 struct xfs_buf **bpp) /* buffer for the ag freelist header */
2104{ 2145{
2105 struct xfs_agf *agf; /* ag freelist header */
2106 int agf_ok; /* set if agf is consistent */
2107 int error; 2146 int error;
2108 2147
2109 ASSERT(agno != NULLAGNUMBER); 2148 ASSERT(agno != NULLAGNUMBER);
2110 error = xfs_trans_read_buf( 2149 error = xfs_trans_read_buf(
2111 mp, tp, mp->m_ddev_targp, 2150 mp, tp, mp->m_ddev_targp,
2112 XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)), 2151 XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)),
2113 XFS_FSS_TO_BB(mp, 1), flags, bpp, NULL); 2152 XFS_FSS_TO_BB(mp, 1), flags, bpp, xfs_agf_read_verify);
2114 if (error) 2153 if (error)
2115 return error; 2154 return error;
2116 if (!*bpp) 2155 if (!*bpp)
2117 return 0; 2156 return 0;
2118 2157
2119 ASSERT(!(*bpp)->b_error); 2158 ASSERT(!(*bpp)->b_error);
2120 agf = XFS_BUF_TO_AGF(*bpp);
2121
2122 /*
2123 * Validate the magic number of the agf block.
2124 */
2125 agf_ok =
2126 agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) &&
2127 XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum)) &&
2128 be32_to_cpu(agf->agf_freeblks) <= be32_to_cpu(agf->agf_length) &&
2129 be32_to_cpu(agf->agf_flfirst) < XFS_AGFL_SIZE(mp) &&
2130 be32_to_cpu(agf->agf_fllast) < XFS_AGFL_SIZE(mp) &&
2131 be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp) &&
2132 be32_to_cpu(agf->agf_seqno) == agno;
2133 if (xfs_sb_version_haslazysbcount(&mp->m_sb))
2134 agf_ok = agf_ok && be32_to_cpu(agf->agf_btreeblks) <=
2135 be32_to_cpu(agf->agf_length);
2136 if (unlikely(XFS_TEST_ERROR(!agf_ok, mp, XFS_ERRTAG_ALLOC_READ_AGF,
2137 XFS_RANDOM_ALLOC_READ_AGF))) {
2138 XFS_CORRUPTION_ERROR("xfs_alloc_read_agf",
2139 XFS_ERRLEVEL_LOW, mp, agf);
2140 xfs_trans_brelse(tp, *bpp);
2141 return XFS_ERROR(EFSCORRUPTED);
2142 }
2143 xfs_buf_set_ref(*bpp, XFS_AGF_REF); 2159 xfs_buf_set_ref(*bpp, XFS_AGF_REF);
2144 return 0; 2160 return 0;
2145} 2161}