xfs: fix incorrect context handling in xfs_trans_roll

The memalloc_nofs_save() and memalloc_nofs_restore() calls are
incorrectly paired in xfs_trans_roll.

Call path:
xfs_trans_alloc()
    __xfs_trans_alloc()
	// tp->t_pflags = memalloc_nofs_save();
	xfs_trans_set_context()
...
xfs_defer_trans_roll()
    xfs_trans_roll()
        xfs_trans_dup()
            // old_tp->t_pflags = 0;
            xfs_trans_switch_context()
        __xfs_trans_commit()
            xfs_trans_free()
                // memalloc_nofs_restore(tp->t_pflags);
                xfs_trans_clear_context()

The code passes 0 to memalloc_nofs_restore() when committing the original
transaction, but memalloc_nofs_restore() should always receive the
flags returned from the paired memalloc_nofs_save() call.

Before commit 3f6d5e6a46 ("mm: introduce memalloc_flags_{save,restore}"),
calling memalloc_nofs_restore(0) would unset the PF_MEMALLOC_NOFS flag,
which could cause memory allocation deadlocks[1].
Fortunately, after that commit, memalloc_nofs_restore(0) does nothing,
so this issue is currently harmless.

Fixes: 756b1c3433 ("xfs: use current->journal_info for detecting transaction recursion")
Link: https://lore.kernel.org/linux-xfs/20251104131857.1587584-1-leo.lilong@huawei.com [1]
Signed-off-by: Wenwu Hou <hwenwur@gmail.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
This commit is contained in:
Wenwu Hou 2026-01-17 14:52:43 +08:00 committed by Carlos Maiolino
parent 01a2896154
commit a1ca658d64
2 changed files with 6 additions and 11 deletions

View file

@ -124,8 +124,6 @@ xfs_trans_dup(
ntp->t_rtx_res = tp->t_rtx_res - tp->t_rtx_res_used;
tp->t_rtx_res = tp->t_rtx_res_used;
xfs_trans_switch_context(tp, ntp);
/* move deferred ops over to the new tp */
xfs_defer_move(ntp, tp);
@ -1043,6 +1041,12 @@ xfs_trans_roll(
* locked be logged in the prior and the next transactions.
*/
tp = *tpp;
/*
* __xfs_trans_commit cleared the NOFS flag by calling into
* xfs_trans_free. Set it again here before doing memory
* allocations.
*/
xfs_trans_set_context(tp);
error = xfs_log_regrant(tp->t_mountp, tp->t_ticket);
if (error)
return error;

View file

@ -280,13 +280,4 @@ xfs_trans_clear_context(
memalloc_nofs_restore(tp->t_pflags);
}
static inline void
xfs_trans_switch_context(
struct xfs_trans *old_tp,
struct xfs_trans *new_tp)
{
new_tp->t_pflags = old_tp->t_pflags;
old_tp->t_pflags = 0;
}
#endif /* __XFS_TRANS_H__ */