aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/xfs/xfs_log_recover.c153
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 */
1206static int
1207xlog_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