diff options
| -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. |
