Merge tag 'nfs-for-4.17-1' of git://git.linux-nfs.org/projects/anna/linux-nfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 12 Apr 2018 19:55:50 +0000 (12:55 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 12 Apr 2018 19:55:50 +0000 (12:55 -0700)
Pull NFS client updates from Anna Schumaker:
 "Stable bugfixes:
   - xprtrdma: Fix corner cases when handling device removal # v4.12+
   - xprtrdma: Fix latency regression on NUMA NFS/RDMA clients # v4.15+

  Features:
   - New sunrpc tracepoint for RPC pings
   - Finer grained NFSv4 attribute checking
   - Don't unnecessarily return NFS v4 delegations

  Other bugfixes and cleanups:
   - Several other small NFSoRDMA cleanups
   - Improvements to the sunrpc RTT measurements
   - A few sunrpc tracepoint cleanups
   - Various fixes for NFS v4 lock notifications
   - Various sunrpc and NFS v4 XDR encoding cleanups
   - Switch to the ida_simple API
   - Fix NFSv4.1 exclusive create
   - Forget acl cache after setattr operation
   - Don't advance the nfs_entry readdir cookie if xdr decoding fails"

* tag 'nfs-for-4.17-1' of git://git.linux-nfs.org/projects/anna/linux-nfs: (47 commits)
  NFS: advance nfs_entry cookie only after decoding completes successfully
  NFSv3/acl: forget acl cache after setattr
  NFSv4.1: Fix exclusive create
  NFSv4: Declare the size up to date after it was set.
  nfs: Use ida_simple API
  NFSv4: Fix the nfs_inode_set_delegation() arguments
  NFSv4: Clean up CB_GETATTR encoding
  NFSv4: Don't ask for attributes when ACCESS is protected by a delegation
  NFSv4: Add a helper to encode/decode struct timespec
  NFSv4: Clean up encode_attrs
  NFSv4; Clean up XDR encoding of type bitmap4
  NFSv4: Allow GFP_NOIO sleeps in decode_attr_owner/decode_attr_group
  SUNRPC: Add a helper for encoding opaque data inline
  SUNRPC: Add helpers for decoding opaque and string types
  NFSv4: Ignore change attribute invalidations if we hold a delegation
  NFS: More fine grained attribute tracking
  NFS: Don't force unnecessary cache invalidation in nfs_update_inode()
  NFS: Don't redirty the attribute cache in nfs_wcc_update_inode()
  NFS: Don't force a revalidation of all attributes if change is missing
  NFS: Convert NFS_INO_INVALID flags to unsigned long
  ...

1  2 
fs/nfs/inode.c
fs/nfs/nfs4xdr.c
fs/nfs/write.c
include/trace/events/sunrpc.h
net/sunrpc/clnt.c
net/sunrpc/xprtsock.c

diff --combined fs/nfs/inode.c
index d17a90c4fa3733495b9b81e08cc343fba2fc967f,ba73eda0600e1e58cb796b0021f6dd535c6f577e..bd15d0b5762665b4f50be2c7a07c513b6891c635
@@@ -85,6 -85,11 +85,6 @@@ int nfs_wait_bit_killable(struct wait_b
  }
  EXPORT_SYMBOL_GPL(nfs_wait_bit_killable);
  
 -int nfs_wait_atomic_killable(atomic_t *p, unsigned int mode)
 -{
 -      return nfs_wait_killable(mode);
 -}
 -
  /**
   * nfs_compat_user_ino64 - returns the user-visible inode number
   * @fileid: 64-bit fileid
@@@ -195,7 -200,10 +195,10 @@@ bool nfs_check_cache_invalid(struct ino
  static void nfs_set_cache_invalid(struct inode *inode, unsigned long flags)
  {
        struct nfs_inode *nfsi = NFS_I(inode);
+       bool have_delegation = nfs_have_delegated_attributes(inode);
  
+       if (have_delegation)
+               flags &= ~(NFS_INO_INVALID_CHANGE|NFS_INO_REVAL_PAGECACHE);
        if (inode->i_mapping->nrpages == 0)
                flags &= ~NFS_INO_INVALID_DATA;
        nfsi->cache_validity |= flags;
@@@ -447,7 -455,7 +450,7 @@@ nfs_fhget(struct super_block *sb, struc
                inode->i_mode = fattr->mode;
                if ((fattr->valid & NFS_ATTR_FATTR_MODE) == 0
                                && nfs_server_capable(inode, NFS_CAP_MODE))
-                       nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR);
+                       nfs_set_cache_invalid(inode, NFS_INO_INVALID_OTHER);
                /* Why so? Because we want revalidate for devices/FIFOs, and
                 * that's precisely what we have in nfs_file_inode_operations.
                 */
                if (fattr->valid & NFS_ATTR_FATTR_ATIME)
                        inode->i_atime = fattr->atime;
                else if (nfs_server_capable(inode, NFS_CAP_ATIME))
-                       nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR);
+                       nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATIME);
                if (fattr->valid & NFS_ATTR_FATTR_MTIME)
                        inode->i_mtime = fattr->mtime;
                else if (nfs_server_capable(inode, NFS_CAP_MTIME))
-                       nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR);
+                       nfs_set_cache_invalid(inode, NFS_INO_INVALID_MTIME);
                if (fattr->valid & NFS_ATTR_FATTR_CTIME)
                        inode->i_ctime = fattr->ctime;
                else if (nfs_server_capable(inode, NFS_CAP_CTIME))
-                       nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR);
+                       nfs_set_cache_invalid(inode, NFS_INO_INVALID_CTIME);
                if (fattr->valid & NFS_ATTR_FATTR_CHANGE)
                        inode_set_iversion_raw(inode, fattr->change_attr);
                else
-                       nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR
-                               | NFS_INO_REVAL_PAGECACHE);
+                       nfs_set_cache_invalid(inode, NFS_INO_INVALID_CHANGE);
                if (fattr->valid & NFS_ATTR_FATTR_SIZE)
                        inode->i_size = nfs_size_to_loff_t(fattr->size);
                else
-                       nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR
-                               | NFS_INO_REVAL_PAGECACHE);
+                       nfs_set_cache_invalid(inode, NFS_INO_INVALID_SIZE);
                if (fattr->valid & NFS_ATTR_FATTR_NLINK)
                        set_nlink(inode, fattr->nlink);
                else if (nfs_server_capable(inode, NFS_CAP_NLINK))
-                       nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR);
+                       nfs_set_cache_invalid(inode, NFS_INO_INVALID_OTHER);
                if (fattr->valid & NFS_ATTR_FATTR_OWNER)
                        inode->i_uid = fattr->uid;
                else if (nfs_server_capable(inode, NFS_CAP_OWNER))
-                       nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR);
+                       nfs_set_cache_invalid(inode, NFS_INO_INVALID_OTHER);
                if (fattr->valid & NFS_ATTR_FATTR_GROUP)
                        inode->i_gid = fattr->gid;
                else if (nfs_server_capable(inode, NFS_CAP_OWNER_GROUP))
-                       nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR);
+                       nfs_set_cache_invalid(inode, NFS_INO_INVALID_OTHER);
                if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED)
                        inode->i_blocks = fattr->du.nfs2.blocks;
                if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) {
@@@ -608,11 -614,6 +609,6 @@@ nfs_setattr(struct dentry *dentry, stru
                goto out;
        }
  
-       /*
-        * Return any delegations if we're going to change ACLs
-        */
-       if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0)
-               NFS_PROTO(inode)->return_delegation(inode);
        error = NFS_PROTO(inode)->setattr(dentry, fattr, attr);
        if (error == 0)
                error = nfs_refresh_inode(inode, fattr);
@@@ -645,6 -646,7 +641,7 @@@ static int nfs_vmtruncate(struct inode 
        /* Optimisation */
        if (offset == 0)
                NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_DATA;
+       NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_SIZE;
  
        spin_unlock(&inode->i_lock);
        truncate_pagecache(inode, offset);
@@@ -657,6 -659,7 +654,7 @@@ out
   * nfs_setattr_update_inode - Update inode metadata after a setattr call.
   * @inode: pointer to struct inode
   * @attr: pointer to struct iattr
+  * @fattr: pointer to struct nfs_fattr
   *
   * Note: we do this in the *proc.c in order to ensure that
   *       it works for things like exclusive creates too.
@@@ -669,6 -672,8 +667,8 @@@ void nfs_setattr_update_inode(struct in
  
        spin_lock(&inode->i_lock);
        NFS_I(inode)->attr_gencount = fattr->gencount;
+       nfs_set_cache_invalid(inode, NFS_INO_INVALID_CHANGE
+                       | NFS_INO_INVALID_CTIME);
        if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) {
                if ((attr->ia_valid & ATTR_MODE) != 0) {
                        int mode = attr->ia_mode & S_IALLUGO;
                                | NFS_INO_INVALID_ACL);
        }
        if ((attr->ia_valid & ATTR_SIZE) != 0) {
+               nfs_set_cache_invalid(inode, NFS_INO_INVALID_MTIME);
                nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC);
                nfs_vmtruncate(inode, attr->ia_size);
        }
        if (fattr->valid)
                nfs_update_inode(inode, fattr);
-       else
-               NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATTR;
        spin_unlock(&inode->i_lock);
  }
  EXPORT_SYMBOL_GPL(nfs_setattr_update_inode);
@@@ -1303,24 -1307,20 +1302,20 @@@ static bool nfs_file_has_buffered_write
        return nfs_file_has_writers(nfsi) && nfs_file_io_is_buffered(nfsi);
  }
  
