|
@@ -867,6 +867,79 @@ validate_head:
|
|
|
return error;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Seek backwards in the log for log record headers.
|
|
|
+ *
|
|
|
+ * Given a starting log block, walk backwards until we find the provided number
|
|
|
+ * of records or hit the provided tail block. The return value is the number of
|
|
|
+ * records encountered or a negative error code. The log block and buffer
|
|
|
+ * pointer of the last record seen are returned in rblk and rhead respectively.
|
|
|
+ */
|
|
|
+STATIC int
|
|
|
+xlog_rseek_logrec_hdr(
|
|
|
+ struct xlog *log,
|
|
|
+ xfs_daddr_t head_blk,
|
|
|
+ xfs_daddr_t tail_blk,
|
|
|
+ int count,
|
|
|
+ struct xfs_buf *bp,
|
|
|
+ xfs_daddr_t *rblk,
|
|
|
+ struct xlog_rec_header **rhead,
|
|
|
+ bool *wrapped)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ int error;
|
|
|
+ int found = 0;
|
|
|
+ char *offset = NULL;
|
|
|
+ xfs_daddr_t end_blk;
|
|
|
+
|
|
|
+ *wrapped = false;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Walk backwards from the head block until we hit the tail or the first
|
|
|
+ * block in the log.
|
|
|
+ */
|
|
|
+ end_blk = head_blk > tail_blk ? tail_blk : 0;
|
|
|
+ for (i = (int) head_blk - 1; i >= end_blk; i--) {
|
|
|
+ error = xlog_bread(log, i, 1, bp, &offset);
|
|
|
+ if (error)
|
|
|
+ goto out_error;
|
|
|
+
|
|
|
+ if (*(__be32 *) offset == cpu_to_be32(XLOG_HEADER_MAGIC_NUM)) {
|
|
|
+ *rblk = i;
|
|
|
+ *rhead = (struct xlog_rec_header *) offset;
|
|
|
+ if (++found == count)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If we haven't hit the tail block or the log record header count,
|
|
|
+ * start looking again from the end of the physical log. Note that
|
|
|
+ * callers can pass head == tail if the tail is not yet known.
|
|
|
+ */
|
|
|
+ if (tail_blk >= head_blk && found != count) {
|
|
|
+ for (i = log->l_logBBsize - 1; i >= (int) tail_blk; i--) {
|
|
|
+ error = xlog_bread(log, i, 1, bp, &offset);
|
|
|
+ if (error)
|
|
|
+ goto out_error;
|
|
|
+
|
|
|
+ if (*(__be32 *)offset ==
|
|
|
+ cpu_to_be32(XLOG_HEADER_MAGIC_NUM)) {
|
|
|
+ *wrapped = true;
|
|
|
+ *rblk = i;
|
|
|
+ *rhead = (struct xlog_rec_header *) offset;
|
|
|
+ if (++found == count)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return found;
|
|
|
+
|
|
|
+out_error:
|
|
|
+ return error;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Find the sync block number or the tail of the log.
|
|
|
*
|
|
@@ -898,8 +971,7 @@ xlog_find_tail(
|
|
|
xfs_daddr_t after_umount_blk;
|
|
|
xfs_lsn_t tail_lsn;
|
|
|
int hblks;
|
|
|
-
|
|
|
- found = 0;
|
|
|
+ bool wrapped = false;
|
|
|
|
|
|
/*
|
|
|
* Find previous log record
|
|
@@ -923,37 +995,16 @@ xlog_find_tail(
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * Search backwards looking for log record header block
|
|
|
+ * Search backwards through the log looking for the log record header
|
|
|
+ * block. This wraps all the way back around to the head so something is
|
|
|
+ * seriously wrong if we can't find it.
|
|
|
*/
|
|
|
ASSERT(*head_blk < INT_MAX);
|
|
|
- for (i = (int)(*head_blk) - 1; i >= 0; i--) {
|
|
|
- error = xlog_bread(log, i, 1, bp, &offset);
|
|
|
- if (error)
|
|
|
- goto done;
|
|
|
-
|
|
|
- if (*(__be32 *)offset == cpu_to_be32(XLOG_HEADER_MAGIC_NUM)) {
|
|
|
- found = 1;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- /*
|
|
|
- * If we haven't found the log record header block, start looking
|
|
|
- * again from the end of the physical log. XXXmiken: There should be
|
|
|
- * a check here to make sure we didn't search more than N blocks in
|
|
|
- * the previous code.
|
|
|
- */
|
|
|
- if (!found) {
|
|
|
- for (i = log->l_logBBsize - 1; i >= (int)(*head_blk); i--) {
|
|
|
- error = xlog_bread(log, i, 1, bp, &offset);
|
|
|
- if (error)
|
|
|
- goto done;
|
|
|
-
|
|
|
- if (*(__be32 *)offset ==
|
|
|
- cpu_to_be32(XLOG_HEADER_MAGIC_NUM)) {
|
|
|
- found = 2;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
+ found = xlog_rseek_logrec_hdr(log, *head_blk, *head_blk, 1, bp, &i,
|
|
|
+ &rhead, &wrapped);
|
|
|
+ if (found < 0) {
|
|
|
+ error = found;
|
|
|
+ goto done;
|
|
|
}
|
|
|
if (!found) {
|
|
|
xfs_warn(log->l_mp, "%s: couldn't find sync record", __func__);
|
|
@@ -961,9 +1012,6 @@ xlog_find_tail(
|
|
|
ASSERT(0);
|
|
|
return -EIO;
|
|
|
}
|
|
|
-
|
|
|
- /* find blk_no of tail of log */
|
|
|
- rhead = (xlog_rec_header_t *)offset;
|
|
|
*tail_blk = BLOCK_LSN(be64_to_cpu(rhead->h_tail_lsn));
|
|
|
|
|
|
/*
|
|
@@ -979,7 +1027,7 @@ xlog_find_tail(
|
|
|
log->l_prev_block = i;
|
|
|
log->l_curr_block = (int)*head_blk;
|
|
|
log->l_curr_cycle = be32_to_cpu(rhead->h_cycle);
|
|
|
- if (found == 2)
|
|
|
+ if (wrapped)
|
|
|
log->l_curr_cycle++;
|
|
|
atomic64_set(&log->l_tail_lsn, be64_to_cpu(rhead->h_tail_lsn));
|
|
|
atomic64_set(&log->l_last_sync_lsn, be64_to_cpu(rhead->h_lsn));
|