diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/xfs/xfs_log_recover.c | 153 |
1 files changed, 93 insertions, 60 deletions
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index c2d04ff8876b..1aae75608453 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c | |||
@@ -1199,6 +1199,84 @@ xlog_verify_head( | |||
1199 | } | 1199 | } |
1200 | 1200 | ||
1201 | /* | 1201 | /* |
1202 | * Check whether the head of the log points to an unmount record. In other | ||
1203 | * words, determine whether the log is clean. If so, update the in-core state | ||
1204 | * appropriately. | ||
1205 | */ | ||
1206 | static int | ||
1207 | xlog_check_unmount_rec( | ||
1208 | struct xlog *log, | ||
1209 | xfs_daddr_t *head_blk, | ||
1210 | xfs_daddr_t *tail_blk, | ||
1211 | struct xlog_rec_header *rhead, | ||
1212 | xfs_daddr_t rhead_blk, | ||
1213 | struct xfs_buf *bp, | ||
1214 | bool *clean) | ||
1215 | { | ||
1216 | struct xlog_op_header *op_head; | ||
1217 | xfs_daddr_t umount_data_blk; | ||
1218 | xfs_daddr_t after_umount_blk; | ||
1219 | int hblks; | ||
1220 | int error; | ||
1221 | char *offset; | ||
1222 | |||
1223 | *clean = false; | ||
1224 | |||
1225 | /* | ||
1226 | * Look for unmount record. If we find it, then we know there was a | ||
1227 | * clean unmount. Since 'i' could be the last block in the physical | ||
1228 | * log, we convert to a log block before comparing to the head_blk. | ||
1229 | * | ||
1230 | * Save the current tail lsn to use to pass to xlog_clear_stale_blocks() | ||
1231 | * below. We won't want to clear the unmount record if there is one, so | ||
1232 | * we pass the lsn of the unmount record rather than the block after it. | ||
1233 | */ | ||
1234 | if (xfs_sb_version_haslogv2(&log->l_mp->m_sb)) { | ||
1235 | int h_size = be32_to_cpu(rhead->h_size); | ||
1236 | int h_version = be32_to_cpu(rhead->h_version); | ||
1237 | |||
1238 | if ((h_version & XLOG_VERSION_2) && | ||
1239 | (h_size > XLOG_HEADER_CYCLE_SIZE)) { | ||
1240 | hblks = h_size / XLOG_HEADER_CYCLE_SIZE; | ||
1241 | if (h_size % XLOG_HEADER_CYCLE_SIZE) | ||
1242 | hblks++; | ||
1243 | } else { | ||
1244 | hblks = 1; | ||
1245 | } | ||
1246 | } else { | ||
1247 | hblks = 1; | ||
1248 | } | ||
1249 | after_umount_blk = rhead_blk + hblks + BTOBB(be32_to_cpu(rhead->h_len)); | ||
1250 | after_umount_blk = do_mod(after_umount_blk, log->l_logBBsize); | ||
1251 | if (*head_blk == after_umount_blk && | ||
1252 | be32_to_cpu(rhead->h_num_logops) == 1) { | ||
1253 | umount_data_blk = rhead_blk + hblks; | ||
1254 | umount_data_blk = do_mod(umount_data_blk, log->l_logBBsize); | ||
1255 | error = xlog_bread(log, umount_data_blk, 1, bp, &offset); | ||
1256 | if (error) | ||
1257 | return error; | ||
1258 | |||
1259 | op_head = (struct xlog_op_header *)offset; | ||
1260 | if (op_head->oh_flags & XLOG_UNMOUNT_TRANS) { | ||
1261 | /* | ||
1262 | * Set tail and last sync so that newly written log | ||
1263 | * records will point recovery to after the current | ||
1264 | * unmount record. | ||
1265 | */ | ||
1266 | xlog_assign_atomic_lsn(&log->l_tail_lsn, | ||
1267 | log->l_curr_cycle, after_umount_blk); | ||
1268 | xlog_assign_atomic_lsn(&log->l_last_sync_lsn, | ||
1269 | log->l_curr_cycle, after_umount_blk); | ||
1270 | *tail_blk = after_umount_blk; | ||
1271 | |||
1272 | *clean = true; | ||
1273 | } | ||
1274 | } | ||
1275 | |||
1276 | return 0; | ||
1277 | } | ||
1278 | |||
1279 | /* | ||
1202 | * Find the sync block number or the tail of the log. | 1280 | * Find the sync block number or the tail of the log. |
1203 | * | 1281 | * |
1204 | * This will be the block number of the last record to have its | 1282 | * This will be the block number of the last record to have its |
@@ -1221,16 +1299,13 @@ xlog_find_tail( | |||
1221 | xfs_daddr_t *tail_blk) | 1299 | xfs_daddr_t *tail_blk) |
1222 | { | 1300 | { |
1223 | xlog_rec_header_t *rhead; | 1301 | xlog_rec_header_t *rhead; |
1224 | xlog_op_header_t *op_head; | ||
1225 | char *offset = NULL; | 1302 | char *offset = NULL; |
1226 | xfs_buf_t *bp; | 1303 | xfs_buf_t *bp; |
1227 | int error; | 1304 | int error; |
1228 | xfs_daddr_t umount_data_blk; | ||
1229 | xfs_daddr_t after_umount_blk; | ||
1230 | xfs_daddr_t rhead_blk; | 1305 | xfs_daddr_t rhead_blk; |
1231 | xfs_lsn_t tail_lsn; | 1306 | xfs_lsn_t tail_lsn; |
1232 | int hblks; | ||
1233 | bool wrapped = false; | 1307 | bool wrapped = false; |
1308 | bool clean = false; | ||
1234 | 1309 | ||
1235 | /* | 1310 | /* |
1236 | * Find previous log record | 1311 | * Find previous log record |
@@ -1301,66 +1376,24 @@ xlog_find_tail( | |||
1301 | BBTOB(log->l_curr_block)); | 1376 | BBTOB(log->l_curr_block)); |
1302 | xlog_assign_grant_head(&log->l_write_head.grant, log->l_curr_cycle, | 1377 | xlog_assign_grant_head(&log->l_write_head.grant, log->l_curr_cycle, |
1303 | BBTOB(log->l_curr_block)); | 1378 | BBTOB(log->l_curr_block)); |
1379 | tail_lsn = atomic64_read(&log->l_tail_lsn); | ||
1304 | 1380 | ||
1305 | /* | 1381 | /* |
1306 | * Look for unmount record. If we find it, then we know there | 1382 | * Look for an unmount record at the head of the log. This sets the log |
1307 | * was a clean unmount. Since 'i' could be the last block in | 1383 | * state to determine whether recovery is necessary. |
1308 | * the physical log, we convert to a log block before comparing | ||
1309 | * to the head_blk. | ||
1310 | * | ||
1311 | * Save the current tail lsn to use to pass to | ||
1312 | * xlog_clear_stale_blocks() below. We won't want to clear the | ||
1313 | * unmount record if there is one, so we pass the lsn of the | ||
1314 | * unmount record rather than the block after it. | ||
1315 | */ | 1384 | */ |
1316 | if (xfs_sb_version_haslogv2(&log->l_mp->m_sb)) { | 1385 | error = xlog_check_unmount_rec(log, head_blk, tail_blk, rhead, |
1317 | int h_size = be32_to_cpu(rhead->h_size); | 1386 | rhead_blk, bp, &clean); |
1318 | int h_version = be32_to_cpu(rhead->h_version); | 1387 | if (error) |
1319 | 1388 | goto done; | |
1320 | if ((h_version & XLOG_VERSION_2) && | ||
1321 | (h_size > XLOG_HEADER_CYCLE_SIZE)) { | ||
1322 | hblks = h_size / XLOG_HEADER_CYCLE_SIZE; | ||
1323 | if (h_size % XLOG_HEADER_CYCLE_SIZE) | ||
1324 | hblks++; | ||
1325 | } else { | ||
1326 | hblks = 1; | ||
1327 | } | ||
1328 | } else { | ||
1329 | hblks = 1; | ||
1330 | } | ||
1331 | after_umount_blk = rhead_blk + hblks + BTOBB(be32_to_cpu(rhead->h_len)); | ||
1332 | after_umount_blk = do_mod(after_umount_blk, log->l_logBBsize); | ||
1333 | tail_lsn = atomic64_read(&log->l_tail_lsn); | ||
1334 | if (*head_blk == after_umount_blk && | ||
1335 | be32_to_cpu(rhead->h_num_logops) == 1) { | ||
1336 | umount_data_blk = rhead_blk + hblks; | ||
1337 | umount_data_blk = do_mod(umount_data_blk, log->l_logBBsize); | ||
1338 | error = xlog_bread(log, umount_data_blk, 1, bp, &offset); | ||
1339 | if (error) | ||
1340 | goto done; | ||
1341 | |||
1342 | op_head = (xlog_op_header_t *)offset; | ||
1343 | if (op_head->oh_flags & XLOG_UNMOUNT_TRANS) { | ||
1344 | /* | ||
1345 | * Set tail and last sync so that newly written | ||
1346 | * log records will point recovery to after the | ||
1347 | * current unmount record. | ||
1348 | */ | ||
1349 | xlog_assign_atomic_lsn(&log->l_tail_lsn, | ||
1350 | log->l_curr_cycle, after_umount_blk); | ||
1351 | xlog_assign_atomic_lsn(&log->l_last_sync_lsn, | ||
1352 | log->l_curr_cycle, after_umount_blk); | ||
1353 | *tail_blk = after_umount_blk; | ||
1354 | 1389 | ||
1355 | /* | 1390 | /* |
1356 | * Note that the unmount was clean. If the unmount | 1391 | * Note that the unmount was clean. If the unmount was not clean, we |
1357 | * was not clean, we need to know this to rebuild the | 1392 | * need to know this to rebuild the superblock counters from the perag |
1358 | * superblock counters from the perag headers if we | 1393 | * headers if we have a filesystem using non-persistent counters. |
1359 | * have a filesystem using non-persistent counters. | 1394 | */ |
1360 | */ | 1395 | if (clean) |
1361 | log->l_mp->m_flags |= XFS_MOUNT_WAS_CLEAN; | 1396 | log->l_mp->m_flags |= XFS_MOUNT_WAS_CLEAN; |
1362 | } | ||
1363 | } | ||
1364 | 1397 | ||
1365 | /* | 1398 | /* |
1366 | * Make sure that there are no blocks in front of the head | 1399 | * Make sure that there are no blocks in front of the head |