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
  ...

33 files changed:
fs/nfs/callback_xdr.c
fs/nfs/delegation.c
fs/nfs/delegation.h
fs/nfs/dir.c
fs/nfs/inode.c
fs/nfs/nfs3proc.c
fs/nfs/nfs3xdr.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4xdr.c
fs/nfs/proc.c
fs/nfs/unlink.c
fs/nfs/write.c
include/linux/nfs_fs.h
include/linux/nfs_xdr.h
include/linux/sunrpc/clnt.h
include/linux/sunrpc/xdr.h
include/linux/sunrpc/xprt.h
include/trace/events/sunrpc.h
net/sunrpc/clnt.c
net/sunrpc/sched.c
net/sunrpc/stats.c
net/sunrpc/sunrpc.h
net/sunrpc/xdr.c
net/sunrpc/xprt.c
net/sunrpc/xprtrdma/backchannel.c
net/sunrpc/xprtrdma/fmr_ops.c
net/sunrpc/xprtrdma/frwr_ops.c
net/sunrpc/xprtrdma/rpc_rdma.c
net/sunrpc/xprtrdma/transport.c
net/sunrpc/xprtrdma/verbs.c
net/sunrpc/xprtrdma/xprt_rdma.h
net/sunrpc/xprtsock.c

index 123c069429a7ba71fed0d1ed986eb7e764f75706..a813979b5be0c7b6491d3ca0843f6c63945ac959 100644 (file)
@@ -535,35 +535,10 @@ static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char
        return 0;
 }
 
-#define CB_SUPPORTED_ATTR0 (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE)
-#define CB_SUPPORTED_ATTR1 (FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY)
-static __be32 encode_attr_bitmap(struct xdr_stream *xdr, const uint32_t *bitmap, __be32 **savep)
+static __be32 encode_attr_bitmap(struct xdr_stream *xdr, const uint32_t *bitmap, size_t sz)
 {
-       __be32 bm[2];
-       __be32 *p;
-
-       bm[0] = htonl(bitmap[0] & CB_SUPPORTED_ATTR0);
-       bm[1] = htonl(bitmap[1] & CB_SUPPORTED_ATTR1);
-       if (bm[1] != 0) {
-               p = xdr_reserve_space(xdr, 16);
-               if (unlikely(p == NULL))
-                       return htonl(NFS4ERR_RESOURCE);
-               *p++ = htonl(2);
-               *p++ = bm[0];
-               *p++ = bm[1];
-       } else if (bm[0] != 0) {
-               p = xdr_reserve_space(xdr, 12);
-               if (unlikely(p == NULL))
-                       return htonl(NFS4ERR_RESOURCE);
-               *p++ = htonl(1);
-               *p++ = bm[0];
-       } else {
-               p = xdr_reserve_space(xdr, 8);
-               if (unlikely(p == NULL))
-                       return htonl(NFS4ERR_RESOURCE);
-               *p++ = htonl(0);
-       }
-       *savep = p;
+       if (xdr_stream_encode_uint32_array(xdr, bitmap, sz) < 0)
+               return cpu_to_be32(NFS4ERR_RESOURCE);
        return 0;
 }
 
@@ -656,9 +631,13 @@ static __be32 encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr,
        
        if (unlikely(status != 0))
                goto out;
-       status = encode_attr_bitmap(xdr, res->bitmap, &savep);
+       status = encode_attr_bitmap(xdr, res->bitmap, ARRAY_SIZE(res->bitmap));
        if (unlikely(status != 0))
                goto out;
+       status = cpu_to_be32(NFS4ERR_RESOURCE);
+       savep = xdr_reserve_space(xdr, sizeof(*savep));
+       if (unlikely(!savep))
+               goto out;
        status = encode_attr_change(xdr, res->bitmap, res->change_attr);
        if (unlikely(status != 0))
                goto out;
index d8b47624fee203de73b26fba07cc2da10ef6c144..1819d0d0ba4b14b92ad311ae2cf588f7f1ecb6a2 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/nfs_xdr.h>
 
 #include "nfs4_fs.h"
+#include "nfs4session.h"
 #include "delegation.h"
 #include "internal.h"
 #include "nfs4trace.h"
@@ -171,11 +172,15 @@ again:
  * nfs_inode_reclaim_delegation - process a delegation reclaim request
  * @inode: inode to process
  * @cred: credential to use for request
- * @res: new delegation state from server
+ * @type: delegation type
+ * @stateid: delegation stateid
+ * @pagemod_limit: write delegation "space_limit"
  *
  */
 void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred,
-                                 struct nfs_openres *res)
+                                 fmode_t type,
+                                 const nfs4_stateid *stateid,
+                                 unsigned long pagemod_limit)
 {
        struct nfs_delegation *delegation;
        struct rpc_cred *oldcred = NULL;
@@ -185,9 +190,9 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred,
        if (delegation != NULL) {
                spin_lock(&delegation->lock);
                if (delegation->inode != NULL) {
-                       nfs4_stateid_copy(&delegation->stateid, &res->delegation);
-                       delegation->type = res->delegation_type;
-                       delegation->pagemod_limit = res->pagemod_limit;
+                       nfs4_stateid_copy(&delegation->stateid, stateid);
+                       delegation->type = type;
+                       delegation->pagemod_limit = pagemod_limit;
                        oldcred = delegation->cred;
                        delegation->cred = get_rpccred(cred);
                        clear_bit(NFS_DELEGATION_NEED_RECLAIM,
@@ -195,14 +200,14 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred,
                        spin_unlock(&delegation->lock);
                        rcu_read_unlock();
                        put_rpccred(oldcred);
-                       trace_nfs4_reclaim_delegation(inode, res->delegation_type);
+                       trace_nfs4_reclaim_delegation(inode, type);
                        return;
                }
                /* We appear to have raced with a delegation return. */
                spin_unlock(&delegation->lock);
        }
        rcu_read_unlock();
-       nfs_inode_set_delegation(inode, cred, res);
+       nfs_inode_set_delegation(inode, cred, type, stateid, pagemod_limit);
 }
 
 static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync)
@@ -329,11 +334,16 @@ nfs_update_inplace_delegation(struct nfs_delegation *delegation,
  * nfs_inode_set_delegation - set up a delegation on an inode
  * @inode: inode to which delegation applies
  * @cred: cred to use for subsequent delegation processing
- * @res: new delegation state from server
+ * @type: delegation type
+ * @stateid: delegation stateid
+ * @pagemod_limit: write delegation "space_limit"
  *
  * Returns zero on success, or a negative errno value.
  */
-int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res)
+int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred,
+                                 fmode_t type,
+                                 const nfs4_stateid *stateid,
+                                 unsigned long pagemod_limit)
 {
        struct nfs_server *server = NFS_SERVER(inode);
        struct nfs_client *clp = server->nfs_client;
@@ -345,9 +355,9 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
        delegation = kmalloc(sizeof(*delegation), GFP_NOFS);
        if (delegation == NULL)
                return -ENOMEM;
-       nfs4_stateid_copy(&delegation->stateid, &res->delegation);
-       delegation->type = res->delegation_type;
-       delegation->pagemod_limit = res->pagemod_limit;
+       nfs4_stateid_copy(&delegation->stateid, stateid);
+       delegation->type = type;
+       delegation->pagemod_limit = pagemod_limit;
        delegation->change_attr = inode_peek_iversion_raw(inode);
        delegation->cred = get_rpccred(cred);
        delegation->inode = inode;
@@ -392,7 +402,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
        rcu_assign_pointer(nfsi->delegation, delegation);
        delegation = NULL;
 
-       trace_nfs4_set_delegation(inode, res->delegation_type);
+       trace_nfs4_set_delegation(inode, type);
 
 out:
        spin_unlock(&clp->cl_lock);
@@ -547,6 +557,22 @@ int nfs4_inode_return_delegation(struct inode *inode)
        return err;
 }
 
+/**
+ * nfs4_inode_make_writeable
+ * @inode: pointer to inode
+ *
+ * Make the inode writeable by returning the delegation if necessary
+ *
+ * Returns zero on success, or a negative errno value.
+ */
+int nfs4_inode_make_writeable(struct inode *inode)
+{
+       if (!nfs4_has_session(NFS_SERVER(inode)->nfs_client) ||
+           !nfs4_check_delegation(inode, FMODE_WRITE))
+               return nfs4_inode_return_delegation(inode);
+       return 0;
+}
+
 static void nfs_mark_return_if_closed_delegation(struct nfs_server *server,
                struct nfs_delegation *delegation)
 {
index 185a09f37a89b22228bdffacdb51604f4b9a3f7b..bb1ef8c37af42706c909d9f6880ca44fd33b5d00 100644 (file)
@@ -36,8 +36,10 @@ enum {
        NFS_DELEGATION_TEST_EXPIRED,
 };
 
-int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
-void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
+int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred,
+               fmode_t type, const nfs4_stateid *stateid, unsigned long pagemod_limit);
+void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred,
+               fmode_t type, const nfs4_stateid *stateid, unsigned long pagemod_limit);
 int nfs4_inode_return_delegation(struct inode *inode);
 int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid);
 void nfs_inode_return_delegation_noreclaim(struct inode *inode);
@@ -70,6 +72,7 @@ int nfs4_check_delegation(struct inode *inode, fmode_t flags);
 bool nfs4_delegation_flush_on_close(const struct inode *inode);
 void nfs_inode_find_delegation_state_and_recover(struct inode *inode,
                const nfs4_stateid *stateid);
+int nfs4_inode_make_writeable(struct inode *inode);
 
 #endif
 
index 2f3f86726f5b96cdbdf426a0ee7264b6fd3aa5ae..73f8b43d988cfa2f7b3366b1147dc296b55802ef 100644 (file)
@@ -1272,7 +1272,9 @@ static void nfs_drop_nlink(struct inode *inode)
        /* drop the inode if we're reasonably sure this is the last link */
        if (inode->i_nlink == 1)
                clear_nlink(inode);
-       NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATTR;
+       NFS_I(inode)->cache_validity |= NFS_INO_INVALID_CHANGE
+               | NFS_INO_INVALID_CTIME
+               | NFS_INO_INVALID_OTHER;
        spin_unlock(&inode->i_lock);
 }
 
@@ -1798,12 +1800,11 @@ static int nfs_safe_remove(struct dentry *dentry)
 
        trace_nfs_remove_enter(dir, dentry);
        if (inode != NULL) {
-               NFS_PROTO(inode)->return_delegation(inode);
-               error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
+               error = NFS_PROTO(dir)->remove(dir, dentry);
                if (error == 0)
                        nfs_drop_nlink(inode);
        } else
-               error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
+               error = NFS_PROTO(dir)->remove(dir, dentry);
        if (error == -ENOENT)
                nfs_dentry_handle_enoent(dentry);
        trace_nfs_remove_exit(dir, dentry, error);
@@ -1932,8 +1933,6 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
                old_dentry, dentry);
 
        trace_nfs_link_enter(inode, dir, dentry);
-       NFS_PROTO(inode)->return_delegation(inode);
-
        d_drop(dentry);
        error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name);
        if (error == 0) {
@@ -2023,10 +2022,6 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                }
        }
 
