aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/xfs/xfs_ag.h23
-rw-r--r--fs/xfs/xfs_alloc.c80
-rw-r--r--fs/xfs/xfs_buf_item.h4
-rw-r--r--fs/xfs/xfs_fsops.c3
-rw-r--r--fs/xfs/xfs_log_recover.c8
5 files changed, 91 insertions, 27 deletions
diff --git a/fs/xfs/xfs_ag.h b/fs/xfs/xfs_ag.h
index f2aeedb6a579..9f4815e0c96f 100644
--- a/fs/xfs/xfs_ag.h
+++ b/fs/xfs/xfs_ag.h
@@ -63,12 +63,29 @@ typedef struct xfs_agf {
63 __be32 agf_spare0; /* spare field */ 63 __be32 agf_spare0; /* spare field */
64 __be32 agf_levels[XFS_BTNUM_AGF]; /* btree levels */ 64 __be32 agf_levels[XFS_BTNUM_AGF]; /* btree levels */
65 __be32 agf_spare1; /* spare field */ 65 __be32 agf_spare1; /* spare field */
66
66 __be32 agf_flfirst; /* first freelist block's index */ 67 __be32 agf_flfirst; /* first freelist block's index */
67 __be32 agf_fllast; /* last freelist block's index */ 68 __be32 agf_fllast; /* last freelist block's index */
68 __be32 agf_flcount; /* count of blocks in freelist */ 69 __be32 agf_flcount; /* count of blocks in freelist */
69 __be32 agf_freeblks; /* total free blocks */ 70 __be32 agf_freeblks; /* total free blocks */
71
70 __be32 agf_longest; /* longest free space */ 72 __be32 agf_longest; /* longest free space */
71 __be32 agf_btreeblks; /* # of blocks held in AGF btrees */ 73 __be32 agf_btreeblks; /* # of blocks held in AGF btrees */
74 uuid_t agf_uuid; /* uuid of filesystem */
75
76 /*
77 * reserve some contiguous space for future logged fields before we add
78 * the unlogged fields. This makes the range logging via flags and
79 * structure offsets much simpler.
80 */
81 __be64 agf_spare64[16];
82
83 /* unlogged fields, written during buffer writeback. */
84 __be64 agf_lsn; /* last write sequence */
85 __be32 agf_crc; /* crc of agf sector */
86 __be32 agf_spare2;
87
88 /* structure must be padded to 64 bit alignment */
72} xfs_agf_t; 89} xfs_agf_t;
73 90
74#define XFS_AGF_MAGICNUM 0x00000001 91#define XFS_AGF_MAGICNUM 0x00000001
@@ -83,7 +100,8 @@ typedef struct xfs_agf {
83#define XFS_AGF_FREEBLKS 0x00000200 100#define XFS_AGF_FREEBLKS 0x00000200
84#define XFS_AGF_LONGEST 0x00000400 101#define XFS_AGF_LONGEST 0x00000400
85#define XFS_AGF_BTREEBLKS 0x00000800 102#define XFS_AGF_BTREEBLKS 0x00000800
86#define XFS_AGF_NUM_BITS 12 103#define XFS_AGF_UUID 0x00001000
104#define XFS_AGF_NUM_BITS 13
87#define XFS_AGF_ALL_BITS ((1 << XFS_AGF_NUM_BITS) - 1) 105#define XFS_AGF_ALL_BITS ((1 << XFS_AGF_NUM_BITS) - 1)
88 106
89#define XFS_AGF_FLAGS \ 107#define XFS_AGF_FLAGS \
@@ -98,7 +116,8 @@ typedef struct xfs_agf {
98 { XFS_AGF_FLCOUNT, "FLCOUNT" }, \ 116 { XFS_AGF_FLCOUNT, "FLCOUNT" }, \
99 { XFS_AGF_FREEBLKS, "FREEBLKS" }, \ 117 { XFS_AGF_FREEBLKS, "FREEBLKS" }, \
100 { XFS_AGF_LONGEST, "LONGEST" }, \ 118 { XFS_AGF_LONGEST, "LONGEST" }, \
101 { XFS_AGF_BTREEBLKS, "BTREEBLKS" } 119 { XFS_AGF_BTREEBLKS, "BTREEBLKS" }, \
120 { XFS_AGF_UUID, "UUID" }
102 121
103/* disk block (xfs_daddr_t) in the AG */ 122/* disk block (xfs_daddr_t) in the AG */
104#define XFS_AGF_DADDR(mp) ((xfs_daddr_t)(1 << (mp)->m_sectbb_log)) 123#define XFS_AGF_DADDR(mp) ((xfs_daddr_t)(1 << (mp)->m_sectbb_log))
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 = {
diff --git a/fs/xfs/xfs_buf_item.h b/fs/xfs/xfs_buf_item.h
index 101ef8377f1b..76bd7a167a70 100644
--- a/fs/xfs/xfs_buf_item.h
+++ b/fs/xfs/xfs_buf_item.h
@@ -45,12 +45,14 @@ extern kmem_zone_t *xfs_buf_item_zone;
45 * once the changes have been replayed into the buffer. 45 * once the changes have been replayed into the buffer.
46 */ 46 */
47#define XFS_BLF_BTREE_BUF (1<<5) 47#define XFS_BLF_BTREE_BUF (1<<5)
48#define XFS_BLF_AGF_BUF (1<<6)
48 49
49#define XFS_BLF_TYPE_MASK \ 50#define XFS_BLF_TYPE_MASK \
50 (XFS_BLF_UDQUOT_BUF | \ 51 (XFS_BLF_UDQUOT_BUF | \
51 XFS_BLF_PDQUOT_BUF | \ 52 XFS_BLF_PDQUOT_BUF | \
52 XFS_BLF_GDQUOT_BUF | \ 53 XFS_BLF_GDQUOT_BUF | \
53 XFS_BLF_BTREE_BUF) 54 XFS_BLF_BTREE_BUF | \
55 XFS_BLF_AGF_BUF)
54 56
55#define XFS_BLF_CHUNK 128 57#define XFS_BLF_CHUNK 128
56#define XFS_BLF_SHIFT 7 58#define XFS_BLF_SHIFT 7
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
index 6fe286a8e29b..b6cca27e9132 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -247,6 +247,9 @@ xfs_growfs_data_private(
247 tmpsize = agsize - XFS_PREALLOC_BLOCKS(mp); 247 tmpsize = agsize - XFS_PREALLOC_BLOCKS(mp);
248 agf->agf_freeblks = cpu_to_be32(tmpsize); 248 agf->agf_freeblks = cpu_to_be32(tmpsize);
249 agf->agf_longest = cpu_to_be32(tmpsize); 249 agf->agf_longest = cpu_to_be32(tmpsize);
250 if (xfs_sb_version_hascrc(&mp->m_sb))
251 uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_uuid);
252
250 error = xfs_bwrite(bp); 253 error = xfs_bwrite(bp);
251 xfs_buf_relse(bp); 254 xfs_buf_relse(bp);
252 if (error) 255 if (error)
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 3762ce2e99fc..dadf24566d16 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -1953,6 +1953,14 @@ xlog_recover_do_reg_buffer(
1953 break; 1953 break;
1954 } 1954 }
1955 break; 1955 break;
1956 case XFS_BLF_AGF_BUF:
1957 if (*(__be32 *)bp->b_addr != cpu_to_be32(XFS_AGF_MAGIC)) {
1958 xfs_warn(mp, "Bad AGF block magic!");
1959 ASSERT(0);
1960 break;
1961 }
1962 bp->b_ops = &xfs_agf_buf_ops;
1963 break;
1956 default: 1964 default:
1957 break; 1965 break;
1958 } 1966 }