diff options
author | Alan Somers <asomers@FreeBSD.org> | 2020-09-24 16:27:53 +0000 |
---|---|---|
committer | Alan Somers <asomers@FreeBSD.org> | 2020-09-24 16:27:53 +0000 |
commit | a62772a78e524da2de90f67bf8824b8a3035dd5c (patch) | |
tree | c37c6bff8628c8df368c90cb905af577f01837af /sys/fs | |
parent | f0f718ce96f74076ea14bff7e71e578573d80641 (diff) | |
download | src-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.c | 16 |
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"); |