aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorBrian Foster <bfoster@redhat.com>2016-03-06 16:22:22 -0500
committerDave Chinner <david@fromorbit.com>2016-03-06 16:22:22 -0500
commit7f6aff3a29b08fc4234c8136eb1ac31b4897522c (patch)
tree5f30fdc12151acff05a50dafee1f885cbf425b3a /fs
parent717bc0ebca0bce9cb3edfc31b49b384a1d55db1c (diff)
xfs: only run torn log write detection on dirty logs
XFS uses CRC verification over a sub-range of the head of the log to detect and handle torn writes. This torn log write detection currently runs unconditionally at mount time, regardless of whether the log is dirty or clean. This is problematic in cases where a filesystem might end up being moved across different, incompatible (i.e., opposite byte-endianness) architectures. The problem lies in the fact that log data is not necessarily written in an architecture independent format. For example, certain bits of data are written in native endian format. Further, the size of certain log data structures differs (i.e., struct xlog_rec_header) depending on the word size of the cpu. This leads to false positive crc verification errors and ultimately failed mounts when a cleanly unmounted filesystem is mounted on a system with an incompatible architecture from data that was written near the head of the log. Update the log head/tail discovery code to run torn write detection only when the log is not clean. This means something other than an unmount record resides at the head of the log and log recovery is imminent. It is a requirement to run log recovery on the same type of host that had written the content of the dirty log and therefore CRC failures are legitimate corruptions in that scenario. Reported-by: Jan Beulich <JBeulich@suse.com> Tested-by: Jan Beulich <JBeulich@suse.com> 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')
-rw-r--r--fs/xfs/xfs_log_recover.c42
1 files changed, 31 insertions, 11 deletions
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 9ac8aa8dc38c..e7aa82faa3d5 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -1376,17 +1376,6 @@ xlog_find_tail(
1376 *tail_blk = BLOCK_LSN(be64_to_cpu(rhead->h_tail_lsn)); 1376 *tail_blk = BLOCK_LSN(be64_to_cpu(rhead->h_tail_lsn));
1377 1377
1378 /* 1378 /*
1379 * Trim the head block back to skip over torn records. We can have
1380 * multiple log I/Os in flight at any time, so we assume CRC failures
1381 * back through the previous several records are torn writes and skip
1382 * them.
1383 */
1384 error = xlog_verify_head(log, head_blk, tail_blk, bp, &rhead_blk,
1385 &rhead, &wrapped);
1386 if (error)
1387 goto done;
1388
1389 /*
1390 * Set the log state based on the current head record. 1379 * Set the log state based on the current head record.
1391 */ 1380 */
1392 xlog_set_state(log, *head_blk, rhead, rhead_blk, wrapped); 1381 xlog_set_state(log, *head_blk, rhead, rhead_blk, wrapped);
@@ -1402,6 +1391,37 @@ xlog_find_tail(
1402 goto done; 1391 goto done;
1403 1392
1404 /* 1393 /*
1394 * Verify the log head if the log is not clean (e.g., we have anything
1395 * but an unmount record at the head). This uses CRC verification to
1396 * detect and trim torn writes. If discovered, CRC failures are
1397 * considered torn writes and the log head is trimmed accordingly.
1398 *
1399 * Note that we can only run CRC verification when the log is dirty
1400 * because there's no guarantee that the log data behind an unmount
1401 * record is compatible with the current architecture.
1402 */
1403 if (!clean) {
1404 xfs_daddr_t orig_head = *head_blk;
1405
1406 error = xlog_verify_head(log, head_blk, tail_blk, bp,
1407 &rhead_blk, &rhead, &wrapped);
1408 if (error)
1409 goto done;
1410
1411 /* update in-core state again if the head changed */
1412 if (*head_blk != orig_head) {
1413 xlog_set_state(log, *head_blk, rhead, rhead_blk,
1414 wrapped);
1415 tail_lsn = atomic64_read(&log->l_tail_lsn);
1416 error = xlog_check_unmount_rec(log, head_blk, tail_blk,
1417 rhead, rhead_blk, bp,
1418 &clean);
1419 if (error)
1420 goto done;
1421 }
1422 }
1423
1424 /*
1405 * Note that the unmount was clean. If the unmount was not clean, we 1425 * Note that the unmount was clean. If the unmount was not clean, we
1406 * need to know this to rebuild the superblock counters from the perag 1426 * need to know this to rebuild the superblock counters from the perag
1407 * headers if we have a filesystem using non-persistent counters. 1427 * headers if we have a filesystem using non-persistent counters.