Skip to content

Commit 41e6362

Browse files
dgchinnerDarrick J. Wong
authored andcommitted
xfs: xfs_do_force_shutdown needs to block racing shutdowns
When we call xfs_forced_shutdown(), the caller often expects the filesystem to be completely shut down when it returns. However, if we have racing xfs_forced_shutdown() calls, the first caller sets the mount shutdown flag then goes to shutdown the log. The second caller sees the mount shutdown flag and returns immediately - it does not wait for the log to be shut down. Unfortunately, xfs_forced_shutdown() is used in some places that expect it to completely shut down the filesystem before it returns (e.g. xfs_trans_log_inode()). As such, returning before the log has been shut down leaves us in a place where the transaction failed to complete correctly but we still call xfs_trans_commit(). This situation arises because xfs_trans_log_inode() does not return an error and instead calls xfs_force_shutdown() to ensure that the transaction being committed is aborted. Unfortunately, we have a race condition where xfs_trans_commit() needs to check xlog_is_shutdown() because it can't abort log items before the log is shut down, but it needs to use xfs_is_shutdown() because xfs_forced_shutdown() does not block waiting for the log to shut down. To fix this conundrum, first we make all calls to xfs_forced_shutdown() block until the log is also shut down. This means we can then safely use xfs_forced_shutdown() as a mechanism that ensures the currently running transaction will be aborted by xfs_trans_commit() regardless of the shutdown check it uses. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Darrick J. Wong <djwong@kernel.org> Signed-off-by: Darrick J. Wong <djwong@kernel.org>
1 parent b5f17be commit 41e6362

3 files changed

Lines changed: 17 additions & 1 deletion

File tree

fs/xfs/xfs_fsops.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "xfs_fsops.h"
1818
#include "xfs_trans_space.h"
1919
#include "xfs_log.h"
20+
#include "xfs_log_priv.h"
2021
#include "xfs_ag.h"
2122
#include "xfs_ag_resv.h"
2223
#include "xfs_trace.h"
@@ -518,8 +519,11 @@ xfs_do_force_shutdown(
518519
int tag;
519520
const char *why;
520521

521-
if (test_and_set_bit(XFS_OPSTATE_SHUTDOWN, &mp->m_opstate))
522+
523+
if (test_and_set_bit(XFS_OPSTATE_SHUTDOWN, &mp->m_opstate)) {
524+
xlog_shutdown_wait(mp->m_log);
522525
return;
526+
}
523527
if (mp->m_sb_bp)
524528
mp->m_sb_bp->b_flags |= XBF_DONE;
525529

fs/xfs/xfs_log.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3923,6 +3923,7 @@ xlog_force_shutdown(
39233923
xlog_state_shutdown_callbacks(log);
39243924
spin_unlock(&log->l_icloglock);
39253925

3926+
wake_up_var(&log->l_opstate);
39263927
return log_error;
39273928
}
39283929

fs/xfs/xfs_log_priv.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,17 @@ xlog_is_shutdown(struct xlog *log)
484484
return test_bit(XLOG_IO_ERROR, &log->l_opstate);
485485
}
486486

487+
/*
488+
* Wait until the xlog_force_shutdown() has marked the log as shut down
489+
* so xlog_is_shutdown() will always return true.
490+
*/
491+
static inline void
492+
xlog_shutdown_wait(
493+
struct xlog *log)
494+
{
495+
wait_var_event(&log->l_opstate, xlog_is_shutdown(log));
496+
}
497+
487498
/* common routines */
488499
extern int
489500
xlog_recover(

0 commit comments

Comments
 (0)