Merge branch 'afs-dh' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 12 Apr 2018 18:59:06 +0000 (11:59 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 12 Apr 2018 18:59:06 +0000 (11:59 -0700)
Pull AFS updates from Al Viro:
 "The AFS series posted by dhowells depended upon lookup_one_len()
  rework; now that prereq is in the mainline, that series had been
  rebased on top of it and got some exposure and testing..."

* 'afs-dh' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  afs: Do better accretion of small writes on newly created content
  afs: Add stats for data transfer operations
  afs: Trace protocol errors
  afs: Locally edit directory data for mkdir/create/unlink/...
  afs: Adjust the directory XDR structures
  afs: Split the directory content defs into a header
  afs: Fix directory handling
  afs: Split the dynroot stuff out and give it its own ops tables
  afs: Keep track of invalid-before version for dentry coherency
  afs: Rearrange status mapping
  afs: Make it possible to get the data version in readpage
  afs: Init inode before accessing cache
  afs: Introduce a statistics proc file
  afs: Dump bad status record
  afs: Implement @cell substitution handling
  afs: Implement @sys substitution handling
  afs: Prospectively look up extra files when doing a single lookup
  afs: Don't over-increment the cell usage count when pinning it
  afs: Fix checker warnings
  vfs: Remove the const from dir_context::actor

1  2 
fs/afs/write.c
include/linux/fs.h

diff --combined fs/afs/write.c
index dbc3c0b0142db59b1c91707abf0f2e6185d46a51,160f6cc26c008a1c906211288178fb9176e5066c..c164698dc30481156eb9738e0c3f1b91d5ab5108
@@@ -42,10 -42,11 +42,11 @@@ static int afs_fill_page(struct afs_vno
        if (!req)
                return -ENOMEM;
  
-       atomic_set(&req->usage, 1);
+       refcount_set(&req->usage, 1);
        req->pos = pos;
        req->len = len;
        req->nr_pages = 1;
+       req->pages = req->array;
        req->pages[0] = page;
        get_page(page);
  
@@@ -124,7 -125,12 +125,12 @@@ try_again
                                             page->index, priv);
                        goto flush_conflicting_write;
                }
-               if (to < f || from > t)
+               /* If the file is being filled locally, allow inter-write
+                * spaces to be merged into writes.  If it's not, only write
+                * back what the user gives us.
+                */
+               if (!test_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags) &&
+                   (to < f || from > t))
                        goto flush_conflicting_write;
                if (from < f)
                        f = from;
@@@ -355,6 -361,12 +361,12 @@@ found_key
        }
  
        switch (ret) {
+       case 0:
+               afs_stat_v(vnode, n_stores);
+               atomic_long_add((last * PAGE_SIZE + to) -
+                               (first * PAGE_SIZE + offset),
+                               &afs_v2net(vnode)->n_store_bytes);
+               break;
        case -EACCES:
        case -EPERM:
        case -ENOKEY:
@@@ -412,7 -424,8 +424,8 @@@ static int afs_write_back_from_locked_p
                trace_afs_page_dirty(vnode, tracepoint_string("WARN"),
                                     primary_page->index, priv);
  
-       if (start >= final_page || to < PAGE_SIZE)
+       if (start >= final_page ||
+           (to < PAGE_SIZE && !test_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags)))
                goto no_more;
  
        start++;
                }
  
                for (loop = 0; loop < n; loop++) {
-                       if (to != PAGE_SIZE)
-                               break;
                        page = pages[loop];
+                       if (to != PAGE_SIZE &&
+                           !test_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags))
+                               break;
                        if (page->index > final_page)
                                break;
                        if (!trylock_page(page))
                        priv = page_private(page);
                        f = priv & AFS_PRIV_MAX;
                        t = priv >> AFS_PRIV_SHIFT;
-                       if (f != 0) {
+                       if (f != 0 &&
+                           !test_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags)) {
                                unlock_page(page);
                                break;
                        }
