Skip to content

Commit ce6d9c1

Browse files
Mike Snitzerakpm00
authored andcommitted
NFS: fix nfs_release_folio() to not deadlock via kcompactd writeback
Add PF_KCOMPACTD flag and current_is_kcompactd() helper to check for it so nfs_release_folio() can skip calling nfs_wb_folio() from kcompactd. Otherwise NFS can deadlock waiting for kcompactd enduced writeback which recurses back to NFS (which triggers writeback to NFSD via NFS loopback mount on the same host, NFSD blocks waiting for XFS's call to __filemap_get_folio): 6070.550357] INFO: task kcompactd0:58 blocked for more than 4435 seconds. {--- [58] "kcompactd0" [<0>] folio_wait_bit+0xe8/0x200 [<0>] folio_wait_writeback+0x2b/0x80 [<0>] nfs_wb_folio+0x80/0x1b0 [nfs] [<0>] nfs_release_folio+0x68/0x130 [nfs] [<0>] split_huge_page_to_list_to_order+0x362/0x840 [<0>] migrate_pages_batch+0x43d/0xb90 [<0>] migrate_pages_sync+0x9a/0x240 [<0>] migrate_pages+0x93c/0x9f0 [<0>] compact_zone+0x8e2/0x1030 [<0>] compact_node+0xdb/0x120 [<0>] kcompactd+0x121/0x2e0 [<0>] kthread+0xcf/0x100 [<0>] ret_from_fork+0x31/0x40 [<0>] ret_from_fork_asm+0x1a/0x30 ---} [akpm@linux-foundation.org: fix build] Link: https://lkml.kernel.org/r/20250225022002.26141-1-snitzer@kernel.org Fixes: 96780ca ("NFS: fix up nfs_release_folio() to try to release the page") Signed-off-by: Mike Snitzer <snitzer@kernel.org> Cc: Anna Schumaker <anna.schumaker@oracle.com> Cc: Trond Myklebust <trond.myklebust@hammerspace.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent 57d910c commit ce6d9c1

File tree

4 files changed

+11
-2
lines changed

4 files changed

+11
-2
lines changed

fs/nfs/file.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <linux/pagemap.h>
3030
#include <linux/gfp.h>
3131
#include <linux/swap.h>
32+
#include <linux/compaction.h>
3233

3334
#include <linux/uaccess.h>
3435
#include <linux/filelock.h>
@@ -457,7 +458,7 @@ static bool nfs_release_folio(struct folio *folio, gfp_t gfp)
457458
/* If the private flag is set, then the folio is not freeable */
458459
if (folio_test_private(folio)) {
459460
if ((current_gfp_context(gfp) & GFP_KERNEL) != GFP_KERNEL ||
460-
current_is_kswapd())
461+
current_is_kswapd() || current_is_kcompactd())
461462
return false;
462463
if (nfs_wb_folio(folio->mapping->host, folio) < 0)
463464
return false;

include/linux/compaction.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ static inline unsigned long compact_gap(unsigned int order)
8080
return 2UL << order;
8181
}
8282

83+
static inline int current_is_kcompactd(void)
84+
{
85+
return current->flags & PF_KCOMPACTD;
86+
}
87+
8388
#ifdef CONFIG_COMPACTION
8489

8590
extern unsigned int extfrag_for_order(struct zone *zone, unsigned int order);

include/linux/sched.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1701,7 +1701,7 @@ extern struct pid *cad_pid;
17011701
#define PF_USED_MATH 0x00002000 /* If unset the fpu must be initialized before use */
17021702
#define PF_USER_WORKER 0x00004000 /* Kernel thread cloned from userspace thread */
17031703
#define PF_NOFREEZE 0x00008000 /* This thread should not be frozen */
1704-
#define PF__HOLE__00010000 0x00010000
1704+
#define PF_KCOMPACTD 0x00010000 /* I am kcompactd */
17051705
#define PF_KSWAPD 0x00020000 /* I am kswapd */
17061706
#define PF_MEMALLOC_NOFS 0x00040000 /* All allocations inherit GFP_NOFS. See memalloc_nfs_save() */
17071707
#define PF_MEMALLOC_NOIO 0x00080000 /* All allocations inherit GFP_NOIO. See memalloc_noio_save() */

mm/compaction.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3181,6 +3181,7 @@ static int kcompactd(void *p)
31813181
long default_timeout = msecs_to_jiffies(HPAGE_FRAG_CHECK_INTERVAL_MSEC);
31823182
long timeout = default_timeout;
31833183

3184+
current->flags |= PF_KCOMPACTD;
31843185
set_freezable();
31853186

31863187
pgdat->kcompactd_max_order = 0;
@@ -3237,6 +3238,8 @@ static int kcompactd(void *p)
32373238
pgdat->proactive_compact_trigger = false;
32383239
}
32393240

3241+
current->flags &= ~PF_KCOMPACTD;
3242+
32403243
return 0;
32413244
}
32423245

0 commit comments

Comments
 (0)