summaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_log.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_log.c')
-rw-r--r--fs/xfs/xfs_log.c20
1 files changed, 18 insertions, 2 deletions
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index a613f008b95f..58699881c100 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -1110,6 +1110,7 @@ xfs_log_cover(
{
struct xlog *log = mp->m_log;
int error = 0;
+ bool need_covered;
ASSERT((xlog_cil_empty(log) && xlog_iclogs_empty(log) &&
!xfs_ail_min_lsn(log->l_ailp)) ||
@@ -1119,6 +1120,21 @@ xfs_log_cover(
return 0;
/*
+ * xfs_log_need_covered() is not idempotent because it progresses the
+ * state machine if the log requires covering. Therefore, we must call
+ * this function once and use the result until we've issued an sb sync.
+ * Do so first to make that abundantly clear.
+ *
+ * Fall into the covering sequence if the log needs covering or the
+ * mount has lazy superblock accounting to sync to disk. The sb sync
+ * used for covering accumulates the in-core counters, so covering
+ * handles this for us.
+ */
+ need_covered = xfs_log_need_covered(mp);
+ if (!need_covered && !xfs_sb_version_haslazysbcount(&mp->m_sb))
+ return 0;
+
+ /*
* To cover the log, commit the superblock twice (at most) in
* independent checkpoints. The first serves as a reference for the
* tail pointer. The sync transaction and AIL push empties the AIL and
@@ -1127,12 +1143,12 @@ xfs_log_cover(
* covering the log. Push the AIL one more time to leave it empty, as
* we found it.
*/
- while (xfs_log_need_covered(mp)) {
+ do {
error = xfs_sync_sb(mp, true);
if (error)
break;
xfs_ail_push_all_sync(mp->m_ail);
- }
+ } while (xfs_log_need_covered(mp));
return error;
}