- static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
+ static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
  {
-       unsigned long ret = 0;
        if ((fattr->valid & NFS_ATTR_FATTR_PRECHANGE)
                        && (fattr->valid & NFS_ATTR_FATTR_CHANGE)
                        && inode_eq_iversion_raw(inode, fattr->pre_change_attr)) {
                inode_set_iversion_raw(inode, fattr->change_attr);
                if (S_ISDIR(inode->i_mode))
                        nfs_set_cache_invalid(inode, NFS_INO_INVALID_DATA);
-               ret |= NFS_INO_INVALID_ATTR;
        }
        /* If we have atomic WCC data, we may update some attributes */
        if ((fattr->valid & NFS_ATTR_FATTR_PRECTIME)
                        && (fattr->valid & NFS_ATTR_FATTR_CTIME)
                        && timespec_equal(&inode->i_ctime, &fattr->pre_ctime)) {
                memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
-               ret |= NFS_INO_INVALID_ATTR;
        }
  
        if ((fattr->valid & NFS_ATTR_FATTR_PREMTIME)
                memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
                if (S_ISDIR(inode->i_mode))
                        nfs_set_cache_invalid(inode, NFS_INO_INVALID_DATA);
-               ret |= NFS_INO_INVALID_ATTR;
        }
        if ((fattr->valid & NFS_ATTR_FATTR_PRESIZE)
                        && (fattr->valid & NFS_ATTR_FATTR_SIZE)
                        && i_size_read(inode) == nfs_size_to_loff_t(fattr->pre_size)
                        && !nfs_have_writebacks(inode)) {
                i_size_write(inode, nfs_size_to_loff_t(fattr->size));
-               ret |= NFS_INO_INVALID_ATTR;
        }
-       return ret;
  }
  
  /**
@@@ -1369,33 -1365,41 +1360,41 @@@ static int nfs_check_inode_attributes(s
        if (!nfs_file_has_buffered_writers(nfsi)) {
                /* Verify a few of the more important attributes */
                if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 && !inode_eq_iversion_raw(inode, fattr->change_attr))
-                       invalid |= NFS_INO_INVALID_ATTR | NFS_INO_REVAL_PAGECACHE;
+                       invalid |= NFS_INO_INVALID_CHANGE
+                               | NFS_INO_REVAL_PAGECACHE;
  
                if ((fattr->valid & NFS_ATTR_FATTR_MTIME) && !timespec_equal(&inode->i_mtime, &fattr->mtime))
-                       invalid |= NFS_INO_INVALID_ATTR;
+                       invalid |= NFS_INO_INVALID_MTIME;
  
                if ((fattr->valid & NFS_ATTR_FATTR_CTIME) && !timespec_equal(&inode->i_ctime, &fattr->ctime))
-                       invalid |= NFS_INO_INVALID_ATTR;
+                       invalid |= NFS_INO_INVALID_CTIME;
  
                if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
                        cur_size = i_size_read(inode);
                        new_isize = nfs_size_to_loff_t(fattr->size);
                        if (cur_size != new_isize)
-                               invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
+                               invalid |= NFS_INO_INVALID_SIZE
+                                       | NFS_INO_REVAL_PAGECACHE;
                }
        }
  
        /* Have any file permissions changed? */
        if ((fattr->valid & NFS_ATTR_FATTR_MODE) && (inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO))
-               invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;
+               invalid |= NFS_INO_INVALID_ACCESS
+                       | NFS_INO_INVALID_ACL
+                       | NFS_INO_INVALID_OTHER;
        if ((fattr->valid & NFS_ATTR_FATTR_OWNER) && !uid_eq(inode->i_uid, fattr->uid))
-               invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;
+               invalid |= NFS_INO_INVALID_ACCESS
+                       | NFS_INO_INVALID_ACL
+                       | NFS_INO_INVALID_OTHER;
        if ((fattr->valid & NFS_ATTR_FATTR_GROUP) && !gid_eq(inode->i_gid, fattr->gid))
-               invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;
+               invalid |= NFS_INO_INVALID_ACCESS
+                       | NFS_INO_INVALID_ACL
+                       | NFS_INO_INVALID_OTHER;
  
        /* Has the link count changed? */
        if ((fattr->valid & NFS_ATTR_FATTR_NLINK) && inode->i_nlink != fattr->nlink)
-               invalid |= NFS_INO_INVALID_ATTR;
+               invalid |= NFS_INO_INVALID_OTHER;
  
        if ((fattr->valid & NFS_ATTR_FATTR_ATIME) && !timespec_equal(&inode->i_atime, &fattr->atime))
                invalid |= NFS_INO_INVALID_ATIME;
@@@ -1597,10 -1601,9 +1596,9 @@@ int nfs_refresh_inode(struct inode *ino
  }
  EXPORT_SYMBOL_GPL(nfs_refresh_inode);
  
- static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr *fattr)
+ static int nfs_post_op_update_inode_locked(struct inode *inode,
+               struct nfs_fattr *fattr, unsigned int invalid)
  {
-       unsigned long invalid = NFS_INO_INVALID_ATTR;
        if (S_ISDIR(inode->i_mode))
                invalid |= NFS_INO_INVALID_DATA;
        nfs_set_cache_invalid(inode, invalid);
@@@ -1629,7 -1632,9 +1627,9 @@@ int nfs_post_op_update_inode(struct ino
  
        spin_lock(&inode->i_lock);
        nfs_fattr_set_barrier(fattr);
-       status = nfs_post_op_update_inode_locked(inode, fattr);
+       status = nfs_post_op_update_inode_locked(inode, fattr,
+                       NFS_INO_INVALID_CHANGE
+                       | NFS_INO_INVALID_CTIME);
        spin_unlock(&inode->i_lock);
  
        return status;
@@@ -1681,7 -1686,10 +1681,10 @@@ int nfs_post_op_update_inode_force_wcc_
                fattr->valid |= NFS_ATTR_FATTR_PRESIZE;
        }
  out_noforce:
-       status = nfs_post_op_update_inode_locked(inode, fattr);
+       status = nfs_post_op_update_inode_locked(inode, fattr,
+                       NFS_INO_INVALID_CHANGE
+                       | NFS_INO_INVALID_CTIME
+                       | NFS_INO_INVALID_MTIME);
        return status;
  }
  
@@@ -1789,7 -1797,7 +1792,7 @@@ static int nfs_update_inode(struct inod
                        | NFS_INO_REVAL_PAGECACHE);
  
        /* Do atomic weak cache consistency updates */
