All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Miklos Szeredi" <mszeredi@redhat.com>
Cc: linux-cxl@vger.kernel.org, nvdimm@lists.linux.dev
Subject: Re: [PATCH v2 7/8] fuse: add extent map I/O support
Date: Thu, 01 Oct 2026 15:27:35 +0000	[thread overview]
Message-ID: <20261001152735.8189B1F000FF@smtp.kernel.org> (raw)
In-Reply-To: <20261001150935.655979-8-mszeredi@redhat.com>

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] fuse: missing inode_lock_shared() in DAX read path causes lockdep splats and races
- [High] fuse: fuse_rw_clamp() truncates writes at EOF to 0 bytes, causing infinite loops
- [High] fuse: O_APPEND writes bypass fuse_rw_clamp limits due to ordering
- [High] fuse: ABBA deadlock between mmap_lock and i_rwsem in DAX page fault
--

commit 900b63ca4cd5e837e1d2beda0ce7ca37d122ab2d
Author: Miklos Szeredi <mszeredi@redhat.com>
Subject: fuse: add extent map I/O support

Wire up read, write, splice and mmap operations for extent-mapped
files through the iomap/DAX infrastructure.

> diff --git a/fs/fuse/ext_map.c b/fs/fuse/ext_map.c
> index ab01d678d08e5..61cb22e821b60 100644
> --- a/fs/fuse/ext_map.c
> +++ b/fs/fuse/ext_map.c
[ ... ]
> +static vm_fault_t fuse_ext_map_huge_fault(struct vm_fault *vmf, unsigned int order)
> +{
> +	struct inode *inode = file_inode(vmf->vma->vm_file);
> +	bool write_fault = (vmf->flags & FAULT_FLAG_WRITE) && (vmf->vma->vm_flags & VM_SHARED);
> +	vm_fault_t ret;
> +	unsigned long pfn;
> +
> +	if (WARN_ON_ONCE(!IS_DAX(inode)))
> +		return VM_FAULT_SIGBUS;
> +
> +	if (write_fault) {
> +		sb_start_pagefault(inode->i_sb);
> +		file_update_time(vmf->vma->vm_file);
> +	}
> +
> +	filemap_invalidate_lock_shared(inode->i_mapping);
> +
> +	ret = dax_iomap_fault(vmf, order, &pfn, NULL, &fuse_ext_map_iomap_ops);
> +	if (ret & VM_FAULT_NEEDDSYNC)
> +		ret = dax_finish_sync_fault(vmf, order, pfn);
        ^^^^

[Severity: High]
Can this create an ABBA deadlock between mmap_lock and i_rwsem?

This page fault handler is entered holding the VFS mmap_lock, and then
takes filemap_invalidate_lock_shared(). If the fault requires a data
sync (O_DSYNC), it calls dax_finish_sync_fault() which synchronously
invokes vfs_fsync_range(). 

The filesystem's fsync handler, fuse_fsync(), unconditionally acquires
inode_lock(inode). This creates an mmap_lock -> inode_lock dependency,
which violates the standard kernel lock hierarchy and can deadlock if
another thread holds the inode_lock while taking a page fault.

> +
> +	filemap_invalidate_unlock_shared(inode->i_mapping);
> +
> +	if (write_fault)
> +		sb_end_pagefault(inode->i_sb);
> +
> +	return ret;
> +}
[ ... ]
> +ssize_t fuse_ext_map_write_iter(struct kiocb *iocb, struct iov_iter *from)
> +{
> +	ssize_t res;
> +
> +	fuse_rw_clamp(iocb, from);
> +
> +	res = generic_write_checks(iocb, from);
        ^^^^

[Severity: High]
Can O_APPEND writes bypass the file size limits checked in
fuse_rw_clamp() due to this ordering?

Because fuse_rw_clamp() runs before generic_write_checks(),
kiocb->ki_pos is not yet updated to i_size for O_APPEND writes. Clamping
will evaluate based on the old, smaller position, and
generic_write_checks() will then advance ki_pos to i_size, allowing an
out-of-bounds write via dax_iomap_rw().

[Severity: High]
Also, does fuse_rw_clamp() cause writes at or past EOF to return 0
instead of a standard POSIX error?

When a write starts at or past i_size, fuse_rw_clamp() truncates the
iterator to 0. Then, generic_write_checks() returns 0, which propagates
up to the VFS. This can cause standard utilities (like cp and dd) to
retry indefinitely in an infinite loop instead of receiving -ENOSPC or
-EFBIG.

> +	if (res <= 0)
> +		return res;
> +
> +	res = kiocb_modified(iocb);
> +	if (res)
> +		return res;
> +
> +	return dax_iomap_rw(iocb, from, &fuse_ext_map_iomap_ops);
> +}

