]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
xfs: fix incorrect context handling in xfs_trans_roll
authorWenwu Hou <hwenwur@gmail.com>
Sat, 17 Jan 2026 06:52:43 +0000 (14:52 +0800)
committerCarlos Maiolino <cem@kernel.org>
Wed, 21 Jan 2026 11:59:10 +0000 (12:59 +0100)
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 3f6d5e6a468d ("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: 756b1c343333 ("xfs: use current->journal_info for detecting transaction recursion")
Link: https://lore.kernel.org/linux-xfs/20251104131857.1587584-1-leo.lilong@huawei.com
Signed-off-by: Wenwu Hou <hwenwur@gmail.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
fs/xfs/xfs_trans.c
fs/xfs/xfs_trans.h

index 2c3c29d0d4a08d801d61e81bdd886f3fbcfb1a47..bcc470f56e4662920961f1bef2d4c71265933b5b 100644 (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;
index 8830600b3e72981812a925a25f46d22120be23df..eb83c5dac0320fb237c40c181bd476a3f1c1d0c1 100644 (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__ */