aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorBrian Foster <bfoster@redhat.com>2016-01-03 23:55:10 -0500
committerDave Chinner <david@fromorbit.com>2016-01-03 23:55:10 -0500
commitd7f37692e38798797d415153bc186afb2bbac645 (patch)
treebf5ec274e20b3aacee19bb29871741c2d8fd69c1 /fs/xfs
parentb94fb2d1780d7cd9d55b21e2bb879a54ed3074cc (diff)
xfs: return start block of first bad log record during recovery
Each log recovery pass walks from the tail block to the head block and processes records appropriately based on the associated log pass type. There are various failure conditions that can occur through this sequence, such as I/O errors, CRC errors, etc. Log torn write detection will perform CRC verification near the head of the log to detect torn writes and trim torn records from the log appropriately. As it is, xlog_do_recovery_pass() only returns an error code in the event of CRC failure, which isn't enough information to trim the head of the log. Update xlog_do_recovery_pass() to optionally return the start block of the associated record when an error occurs. This patch contains no functional changes. Signed-off-by: Brian Foster <bfoster@redhat.com> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/xfs_log_recover.c20
1 files changed, 16 insertions, 4 deletions
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 9ec4bbd28d55..e0318e8a0771 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -4239,10 +4239,12 @@ xlog_do_recovery_pass(
4239 struct xlog *log, 4239 struct xlog *log,
4240 xfs_daddr_t head_blk, 4240 xfs_daddr_t head_blk,
4241 xfs_daddr_t tail_blk, 4241 xfs_daddr_t tail_blk,
4242 int pass) 4242 int pass,
4243 xfs_daddr_t *first_bad) /* out: first bad log rec */
4243{ 4244{
4244 xlog_rec_header_t *rhead; 4245 xlog_rec_header_t *rhead;
4245 xfs_daddr_t blk_no; 4246 xfs_daddr_t blk_no;
4247 xfs_daddr_t rhead_blk;
4246 char *offset; 4248 char *offset;
4247 xfs_buf_t *hbp, *dbp; 4249 xfs_buf_t *hbp, *dbp;
4248 int error = 0, h_size, h_len; 4250 int error = 0, h_size, h_len;
@@ -4251,6 +4253,7 @@ xlog_do_recovery_pass(
4251 struct hlist_head rhash[XLOG_RHASH_SIZE]; 4253 struct hlist_head rhash[XLOG_RHASH_SIZE];
4252 4254
4253 ASSERT(head_blk != tail_blk); 4255 ASSERT(head_blk != tail_blk);
4256 rhead_blk = 0;
4254 4257
4255 /* 4258 /*
4256 * Read the header of the tail block and get the iclog buffer size from 4259 * Read the header of the tail block and get the iclog buffer size from
@@ -4325,7 +4328,7 @@ xlog_do_recovery_pass(
4325 } 4328 }
4326 4329
4327 memset(rhash, 0, sizeof(rhash)); 4330 memset(rhash, 0, sizeof(rhash));
4328 blk_no = tail_blk; 4331 blk_no = rhead_blk = tail_blk;
4329 if (tail_blk > head_blk) { 4332 if (tail_blk > head_blk) {
4330 /* 4333 /*
4331 * Perform recovery around the end of the physical log. 4334 * Perform recovery around the end of the physical log.
@@ -4436,11 +4439,14 @@ xlog_do_recovery_pass(
4436 pass); 4439 pass);
4437 if (error) 4440 if (error)
4438 goto bread_err2; 4441 goto bread_err2;
4442
4439 blk_no += bblks; 4443 blk_no += bblks;
4444 rhead_blk = blk_no;
4440 } 4445 }
4441 4446
4442 ASSERT(blk_no >= log->l_logBBsize); 4447 ASSERT(blk_no >= log->l_logBBsize);
4443 blk_no -= log->l_logBBsize; 4448 blk_no -= log->l_logBBsize;
4449 rhead_blk = blk_no;
4444 } 4450 }
4445 4451
4446 /* read first part of physical log */ 4452 /* read first part of physical log */
@@ -4464,13 +4470,19 @@ xlog_do_recovery_pass(
4464 error = xlog_recover_process(log, rhash, rhead, offset, pass); 4470 error = xlog_recover_process(log, rhash, rhead, offset, pass);
4465 if (error) 4471 if (error)
4466 goto bread_err2; 4472 goto bread_err2;
4473
4467 blk_no += bblks + hblks; 4474 blk_no += bblks + hblks;
4475 rhead_blk = blk_no;
4468 } 4476 }
4469 4477
4470 bread_err2: 4478 bread_err2:
4471 xlog_put_bp(dbp); 4479 xlog_put_bp(dbp);
4472 bread_err1: 4480 bread_err1:
4473 xlog_put_bp(hbp); 4481 xlog_put_bp(hbp);
4482
4483 if (error && first_bad)
4484 *first_bad = rhead_blk;
4485
4474 return error; 4486 return error;
4475} 4487}
4476 4488
@@ -4508,7 +4520,7 @@ xlog_do_log_recovery(
4508 INIT_LIST_HEAD(&log->l_buf_cancel_table[i]); 4520 INIT_LIST_HEAD(&log->l_buf_cancel_table[i]);
4509 4521
4510 error = xlog_do_recovery_pass(log, head_blk, tail_blk, 4522 error = xlog_do_recovery_pass(log, head_blk, tail_blk,
4511 XLOG_RECOVER_PASS1); 4523 XLOG_RECOVER_PASS1, NULL);
4512 if (error != 0) { 4524 if (error != 0) {
4513 kmem_free(log->l_buf_cancel_table); 4525 kmem_free(log->l_buf_cancel_table);
4514 log->l_buf_cancel_table = NULL; 4526 log->l_buf_cancel_table = NULL;
@@ -4519,7 +4531,7 @@ xlog_do_log_recovery(
4519 * When it is complete free the table of buf cancel items. 4531 * When it is complete free the table of buf cancel items.
4520 */ 4532 */
4521 error = xlog_do_recovery_pass(log, head_blk, tail_blk, 4533 error = xlog_do_recovery_pass(log, head_blk, tail_blk,
4522 XLOG_RECOVER_PASS2); 4534 XLOG_RECOVER_PASS2, NULL);
4523#ifdef DEBUG 4535#ifdef DEBUG
4524 if (!error) { 4536 if (!error) {
4525 int i; 4537 int i;