-       NFS_PROTO(old_inode)->return_delegation(old_inode);
-       if (new_inode != NULL)
-               NFS_PROTO(new_inode)->return_delegation(new_inode);
-
        task = nfs_async_rename(old_dir, new_dir, old_dentry, new_dentry, NULL);
        if (IS_ERR(task)) {
                error = PTR_ERR(task);
index d17a90c4fa3733495b9b81e08cc343fba2fc967f..bd15d0b5762665b4f50be2c7a07c513b6891c635 100644 (file)
@@ -195,7 +195,10 @@ bool nfs_check_cache_invalid(struct inode *inode, unsigned long flags)
 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 +450,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st
                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.
                 */
@@ -493,37 +496,35 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st
                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 +609,6 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
                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 +641,7 @@ static int nfs_vmtruncate(struct inode * inode, loff_t offset)
        /* 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 +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 +667,8 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr,
 
        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;
@@ -683,13 +683,12 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr,
                                | 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 +1302,20 @@ static bool nfs_file_has_buffered_writers(struct nfs_inode *nfsi)
        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)
@@ -1329,17 +1324,13 @@ static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr
                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 +1360,41 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
        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 +1596,9 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
 }
 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 +1627,9 @@ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 
        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 +1681,10 @@ int nfs_post_op_update_inode_force_wcc_locked(struct inode *inode, struct nfs_fa
                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 +1792,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                        | 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;
@@ -1803,17 +1806,25 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                                        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;
        }
 
@@ -1821,7 +1832,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                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;
        }
@@ -1830,7 +1841,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                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;
        }
@@ -1845,7 +1856,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                        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",
@@ -1856,7 +1867,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                }
        } 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;
@@ -1877,55 +1888,61 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                        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;
        }
@@ -1942,6 +1959,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 
        /* 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;
@@ -1962,10 +1980,6 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                        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)))
index 7327930ad970ab98338e8f21a4fb363559205522..eadf1ab31d1666c7ce462b56d8f00ae80de7650a 100644 (file)
@@ -138,8 +138,11 @@ nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
                msg.rpc_cred = nfs_file_cred(sattr->ia_file);
        nfs_fattr_init(fattr);
        status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
-       if (status == 0)
+       if (status == 0) {
+               if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL)
+                       nfs_zap_acl_cache(inode);
                nfs_setattr_update_inode(inode, sattr, fattr);
+       }
        dprintk("NFS reply setattr: %d\n", status);
        return status;
 }
@@ -383,11 +386,11 @@ out:
 }
 
 static int
-nfs3_proc_remove(struct inode *dir, const struct qstr *name)
+nfs3_proc_remove(struct inode *dir, struct dentry *dentry)
 {
        struct nfs_removeargs arg = {
                .fh = NFS_FH(dir),
-               .name = *name,
+               .name = dentry->d_name,
        };
        struct nfs_removeres res;
        struct rpc_message msg = {
@@ -397,7 +400,7 @@ nfs3_proc_remove(struct inode *dir, const struct qstr *name)
        };
        int status = -ENOMEM;
 
-       dprintk("NFS call  remove %s\n", name->name);
+       dprintk("NFS call  remove %pd2\n", dentry);
        res.dir_attr = nfs_alloc_fattr();
        if (res.dir_attr == NULL)
                goto out;
@@ -411,7 +414,7 @@ out:
 }
 
 static void
-nfs3_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
+nfs3_proc_unlink_setup(struct rpc_message *msg, struct dentry *dentry)
 {
        msg->rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE];
 }
@@ -433,7 +436,9 @@ nfs3_proc_unlink_done(struct rpc_task *task, struct inode *dir)
 }
 
 static void
-nfs3_proc_rename_setup(struct rpc_message *msg, struct inode *dir)
+nfs3_proc_rename_setup(struct rpc_message *msg,
+               struct dentry *old_dentry,
+               struct dentry *new_dentry)
 {
        msg->rpc_proc = &nfs3_procedures[NFS3PROC_RENAME];
 }
@@ -908,12 +913,6 @@ static int nfs3_have_delegation(struct inode *inode, fmode_t flags)
        return 0;
 }
 
-static int nfs3_return_delegation(struct inode *inode)
-{
-       nfs_wb_all(inode);
-       return 0;
-}
-
 static const struct inode_operations nfs3_dir_inode_operations = {
        .create         = nfs_create,
        .lookup         = nfs_lookup,
@@ -990,7 +989,6 @@ const struct nfs_rpc_ops nfs_v3_clientops = {
        .clear_acl_cache = forget_all_cached_acls,
        .close_context  = nfs_close_context,
        .have_delegation = nfs3_have_delegation,
-       .return_delegation = nfs3_return_delegation,
        .alloc_client   = nfs_alloc_client,
        .init_client    = nfs_init_client,
        .free_client    = nfs_free_client,
index 6cd33bd5da87c355c47ade6823e2c2683941e1b2..09ee36dd84262971296138b9945dc843b5926645 100644 (file)
@@ -1997,6 +1997,7 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
        struct nfs_entry old = *entry;
        __be32 *p;
        int error;
+       u64 new_cookie;
 
        p = xdr_inline_decode(xdr, 4);
        if (unlikely(p == NULL))
@@ -2019,8 +2020,7 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
        if (unlikely(error))
                return error;
 
-       entry->prev_cookie = entry->cookie;
-       error = decode_cookie3(xdr, &entry->cookie);
+       error = decode_cookie3(xdr, &new_cookie);
        if (unlikely(error))
                return error;
 
@@ -2054,6 +2054,9 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
                        zero_nfs_fh3(entry->fh);
        }
 
+       entry->prev_cookie = entry->cookie;
+       entry->cookie = new_cookie;
+
        return 0;
 
 out_overflow:
index 47f3c273245e47b7c50a2e76a8b22de312190c5e..b71757e85066995786df12ebe2e10b5bb19c6ef9 100644 (file)
@@ -1045,7 +1045,9 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo,
        struct nfs_inode *nfsi = NFS_I(dir);
 
        spin_lock(&dir->i_lock);
-       nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
+       nfsi->cache_validity |= NFS_INO_INVALID_CTIME
+               | NFS_INO_INVALID_MTIME
+               | NFS_INO_INVALID_DATA;
        if (cinfo->atomic && cinfo->before == inode_peek_iversion_raw(dir)) {
                nfsi->cache_validity &= ~NFS_INO_REVAL_PAGECACHE;
                nfsi->attrtimeo_timestamp = jiffies;
@@ -1669,6 +1671,7 @@ static void nfs4_return_incompatible_delegation(struct inode *inode, fmode_t fmo
 {
        struct nfs_delegation *delegation;
 
+       fmode &= FMODE_READ|FMODE_WRITE;
        rcu_read_lock();
        delegation = rcu_dereference(NFS_I(inode)->delegation);
        if (delegation == NULL || (delegation->type & fmode) == fmode) {
@@ -1751,12 +1754,16 @@ nfs4_opendata_check_deleg(struct nfs4_opendata *data, struct nfs4_state *state)
        }
        if ((delegation_flags & 1UL<<NFS_DELEGATION_NEED_RECLAIM) == 0)
                nfs_inode_set_delegation(state->inode,
-                                        data->owner->so_cred,
-                                        &data->o_res);
+                               data->owner->so_cred,
+                               data->o_res.delegation_type,
+                               &data->o_res.delegation,
+                               data->o_res.pagemod_limit);
        else
                nfs_inode_reclaim_delegation(state->inode,
-                                            data->owner->so_cred,
-                                            &data->o_res);
+                               data->owner->so_cred,
+                               data->o_res.delegation_type,
+                               &data->o_res.delegation,
+                               data->o_res.pagemod_limit);
 }
 
 /*
@@ -2743,27 +2750,40 @@ static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st
  * fields corresponding to attributes that were used to store the verifier.
  * Make sure we clobber those fields in the later setattr call
  */
-static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata,
+static unsigned nfs4_exclusive_attrset(struct nfs4_opendata *opendata,
                                struct iattr *sattr, struct nfs4_label **label)
 {
-       const u32 *attrset = opendata->o_res.attrset;
+       const __u32 *bitmask = opendata->o_arg.server->exclcreat_bitmask;
+       __u32 attrset[3];
+       unsigned ret;
+       unsigned i;
 
-       if ((attrset[1] & FATTR4_WORD1_TIME_ACCESS) &&
-           !(sattr->ia_valid & ATTR_ATIME_SET))
-               sattr->ia_valid |= ATTR_ATIME;
+       for (i = 0; i < ARRAY_SIZE(attrset); i++) {
+               attrset[i] = opendata->o_res.attrset[i];
+               if (opendata->o_arg.createmode == NFS4_CREATE_EXCLUSIVE4_1)
+                       attrset[i] &= ~bitmask[i];
+       }
+
+       ret = (opendata->o_arg.createmode == NFS4_CREATE_EXCLUSIVE) ?
+               sattr->ia_valid : 0;
 
-       if ((attrset[1] & FATTR4_WORD1_TIME_MODIFY) &&
-           !(sattr->ia_valid & ATTR_MTIME_SET))
-               sattr->ia_valid |= ATTR_MTIME;
+       if ((attrset[1] & (FATTR4_WORD1_TIME_ACCESS|FATTR4_WORD1_TIME_ACCESS_SET))) {
+               if (sattr->ia_valid & ATTR_ATIME_SET)
+                       ret |= ATTR_ATIME_SET;
+               else
+                       ret |= ATTR_ATIME;
+       }
 
-       /* Except MODE, it seems harmless of setting twice. */
-       if (opendata->o_arg.createmode != NFS4_CREATE_EXCLUSIVE &&
-               (attrset[1] & FATTR4_WORD1_MODE ||
-                attrset[2] & FATTR4_WORD2_MODE_UMASK))
-               sattr->ia_valid &= ~ATTR_MODE;
+       if ((attrset[1] & (FATTR4_WORD1_TIME_MODIFY|FATTR4_WORD1_TIME_MODIFY_SET))) {
+               if (sattr->ia_valid & ATTR_MTIME_SET)
+                       ret |= ATTR_MTIME_SET;
+               else
+                       ret |= ATTR_MTIME;
+       }
 
-       if (attrset[2] & FATTR4_WORD2_SECURITY_LABEL)
+       if (!(attrset[2] & FATTR4_WORD2_SECURITY_LABEL))
                *label = NULL;
+       return ret;
 }
 
 static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
@@ -2892,12 +2912,15 @@ static int _nfs4_do_open(struct inode *dir,
 
        if ((opendata->o_arg.open_flags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL) &&
            (opendata->o_arg.createmode != NFS4_CREATE_GUARDED)) {
-               nfs4_exclusive_attrset(opendata, sattr, &label);
+               unsigned attrs = nfs4_exclusive_attrset(opendata, sattr, &label);
                /*
                 * send create attributes which was not set by open
                 * with an extra setattr.
                 */
-               if (sattr->ia_valid & NFS4_VALID_ATTRS) {
+               if (attrs || label) {
+                       unsigned ia_old = sattr->ia_valid;
+
+                       sattr->ia_valid = attrs;
                        nfs_fattr_init(opendata->o_res.f_attr);
                        status = nfs4_do_setattr(state->inode, cred,
                                        opendata->o_res.f_attr, sattr,
@@ -2907,6 +2930,7 @@ static int _nfs4_do_open(struct inode *dir,
                                                opendata->o_res.f_attr);
                                nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel);
                        }
+                       sattr->ia_valid = ia_old;
                }
        }
        if (opened && opendata->file_created)
@@ -3874,6 +3898,10 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
        if (IS_ERR(label))
                return PTR_ERR(label);
 
+       /* Return any delegations if we're going to change ACLs */
+       if ((sattr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0)
+               nfs4_inode_make_writeable(inode);
+
        status = nfs4_do_setattr(inode, cred, fattr, sattr, ctx, NULL, label);
        if (status == 0) {
                nfs_setattr_update_inode(inode, sattr, fattr);
@@ -4048,7 +4076,6 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
        struct nfs_server *server = NFS_SERVER(inode);
        struct nfs4_accessargs args = {
                .fh = NFS_FH(inode),
-               .bitmask = server->cache_consistency_bitmask,
                .access = entry->mask,
        };
        struct nfs4_accessres res = {
@@ -4062,14 +4089,18 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
        };
        int status = 0;
 
-       res.fattr = nfs_alloc_fattr();
-       if (res.fattr == NULL)
-               return -ENOMEM;
+       if (!nfs_have_delegated_attributes(inode)) {
+               res.fattr = nfs_alloc_fattr();
+               if (res.fattr == NULL)
+                       return -ENOMEM;
+               args.bitmask = server->cache_consistency_bitmask;
+       }
 
        status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
        if (!status) {
                nfs_access_set_mask(entry, res.access);
-               nfs_refresh_inode(inode, res.fattr);
+               if (res.fattr)
+                       nfs_refresh_inode(inode, res.fattr);
        }
        nfs_free_fattr(res.fattr);
        return status;
@@ -4199,10 +4230,32 @@ static int _nfs4_proc_remove(struct inode *dir, const struct qstr *name)
        return status;
 }
 
-static int nfs4_proc_remove(struct inode *dir, const struct qstr *name)
+static int nfs4_proc_remove(struct inode *dir, struct dentry *dentry)
+{
+       struct nfs4_exception exception = { };
+       struct inode *inode = d_inode(dentry);
+       int err;
+
+       if (inode) {
+               if (inode->i_nlink == 1)
+                       nfs4_inode_return_delegation(inode);
+               else
+                       nfs4_inode_make_writeable(inode);
+       }
+       do {
+               err = _nfs4_proc_remove(dir, &dentry->d_name);
+               trace_nfs4_remove(dir, &dentry->d_name, err);
+               err = nfs4_handle_exception(NFS_SERVER(dir), err,
+                               &exception);
+       } while (exception.retry);
+       return err;
+}
+
+static int nfs4_proc_rmdir(struct inode *dir, const struct qstr *name)
 {
        struct nfs4_exception exception = { };
        int err;
+
        do {
                err = _nfs4_proc_remove(dir, name);
                trace_nfs4_remove(dir, name, err);
@@ -4212,17 +4265,20 @@ static int nfs4_proc_remove(struct inode *dir, const struct qstr *name)
        return err;
 }
 
-static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
+static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct dentry *dentry)
 {
-       struct nfs_server *server = NFS_SERVER(dir);
        struct nfs_removeargs *args = msg->rpc_argp;
        struct nfs_removeres *res = msg->rpc_resp;
+       struct inode *inode = d_inode(dentry);
 
-       res->server = server;
+       res->server = NFS_SB(dentry->d_sb);
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE];
        nfs4_init_sequence(&args->seq_args, &res->seq_res, 1);
 
        nfs_fattr_init(res->dir_attr);
+
+       if (inode)
+               nfs4_inode_return_delegation(inode);
 }
 
 static void nfs4_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data)
@@ -4248,14 +4304,21 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
        return 1;
 }
 
