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
commit65b99a08b350876e8835fc0e7173598165f64dee (patch)
treee8c8b43e553817442a63916cddd9c9cec860ac11 /fs
parent82ff6cc26e98f9bba8e2a10f727e335fa241cc47 (diff)
xfs: refactor unmount record detection into helper
Once the mount sequence has identified the head and tail blocks of the physical log, the record at the head of the log is located and examined for an unmount record to determine if the log is clean. This currently occurs after torn write verification of the head region of the log. This must ultimately be separated from torn write verification and may need to be called again if the log head is walked back due to a torn write (to determine whether the new head record is an unmount record). Separate this logic into a new helper function. This patch does not change behavior. 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.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