[Restored Cc list]
On Thu, Oct 8, 2026 at 1:36 PM <[email protected]> wrote:
> > 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
> [ ... ]
> > @@ -74,10 +73,13 @@ ssize_t fuse_passthrough_write_iter(struct kiocb *iocb,
> > if (!count)
> > return 0;
> >
> > - inode_lock(inode);
> > + guard(rwsem_write)(&inode->i_rwsem);
> > +
> > + if (!backing_file)
> > + return fuse_ext_map_write_iter(iocb, iter);
>
> [Severity: High]
> Does this introduce an ABBA deadlock between pipe_lock and the inode lock?
>
> For normal passthrough, fuse_passthrough_splice_write() acquires the inode
> lock first, and then calls backing_file_splice_write(), which ultimately
> acquires pipe_lock() via the backing file's splice_write callback.
>
> However, the EXTMAP DAX path added below for splice_write() directly calls
> iter_file_splice_write(), which acquires pipe_lock() first. That function then
> invokes fuse_passthrough_write_iter() where the inode lock is acquired here
> via guard(rwsem_write).
Brute force fix would be to prevent mixing plain and ext-map
passthrough. Might be a good idea anyway.
However I'm thinking about why fuse_passthrough_splice_write() needs
to lock the fuse inode.
Tracing back through git history that inode lock really originates
from commit 2a92e07edc5e ("ovl: add ovl_write_iter()"), which added
stacked writes. That was copied into ovl_splice_write() by commit
9b91b6b019fd ("ovl: fix deadlock in splice write"). Which was then
added to fuse_passthrough_splice_write() by commit 5ca73468612d
("fuse: implement splice read/write passthrough").
Even for the original ovl code, I don't see an explanation for the
inode lock, but I'm probably missing something.
Amir, any thoughts about why that inode_lock() could be necessary?
Getting rid of it would restore the pipe lock/inode lock order to
what's normal (pipe lock being the outer one) in fuse and overlayfs.
Thanks,
Miklos
Thanks,
Miklos