-static void nfs4_proc_rename_setup(struct rpc_message *msg, struct inode *dir)
+static void nfs4_proc_rename_setup(struct rpc_message *msg,
+               struct dentry *old_dentry,
+               struct dentry *new_dentry)
 {
-       struct nfs_server *server = NFS_SERVER(dir);
        struct nfs_renameargs *arg = msg->rpc_argp;
        struct nfs_renameres *res = msg->rpc_resp;
+       struct inode *old_inode = d_inode(old_dentry);
+       struct inode *new_inode = d_inode(new_dentry);
 
+       if (old_inode)
+               nfs4_inode_make_writeable(old_inode);
+       if (new_inode)
+               nfs4_inode_return_delegation(new_inode);
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME];
-       res->server = server;
+       res->server = NFS_SB(old_dentry->d_sb);
        nfs4_init_sequence(&arg->seq_args, &res->seq_res, 1);
 }
 
@@ -4317,6 +4380,8 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, const struct
        }
        arg.bitmask = nfs4_bitmask(server, res.label);
 
+       nfs4_inode_make_writeable(inode);
+
        status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
        if (!status) {
                update_changeattr(dir, &res.cinfo, res.fattr->time_start);
@@ -5310,7 +5375,7 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl
        i = buf_to_pages_noslab(buf, buflen, arg.acl_pages);
        if (i < 0)
                return i;
-       nfs4_inode_return_delegation(inode);
+       nfs4_inode_make_writeable(inode);
        ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
 
        /*
@@ -5325,7 +5390,8 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl
         * so mark the attribute cache invalid.
         */
        spin_lock(&inode->i_lock);
-       NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATTR;
+       NFS_I(inode)->cache_validity |= NFS_INO_INVALID_CHANGE
+               | NFS_INO_INVALID_CTIME;
        spin_unlock(&inode->i_lock);
        nfs_access_zap_cache(inode);
        nfs_zap_acl_cache(inode);
@@ -6621,22 +6687,24 @@ static int
 nfs4_wake_lock_waiter(wait_queue_entry_t *wait, unsigned int mode, int flags, void *key)
 {
        int ret;
-       struct cb_notify_lock_args *cbnl = key;
        struct nfs4_lock_waiter *waiter = wait->private;
-       struct nfs_lowner       *lowner = &cbnl->cbnl_owner,
-                               *wowner = waiter->owner;
 
-       /* Only wake if the callback was for the same owner */
-       if (lowner->clientid != wowner->clientid ||
-           lowner->id != wowner->id             ||
-           lowner->s_dev != wowner->s_dev)
-               return 0;
+       /* NULL key means to wake up everyone */
+       if (key) {
+               struct cb_notify_lock_args      *cbnl = key;
+               struct nfs_lowner               *lowner = &cbnl->cbnl_owner,
+                                               *wowner = waiter->owner;
 
-       /* Make sure it's for the right inode */
-       if (nfs_compare_fh(NFS_FH(waiter->inode), &cbnl->cbnl_fh))
-               return 0;
+               /* Only wake if the callback was for the same owner. */
+               if (lowner->id != wowner->id || lowner->s_dev != wowner->s_dev)
+                       return 0;
 
-       waiter->notified = true;
+               /* Make sure it's for the right inode */
+               if (nfs_compare_fh(NFS_FH(waiter->inode), &cbnl->cbnl_fh))
+                       return 0;
+
+               waiter->notified = true;
+       }
 
        /* override "private" so we can use default_wake_function */
        wait->private = waiter->task;
@@ -6673,6 +6741,7 @@ nfs4_retry_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
        add_wait_queue(q, &wait);
 
        while(!signalled()) {
+               waiter.notified = false;
                status = nfs4_proc_setlk(state, cmd, request);
                if ((status != -EAGAIN) || IS_SETLK(cmd))
                        break;
@@ -8414,6 +8483,8 @@ static int nfs41_reclaim_complete_handle_errors(struct rpc_task *task, struct nf
 {
        switch(task->tk_status) {
        case 0:
+               wake_up_all(&clp->cl_lock_waitq);
+               /* Fallthrough */
        case -NFS4ERR_COMPLETE_ALREADY:
        case -NFS4ERR_WRONG_CRED: /* What to do here? */
                break;
@@ -9593,7 +9664,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
        .link           = nfs4_proc_link,
        .symlink        = nfs4_proc_symlink,
        .mkdir          = nfs4_proc_mkdir,
-       .rmdir          = nfs4_proc_remove,
+       .rmdir          = nfs4_proc_rmdir,
        .readdir        = nfs4_proc_readdir,
        .mknod          = nfs4_proc_mknod,
        .statfs         = nfs4_proc_statfs,
@@ -9614,7 +9685,6 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
        .close_context  = nfs4_close_context,
        .open_context   = nfs4_atomic_open,
        .have_delegation = nfs4_have_delegation,
-       .return_delegation = nfs4_inode_return_delegation,
        .alloc_client   = nfs4_alloc_client,
        .init_client    = nfs4_init_client,
        .free_client    = nfs4_free_client,
index 91a4d4eeb235ca5510c85a5f34e18dde27d80c89..c10a422efe6f4422ab22750c22cce18b37ef36f9 100644 (file)
@@ -428,7 +428,6 @@ nfs4_insert_state_owner_locked(struct nfs4_state_owner *new)
        struct rb_node **p = &server->state_owners.rb_node,
                       *parent = NULL;
        struct nfs4_state_owner *sp;
-       int err;
 
        while (*p != NULL) {
                parent = *p;
@@ -445,9 +444,6 @@ nfs4_insert_state_owner_locked(struct nfs4_state_owner *new)
                        return sp;
                }
        }
-       err = ida_get_new(&server->openowner_id, &new->so_seqid.owner_id);
-       if (err)
-               return ERR_PTR(err);
        rb_link_node(&new->so_server_node, parent, p);
        rb_insert_color(&new->so_server_node, &server->state_owners);
        return new;
@@ -460,7 +456,6 @@ nfs4_remove_state_owner_locked(struct nfs4_state_owner *sp)
 
        if (!RB_EMPTY_NODE(&sp->so_server_node))
                rb_erase(&sp->so_server_node, &server->state_owners);
-       ida_remove(&server->openowner_id, sp->so_seqid.owner_id);
 }
 
 static void
@@ -495,6 +490,12 @@ nfs4_alloc_state_owner(struct nfs_server *server,
        sp = kzalloc(sizeof(*sp), gfp_flags);
        if (!sp)
                return NULL;
+       sp->so_seqid.owner_id = ida_simple_get(&server->openowner_id, 0, 0,
+                                               gfp_flags);
+       if (sp->so_seqid.owner_id < 0) {
+               kfree(sp);
+               return NULL;
+       }
        sp->so_server = server;
        sp->so_cred = get_rpccred(cred);
        spin_lock_init(&sp->so_lock);
@@ -526,6 +527,7 @@ static void nfs4_free_state_owner(struct nfs4_state_owner *sp)
 {
        nfs4_destroy_seqid_counter(&sp->so_seqid);
        put_rpccred(sp->so_cred);
+       ida_simple_remove(&sp->so_server->openowner_id, sp->so_seqid.owner_id);
        kfree(sp);
 }
 
@@ -576,13 +578,9 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server,
        new = nfs4_alloc_state_owner(server, cred, gfp_flags);
        if (new == NULL)
                goto out;
-       do {
-               if (ida_pre_get(&server->openowner_id, gfp_flags) == 0)
-                       break;
-               spin_lock(&clp->cl_lock);
-               sp = nfs4_insert_state_owner_locked(new);
-               spin_unlock(&clp->cl_lock);
-       } while (sp == ERR_PTR(-EAGAIN));
+       spin_lock(&clp->cl_lock);
+       sp = nfs4_insert_state_owner_locked(new);
+       spin_unlock(&clp->cl_lock);
        if (sp != new)
                nfs4_free_state_owner(new);
 out:
index b993ad282de2002579255914d8bca14698f16854..9b73920323211351f14752f3d6c92e627c6fa9ed 100644 (file)
@@ -98,6 +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))
@@ -112,7 +113,8 @@ static int nfs4_stat_to_errno(int);
 #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 + \
@@ -123,7 +125,8 @@ static int nfs4_stat_to_errno(int);
                                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 +960,35 @@ static void encode_uint64(struct xdr_stream *xdr, u64 n)
        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 +1043,14 @@ static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *ve
        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,
@@ -1022,9 +1062,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
        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 };
 
        /*
@@ -1072,7 +1110,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
        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;
@@ -1081,7 +1119,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
        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;
@@ -1093,19 +1131,8 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
                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);
@@ -1118,16 +1145,14 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
        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 +1224,45 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *
                        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 +2101,8 @@ static void nfs4_xdr_enc_access(struct rpc_rqst *req, struct xdr_stream *xdr,
        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 +2544,17 @@ static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr,
        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 +2633,8 @@ static void nfs4_xdr_enc_pathconf(struct rpc_rqst *req, struct xdr_stream *xdr,
        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 +2652,8 @@ static void nfs4_xdr_enc_statfs(struct rpc_rqst *req, struct xdr_stream *xdr,
        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 +2673,7 @@ static void nfs4_xdr_enc_server_caps(struct rpc_rqst *req,
        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 +3207,27 @@ static int decode_ace(struct xdr_stream *xdr, void *ace)
        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 +3963,7 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap,
        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 +3998,7 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap,
        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 +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 +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 +6236,8 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
        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 +7517,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
        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;
@@ -7551,8 +7534,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
        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);
@@ -7586,6 +7568,9 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
        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:
index f7fd9192d4bc8e853656508cd492ae50aef4723e..4e93d63087338be524918512085c2e2f5a071cdb 100644 (file)
@@ -300,11 +300,11 @@ out:
 }
   
 static int
-nfs_proc_remove(struct inode *dir, const struct qstr *name)
+nfs_proc_remove(struct inode *dir, struct dentry *dentry)
 {
        struct nfs_removeargs arg = {
                .fh = NFS_FH(dir),
-               .name = *name,
+               .name = dentry->d_name,
        };
        struct rpc_message msg = { 
                .rpc_proc = &nfs_procedures[NFSPROC_REMOVE],
@@ -312,7 +312,7 @@ nfs_proc_remove(struct inode *dir, const struct qstr *name)
        };
        int                     status;
 
-       dprintk("NFS call  remove %s\n", name->name);
+       dprintk("NFS call  remove %pd2\n",dentry);
        status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
        nfs_mark_for_revalidate(dir);
 
@@ -321,7 +321,7 @@ nfs_proc_remove(struct inode *dir, const struct qstr *name)
 }
 
 static void
-nfs_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
+nfs_proc_unlink_setup(struct rpc_message *msg, struct dentry *dentry)
 {
        msg->rpc_proc = &nfs_procedures[NFSPROC_REMOVE];
 }
@@ -338,7 +338,9 @@ static int nfs_proc_unlink_done(struct rpc_task *task, struct inode *dir)
 }
 
 static void
-nfs_proc_rename_setup(struct rpc_message *msg, struct inode *dir)
+nfs_proc_rename_setup(struct rpc_message *msg,
+               struct dentry *old_dentry,
+               struct dentry *new_dentry)
 {
        msg->rpc_proc = &nfs_procedures[NFSPROC_RENAME];
 }
@@ -671,12 +673,6 @@ static int nfs_have_delegation(struct inode *inode, fmode_t flags)
        return 0;
 }
 
-static int nfs_return_delegation(struct inode *inode)
-{
-       nfs_wb_all(inode);
-       return 0;
-}
-
 static const struct inode_operations nfs_dir_inode_operations = {
        .create         = nfs_create,
        .lookup         = nfs_lookup,
@@ -741,7 +737,6 @@ const struct nfs_rpc_ops nfs_v2_clientops = {
        .lock_check_bounds = nfs_lock_check_bounds,
        .close_context  = nfs_close_context,
        .have_delegation = nfs_have_delegation,
-       .return_delegation = nfs_return_delegation,
        .alloc_client   = nfs_alloc_client,
        .init_client    = nfs_init_client,
        .free_client    = nfs_free_client,
index 630b4a3c1a93de58cfe7a6acc4ea5c083027ea4f..bf54fc9ae135fa3098bbfb4e713835cabde77c20 100644 (file)
@@ -105,7 +105,7 @@ static void nfs_do_call_unlink(struct nfs_unlinkdata *data)
        data->args.fh = NFS_FH(dir);
        nfs_fattr_init(data->res.dir_attr);
 
-       NFS_PROTO(dir)->unlink_setup(&msg, dir);
+       NFS_PROTO(dir)->unlink_setup(&msg, data->dentry);
 
        task_setup_data.rpc_client = NFS_CLIENT(dir);
        task = rpc_run_task(&task_setup_data);
@@ -386,7 +386,7 @@ nfs_async_rename(struct inode *old_dir, struct inode *new_dir,
 
        nfs_sb_active(old_dir->i_sb);
 
-       NFS_PROTO(data->old_dir)->rename_setup(&msg, old_dir);
+       NFS_PROTO(data->old_dir)->rename_setup(&msg, old_dentry, new_dentry);
 
        return rpc_run_task(&task_setup_data);
 }
@@ -463,9 +463,6 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry)
 
        fileid = NFS_FILEID(d_inode(dentry));
 
-       /* Return delegation in anticipation of the rename */
-       NFS_PROTO(d_inode(dentry))->return_delegation(d_inode(dentry));
-
        sdentry = NULL;
        do {
                int slen;
index 6579f3b367bdad8107340fdbbec32e439afd079d..0193053bc139d3228602d589dbb643206e970dba 100644 (file)
@@ -231,6 +231,7 @@ static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int c
        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 @@ static int nfs_writeback_done(struct rpc_task *task,
        }
 
        /* 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;
 }
 
index 38187c68063dad5fa34b3731946c9767c684dc3b..2f129bbfaae829cd9d04c8b7f91d13f9305221ec 100644 (file)
@@ -198,14 +198,24 @@ struct nfs_inode {
 /*
  * Cache validity bit flags
  */
-#define NFS_INO_INVALID_ATTR   0x0001          /* cached attrs are invalid */
-#define NFS_INO_INVALID_DATA   0x0002          /* cached data is invalid */
-#define NFS_INO_INVALID_ATIME  0x0004          /* cached atime is invalid */
-#define NFS_INO_INVALID_ACCESS 0x0008          /* cached access cred invalid */
-#define NFS_INO_INVALID_ACL    0x0010          /* cached acls are invalid */
-#define NFS_INO_REVAL_PAGECACHE        0x0020          /* must revalidate pagecache */
-#define NFS_INO_REVAL_FORCED   0x0040          /* force revalidation ignoring a delegation */
-#define NFS_INO_INVALID_LABEL  0x0080          /* cached label is invalid */
+#define NFS_INO_INVALID_DATA   BIT(1)          /* cached data is invalid */
+#define NFS_INO_INVALID_ATIME  BIT(2)          /* cached atime is invalid */
+#define NFS_INO_INVALID_ACCESS BIT(3)          /* cached access cred invalid */
+#define NFS_INO_INVALID_ACL    BIT(4)          /* cached acls are invalid */
+#define NFS_INO_REVAL_PAGECACHE        BIT(5)          /* must revalidate pagecache */
+#define NFS_INO_REVAL_FORCED   BIT(6)          /* force revalidation ignoring a delegation */
+#define NFS_INO_INVALID_LABEL  BIT(7)          /* cached label is invalid */
+#define NFS_INO_INVALID_CHANGE BIT(8)          /* cached change is invalid */
+#define NFS_INO_INVALID_CTIME  BIT(9)          /* cached ctime is invalid */
+#define NFS_INO_INVALID_MTIME  BIT(10)         /* cached mtime is invalid */
+#define NFS_INO_INVALID_SIZE   BIT(11)         /* cached size is invalid */
+#define NFS_INO_INVALID_OTHER  BIT(12)         /* other attrs are invalid */
+
+#define NFS_INO_INVALID_ATTR   (NFS_INO_INVALID_CHANGE \
+               | NFS_INO_INVALID_CTIME \
+               | NFS_INO_INVALID_MTIME \
+               | NFS_INO_INVALID_SIZE \
+               | NFS_INO_INVALID_OTHER)        /* inode metadata is invalid */
 
 /*
  * Bit offsets in flags field
@@ -292,10 +302,11 @@ static inline void nfs_mark_for_revalidate(struct inode *inode)
        struct nfs_inode *nfsi = NFS_I(inode);
 
        spin_lock(&inode->i_lock);
-       nfsi->cache_validity |= NFS_INO_INVALID_ATTR |
-                               NFS_INO_REVAL_PAGECACHE |
-                               NFS_INO_INVALID_ACCESS |
-                               NFS_INO_INVALID_ACL;
+       nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE
+               | NFS_INO_INVALID_ACCESS
+               | NFS_INO_INVALID_ACL
+               | NFS_INO_INVALID_CHANGE
+               | NFS_INO_INVALID_CTIME;
        if (S_ISDIR(inode->i_mode))
                nfsi->cache_validity |= NFS_INO_INVALID_DATA;
        spin_unlock(&inode->i_lock);
index 6959968dc36a779b3cb61cf80b6c2e1b99672ff7..34d28564ecf37e59f1b3d6a8a370ee8257c3e0a2 100644 (file)
@@ -1590,11 +1590,13 @@ struct nfs_rpc_ops {
                            unsigned int);
        int     (*create)  (struct inode *, struct dentry *,
                            struct iattr *, int);
-       int     (*remove)  (struct inode *, const struct qstr *);
-       void    (*unlink_setup)  (struct rpc_message *, struct inode *dir);
+       int     (*remove)  (struct inode *, struct dentry *);
+       void    (*unlink_setup)  (struct rpc_message *, struct dentry *);
        void    (*unlink_rpc_prepare) (struct rpc_task *, struct nfs_unlinkdata *);
        int     (*unlink_done) (struct rpc_task *, struct inode *);
-       void    (*rename_setup)  (struct rpc_message *msg, struct inode *dir);
+       void    (*rename_setup)  (struct rpc_message *msg,
+                       struct dentry *old_dentry,
+                       struct dentry *new_dentry);
        void    (*rename_rpc_prepare)(struct rpc_task *task, struct nfs_renamedata *);
        int     (*rename_done) (struct rpc_task *task, struct inode *old_dir, struct inode *new_dir);
        int     (*link)    (struct inode *, struct inode *, const struct qstr *);
@@ -1633,7 +1635,6 @@ struct nfs_rpc_ops {
                                struct iattr *iattr,
                                int *);
        int (*have_delegation)(struct inode *, fmode_t);
-       int (*return_delegation)(struct inode *);
        struct nfs_client *(*alloc_client) (const struct nfs_client_initdata *);
        struct nfs_client *(*init_client) (struct nfs_client *,
                                const struct nfs_client_initdata *);
index ed761f751ecbd954ee440d864d2ba7ee47a3f3f9..9b11b6a0978c95467761d142716c873ac5c201d4 100644 (file)
@@ -217,5 +217,12 @@ void rpc_clnt_xprt_switch_add_xprt(struct rpc_clnt *, struct rpc_xprt *);
 bool rpc_clnt_xprt_switch_has_addr(struct rpc_clnt *clnt,
                        const struct sockaddr *sap);
 void rpc_cleanup_clids(void);
+
+static inline int rpc_reply_expected(struct rpc_task *task)
+{
+       return (task->tk_msg.rpc_proc != NULL) &&
+               (task->tk_msg.rpc_proc->p_decode != NULL);
+}
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_SUNRPC_CLNT_H */
index d950223c64b1c533ebc624ff3337cb40000bad81..2bd68177a442e5402f7b015d16ac6047c14c5b0e 100644 (file)
@@ -253,6 +253,12 @@ xdr_stream_remaining(const struct xdr_stream *xdr)
        return xdr->nwords << 2;
 }
 
+ssize_t xdr_stream_decode_opaque(struct xdr_stream *xdr, void *ptr,
+               size_t size);
+ssize_t xdr_stream_decode_opaque_dup(struct xdr_stream *xdr, void **ptr,
+               size_t maxlen, gfp_t gfp_flags);
+ssize_t xdr_stream_decode_string(struct xdr_stream *xdr, char *str,
+               size_t size);
 ssize_t xdr_stream_decode_string_dup(struct xdr_stream *xdr, char **str,
                size_t maxlen, gfp_t gfp_flags);
 /**
@@ -312,6 +318,31 @@ xdr_stream_encode_u64(struct xdr_stream *xdr, __u64 n)
        return len;
 }
 
+/**
+ * xdr_stream_encode_opaque_inline - Encode opaque xdr data
+ * @xdr: pointer to xdr_stream
+ * @ptr: pointer to void pointer
+ * @len: size of object
+ *
+ * Return values:
+ *   On success, returns length in bytes of XDR buffer consumed
+ *   %-EMSGSIZE on XDR buffer overflow
+ */
+static inline ssize_t
+xdr_stream_encode_opaque_inline(struct xdr_stream *xdr, void **ptr, size_t len)
+{
+       size_t count = sizeof(__u32) + xdr_align_size(len);
+       __be32 *p = xdr_reserve_space(xdr, count);
+
+       if (unlikely(!p)) {
+               *ptr = NULL;
+               return -EMSGSIZE;
+       }
+       xdr_encode_opaque(p, NULL, len);
+       *ptr = ++p;
+       return count;
+}
+
 /**
  * xdr_stream_encode_opaque_fixed - Encode fixed length opaque xdr data
  * @xdr: pointer to xdr_stream
@@ -355,6 +386,31 @@ xdr_stream_encode_opaque(struct xdr_stream *xdr, const void *ptr, size_t len)
        return count;
 }
 
+/**
+ * xdr_stream_encode_uint32_array - Encode variable length array of integers
+ * @xdr: pointer to xdr_stream
+ * @array: array of integers
+ * @array_size: number of elements in @array
+ *
+ * Return values:
+ *   On success, returns length in bytes of XDR buffer consumed
+ *   %-EMSGSIZE on XDR buffer overflow
+ */
+static inline ssize_t
+xdr_stream_encode_uint32_array(struct xdr_stream *xdr,
+               const __u32 *array, size_t array_size)
+{
+       ssize_t ret = (array_size+1) * sizeof(__u32);
+       __be32 *p = xdr_reserve_space(xdr, ret);
+
+       if (unlikely(!p))
+               return -EMSGSIZE;
+       *p++ = cpu_to_be32(array_size);
+       for (; array_size > 0; p++, array++, array_size--)
+               *p = cpu_to_be32p(array);
+       return ret;
+}
+
 /**
  * xdr_stream_decode_u32 - Decode a 32-bit integer
  * @xdr: pointer to xdr_stream
@@ -432,6 +488,44 @@ xdr_stream_decode_opaque_inline(struct xdr_stream *xdr, void **ptr, size_t maxle
        }
        return len;
 }
+
+/**
+ * xdr_stream_decode_uint32_array - Decode variable length array of integers
+ * @xdr: pointer to xdr_stream
+ * @array: location to store the integer array or NULL
+ * @array_size: number of elements to store
+ *
+ * Return values:
+ *   On success, returns number of elements stored in @array
+ *   %-EBADMSG on XDR buffer overflow
+ *   %-EMSGSIZE if the size of the array exceeds @array_size
+ */
+static inline ssize_t
+xdr_stream_decode_uint32_array(struct xdr_stream *xdr,
+               __u32 *array, size_t array_size)
+{
+       __be32 *p;
+       __u32 len;
+       ssize_t retval;
+
+       if (unlikely(xdr_stream_decode_u32(xdr, &len) < 0))
+               return -EBADMSG;
+       p = xdr_inline_decode(xdr, len * sizeof(*p));
+       if (unlikely(!p))
+               return -EBADMSG;
+       if (array == NULL)
+               return len;
+       if (len <= array_size) {
+               if (len < array_size)
+                       memset(array+len, 0, (array_size-len)*sizeof(*array));
+               array_size = len;
+               retval = len;
+       } else
+               retval = -EMSGSIZE;
+       for (; array_size > 0; p++, array++, array_size--)
+               *array = be32_to_cpup(p);
+       return retval;
+}
 #endif /* __KERNEL__ */
 
 #endif /* _SUNRPC_XDR_H_ */
index 7fad83881ce197bd8b629c85fe25b67239e309dc..5fea0fb420df2d3a42037e7e420aea1f38e05bd8 100644 (file)
@@ -197,7 +197,7 @@ struct rpc_xprt {
        struct list_head        free;           /* free slots */
        unsigned int            max_reqs;       /* max number of slots */
        unsigned int            min_reqs;       /* min number of slots */
-       atomic_t                num_reqs;       /* total slots */
+       unsigned int            num_reqs;       /* total slots */
        unsigned long           state;          /* transport state */
        unsigned char           resvport   : 1; /* use a reserved port */
        atomic_t                swapper;        /* we're swapping over this
@@ -373,6 +373,7 @@ void                        xprt_wait_for_buffer_space(struct rpc_task *task, rpc_action action);
 void                   xprt_write_space(struct rpc_xprt *xprt);
 void                   xprt_adjust_cwnd(struct rpc_xprt *xprt, struct rpc_task *task, int result);
 struct rpc_rqst *      xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid);
+void                   xprt_update_rtt(struct rpc_task *task);
 void                   xprt_complete_rqst(struct rpc_task *task, int copied);
 void                   xprt_pin_rqst(struct rpc_rqst *req);
 void                   xprt_unpin_rqst(struct rpc_rqst *req);
index 922cb8968fb246ed22126b910713b07d1ecc8597..335d87242439db1b64d2ed7ad0c167844d0c5dad 100644 (file)
@@ -50,9 +50,9 @@ DEFINE_EVENT(rpc_task_status, rpc_bind_status,
 );
 
 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 @@ TRACE_EVENT(rpc_connect_status,
        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 @@ 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)
@@ -117,7 +117,8 @@ DECLARE_EVENT_CLASS(rpc_task_running,
                ),
 
        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;
@@ -136,33 +137,33 @@ DECLARE_EVENT_CLASS(rpc_task_running,
 
 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)
@@ -175,7 +176,8 @@ DECLARE_EVENT_CLASS(rpc_task_queued,
                ),
 
        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;
@@ -196,18 +198,63 @@ DECLARE_EVENT_CLASS(rpc_task_queued,
 
 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(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(clnt, task, q)
+       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)
 );
 
 /*
@@ -406,6 +453,27 @@ DEFINE_EVENT(rpc_xprt_event, xprt_complete_rqst,
        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),
 
index 806395687bb661ab570b7dbc20858edba12ca931..c2266f3872137a55993b2ad7d59bd9b623d03322 100644 (file)
@@ -1887,7 +1887,7 @@ call_connect_status(struct rpc_task *task)
 
        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 @@ call_transmit_status(struct rpc_task *task)
        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 @@ 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;
 
index d9db2eab3a8df1dec09a0df3a0e5e6310e5fe91d..3fe5d60ab0e2c6ecd24a4946c32e07dfd941411f 100644 (file)
@@ -276,7 +276,7 @@ static void rpc_set_active(struct rpc_task *task)
 {
        rpc_task_set_debuginfo(task);
        set_bit(RPC_TASK_ACTIVE, &task->tk_runstate);
-       trace_rpc_task_begin(task->tk_client, task, NULL);
+       trace_rpc_task_begin(task, NULL);
 }
 
 /*
@@ -291,7 +291,7 @@ static int rpc_complete_task(struct rpc_task *task)
        unsigned long flags;
        int ret;
 
-       trace_rpc_task_complete(task->tk_client, task, NULL);
+       trace_rpc_task_complete(task, NULL);
 
        spin_lock_irqsave(&wq->lock, flags);
        clear_bit(RPC_TASK_ACTIVE, &task->tk_runstate);
@@ -358,7 +358,7 @@ static void __rpc_sleep_on_priority(struct rpc_wait_queue *q,
        dprintk("RPC: %5u sleep_on(queue \"%s\" time %lu)\n",
                        task->tk_pid, rpc_qname(q), jiffies);
 
-       trace_rpc_task_sleep(task->tk_client, task, q);
+       trace_rpc_task_sleep(task, q);
 
        __rpc_add_wait_queue(q, task, queue_priority);
 
@@ -428,7 +428,7 @@ static void __rpc_do_wake_up_task_on_wq(struct workqueue_struct *wq,
                return;
        }
 
-       trace_rpc_task_wakeup(task->tk_client, task, queue);
+       trace_rpc_task_wakeup(task, queue);
 
        __rpc_remove_wait_queue(queue, task);
 
@@ -780,7 +780,7 @@ static void __rpc_execute(struct rpc_task *task)
                }
                if (!do_action)
                        break;
-               trace_rpc_task_run_action(task->tk_client, task, do_action);
+               trace_rpc_task_run_action(task, do_action);
                do_action(task);
 
                /*
index 1e671333c3d5b5a61be412860a4cfe85db7b66eb..f68aa46c9dd7125bee03506a9a3e4914939770ae 100644 (file)
@@ -24,6 +24,8 @@
 #include <linux/sunrpc/metrics.h>
 #include <linux/rcupdate.h>
 
+#include <trace/events/sunrpc.h>
+
 #include "netns.h"
 
 #define RPCDBG_FACILITY        RPCDBG_MISC
@@ -148,7 +150,7 @@ void rpc_count_iostats_metrics(const struct rpc_task *task,
                               struct rpc_iostats *op_metrics)
 {
        struct rpc_rqst *req = task->tk_rqstp;
-       ktime_t delta, now;
+       ktime_t backlog, execute, now;
 
        if (!op_metrics || !req)
                return;
@@ -164,16 +166,20 @@ void rpc_count_iostats_metrics(const struct rpc_task *task,
        op_metrics->om_bytes_sent += req->rq_xmit_bytes_sent;
        op_metrics->om_bytes_recv += req->rq_reply_bytes_recvd;
 
+       backlog = 0;
        if (ktime_to_ns(req->rq_xtime)) {
-               delta = ktime_sub(req->rq_xtime, task->tk_start);
-               op_metrics->om_queue = ktime_add(op_metrics->om_queue, delta);
+               backlog = ktime_sub(req->rq_xtime, task->tk_start);
+               op_metrics->om_queue = ktime_add(op_metrics->om_queue, backlog);
        }
+
        op_metrics->om_rtt = ktime_add(op_metrics->om_rtt, req->rq_rtt);
 
-       delta = ktime_sub(now, task->tk_start);
-       op_metrics->om_execute = ktime_add(op_metrics->om_execute, delta);
+       execute = ktime_sub(now, task->tk_start);
+       op_metrics->om_execute = ktime_add(op_metrics->om_execute, execute);
 
        spin_unlock(&op_metrics->om_lock);
+
+       trace_rpc_stats_latency(req->rq_task, backlog, req->rq_rtt, execute);
 }
 EXPORT_SYMBOL_GPL(rpc_count_iostats_metrics);
 
index f2b7cb540e61997ce427e132f7d0f20cada5a46e..09a0315ea77b3955115aa3db9abe891b518799c9 100644 (file)
@@ -37,12 +37,6 @@ struct rpc_buffer {
        char    data[];
 };
 
-static inline int rpc_reply_expected(struct rpc_task *task)
-{
-       return (task->tk_msg.rpc_proc != NULL) &&
-               (task->tk_msg.rpc_proc->p_decode != NULL);
-}
-
 static inline int sock_is_loopback(struct sock *sk)
 {
        struct dst_entry *dst;
index e34f4ee7f2b6cecdf404daab0d3aab363d94ba01..30afbd236656672e0e9e87d6bfc07a76b742bf4d 100644 (file)
@@ -1518,6 +1518,88 @@ out:
 }
 EXPORT_SYMBOL_GPL(xdr_process_buf);
 
+/**
+ * xdr_stream_decode_opaque - Decode variable length opaque
+ * @xdr: pointer to xdr_stream
+ * @ptr: location to store opaque data
+ * @size: size of storage buffer @ptr
+ *
+ * Return values:
+ *   On success, returns size of object stored in *@ptr
+ *   %-EBADMSG on XDR buffer overflow
+ *   %-EMSGSIZE on overflow of storage buffer @ptr
+ */
+ssize_t xdr_stream_decode_opaque(struct xdr_stream *xdr, void *ptr, size_t size)
+{
+       ssize_t ret;
+       void *p;
+
+       ret = xdr_stream_decode_opaque_inline(xdr, &p, size);
+       if (ret <= 0)
+               return ret;
+       memcpy(ptr, p, ret);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(xdr_stream_decode_opaque);
+
+/**
+ * xdr_stream_decode_opaque_dup - Decode and duplicate variable length opaque
+ * @xdr: pointer to xdr_stream
+ * @ptr: location to store pointer to opaque data
+ * @maxlen: maximum acceptable object size
+ * @gfp_flags: GFP mask to use
+ *
+ * Return values:
+ *   On success, returns size of object stored in *@ptr
+ *   %-EBADMSG on XDR buffer overflow
+ *   %-EMSGSIZE if the size of the object would exceed @maxlen
+ *   %-ENOMEM on memory allocation failure
+ */
+ssize_t xdr_stream_decode_opaque_dup(struct xdr_stream *xdr, void **ptr,
+               size_t maxlen, gfp_t gfp_flags)
+{
+       ssize_t ret;
+       void *p;
+
+       ret = xdr_stream_decode_opaque_inline(xdr, &p, maxlen);
+       if (ret > 0) {
+               *ptr = kmemdup(p, ret, gfp_flags);
+               if (*ptr != NULL)
+                       return ret;
+               ret = -ENOMEM;
+       }
+       *ptr = NULL;
+       return ret;
+}
+EXPORT_SYMBOL_GPL(xdr_stream_decode_opaque_dup);
+
+/**
+ * xdr_stream_decode_string - Decode variable length string
+ * @xdr: pointer to xdr_stream
+ * @str: location to store string
+ * @size: size of storage buffer @str
+ *
+ * Return values:
+ *   On success, returns length of NUL-terminated string stored in *@str
+ *   %-EBADMSG on XDR buffer overflow
+ *   %-EMSGSIZE on overflow of storage buffer @str
+ */
+ssize_t xdr_stream_decode_string(struct xdr_stream *xdr, char *str, size_t size)
+{
+       ssize_t ret;
+       void *p;
+
+       ret = xdr_stream_decode_opaque_inline(xdr, &p, size);
+       if (ret > 0) {
+               memcpy(str, p, ret);
+               str[ret] = '\0';
+               return strlen(str);
+       }
+       *str = '\0';
+       return ret;
+}
+EXPORT_SYMBOL_GPL(xdr_stream_decode_string);
+
 /**
  * xdr_stream_decode_string_dup - Decode and duplicate variable length string
  * @xdr: pointer to xdr_stream
index 8f0ad4f268da58e2380361e72e9adcace18548dd..70f005044f06417ee09c94b85b9d125dc34da206 100644 (file)
@@ -826,6 +826,7 @@ static void xprt_connect_status(struct rpc_task *task)
  * @xprt: transport on which the original request was transmitted
  * @xid: RPC XID of incoming reply
  *
+ * Caller holds xprt->recv_lock.
  */
 struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid)
 {
@@ -834,6 +835,7 @@ struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid)
        list_for_each_entry(entry, &xprt->recv, rq_list)
                if (entry->rq_xid == xid) {
                        trace_xprt_lookup_rqst(xprt, xid, 0);
+                       entry->rq_rtt = ktime_sub(ktime_get(), entry->rq_xtime);
                        return entry;
                }
 
@@ -889,7 +891,13 @@ __must_hold(&req->rq_xprt->recv_lock)
        }
 }
 
