diff options
Diffstat (limited to 'fs/xfs/xfs_alloc.c')
-rw-r--r-- | fs/xfs/xfs_alloc.c | 80 |
1 files changed, 56 insertions, 24 deletions
diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c index a8beb5c7dd60..c34f799aa92e 100644 --- a/fs/xfs/xfs_alloc.c +++ b/fs/xfs/xfs_alloc.c | |||
@@ -33,7 +33,9 @@ | |||
33 | #include "xfs_alloc.h" | 33 | #include "xfs_alloc.h" |
34 | #include "xfs_extent_busy.h" | 34 | #include "xfs_extent_busy.h" |
35 | #include "xfs_error.h" | 35 | #include "xfs_error.h" |
36 | #include "xfs_cksum.h" | ||
36 | #include "xfs_trace.h" | 37 | #include "xfs_trace.h" |
38 | #include "xfs_buf_item.h" | ||
37 | 39 | ||
38 | struct workqueue_struct *xfs_alloc_wq; | 40 | struct workqueue_struct *xfs_alloc_wq; |
39 | 41 | ||
@@ -2058,11 +2060,14 @@ xfs_alloc_log_agf( | |||
2058 | offsetof(xfs_agf_t, agf_freeblks), | 2060 | offsetof(xfs_agf_t, agf_freeblks), |
2059 | offsetof(xfs_agf_t, agf_longest), | 2061 | offsetof(xfs_agf_t, agf_longest), |
2060 | offsetof(xfs_agf_t, agf_btreeblks), | 2062 | offsetof(xfs_agf_t, agf_btreeblks), |
2063 | offsetof(xfs_agf_t, agf_uuid), | ||
2061 | sizeof(xfs_agf_t) | 2064 | sizeof(xfs_agf_t) |
2062 | }; | 2065 | }; |
2063 | 2066 | ||
2064 | trace_xfs_agf(tp->t_mountp, XFS_BUF_TO_AGF(bp), fields, _RET_IP_); | 2067 | trace_xfs_agf(tp->t_mountp, XFS_BUF_TO_AGF(bp), fields, _RET_IP_); |
2065 | 2068 | ||
2069 | xfs_trans_buf_set_type(tp, bp, XFS_BLF_AGF_BUF); | ||
2070 | |||
2066 | xfs_btree_offsets(fields, offsets, XFS_AGF_NUM_BITS, &first, &last); | 2071 | xfs_btree_offsets(fields, offsets, XFS_AGF_NUM_BITS, &first, &last); |
2067 | xfs_trans_log_buf(tp, bp, (uint)first, (uint)last); | 2072 | xfs_trans_log_buf(tp, bp, (uint)first, (uint)last); |
2068 | } | 2073 | } |
@@ -2143,22 +2148,24 @@ xfs_alloc_put_freelist( | |||
2143 | return 0; | 2148 | return 0; |
2144 | } | 2149 | } |
2145 | 2150 | ||
2146 | static void | 2151 | static bool |
2147 | xfs_agf_verify( | 2152 | xfs_agf_verify( |
2153 | struct xfs_mount *mp, | ||
2148 | struct xfs_buf *bp) | 2154 | struct xfs_buf *bp) |
2149 | { | 2155 | { |
2150 | struct xfs_mount *mp = bp->b_target->bt_mount; | 2156 | struct xfs_agf *agf = XFS_BUF_TO_AGF(bp); |
2151 | struct xfs_agf *agf; | ||
2152 | int agf_ok; | ||
2153 | 2157 | ||
2154 | agf = XFS_BUF_TO_AGF(bp); | 2158 | if (xfs_sb_version_hascrc(&mp->m_sb) && |
2159 | !uuid_equal(&agf->agf_uuid, &mp->m_sb.sb_uuid)) | ||
2160 | return false; | ||
2155 | 2161 | ||
2156 | agf_ok = agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) && | 2162 | if (!(agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) && |
2157 | XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum)) && | 2163 | XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum)) && |
2158 | be32_to_cpu(agf->agf_freeblks) <= be32_to_cpu(agf->agf_length) && | 2164 | be32_to_cpu(agf->agf_freeblks) <= be32_to_cpu(agf->agf_length) && |
2159 | be32_to_cpu(agf->agf_flfirst) < XFS_AGFL_SIZE(mp) && | 2165 | be32_to_cpu(agf->agf_flfirst) < XFS_AGFL_SIZE(mp) && |
2160 | be32_to_cpu(agf->agf_fllast) < XFS_AGFL_SIZE(mp) && | 2166 | be32_to_cpu(agf->agf_fllast) < XFS_AGFL_SIZE(mp) && |
2161 | be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp); | 2167 | be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp))) |
2168 | return false; | ||
2162 | 2169 | ||
2163 | /* | 2170 | /* |
2164 | * during growfs operations, the perag is not fully initialised, | 2171 | * during growfs operations, the perag is not fully initialised, |
@@ -2166,33 +2173,58 @@ xfs_agf_verify( | |||
2166 | * use it by using uncached buffers that don't have the perag attached | 2173 | * use it by using uncached buffers that don't have the perag attached |
2167 | * so we can detect and avoid this problem. | 2174 | * so we can detect and avoid this problem. |
2168 | */ | 2175 | */ |
2169 | if (bp->b_pag) | 2176 | if (bp->b_pag && be32_to_cpu(agf->agf_seqno) != bp->b_pag->pag_agno) |
2170 | agf_ok = agf_ok && be32_to_cpu(agf->agf_seqno) == | 2177 | return false; |
2171 | bp->b_pag->pag_agno; | ||
2172 | 2178 | ||
2173 | if (xfs_sb_version_haslazysbcount(&mp->m_sb)) | 2179 | if (xfs_sb_version_haslazysbcount(&mp->m_sb) && |
2174 | agf_ok = agf_ok && be32_to_cpu(agf->agf_btreeblks) <= | 2180 | be32_to_cpu(agf->agf_btreeblks) > be32_to_cpu(agf->agf_length)) |
2175 | be32_to_cpu(agf->agf_length); | 2181 | return false; |
2182 | |||
2183 | return true;; | ||
2176 | 2184 | ||
2177 | if (unlikely(XFS_TEST_ERROR(!agf_ok, mp, XFS_ERRTAG_ALLOC_READ_AGF, | ||
2178 | XFS_RANDOM_ALLOC_READ_AGF))) { | ||
2179 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, agf); | ||
2180 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
2181 | } | ||
2182 | } | 2185 | } |
2183 | 2186 | ||
2184 | static void | 2187 | static void |
2185 | xfs_agf_read_verify( | 2188 | xfs_agf_read_verify( |
2186 | struct xfs_buf *bp) | 2189 | struct xfs_buf *bp) |
2187 | { | 2190 | { |
2188 | xfs_agf_verify(bp); | 2191 | struct xfs_mount *mp = bp->b_target->bt_mount; |
2192 | int agf_ok = 1; | ||
2193 | |||
2194 | if (xfs_sb_version_hascrc(&mp->m_sb)) | ||
2195 | agf_ok = xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length), | ||
2196 | offsetof(struct xfs_agf, agf_crc)); | ||
2197 | |||
2198 | agf_ok = agf_ok && xfs_agf_verify(mp, bp); | ||
2199 | |||
2200 | if (unlikely(XFS_TEST_ERROR(!agf_ok, mp, XFS_ERRTAG_ALLOC_READ_AGF, | ||
2201 | XFS_RANDOM_ALLOC_READ_AGF))) { | ||
2202 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); | ||
2203 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
2204 | } | ||
2189 | } | 2205 | } |
2190 | 2206 | ||
2191 | static void | 2207 | static void |
2192 | xfs_agf_write_verify( | 2208 | xfs_agf_write_verify( |
2193 | struct xfs_buf *bp) | 2209 | struct xfs_buf *bp) |
2194 | { | 2210 | { |
2195 | xfs_agf_verify(bp); | 2211 | struct xfs_mount *mp = bp->b_target->bt_mount; |
2212 | struct xfs_buf_log_item *bip = bp->b_fspriv; | ||
2213 | |||
2214 | if (!xfs_agf_verify(mp, bp)) { | ||
2215 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); | ||
2216 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
2217 | return; | ||
2218 | } | ||
2219 | |||
2220 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | ||
2221 | return; | ||
2222 | |||
2223 | if (bip) | ||
2224 | XFS_BUF_TO_AGF(bp)->agf_lsn = cpu_to_be64(bip->bli_item.li_lsn); | ||
2225 | |||
2226 | xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length), | ||
2227 | offsetof(struct xfs_agf, agf_crc)); | ||
2196 | } | 2228 | } |
2197 | 2229 | ||
2198 | const struct xfs_buf_ops xfs_agf_buf_ops = { | 2230 | const struct xfs_buf_ops xfs_agf_buf_ops = { |