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
commiteed6b462fb2a2661a416c227be6498b0ea2a7aab (patch)
treede8bf906df9dd9766905fa3c042a347ea4def7d0 /fs/xfs
parent6528250b712102a7481c28db535ef251459d1868 (diff)
xfs: refactor log record start detection into a new helper
As part of the head/tail discovery process, log recovery locates the head block and then reverse seeks to find the start of the last active record in the log. This is non-trivial as the record itself could have wrapped around the end of the physical log. Log recovery torn write detection potentially needs to walk further behind the last record in the log, as multiple log I/Os can be in-flight at one time during a crash event. Therefore, refactor the reverse log record header search mechanism into a new helper that supports the ability to seek past an arbitrary number of log records (or until the tail is hit). Update the head/tail search mechanism to call the new helper, but otherwise there is no change in log recovery behavior. 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.c118
1 files changed, 83 insertions, 35 deletions
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 1be259044096..423c36dbcdea 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -868,6 +868,79 @@ validate_head:
868} 868}
869 869
870/* 870/*
871 * Seek backwards in the log for log record headers.
872 *
873 * Given a starting log block, walk backwards until we find the provided number
874 * of records or hit the provided tail block. The return value is the number of
875 * records encountered or a negative error code. The log block and buffer
876 * pointer of the last record seen are returned in rblk and rhead respectively.
877 */
878STATIC int
879xlog_rseek_logrec_hdr(
880 struct xlog *log,
881 xfs_daddr_t head_blk,
882 xfs_daddr_t tail_blk,
883 int count,
884 struct xfs_buf *bp,
885 xfs_daddr_t *rblk,
886 struct xlog_rec_header **rhead,
887 bool *wrapped)
888{
889 int i;
890 int error;
891 int found = 0;
892 char *offset = NULL;
893 xfs_daddr_t end_blk;
894
895 *wrapped = false;
896
897 /*
898 * Walk backwards from the head block until we hit the tail or the first
899 * block in the log.
900 */
901 end_blk = head_blk > tail_blk ? tail_blk : 0;
902 for (i = (int) head_blk - 1; i >= end_blk; i--) {
903 error = xlog_bread(log, i, 1, bp, &offset);
904 if (error)
905 goto out_error;
906
907 if (*(__be32 *) offset == cpu_to_be32(XLOG_HEADER_MAGIC_NUM)) {
908 *rblk = i;
909 *rhead = (struct xlog_rec_header *) offset;
910 if (++found == count)
911 break;
912 }
913 }
914
915 /*
916 * If we haven't hit the tail block or the log record header count,
917 * start looking again from the end of the physical log. Note that
918 * callers can pass head == tail if the tail is not yet known.
919 */
920 if (tail_blk >= head_blk && found != count) {
921 for (i = log->l_logBBsize - 1; i >= (int) tail_blk; i--) {
922 error = xlog_bread(log, i, 1, bp, &offset);
923 if (error)
924 goto out_error;
925
926 if (*(__be32 *)offset ==
927 cpu_to_be32(XLOG_HEADER_MAGIC_NUM)) {
928 *wrapped = true;
929 *rblk = i;
930 *rhead = (struct xlog_rec_header *) offset;
931 if (++found == count)
932 break;
933 }
934 }
935 }
936
937 return found;
938
939out_error:
940 return error;
941}
942
943/*
871 * Find the sync block number or the tail of the log. 944 * Find the sync block number or the tail of the log.
872 * 945 *
873 * This will be the block number of the last record to have its 946 * This will be the block number of the last record to have its
@@ -898,8 +971,7 @@ xlog_find_tail(
898 xfs_daddr_t after_umount_blk; 971 xfs_daddr_t after_umount_blk;
899 xfs_lsn_t tail_lsn; 972 xfs_lsn_t tail_lsn;
900 int hblks; 973 int hblks;
901 974 bool wrapped = false;
902 found = 0;
903 975
904 /* 976 /*
905 * Find previous log record 977 * Find previous log record
@@ -923,37 +995,16 @@ xlog_find_tail(
923 } 995 }
924 996
925 /* 997 /*
926 * Search backwards looking for log record header block 998 * Search backwards through the log looking for the log record header
999 * block. This wraps all the way back around to the head so something is
1000 * seriously wrong if we can't find it.
927 */ 1001 */
928 ASSERT(*head_blk < INT_MAX); 1002 ASSERT(*head_blk < INT_MAX);
929 for (i = (int)(*head_blk) - 1; i >= 0; i--) { 1003 found = xlog_rseek_logrec_hdr(log, *head_blk, *head_blk, 1, bp, &i,
930 error = xlog_bread(log, i, 1, bp, &offset); 1004 &rhead, &wrapped);
931 if (error) 1005 if (found < 0) {
932 goto done; 1006 error = found;
933 1007 goto done;
934 if (*(__be32 *)offset == cpu_to_be32(XLOG_HEADER_MAGIC_NUM)) {
935 found = 1;
936 break;
937 }
938 }
939 /*
940 * If we haven't found the log record header block, start looking
941 * again from the end of the physical log. XXXmiken: There should be
942 * a check here to make sure we didn't search more than N blocks in
943 * the previous code.
944 */
945 if (!found) {
946 for (i = log->l_logBBsize - 1; i >= (int)(*head_blk); i--) {
947 error = xlog_bread(log, i, 1, bp, &offset);
948 if (error)
949 goto done;
950
951 if (*(__be32 *)offset ==
952 cpu_to_be32(XLOG_HEADER_MAGIC_NUM)) {
953 found = 2;
954 break;
955 }
956 }
957 } 1008 }
958 if (!found) { 1009 if (!found) {
959 xfs_warn(log->l_mp, "%s: couldn't find sync record", __func__); 1010 xfs_warn(log->l_mp, "%s: couldn't find sync record", __func__);
@@ -961,9 +1012,6 @@ xlog_find_tail(
961 ASSERT(0); 1012 ASSERT(0);
962 return -EIO; 1013 return -EIO;
963 } 1014 }
964
965 /* find blk_no of tail of log */
966 rhead = (xlog_rec_header_t *)offset;
967 *tail_blk = BLOCK_LSN(be64_to_cpu(rhead->h_tail_lsn)); 1015 *tail_blk = BLOCK_LSN(be64_to_cpu(rhead->h_tail_lsn));
968 1016
969 /* 1017 /*
@@ -979,7 +1027,7 @@ xlog_find_tail(
979 log->l_prev_block = i; 1027 log->l_prev_block = i;
980 log->l_curr_block = (int)*head_blk; 1028 log->l_curr_block = (int)*head_blk;
981 log->l_curr_cycle = be32_to_cpu(rhead->h_cycle); 1029 log->l_curr_cycle = be32_to_cpu(rhead->h_cycle);
982 if (found == 2) 1030 if (wrapped)
983 log->l_curr_cycle++; 1031 log->l_curr_cycle++;
984 atomic64_set(&log->l_tail_lsn, be64_to_cpu(rhead->h_tail_lsn)); 1032 atomic64_set(&log->l_tail_lsn, be64_to_cpu(rhead->h_tail_lsn));
985 atomic64_set(&log->l_last_sync_lsn, be64_to_cpu(rhead->h_lsn)); 1033 atomic64_set(&log->l_last_sync_lsn, be64_to_cpu(rhead->h_lsn));