-static void xprt_update_rtt(struct rpc_task *task)
+/**
+ * xprt_update_rtt - Update RPC RTT statistics
+ * @task: RPC request that recently completed
+ *
+ * Caller holds xprt->recv_lock.
+ */
+void xprt_update_rtt(struct rpc_task *task)
 {
        struct rpc_rqst *req = task->tk_rqstp;
        struct rpc_rtt *rtt = task->tk_client->cl_rtt;
@@ -902,13 +910,14 @@ static void xprt_update_rtt(struct rpc_task *task)
                rpc_set_timeo(rtt, timer, req->rq_ntrans - 1);
        }
 }
+EXPORT_SYMBOL_GPL(xprt_update_rtt);
 
 /**
  * xprt_complete_rqst - called when reply processing is complete
  * @task: RPC request that recently completed
  * @copied: actual number of bytes received from the transport
  *
- * Caller holds transport lock.
+ * Caller holds xprt->recv_lock.
  */
 void xprt_complete_rqst(struct rpc_task *task, int copied)
 {
@@ -920,9 +929,6 @@ void xprt_complete_rqst(struct rpc_task *task, int copied)
        trace_xprt_complete_rqst(xprt, req->rq_xid, copied);
 
        xprt->stat.recvs++;
-       req->rq_rtt = ktime_sub(ktime_get(), req->rq_xtime);
-       if (xprt->ops->timer != NULL)
-               xprt_update_rtt(task);
 
        list_del_init(&req->rq_list);
        req->rq_private_buf.len = copied;
@@ -1003,7 +1009,7 @@ void xprt_transmit(struct rpc_task *task)
        struct rpc_rqst *req = task->tk_rqstp;
        struct rpc_xprt *xprt = req->rq_xprt;
        unsigned int connect_cookie;
-       int status, numreqs;
+       int status;
 
        dprintk("RPC: %5u xprt_transmit(%u)\n", task->tk_pid, req->rq_slen);
 
@@ -1027,7 +1033,6 @@ void xprt_transmit(struct rpc_task *task)
                return;
 
        connect_cookie = xprt->connect_cookie;
-       req->rq_xtime = ktime_get();
        status = xprt->ops->send_request(task);
        trace_xprt_transmit(xprt, req->rq_xid, status);
        if (status != 0) {
@@ -1042,9 +1047,6 @@ void xprt_transmit(struct rpc_task *task)
 
        xprt->ops->set_retrans_timeout(task);
 
-       numreqs = atomic_read(&xprt->num_reqs);
-       if (numreqs > xprt->stat.max_slots)
-               xprt->stat.max_slots = numreqs;
        xprt->stat.sends++;
        xprt->stat.req_u += xprt->stat.sends - xprt->stat.recvs;
        xprt->stat.bklog_u += xprt->backlog.qlen;
@@ -1106,14 +1108,15 @@ static struct rpc_rqst *xprt_dynamic_alloc_slot(struct rpc_xprt *xprt)
 {
        struct rpc_rqst *req = ERR_PTR(-EAGAIN);
 
-       if (!atomic_add_unless(&xprt->num_reqs, 1, xprt->max_reqs))
+       if (xprt->num_reqs >= xprt->max_reqs)
                goto out;
+       ++xprt->num_reqs;
        spin_unlock(&xprt->reserve_lock);
        req = kzalloc(sizeof(struct rpc_rqst), GFP_NOFS);
        spin_lock(&xprt->reserve_lock);
        if (req != NULL)
                goto out;
-       atomic_dec(&xprt->num_reqs);
+       --xprt->num_reqs;
        req = ERR_PTR(-ENOMEM);
 out:
        return req;
@@ -1121,7 +1124,8 @@ out:
 
 static bool xprt_dynamic_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req)
 {
-       if (atomic_add_unless(&xprt->num_reqs, -1, xprt->min_reqs)) {
+       if (xprt->num_reqs > xprt->min_reqs) {
+               --xprt->num_reqs;
                kfree(req);
                return true;
        }
@@ -1157,6 +1161,8 @@ void xprt_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task)
        spin_unlock(&xprt->reserve_lock);
        return;
 out_init_req:
+       xprt->stat.max_slots = max_t(unsigned int, xprt->stat.max_slots,
+                                    xprt->num_reqs);
        task->tk_status = 0;
        task->tk_rqstp = req;
        xprt_request_init(task, xprt);
@@ -1224,7 +1230,7 @@ struct rpc_xprt *xprt_alloc(struct net *net, size_t size,
        else
                xprt->max_reqs = num_prealloc;
        xprt->min_reqs = num_prealloc;
-       atomic_set(&xprt->num_reqs, num_prealloc);
+       xprt->num_reqs = num_prealloc;
 
        return xprt;
 
index ed1a4a3065ee8a4e6530bc20c94e8a63e57f0adf..47ebac94976991269be86f7200c9f73d8bfc8959 100644 (file)
@@ -44,13 +44,6 @@ static int rpcrdma_bc_setup_rqst(struct rpcrdma_xprt *r_xprt,
        if (IS_ERR(req))
                return PTR_ERR(req);
 
-       rb = rpcrdma_alloc_regbuf(RPCRDMA_HDRBUF_SIZE,
-                                 DMA_TO_DEVICE, GFP_KERNEL);
-       if (IS_ERR(rb))
-               goto out_fail;
-       req->rl_rdmabuf = rb;
-       xdr_buf_init(&req->rl_hdrbuf, rb->rg_base, rdmab_length(rb));
-
        size = r_xprt->rx_data.inline_rsize;
        rb = rpcrdma_alloc_regbuf(size, DMA_TO_DEVICE, GFP_KERNEL);
        if (IS_ERR(rb))
index d5f95bb39300e61ac2e3e4f9ddd83e947135473f..5cc68a824f451b16d66a88c7cb43f2d16628ea38 100644 (file)
@@ -191,7 +191,7 @@ fmr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
 
        mr = rpcrdma_mr_get(r_xprt);
        if (!mr)
-               return ERR_PTR(-ENOBUFS);
+               return ERR_PTR(-EAGAIN);
 
        pageoff = offset_in_page(seg1->mr_offset);
        seg1->mr_offset -= pageoff;     /* start of page */
@@ -251,6 +251,16 @@ out_maperr:
        return ERR_PTR(-EIO);
 }
 
+/* Post Send WR containing the RPC Call message.
+ */
+static int
+fmr_op_send(struct rpcrdma_ia *ia, struct rpcrdma_req *req)
+{
+       struct ib_send_wr *bad_wr;
+
+       return ib_post_send(ia->ri_id->qp, &req->rl_sendctx->sc_wr, &bad_wr);
+}
+
 /* Invalidate all memory regions that were registered for "req".
  *
  * Sleeps until it is safe for the host CPU to access the
@@ -305,6 +315,7 @@ out_reset:
 
 const struct rpcrdma_memreg_ops rpcrdma_fmr_memreg_ops = {
        .ro_map                         = fmr_op_map,
+       .ro_send                        = fmr_op_send,
        .ro_unmap_sync                  = fmr_op_unmap_sync,
        .ro_recover_mr                  = fmr_op_recover_mr,
        .ro_open                        = fmr_op_open,
index 90f688f19783d089fe90fffc40f104bb6e43a94c..c5743a0960be46a10a67b6021ab5332d9a0b37a8 100644 (file)
@@ -357,8 +357,7 @@ frwr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
        struct rpcrdma_mr *mr;
        struct ib_mr *ibmr;
        struct ib_reg_wr *reg_wr;
-       struct ib_send_wr *bad_wr;
-       int rc, i, n;
+       int i, n;
        u8 key;
 
        mr = NULL;
@@ -367,7 +366,7 @@ frwr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
                        rpcrdma_mr_defer_recovery(mr);
                mr = rpcrdma_mr_get(r_xprt);
                if (!mr)
-                       return ERR_PTR(-ENOBUFS);
+                       return ERR_PTR(-EAGAIN);
        } while (mr->frwr.fr_state != FRWR_IS_INVALID);
        frwr = &mr->frwr;
        frwr->fr_state = FRWR_IS_VALID;
@@ -407,22 +406,12 @@ frwr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
        ib_update_fast_reg_key(ibmr, ++key);
 
        reg_wr = &frwr->fr_regwr;
-       reg_wr->wr.next = NULL;
-       reg_wr->wr.opcode = IB_WR_REG_MR;
-       frwr->fr_cqe.done = frwr_wc_fastreg;
-       reg_wr->wr.wr_cqe = &frwr->fr_cqe;
-       reg_wr->wr.num_sge = 0;
-       reg_wr->wr.send_flags = 0;
        reg_wr->mr = ibmr;
        reg_wr->key = ibmr->rkey;
        reg_wr->access = writing ?
                         IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE :
                         IB_ACCESS_REMOTE_READ;
 
-       rc = ib_post_send(ia->ri_id->qp, &reg_wr->wr, &bad_wr);
-       if (rc)
-               goto out_senderr;
-
        mr->mr_handle = ibmr->rkey;
        mr->mr_length = ibmr->length;
        mr->mr_offset = ibmr->iova;
@@ -442,11 +431,40 @@ out_mapmr_err:
               frwr->fr_mr, n, mr->mr_nents);
        rpcrdma_mr_defer_recovery(mr);
        return ERR_PTR(-EIO);
+}
 
-out_senderr:
-       pr_err("rpcrdma: FRWR registration ib_post_send returned %i\n", rc);
-       rpcrdma_mr_defer_recovery(mr);
-       return ERR_PTR(-ENOTCONN);
+/* Post Send WR containing the RPC Call message.
+ *
+ * For FRMR, chain any FastReg WRs to the Send WR. Only a
+ * single ib_post_send call is needed to register memory
+ * and then post the Send WR.
+ */
+static int
+frwr_op_send(struct rpcrdma_ia *ia, struct rpcrdma_req *req)
+{
+       struct ib_send_wr *post_wr, *bad_wr;
+       struct rpcrdma_mr *mr;
+
+       post_wr = &req->rl_sendctx->sc_wr;
+       list_for_each_entry(mr, &req->rl_registered, mr_list) {
+               struct rpcrdma_frwr *frwr;
+
+               frwr = &mr->frwr;
+
+               frwr->fr_cqe.done = frwr_wc_fastreg;
+               frwr->fr_regwr.wr.next = post_wr;
+               frwr->fr_regwr.wr.wr_cqe = &frwr->fr_cqe;
+               frwr->fr_regwr.wr.num_sge = 0;
+               frwr->fr_regwr.wr.opcode = IB_WR_REG_MR;
+               frwr->fr_regwr.wr.send_flags = 0;
+
+               post_wr = &frwr->fr_regwr.wr;
+       }
+
+       /* If ib_post_send fails, the next ->send_request for
+        * @req will queue these MWs for recovery.
+        */
+       return ib_post_send(ia->ri_id->qp, post_wr, &bad_wr);
 }
 
 /* Handle a remotely invalidated mr on the @mrs list
@@ -561,6 +579,7 @@ reset_mrs:
 
 const struct rpcrdma_memreg_ops rpcrdma_frwr_memreg_ops = {
        .ro_map                         = frwr_op_map,
+       .ro_send                        = frwr_op_send,
        .ro_reminv                      = frwr_op_reminv,
        .ro_unmap_sync                  = frwr_op_unmap_sync,
        .ro_recover_mr                  = frwr_op_recover_mr,
index f0855a959a278dac5c8e6459cd94df244f87ee2c..e8adad33d0bb71671625c4da2b29ca05d8ce7b2a 100644 (file)
@@ -365,7 +365,7 @@ rpcrdma_encode_read_list(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req,
                seg = r_xprt->rx_ia.ri_ops->ro_map(r_xprt, seg, nsegs,
                                                   false, &mr);
                if (IS_ERR(seg))
-                       return PTR_ERR(seg);
+                       goto out_maperr;
                rpcrdma_mr_push(mr, &req->rl_registered);
 
                if (encode_read_segment(xdr, mr, pos) < 0)
@@ -377,6 +377,11 @@ rpcrdma_encode_read_list(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req,
        } while (nsegs);
 
        return 0;
+
+out_maperr:
+       if (PTR_ERR(seg) == -EAGAIN)
+               xprt_wait_for_buffer_space(rqst->rq_task, NULL);
+       return PTR_ERR(seg);
 }
 
 /* Register and XDR encode the Write list. Supports encoding a list
@@ -423,7 +428,7 @@ rpcrdma_encode_write_list(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req,
                seg = r_xprt->rx_ia.ri_ops->ro_map(r_xprt, seg, nsegs,
                                                   true, &mr);
                if (IS_ERR(seg))
-                       return PTR_ERR(seg);
+                       goto out_maperr;
                rpcrdma_mr_push(mr, &req->rl_registered);
 
                if (encode_rdma_segment(xdr, mr) < 0)
@@ -440,6 +445,11 @@ rpcrdma_encode_write_list(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req,
        *segcount = cpu_to_be32(nchunks);
 
        return 0;
+
+out_maperr:
+       if (PTR_ERR(seg) == -EAGAIN)
+               xprt_wait_for_buffer_space(rqst->rq_task, NULL);
+       return PTR_ERR(seg);
 }
 
 /* Register and XDR encode the Reply chunk. Supports encoding an array
@@ -481,7 +491,7 @@ rpcrdma_encode_reply_chunk(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req,
                seg = r_xprt->rx_ia.ri_ops->ro_map(r_xprt, seg, nsegs,
                                                   true, &mr);
                if (IS_ERR(seg))
-                       return PTR_ERR(seg);
+                       goto out_maperr;
                rpcrdma_mr_push(mr, &req->rl_registered);
 
                if (encode_rdma_segment(xdr, mr) < 0)
@@ -498,6 +508,11 @@ rpcrdma_encode_reply_chunk(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req,
        *segcount = cpu_to_be32(nchunks);
 
        return 0;
+
+out_maperr:
+       if (PTR_ERR(seg) == -EAGAIN)
+               xprt_wait_for_buffer_space(rqst->rq_task, NULL);
+       return PTR_ERR(seg);
 }
 
 /**
@@ -724,8 +739,8 @@ rpcrdma_prepare_send_sges(struct rpcrdma_xprt *r_xprt,
  * Returns:
  *     %0 if the RPC was sent successfully,
  *     %-ENOTCONN if the connection was lost,
- *     %-EAGAIN if not enough pages are available for on-demand reply buffer,
- *     %-ENOBUFS if no MRs are available to register chunks,
+ *     %-EAGAIN if the caller should call again with the same arguments,
+ *     %-ENOBUFS if the caller should call again after a delay,
  *     %-EMSGSIZE if the transport header is too small,
  *     %-EIO if a permanent problem occurred while marshaling.
  */
@@ -868,10 +883,7 @@ rpcrdma_marshal_req(struct rpcrdma_xprt *r_xprt, struct rpc_rqst *rqst)
        return 0;
 
 out_err:
-       if (ret != -ENOBUFS) {
-               pr_err("rpcrdma: header marshaling failed (%d)\n", ret);
-               r_xprt->rx_stats.failed_marshal_count++;
-       }
+       r_xprt->rx_stats.failed_marshal_count++;
        return ret;
 }
 
@@ -1366,7 +1378,7 @@ void rpcrdma_reply_handler(struct rpcrdma_rep *rep)
 
        trace_xprtrdma_reply(rqst->rq_task, rep, req, credits);
 
-       queue_work_on(req->rl_cpu, rpcrdma_receive_wq, &rep->rr_work);
+       queue_work(rpcrdma_receive_wq, &rep->rr_work);
        return;
 
 out_badstatus:
index 4b1ecfe979cf4d5b0df54679fdd127f7b24847f8..cc1aad325496ad13b3eb9fda328276a401e72ca6 100644 (file)
@@ -52,7 +52,6 @@
 #include <linux/slab.h>
 #include <linux/seq_file.h>
 #include <linux/sunrpc/addr.h>
-#include <linux/smp.h>
 
 #include "xprt_rdma.h"
 
@@ -237,8 +236,6 @@ rpcrdma_connect_worker(struct work_struct *work)
        struct rpc_xprt *xprt = &r_xprt->rx_xprt;
 
        spin_lock_bh(&xprt->transport_lock);
-       if (++xprt->connect_cookie == 0)        /* maintain a reserved value */
-               ++xprt->connect_cookie;
        if (ep->rep_connected > 0) {
                if (!xprt_test_and_set_connected(xprt))
                        xprt_wake_pending_tasks(xprt, 0);
@@ -540,29 +537,6 @@ xprt_rdma_connect(struct rpc_xprt *xprt, struct rpc_task *task)
        }
 }
 
-/* Allocate a fixed-size buffer in which to construct and send the
- * RPC-over-RDMA header for this request.
- */
-static bool
-rpcrdma_get_rdmabuf(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req,
-                   gfp_t flags)
-{
-       size_t size = RPCRDMA_HDRBUF_SIZE;
-       struct rpcrdma_regbuf *rb;
-
-       if (req->rl_rdmabuf)
-               return true;
-
-       rb = rpcrdma_alloc_regbuf(size, DMA_TO_DEVICE, flags);
-       if (IS_ERR(rb))
-               return false;
-
-       r_xprt->rx_stats.hardway_register_count += size;
-       req->rl_rdmabuf = rb;
-       xdr_buf_init(&req->rl_hdrbuf, rb->rg_base, rdmab_length(rb));
-       return true;
-}
-
 static bool
 rpcrdma_get_sendbuf(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req,
                    size_t size, gfp_t flags)
@@ -644,15 +618,11 @@ xprt_rdma_allocate(struct rpc_task *task)
        if (RPC_IS_SWAPPER(task))
                flags = __GFP_MEMALLOC | GFP_NOWAIT | __GFP_NOWARN;
 
-       if (!rpcrdma_get_rdmabuf(r_xprt, req, flags))
-               goto out_fail;
        if (!rpcrdma_get_sendbuf(r_xprt, req, rqst->rq_callsize, flags))
                goto out_fail;
        if (!rpcrdma_get_recvbuf(r_xprt, req, rqst->rq_rcvsize, flags))
                goto out_fail;
 
-       req->rl_cpu = smp_processor_id();
-       req->rl_connect_cookie = 0;     /* our reserved value */
        rpcrdma_set_xprtdata(rqst, req);
        rqst->rq_buffer = req->rl_sendbuf->rg_base;
        rqst->rq_rbuffer = req->rl_recvbuf->rg_base;
@@ -694,7 +664,8 @@ xprt_rdma_free(struct rpc_task *task)
  * Returns:
  *     %0 if the RPC message has been sent
  *     %-ENOTCONN if the caller should reconnect and call again
- *     %-ENOBUFS if the caller should call again later
+ *     %-EAGAIN if the caller should call again
+ *     %-ENOBUFS if the caller should call again after a delay
  *     %-EIO if a permanent error occurred and the request was not
  *             sent. Do not try to send this message again.
  */
@@ -723,9 +694,9 @@ xprt_rdma_send_request(struct rpc_task *task)
                rpcrdma_recv_buffer_get(req);
 
        /* Must suppress retransmit to maintain credits */
-       if (req->rl_connect_cookie == xprt->connect_cookie)
+       if (rqst->rq_connect_cookie == xprt->connect_cookie)
                goto drop_connection;
-       req->rl_connect_cookie = xprt->connect_cookie;
+       rqst->rq_xtime = ktime_get();
 
        __set_bit(RPCRDMA_REQ_F_PENDING, &req->rl_flags);
        if (rpcrdma_ep_post(&r_xprt->rx_ia, &r_xprt->rx_ep, req))
@@ -733,6 +704,12 @@ xprt_rdma_send_request(struct rpc_task *task)
 
        rqst->rq_xmit_bytes_sent += rqst->rq_snd_buf.len;
        rqst->rq_bytes_sent = 0;
+
+       /* An RPC with no reply will throw off credit accounting,
+        * so drop the connection to reset the credit grant.
+        */
+       if (!rpc_reply_expected(task))
+               goto drop_connection;
        return 0;
 
 failed_marshal:
index e6f84a6434a049e41d83092a0764668a21416d4c..fe5eaca2d19744df58f0e240766048d4a8be25e9 100644 (file)
@@ -250,11 +250,11 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event)
                wait_for_completion(&ia->ri_remove_done);
 
                ia->ri_id = NULL;
-               ia->ri_pd = NULL;
                ia->ri_device = NULL;
                /* Return 1 to ensure the core destroys the id. */
                return 1;
        case RDMA_CM_EVENT_ESTABLISHED:
+               ++xprt->rx_xprt.connect_cookie;
                connstate = 1;
                rpcrdma_update_connect_private(xprt, &event->param.conn);
                goto connected;
@@ -273,6 +273,7 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event)
                        connstate = -EAGAIN;
                goto connected;
        case RDMA_CM_EVENT_DISCONNECTED:
