fuse: update attributes before splice read
authorMiklos Szeredi <mszeredi@redhat.com>
Wed, 24 Aug 2016 16:17:04 +0000 (18:17 +0200)
committerMiklos Szeredi <mszeredi@redhat.com>
Wed, 24 Aug 2016 16:17:04 +0000 (18:17 +0200)
Before normal cached read fuse already updated attributes from userspace in
two cases:

 1) the end of the read was beyond current i_size

 2) in auto invalidate mode, to make sure we don't read stale data from the
    cache

The same logic would apply to reads with splice(2) as well, but in that
case the attribute refresh was missing.

This patch creates a helper, fuse_update_attr_before_read(), and calls this
in both the normal and the splice cases.

Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Fixes: a8894274a358 ("fuse: update attributes on aio_read")
Cc: <stable@vger.kernel.org> # v3.6+
fs/fuse/file.c

index 3988b43c2f5ac8d87533db4de75395e5c4d1c286..4b0a8db5ca9e0585e2241520ff90156f29cf8485 100644 (file)
@@ -914,27 +914,49 @@ out:
        return err;
 }
 
-static ssize_t fuse_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
+static ssize_t fuse_update_attr_before_read(struct file *filp, loff_t pos,
+                                           size_t len)
 {
-       struct inode *inode = iocb->ki_filp->f_mapping->host;
+       struct inode *inode = filp->f_mapping->host;
        struct fuse_conn *fc = get_fuse_conn(inode);
+       int err = 0;
 
        /*
         * In auto invalidate mode, always update attributes on read.
         * Otherwise, only update if we attempt to read past EOF (to ensure
         * i_size is up to date).
         */
-       if (fc->auto_inval_data ||
-           (iocb->ki_pos + iov_iter_count(to) > i_size_read(inode))) {
-               int err;
-               err = fuse_update_attributes(inode, NULL, iocb->ki_filp, NULL);
-               if (err)
-                       return err;
-       }
+       if (fc->auto_inval_data || (pos + len > i_size_read(inode)))
+               err = fuse_update_attributes(inode, NULL, filp, NULL);
+
+       return err;
+}
+
+static ssize_t fuse_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
+{
+       ssize_t err;
+
+       err = fuse_update_attr_before_read(iocb->ki_filp, iocb->ki_pos,
+                                          iov_iter_count(to));
+       if (err)
+               return err;
 
        return generic_file_read_iter(iocb, to);
 }
 
+static ssize_t fuse_file_splice_read(struct file *in, loff_t *ppos,
+                                    struct pipe_inode_info *pipe, size_t len,
+                                    unsigned int flags)
+{
+       ssize_t err;
+
+       err = fuse_update_attr_before_read(in, *ppos, len);
+       if (err)
+               return err;
+
+       return generic_file_splice_read(in, ppos, pipe, len, flags);
+}
+
 static void fuse_write_fill(struct fuse_req *req, struct fuse_file *ff,
                            loff_t pos, size_t count)
 {
@@ -3033,7 +3055,7 @@ static const struct file_operations fuse_file_operations = {
        .fsync          = fuse_fsync,
        .lock           = fuse_file_lock,
        .flock          = fuse_file_flock,
-       .splice_read    = generic_file_splice_read,
+       .splice_read    = fuse_file_splice_read,
        .unlocked_ioctl = fuse_file_ioctl,
        .compat_ioctl   = fuse_file_compat_ioctl,
        .poll           = fuse_file_poll,
This page took 0.025883 seconds and 5 git commands to generate.