summaryrefslogtreecommitdiffstats
path: root/fs/fuse/cuse.c
diff options
context:
space:
mode:
authorPavel Emelyanov <xemul@openvz.org>2013-10-10 15:12:05 +0200
committerMiklos Szeredi <mszeredi@suse.cz>2014-04-02 15:38:50 +0200
commitea8cd33390fafc1eca06a26e6a9c7bf1d386526f (patch)
treeeb0b3ecdf4760b3b96bc2d0d179e4c59c33d7ade /fs/fuse/cuse.c
parentfuse: fuse_flush() should wait on writeback (diff)
downloadlinux-ea8cd33390fafc1eca06a26e6a9c7bf1d386526f.tar.xz
linux-ea8cd33390fafc1eca06a26e6a9c7bf1d386526f.zip
fuse: Fix O_DIRECT operations vs cached writeback misorder
The problem is: 1. write cached data to a file 2. read directly from the same file (via another fd) The 2nd operation may read stale data, i.e. the one that was in a file before the 1st op. Problem is in how fuse manages writeback. When direct op occurs the core kernel code calls filemap_write_and_wait to flush all the cached ops in flight. But fuse acks the writeback right after the ->writepages callback exits w/o waiting for the real write to happen. Thus the subsequent direct op proceeds while the real writeback is still in flight. This is a problem for backends that reorder operation. Fix this by making the fuse direct IO callback explicitly wait on the in-flight writeback to finish. Signed-off-by: Maxim Patlasov <MPatlasov@parallels.com> Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Diffstat (limited to 'fs/fuse/cuse.c')
-rw-r--r--fs/fuse/cuse.c5
1 files changed, 3 insertions, 2 deletions
diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c
index b96a49b37d66..23e363f38302 100644
--- a/fs/fuse/cuse.c
+++ b/fs/fuse/cuse.c
@@ -95,7 +95,7 @@ static ssize_t cuse_read(struct file *file, char __user *buf, size_t count,
struct iovec iov = { .iov_base = buf, .iov_len = count };
struct fuse_io_priv io = { .async = 0, .file = file };
- return fuse_direct_io(&io, &iov, 1, count, &pos, 0);
+ return fuse_direct_io(&io, &iov, 1, count, &pos, FUSE_DIO_CUSE);
}
static ssize_t cuse_write(struct file *file, const char __user *buf,
@@ -109,7 +109,8 @@ static ssize_t cuse_write(struct file *file, const char __user *buf,
* No locking or generic_write_checks(), the server is
* responsible for locking and sanity checks.
*/
- return fuse_direct_io(&io, &iov, 1, count, &pos, 1);
+ return fuse_direct_io(&io, &iov, 1, count, &pos,
+ FUSE_DIO_WRITE | FUSE_DIO_CUSE);
}
static int cuse_open(struct inode *inode, struct file *file)