diff options
-rw-r--r-- | fs/xfs/xfs_log_recover.c | 118 |
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 | */ | ||
878 | STATIC int | ||
879 | xlog_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 | |||
939 | out_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)); |