int afs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
                struct iattr *attr)
 {
+       const unsigned int supported =
+               ATTR_SIZE | ATTR_MODE | ATTR_UID | ATTR_GID |
+               ATTR_MTIME | ATTR_MTIME_SET | ATTR_TIMES_SET | ATTR_TOUCH;
        struct afs_operation *op;
        struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry));
+       struct inode *inode = &vnode->vfs_inode;
+       loff_t i_size;
        int ret;
 
        _enter("{%llx:%llu},{n=%pd},%x",
               vnode->fid.vid, vnode->fid.vnode, dentry,
               attr->ia_valid);
 
-       if (!(attr->ia_valid & (ATTR_SIZE | ATTR_MODE | ATTR_UID | ATTR_GID |
-                               ATTR_MTIME | ATTR_MTIME_SET | ATTR_TIMES_SET |
-                               ATTR_TOUCH))) {
+       if (!(attr->ia_valid & supported)) {
                _leave(" = 0 [unsupported]");
                return 0;
        }
 
+       i_size = i_size_read(inode);
        if (attr->ia_valid & ATTR_SIZE) {
-               if (!S_ISREG(vnode->vfs_inode.i_mode))
+               if (!S_ISREG(inode->i_mode))
                        return -EISDIR;
 
-               ret = inode_newsize_ok(&vnode->vfs_inode, attr->ia_size);
+               ret = inode_newsize_ok(inode, attr->ia_size);
                if (ret)
                        return ret;
 
-               if (attr->ia_size == i_size_read(&vnode->vfs_inode))
+               if (attr->ia_size == i_size)
                        attr->ia_valid &= ~ATTR_SIZE;
        }
 
        fscache_use_cookie(afs_vnode_cache(vnode), true);
 
-       /* flush any dirty data outstanding on a regular file */
-       if (S_ISREG(vnode->vfs_inode.i_mode))
-               filemap_write_and_wait(vnode->vfs_inode.i_mapping);
-
        /* Prevent any new writebacks from starting whilst we do this. */
        down_write(&vnode->validate_lock);
 
+       if ((attr->ia_valid & ATTR_SIZE) && S_ISREG(inode->i_mode)) {
+               loff_t size = attr->ia_size;
+
+               /* Wait for any outstanding writes to the server to complete */
+               loff_t from = min(size, i_size);
+               loff_t to = max(size, i_size);
+               ret = filemap_fdatawait_range(inode->i_mapping, from, to);
+               if (ret < 0)
+                       goto out_unlock;
+
+               /* Don't talk to the server if we're just shortening in-memory
+                * writes that haven't gone to the server yet.
+                */
+               if (!(attr->ia_valid & (supported & ~ATTR_SIZE & ~ATTR_MTIME)) &&
+                   attr->ia_size < i_size &&
+                   attr->ia_size > vnode->status.size) {
+                       truncate_pagecache(inode, attr->ia_size);
+                       fscache_resize_cookie(afs_vnode_cache(vnode),
+                                             attr->ia_size);
+                       i_size_write(inode, attr->ia_size);
+                       ret = 0;
+                       goto out_unlock;
+               }
+       }
+
        op = afs_alloc_operation(((attr->ia_valid & ATTR_FILE) ?
                                  afs_file_key(attr->ia_file) : NULL),
                                 vnode->volume);