]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 4 Apr 2014 22:34:27 +0000 (15:34 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 4 Apr 2014 22:34:27 +0000 (15:34 -0700)
Pull fuse update from Miklos Szeredi:
 "This series adds cached writeback support to fuse, improving write
  throughput"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
  fuse: fix "uninitialized variable" warning
  fuse: Turn writeback cache on
  fuse: Fix O_DIRECT operations vs cached writeback misorder
  fuse: fuse_flush() should wait on writeback
  fuse: Implement write_begin/write_end callbacks
  fuse: restructure fuse_readpage()
  fuse: Flush files on wb close
  fuse: Trust kernel i_mtime only
  fuse: Trust kernel i_size only
  fuse: Connection bit for enabling writeback
  fuse: Prepare to handle short reads
  fuse: Linking file to inode helper

1  2 
fs/fuse/inode.c

diff --combined fs/fuse/inode.c
index 9c761b611c5418b1fcc8b08d7b144a3a1689cdf0,9ba191917415036dd49130be3be8568756e387cb..b4bff1b15028ff3fb99e33521517acb38f355177
@@@ -123,7 -123,7 +123,7 @@@ static void fuse_destroy_inode(struct i
  
  static void fuse_evict_inode(struct inode *inode)
  {
 -      truncate_inode_pages(&inode->i_data, 0);
 +      truncate_inode_pages_final(&inode->i_data);
        clear_inode(inode);
        if (inode->i_sb->s_flags & MS_ACTIVE) {
                struct fuse_conn *fc = get_fuse_conn(inode);
@@@ -170,8 -170,11 +170,11 @@@ void fuse_change_attributes_common(stru
        inode->i_blocks  = attr->blocks;
        inode->i_atime.tv_sec   = attr->atime;
        inode->i_atime.tv_nsec  = attr->atimensec;
-       inode->i_mtime.tv_sec   = attr->mtime;
-       inode->i_mtime.tv_nsec  = attr->mtimensec;
+       /* mtime from server may be stale due to local buffered write */
+       if (!fc->writeback_cache || !S_ISREG(inode->i_mode)) {
+               inode->i_mtime.tv_sec   = attr->mtime;
+               inode->i_mtime.tv_nsec  = attr->mtimensec;
+       }
        inode->i_ctime.tv_sec   = attr->ctime;
        inode->i_ctime.tv_nsec  = attr->ctimensec;
  
@@@ -197,6 -200,7 +200,7 @@@ void fuse_change_attributes(struct inod
  {
        struct fuse_conn *fc = get_fuse_conn(inode);
        struct fuse_inode *fi = get_fuse_inode(inode);
+       bool is_wb = fc->writeback_cache;
        loff_t oldsize;
        struct timespec old_mtime;
  
        fuse_change_attributes_common(inode, attr, attr_valid);
  
        oldsize = inode->i_size;
-       i_size_write(inode, attr->size);
+       /*
+        * In case of writeback_cache enabled, the cached writes beyond EOF
+        * extend local i_size without keeping userspace server in sync. So,
+        * attr->size coming from server can be stale. We cannot trust it.
+        */
+       if (!is_wb || !S_ISREG(inode->i_mode))
+               i_size_write(inode, attr->size);
        spin_unlock(&fc->lock);
  
-       if (S_ISREG(inode->i_mode)) {
+       if (!is_wb && S_ISREG(inode->i_mode)) {
                bool inval = false;
  
                if (oldsize != attr->size) {
@@@ -243,6 -253,8 +253,8 @@@ static void fuse_init_inode(struct inod
  {
        inode->i_mode = attr->mode & S_IFMT;
        inode->i_size = attr->size;
+       inode->i_mtime.tv_sec  = attr->mtime;
+       inode->i_mtime.tv_nsec = attr->mtimensec;
        if (S_ISREG(inode->i_mode)) {
                fuse_init_common(inode);
                fuse_init_file_inode(inode);
@@@ -289,7 -301,9 +301,9 @@@ struct inode *fuse_iget(struct super_bl
                return NULL;
  
        if ((inode->i_state & I_NEW)) {
-               inode->i_flags |= S_NOATIME|S_NOCMTIME;
+               inode->i_flags |= S_NOATIME;
+               if (!fc->writeback_cache || !S_ISREG(inode->i_mode))
+                       inode->i_flags |= S_NOCMTIME;
                inode->i_generation = generation;
                inode->i_data.backing_dev_info = &fc->bdi;
                fuse_init_inode(inode, attr);
@@@ -873,6 -887,8 +887,8 @@@ static void process_init_reply(struct f
                        }
                        if (arg->flags & FUSE_ASYNC_DIO)
                                fc->async_dio = 1;
+                       if (arg->flags & FUSE_WRITEBACK_CACHE)
+                               fc->writeback_cache = 1;
                } else {
                        ra_pages = fc->max_read / PAGE_CACHE_SIZE;
                        fc->no_lock = 1;
@@@ -900,7 -916,8 +916,8 @@@ static void fuse_send_init(struct fuse_
                FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK |
                FUSE_SPLICE_WRITE | FUSE_SPLICE_MOVE | FUSE_SPLICE_READ |
                FUSE_FLOCK_LOCKS | FUSE_IOCTL_DIR | FUSE_AUTO_INVAL_DATA |
-               FUSE_DO_READDIRPLUS | FUSE_READDIRPLUS_AUTO | FUSE_ASYNC_DIO;
+               FUSE_DO_READDIRPLUS | FUSE_READDIRPLUS_AUTO | FUSE_ASYNC_DIO |
+               FUSE_WRITEBACK_CACHE;
        req->in.h.opcode = FUSE_INIT;
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(*arg);