-       invalid |= nfs_wcc_update_inode(inode, fattr);
+       nfs_wcc_update_inode(inode, fattr);
  
        if (pnfs_layoutcommit_outstanding(inode)) {
                nfsi->cache_validity |= save_cache_validity & NFS_INO_INVALID_ATTR;
                                        inode->i_sb->s_id, inode->i_ino);
                        /* Could it be a race with writeback? */
                        if (!have_writers) {
-                               invalid |= NFS_INO_INVALID_ATTR
+                               invalid |= NFS_INO_INVALID_CHANGE
                                        | NFS_INO_INVALID_DATA
                                        | NFS_INO_INVALID_ACCESS
                                        | NFS_INO_INVALID_ACL;
+                               /* Force revalidate of all attributes */
+                               save_cache_validity |= NFS_INO_INVALID_CTIME
+                                       | NFS_INO_INVALID_MTIME
+                                       | NFS_INO_INVALID_SIZE
+                                       | NFS_INO_INVALID_OTHER;
                                if (S_ISDIR(inode->i_mode))
                                        nfs_force_lookup_revalidate(inode);
                        }
                        inode_set_iversion_raw(inode, fattr->change_attr);
                }
        } else {
-               nfsi->cache_validity |= save_cache_validity;
+               nfsi->cache_validity |= save_cache_validity &
+                               (NFS_INO_INVALID_CHANGE
+                               | NFS_INO_REVAL_PAGECACHE
+                               | NFS_INO_REVAL_FORCED);
                cache_revalidated = false;
        }
  
                memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
        } else if (server->caps & NFS_CAP_MTIME) {
                nfsi->cache_validity |= save_cache_validity &
-                               (NFS_INO_INVALID_ATTR
+                               (NFS_INO_INVALID_MTIME
                                | NFS_INO_REVAL_FORCED);
                cache_revalidated = false;
        }
                memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
        } else if (server->caps & NFS_CAP_CTIME) {
                nfsi->cache_validity |= save_cache_validity &
-                               (NFS_INO_INVALID_ATTR
+                               (NFS_INO_INVALID_CTIME
                                | NFS_INO_REVAL_FORCED);
                cache_revalidated = false;
        }
                        if (!nfs_have_writebacks(inode) || new_isize > cur_isize) {
                                i_size_write(inode, new_isize);
                                if (!have_writers)
-                                       invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
+                                       invalid |= NFS_INO_INVALID_DATA;
                        }
                        dprintk("NFS: isize change on server for file %s/%ld "
                                        "(%Ld to %Ld)\n",
                }
        } else {
                nfsi->cache_validity |= save_cache_validity &
-                               (NFS_INO_INVALID_ATTR
+                               (NFS_INO_INVALID_SIZE
                                | NFS_INO_REVAL_PAGECACHE
                                | NFS_INO_REVAL_FORCED);
                cache_revalidated = false;
                        umode_t newmode = inode->i_mode & S_IFMT;
                        newmode |= fattr->mode & S_IALLUGO;
                        inode->i_mode = newmode;
-                       invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
+                       invalid |= NFS_INO_INVALID_ACCESS
+                               | NFS_INO_INVALID_ACL
+                               | NFS_INO_INVALID_OTHER;
                }
        } else if (server->caps & NFS_CAP_MODE) {
                nfsi->cache_validity |= save_cache_validity &
-                               (NFS_INO_INVALID_ATTR
-                               | NFS_INO_INVALID_ACCESS
+                               (NFS_INO_INVALID_ACCESS
                                | NFS_INO_INVALID_ACL
+                               | NFS_INO_INVALID_OTHER
                                | NFS_INO_REVAL_FORCED);
                cache_revalidated = false;
        }
  
        if (fattr->valid & NFS_ATTR_FATTR_OWNER) {
                if (!uid_eq(inode->i_uid, fattr->uid)) {
-                       invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
+                       invalid |= NFS_INO_INVALID_ACCESS
+                               | NFS_INO_INVALID_ACL
+                               | NFS_INO_INVALID_OTHER;
                        inode->i_uid = fattr->uid;
                }
        } else if (server->caps & NFS_CAP_OWNER) {
                nfsi->cache_validity |= save_cache_validity &
-                               (NFS_INO_INVALID_ATTR
-                               | NFS_INO_INVALID_ACCESS
+                               (NFS_INO_INVALID_ACCESS
                                | NFS_INO_INVALID_ACL
+                               | NFS_INO_INVALID_OTHER
                                | NFS_INO_REVAL_FORCED);
                cache_revalidated = false;
        }
  
        if (fattr->valid & NFS_ATTR_FATTR_GROUP) {
                if (!gid_eq(inode->i_gid, fattr->gid)) {
-                       invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
+                       invalid |= NFS_INO_INVALID_ACCESS
+                               | NFS_INO_INVALID_ACL
+                               | NFS_INO_INVALID_OTHER;
                        inode->i_gid = fattr->gid;
                }
        } else if (server->caps & NFS_CAP_OWNER_GROUP) {
                nfsi->cache_validity |= save_cache_validity &
-                               (NFS_INO_INVALID_ATTR
-                               | NFS_INO_INVALID_ACCESS
+                               (NFS_INO_INVALID_ACCESS
                                | NFS_INO_INVALID_ACL
+                               | NFS_INO_INVALID_OTHER
                                | NFS_INO_REVAL_FORCED);
                cache_revalidated = false;
        }
  
        if (fattr->valid & NFS_ATTR_FATTR_NLINK) {
                if (inode->i_nlink != fattr->nlink) {
-                       invalid |= NFS_INO_INVALID_ATTR;
+                       invalid |= NFS_INO_INVALID_OTHER;
                        if (S_ISDIR(inode->i_mode))
                                invalid |= NFS_INO_INVALID_DATA;
                        set_nlink(inode, fattr->nlink);
                }
        } else if (server->caps & NFS_CAP_NLINK) {
                nfsi->cache_validity |= save_cache_validity &
-                               (NFS_INO_INVALID_ATTR
+                               (NFS_INO_INVALID_OTHER
                                | NFS_INO_REVAL_FORCED);
                cache_revalidated = false;
        }
  
        /* Update attrtimeo value if we're out of the unstable period */
        if (invalid & NFS_INO_INVALID_ATTR) {
+               invalid &= ~NFS_INO_INVALID_ATTR;
                nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
                nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
                nfsi->attrtimeo_timestamp = now;
                        nfsi->attr_gencount = fattr->gencount;
        }
  
-       /* Don't declare attrcache up to date if there were no attrs! */
-       if (cache_revalidated)
-               invalid &= ~NFS_INO_INVALID_ATTR;
        /* Don't invalidate the data if we were to blame */
        if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
                                || S_ISLNK(inode->i_mode)))
diff --combined fs/nfs/nfs4xdr.c
index b993ad282de2002579255914d8bca14698f16854,aa550fb08d2af3f9f84f7dc4ac9196a753fb8d39..9b73920323211351f14752f3d6c92e627c6fa9ed
@@@ -52,6 -52,7 +52,6 @@@
  #include <linux/nfs.h>
  #include <linux/nfs4.h>
  #include <linux/nfs_fs.h>
 -#include <linux/fs_struct.h>
  
  #include "nfs4_fs.h"
  #include "internal.h"
@@@ -98,6 -99,7 +98,7 @@@ static int nfs4_stat_to_errno(int)
                                ((3+NFS4_FHSIZE) >> 2))
  #define nfs4_fattr_bitmap_maxsz 4
  #define encode_getattr_maxsz    (op_encode_hdr_maxsz + nfs4_fattr_bitmap_maxsz)
+ #define nfstime4_maxsz                (3)
  #define nfs4_name_maxsz               (1 + ((3 + NFS4_MAXNAMLEN) >> 2))
  #define nfs4_path_maxsz               (1 + ((3 + NFS4_MAXPATHLEN) >> 2))
  #define nfs4_owner_maxsz      (1 + XDR_QUADLEN(IDMAP_NAMESZ))
  #define decode_mdsthreshold_maxsz (1 + 1 + nfs4_fattr_bitmap_maxsz + 1 + 8)
  /* This is based on getfattr, which uses the most attributes: */
  #define nfs4_fattr_value_maxsz        (1 + (1 + 2 + 2 + 4 + 2 + 1 + 1 + 2 + 2 + \
-                               3 + 3 + 3 + nfs4_owner_maxsz + \
+                               3*nfstime4_maxsz + \
+                               nfs4_owner_maxsz + \
                                nfs4_group_maxsz + nfs4_label_maxsz + \
                                 decode_mdsthreshold_maxsz))
  #define nfs4_fattr_maxsz      (nfs4_fattr_bitmap_maxsz + \
                                nfs4_owner_maxsz + \
                                nfs4_group_maxsz + \
                                nfs4_label_maxsz + \
-                               4 + 4)
+                               1 + nfstime4_maxsz + \
+                               1 + nfstime4_maxsz)
  #define encode_savefh_maxsz     (op_encode_hdr_maxsz)
  #define decode_savefh_maxsz     (op_decode_hdr_maxsz)
  #define encode_restorefh_maxsz  (op_encode_hdr_maxsz)
@@@ -957,6 -961,35 +960,35 @@@ static void encode_uint64(struct xdr_st
        WARN_ON_ONCE(xdr_stream_encode_u64(xdr, n) < 0);
  }
  
