]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 16 Aug 2012 18:46:31 +0000 (11:46 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 16 Aug 2012 18:46:31 +0000 (11:46 -0700)
Pull fuse updates from Miklos Szeredi.

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
  fuse: verify all ioctl retry iov elements
  fuse: add missing INIT flag descriptions
  fuse: add missing INIT flags
  fuse: update attributes on aio_read
  fuse: invalidate inode mapping if mtime changes
  fuse: add FUSE_AUTO_INVAL_DATA init flag

fs/fuse/file.c
fs/fuse/fuse_i.h
fs/fuse/inode.c
include/linux/fuse.h

index 93d8d6c9494dbd5737b0842a3ebb55ef972e0d87..aba15f1b7ad2974aa85e2c7272afc3d7836a40bc 100644 (file)
@@ -703,13 +703,16 @@ static ssize_t fuse_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
                                  unsigned long nr_segs, loff_t pos)
 {
        struct inode *inode = iocb->ki_filp->f_mapping->host;
+       struct fuse_conn *fc = get_fuse_conn(inode);
 
-       if (pos + iov_length(iov, nr_segs) > i_size_read(inode)) {
+       /*
+        * 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 ||
+           (pos + iov_length(iov, nr_segs) > i_size_read(inode))) {
                int err;
-               /*
-                * If trying to read past EOF, make sure the i_size
-                * attribute is up-to-date.
-                */
                err = fuse_update_attributes(inode, NULL, iocb->ki_filp, NULL);
                if (err)
                        return err;
@@ -1700,7 +1703,7 @@ static int fuse_verify_ioctl_iov(struct iovec *iov, size_t count)
        size_t n;
        u32 max = FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT;
 
-       for (n = 0; n < count; n++) {
+       for (n = 0; n < count; n++, iov++) {
                if (iov->iov_len > (size_t) max)
                        return -ENOMEM;
                max -= iov->iov_len;
index 771fb6322c0750d223bb2ee7873f6d0cdbdef41b..e24dd74e3068d130545ee58f918519d4ca2ee620 100644 (file)
@@ -484,6 +484,9 @@ struct fuse_conn {
        /** Is fallocate not implemented by fs? */
        unsigned no_fallocate:1;
 
+       /** Use enhanced/automatic page cache invalidation. */
+       unsigned auto_inval_data:1;
+
        /** The number of requests waiting for completion */
        atomic_t num_waiting;
 
index 1cd61652018c7c8547a060344ef998ee6ae96879..ce0a2838ccd097a5392d469fc0650d2e7b0d7e8d 100644 (file)
@@ -197,6 +197,7 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
        struct fuse_conn *fc = get_fuse_conn(inode);
        struct fuse_inode *fi = get_fuse_inode(inode);
        loff_t oldsize;
+       struct timespec old_mtime;
 
        spin_lock(&fc->lock);
        if (attr_version != 0 && fi->attr_version > attr_version) {
@@ -204,15 +205,35 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
                return;
        }
 
+       old_mtime = inode->i_mtime;
        fuse_change_attributes_common(inode, attr, attr_valid);
 
        oldsize = inode->i_size;
        i_size_write(inode, attr->size);
        spin_unlock(&fc->lock);
 
-       if (S_ISREG(inode->i_mode) && oldsize != attr->size) {
-               truncate_pagecache(inode, oldsize, attr->size);
-               invalidate_inode_pages2(inode->i_mapping);
+       if (S_ISREG(inode->i_mode)) {
+               bool inval = false;
+
+               if (oldsize != attr->size) {
+                       truncate_pagecache(inode, oldsize, attr->size);
+                       inval = true;
+               } else if (fc->auto_inval_data) {
+                       struct timespec new_mtime = {
+                               .tv_sec = attr->mtime,
+                               .tv_nsec = attr->mtimensec,
+                       };
+
+                       /*
+                        * Auto inval mode also checks and invalidates if mtime
+                        * has changed.
+                        */
+                       if (!timespec_equal(&old_mtime, &new_mtime))
+                               inval = true;
+               }
+
+               if (inval)
+                       invalidate_inode_pages2(inode->i_mapping);
        }
 }
 
@@ -834,6 +855,8 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
                                fc->big_writes = 1;
                        if (arg->flags & FUSE_DONT_MASK)
                                fc->dont_mask = 1;
+                       if (arg->flags & FUSE_AUTO_INVAL_DATA)
+                               fc->auto_inval_data = 1;
                } else {
                        ra_pages = fc->max_read / PAGE_CACHE_SIZE;
                        fc->no_lock = 1;
@@ -859,7 +882,8 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
        arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE;
        arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC |
                FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK |
-               FUSE_FLOCK_LOCKS;
+               FUSE_SPLICE_WRITE | FUSE_SPLICE_MOVE | FUSE_SPLICE_READ |
+               FUSE_FLOCK_LOCKS | FUSE_IOCTL_DIR | FUSE_AUTO_INVAL_DATA;
        req->in.h.opcode = FUSE_INIT;
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(*arg);
index 9303348965fbdbc8a8d6d706949b543d54c5609b..d8c713e148e3a5c15fc166e507fe811210872027 100644 (file)
@@ -57,6 +57,9 @@
  *
  * 7.19
  *  - add FUSE_FALLOCATE
+ *
+ * 7.20
+ *  - add FUSE_AUTO_INVAL_DATA
  */
 
 #ifndef _LINUX_FUSE_H
@@ -88,7 +91,7 @@
 #define FUSE_KERNEL_VERSION 7
 
 /** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 19
+#define FUSE_KERNEL_MINOR_VERSION 20
 
 /** The node ID of the root inode */
 #define FUSE_ROOT_ID 1
@@ -163,10 +166,19 @@ struct fuse_file_lock {
 /**
  * INIT request/reply flags
  *
+ * FUSE_ASYNC_READ: asynchronous read requests
  * FUSE_POSIX_LOCKS: remote locking for POSIX file locks
+ * FUSE_FILE_OPS: kernel sends file handle for fstat, etc... (not yet supported)
+ * FUSE_ATOMIC_O_TRUNC: handles the O_TRUNC open flag in the filesystem
  * FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".."
+ * FUSE_BIG_WRITES: filesystem can handle write size larger than 4kB
  * FUSE_DONT_MASK: don't apply umask to file mode on create operations
+ * FUSE_SPLICE_WRITE: kernel supports splice write on the device
+ * FUSE_SPLICE_MOVE: kernel supports splice move on the device
+ * FUSE_SPLICE_READ: kernel supports splice read on the device
  * FUSE_FLOCK_LOCKS: remote locking for BSD style file locks
+ * FUSE_HAS_IOCTL_DIR: kernel supports ioctl on directories
+ * FUSE_AUTO_INVAL_DATA: automatically invalidate cached pages
  */
 #define FUSE_ASYNC_READ                (1 << 0)
 #define FUSE_POSIX_LOCKS       (1 << 1)
@@ -175,7 +187,12 @@ struct fuse_file_lock {
 #define FUSE_EXPORT_SUPPORT    (1 << 4)
 #define FUSE_BIG_WRITES                (1 << 5)
 #define FUSE_DONT_MASK         (1 << 6)
+#define FUSE_SPLICE_WRITE      (1 << 7)
+#define FUSE_SPLICE_MOVE       (1 << 8)
+#define FUSE_SPLICE_READ       (1 << 9)
 #define FUSE_FLOCK_LOCKS       (1 << 10)
+#define FUSE_HAS_IOCTL_DIR     (1 << 11)
+#define FUSE_AUTO_INVAL_DATA   (1 << 12)
 
 /**
  * CUSE INIT request/reply flags