diff options
-rw-r--r-- | fs/xfs/libxfs/xfs_alloc.c | 12 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_attr_leaf.c | 3 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_bmap.c | 10 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_btree.c | 17 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_da_btree.c | 4 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_dir2_block.c | 3 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_dir2_data.c | 3 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_dir2_leaf.c | 3 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_dir2_node.c | 3 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_ialloc.c | 10 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_sb.c | 10 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_symlink_remote.c | 7 | ||||
-rw-r--r-- | fs/xfs/xfs_bmap_util.c | 2 | ||||
-rw-r--r-- | fs/xfs/xfs_iomap.c | 14 | ||||
-rw-r--r-- | fs/xfs/xfs_log.c | 71 | ||||
-rw-r--r-- | fs/xfs/xfs_log.h | 1 | ||||
-rw-r--r-- | fs/xfs/xfs_log_priv.h | 51 | ||||
-rw-r--r-- | fs/xfs/xfs_log_recover.c | 12 |
18 files changed, 210 insertions, 26 deletions
diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c index 9b5da7e3b5c2..e926197e0620 100644 --- a/fs/xfs/libxfs/xfs_alloc.c +++ b/fs/xfs/libxfs/xfs_alloc.c | |||
@@ -482,7 +482,9 @@ xfs_agfl_verify( | |||
482 | be32_to_cpu(agfl->agfl_bno[i]) >= mp->m_sb.sb_agblocks) | 482 | be32_to_cpu(agfl->agfl_bno[i]) >= mp->m_sb.sb_agblocks) |
483 | return false; | 483 | return false; |
484 | } | 484 | } |
485 | return true; | 485 | |
486 | return xfs_log_check_lsn(mp, | ||
487 | be64_to_cpu(XFS_BUF_TO_AGFL(bp)->agfl_lsn)); | ||
486 | } | 488 | } |
487 | 489 | ||
488 | static void | 490 | static void |
@@ -2259,9 +2261,13 @@ xfs_agf_verify( | |||
2259 | { | 2261 | { |
2260 | struct xfs_agf *agf = XFS_BUF_TO_AGF(bp); | 2262 | struct xfs_agf *agf = XFS_BUF_TO_AGF(bp); |
2261 | 2263 | ||
2262 | if (xfs_sb_version_hascrc(&mp->m_sb) && | 2264 | if (xfs_sb_version_hascrc(&mp->m_sb)) { |
2263 | !uuid_equal(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid)) | 2265 | if (!uuid_equal(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid)) |
2264 | return false; | 2266 | return false; |
2267 | if (!xfs_log_check_lsn(mp, | ||
2268 | be64_to_cpu(XFS_BUF_TO_AGF(bp)->agf_lsn))) | ||
2269 | return false; | ||
2270 | } | ||
2265 | 2271 | ||
2266 | if (!(agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) && | 2272 | if (!(agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) && |
2267 | XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum)) && | 2273 | XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum)) && |
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c index 33df52d97ec7..aa187f7ba2dd 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.c +++ b/fs/xfs/libxfs/xfs_attr_leaf.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include "xfs_buf_item.h" | 41 | #include "xfs_buf_item.h" |
42 | #include "xfs_cksum.h" | 42 | #include "xfs_cksum.h" |
43 | #include "xfs_dir2.h" | 43 | #include "xfs_dir2.h" |
44 | #include "xfs_log.h" | ||
44 | 45 | ||
45 | 46 | ||
46 | /* | 47 | /* |
@@ -266,6 +267,8 @@ xfs_attr3_leaf_verify( | |||
266 | return false; | 267 | return false; |
267 | if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn) | 268 | if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn) |
268 | return false; | 269 | return false; |
270 | if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->info.lsn))) | ||
271 | return false; | ||
269 | } else { | 272 | } else { |
270 | if (ichdr.magic != XFS_ATTR_LEAF_MAGIC) | 273 | if (ichdr.magic != XFS_ATTR_LEAF_MAGIC) |
271 | return false; | 274 | return false; |
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index 5256fe59623b..ab92d10890ed 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c | |||
@@ -948,14 +948,16 @@ xfs_bmap_local_to_extents( | |||
948 | bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0); | 948 | bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0); |
949 | 949 | ||
950 | /* | 950 | /* |
951 | * Initialise the block and copy the data | 951 | * Initialize the block, copy the data and log the remote buffer. |
952 | * | 952 | * |
953 | * Note: init_fn must set the buffer log item type correctly! | 953 | * The callout is responsible for logging because the remote format |
954 | * might differ from the local format and thus we don't know how much to | ||
955 | * log here. Note that init_fn must also set the buffer log item type | ||
956 | * correctly. | ||
954 | */ | 957 | */ |
955 | init_fn(tp, bp, ip, ifp); | 958 | init_fn(tp, bp, ip, ifp); |
956 | 959 | ||
957 | /* account for the change in fork size and log everything */ | 960 | /* account for the change in fork size */ |
958 | xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1); | ||
959 | xfs_idata_realloc(ip, -ifp->if_bytes, whichfork); | 961 | xfs_idata_realloc(ip, -ifp->if_bytes, whichfork); |
960 | xfs_bmap_local_to_extents_empty(ip, whichfork); | 962 | xfs_bmap_local_to_extents_empty(ip, whichfork); |
961 | flags |= XFS_ILOG_CORE; | 963 | flags |= XFS_ILOG_CORE; |
diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c index f7d7ee7a2607..235d026c7f9c 100644 --- a/fs/xfs/libxfs/xfs_btree.c +++ b/fs/xfs/libxfs/xfs_btree.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include "xfs_trace.h" | 32 | #include "xfs_trace.h" |
33 | #include "xfs_cksum.h" | 33 | #include "xfs_cksum.h" |
34 | #include "xfs_alloc.h" | 34 | #include "xfs_alloc.h" |
35 | #include "xfs_log.h" | ||
35 | 36 | ||
36 | /* | 37 | /* |
37 | * Cursor allocation zone. | 38 | * Cursor allocation zone. |
@@ -243,8 +244,14 @@ bool | |||
243 | xfs_btree_lblock_verify_crc( | 244 | xfs_btree_lblock_verify_crc( |
244 | struct xfs_buf *bp) | 245 | struct xfs_buf *bp) |
245 | { | 246 | { |
246 | if (xfs_sb_version_hascrc(&bp->b_target->bt_mount->m_sb)) | 247 | struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); |
248 | struct xfs_mount *mp = bp->b_target->bt_mount; | ||
249 | |||
250 | if (xfs_sb_version_hascrc(&mp->m_sb)) { | ||
251 | if (!xfs_log_check_lsn(mp, be64_to_cpu(block->bb_u.l.bb_lsn))) | ||
252 | return false; | ||
247 | return xfs_buf_verify_cksum(bp, XFS_BTREE_LBLOCK_CRC_OFF); | 253 | return xfs_buf_verify_cksum(bp, XFS_BTREE_LBLOCK_CRC_OFF); |
254 | } | ||
248 | 255 | ||
249 | return true; | 256 | return true; |
250 | } | 257 | } |
@@ -275,8 +282,14 @@ bool | |||
275 | xfs_btree_sblock_verify_crc( | 282 | xfs_btree_sblock_verify_crc( |
276 | struct xfs_buf *bp) | 283 | struct xfs_buf *bp) |
277 | { | 284 | { |
278 | if (xfs_sb_version_hascrc(&bp->b_target->bt_mount->m_sb)) | 285 | struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); |
286 | struct xfs_mount *mp = bp->b_target->bt_mount; | ||
287 | |||
288 | if (xfs_sb_version_hascrc(&mp->m_sb)) { | ||
289 | if (!xfs_log_check_lsn(mp, be64_to_cpu(block->bb_u.s.bb_lsn))) | ||
290 | return false; | ||
279 | return xfs_buf_verify_cksum(bp, XFS_BTREE_SBLOCK_CRC_OFF); | 291 | return xfs_buf_verify_cksum(bp, XFS_BTREE_SBLOCK_CRC_OFF); |
292 | } | ||
280 | 293 | ||
281 | return true; | 294 | return true; |
282 | } | 295 | } |
diff --git a/fs/xfs/libxfs/xfs_da_btree.c b/fs/xfs/libxfs/xfs_da_btree.c index be43248a5822..e89a0f8f827c 100644 --- a/fs/xfs/libxfs/xfs_da_btree.c +++ b/fs/xfs/libxfs/xfs_da_btree.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include "xfs_trace.h" | 39 | #include "xfs_trace.h" |
40 | #include "xfs_cksum.h" | 40 | #include "xfs_cksum.h" |
41 | #include "xfs_buf_item.h" | 41 | #include "xfs_buf_item.h" |
42 | #include "xfs_log.h" | ||
42 | 43 | ||
43 | /* | 44 | /* |
44 | * xfs_da_btree.c | 45 | * xfs_da_btree.c |
@@ -150,6 +151,8 @@ xfs_da3_node_verify( | |||
150 | return false; | 151 | return false; |
151 | if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn) | 152 | if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn) |
152 | return false; | 153 | return false; |
154 | if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->info.lsn))) | ||
155 | return false; | ||
153 | } else { | 156 | } else { |
154 | if (ichdr.magic != XFS_DA_NODE_MAGIC) | 157 | if (ichdr.magic != XFS_DA_NODE_MAGIC) |
155 | return false; | 158 | return false; |
@@ -322,6 +325,7 @@ xfs_da3_node_create( | |||
322 | if (xfs_sb_version_hascrc(&mp->m_sb)) { | 325 | if (xfs_sb_version_hascrc(&mp->m_sb)) { |
323 | struct xfs_da3_node_hdr *hdr3 = bp->b_addr; | 326 | struct xfs_da3_node_hdr *hdr3 = bp->b_addr; |
324 | 327 | ||
328 | memset(hdr3, 0, sizeof(struct xfs_da3_node_hdr)); | ||
325 | ichdr.magic = XFS_DA3_NODE_MAGIC; | 329 | ichdr.magic = XFS_DA3_NODE_MAGIC; |
326 | hdr3->info.blkno = cpu_to_be64(bp->b_bn); | 330 | hdr3->info.blkno = cpu_to_be64(bp->b_bn); |
327 | hdr3->info.owner = cpu_to_be64(args->dp->i_ino); | 331 | hdr3->info.owner = cpu_to_be64(args->dp->i_ino); |
diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c index 4778d1dd511a..9c10e2b8cfcb 100644 --- a/fs/xfs/libxfs/xfs_dir2_block.c +++ b/fs/xfs/libxfs/xfs_dir2_block.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include "xfs_error.h" | 34 | #include "xfs_error.h" |
35 | #include "xfs_trace.h" | 35 | #include "xfs_trace.h" |
36 | #include "xfs_cksum.h" | 36 | #include "xfs_cksum.h" |
37 | #include "xfs_log.h" | ||
37 | 38 | ||
38 | /* | 39 | /* |
39 | * Local function prototypes. | 40 | * Local function prototypes. |
@@ -71,6 +72,8 @@ xfs_dir3_block_verify( | |||
71 | return false; | 72 | return false; |
72 | if (be64_to_cpu(hdr3->blkno) != bp->b_bn) | 73 | if (be64_to_cpu(hdr3->blkno) != bp->b_bn) |
73 | return false; | 74 | return false; |
75 | if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->lsn))) | ||
76 | return false; | ||
74 | } else { | 77 | } else { |
75 | if (hdr3->magic != cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)) | 78 | if (hdr3->magic != cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)) |
76 | return false; | 79 | return false; |
diff --git a/fs/xfs/libxfs/xfs_dir2_data.c b/fs/xfs/libxfs/xfs_dir2_data.c index 824131e71bc5..af71a84f343c 100644 --- a/fs/xfs/libxfs/xfs_dir2_data.c +++ b/fs/xfs/libxfs/xfs_dir2_data.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include "xfs_trans.h" | 31 | #include "xfs_trans.h" |
32 | #include "xfs_buf_item.h" | 32 | #include "xfs_buf_item.h" |
33 | #include "xfs_cksum.h" | 33 | #include "xfs_cksum.h" |
34 | #include "xfs_log.h" | ||
34 | 35 | ||
35 | /* | 36 | /* |
36 | * Check the consistency of the data block. | 37 | * Check the consistency of the data block. |
@@ -224,6 +225,8 @@ xfs_dir3_data_verify( | |||
224 | return false; | 225 | return false; |
225 | if (be64_to_cpu(hdr3->blkno) != bp->b_bn) | 226 | if (be64_to_cpu(hdr3->blkno) != bp->b_bn) |
226 | return false; | 227 | return false; |
228 | if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->lsn))) | ||
229 | return false; | ||
227 | } else { | 230 | } else { |
228 | if (hdr3->magic != cpu_to_be32(XFS_DIR2_DATA_MAGIC)) | 231 | if (hdr3->magic != cpu_to_be32(XFS_DIR2_DATA_MAGIC)) |
229 | return false; | 232 | return false; |
diff --git a/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c index f300240ebb8d..3923e1f94697 100644 --- a/fs/xfs/libxfs/xfs_dir2_leaf.c +++ b/fs/xfs/libxfs/xfs_dir2_leaf.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include "xfs_trans.h" | 33 | #include "xfs_trans.h" |
34 | #include "xfs_buf_item.h" | 34 | #include "xfs_buf_item.h" |
35 | #include "xfs_cksum.h" | 35 | #include "xfs_cksum.h" |
36 | #include "xfs_log.h" | ||
36 | 37 | ||
37 | /* | 38 | /* |
38 | * Local function declarations. | 39 | * Local function declarations. |
@@ -164,6 +165,8 @@ xfs_dir3_leaf_verify( | |||
164 | return false; | 165 | return false; |
165 | if (be64_to_cpu(leaf3->info.blkno) != bp->b_bn) | 166 | if (be64_to_cpu(leaf3->info.blkno) != bp->b_bn) |
166 | return false; | 167 | return false; |
168 | if (!xfs_log_check_lsn(mp, be64_to_cpu(leaf3->info.lsn))) | ||
169 | return false; | ||
167 | } else { | 170 | } else { |
168 | if (leaf->hdr.info.magic != cpu_to_be16(magic)) | 171 | if (leaf->hdr.info.magic != cpu_to_be16(magic)) |
169 | return false; | 172 | return false; |
diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c index cc28e924545b..70b0cb2fd556 100644 --- a/fs/xfs/libxfs/xfs_dir2_node.c +++ b/fs/xfs/libxfs/xfs_dir2_node.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include "xfs_trans.h" | 33 | #include "xfs_trans.h" |
34 | #include "xfs_buf_item.h" | 34 | #include "xfs_buf_item.h" |
35 | #include "xfs_cksum.h" | 35 | #include "xfs_cksum.h" |
36 | #include "xfs_log.h" | ||
36 | 37 | ||
37 | /* | 38 | /* |
38 | * Function declarations. | 39 | * Function declarations. |
@@ -97,6 +98,8 @@ xfs_dir3_free_verify( | |||
97 | return false; | 98 | return false; |
98 | if (be64_to_cpu(hdr3->blkno) != bp->b_bn) | 99 | if (be64_to_cpu(hdr3->blkno) != bp->b_bn) |
99 | return false; | 100 | return false; |
101 | if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->lsn))) | ||
102 | return false; | ||
100 | } else { | 103 | } else { |
101 | if (hdr->magic != cpu_to_be32(XFS_DIR2_FREE_MAGIC)) | 104 | if (hdr->magic != cpu_to_be32(XFS_DIR2_FREE_MAGIC)) |
102 | return false; | 105 | return false; |
diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c index 54deb2d12ac6..70c1db99f6a7 100644 --- a/fs/xfs/libxfs/xfs_ialloc.c +++ b/fs/xfs/libxfs/xfs_ialloc.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include "xfs_icreate_item.h" | 38 | #include "xfs_icreate_item.h" |
39 | #include "xfs_icache.h" | 39 | #include "xfs_icache.h" |
40 | #include "xfs_trace.h" | 40 | #include "xfs_trace.h" |
41 | #include "xfs_log.h" | ||
41 | 42 | ||
42 | 43 | ||
43 | /* | 44 | /* |
@@ -2500,9 +2501,14 @@ xfs_agi_verify( | |||
2500 | struct xfs_mount *mp = bp->b_target->bt_mount; | 2501 | struct xfs_mount *mp = bp->b_target->bt_mount; |
2501 | struct xfs_agi *agi = XFS_BUF_TO_AGI(bp); | 2502 | struct xfs_agi *agi = XFS_BUF_TO_AGI(bp); |
2502 | 2503 | ||
2503 | if (xfs_sb_version_hascrc(&mp->m_sb) && | 2504 | if (xfs_sb_version_hascrc(&mp->m_sb)) { |
2504 | !uuid_equal(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid)) | 2505 | if (!uuid_equal(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid)) |
2506 | return false; | ||
2507 | if (!xfs_log_check_lsn(mp, | ||
2508 | be64_to_cpu(XFS_BUF_TO_AGI(bp)->agi_lsn))) | ||
2505 | return false; | 2509 | return false; |
2510 | } | ||
2511 | |||
2506 | /* | 2512 | /* |
2507 | * Validate the magic number of the agi block. | 2513 | * Validate the magic number of the agi block. |
2508 | */ | 2514 | */ |
diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c index 47425140f343..a0b071d881a0 100644 --- a/fs/xfs/libxfs/xfs_sb.c +++ b/fs/xfs/libxfs/xfs_sb.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include "xfs_bmap_btree.h" | 35 | #include "xfs_bmap_btree.h" |
36 | #include "xfs_alloc_btree.h" | 36 | #include "xfs_alloc_btree.h" |
37 | #include "xfs_ialloc_btree.h" | 37 | #include "xfs_ialloc_btree.h" |
38 | #include "xfs_log.h" | ||
38 | 39 | ||
39 | /* | 40 | /* |
40 | * Physical superblock buffer manipulations. Shared with libxfs in userspace. | 41 | * Physical superblock buffer manipulations. Shared with libxfs in userspace. |
@@ -163,6 +164,15 @@ xfs_mount_validate_sb( | |||
163 | "Filesystem can not be safely mounted by this kernel."); | 164 | "Filesystem can not be safely mounted by this kernel."); |
164 | return -EINVAL; | 165 | return -EINVAL; |
165 | } | 166 | } |
167 | } else if (xfs_sb_version_hascrc(sbp)) { | ||
168 | /* | ||
169 | * We can't read verify the sb LSN because the read verifier is | ||
170 | * called before the log is allocated and processed. We know the | ||
171 | * log is set up before write verifier (!check_version) calls, | ||
172 | * so just check it here. | ||
173 | */ | ||
174 | if (!xfs_log_check_lsn(mp, sbp->sb_lsn)) | ||
175 | return -EFSCORRUPTED; | ||
166 | } | 176 | } |
167 | 177 | ||
168 | if (xfs_sb_version_has_pquotino(sbp)) { | 178 | if (xfs_sb_version_has_pquotino(sbp)) { |
diff --git a/fs/xfs/libxfs/xfs_symlink_remote.c b/fs/xfs/libxfs/xfs_symlink_remote.c index 8f8af05b3f13..cb6fd20a4d3d 100644 --- a/fs/xfs/libxfs/xfs_symlink_remote.c +++ b/fs/xfs/libxfs/xfs_symlink_remote.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include "xfs_cksum.h" | 31 | #include "xfs_cksum.h" |
32 | #include "xfs_trans.h" | 32 | #include "xfs_trans.h" |
33 | #include "xfs_buf_item.h" | 33 | #include "xfs_buf_item.h" |
34 | #include "xfs_log.h" | ||
34 | 35 | ||
35 | 36 | ||
36 | /* | 37 | /* |
@@ -60,6 +61,7 @@ xfs_symlink_hdr_set( | |||
60 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | 61 | if (!xfs_sb_version_hascrc(&mp->m_sb)) |
61 | return 0; | 62 | return 0; |
62 | 63 | ||
64 | memset(dsl, 0, sizeof(struct xfs_dsymlink_hdr)); | ||
63 | dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC); | 65 | dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC); |
64 | dsl->sl_offset = cpu_to_be32(offset); | 66 | dsl->sl_offset = cpu_to_be32(offset); |
65 | dsl->sl_bytes = cpu_to_be32(size); | 67 | dsl->sl_bytes = cpu_to_be32(size); |
@@ -116,6 +118,8 @@ xfs_symlink_verify( | |||
116 | return false; | 118 | return false; |
117 | if (dsl->sl_owner == 0) | 119 | if (dsl->sl_owner == 0) |
118 | return false; | 120 | return false; |
121 | if (!xfs_log_check_lsn(mp, be64_to_cpu(dsl->sl_lsn))) | ||
122 | return false; | ||
119 | 123 | ||
120 | return true; | 124 | return true; |
121 | } | 125 | } |
@@ -183,6 +187,7 @@ xfs_symlink_local_to_remote( | |||
183 | if (!xfs_sb_version_hascrc(&mp->m_sb)) { | 187 | if (!xfs_sb_version_hascrc(&mp->m_sb)) { |
184 | bp->b_ops = NULL; | 188 | bp->b_ops = NULL; |
185 | memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes); | 189 | memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes); |
190 | xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1); | ||
186 | return; | 191 | return; |
187 | } | 192 | } |
188 | 193 | ||
@@ -198,4 +203,6 @@ xfs_symlink_local_to_remote( | |||
198 | buf = bp->b_addr; | 203 | buf = bp->b_addr; |
199 | buf += xfs_symlink_hdr_set(mp, ip->i_ino, 0, ifp->if_bytes, bp); | 204 | buf += xfs_symlink_hdr_set(mp, ip->i_ino, 0, ifp->if_bytes, bp); |
200 | memcpy(buf, ifp->if_u1.if_data, ifp->if_bytes); | 205 | memcpy(buf, ifp->if_u1.if_data, ifp->if_bytes); |
206 | xfs_trans_log_buf(tp, bp, 0, sizeof(struct xfs_dsymlink_hdr) + | ||
207 | ifp->if_bytes - 1); | ||
201 | } | 208 | } |
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c index 3bf4ad0d19e4..eca325e42261 100644 --- a/fs/xfs/xfs_bmap_util.c +++ b/fs/xfs/xfs_bmap_util.c | |||
@@ -1027,7 +1027,7 @@ xfs_alloc_file_space( | |||
1027 | xfs_bmap_init(&free_list, &firstfsb); | 1027 | xfs_bmap_init(&free_list, &firstfsb); |
1028 | error = xfs_bmapi_write(tp, ip, startoffset_fsb, | 1028 | error = xfs_bmapi_write(tp, ip, startoffset_fsb, |
1029 | allocatesize_fsb, alloc_type, &firstfsb, | 1029 | allocatesize_fsb, alloc_type, &firstfsb, |
1030 | 0, imapp, &nimaps, &free_list); | 1030 | resblks, imapp, &nimaps, &free_list); |
1031 | if (error) { | 1031 | if (error) { |
1032 | goto error0; | 1032 | goto error0; |
1033 | } | 1033 | } |
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index dca69c6711b2..4a988d76d713 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c | |||
@@ -202,8 +202,8 @@ xfs_iomap_write_direct( | |||
202 | xfs_bmap_init(&free_list, &firstfsb); | 202 | xfs_bmap_init(&free_list, &firstfsb); |
203 | nimaps = 1; | 203 | nimaps = 1; |
204 | error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb, | 204 | error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb, |
205 | XFS_BMAPI_PREALLOC, &firstfsb, 0, | 205 | XFS_BMAPI_PREALLOC, &firstfsb, resblks, imap, |
206 | imap, &nimaps, &free_list); | 206 | &nimaps, &free_list); |
207 | if (error) | 207 | if (error) |
208 | goto out_bmap_cancel; | 208 | goto out_bmap_cancel; |
209 | 209 | ||
@@ -750,9 +750,9 @@ xfs_iomap_write_allocate( | |||
750 | * pointer that the caller gave to us. | 750 | * pointer that the caller gave to us. |
751 | */ | 751 | */ |
752 | error = xfs_bmapi_write(tp, ip, map_start_fsb, | 752 | error = xfs_bmapi_write(tp, ip, map_start_fsb, |
753 | count_fsb, 0, | 753 | count_fsb, 0, &first_block, |
754 | &first_block, 1, | 754 | nres, imap, &nimaps, |
755 | imap, &nimaps, &free_list); | 755 | &free_list); |
756 | if (error) | 756 | if (error) |
757 | goto trans_cancel; | 757 | goto trans_cancel; |
758 | 758 | ||
@@ -866,8 +866,8 @@ xfs_iomap_write_unwritten( | |||
866 | xfs_bmap_init(&free_list, &firstfsb); | 866 | xfs_bmap_init(&free_list, &firstfsb); |
867 | nimaps = 1; | 867 | nimaps = 1; |
868 | error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb, | 868 | error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb, |
869 | XFS_BMAPI_CONVERT, &firstfsb, | 869 | XFS_BMAPI_CONVERT, &firstfsb, resblks, |
870 | 1, &imap, &nimaps, &free_list); | 870 | &imap, &nimaps, &free_list); |
871 | if (error) | 871 | if (error) |
872 | goto error_on_bmapi_transaction; | 872 | goto error_on_bmapi_transaction; |
873 | 873 | ||
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index 401252360a62..f52c72a1a06f 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c | |||
@@ -2422,11 +2422,20 @@ xlog_write( | |||
2422 | &partial_copy_len); | 2422 | &partial_copy_len); |
2423 | xlog_verify_dest_ptr(log, ptr); | 2423 | xlog_verify_dest_ptr(log, ptr); |
2424 | 2424 | ||
2425 | /* copy region */ | 2425 | /* |
2426 | * Copy region. | ||
2427 | * | ||
2428 | * Unmount records just log an opheader, so can have | ||
2429 | * empty payloads with no data region to copy. Hence we | ||
2430 | * only copy the payload if the vector says it has data | ||
2431 | * to copy. | ||
2432 | */ | ||
2426 | ASSERT(copy_len >= 0); | 2433 | ASSERT(copy_len >= 0); |
2427 | memcpy(ptr, reg->i_addr + copy_off, copy_len); | 2434 | if (copy_len > 0) { |
2428 | xlog_write_adv_cnt(&ptr, &len, &log_offset, copy_len); | 2435 | memcpy(ptr, reg->i_addr + copy_off, copy_len); |
2429 | 2436 | xlog_write_adv_cnt(&ptr, &len, &log_offset, | |
2437 | copy_len); | ||
2438 | } | ||
2430 | copy_len += start_rec_copy + sizeof(xlog_op_header_t); | 2439 | copy_len += start_rec_copy + sizeof(xlog_op_header_t); |
2431 | record_cnt++; | 2440 | record_cnt++; |
2432 | data_cnt += contwr ? copy_len : 0; | 2441 | data_cnt += contwr ? copy_len : 0; |
@@ -3165,11 +3174,19 @@ xlog_state_switch_iclogs( | |||
3165 | } | 3174 | } |
3166 | 3175 | ||
3167 | if (log->l_curr_block >= log->l_logBBsize) { | 3176 | if (log->l_curr_block >= log->l_logBBsize) { |
3177 | /* | ||
3178 | * Rewind the current block before the cycle is bumped to make | ||
3179 | * sure that the combined LSN never transiently moves forward | ||
3180 | * when the log wraps to the next cycle. This is to support the | ||
3181 | * unlocked sample of these fields from xlog_valid_lsn(). Most | ||
3182 | * other cases should acquire l_icloglock. | ||
3183 | */ | ||
3184 | log->l_curr_block -= log->l_logBBsize; | ||
3185 | ASSERT(log->l_curr_block >= 0); | ||
3186 | smp_wmb(); | ||
3168 | log->l_curr_cycle++; | 3187 | log->l_curr_cycle++; |
3169 | if (log->l_curr_cycle == XLOG_HEADER_MAGIC_NUM) | 3188 | if (log->l_curr_cycle == XLOG_HEADER_MAGIC_NUM) |
3170 | log->l_curr_cycle++; | 3189 | log->l_curr_cycle++; |
3171 | log->l_curr_block -= log->l_logBBsize; | ||
3172 | ASSERT(log->l_curr_block >= 0); | ||
3173 | } | 3190 | } |
3174 | ASSERT(iclog == log->l_iclog); | 3191 | ASSERT(iclog == log->l_iclog); |
3175 | log->l_iclog = iclog->ic_next; | 3192 | log->l_iclog = iclog->ic_next; |
@@ -4023,3 +4040,45 @@ xlog_iclogs_empty( | |||
4023 | return 1; | 4040 | return 1; |
4024 | } | 4041 | } |
4025 | 4042 | ||
4043 | /* | ||
4044 | * Verify that an LSN stamped into a piece of metadata is valid. This is | ||
4045 | * intended for use in read verifiers on v5 superblocks. | ||
4046 | */ | ||
4047 | bool | ||
4048 | xfs_log_check_lsn( | ||
4049 | struct xfs_mount *mp, | ||
4050 | xfs_lsn_t lsn) | ||
4051 | { | ||
4052 | struct xlog *log = mp->m_log; | ||
4053 | bool valid; | ||
4054 | |||
4055 | /* | ||
4056 | * norecovery mode skips mount-time log processing and unconditionally | ||
4057 | * resets the in-core LSN. We can't validate in this mode, but | ||
4058 | * modifications are not allowed anyways so just return true. | ||
4059 | */ | ||
4060 | if (mp->m_flags & XFS_MOUNT_NORECOVERY) | ||
4061 | return true; | ||
4062 | |||
4063 | /* | ||
4064 | * Some metadata LSNs are initialized to NULL (e.g., the agfl). This is | ||
4065 | * handled by recovery and thus safe to ignore here. | ||
4066 | */ | ||
4067 | if (lsn == NULLCOMMITLSN) | ||
4068 | return true; | ||
4069 | |||
4070 | valid = xlog_valid_lsn(mp->m_log, lsn); | ||
4071 | |||
4072 | /* warn the user about what's gone wrong before verifier failure */ | ||
4073 | if (!valid) { | ||
4074 | spin_lock(&log->l_icloglock); | ||
4075 | xfs_warn(mp, | ||
4076 | "Corruption warning: Metadata has LSN (%d:%d) ahead of current LSN (%d:%d). " | ||
4077 | "Please unmount and run xfs_repair (>= v4.3) to resolve.", | ||
4078 | CYCLE_LSN(lsn), BLOCK_LSN(lsn), | ||
4079 | log->l_curr_cycle, log->l_curr_block); | ||
4080 | spin_unlock(&log->l_icloglock); | ||
4081 | } | ||
4082 | |||
4083 | return valid; | ||
4084 | } | ||
diff --git a/fs/xfs/xfs_log.h b/fs/xfs/xfs_log.h index 09d91d3166cd..aa533a7d50f2 100644 --- a/fs/xfs/xfs_log.h +++ b/fs/xfs/xfs_log.h | |||
@@ -181,5 +181,6 @@ bool xfs_log_item_in_current_chkpt(struct xfs_log_item *lip); | |||
181 | void xfs_log_work_queue(struct xfs_mount *mp); | 181 | void xfs_log_work_queue(struct xfs_mount *mp); |
182 | void xfs_log_worker(struct work_struct *work); | 182 | void xfs_log_worker(struct work_struct *work); |
183 | void xfs_log_quiesce(struct xfs_mount *mp); | 183 | void xfs_log_quiesce(struct xfs_mount *mp); |
184 | bool xfs_log_check_lsn(struct xfs_mount *, xfs_lsn_t); | ||
184 | 185 | ||
185 | #endif /* __XFS_LOG_H__ */ | 186 | #endif /* __XFS_LOG_H__ */ |
diff --git a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h index 950f3f94720c..8daba7491b13 100644 --- a/fs/xfs/xfs_log_priv.h +++ b/fs/xfs/xfs_log_priv.h | |||
@@ -560,4 +560,55 @@ static inline void xlog_wait(wait_queue_head_t *wq, spinlock_t *lock) | |||
560 | remove_wait_queue(wq, &wait); | 560 | remove_wait_queue(wq, &wait); |
561 | } | 561 | } |
562 | 562 | ||
563 | /* | ||
564 | * The LSN is valid so long as it is behind the current LSN. If it isn't, this | ||
565 | * means that the next log record that includes this metadata could have a | ||
566 | * smaller LSN. In turn, this means that the modification in the log would not | ||
567 | * replay. | ||
568 | */ | ||
569 | static inline bool | ||
570 | xlog_valid_lsn( | ||
571 | struct xlog *log, | ||
572 | xfs_lsn_t lsn) | ||
573 | { | ||
574 | int cur_cycle; | ||
575 | int cur_block; | ||
576 | bool valid = true; | ||
577 | |||
578 | /* | ||
579 | * First, sample the current lsn without locking to avoid added | ||
580 | * contention from metadata I/O. The current cycle and block are updated | ||
581 | * (in xlog_state_switch_iclogs()) and read here in a particular order | ||
582 | * to avoid false negatives (e.g., thinking the metadata LSN is valid | ||
583 | * when it is not). | ||
584 | * | ||
585 | * The current block is always rewound before the cycle is bumped in | ||
586 | * xlog_state_switch_iclogs() to ensure the current LSN is never seen in | ||
587 | * a transiently forward state. Instead, we can see the LSN in a | ||
588 | * transiently behind state if we happen to race with a cycle wrap. | ||
589 | */ | ||
590 | cur_cycle = ACCESS_ONCE(log->l_curr_cycle); | ||
591 | smp_rmb(); | ||
592 | cur_block = ACCESS_ONCE(log->l_curr_block); | ||
593 | |||
594 | if ((CYCLE_LSN(lsn) > cur_cycle) || | ||
595 | (CYCLE_LSN(lsn) == cur_cycle && BLOCK_LSN(lsn) > cur_block)) { | ||
596 | /* | ||
597 | * If the metadata LSN appears invalid, it's possible the check | ||
598 | * above raced with a wrap to the next log cycle. Grab the lock | ||
599 | * to check for sure. | ||
600 | */ | ||
601 | spin_lock(&log->l_icloglock); | ||
602 | cur_cycle = log->l_curr_cycle; | ||
603 | cur_block = log->l_curr_block; | ||
604 | spin_unlock(&log->l_icloglock); | ||
605 | |||
606 | if ((CYCLE_LSN(lsn) > cur_cycle) || | ||
607 | (CYCLE_LSN(lsn) == cur_cycle && BLOCK_LSN(lsn) > cur_block)) | ||
608 | valid = false; | ||
609 | } | ||
610 | |||
611 | return valid; | ||
612 | } | ||
613 | |||
563 | #endif /* __XFS_LOG_PRIV_H__ */ | 614 | #endif /* __XFS_LOG_PRIV_H__ */ |
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 512a0945d52a..f8f1363dc045 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c | |||
@@ -4609,9 +4609,19 @@ xlog_recover( | |||
4609 | int error; | 4609 | int error; |
4610 | 4610 | ||
4611 | /* find the tail of the log */ | 4611 | /* find the tail of the log */ |
4612 | if ((error = xlog_find_tail(log, &head_blk, &tail_blk))) | 4612 | error = xlog_find_tail(log, &head_blk, &tail_blk); |
4613 | if (error) | ||
4613 | return error; | 4614 | return error; |
4614 | 4615 | ||
4616 | /* | ||
4617 | * The superblock was read before the log was available and thus the LSN | ||
4618 | * could not be verified. Check the superblock LSN against the current | ||
4619 | * LSN now that it's known. | ||
4620 | */ | ||
4621 | if (xfs_sb_version_hascrc(&log->l_mp->m_sb) && | ||
4622 | !xfs_log_check_lsn(log->l_mp, log->l_mp->m_sb.sb_lsn)) | ||
4623 | return -EINVAL; | ||
4624 | |||
4615 | if (tail_blk != head_blk) { | 4625 | if (tail_blk != head_blk) { |
4616 | /* There used to be a comment here: | 4626 | /* There used to be a comment here: |
4617 | * | 4627 | * |