diff options
author | Pavel Emelyanov <xemul@openvz.org> | 2013-10-10 09:12:05 -0400 |
---|---|---|
committer | Miklos Szeredi <mszeredi@suse.cz> | 2014-04-02 09:38:50 -0400 |
commit | ea8cd33390fafc1eca06a26e6a9c7bf1d386526f (patch) | |
tree | eb0b3ecdf4760b3b96bc2d0d179e4c59c33d7ade /fs/fuse/fuse_i.h | |
parent | fe38d7df230b022e72014ef7aa799a4f2acfecf3 (diff) |
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/fuse_i.h')
-rw-r--r-- | fs/fuse/fuse_i.h | 13 |
1 files changed, 12 insertions, 1 deletions
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 1e6ad6d43051..a257ed8ebee6 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -868,9 +868,20 @@ int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid, | |||
868 | 868 | ||
869 | int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file, | 869 | int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file, |
870 | bool isdir); | 870 | bool isdir); |
871 | |||
872 | /** | ||
873 | * fuse_direct_io() flags | ||
874 | */ | ||
875 | |||
876 | /** If set, it is WRITE; otherwise - READ */ | ||
877 | #define FUSE_DIO_WRITE (1 << 0) | ||
878 | |||
879 | /** CUSE pass fuse_direct_io() a file which f_mapping->host is not from FUSE */ | ||
880 | #define FUSE_DIO_CUSE (1 << 1) | ||
881 | |||
871 | ssize_t fuse_direct_io(struct fuse_io_priv *io, const struct iovec *iov, | 882 | ssize_t fuse_direct_io(struct fuse_io_priv *io, const struct iovec *iov, |
872 | unsigned long nr_segs, size_t count, loff_t *ppos, | 883 | unsigned long nr_segs, size_t count, loff_t *ppos, |
873 | int write); | 884 | int flags); |
874 | long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, | 885 | long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, |
875 | unsigned int flags); | 886 | unsigned int flags); |
876 | long fuse_ioctl_common(struct file *file, unsigned int cmd, | 887 | long fuse_ioctl_common(struct file *file, unsigned int cmd, |