+ static ssize_t xdr_encode_bitmap4(struct xdr_stream *xdr,
+               const __u32 *bitmap, size_t len)
+ {
+       ssize_t ret;
+       /* Trim empty words */
+       while (len > 0 && bitmap[len-1] == 0)
+               len--;
+       ret = xdr_stream_encode_uint32_array(xdr, bitmap, len);
+       if (WARN_ON_ONCE(ret < 0))
+               return ret;
+       return len;
+ }
+ static size_t mask_bitmap4(const __u32 *bitmap, const __u32 *mask,
+               __u32 *res, size_t len)
+ {
+       size_t i;
+       __u32 tmp;
+       while (len > 0 && (bitmap[len-1] == 0 || mask[len-1] == 0))
+               len--;
+       for (i = len; i-- > 0;) {
+               tmp = bitmap[i] & mask[i];
+               res[i] = tmp;
+       }
+       return len;
+ }
  static void encode_nfs4_seqid(struct xdr_stream *xdr,
                const struct nfs_seqid *seqid)
  {
@@@ -1011,6 -1044,14 +1043,14 @@@ static void encode_nfs4_verifier(struc
        encode_opaque_fixed(xdr, verf->data, NFS4_VERIFIER_SIZE);
  }
  
+ static __be32 *
+ xdr_encode_nfstime4(__be32 *p, const struct timespec *t)
+ {
+       p = xdr_encode_hyper(p, (__s64)t->tv_sec);
+       *p++ = cpu_to_be32(t->tv_nsec);
+       return p;
+ }
  static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
                                const struct nfs4_label *label,
                                const umode_t *umask,
        int owner_namelen = 0;
        int owner_grouplen = 0;
        __be32 *p;
-       unsigned i;
        uint32_t len = 0;
-       uint32_t bmval_len;
        uint32_t bmval[3] = { 0 };
  
        /*
        if (attrmask[1] & FATTR4_WORD1_TIME_ACCESS_SET) {
                if (iap->ia_valid & ATTR_ATIME_SET) {
                        bmval[1] |= FATTR4_WORD1_TIME_ACCESS_SET;
-                       len += 16;
+                       len += 4 + (nfstime4_maxsz << 2);
                } else if (iap->ia_valid & ATTR_ATIME) {
                        bmval[1] |= FATTR4_WORD1_TIME_ACCESS_SET;
                        len += 4;
        if (attrmask[1] & FATTR4_WORD1_TIME_MODIFY_SET) {
                if (iap->ia_valid & ATTR_MTIME_SET) {
                        bmval[1] |= FATTR4_WORD1_TIME_MODIFY_SET;
-                       len += 16;
+                       len += 4 + (nfstime4_maxsz << 2);
                } else if (iap->ia_valid & ATTR_MTIME) {
                        bmval[1] |= FATTR4_WORD1_TIME_MODIFY_SET;
                        len += 4;
                bmval[2] |= FATTR4_WORD2_SECURITY_LABEL;
        }
  
-       if (bmval[2] != 0)
-               bmval_len = 3;
-       else if (bmval[1] != 0)
-               bmval_len = 2;
-       else
-               bmval_len = 1;
-       p = reserve_space(xdr, 4 + (bmval_len << 2) + 4 + len);
-       *p++ = cpu_to_be32(bmval_len);
-       for (i = 0; i < bmval_len; i++)
-               *p++ = cpu_to_be32(bmval[i]);
-       *p++ = cpu_to_be32(len);
+       xdr_encode_bitmap4(xdr, bmval, ARRAY_SIZE(bmval));
+       xdr_stream_encode_opaque_inline(xdr, (void **)&p, len);
  
        if (bmval[0] & FATTR4_WORD0_SIZE)
                p = xdr_encode_hyper(p, iap->ia_size);
        if (bmval[1] & FATTR4_WORD1_TIME_ACCESS_SET) {
                if (iap->ia_valid & ATTR_ATIME_SET) {
                        *p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
-                       p = xdr_encode_hyper(p, (s64)iap->ia_atime.tv_sec);
-                       *p++ = cpu_to_be32(iap->ia_atime.tv_nsec);
+                       p = xdr_encode_nfstime4(p, &iap->ia_atime);
                } else
                        *p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
        }
        if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) {
                if (iap->ia_valid & ATTR_MTIME_SET) {
                        *p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
-                       p = xdr_encode_hyper(p, (s64)iap->ia_mtime.tv_sec);
-                       *p++ = cpu_to_be32(iap->ia_mtime.tv_nsec);
+                       p = xdr_encode_nfstime4(p, &iap->ia_mtime);
                } else
                        *p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
        }
@@@ -1199,85 -1225,45 +1224,45 @@@ static void encode_create(struct xdr_st
                        create->server, create->server->attr_bitmask);
  }
  
- static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct compound_hdr *hdr)
- {
-       __be32 *p;
-       encode_op_hdr(xdr, OP_GETATTR, decode_getattr_maxsz, hdr);
-       p = reserve_space(xdr, 8);
-       *p++ = cpu_to_be32(1);
-       *p = cpu_to_be32(bitmap);
- }
- static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1, struct compound_hdr *hdr)
- {
-       __be32 *p;
-       encode_op_hdr(xdr, OP_GETATTR, decode_getattr_maxsz, hdr);
-       p = reserve_space(xdr, 12);
-       *p++ = cpu_to_be32(2);
-       *p++ = cpu_to_be32(bm0);
-       *p = cpu_to_be32(bm1);
- }
- static void
- encode_getattr_three(struct xdr_stream *xdr,
-                    uint32_t bm0, uint32_t bm1, uint32_t bm2,
-                    struct compound_hdr *hdr)
+ static void encode_getattr(struct xdr_stream *xdr,
+               const __u32 *bitmap, const __u32 *mask, size_t len,
+               struct compound_hdr *hdr)
  {
-       __be32 *p;
+       __u32 masked_bitmap[nfs4_fattr_bitmap_maxsz];
  
        encode_op_hdr(xdr, OP_GETATTR, decode_getattr_maxsz, hdr);
-       if (bm2) {
-               p = reserve_space(xdr, 16);
-               *p++ = cpu_to_be32(3);
-               *p++ = cpu_to_be32(bm0);
-               *p++ = cpu_to_be32(bm1);
-               *p = cpu_to_be32(bm2);
-       } else if (bm1) {
-               p = reserve_space(xdr, 12);
-               *p++ = cpu_to_be32(2);
-               *p++ = cpu_to_be32(bm0);
-               *p = cpu_to_be32(bm1);
-       } else {
-               p = reserve_space(xdr, 8);
-               *p++ = cpu_to_be32(1);
-               *p = cpu_to_be32(bm0);
+       if (mask) {
+               if (WARN_ON_ONCE(len > ARRAY_SIZE(masked_bitmap)))
+                       len = ARRAY_SIZE(masked_bitmap);
+               len = mask_bitmap4(bitmap, mask, masked_bitmap, len);
+               bitmap = masked_bitmap;
        }
+       xdr_encode_bitmap4(xdr, bitmap, len);
  }
  
  static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
  {
-       encode_getattr_three(xdr, bitmask[0] & nfs4_fattr_bitmap[0],
-                          bitmask[1] & nfs4_fattr_bitmap[1],
-                          bitmask[2] & nfs4_fattr_bitmap[2],
-                          hdr);
+       encode_getattr(xdr, nfs4_fattr_bitmap, bitmask,
+                       ARRAY_SIZE(nfs4_fattr_bitmap), hdr);
  }
  
  static void encode_getfattr_open(struct xdr_stream *xdr, const u32 *bitmask,
                                 const u32 *open_bitmap,
                                 struct compound_hdr *hdr)
  {
-       encode_getattr_three(xdr,
-                            bitmask[0] & open_bitmap[0],
-                            bitmask[1] & open_bitmap[1],
-                            bitmask[2] & open_bitmap[2],
-                            hdr);
+       encode_getattr(xdr, open_bitmap, bitmask, 3, hdr);
  }
  
  static void encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
  {
-       encode_getattr_three(xdr,
-                            bitmask[0] & nfs4_fsinfo_bitmap[0],
-                            bitmask[1] & nfs4_fsinfo_bitmap[1],
-                            bitmask[2] & nfs4_fsinfo_bitmap[2],
-                            hdr);
+       encode_getattr(xdr, nfs4_fsinfo_bitmap, bitmask,
+                       ARRAY_SIZE(nfs4_fsinfo_bitmap), hdr);
  }
  
  static void encode_fs_locations(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
  {
-       encode_getattr_two(xdr, bitmask[0] & nfs4_fs_locations_bitmap[0],
-                          bitmask[1] & nfs4_fs_locations_bitmap[1], hdr);
+       encode_getattr(xdr, nfs4_fs_locations_bitmap, bitmask,
+                       ARRAY_SIZE(nfs4_fs_locations_bitmap), hdr);
  }
  
  static void encode_getfh(struct xdr_stream *xdr, struct compound_hdr *hdr)
@@@ -2116,7 -2102,8 +2101,8 @@@ static void nfs4_xdr_enc_access(struct 
        encode_sequence(xdr, &args->seq_args, &hdr);
        encode_putfh(xdr, args->fh, &hdr);
        encode_access(xdr, args->access, &hdr);
-       encode_getfattr(xdr, args->bitmask, &hdr);
+       if (args->bitmask)
+               encode_getfattr(xdr, args->bitmask, &hdr);
        encode_nops(&hdr);
  }
  
@@@ -2558,13 -2545,17 +2544,17 @@@ static void nfs4_xdr_enc_getacl(struct 
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
+       const __u32 nfs4_acl_bitmap[1] = {
+               [0] = FATTR4_WORD0_ACL,
+       };
        uint32_t replen;
  
        encode_compound_hdr(xdr, req, &hdr);
        encode_sequence(xdr, &args->seq_args, &hdr);
        encode_putfh(xdr, args->fh, &hdr);
        replen = hdr.replen + op_decode_hdr_maxsz;
-       encode_getattr_two(xdr, FATTR4_WORD0_ACL, 0, &hdr);
+       encode_getattr(xdr, nfs4_acl_bitmap, NULL,
+                       ARRAY_SIZE(nfs4_acl_bitmap), &hdr);
  
        xdr_inline_pages(&req->rq_rcv_buf, replen << 2,
                args->acl_pages, 0, args->acl_len);
@@@ -2643,8 -2634,8 +2633,8 @@@ static void nfs4_xdr_enc_pathconf(struc
        encode_compound_hdr(xdr, req, &hdr);
        encode_sequence(xdr, &args->seq_args, &hdr);
        encode_putfh(xdr, args->fh, &hdr);
-       encode_getattr_one(xdr, args->bitmask[0] & nfs4_pathconf_bitmap[0],
-                          &hdr);
+       encode_getattr(xdr, nfs4_pathconf_bitmap, args->bitmask,
+                       ARRAY_SIZE(nfs4_pathconf_bitmap), &hdr);
        encode_nops(&hdr);
  }
  
@@@ -2662,8 -2653,8 +2652,8 @@@ static void nfs4_xdr_enc_statfs(struct 
        encode_compound_hdr(xdr, req, &hdr);
        encode_sequence(xdr, &args->seq_args, &hdr);
        encode_putfh(xdr, args->fh, &hdr);
-       encode_getattr_two(xdr, args->bitmask[0] & nfs4_statfs_bitmap[0],
-                          args->bitmask[1] & nfs4_statfs_bitmap[1], &hdr);
+       encode_getattr(xdr, nfs4_statfs_bitmap, args->bitmask,
+                       ARRAY_SIZE(nfs4_statfs_bitmap), &hdr);
        encode_nops(&hdr);
  }
  
@@@ -2683,7 -2674,7 +2673,7 @@@ static void nfs4_xdr_enc_server_caps(st
        encode_compound_hdr(xdr, req, &hdr);
        encode_sequence(xdr, &args->seq_args, &hdr);
        encode_putfh(xdr, args->fhandle, &hdr);
-       encode_getattr_three(xdr, bitmask[0], bitmask[1], bitmask[2], &hdr);
+       encode_getattr(xdr, bitmask, NULL, 3, &hdr);
        encode_nops(&hdr);
  }
  
@@@ -3217,34 -3208,27 +3207,27 @@@ static int decode_ace(struct xdr_strea
        return -EIO;
  }
  
- static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
+ static ssize_t
+ decode_bitmap4(struct xdr_stream *xdr, uint32_t *bitmap, size_t sz)
  {
-       uint32_t bmlen;
-       __be32 *p;
-       p = xdr_inline_decode(xdr, 4);
-       if (unlikely(!p))
-               goto out_overflow;
-       bmlen = be32_to_cpup(p);
+       ssize_t ret;
  
-       bitmap[0] = bitmap[1] = bitmap[2] = 0;
-       p = xdr_inline_decode(xdr, (bmlen << 2));
-       if (unlikely(!p))
-               goto out_overflow;
-       if (bmlen > 0) {
-               bitmap[0] = be32_to_cpup(p++);
-               if (bmlen > 1) {
-                       bitmap[1] = be32_to_cpup(p++);
-                       if (bmlen > 2)
-                               bitmap[2] = be32_to_cpup(p);
-               }
-       }
-       return 0;
- out_overflow:
+       ret = xdr_stream_decode_uint32_array(xdr, bitmap, sz);
+       if (likely(ret >= 0))
+               return ret;
+       if (ret == -EMSGSIZE)
+               return sz;
        print_overflow_msg(__func__, xdr);
        return -EIO;
  }
  
+ static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
+ {
+       ssize_t ret;
+       ret = decode_bitmap4(xdr, bitmap, 3);
+       return ret < 0 ? ret : 0;
+ }
  static int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, unsigned int *savep)
  {
        __be32 *p;
@@@ -3980,7 -3964,7 +3963,7 @@@ static int decode_attr_owner(struct xdr
        bitmap[1] &= ~FATTR4_WORD1_OWNER;
  
        if (owner_name != NULL) {
-               len = decode_nfs4_string(xdr, owner_name, GFP_NOWAIT);
+               len = decode_nfs4_string(xdr, owner_name, GFP_NOIO);
                if (len <= 0)
                        goto out;
                dprintk("%s: name=%s\n", __func__, owner_name->data);
@@@ -4015,7 -3999,7 +3998,7 @@@ static int decode_attr_group(struct xdr
        bitmap[1] &= ~FATTR4_WORD1_OWNER_GROUP;
  
        if (group_name != NULL) {
-               len = decode_nfs4_string(xdr, group_name, GFP_NOWAIT);
+               len = decode_nfs4_string(xdr, group_name, GFP_NOIO);
                if (len <= 0)
                        goto out;
                dprintk("%s: name=%s\n", __func__, group_name->data);
@@@ -4155,19 -4139,25 +4138,25 @@@ out_overflow
        return -EIO;
  }
  
+ static __be32 *
+ xdr_decode_nfstime4(__be32 *p, struct timespec *t)
+ {
+       __u64 sec;
+       p = xdr_decode_hyper(p, &sec);
+       t-> tv_sec = (time_t)sec;
+       t->tv_nsec = be32_to_cpup(p++);
+       return p;
+ }
  static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time)
  {
        __be32 *p;
-       uint64_t sec;
-       uint32_t nsec;
  
-       p = xdr_inline_decode(xdr, 12);
+       p = xdr_inline_decode(xdr, nfstime4_maxsz << 2);
        if (unlikely(!p))
                goto out_overflow;
-       p = xdr_decode_hyper(p, &sec);
-       nsec = be32_to_cpup(p);
-       time->tv_sec = (time_t)sec;
-       time->tv_nsec = (long)nsec;
+       xdr_decode_nfstime4(p, time);
        return 0;
  out_overflow:
        print_overflow_msg(__func__, xdr);
@@@ -5470,21 -5460,13 +5459,13 @@@ decode_savefh(struct xdr_stream *xdr
  
  static int decode_setattr(struct xdr_stream *xdr)
  {
-       __be32 *p;
-       uint32_t bmlen;
        int status;
  
        status = decode_op_hdr(xdr, OP_SETATTR);
        if (status)
                return status;
-       p = xdr_inline_decode(xdr, 4);
-       if (unlikely(!p))
-               goto out_overflow;
-       bmlen = be32_to_cpup(p);
-       p = xdr_inline_decode(xdr, bmlen << 2);
-       if (likely(p))
+       if (decode_bitmap4(xdr, NULL, 0) >= 0)
                return 0;
- out_overflow:
        print_overflow_msg(__func__, xdr);
        return -EIO;
  }
@@@ -6255,7 -6237,8 +6236,8 @@@ static int nfs4_xdr_dec_access(struct r
        status = decode_access(xdr, &res->supported, &res->access);
        if (status != 0)
                goto out;
-       decode_getfattr(xdr, res->fattr, res->server);
+       if (res->fattr)
+               decode_getfattr(xdr, res->fattr, res->server);
  out:
        return status;
  }
@@@ -7535,6 -7518,7 +7517,7 @@@ int nfs4_decode_dirent(struct xdr_strea
        unsigned int savep;
        uint32_t bitmap[3] = {0};
        uint32_t len;
+       uint64_t new_cookie;
        __be32 *p = xdr_inline_decode(xdr, 4);
        if (unlikely(!p))
                goto out_overflow;
        p = xdr_inline_decode(xdr, 12);
        if (unlikely(!p))
                goto out_overflow;
-       entry->prev_cookie = entry->cookie;
-       p = xdr_decode_hyper(p, &entry->cookie);
+       p = xdr_decode_hyper(p, &new_cookie);
        entry->len = be32_to_cpup(p);
  
        p = xdr_inline_decode(xdr, entry->len);
        if (entry->fattr->valid & NFS_ATTR_FATTR_TYPE)
                entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
  
+       entry->prev_cookie = entry->cookie;
+       entry->cookie = new_cookie;
        return 0;
  
  out_overflow:
diff --combined fs/nfs/write.c
index 6579f3b367bdad8107340fdbbec32e439afd079d,541471a32784d36183cbea882935af0c50debe33..0193053bc139d3228602d589dbb643206e970dba
@@@ -231,6 -231,7 +231,7 @@@ static void nfs_grow_file(struct page *
        if (i_size >= end)
                goto out;
        i_size_write(inode, end);
+       NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_SIZE;
        nfs_inc_stats(inode, NFSIOS_EXTENDWRITE);
  out:
        spin_unlock(&inode->i_lock);
@@@ -1562,8 -1563,11 +1563,11 @@@ static int nfs_writeback_done(struct rp
        }
  
        /* Deal with the suid/sgid bit corner case */
-       if (nfs_should_remove_suid(inode))
-               nfs_mark_for_revalidate(inode);
+       if (nfs_should_remove_suid(inode)) {
+               spin_lock(&inode->i_lock);
+               NFS_I(inode)->cache_validity |= NFS_INO_INVALID_OTHER;
+               spin_unlock(&inode->i_lock);
+       }
        return 0;
  }
  
