mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2] fuse: dax: Clear stale mapping when inline reclaim lookup misses
@ 2026-10-08 14:09 Cen Zhang
  0 siblings, 0 replies; only message in thread
From: Cen Zhang @ 2026-10-08 14:09 UTC (permalink / raw)
  To: miklos, bo.liu, vgoyal
  Cc: fuse-devel, linux-kernel, baijiaju1990, jjzuming, zzzccc427

A mapping returned by inline reclaim must be detached from its inode
and the connection's busy list before it can be reused. However,
inode_inline_reclaim_one_dmap() leaves dmap unchanged when its second
tree lookup misses. It sets retry but returns the old pointer, and
alloc_dax_mapping_reclaim() accepts a non-NULL result before checking
retry.

With DAX enabled, an exhausted free pool sends a file read or a
non-extending write into inline reclaim. A pinned DAX page can make
fuse_dax_break_layouts() wait. The inode tree semaphore is already
released, and fuse_wait_dax_page() drops the inode's invalidate_lock
while scheduling. This permits the following ordering:

  1. Inline reclaim on inode I selects mapping D and copies its index
     under fi->dax->sem, then releases the semaphore and waits with
     invalidate_lock dropped.
  2. After the page is unpinned, the reclaim worker acquires I's
     invalidate_lock before the inline caller resumes. It relooks up
     the index under fi->dax->sem, removes D and returns it to the free
     pool under fcd->lock.
  3. Mapping setup on inode J takes D from the free pool and publishes
     it in J's tree and the busy list. J has separate inode locks.
  4. Inline reclaim reacquires I's invalidate_lock and fi->dax->sem.
     Its lookup misses, but it returns D. Setup on I then reuses D
     while J still owns it.

Successful stale setup remaps the same DAX window and reinserts the
embedded tree and list nodes, allowing accesses to reach another
file's data and corrupting the mapping structures. A setup error or
an existing mapping on I instead puts the active slot on the free
list. Later reclaim can encounter a cleared inode pointer in the
corrupted busy list.

Clear dmap on the missing-node branch, as in the adjacent branch for
a mapping still in use. Returning NULL with retry set makes the
allocator retry through the existing pool and tree lookups after
releasing both inode locks, rather than reuse an unreserved slot.

The failing worker produced the following KASAN report:

    BUG: KASAN: null-ptr-deref in igrab+0x2d/0x260
    Write of size 4 at addr 00000000000001e8 by task kworker/u16:0/12

    Workqueue: events_dfl_long fuse_dax_free_mem_worker
    Call Trace:
      <TASK>
      dump_stack_lvl+0x93/0xd0
      kasan_report+0xe0/0x110
      ? igrab+0x2d/0x260
      kasan_check_range+0x105/0x1b0
      igrab+0x2d/0x260
      fuse_dax_free_mem_worker+0x172/0x9e0
      process_one_work+0x908/0x19c0
      ? __pfx_process_one_work+0x10/0x10
      ? srso_alias_return_thunk+0x5/0xfbef5
      ? lock_is_held_type+0x8f/0x100
      ? srso_alias_return_thunk+0x5/0xfbef5
      worker_thread+0x65c/0xe40
      ? __pfx_worker_thread+0x10/0x10
      kthread+0x34f/0x460
      ? srso_alias_return_thunk+0x5/0xfbef5
      ? __pfx_kthread+0x10/0x10
      ret_from_fork+0x659/0x940
      ? __pfx_ret_from_fork+0x10/0x10
      ? srso_alias_return_thunk+0x5/0xfbef5
      ? __switch_to+0x74f/0xf80
      ? __pfx_kthread+0x10/0x10
      ret_from_fork_asm+0x1a/0x30
      </TASK>

Fixes: 9a752d18c85ae ("virtiofs: add logic to free up a memory range")
Assisted-by: LLM
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
---
Changes in v2:
- Drop the duplicate Oops report and format the KASAN trace.

Link to v1: https://lore.kernel.org/r/pm-fuse-full-objects-candidate-0016-v2-f3854498f12705839ecb@gmail.com

diff --git a/fs/fuse/dax.c b/fs/fuse/dax.c
index 85cdf0199bc0b8fb121324ffaf8046a054cbfadf..361538bc41e5a44d01da11b76070f8af0e783b2b 100644
--- a/fs/fuse/dax.c
+++ b/fs/fuse/dax.c
@@ -951,6 +951,7 @@ inode_inline_reclaim_one_dmap(struct fuse_conn_dax *fcd, struct inode *inode,
 	node = interval_tree_iter_first(&fi->dax->tree, start_idx, start_idx);
 	/* Range already got reclaimed by somebody else */
 	if (!node) {
+		dmap = NULL;
 		if (retry)
 			*retry = true;
 		goto out_write_dmap_sem;

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2026-10-08 14:09 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-08 14:09 [PATCH v2] fuse: dax: Clear stale mapping when inline reclaim lookup misses Cen Zhang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®