aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_alloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_alloc.c')
-rw-r--r--fs/xfs/xfs_alloc.c80
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
38struct workqueue_struct *xfs_alloc_wq; 40struct 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
2146static void 2151static bool
2147xfs_agf_verify( 2152xfs_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
2184static void 2187static void
2185xfs_agf_read_verify( 2188xfs_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
2191static void 2207static void
2192xfs_agf_write_verify( 2208xfs_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
2198const struct xfs_buf_ops xfs_agf_buf_ops = { 2230const struct xfs_buf_ops xfs_agf_buf_ops = {