aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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));