aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorAndy Poling <andy@realbig.com>2009-11-03 12:26:47 -0500
committerAlex Elder <aelder@sgi.com>2009-12-11 16:11:21 -0500
commitfc5bc4c85c45f0bf854404e5736aa8b65720a18d (patch)
treef7938c5a4386a789606654e83f5dbb91367ef507 /fs
parent5ec4fabb02fcb5b4a4154a27e4299af5aa0f87ac (diff)
xfs: Wrapped journal record corruption on read at recovery
Summary of problem: If a journal record wraps at the physical end of the journal, it has to be read in two parts in xlog_do_recovery_pass(): a read at the physical end and a read at the physical beginning. If xlog_bread() has to re-align the first read, the second read request does not take that re-alignment into account. If the first read was re-aligned, the second read over-writes the end of the data from the first read, effectively corrupting it. This can happen either when reading the record header or reading the record data. The first sanity check in xlog_recover_process_data() is to check for a valid clientid, so that is the error reported. Summary of fix: If there was a first read at the physical end, XFS_BUF_PTR() returns where the data was requested to begin. Conversely, because it is the result of xlog_align(), offset indicates where the requested data for the first read actually begins - whether or not xlog_bread() has re-aligned it. Using offset as the base for the calculation of where to place the second read data ensures that it will be correctly placed immediately following the data from the first read instead of sometimes over-writing the end of it. The attached patch has resolved the reported problem of occasional inability to recover the journal (reporting "bad clientid"). Signed-off-by: Andy Poling <andy@realbig.com> Reviewed-by: Alex Elder <aelder@sgi.com> Signed-off-by: Alex Elder <aelder@sgi.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/xfs/xfs_log_recover.c24
1 files changed, 7 insertions, 17 deletions
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index fb17f8226b09..b5b0d8055910 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -3517,7 +3517,7 @@ xlog_do_recovery_pass(
3517{ 3517{
3518 xlog_rec_header_t *rhead; 3518 xlog_rec_header_t *rhead;
3519 xfs_daddr_t blk_no; 3519 xfs_daddr_t blk_no;
3520 xfs_caddr_t bufaddr, offset; 3520 xfs_caddr_t offset;
3521 xfs_buf_t *hbp, *dbp; 3521 xfs_buf_t *hbp, *dbp;
3522 int error = 0, h_size; 3522 int error = 0, h_size;
3523 int bblks, split_bblks; 3523 int bblks, split_bblks;
@@ -3610,7 +3610,7 @@ xlog_do_recovery_pass(
3610 /* 3610 /*
3611 * Check for header wrapping around physical end-of-log 3611 * Check for header wrapping around physical end-of-log
3612 */ 3612 */
3613 offset = NULL; 3613 offset = XFS_BUF_PTR(hbp);
3614 split_hblks = 0; 3614 split_hblks = 0;
3615 wrapped_hblks = 0; 3615 wrapped_hblks = 0;
3616 if (blk_no + hblks <= log->l_logBBsize) { 3616 if (blk_no + hblks <= log->l_logBBsize) {
@@ -3646,9 +3646,8 @@ xlog_do_recovery_pass(
3646 * - order is important. 3646 * - order is important.
3647 */ 3647 */
3648 wrapped_hblks = hblks - split_hblks; 3648 wrapped_hblks = hblks - split_hblks;
3649 bufaddr = XFS_BUF_PTR(hbp);
3650 error = XFS_BUF_SET_PTR(hbp, 3649 error = XFS_BUF_SET_PTR(hbp,
3651 bufaddr + BBTOB(split_hblks), 3650 offset + BBTOB(split_hblks),
3652 BBTOB(hblks - split_hblks)); 3651 BBTOB(hblks - split_hblks));
3653 if (error) 3652 if (error)
3654 goto bread_err2; 3653 goto bread_err2;
@@ -3658,14 +3657,10 @@ xlog_do_recovery_pass(
3658 if (error) 3657 if (error)
3659 goto bread_err2; 3658 goto bread_err2;
3660 3659
3661 error = XFS_BUF_SET_PTR(hbp, bufaddr, 3660 error = XFS_BUF_SET_PTR(hbp, offset,
3662 BBTOB(hblks)); 3661 BBTOB(hblks));
3663 if (error) 3662 if (error)
3664 goto bread_err2; 3663 goto bread_err2;
3665
3666 if (!offset)
3667 offset = xlog_align(log, 0,
3668 wrapped_hblks, hbp);
3669 } 3664 }
3670 rhead = (xlog_rec_header_t *)offset; 3665 rhead = (xlog_rec_header_t *)offset;
3671 error = xlog_valid_rec_header(log, rhead, 3666 error = xlog_valid_rec_header(log, rhead,
@@ -3685,7 +3680,7 @@ xlog_do_recovery_pass(
3685 } else { 3680 } else {
3686 /* This log record is split across the 3681 /* This log record is split across the
3687 * physical end of log */ 3682 * physical end of log */
3688 offset = NULL; 3683 offset = XFS_BUF_PTR(dbp);
3689 split_bblks = 0; 3684 split_bblks = 0;
3690 if (blk_no != log->l_logBBsize) { 3685 if (blk_no != log->l_logBBsize) {
3691 /* some data is before the physical 3686 /* some data is before the physical
@@ -3714,9 +3709,8 @@ xlog_do_recovery_pass(
3714 * _first_, then the log start (LR header end) 3709 * _first_, then the log start (LR header end)
3715 * - order is important. 3710 * - order is important.
3716 */ 3711 */
3717 bufaddr = XFS_BUF_PTR(dbp);
3718 error = XFS_BUF_SET_PTR(dbp, 3712 error = XFS_BUF_SET_PTR(dbp,
3719 bufaddr + BBTOB(split_bblks), 3713 offset + BBTOB(split_bblks),
3720 BBTOB(bblks - split_bblks)); 3714 BBTOB(bblks - split_bblks));
3721 if (error) 3715 if (error)
3722 goto bread_err2; 3716 goto bread_err2;
@@ -3727,13 +3721,9 @@ xlog_do_recovery_pass(
3727 if (error) 3721 if (error)
3728 goto bread_err2; 3722 goto bread_err2;
3729 3723
3730 error = XFS_BUF_SET_PTR(dbp, bufaddr, h_size); 3724 error = XFS_BUF_SET_PTR(dbp, offset, h_size);
3731 if (error) 3725 if (error)
3732 goto bread_err2; 3726 goto bread_err2;
3733
3734 if (!offset)
3735 offset = xlog_align(log, wrapped_hblks,
3736 bblks - split_bblks, dbp);
3737 } 3727 }
3738 xlog_unpack_data(rhead, offset, log); 3728 xlog_unpack_data(rhead, offset, log);
3739 if ((error = xlog_recover_process_data(log, rhash, 3729 if ((error = xlog_recover_process_data(log, rhash,