aboutsummaryrefslogtreecommitdiff
path: root/sys/fs
diff options
context:
space:
mode:
authorAlan Somers <asomers@FreeBSD.org>2020-09-24 16:27:53 +0000
committerAlan Somers <asomers@FreeBSD.org>2020-09-24 16:27:53 +0000
commita62772a78e524da2de90f67bf8824b8a3035dd5c (patch)
treec37c6bff8628c8df368c90cb905af577f01837af /sys/fs
parentf0f718ce96f74076ea14bff7e71e578573d80641 (diff)
downloadsrc-a62772a78e524da2de90f67bf8824b8a3035dd5c.tar.gz
src-a62772a78e524da2de90f67bf8824b8a3035dd5c.zip
fusefs: fix mmap'd writes in direct_io mode
If a FUSE server returns FOPEN_DIRECT_IO in response to FUSE_OPEN, that instructs the kernel to bypass the page cache for that file. This feature is also known by libfuse's name: "direct_io". However, when accessing a file via mmap, there is no possible way to bypass the cache completely. This change fixes a deadlock that would happen when an mmap'd write tried to invalidate a portion of the cache, wrongly assuming that a write couldn't possibly come from cache if direct_io were set. Arguably, we could instead disable mmap for files with FOPEN_DIRECT_IO set. But allowing it is less likely to cause user complaints, and is more in keeping with the spirit of open(2), where O_DIRECT instructs the kernel to "reduce", not "eliminate" cache effects. PR: 247276 Reported by: trapexit@spawn.link Reviewed by: cem MFC after: 3 days Differential Revision: https://reviews.freebsd.org/D26485
Notes
Notes: svn path=/head/; revision=366121
Diffstat (limited to 'sys/fs')
-rw-r--r--sys/fs/fuse/fuse_io.c16
1 files changed, 8 insertions, 8 deletions
diff --git a/sys/fs/fuse/fuse_io.c b/sys/fs/fuse/fuse_io.c
index ac0235e8c718..4e178bb5340a 100644
--- a/sys/fs/fuse/fuse_io.c
+++ b/sys/fs/fuse/fuse_io.c
@@ -291,6 +291,7 @@ fuse_io_dispatch(struct vnode *vp, struct uio *uio, int ioflag,
fuse_vnode_update(vp, FN_MTIMECHANGE | FN_CTIMECHANGE);
if (directio) {
off_t start, end, filesize;
+ bool pages = (ioflag & IO_VMIO) != 0;
SDT_PROBE2(fusefs, , io, trace, 1,
"direct write of vnode");
@@ -301,15 +302,14 @@ fuse_io_dispatch(struct vnode *vp, struct uio *uio, int ioflag,
start = uio->uio_offset;
end = start + uio->uio_resid;
- KASSERT((ioflag & (IO_VMIO | IO_DIRECT)) !=
- (IO_VMIO | IO_DIRECT),
- ("IO_DIRECT used for a cache flush?"));
- /* Invalidate the write cache when writing directly */
- err = fuse_inval_buf_range(vp, filesize, start, end);
- if (err)
- return (err);
+ if (!pages) {
+ err = fuse_inval_buf_range(vp, filesize, start,
+ end);
+ if (err)
+ return (err);
+ }
err = fuse_write_directbackend(vp, uio, cred, fufh,
- filesize, ioflag, false);
+ filesize, ioflag, pages);
} else {
SDT_PROBE2(fusefs, , io, trace, 1,
"buffered write of vnode");