@@@ -570,11 -585,10 +585,11 @@@ static int afs_writepages_region(struc
  
                _debug("wback %lx", page->index);
  
 -              /* at this point we hold neither mapping->tree_lock nor lock on
 -               * the page itself: the page may be truncated or invalidated
 -               * (changing page->mapping to NULL), or even swizzled back from
 -               * swapper_space to tmpfs file mapping
 +              /*
 +               * at this point we hold neither the i_pages lock nor the
 +               * page lock: the page may be truncated or invalidated
 +               * (changing page->mapping to NULL), or even swizzled
 +               * back from swapper_space to tmpfs file mapping
                 */
                ret = lock_page_killable(page);
                if (ret < 0) {
@@@ -734,20 -748,6 +749,6 @@@ int afs_fsync(struct file *file, loff_
        return file_write_and_wait_range(file, start, end);
  }
  
- /*
-  * Flush out all outstanding writes on a file opened for writing when it is
-  * closed.
-  */
- int afs_flush(struct file *file, fl_owner_t id)
- {
-       _enter("");
-       if ((file->f_mode & FMODE_WRITE) == 0)
-               return 0;
-       return vfs_fsync(file, 0);
- }
  /*
   * notification that a previously read-only page is about to become writable
   * - if it returns an error, the caller will deliver a bus error signal
diff --combined include/linux/fs.h
index 92efaf1f89775f7b017477617dd983c10e0dc4d2,3a5c19d9f651aab263f44703001cba8b9a77ca58..5d93995743b5be6d3809ef9d893646a65f496356
@@@ -13,7 -13,6 +13,7 @@@
  #include <linux/list_lru.h>
  #include <linux/llist.h>
  #include <linux/radix-tree.h>
 +#include <linux/xarray.h>
  #include <linux/rbtree.h>
  #include <linux/init.h>
  #include <linux/pid.h>
@@@ -391,11 -390,12 +391,11 @@@ int pagecache_write_end(struct file *, 
  
  struct address_space {
        struct inode            *host;          /* owner: inode, block_device */
 -      struct radix_tree_root  page_tree;      /* radix tree of all pages */
 -      spinlock_t              tree_lock;      /* and lock protecting it */
 +      struct radix_tree_root  i_pages;        /* cached pages */
        atomic_t                i_mmap_writable;/* count VM_SHARED mappings */
        struct rb_root_cached   i_mmap;         /* tree of private and shared mappings */
        struct rw_semaphore     i_mmap_rwsem;   /* protect tree, count, list */
 -      /* Protected by tree_lock together with the radix tree */
 +      /* Protected by the i_pages lock */
        unsigned long           nrpages;        /* number of total pages */
        /* number of shadow or DAX exceptional entries */
        unsigned long           nrexceptional;
@@@ -1667,7 -1667,7 +1667,7 @@@ typedef int (*filldir_t)(struct dir_con
                         unsigned);
  
  struct dir_context {
-       const filldir_t actor;
+       filldir_t actor;
        loff_t pos;
  };
  
@@@ -1989,7 -1989,7 +1989,7 @@@ static inline void init_sync_kiocb(stru
   *
   * I_WB_SWITCH                Cgroup bdi_writeback switching in progress.  Used to
   *                    synchronize competing switching instances and to tell
 - *                    wb stat updates to grab mapping->tree_lock.  See
 + *                    wb stat updates to grab the i_pages lock.  See
   *                    inode_switch_wb_work_fn() for details.
   *
   * I_OVL_INUSE                Used by overlayfs to get exclusive ownership on upper
@@@ -3127,10 -3127,6 +3127,10 @@@ extern int simple_rmdir(struct inode *
  extern int simple_rename(struct inode *, struct dentry *,
                         struct inode *, struct dentry *, unsigned int);
  extern int noop_fsync(struct file *, loff_t, loff_t, int);
 +extern int noop_set_page_dirty(struct page *page);
 +extern void noop_invalidatepage(struct page *page, unsigned int offset,
 +              unsigned int length);
 +extern ssize_t noop_direct_IO(struct kiocb *iocb, struct iov_iter *iter);
  extern int simple_empty(struct dentry *);
  extern int simple_readpage(struct file *file, struct page *page);
  extern int simple_write_begin(struct file *file, struct address_space *mapping,