fusefs: fix a deadlock in VOP_PUTPAGES
As of r346162 fuse now invalidates the cache during writes. But it can't do that when writing from VOP_PUTPAGES, because the write is coming _from_ the cache. Trying to invalidate the cache in that situation causes a deadlock in vm_object_page_remove, because the pages in question have already been busied by the same thread. PR: 235774 Sponsored by: The FreeBSD Foundation
This commit is contained in:
parent
75d5cb29cb
commit
9c7ec33162
@ -122,7 +122,7 @@ fuse_write_biobackend(struct vnode *vp, struct uio *uio,
|
||||
SDT_PROBE_DEFINE5(fusefs, , io, io_dispatch, "struct vnode*", "struct uio*",
|
||||
"int", "struct ucred*", "struct fuse_filehandle*");
|
||||
int
|
||||
fuse_io_dispatch(struct vnode *vp, struct uio *uio, int ioflag,
|
||||
fuse_io_dispatch(struct vnode *vp, struct uio *uio, int ioflag, bool pages,
|
||||
struct ucred *cred, pid_t pid)
|
||||
{
|
||||
struct fuse_filehandle *fufh;
|
||||
@ -172,13 +172,20 @@ fuse_io_dispatch(struct vnode *vp, struct uio *uio, int ioflag,
|
||||
* cached.
|
||||
*/
|
||||
if (directio || fuse_data_cache_mode == FUSE_CACHE_WT) {
|
||||
const int iosize = fuse_iosize(vp);
|
||||
off_t start, end;
|
||||
|
||||
SDT_PROBE2(fusefs, , io, trace, 1,
|
||||
"direct write of vnode");
|
||||
start = uio->uio_offset;
|
||||
end = start + uio->uio_resid;
|
||||
v_inval_buf_range(vp, start, end, fuse_iosize(vp));
|
||||
/*
|
||||
* Invalidate the write cache unless we're coming from
|
||||
* VOP_PUTPAGES, in which case we're writing _from_ the
|
||||
* write cache
|
||||
*/
|
||||
if (!pages )
|
||||
v_inval_buf_range(vp, start, end, iosize);
|
||||
err = fuse_write_directbackend(vp, uio, cred, fufh,
|
||||
ioflag);
|
||||
} else {
|
||||
|
@ -60,7 +60,7 @@
|
||||
#ifndef _FUSE_IO_H_
|
||||
#define _FUSE_IO_H_
|
||||
|
||||
int fuse_io_dispatch(struct vnode *vp, struct uio *uio, int ioflag,
|
||||
int fuse_io_dispatch(struct vnode *vp, struct uio *uio, int ioflag, bool pages,
|
||||
struct ucred *cred, pid_t pid);
|
||||
int fuse_io_strategy(struct vnode *vp, struct buf *bp);
|
||||
int fuse_io_flushbuf(struct vnode *vp, int waitfor, struct thread *td);
|
||||
|
@ -1222,7 +1222,7 @@ fuse_vnop_read(struct vop_read_args *ap)
|
||||
ioflag |= IO_DIRECT;
|
||||
}
|
||||
|
||||
return fuse_io_dispatch(vp, uio, ioflag, cred, pid);
|
||||
return fuse_io_dispatch(vp, uio, ioflag, false, cred, pid);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1729,7 +1729,7 @@ fuse_vnop_write(struct vop_write_args *ap)
|
||||
ioflag |= IO_DIRECT;
|
||||
}
|
||||
|
||||
return fuse_io_dispatch(vp, uio, ioflag, cred, pid);
|
||||
return fuse_io_dispatch(vp, uio, ioflag, false, cred, pid);
|
||||
}
|
||||
|
||||
SDT_PROBE_DEFINE1(fusefs, , vnops, vnop_getpages_error, "int");
|
||||
@ -1803,7 +1803,7 @@ fuse_vnop_getpages(struct vop_getpages_args *ap)
|
||||
uio.uio_rw = UIO_READ;
|
||||
uio.uio_td = td;
|
||||
|
||||
error = fuse_io_dispatch(vp, &uio, IO_DIRECT, cred, pid);
|
||||
error = fuse_io_dispatch(vp, &uio, IO_DIRECT, true, cred, pid);
|
||||
pmap_qremove(kva, npages);
|
||||
|
||||
uma_zfree(fuse_pbuf_zone, bp);
|
||||
@ -1936,7 +1936,7 @@ fuse_vnop_putpages(struct vop_putpages_args *ap)
|
||||
uio.uio_rw = UIO_WRITE;
|
||||
uio.uio_td = td;
|
||||
|
||||
error = fuse_io_dispatch(vp, &uio, IO_DIRECT, cred, pid);
|
||||
error = fuse_io_dispatch(vp, &uio, IO_DIRECT, true, cred, pid);
|
||||
|
||||
pmap_qremove(kva, npages);
|
||||
uma_zfree(fuse_pbuf_zone, bp);
|
||||
|
Loading…
Reference in New Issue
Block a user