aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_alloc.c
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2013-04-03 01:11:13 -0400
committerBen Myers <bpm@sgi.com>2013-04-21 15:54:46 -0400
commit4e0e6040c4052aff15a494ac05778f4086d24c33 (patch)
tree6116acb302eb4be87e0193cb7476812a4cbddaac /fs/xfs/xfs_alloc.c
parentee1a47ab0e77600fcbdf1c87d461bd8f3f63150d (diff)
xfs: add CRC checks to the AGF
The AGF already has some self identifying fields (e.g. the sequence number) so we only need to add the uuid to it to identify the filesystem it belongs to. The location is fixed based on the sequence number, so there's no need to add a block number, either. Hence the only additional fields are the CRC and LSN fields. These are unlogged, so place some space between the end of the logged fields and them so that future expansion of the AGF for logged fields can be placed adjacent to the existing logged fields and hence not complicate the field-derived range based logging we currently have. Based originally on a patch from myself, modified further by Christoph Hellwig and then modified again to fit into the verifier structure with additional fields by myself. The multiple signed-off-by tags indicate the age and history of this patch. Signed-off-by: Dave Chinner <dgc@sgi.com> Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Ben Myers <bpm@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.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 = {