diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/xfs/xfs_ag.h | 23 | ||||
-rw-r--r-- | fs/xfs/xfs_alloc.c | 80 | ||||
-rw-r--r-- | fs/xfs/xfs_buf_item.h | 4 | ||||
-rw-r--r-- | fs/xfs/xfs_fsops.c | 3 | ||||
-rw-r--r-- | fs/xfs/xfs_log_recover.c | 8 |
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 | ||
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 = { |
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 | } |