> diff --git a/fs/fuse/passthrough.c b/fs/fuse/passthrough.c
> index e9ab1aea34e27..040817ad76e94 100644
> --- a/fs/fuse/passthrough.c
> +++ b/fs/fuse/passthrough.c
> @@ -48,10 +47,10 @@ ssize_t fuse_passthrough_read_iter(struct kiocb *iocb, struct iov_iter *iter)
>  	if (!count)
>  		return 0;
>  
> -	ret = backing_file_read_iter(backing_file, iter, iocb, iocb->ki_flags,
> -				     &ctx);
> +	if (!backing_file)
> +		return fuse_ext_map_read_iter(iocb, iter);
        ^^^^

[Severity: High]
Does this path miss acquiring the inode read lock before calling into
the DAX read operations?

When fuse_ext_map_read_iter() processes the read, it delegates to
dax_iomap_rw() which expects the VFS inode lock to be held for
synchronization against truncates. Skipping
inode_lock_shared(&inode->i_rwsem) here could lead to lockdep splats or
out-of-bounds reads during concurrent mapping changes.

>  
> -	return ret;
> +	return backing_file_read_iter(backing_file, iter, iocb, iocb->ki_flags, &ctx);
>  }

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261001150935.655979-1-mszeredi@redhat.com?part=7

  reply	other threads:[~2026-10-01 15:27 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-01 15:07 [PATCH v2 0/8] fuse: DAX device based extent maps (famfs) Miklos Szeredi
2026-10-01 15:07 ` [PATCH v2 1/8] dax: replace exported dax_dev_get() with non-allocating dax_dev_find() Miklos Szeredi
2026-10-01 15:07 ` [PATCH v2 2/8] fuse: add helpers for EIO return value with kernel message Miklos Szeredi
2026-10-01 15:18   ` sashiko-bot
2026-10-01 16:32   ` Amir Goldstein
2026-10-05  9:46     ` Miklos Szeredi
2026-10-01 15:07 ` [PATCH v2 3/8] fuse: support 64 bit, server allocated backing ID Miklos Szeredi
2026-10-01 15:26   ` sashiko-bot
2026-10-01 17:07   ` Amir Goldstein
2026-10-01 18:58     ` Amir Goldstein
2026-10-05 13:33       ` Miklos Szeredi
2026-10-06 21:24         ` Amir Goldstein
2026-10-07 12:46           ` Miklos Szeredi
2026-10-01 15:07 ` [PATCH v2 4/8] fuse: support opening 64 bit " Miklos Szeredi
2026-10-01 15:22   ` sashiko-bot
2026-10-01 17:09   ` Amir Goldstein
2026-10-01 15:07 ` [PATCH v2 5/8] fuse: add support for opening dax device as backing Miklos Szeredi
2026-10-01 15:30   ` sashiko-bot
2026-10-01 16:07   ` Amir Goldstein
2026-10-01 15:07 ` [PATCH v2 6/8] fuse: add extent map data structure Miklos Szeredi
2026-10-01 15:24   ` sashiko-bot
2026-10-01 15:07 ` [PATCH v2 7/8] fuse: add extent map I/O support Miklos Szeredi
2026-10-01 15:27   ` sashiko-bot [this message]
2026-10-01 16:11   ` Amir Goldstein
2026-10-01 15:07 ` [PATCH v2 8/8] fuse: add support for striped backing Miklos Szeredi
2026-10-05 23:27 ` [PATCH v2 0/8] fuse: DAX device based extent maps (famfs) John Groves
2026-10-06  9:48   ` Miklos Szeredi
2026-10-08 23:00     ` John Groves
2026-10-09 10:39       ` Miklos Szeredi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261001152735.8189B1F000FF@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-cxl@vger.kernel.org \
    --cc=mszeredi@redhat.com \
    --cc=nvdimm@lists.linux.dev \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.