@@@ -1620,8 -1624,8 +1624,8 @@@ static void nfs_writeback_result(struc
  
  static int wait_on_commit(struct nfs_mds_commit_info *cinfo)
  {
 -      return wait_on_atomic_t(&cinfo->rpcs_out,
 -                      nfs_wait_atomic_killable, TASK_KILLABLE);
 +      return wait_var_event_killable(&cinfo->rpcs_out,
 +                                     !atomic_read(&cinfo->rpcs_out));
  }
  
  static void nfs_commit_begin(struct nfs_mds_commit_info *cinfo)
  static void nfs_commit_end(struct nfs_mds_commit_info *cinfo)
  {
        if (atomic_dec_and_test(&cinfo->rpcs_out))
 -              wake_up_atomic_t(&cinfo->rpcs_out);
 +              wake_up_var(&cinfo->rpcs_out);
  }
  
  void nfs_commitdata_release(struct nfs_commit_data *data)
@@@ -1876,43 -1880,40 +1880,43 @@@ int nfs_generic_commit_list(struct inod
        return status;
  }
  
 -int nfs_commit_inode(struct inode *inode, int how)
 +static int __nfs_commit_inode(struct inode *inode, int how,
 +              struct writeback_control *wbc)
  {
        LIST_HEAD(head);
        struct nfs_commit_info cinfo;
        int may_wait = how & FLUSH_SYNC;
 -      int error = 0;
 -      int res;
 +      int ret, nscan;
  
        nfs_init_cinfo_from_inode(&cinfo, inode);
        nfs_commit_begin(cinfo.mds);
 -      res = nfs_scan_commit(inode, &head, &cinfo);
 -      if (res)
 -              error = nfs_generic_commit_list(inode, &head, how, &cinfo);
 +      for (;;) {
 +              ret = nscan = nfs_scan_commit(inode, &head, &cinfo);
 +              if (ret <= 0)
 +                      break;
 +              ret = nfs_generic_commit_list(inode, &head, how, &cinfo);
 +              if (ret < 0)
 +                      break;
 +              ret = 0;
 +              if (wbc && wbc->sync_mode == WB_SYNC_NONE) {
 +                      if (nscan < wbc->nr_to_write)
 +                              wbc->nr_to_write -= nscan;
 +                      else
 +                              wbc->nr_to_write = 0;
 +              }
 +              if (nscan < INT_MAX)
 +                      break;
 +              cond_resched();
 +      }
        nfs_commit_end(cinfo.mds);
 -      if (res == 0)
 -              return res;
 -      if (error < 0)
 -              goto out_error;
 -      if (!may_wait)
 -              goto out_mark_dirty;
 -      error = wait_on_commit(cinfo.mds);
 -      if (error < 0)
 -              return error;
 -      return res;
 -out_error:
 -      res = error;
 -      /* Note: If we exit without ensuring that the commit is complete,
 -       * we must mark the inode as dirty. Otherwise, future calls to
 -       * sync_inode() with the WB_SYNC_ALL flag set will fail to ensure
 -       * that the data is on the disk.
 -       */
 -out_mark_dirty:
 -      __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
 -      return res;
 +      if (ret || !may_wait)
 +              return ret;
 +      return wait_on_commit(cinfo.mds);
 +}
 +
 +int nfs_commit_inode(struct inode *inode, int how)
 +{
 +      return __nfs_commit_inode(inode, how, NULL);
  }
  EXPORT_SYMBOL_GPL(nfs_commit_inode);
  
@@@ -1922,11 -1923,11 +1926,11 @@@ int nfs_write_inode(struct inode *inode
        int flags = FLUSH_SYNC;
        int ret = 0;
  
 -      /* no commits means nothing needs to be done */
 -      if (!atomic_long_read(&nfsi->commit_info.ncommit))
 -              return ret;
 -
        if (wbc->sync_mode == WB_SYNC_NONE) {
 +              /* no commits means nothing needs to be done */
 +              if (!atomic_long_read(&nfsi->commit_info.ncommit))
 +                      goto check_requests_outstanding;
 +
                /* Don't commit yet if this is a non-blocking flush and there
                 * are a lot of outstanding writes for this mapping.
                 */
                flags = 0;
        }
  
 -      ret = nfs_commit_inode(inode, flags);
 -      if (ret >= 0) {
 -              if (wbc->sync_mode == WB_SYNC_NONE) {
 -                      if (ret < wbc->nr_to_write)
 -                              wbc->nr_to_write -= ret;
 -                      else
 -                              wbc->nr_to_write = 0;
 -              }
 -              return 0;
 -      }
 +      ret = __nfs_commit_inode(inode, flags, wbc);
 +      if (!ret) {
 +              if (flags & FLUSH_SYNC)
 +                      return 0;
 +      } else if (atomic_long_read(&nfsi->commit_info.ncommit))
 +              goto out_mark_dirty;
 +
 +check_requests_outstanding:
 +      if (!atomic_read(&nfsi->commit_info.rpcs_out))
 +              return ret;
  out_mark_dirty:
        __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
        return ret;
index 922cb8968fb246ed22126b910713b07d1ecc8597,76887d60f0c0f7adff0a75054514c240a5403b62..335d87242439db1b64d2ed7ad0c167844d0c5dad
@@@ -50,9 -50,9 +50,9 @@@ DEFINE_EVENT(rpc_task_status, rpc_bind_
  );
  
  TRACE_EVENT(rpc_connect_status,
-       TP_PROTO(struct rpc_task *task, int status),
+       TP_PROTO(const struct rpc_task *task),
  
-       TP_ARGS(task, status),
+       TP_ARGS(task),
  
        TP_STRUCT__entry(
                __field(unsigned int, task_id)
@@@ -63,7 -63,7 +63,7 @@@
        TP_fast_assign(
                __entry->task_id = task->tk_pid;
                __entry->client_id = task->tk_client->cl_clid;
-               __entry->status = status;
+               __entry->status = task->tk_status;
        ),
  
        TP_printk("task:%u@%u status=%d",
@@@ -103,9 -103,9 +103,9 @@@ TRACE_EVENT(rpc_request
  
  DECLARE_EVENT_CLASS(rpc_task_running,
  
-       TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const void *action),
+       TP_PROTO(const struct rpc_task *task, const void *action),
  
-       TP_ARGS(clnt, task, action),
+       TP_ARGS(task, action),
  
        TP_STRUCT__entry(
                __field(unsigned int, task_id)
                ),
  
        TP_fast_assign(
-               __entry->client_id = clnt ? clnt->cl_clid : -1;
+               __entry->client_id = task->tk_client ?
+                                    task->tk_client->cl_clid : -1;
                __entry->task_id = task->tk_pid;
                __entry->action = action;
                __entry->runstate = task->tk_runstate;
  
  DEFINE_EVENT(rpc_task_running, rpc_task_begin,
  
-       TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const void *action),
+       TP_PROTO(const struct rpc_task *task, const void *action),
  
-       TP_ARGS(clnt, task, action)
+       TP_ARGS(task, action)
  
  );
  
  DEFINE_EVENT(rpc_task_running, rpc_task_run_action,
  
-       TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const void *action),
+       TP_PROTO(const struct rpc_task *task, const void *action),
  
-       TP_ARGS(clnt, task, action)
+       TP_ARGS(task, action)
  
  );
  
  DEFINE_EVENT(rpc_task_running, rpc_task_complete,
  
-       TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const void *action),
+       TP_PROTO(const struct rpc_task *task, const void *action),
  
-       TP_ARGS(clnt, task, action)
+       TP_ARGS(task, action)
  
  );
  
  DECLARE_EVENT_CLASS(rpc_task_queued,
  
-       TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const struct rpc_wait_queue *q),
+       TP_PROTO(const struct rpc_task *task, const struct rpc_wait_queue *q),
  
-       TP_ARGS(clnt, task, q),
+       TP_ARGS(task, q),
  
        TP_STRUCT__entry(
                __field(unsigned int, task_id)
                ),
  
        TP_fast_assign(
-               __entry->client_id = clnt ? clnt->cl_clid : -1;
+               __entry->client_id = task->tk_client ?
+                                    task->tk_client->cl_clid : -1;
                __entry->task_id = task->tk_pid;
                __entry->timeout = task->tk_timeout;
                __entry->runstate = task->tk_runstate;
  
  DEFINE_EVENT(rpc_task_queued, rpc_task_sleep,
  
-       TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const struct rpc_wait_queue *q),
+       TP_PROTO(const struct rpc_task *task, const struct rpc_wait_queue *q),
  
-       TP_ARGS(clnt, task, q)
+       TP_ARGS(task, q)
  
  );
  
  DEFINE_EVENT(rpc_task_queued, rpc_task_wakeup,
  
-       TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const struct rpc_wait_queue *q),
+       TP_PROTO(const struct rpc_task *task, const struct rpc_wait_queue *q),
  
-       TP_ARGS(clnt, task, q)
+       TP_ARGS(task, q)
  
  );
  
+ TRACE_EVENT(rpc_stats_latency,
+       TP_PROTO(
+               const struct rpc_task *task,
+               ktime_t backlog,
+               ktime_t rtt,
+               ktime_t execute
+       ),
+       TP_ARGS(task, backlog, rtt, execute),
+       TP_STRUCT__entry(
+               __field(u32, xid)
+               __field(int, version)
+               __string(progname, task->tk_client->cl_program->name)
+               __string(procname, rpc_proc_name(task))
+               __field(unsigned long, backlog)
+               __field(unsigned long, rtt)
+               __field(unsigned long, execute)
+               __string(addr,
+                        task->tk_xprt->address_strings[RPC_DISPLAY_ADDR])
+               __string(port,
+                        task->tk_xprt->address_strings[RPC_DISPLAY_PORT])
+       ),
+       TP_fast_assign(
+               __entry->xid = be32_to_cpu(task->tk_rqstp->rq_xid);
+               __entry->version = task->tk_client->cl_vers;
+               __assign_str(progname, task->tk_client->cl_program->name)
+               __assign_str(procname, rpc_proc_name(task))
+               __entry->backlog = ktime_to_us(backlog);
+               __entry->rtt = ktime_to_us(rtt);
+               __entry->execute = ktime_to_us(execute);
+               __assign_str(addr,
+                            task->tk_xprt->address_strings[RPC_DISPLAY_ADDR]);
+               __assign_str(port,
+                            task->tk_xprt->address_strings[RPC_DISPLAY_PORT]);
+       ),
+       TP_printk("peer=[%s]:%s xid=0x%08x %sv%d %s backlog=%lu rtt=%lu execute=%lu",
+               __get_str(addr), __get_str(port), __entry->xid,
+               __get_str(progname), __entry->version, __get_str(procname),
+               __entry->backlog, __entry->rtt, __entry->execute)
+ );
  /*
   * First define the enums in the below macros to be exported to userspace
   * via TRACE_DEFINE_ENUM().
@@@ -406,6 -453,27 +453,27 @@@ DEFINE_EVENT(rpc_xprt_event, xprt_compl
        TP_PROTO(struct rpc_xprt *xprt, __be32 xid, int status),
        TP_ARGS(xprt, xid, status));
  
+ TRACE_EVENT(xprt_ping,
+       TP_PROTO(const struct rpc_xprt *xprt, int status),
+       TP_ARGS(xprt, status),
+       TP_STRUCT__entry(
+               __field(int, status)
+               __string(addr, xprt->address_strings[RPC_DISPLAY_ADDR])
+               __string(port, xprt->address_strings[RPC_DISPLAY_PORT])
+       ),
+       TP_fast_assign(
+               __entry->status = status;
+               __assign_str(addr, xprt->address_strings[RPC_DISPLAY_ADDR]);
+               __assign_str(port, xprt->address_strings[RPC_DISPLAY_PORT]);
+       ),
+       TP_printk("peer=[%s]:%s status=%d",
+                       __get_str(addr), __get_str(port), __entry->status)
+ );
  TRACE_EVENT(xs_tcp_data_ready,
        TP_PROTO(struct rpc_xprt *xprt, int err, unsigned int total),
  
@@@ -485,55 -553,31 +553,55 @@@ TRACE_EVENT(xs_tcp_data_recv
                { (1UL << RQ_BUSY),             "RQ_BUSY"})
  
  TRACE_EVENT(svc_recv,
 -      TP_PROTO(struct svc_rqst *rqst, int status),
 +      TP_PROTO(struct svc_rqst *rqst, int len),
  
 -      TP_ARGS(rqst, status),
 +      TP_ARGS(rqst, len),
  
        TP_STRUCT__entry(
                __field(u32, xid)
 -              __field(int, status)
 +              __field(int, len)
                __field(unsigned long, flags)
 -              __dynamic_array(unsigned char, addr, rqst->rq_addrlen)
 +              __string(addr, rqst->rq_xprt->xpt_remotebuf)
        ),
  
        TP_fast_assign(
 -              __entry->xid = status > 0 ? be32_to_cpu(rqst->rq_xid) : 0;
 -              __entry->status = status;
 +              __entry->xid = be32_to_cpu(rqst->rq_xid);
 +              __entry->len = len;
                __entry->flags = rqst->rq_flags;
 -              memcpy(__get_dynamic_array(addr),
 -                      &rqst->rq_addr, rqst->rq_addrlen);
 +              __assign_str(addr, rqst->rq_xprt->xpt_remotebuf);
        ),
  
 -      TP_printk("addr=%pIScp xid=0x%08x status=%d flags=%s",
 -                      (struct sockaddr *)__get_dynamic_array(addr),
 -                      __entry->xid, __entry->status,
 +      TP_printk("addr=%s xid=0x%08x len=%d flags=%s",
 +                      __get_str(addr), __entry->xid, __entry->len,
                        show_rqstp_flags(__entry->flags))
  );
  
 +TRACE_EVENT(svc_process,
 +      TP_PROTO(const struct svc_rqst *rqst, const char *name),
 +
 +      TP_ARGS(rqst, name),
 +
 +      TP_STRUCT__entry(
 +              __field(u32, xid)
 +              __field(u32, vers)
 +              __field(u32, proc)
 +              __string(service, name)
 +              __string(addr, rqst->rq_xprt->xpt_remotebuf)
 +      ),
 +
 +      TP_fast_assign(
 +              __entry->xid = be32_to_cpu(rqst->rq_xid);
 +              __entry->vers = rqst->rq_vers;
 +              __entry->proc = rqst->rq_proc;
 +              __assign_str(service, name);
 +              __assign_str(addr, rqst->rq_xprt->xpt_remotebuf);
 +      ),
 +
 +      TP_printk("addr=%s xid=0x%08x service=%s vers=%u proc=%u",
 +                      __get_str(addr), __entry->xid,
 +                      __get_str(service), __entry->vers, __entry->proc)
 +);
 +
  DECLARE_EVENT_CLASS(svc_rqst_event,
  
        TP_PROTO(struct svc_rqst *rqst),
        TP_STRUCT__entry(
                __field(u32, xid)
                __field(unsigned long, flags)
 -              __dynamic_array(unsigned char, addr, rqst->rq_addrlen)
 +              __string(addr, rqst->rq_xprt->xpt_remotebuf)
        ),
  
        TP_fast_assign(
                __entry->xid = be32_to_cpu(rqst->rq_xid);
                __entry->flags = rqst->rq_flags;
 -              memcpy(__get_dynamic_array(addr),
 -                      &rqst->rq_addr, rqst->rq_addrlen);
 +              __assign_str(addr, rqst->rq_xprt->xpt_remotebuf);
        ),
  
 -      TP_printk("addr=%pIScp rq_xid=0x%08x flags=%s",
 -              (struct sockaddr *)__get_dynamic_array(addr),
 -              __entry->xid,
 -              show_rqstp_flags(__entry->flags))
 +      TP_printk("addr=%s xid=0x%08x flags=%s",
 +                      __get_str(addr), __entry->xid,
 +                      show_rqstp_flags(__entry->flags))
  );
  
  DEFINE_EVENT(svc_rqst_event, svc_defer,
@@@ -575,21 -621,27 +643,21 @@@ DECLARE_EVENT_CLASS(svc_rqst_status
                __field(u32, xid)
                __field(int, status)
                __field(unsigned long, flags)
 -              __dynamic_array(unsigned char, addr, rqst->rq_addrlen)
 +              __string(addr, rqst->rq_xprt->xpt_remotebuf)
        ),
  
        TP_fast_assign(
                __entry->xid = be32_to_cpu(rqst->rq_xid);
                __entry->status = status;
                __entry->flags = rqst->rq_flags;
 -              memcpy(__get_dynamic_array(addr),
 -                      &rqst->rq_addr, rqst->rq_addrlen);
 +              __assign_str(addr, rqst->rq_xprt->xpt_remotebuf);
        ),
  
 -      TP_printk("addr=%pIScp rq_xid=0x%08x status=%d flags=%s",
 -              (struct sockaddr *)__get_dynamic_array(addr),
 -              __entry->xid,
 -              __entry->status, show_rqstp_flags(__entry->flags))
 +      TP_printk("addr=%s xid=0x%08x status=%d flags=%s",
 +                __get_str(addr), __entry->xid,
 +                __entry->status, show_rqstp_flags(__entry->flags))
  );
  
 -DEFINE_EVENT(svc_rqst_status, svc_process,
 -      TP_PROTO(struct svc_rqst *rqst, int status),
 -      TP_ARGS(rqst, status));
 -
  DEFINE_EVENT(svc_rqst_status, svc_send,
        TP_PROTO(struct svc_rqst *rqst, int status),
        TP_ARGS(rqst, status));
                { (1UL << XPT_OLD),             "XPT_OLD"},             \
                { (1UL << XPT_LISTENER),        "XPT_LISTENER"},        \
                { (1UL << XPT_CACHE_AUTH),      "XPT_CACHE_AUTH"},      \
 -              { (1UL << XPT_LOCAL),           "XPT_LOCAL"})
 +              { (1UL << XPT_LOCAL),           "XPT_LOCAL"},           \
 +              { (1UL << XPT_KILL_TEMP),       "XPT_KILL_TEMP"},       \
 +              { (1UL << XPT_CONG_CTRL),       "XPT_CONG_CTRL"})
  
  TRACE_EVENT(svc_xprt_do_enqueue,
        TP_PROTO(struct svc_xprt *xprt, struct svc_rqst *rqst),
                __field(struct svc_xprt *, xprt)
                __field(int, pid)
                __field(unsigned long, flags)
 -              __dynamic_array(unsigned char, addr, xprt != NULL ?
 -                      xprt->xpt_remotelen : 0)
 +              __string(addr, xprt->xpt_remotebuf)
        ),
  
        TP_fast_assign(
                __entry->xprt = xprt;
                __entry->pid = rqst? rqst->rq_task->pid : 0;
 -              if (xprt) {
 -                      memcpy(__get_dynamic_array(addr),
 -                              &xprt->xpt_remote,
 -                              xprt->xpt_remotelen);
 -                      __entry->flags = xprt->xpt_flags;
 -              } else
 -                      __entry->flags = 0;
 -      ),
 -
 -      TP_printk("xprt=0x%p addr=%pIScp pid=%d flags=%s", __entry->xprt,
 -              __get_dynamic_array_len(addr) != 0 ?
 -                      (struct sockaddr *)__get_dynamic_array(addr) : NULL,
 -              __entry->pid, show_svc_xprt_flags(__entry->flags))
 +              __entry->flags = xprt->xpt_flags;
 +              __assign_str(addr, xprt->xpt_remotebuf);
 +      ),
 +
 +      TP_printk("xprt=%p addr=%s pid=%d flags=%s",
 +                      __entry->xprt, __get_str(addr),
 +                      __entry->pid, show_svc_xprt_flags(__entry->flags))
  );
  
  DECLARE_EVENT_CLASS(svc_xprt_event,
        TP_STRUCT__entry(
                __field(struct svc_xprt *, xprt)
                __field(unsigned long, flags)
 -              __dynamic_array(unsigned char, addr, xprt != NULL ?
 -                      xprt->xpt_remotelen : 0)
 +              __string(addr, xprt->xpt_remotebuf)
        ),
  
        TP_fast_assign(
                __entry->xprt = xprt;
 -              if (xprt) {
 -                      memcpy(__get_dynamic_array(addr),
 -                                      &xprt->xpt_remote,
 -                                      xprt->xpt_remotelen);
 -                      __entry->flags = xprt->xpt_flags;
 -              } else
 -                      __entry->flags = 0;
 -      ),
 -
 -      TP_printk("xprt=0x%p addr=%pIScp flags=%s", __entry->xprt,
 -              __get_dynamic_array_len(addr) != 0 ?
 -                      (struct sockaddr *)__get_dynamic_array(addr) : NULL,
 -              show_svc_xprt_flags(__entry->flags))
 -);
 +              __entry->flags = xprt->xpt_flags;
 +              __assign_str(addr, xprt->xpt_remotebuf);
 +      ),
  
 -DEFINE_EVENT(svc_xprt_event, svc_xprt_dequeue,
 -      TP_PROTO(struct svc_xprt *xprt),
 -      TP_ARGS(xprt));
 +      TP_printk("xprt=%p addr=%s flags=%s",
 +                      __entry->xprt, __get_str(addr),
 +                      show_svc_xprt_flags(__entry->flags))
 +);
  
  DEFINE_EVENT(svc_xprt_event, svc_xprt_no_write_space,
        TP_PROTO(struct svc_xprt *xprt),
        TP_ARGS(xprt));
  
 +TRACE_EVENT(svc_xprt_dequeue,
 +      TP_PROTO(struct svc_rqst *rqst),
 +
 +      TP_ARGS(rqst),
 +
 +      TP_STRUCT__entry(
 +              __field(struct svc_xprt *, xprt)
 +              __field(unsigned long, flags)
 +              __field(unsigned long, wakeup)
 +              __string(addr, rqst->rq_xprt->xpt_remotebuf)
 +      ),
 +
 +      TP_fast_assign(
 +              __entry->xprt = rqst->rq_xprt;
 +              __entry->flags = rqst->rq_xprt->xpt_flags;
 +              __entry->wakeup = ktime_to_us(ktime_sub(ktime_get(),
 +                                                      rqst->rq_qtime));
 +              __assign_str(addr, rqst->rq_xprt->xpt_remotebuf);
 +      ),
 +
 +      TP_printk("xprt=%p addr=%s flags=%s wakeup-us=%lu",
 +                      __entry->xprt, __get_str(addr),
 +                      show_svc_xprt_flags(__entry->flags),
 +                      __entry->wakeup)
 +);
 +
  TRACE_EVENT(svc_wake_up,
        TP_PROTO(int pid),
  
@@@ -712,42 -754,28 +780,42 @@@ TRACE_EVENT(svc_handle_xprt
                __field(struct svc_xprt *, xprt)
                __field(int, len)
                __field(unsigned long, flags)
 -              __dynamic_array(unsigned char, addr, xprt != NULL ?
 -                      xprt->xpt_remotelen : 0)
 +              __string(addr, xprt->xpt_remotebuf)
        ),
  
        TP_fast_assign(
                __entry->xprt = xprt;
                __entry->len = len;
 -              if (xprt) {
 -                      memcpy(__get_dynamic_array(addr),
 -                                      &xprt->xpt_remote,
 -                                      xprt->xpt_remotelen);
 -                      __entry->flags = xprt->xpt_flags;
 -              } else
 -                      __entry->flags = 0;
 -      ),
 -
 -      TP_printk("xprt=0x%p addr=%pIScp len=%d flags=%s", __entry->xprt,
 -              __get_dynamic_array_len(addr) != 0 ?
 -                      (struct sockaddr *)__get_dynamic_array(addr) : NULL,
 +              __entry->flags = xprt->xpt_flags;
 +              __assign_str(addr, xprt->xpt_remotebuf);
 +      ),
 +
 +      TP_printk("xprt=%p addr=%s len=%d flags=%s",
 +              __entry->xprt, __get_str(addr),
                __entry->len, show_svc_xprt_flags(__entry->flags))
  );
  
 +TRACE_EVENT(svc_stats_latency,
 +      TP_PROTO(const struct svc_rqst *rqst),
 +
 +      TP_ARGS(rqst),
 +
 +      TP_STRUCT__entry(
 +              __field(u32, xid)
 +              __field(unsigned long, execute)
 +              __string(addr, rqst->rq_xprt->xpt_remotebuf)
 +      ),
 +
 +      TP_fast_assign(
 +              __entry->xid = be32_to_cpu(rqst->rq_xid);
 +              __entry->execute = ktime_to_us(ktime_sub(ktime_get(),
 +                                                       rqst->rq_stime));
 +              __assign_str(addr, rqst->rq_xprt->xpt_remotebuf);
 +      ),
 +
 +      TP_printk("addr=%s xid=0x%08x execute-us=%lu",
 +              __get_str(addr), __entry->xid, __entry->execute)
 +);
  
  DECLARE_EVENT_CLASS(svc_deferred_event,
        TP_PROTO(struct svc_deferred_req *dr),
  
        TP_STRUCT__entry(
                __field(u32, xid)
 -              __dynamic_array(unsigned char, addr, dr->addrlen)
 +              __string(addr, dr->xprt->xpt_remotebuf)
        ),
  
        TP_fast_assign(
                __entry->xid = be32_to_cpu(*(__be32 *)(dr->args +
                                                       (dr->xprt_hlen>>2)));
 -              memcpy(__get_dynamic_array(addr), &dr->addr, dr->addrlen);
 +              __assign_str(addr, dr->xprt->xpt_remotebuf);
        ),
  
 -      TP_printk("addr=%pIScp xid=0x%08x",
 -              (struct sockaddr *)__get_dynamic_array(addr),
 -              __entry->xid)
 +      TP_printk("addr=%s xid=0x%08x", __get_str(addr), __entry->xid)
  );
  
  DEFINE_EVENT(svc_deferred_event, svc_drop_deferred,
diff --combined net/sunrpc/clnt.c
index 806395687bb661ab570b7dbc20858edba12ca931,166f8c1680d1e4f82a575354768397b51e2e9d87..c2266f3872137a55993b2ad7d59bd9b623d03322
@@@ -1231,7 -1231,7 +1231,7 @@@ static const struct sockaddr_in6 rpc_in
   * negative errno is returned.
   */
  static int rpc_sockname(struct net *net, struct sockaddr *sap, size_t salen,
 -                      struct sockaddr *buf, int buflen)
 +                      struct sockaddr *buf)
  {
        struct socket *sock;
        int err;
                goto out_release;
        }
  
 -      err = kernel_getsockname(sock, buf, &buflen);
 +      err = kernel_getsockname(sock, buf);
        if (err < 0) {
                dprintk("RPC:       getsockname failed (%d)\n", err);
                goto out_release;
@@@ -1353,7 -1353,7 +1353,7 @@@ int rpc_localaddr(struct rpc_clnt *clnt
        rcu_read_unlock();
  
        rpc_set_port(sap, 0);
 -      err = rpc_sockname(net, sap, salen, buf, buflen);
 +      err = rpc_sockname(net, sap, salen, buf);
        put_net(net);
        if (err != 0)
                /* Couldn't discover local address, return ANYADDR */
@@@ -1887,7 -1887,7 +1887,7 @@@ call_connect_status(struct rpc_task *ta
  
        dprint_status(task);
  
-       trace_rpc_connect_status(task, status);
+       trace_rpc_connect_status(task);
        task->tk_status = 0;
        switch (status) {
        case -ECONNREFUSED:
@@@ -2014,6 -2014,9 +2014,9 @@@ call_transmit_status(struct rpc_task *t
        case -EPERM:
                if (RPC_IS_SOFTCONN(task)) {
                        xprt_end_transmit(task);
+                       if (!task->tk_msg.rpc_proc->p_proc)
+                               trace_xprt_ping(task->tk_xprt,
+                                               task->tk_status);
                        rpc_exit(task, task->tk_status);
                        break;
                }
@@@ -2112,6 -2115,9 +2115,9 @@@ call_status(struct rpc_task *task
        struct rpc_rqst *req = task->tk_rqstp;
        int             status;
  
+       if (!task->tk_msg.rpc_proc->p_proc)
+               trace_xprt_ping(task->tk_xprt, task->tk_status);
        if (req->rq_reply_bytes_recvd > 0 && !req->rq_bytes_sent)
                task->tk_status = req->rq_reply_bytes_recvd;
  
diff --combined net/sunrpc/xprtsock.c
index 956e29c1438d504261f1ba4cd116c150ca74aa76,e3c6a3df278b1fa4f175aebb72019f195aff5cd0..c8902f11efdd513c066f7f1b4c2c24405d8dfe5f
@@@ -527,6 -527,7 +527,7 @@@ static int xs_local_send_request(struc
        xs_pktdump("packet data:",
                        req->rq_svec->iov_base, req->rq_svec->iov_len);
  
+       req->rq_xtime = ktime_get();
        status = xs_sendpages(transport->sock, NULL, 0, xdr, req->rq_bytes_sent,
                              true, &sent);
        dprintk("RPC:       %s(%u) = %d\n",
@@@ -589,6 -590,7 +590,7 @@@ static int xs_udp_send_request(struct r
  
        if (!xprt_bound(xprt))
                return -ENOTCONN;
+       req->rq_xtime = ktime_get();
        status = xs_sendpages(transport->sock, xs_addr(xprt), xprt->addrlen,
                              xdr, req->rq_bytes_sent, true, &sent);
  
@@@ -678,6 -680,7 +680,7 @@@ static int xs_tcp_send_request(struct r
        /* Continue transmitting the packet/record. We must be careful
         * to cope with writespace callbacks arriving _after_ we have
         * called sendmsg(). */
+       req->rq_xtime = ktime_get();
        while (1) {
                sent = 0;
                status = xs_sendpages(transport->sock, NULL, 0, xdr,
@@@ -1060,6 -1063,7 +1063,7 @@@ static void xs_udp_data_read_skb(struc
        if (!rovr)
                goto out_unlock;
        xprt_pin_rqst(rovr);
+       xprt_update_rtt(rovr->rq_task);
        spin_unlock(&xprt->recv_lock);
        task = rovr->rq_task;
  
@@@ -1794,9 -1798,10 +1798,9 @@@ static void xs_sock_set_reuseport(struc
  static unsigned short xs_sock_getport(struct socket *sock)
  {
        struct sockaddr_storage buf;
 -      int buflen;
        unsigned short port = 0;
  
 -      if (kernel_getsockname(sock, (struct sockaddr *)&buf, &buflen) < 0)
 +      if (kernel_getsockname(sock, (struct sockaddr *)&buf) < 0)
                goto out;
        switch (buf.ss_family) {
        case AF_INET6: