diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/xfs/xfs_log_recover.c | 42 |
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. |