aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/libxfs/xfs_alloc.c12
-rw-r--r--fs/xfs/libxfs/xfs_attr_leaf.c3
-rw-r--r--fs/xfs/libxfs/xfs_bmap.c10
-rw-r--r--fs/xfs/libxfs/xfs_btree.c17
-rw-r--r--fs/xfs/libxfs/xfs_da_btree.c4
-rw-r--r--fs/xfs/libxfs/xfs_dir2_block.c3
-rw-r--r--fs/xfs/libxfs/xfs_dir2_data.c3
-rw-r--r--fs/xfs/libxfs/xfs_dir2_leaf.c3
-rw-r--r--fs/xfs/libxfs/xfs_dir2_node.c3
-rw-r--r--fs/xfs/libxfs/xfs_ialloc.c10
-rw-r--r--fs/xfs/libxfs/xfs_sb.c10
-rw-r--r--fs/xfs/libxfs/xfs_symlink_remote.c7
-rw-r--r--fs/xfs/xfs_bmap_util.c2
-rw-r--r--fs/xfs/xfs_iomap.c14
-rw-r--r--fs/xfs/xfs_log.c71
-rw-r--r--fs/xfs/xfs_log.h1
-rw-r--r--fs/xfs/xfs_log_priv.h51
-rw-r--r--fs/xfs/xfs_log_recover.c12
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
488static void 490static 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
243xfs_btree_lblock_verify_crc( 244xfs_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
275xfs_btree_sblock_verify_crc( 282xfs_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 */
4047bool
4048xfs_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);
181void xfs_log_work_queue(struct xfs_mount *mp); 181void xfs_log_work_queue(struct xfs_mount *mp);
182void xfs_log_worker(struct work_struct *work); 182void xfs_log_worker(struct work_struct *work);
183void xfs_log_quiesce(struct xfs_mount *mp); 183void xfs_log_quiesce(struct xfs_mount *mp);
184bool 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 */
569static inline bool
570xlog_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 *