+               ++xprt->rx_xprt.connect_cookie;
                connstate = -ECONNABORTED;
 connected:
                xprt->rx_buf.rb_credits = 1;
@@ -445,7 +446,9 @@ rpcrdma_ia_remove(struct rpcrdma_ia *ia)
                ia->ri_id->qp = NULL;
        }
        ib_free_cq(ep->rep_attr.recv_cq);
+       ep->rep_attr.recv_cq = NULL;
        ib_free_cq(ep->rep_attr.send_cq);
+       ep->rep_attr.send_cq = NULL;
 
        /* The ULP is responsible for ensuring all DMA
         * mappings and MRs are gone.
@@ -458,6 +461,8 @@ rpcrdma_ia_remove(struct rpcrdma_ia *ia)
                rpcrdma_dma_unmap_regbuf(req->rl_recvbuf);
        }
        rpcrdma_mrs_destroy(buf);
+       ib_dealloc_pd(ia->ri_pd);
+       ia->ri_pd = NULL;
 
        /* Allow waiters to continue */
        complete(&ia->ri_remove_done);
@@ -589,11 +594,8 @@ rpcrdma_ep_create(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia,
 
        /* Client offers RDMA Read but does not initiate */
        ep->rep_remote_cma.initiator_depth = 0;
-       if (ia->ri_device->attrs.max_qp_rd_atom > 32)   /* arbitrary but <= 255 */
-               ep->rep_remote_cma.responder_resources = 32;
-       else
-               ep->rep_remote_cma.responder_resources =
-                                               ia->ri_device->attrs.max_qp_rd_atom;
+       ep->rep_remote_cma.responder_resources =
+               min_t(int, U8_MAX, ia->ri_device->attrs.max_qp_rd_atom);
 
        /* Limit transport retries so client can detect server
         * GID changes quickly. RPC layer handles re-establishing
@@ -628,14 +630,16 @@ rpcrdma_ep_destroy(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
 {
        cancel_delayed_work_sync(&ep->rep_connect_worker);
 
-       if (ia->ri_id->qp) {
+       if (ia->ri_id && ia->ri_id->qp) {
                rpcrdma_ep_disconnect(ep, ia);
                rdma_destroy_qp(ia->ri_id);
                ia->ri_id->qp = NULL;
        }
 
-       ib_free_cq(ep->rep_attr.recv_cq);
-       ib_free_cq(ep->rep_attr.send_cq);
+       if (ep->rep_attr.recv_cq)
+               ib_free_cq(ep->rep_attr.recv_cq);
+       if (ep->rep_attr.send_cq)
+               ib_free_cq(ep->rep_attr.send_cq);
 }
 
 /* Re-establish a connection after a device removal event.
@@ -1024,7 +1028,7 @@ rpcrdma_mrs_create(struct rpcrdma_xprt *r_xprt)
        LIST_HEAD(free);
        LIST_HEAD(all);
 
-       for (count = 0; count < 32; count++) {
+       for (count = 0; count < 3; count++) {
                struct rpcrdma_mr *mr;
                int rc;
 
@@ -1049,8 +1053,9 @@ rpcrdma_mrs_create(struct rpcrdma_xprt *r_xprt)
        list_splice(&all, &buf->rb_all);
        r_xprt->rx_stats.mrs_allocated += count;
        spin_unlock(&buf->rb_mrlock);
-
        trace_xprtrdma_createmrs(r_xprt, count);
+
+       xprt_write_space(&r_xprt->rx_xprt);
 }
 
 static void
@@ -1068,17 +1073,27 @@ struct rpcrdma_req *
 rpcrdma_create_req(struct rpcrdma_xprt *r_xprt)
 {
        struct rpcrdma_buffer *buffer = &r_xprt->rx_buf;
+       struct rpcrdma_regbuf *rb;
        struct rpcrdma_req *req;
 
        req = kzalloc(sizeof(*req), GFP_KERNEL);
        if (req == NULL)
                return ERR_PTR(-ENOMEM);
 
+       rb = rpcrdma_alloc_regbuf(RPCRDMA_HDRBUF_SIZE,
+                                 DMA_TO_DEVICE, GFP_KERNEL);
+       if (IS_ERR(rb)) {
+               kfree(req);
+               return ERR_PTR(-ENOMEM);
+       }
+       req->rl_rdmabuf = rb;
+       xdr_buf_init(&req->rl_hdrbuf, rb->rg_base, rdmab_length(rb));
+       req->rl_buffer = buffer;
+       INIT_LIST_HEAD(&req->rl_registered);
+
        spin_lock(&buffer->rb_reqslock);
        list_add(&req->rl_all, &buffer->rb_allreqs);
        spin_unlock(&buffer->rb_reqslock);
-       req->rl_buffer = &r_xprt->rx_buf;
-       INIT_LIST_HEAD(&req->rl_registered);
        return req;
 }
 
@@ -1535,7 +1550,6 @@ rpcrdma_ep_post(struct rpcrdma_ia *ia,
                struct rpcrdma_req *req)
 {
        struct ib_send_wr *send_wr = &req->rl_sendctx->sc_wr;
-       struct ib_send_wr *send_wr_fail;
        int rc;
 
        if (req->rl_reply) {
@@ -1554,7 +1568,7 @@ rpcrdma_ep_post(struct rpcrdma_ia *ia,
                --ep->rep_send_count;
        }
 
-       rc = ib_post_send(ia->ri_id->qp, send_wr, &send_wr_fail);
+       rc = ia->ri_ops->ro_send(ia, req);
        trace_xprtrdma_post_send(req, rc);
        if (rc)
                return -ENOTCONN;
index 69883a960a3ffbebcc1cfc4c400ab1879f4a0c90..3d3b423fa9c1d3a9cf8497d109c25599042bea68 100644 (file)
@@ -334,8 +334,6 @@ enum {
 struct rpcrdma_buffer;
 struct rpcrdma_req {
        struct list_head        rl_list;
-       int                     rl_cpu;
-       unsigned int            rl_connect_cookie;
        struct rpcrdma_buffer   *rl_buffer;
        struct rpcrdma_rep      *rl_reply;
        struct xdr_stream       rl_stream;
@@ -474,6 +472,8 @@ struct rpcrdma_memreg_ops {
                        (*ro_map)(struct rpcrdma_xprt *,
                                  struct rpcrdma_mr_seg *, int, bool,
                                  struct rpcrdma_mr **);
+       int             (*ro_send)(struct rpcrdma_ia *ia,
+                                  struct rpcrdma_req *req);
        void            (*ro_reminv)(struct rpcrdma_rep *rep,
                                     struct list_head *mrs);
        void            (*ro_unmap_sync)(struct rpcrdma_xprt *,
index 956e29c1438d504261f1ba4cd116c150ca74aa76..c8902f11efdd513c066f7f1b4c2c24405d8dfe5f 100644 (file)
@@ -527,6 +527,7 @@ static int xs_local_send_request(struct rpc_task *task)
        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 @@ static int xs_udp_send_request(struct rpc_task *task)
 
        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 @@ static int xs_tcp_send_request(struct rpc_task *task)
        /* 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 @@ static void xs_udp_data_read_skb(struct rpc_xprt *xprt,
        if (!rovr)
                goto out_unlock;
        xprt_pin_rqst(rovr);
+       xprt_update_rtt(rovr->rq_task);
        spin_unlock(&xprt->recv_lock);
        task = rovr->rq_task;