]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge tag 'nfs-for-4.11-1' of git://git.linux-nfs.org/projects/anna/linux-nfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 2 Mar 2017 00:10:30 +0000 (16:10 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 2 Mar 2017 00:10:30 +0000 (16:10 -0800)
Pull NFS client updates from Anna Schumaker:
 "Highlights include:

  Stable bugfixes:
   - NFSv4: Fix memory and state leak in _nfs4_open_and_get_state
   - xprtrdma: Fix Read chunk padding
   - xprtrdma: Per-connection pad optimization
   - xprtrdma: Disable pad optimization by default
   - xprtrdma: Reduce required number of send SGEs
   - nlm: Ensure callback code also checks that the files match
   - pNFS/flexfiles: If the layout is invalid, it must be updated before
     retrying
   - NFSv4: Fix reboot recovery in copy offload
   - Revert "NFSv4.1: Handle NFS4ERR_BADSESSION/NFS4ERR_DEADSESSION
     replies to OP_SEQUENCE"
   - NFSv4: fix getacl head length estimation
   - NFSv4: fix getacl ERANGE for sum ACL buffer sizes

  Features:
   - Add and use dprintk_cont macros
   - Various cleanups to NFS v4.x to reduce code duplication and
     complexity
   - Remove unused cr_magic related code
   - Improvements to sunrpc "read from buffer" code
   - Clean up sunrpc timeout code and allow changing TCP timeout
     parameters
   - Remove duplicate mw_list management code in xprtrdma
   - Add generic functions for encoding and decoding xdr streams

  Bugfixes:
   - Clean up nfs_show_mountd_netid
   - Make layoutreturn_ops static and use NULL instead of 0 to fix
     sparse warnings
   - Properly handle -ERESTARTSYS in nfs_rename()
   - Check if register_shrinker() failed during rpcauth_init()
   - Properly clean up procfs/pipefs entries
   - Various NFS over RDMA related fixes
   - Silence unititialized variable warning in sunrpc"

* tag 'nfs-for-4.11-1' of git://git.linux-nfs.org/projects/anna/linux-nfs: (64 commits)
  NFSv4: fix getacl ERANGE for some ACL buffer sizes
  NFSv4: fix getacl head length estimation
  Revert "NFSv4.1: Handle NFS4ERR_BADSESSION/NFS4ERR_DEADSESSION replies to OP_SEQUENCE"
  NFSv4: Fix reboot recovery in copy offload
  pNFS/flexfiles: If the layout is invalid, it must be updated before retrying
  NFSv4: Clean up owner/group attribute decode
  SUNRPC: Add a helper function xdr_stream_decode_string_dup()
  NFSv4: Remove bogus "struct nfs_client" argument from decode_ace()
  NFSv4: Fix the underestimation of delegation XDR space reservation
  NFSv4: Replace callback string decode function with a generic
  NFSv4: Replace the open coded decode_opaque_inline() with the new generic
  NFSv4: Replace ad-hoc xdr encode/decode helpers with xdr_stream_* generics
  SUNRPC: Add generic helpers for xdr_stream encode/decode
  sunrpc: silence uninitialized variable warning
  nlm: Ensure callback code also checks that the files match
  sunrpc: Allow xprt->ops->timer method to sleep
  xprtrdma: Refactor management of mw_list field
  xprtrdma: Handle stale connection rejection
  xprtrdma: Properly recover FRWRs with in-flight FASTREG WRs
  xprtrdma: Shrink send SGEs array
  ...

39 files changed:
fs/nfs/cache_lib.c
fs/nfs/callback_xdr.c
fs/nfs/dir.c
fs/nfs/filelayout/filelayout.c
fs/nfs/flexfilelayout/flexfilelayout.c
fs/nfs/nfs42proc.c
fs/nfs/nfs4_fs.h
fs/nfs/nfs4proc.c
fs/nfs/nfs4renewd.c
fs/nfs/nfs4session.h
fs/nfs/nfs4state.c
fs/nfs/nfs4trace.h
fs/nfs/nfs4xdr.c
fs/nfs/super.c
fs/nfs/write.c
include/linux/lockd/lockd.h
include/linux/sunrpc/auth.h
include/linux/sunrpc/cache.h
include/linux/sunrpc/clnt.h
include/linux/sunrpc/debug.h
include/linux/sunrpc/xdr.h
include/linux/sunrpc/xprt.h
include/linux/sunrpc/xprtsock.h
net/sunrpc/auth.c
net/sunrpc/auth_null.c
net/sunrpc/auth_unix.c
net/sunrpc/cache.c
net/sunrpc/clnt.c
net/sunrpc/debugfs.c
net/sunrpc/svcauth_unix.c
net/sunrpc/xdr.c
net/sunrpc/xprt.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 6de15709d02497642eaefc4940f43064d820676a..2ae676f93e6bd5e3823358bcd3b988ce074adc75 100644 (file)
@@ -141,8 +141,7 @@ int nfs_cache_register_net(struct net *net, struct cache_detail *cd)
 
 void nfs_cache_unregister_sb(struct super_block *sb, struct cache_detail *cd)
 {
-       if (cd->u.pipefs.dir)
-               sunrpc_cache_unregister_pipefs(cd);
+       sunrpc_cache_unregister_pipefs(cd);
 }
 
 void nfs_cache_unregister_net(struct net *net, struct cache_detail *cd)
index fd0284c1dc328b92520aa0c39b4ca2a4b9899915..d051fc3583a9097d46d8159860ea6c22a7ec116a 100644 (file)
@@ -83,23 +83,15 @@ static __be32 *read_buf(struct xdr_stream *xdr, size_t nbytes)
        return p;
 }
 
-static __be32 decode_string(struct xdr_stream *xdr, unsigned int *len, const char **str)
+static __be32 decode_string(struct xdr_stream *xdr, unsigned int *len,
+               const char **str, size_t maxlen)
 {
-       __be32 *p;
-
-       p = read_buf(xdr, 4);
-       if (unlikely(p == NULL))
-               return htonl(NFS4ERR_RESOURCE);
-       *len = ntohl(*p);
-
-       if (*len != 0) {
-               p = read_buf(xdr, *len);
-               if (unlikely(p == NULL))
-                       return htonl(NFS4ERR_RESOURCE);
-               *str = (const char *)p;
-       } else
-               *str = NULL;
+       ssize_t err;
 
+       err = xdr_stream_decode_opaque_inline(xdr, (void **)str, maxlen);
+       if (err < 0)
+               return cpu_to_be32(NFS4ERR_RESOURCE);
+       *len = err;
        return 0;
 }
 
@@ -162,15 +154,9 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound
        __be32 *p;
        __be32 status;
 
-       status = decode_string(xdr, &hdr->taglen, &hdr->tag);
+       status = decode_string(xdr, &hdr->taglen, &hdr->tag, CB_OP_TAGLEN_MAXSZ);
        if (unlikely(status != 0))
                return status;
-       /* We do not like overly long tags! */
-       if (hdr->taglen > CB_OP_TAGLEN_MAXSZ) {
-               printk("NFS: NFSv4 CALLBACK %s: client sent tag of length %u\n",
-                               __func__, hdr->taglen);
-               return htonl(NFS4ERR_RESOURCE);
-       }
        p = read_buf(xdr, 12);
        if (unlikely(p == NULL))
                return htonl(NFS4ERR_RESOURCE);
@@ -582,12 +568,8 @@ out:
 
 static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
 {
-       __be32 *p;
-
-       p = xdr_reserve_space(xdr, 4 + len);
-       if (unlikely(p == NULL))
-               return htonl(NFS4ERR_RESOURCE);
-       xdr_encode_opaque(p, str, len);
+       if (unlikely(xdr_stream_encode_opaque(xdr, str, len) < 0))
+               return cpu_to_be32(NFS4ERR_RESOURCE);
        return 0;
 }
 
index fad81041f5ab6a60e23e53f45ae429bbde7a9470..fb499a3f21b58ed341bbe17933bd5e191c850212 100644 (file)
@@ -2002,6 +2002,29 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
 }
 EXPORT_SYMBOL_GPL(nfs_link);
 
+static void
+nfs_complete_rename(struct rpc_task *task, struct nfs_renamedata *data)
+{
+       struct dentry *old_dentry = data->old_dentry;
+       struct dentry *new_dentry = data->new_dentry;
+       struct inode *old_inode = d_inode(old_dentry);
+       struct inode *new_inode = d_inode(new_dentry);
+
+       nfs_mark_for_revalidate(old_inode);
+
+       switch (task->tk_status) {
+       case 0:
+               if (new_inode != NULL)
+                       nfs_drop_nlink(new_inode);
+               d_move(old_dentry, new_dentry);
+               nfs_set_verifier(new_dentry,
+                                       nfs_save_change_attribute(data->new_dir));
+               break;
+       case -ENOENT:
+               nfs_dentry_handle_enoent(old_dentry);
+       }
+}
+
 /*
  * RENAME
  * FIXME: Some nfsds, like the Linux user space nfsd, may generate a
@@ -2084,7 +2107,8 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        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);
+       task = nfs_async_rename(old_dir, new_dir, old_dentry, new_dentry,
+                                       nfs_complete_rename);
        if (IS_ERR(task)) {
                error = PTR_ERR(task);
                goto out;
@@ -2094,21 +2118,11 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (error == 0)
                error = task->tk_status;
        rpc_put_task(task);
-       nfs_mark_for_revalidate(old_inode);
 out:
        if (rehash)
                d_rehash(rehash);
        trace_nfs_rename_exit(old_dir, old_dentry,
                        new_dir, new_dentry, error);
-       if (!error) {
-               if (new_inode != NULL)
-                       nfs_drop_nlink(new_inode);
-               d_move(old_dentry, new_dentry);
-               nfs_set_verifier(new_dentry,
-                                       nfs_save_change_attribute(new_dir));
-       } else if (error == -ENOENT)
-               nfs_dentry_handle_enoent(old_dentry);
-
        /* new dentry created? */
        if (dentry)
                dput(dentry);
index 18f98e08544db97757a7701838996f368c27555d..44347f4bdc1516f54f030ca9f0d95332ab816116 100644 (file)
@@ -305,7 +305,7 @@ static void filelayout_read_prepare(struct rpc_task *task, void *data)
        }
        hdr->pgio_done_cb = filelayout_read_done_cb;
 
-       if (nfs41_setup_sequence(hdr->ds_clp->cl_session,
+       if (nfs4_setup_sequence(hdr->ds_clp,
                        &hdr->args.seq_args,
                        &hdr->res.seq_res,
                        task))
@@ -403,7 +403,7 @@ static void filelayout_write_prepare(struct rpc_task *task, void *data)
                rpc_exit(task, 0);
                return;
        }
-       if (nfs41_setup_sequence(hdr->ds_clp->cl_session,
+       if (nfs4_setup_sequence(hdr->ds_clp,
                        &hdr->args.seq_args,
                        &hdr->res.seq_res,
                        task))
@@ -438,7 +438,7 @@ static void filelayout_commit_prepare(struct rpc_task *task, void *data)
 {
        struct nfs_commit_data *wdata = data;
 
-       nfs41_setup_sequence(wdata->ds_clp->cl_session,
+       nfs4_setup_sequence(wdata->ds_clp,
                        &wdata->args.seq_args,
                        &wdata->res.seq_res,
                        task);
index d6acc688df7ed74334ae823af65a24c73f6cb4ff..42dedf2d625fca62a418c5e4f82935dc41a53987 100644 (file)
@@ -1053,9 +1053,6 @@ static int ff_layout_async_handle_error_v4(struct rpc_task *task,
        struct nfs_client *mds_client = mds_server->nfs_client;
        struct nfs4_slot_table *tbl = &clp->cl_session->fc_slot_table;
 
-       if (task->tk_status >= 0)
-               return 0;
-
        switch (task->tk_status) {
        /* MDS state errors */
        case -NFS4ERR_DELEG_REVOKED:
@@ -1157,9 +1154,6 @@ static int ff_layout_async_handle_error_v3(struct rpc_task *task,
 {
        struct nfs4_deviceid_node *devid = FF_LAYOUT_DEVID_NODE(lseg, idx);
 
-       if (task->tk_status >= 0)
-               return 0;
-
        switch (task->tk_status) {
        /* File access problems. Don't mark the device as unavailable */
        case -EACCES:
@@ -1195,6 +1189,13 @@ static int ff_layout_async_handle_error(struct rpc_task *task,
 {
        int vers = clp->cl_nfs_mod->rpc_vers->number;
 
+       if (task->tk_status >= 0)
+               return 0;
+
+       /* Handle the case of an invalid layout segment */
+       if (!pnfs_is_valid_lseg(lseg))
+               return -NFS4ERR_RESET_TO_PNFS;
+
        switch (vers) {
        case 3:
                return ff_layout_async_handle_error_v3(task, lseg, idx);
@@ -1384,30 +1385,14 @@ static void ff_layout_read_prepare_v3(struct rpc_task *task, void *data)
        rpc_call_start(task);
 }
 
-static int ff_layout_setup_sequence(struct nfs_client *ds_clp,
-                                   struct nfs4_sequence_args *args,
-                                   struct nfs4_sequence_res *res,
-                                   struct rpc_task *task)
-{
-       if (ds_clp->cl_session)
-               return nfs41_setup_sequence(ds_clp->cl_session,
-                                          args,
-                                          res,
-                                          task);
-       return nfs40_setup_sequence(ds_clp->cl_slot_tbl,
-                                  args,
-                                  res,
-                                  task);
-}
-
 static void ff_layout_read_prepare_v4(struct rpc_task *task, void *data)
 {
        struct nfs_pgio_header *hdr = data;
 
-       if (ff_layout_setup_sequence(hdr->ds_clp,
-                                    &hdr->args.seq_args,
-                                    &hdr->res.seq_res,
-                                    task))
+       if (nfs4_setup_sequence(hdr->ds_clp,
+                               &hdr->args.seq_args,
+                               &hdr->res.seq_res,
+                               task))
                return;
 
        if (ff_layout_read_prepare_common(task, hdr))
@@ -1578,10 +1563,10 @@ static void ff_layout_write_prepare_v4(struct rpc_task *task, void *data)
 {
        struct nfs_pgio_header *hdr = data;
 
-       if (ff_layout_setup_sequence(hdr->ds_clp,
-                                    &hdr->args.seq_args,
-                                    &hdr->res.seq_res,
-                                    task))
+       if (nfs4_setup_sequence(hdr->ds_clp,
+                               &hdr->args.seq_args,
+                               &hdr->res.seq_res,
+                               task))
                return;
 
        if (ff_layout_write_prepare_common(task, hdr))
@@ -1667,10 +1652,10 @@ static void ff_layout_commit_prepare_v4(struct rpc_task *task, void *data)
 {
        struct nfs_commit_data *wdata = data;
 
-       if (ff_layout_setup_sequence(wdata->ds_clp,
-                                &wdata->args.seq_args,
-                                &wdata->res.seq_res,
-                                task))
+       if (nfs4_setup_sequence(wdata->ds_clp,
+                               &wdata->args.seq_args,
+                               &wdata->res.seq_res,
+                               task))
                return;
        ff_layout_commit_prepare_common(task, data);
 }
@@ -1965,10 +1950,7 @@ static int ff_layout_encode_ioerr(struct xdr_stream *xdr,
 static void
 encode_opaque_fixed(struct xdr_stream *xdr, const void *buf, size_t len)
 {
-       __be32 *p;
-
-       p = xdr_reserve_space(xdr, len);
-       xdr_encode_opaque_fixed(p, buf, len);
+       WARN_ON_ONCE(xdr_stream_encode_opaque_fixed(xdr, buf, len) < 0);
 }
 
 static void
@@ -2092,7 +2074,7 @@ ff_layout_free_layoutreturn(struct nfs4_xdr_opaque_data *args)
        kfree(ff_args);
 }
 
-const struct nfs4_xdr_opaque_ops layoutreturn_ops = {
+static const struct nfs4_xdr_opaque_ops layoutreturn_ops = {
        .encode = ff_layout_encode_layoutreturn,
        .free = ff_layout_free_layoutreturn,
 };
index d12ff9385f493f374c5b0aa7a184efa8275cc55c..1e486c73ec9438d99e2e4a5b6637ec64594b626c 100644 (file)
@@ -12,6 +12,7 @@
 #include "nfs42.h"
 #include "iostat.h"
 #include "pnfs.h"
+#include "nfs4session.h"
 #include "internal.h"
 
 #define NFSDBG_FACILITY NFSDBG_PROC
@@ -128,30 +129,26 @@ out_unlock:
        return err;
 }
 
-static ssize_t _nfs42_proc_copy(struct file *src, loff_t pos_src,
+static ssize_t _nfs42_proc_copy(struct file *src,
                                struct nfs_lock_context *src_lock,
-                               struct file *dst, loff_t pos_dst,
+                               struct file *dst,
                                struct nfs_lock_context *dst_lock,
-                               size_t count)
+                               struct nfs42_copy_args *args,
+                               struct nfs42_copy_res *res)
 {
-       struct nfs42_copy_args args = {
-               .src_fh         = NFS_FH(file_inode(src)),
-               .src_pos        = pos_src,
-               .dst_fh         = NFS_FH(file_inode(dst)),
-               .dst_pos        = pos_dst,
-               .count          = count,
-       };
-       struct nfs42_copy_res res;
        struct rpc_message msg = {
                .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COPY],
-               .rpc_argp = &args,
-               .rpc_resp = &res,
+               .rpc_argp = args,
+               .rpc_resp = res,
        };
        struct inode *dst_inode = file_inode(dst);
        struct nfs_server *server = NFS_SERVER(dst_inode);
+       loff_t pos_src = args->src_pos;
+       loff_t pos_dst = args->dst_pos;
+       size_t count = args->count;
        int status;
 
-       status = nfs4_set_rw_stateid(&args.src_stateid, src_lock->open_context,
+       status = nfs4_set_rw_stateid(&args->src_stateid, src_lock->open_context,
                                     src_lock, FMODE_READ);
        if (status)
                return status;
@@ -161,7 +158,7 @@ static ssize_t _nfs42_proc_copy(struct file *src, loff_t pos_src,
        if (status)
                return status;
 
-       status = nfs4_set_rw_stateid(&args.dst_stateid, dst_lock->open_context,
+       status = nfs4_set_rw_stateid(&args->dst_stateid, dst_lock->open_context,
                                     dst_lock, FMODE_WRITE);
        if (status)
                return status;
@@ -171,22 +168,22 @@ static ssize_t _nfs42_proc_copy(struct file *src, loff_t pos_src,
                return status;
 
        status = nfs4_call_sync(server->client, server, &msg,
-                               &args.seq_args, &res.seq_res, 0);
+                               &args->seq_args, &res->seq_res, 0);
        if (status == -ENOTSUPP)
                server->caps &= ~NFS_CAP_COPY;
        if (status)
                return status;
 
-       if (res.write_res.verifier.committed != NFS_FILE_SYNC) {
-               status = nfs_commit_file(dst, &res.write_res.verifier.verifier);
+       if (res->write_res.verifier.committed != NFS_FILE_SYNC) {
+               status = nfs_commit_file(dst, &res->write_res.verifier.verifier);
                if (status)
                        return status;
        }
 
        truncate_pagecache_range(dst_inode, pos_dst,
-                                pos_dst + res.write_res.count);
+                                pos_dst + res->write_res.count);
 
-       return res.write_res.count;
+       return res->write_res.count;
 }
 
 ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
@@ -196,8 +193,22 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
        struct nfs_server *server = NFS_SERVER(file_inode(dst));
        struct nfs_lock_context *src_lock;
        struct nfs_lock_context *dst_lock;
-       struct nfs4_exception src_exception = { };
-       struct nfs4_exception dst_exception = { };
+       struct nfs42_copy_args args = {
+               .src_fh         = NFS_FH(file_inode(src)),
+               .src_pos        = pos_src,
+               .dst_fh         = NFS_FH(file_inode(dst)),
+               .dst_pos        = pos_dst,
+               .count          = count,
+       };
+       struct nfs42_copy_res res;
+       struct nfs4_exception src_exception = {
+               .inode          = file_inode(src),
+               .stateid        = &args.src_stateid,
+       };
+       struct nfs4_exception dst_exception = {
+               .inode          = file_inode(dst),
+               .stateid        = &args.dst_stateid,
+       };
        ssize_t err, err2;
 
        if (!nfs_server_capable(file_inode(dst), NFS_CAP_COPY))
@@ -207,7 +218,6 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
        if (IS_ERR(src_lock))
                return PTR_ERR(src_lock);
 
-       src_exception.inode = file_inode(src);
        src_exception.state = src_lock->open_context->state;
 
        dst_lock = nfs_get_lock_context(nfs_file_open_context(dst));
@@ -216,15 +226,17 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
                goto out_put_src_lock;
        }
 
-       dst_exception.inode = file_inode(dst);
        dst_exception.state = dst_lock->open_context->state;
 
        do {
                inode_lock(file_inode(dst));
-               err = _nfs42_proc_copy(src, pos_src, src_lock,
-                                      dst, pos_dst, dst_lock, count);
+               err = _nfs42_proc_copy(src, src_lock,
+                               dst, dst_lock,
+                               &args, &res);
                inode_unlock(file_inode(dst));
 
+               if (err >= 0)
+                       break;
                if (err == -ENOTSUPP) {
                        err = -EOPNOTSUPP;
                        break;
@@ -331,9 +343,8 @@ nfs42_layoutstat_prepare(struct rpc_task *task, void *calldata)
        }
        nfs4_stateid_copy(&data->args.stateid, &lo->plh_stateid);
        spin_unlock(&inode->i_lock);
-       nfs41_setup_sequence(nfs4_get_session(server), &data->args.seq_args,
-                            &data->res.seq_res, task);
-
+       nfs4_setup_sequence(server->nfs_client, &data->args.seq_args,
+                           &data->res.seq_res, task);
 }
 
 static void
index 66516583366069dd85d10d0fd9b0e826ce33268f..af285cc27ccf8c8457dee080cccbf75df77f0fcb 100644 (file)
@@ -273,14 +273,6 @@ extern int nfs4_set_rw_stateid(nfs4_stateid *stateid,
                fmode_t fmode);
 
 #if defined(CONFIG_NFS_V4_1)
-static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *server)
-{
-       return server->nfs_client->cl_session;
-}
-
-extern int nfs41_setup_sequence(struct nfs4_session *session,
-               struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
-               struct rpc_task *task);
 extern int nfs41_sequence_done(struct rpc_task *, struct nfs4_sequence_res *);
 extern int nfs4_proc_create_session(struct nfs_client *, struct rpc_cred *);
 extern int nfs4_proc_destroy_session(struct nfs4_session *, struct rpc_cred *);
@@ -357,11 +349,6 @@ nfs4_state_protect_write(struct nfs_client *clp, struct rpc_clnt **clntp,
                hdr->args.stable = NFS_FILE_SYNC;
 }
 #else /* CONFIG_NFS_v4_1 */
-static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *server)
-{
-       return NULL;
-}
-
 static inline bool
 is_ds_only_client(struct nfs_client *clp)
 {
@@ -466,7 +453,7 @@ extern void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid);
 extern void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid);
 extern void nfs_release_seqid(struct nfs_seqid *seqid);
 extern void nfs_free_seqid(struct nfs_seqid *seqid);
-extern int nfs40_setup_sequence(struct nfs4_slot_table *tbl,
+extern int nfs4_setup_sequence(const struct nfs_client *client,
                                struct nfs4_sequence_args *args,
                                struct nfs4_sequence_res *res,
                                struct rpc_task *task);
index 0a0eaecf967683f66461874408a1f572c4b154f1..1b183686c6d4f06c3b1d4ed044c527bff6ba4a83 100644 (file)
@@ -577,12 +577,7 @@ nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server,
 static bool _nfs4_is_integrity_protected(struct nfs_client *clp)
 {
        rpc_authflavor_t flavor = clp->cl_rpcclient->cl_auth->au_flavor;
-
-       if (flavor == RPC_AUTH_GSS_KRB5I ||
-           flavor == RPC_AUTH_GSS_KRB5P)
-               return true;
-
-       return false;
+       return (flavor == RPC_AUTH_GSS_KRB5I) || (flavor == RPC_AUTH_GSS_KRB5P);
 }
 
 static void do_renew_lease(struct nfs_client *clp, unsigned long timestamp)
@@ -622,48 +617,6 @@ static void nfs4_set_sequence_privileged(struct nfs4_sequence_args *args)
        args->sa_privileged = 1;
 }
 
-int nfs40_setup_sequence(struct nfs4_slot_table *tbl,
-                        struct nfs4_sequence_args *args,
-                        struct nfs4_sequence_res *res,
-                        struct rpc_task *task)
-{
-       struct nfs4_slot *slot;
-
-       /* slot already allocated? */
-       if (res->sr_slot != NULL)
-               goto out_start;
-
-       spin_lock(&tbl->slot_tbl_lock);
-       if (nfs4_slot_tbl_draining(tbl) && !args->sa_privileged)
-               goto out_sleep;
-
-       slot = nfs4_alloc_slot(tbl);
-       if (IS_ERR(slot)) {
-               if (slot == ERR_PTR(-ENOMEM))
-                       task->tk_timeout = HZ >> 2;
-               goto out_sleep;
-       }
-       spin_unlock(&tbl->slot_tbl_lock);
-
-       slot->privileged = args->sa_privileged ? 1 : 0;
-       args->sa_slot = slot;
-       res->sr_slot = slot;
-
-out_start:
-       rpc_call_start(task);
-       return 0;
-
-out_sleep:
-       if (args->sa_privileged)
-               rpc_sleep_on_priority(&tbl->slot_tbl_waitq, task,
-                               NULL, RPC_PRIORITY_PRIVILEGED);
-       else
-               rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
-       spin_unlock(&tbl->slot_tbl_lock);
-       return -EAGAIN;
-}
-EXPORT_SYMBOL_GPL(nfs40_setup_sequence);
-
 static void nfs40_sequence_free_slot(struct nfs4_sequence_res *res)
 {
        struct nfs4_slot *slot = res->sr_slot;
@@ -815,10 +768,6 @@ static int nfs41_sequence_process(struct rpc_task *task,
        case -NFS4ERR_SEQ_FALSE_RETRY:
                ++slot->seq_nr;
                goto retry_nowait;
-       case -NFS4ERR_DEADSESSION:
-       case -NFS4ERR_BADSESSION:
-               nfs4_schedule_session_recovery(session, res->sr_status);
-               goto retry_nowait;
        default:
                /* Just update the slot sequence no. */
                slot->seq_done = 1;
@@ -882,101 +831,14 @@ int nfs4_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
 }
 EXPORT_SYMBOL_GPL(nfs4_sequence_done);
 
-int nfs41_setup_sequence(struct nfs4_session *session,
-                               struct nfs4_sequence_args *args,
-                               struct nfs4_sequence_res *res,
-                               struct rpc_task *task)
-{
-       struct nfs4_slot *slot;
-       struct nfs4_slot_table *tbl;
-
-       dprintk("--> %s\n", __func__);
-       /* slot already allocated? */
-       if (res->sr_slot != NULL)
-               goto out_success;
-
-       tbl = &session->fc_slot_table;
-
-       task->tk_timeout = 0;
-
-       spin_lock(&tbl->slot_tbl_lock);
-       if (test_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state) &&
-           !args->sa_privileged) {
-               /* The state manager will wait until the slot table is empty */
-               dprintk("%s session is draining\n", __func__);
-               goto out_sleep;
-       }
-
-       slot = nfs4_alloc_slot(tbl);
-       if (IS_ERR(slot)) {
-               /* If out of memory, try again in 1/4 second */
-               if (slot == ERR_PTR(-ENOMEM))
-                       task->tk_timeout = HZ >> 2;
-               dprintk("<-- %s: no free slots\n", __func__);
-               goto out_sleep;
-       }
-       spin_unlock(&tbl->slot_tbl_lock);
-
-       slot->privileged = args->sa_privileged ? 1 : 0;
-       args->sa_slot = slot;
-
-       dprintk("<-- %s slotid=%u seqid=%u\n", __func__,
-                       slot->slot_nr, slot->seq_nr);
-
-       res->sr_slot = slot;
-       res->sr_timestamp = jiffies;
-       res->sr_status_flags = 0;
-       /*
-        * sr_status is only set in decode_sequence, and so will remain
-        * set to 1 if an rpc level failure occurs.
-        */
-       res->sr_status = 1;
-       trace_nfs4_setup_sequence(session, args);
-out_success:
-       rpc_call_start(task);
-       return 0;
-out_sleep:
-       /* Privileged tasks are queued with top priority */
-       if (args->sa_privileged)
-               rpc_sleep_on_priority(&tbl->slot_tbl_waitq, task,
-                               NULL, RPC_PRIORITY_PRIVILEGED);
-       else
-               rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
-       spin_unlock(&tbl->slot_tbl_lock);
-       return -EAGAIN;
-}
-EXPORT_SYMBOL_GPL(nfs41_setup_sequence);
-
-static int nfs4_setup_sequence(const struct nfs_server *server,
-                              struct nfs4_sequence_args *args,
-                              struct nfs4_sequence_res *res,
-                              struct rpc_task *task)
-{
-       struct nfs4_session *session = nfs4_get_session(server);
-       int ret = 0;
-
-       if (!session)
-               return nfs40_setup_sequence(server->nfs_client->cl_slot_tbl,
-                                           args, res, task);
-
-       dprintk("--> %s clp %p session %p sr_slot %u\n",
-               __func__, session->clp, session, res->sr_slot ?
-                       res->sr_slot->slot_nr : NFS4_NO_SLOT);
-
-       ret = nfs41_setup_sequence(session, args, res, task);
-
-       dprintk("<-- %s status=%d\n", __func__, ret);
-       return ret;
-}
-
 static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata)
 {
        struct nfs4_call_sync_data *data = calldata;
-       struct nfs4_session *session = nfs4_get_session(data->seq_server);
 
        dprintk("--> %s data->seq_server %p\n", __func__, data->seq_server);
 
-       nfs41_setup_sequence(session, data->seq_args, data->seq_res, task);
+       nfs4_setup_sequence(data->seq_server->nfs_client,
+                           data->seq_args, data->seq_res, task);
 }
 
 static void nfs41_call_sync_done(struct rpc_task *task, void *calldata)
@@ -993,15 +855,6 @@ static const struct rpc_call_ops nfs41_call_sync_ops = {
 
 #else  /* !CONFIG_NFS_V4_1 */
 
-static int nfs4_setup_sequence(const struct nfs_server *server,
-                              struct nfs4_sequence_args *args,
-                              struct nfs4_sequence_res *res,
-                              struct rpc_task *task)
-{
-       return nfs40_setup_sequence(server->nfs_client->cl_slot_tbl,
-                                   args, res, task);
-}
-
 static int nfs4_sequence_process(struct rpc_task *task, struct nfs4_sequence_res *res)
 {
        return nfs40_sequence_done(task, res);
@@ -1022,10 +875,68 @@ EXPORT_SYMBOL_GPL(nfs4_sequence_done);
 
 #endif /* !CONFIG_NFS_V4_1 */
 
+int nfs4_setup_sequence(const struct nfs_client *client,
+                       struct nfs4_sequence_args *args,
+                       struct nfs4_sequence_res *res,
+                       struct rpc_task *task)
+{
+       struct nfs4_session *session = nfs4_get_session(client);
+       struct nfs4_slot_table *tbl  = client->cl_slot_tbl;
+       struct nfs4_slot *slot;
+
+       /* slot already allocated? */
+       if (res->sr_slot != NULL)
+               goto out_start;
+
+       if (session) {
+               tbl = &session->fc_slot_table;
+               task->tk_timeout = 0;
+       }
+
+       spin_lock(&tbl->slot_tbl_lock);
+       /* The state manager will wait until the slot table is empty */
+       if (nfs4_slot_tbl_draining(tbl) && !args->sa_privileged)
+               goto out_sleep;
+
+       slot = nfs4_alloc_slot(tbl);
+       if (IS_ERR(slot)) {
+               /* Try again in 1/4 second */
+               if (slot == ERR_PTR(-ENOMEM))
+                       task->tk_timeout = HZ >> 2;
+               goto out_sleep;
+       }
+       spin_unlock(&tbl->slot_tbl_lock);
+
+       slot->privileged = args->sa_privileged ? 1 : 0;
+       args->sa_slot = slot;
+
+       res->sr_slot = slot;
+       if (session) {
+               res->sr_timestamp = jiffies;
+               res->sr_status_flags = 0;
+               res->sr_status = 1;
+       }
+
+       trace_nfs4_setup_sequence(session, args);
+out_start:
+       rpc_call_start(task);
+       return 0;
+
+out_sleep:
+       if (args->sa_privileged)
+               rpc_sleep_on_priority(&tbl->slot_tbl_waitq, task,
+                               NULL, RPC_PRIORITY_PRIVILEGED);
+       else
+               rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
+       spin_unlock(&tbl->slot_tbl_lock);
+       return -EAGAIN;
+}
+EXPORT_SYMBOL_GPL(nfs4_setup_sequence);
+
 static void nfs40_call_sync_prepare(struct rpc_task *task, void *calldata)
 {
        struct nfs4_call_sync_data *data = calldata;
-       nfs4_setup_sequence(data->seq_server,
+       nfs4_setup_sequence(data->seq_server->nfs_client,
                                data->seq_args, data->seq_res, task);
 }
 
@@ -1330,14 +1241,6 @@ static void nfs4_opendata_put(struct nfs4_opendata *p)
                kref_put(&p->kref, nfs4_opendata_free);
 }
 
-static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task)
-{
-       int ret;
-
-       ret = rpc_wait_for_completion_task(task);
-       return ret;
-}
-
 static bool nfs4_mode_match_open_stateid(struct nfs4_state *state,
                fmode_t fmode)
 {
@@ -1732,17 +1635,15 @@ _nfs4_opendata_reclaim_to_nfs4_state(struct nfs4_opendata *data)
        int ret;
 
        if (!data->rpc_done) {
-               if (data->rpc_status) {
-                       ret = data->rpc_status;
-                       goto err;
-               }
+               if (data->rpc_status)
+                       return ERR_PTR(data->rpc_status);
                /* cached opens have already been processed */
                goto update;
        }
 
        ret = nfs_refresh_inode(inode, &data->f_attr);
        if (ret)
-               goto err;
+               return ERR_PTR(ret);
 
        if (data->o_res.delegation_type != 0)
                nfs4_opendata_check_deleg(data, state);
@@ -1752,9 +1653,6 @@ update:
        atomic_inc(&state->count);
 
        return state;
-err:
-       return ERR_PTR(ret);
-
 }
 
 static struct nfs4_state *
@@ -2048,8 +1946,8 @@ static void nfs4_open_confirm_prepare(struct rpc_task *task, void *calldata)
 {
        struct nfs4_opendata *data = calldata;
 
-       nfs40_setup_sequence(data->o_arg.server->nfs_client->cl_slot_tbl,
-                            &data->c_arg.seq_args, &data->c_res.seq_res, task);
+       nfs4_setup_sequence(data->o_arg.server->nfs_client,
+                          &data->c_arg.seq_args, &data->c_res.seq_res, task);
 }
 
 static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata)
@@ -2124,7 +2022,7 @@ static int _nfs4_proc_open_confirm(struct nfs4_opendata *data)
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
                return PTR_ERR(task);
-       status = nfs4_wait_for_completion_rpc_task(task);
+       status = rpc_wait_for_completion_task(task);
        if (status != 0) {
                data->cancelled = 1;
                smp_wmb();
@@ -2172,7 +2070,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
                nfs_copy_fh(&data->o_res.fh, data->o_arg.fh);
        }
        data->timestamp = jiffies;
-       if (nfs4_setup_sequence(data->o_arg.server,
+       if (nfs4_setup_sequence(data->o_arg.server->nfs_client,
                                &data->o_arg.seq_args,
                                &data->o_res.seq_res,
                                task) != 0)
@@ -2289,15 +2187,15 @@ static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover)
                data->is_recover = 1;
        }
        task = rpc_run_task(&task_setup_data);
-        if (IS_ERR(task))
-                return PTR_ERR(task);
-        status = nfs4_wait_for_completion_rpc_task(task);
-        if (status != 0) {
-                data->cancelled = 1;
-                smp_wmb();
-        } else
-                status = data->rpc_status;
-        rpc_put_task(task);
+       if (IS_ERR(task))
+               return PTR_ERR(task);
+       status = rpc_wait_for_completion_task(task);
+       if (status != 0) {
+               data->cancelled = 1;
+               smp_wmb();
+       } else
+               status = data->rpc_status;
+       rpc_put_task(task);
 
        return status;
 }
@@ -2306,7 +2204,7 @@ static int _nfs4_recover_proc_open(struct nfs4_opendata *data)
 {
        struct inode *dir = d_inode(data->dir);
        struct nfs_openres *o_res = &data->o_res;
-        int status;
+       int status;
 
        status = nfs4_run_open_task(data, 1);
        if (status != 0 || !data->rpc_done)
@@ -2314,11 +2212,8 @@ static int _nfs4_recover_proc_open(struct nfs4_opendata *data)
 
        nfs_fattr_map_and_free_names(NFS_SERVER(dir), &data->f_attr);
 
-       if (o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) {
+       if (o_res->rflags & NFS4_OPEN_RESULT_CONFIRM)
                status = _nfs4_proc_open_confirm(data);
-               if (status != 0)
-                       return status;
-       }
 
        return status;
 }
@@ -2412,11 +2307,6 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
        return 0;
 }
 
-static int nfs4_recover_expired_lease(struct nfs_server *server)
-{
-       return nfs4_client_recover_expired_lease(server->nfs_client);
-}
-
 /*
  * OPEN_EXPIRED:
  *     reclaim state on the server after a network partition.
@@ -2730,6 +2620,7 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
        ret = PTR_ERR(state);
        if (IS_ERR(state))
                goto out;
+       ctx->state = state;
        if (server->caps & NFS_CAP_POSIX_LOCK)
                set_bit(NFS_STATE_POSIX_LOCKS, &state->flags);
        if (opendata->o_res.rflags & NFS4_OPEN_RESULT_MAY_NOTIFY_LOCK)
@@ -2755,7 +2646,6 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
        if (ret != 0)
                goto out;
 
-       ctx->state = state;
        if (d_inode(dentry) == state->inode) {
                nfs_inode_attach_open_context(ctx);
                if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq))
@@ -2794,7 +2684,7 @@ static int _nfs4_do_open(struct inode *dir,
                dprintk("nfs4_do_open: nfs4_get_state_owner failed!\n");
                goto out_err;
        }
-       status = nfs4_recover_expired_lease(server);
+       status = nfs4_client_recover_expired_lease(server->nfs_client);
        if (status != 0)
                goto err_put_state_owner;
        if (d_really_is_positive(dentry))
@@ -2940,12 +2830,12 @@ static int _nfs4_do_setattr(struct inode *inode,
                            struct nfs_open_context *ctx)
 {
        struct nfs_server *server = NFS_SERVER(inode);
-        struct rpc_message msg = {
+       struct rpc_message msg = {
                .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_SETATTR],
                .rpc_argp       = arg,
                .rpc_resp       = res,
                .rpc_cred       = cred,
-        };
+       };
        struct rpc_cred *delegation_cred = NULL;
        unsigned long timestamp = jiffies;
        fmode_t fmode;
@@ -2993,18 +2883,18 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
 {
        struct nfs_server *server = NFS_SERVER(inode);
        struct nfs4_state *state = ctx ? ctx->state : NULL;
-        struct nfs_setattrargs  arg = {
-                .fh             = NFS_FH(inode),
-                .iap            = sattr,
+       struct nfs_setattrargs  arg = {
+               .fh             = NFS_FH(inode),
+               .iap            = sattr,
                .server         = server,
                .bitmask = server->attr_bitmask,
                .label          = ilabel,
-        };
-        struct nfs_setattrres  res = {
+       };
+       struct nfs_setattrres  res = {
                .fattr          = fattr,
                .label          = olabel,
                .server         = server,
-        };
+       };
        struct nfs4_exception exception = {
                .state = state,
                .inode = inode,
@@ -3118,7 +3008,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
                }
        }
 
-        /* hmm. we are done with the inode, and in the process of freeing
+       /* hmm. we are done with the inode, and in the process of freeing
         * the state_owner. we keep this around to process errors
         */
        switch (task->tk_status) {
@@ -3234,7 +3124,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
        else if (calldata->arg.bitmask == NULL)
                calldata->res.fattr = NULL;
        calldata->timestamp = jiffies;
-       if (nfs4_setup_sequence(NFS_SERVER(inode),
+       if (nfs4_setup_sequence(NFS_SERVER(inode)->nfs_client,
                                &calldata->arg.seq_args,
                                &calldata->res.seq_res,
                                task) != 0)
@@ -3522,16 +3412,11 @@ static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandl
                .pseudoflavor = flavor,
        };
        struct rpc_auth *auth;
-       int ret;
 
        auth = rpcauth_create(&auth_args, server->client);
-       if (IS_ERR(auth)) {
-               ret = -EACCES;
-               goto out;
-       }
-       ret = nfs4_lookup_root(server, fhandle, info);
-out:
-       return ret;
+       if (IS_ERR(auth))
+               return -EACCES;
+       return nfs4_lookup_root(server, fhandle, info);
 }
 
 /*
@@ -4114,7 +3999,7 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
 
 static void nfs4_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data)
 {
-       nfs4_setup_sequence(NFS_SB(data->dentry->d_sb),
+       nfs4_setup_sequence(NFS_SB(data->dentry->d_sb)->nfs_client,
                        &data->args.seq_args,
                        &data->res.seq_res,
                        task);
@@ -4148,7 +4033,7 @@ static void nfs4_proc_rename_setup(struct rpc_message *msg, struct inode *dir)
 
 static void nfs4_proc_rename_rpc_prepare(struct rpc_task *task, struct nfs_renamedata *data)
 {
-       nfs4_setup_sequence(NFS_SERVER(data->old_dir),
+       nfs4_setup_sequence(NFS_SERVER(data->old_dir)->nfs_client,
                        &data->args.seq_args,
                        &data->res.seq_res,
                        task);
@@ -4723,7 +4608,7 @@ static void nfs4_proc_read_setup(struct nfs_pgio_header *hdr,
 static int nfs4_proc_pgio_rpc_prepare(struct rpc_task *task,
                                      struct nfs_pgio_header *hdr)
 {
-       if (nfs4_setup_sequence(NFS_SERVER(hdr->inode),
+       if (nfs4_setup_sequence(NFS_SERVER(hdr->inode)->nfs_client,
                        &hdr->args.seq_args,
                        &hdr->res.seq_res,
                        task))
@@ -4822,7 +4707,7 @@ static void nfs4_proc_write_setup(struct nfs_pgio_header *hdr,
 
 static void nfs4_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commit_data *data)
 {
-       nfs4_setup_sequence(NFS_SERVER(data->inode),
+       nfs4_setup_sequence(NFS_SERVER(data->inode)->nfs_client,
                        &data->args.seq_args,
                        &data->res.seq_res,
                        task);
@@ -4975,8 +4860,8 @@ static int buf_to_pages_noslab(const void *buf, size_t buflen,
                if (newpage == NULL)
                        goto unwind;
                memcpy(page_address(newpage), buf, len);
-                buf += len;
-                buflen -= len;
+               buf += len;
+               buflen -= len;
                *pages++ = newpage;
                rc++;
        } while (buflen != 0);
@@ -5069,7 +4954,7 @@ out:
  */
 static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
 {
-       struct page *pages[NFS4ACL_MAXPAGES] = {NULL, };
+       struct page *pages[NFS4ACL_MAXPAGES + 1] = {NULL, };
        struct nfs_getaclargs args = {
                .fh = NFS_FH(inode),
                .acl_pages = pages,
@@ -5083,13 +4968,9 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
                .rpc_argp = &args,
                .rpc_resp = &res,
        };
-       unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE);
+       unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE) + 1;
        int ret = -ENOMEM, i;
 
-       /* As long as we're doing a round trip to the server anyway,
-        * let's be prepared for a page of acl data. */
-       if (npages == 0)
-               npages = 1;
        if (npages > ARRAY_SIZE(pages))
                return -ERANGE;
 
@@ -5299,8 +5180,8 @@ static int _nfs4_do_set_security_label(struct inode *inode,
        struct nfs_server *server = NFS_SERVER(inode);
        const u32 bitmask[3] = { 0, 0, FATTR4_WORD2_SECURITY_LABEL };
        struct nfs_setattrargs arg = {
-               .fh             = NFS_FH(inode),
-               .iap            = &sattr,
+               .fh             = NFS_FH(inode),
+               .iap            = &sattr,
                .server         = server,
                .bitmask        = bitmask,
                .label          = ilabel,
@@ -5311,9 +5192,9 @@ static int _nfs4_do_set_security_label(struct inode *inode,
                .server         = server,
        };
        struct rpc_message msg = {
-               .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_SETATTR],
-               .rpc_argp       = &arg,
-               .rpc_resp       = &res,
+               .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_SETATTR],
+               .rpc_argp       = &arg,
+               .rpc_resp       = &res,
        };
        int status;
 
@@ -5747,7 +5628,7 @@ static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data)
        if (!d_data->lr.roc && nfs4_wait_on_layoutreturn(d_data->inode, task))
                return;
 
-       nfs4_setup_sequence(d_data->res.server,
+       nfs4_setup_sequence(d_data->res.server->nfs_client,
                        &d_data->args.seq_args,
                        &d_data->res.seq_res,
                        task);
@@ -5817,7 +5698,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
                return PTR_ERR(task);
        if (!issync)
                goto out;
-       status = nfs4_wait_for_completion_rpc_task(task);
+       status = rpc_wait_for_completion_task(task);
        if (status != 0)
                goto out;
        status = data->rpc_status;
@@ -5859,8 +5740,8 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock
        };
        struct rpc_message msg = {
                .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_LOCKT],
-               .rpc_argp       = &arg,
-               .rpc_resp       = &res,
+               .rpc_argp       = &arg,
+               .rpc_resp       = &res,
                .rpc_cred       = state->owner->so_cred,
        };
        struct nfs4_lock_state *lsp;
@@ -5989,7 +5870,7 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)
                goto out_no_action;
        }
        calldata->timestamp = jiffies;
-       if (nfs4_setup_sequence(calldata->server,
+       if (nfs4_setup_sequence(calldata->server->nfs_client,
                                &calldata->arg.seq_args,
                                &calldata->res.seq_res,
                                task) != 0)
@@ -6087,7 +5968,7 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *
        status = PTR_ERR(task);
        if (IS_ERR(task))
                goto out;
-       status = nfs4_wait_for_completion_rpc_task(task);
+       status = rpc_wait_for_completion_task(task);
        rpc_put_task(task);
 out:
        request->fl_flags = fl_flags;
@@ -6174,7 +6055,7 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
                goto out_release_open_seqid;
        }
        data->timestamp = jiffies;
-       if (nfs4_setup_sequence(data->server,
+       if (nfs4_setup_sequence(data->server->nfs_client,
                                &data->arg.seq_args,
                                &data->res.seq_res,
                                task) == 0)
@@ -6314,7 +6195,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
                return PTR_ERR(task);
-       ret = nfs4_wait_for_completion_rpc_task(task);
+       ret = rpc_wait_for_completion_task(task);
        if (ret == 0) {
                ret = data->rpc_status;
                if (ret)
@@ -6393,8 +6274,7 @@ static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *reques
        if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) ||
            test_bit(NFS_LOCK_LOST, &lsp->ls_flags))
                return 0;
-       status = nfs4_lock_expired(state, request);
-       return status;
+       return nfs4_lock_expired(state, request);
 }
 #endif
 
@@ -6640,8 +6520,8 @@ static void nfs4_release_lockowner_prepare(struct rpc_task *task, void *calldata
 {
        struct nfs_release_lockowner_data *data = calldata;
        struct nfs_server *server = data->server;
-       nfs40_setup_sequence(server->nfs_client->cl_slot_tbl,
-                            &data->args.seq_args, &data->res.seq_res, task);
+       nfs4_setup_sequence(server->nfs_client, &data->args.seq_args,
+                          &data->res.seq_res, task);
        data->args.lock_owner.clientid = server->nfs_client->cl_clientid;
        data->timestamp = jiffies;
 }
@@ -7232,11 +7112,9 @@ static bool
 nfs41_same_server_scope(struct nfs41_server_scope *a,
                        struct nfs41_server_scope *b)
 {
-       if (a->server_scope_sz == b->server_scope_sz &&
-           memcmp(a->server_scope, b->server_scope, a->server_scope_sz) == 0)
-               return true;
-
-       return false;
+       if (a->server_scope_sz != b->server_scope_sz)
+               return false;
+       return memcmp(a->server_scope, b->server_scope, a->server_scope_sz) == 0;
 }
 
 static void
@@ -7831,7 +7709,7 @@ static void nfs4_get_lease_time_prepare(struct rpc_task *task,
        dprintk("--> %s\n", __func__);
        /* just setup sequence, do not trigger session recovery
           since we're invoked within one */
-       nfs41_setup_sequence(data->clp->cl_session,
+       nfs4_setup_sequence(data->clp,
                        &data->args->la_seq_args,
                        &data->res->lr_seq_res,
                        task);
@@ -8202,7 +8080,7 @@ static void nfs41_sequence_prepare(struct rpc_task *task, void *data)
        args = task->tk_msg.rpc_argp;
        res = task->tk_msg.rpc_resp;
 
-       nfs41_setup_sequence(clp->cl_session, args, res, task);
+       nfs4_setup_sequence(clp, args, res, task);
 }
 
 static const struct rpc_call_ops nfs41_sequence_ops = {
@@ -8290,7 +8168,7 @@ static void nfs4_reclaim_complete_prepare(struct rpc_task *task, void *data)
 {
        struct nfs4_reclaim_complete_data *calldata = data;
 
-       nfs41_setup_sequence(calldata->clp->cl_session,
+       nfs4_setup_sequence(calldata->clp,
                        &calldata->arg.seq_args,
                        &calldata->res.seq_res,
                        task);
@@ -8382,7 +8260,7 @@ static int nfs41_proc_reclaim_complete(struct nfs_client *clp,
                status = PTR_ERR(task);
                goto out;
        }
-       status = nfs4_wait_for_completion_rpc_task(task);
+       status = rpc_wait_for_completion_task(task);
        if (status == 0)
                status = task->tk_status;
        rpc_put_task(task);
@@ -8397,10 +8275,9 @@ nfs4_layoutget_prepare(struct rpc_task *task, void *calldata)
 {
        struct nfs4_layoutget *lgp = calldata;
        struct nfs_server *server = NFS_SERVER(lgp->args.inode);
-       struct nfs4_session *session = nfs4_get_session(server);
 
        dprintk("--> %s\n", __func__);
-       nfs41_setup_sequence(session, &lgp->args.seq_args,
+       nfs4_setup_sequence(server->nfs_client, &lgp->args.seq_args,
                                &lgp->res.seq_res, task);
        dprintk("<-- %s\n", __func__);
 }
@@ -8615,7 +8492,7 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout, gfp_t gfp_flags)
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
                return ERR_CAST(task);
-       status = nfs4_wait_for_completion_rpc_task(task);
+       status = rpc_wait_for_completion_task(task);
        if (status == 0) {
                status = nfs4_layoutget_handle_exception(task, lgp, &exception);
                *timeout = exception.timeout;
@@ -8644,7 +8521,7 @@ nfs4_layoutreturn_prepare(struct rpc_task *task, void *calldata)
        struct nfs4_layoutreturn *lrp = calldata;
 
        dprintk("--> %s\n", __func__);
-       nfs41_setup_sequence(lrp->clp->cl_session,
+       nfs4_setup_sequence(lrp->clp,
                        &lrp->args.seq_args,
                        &lrp->res.seq_res,
                        task);
@@ -8794,9 +8671,8 @@ static void nfs4_layoutcommit_prepare(struct rpc_task *task, void *calldata)
 {
        struct nfs4_layoutcommit_data *data = calldata;
        struct nfs_server *server = NFS_SERVER(data->args.inode);
-       struct nfs4_session *session = nfs4_get_session(server);
 
-       nfs41_setup_sequence(session,
+       nfs4_setup_sequence(server->nfs_client,
                        &data->args.seq_args,
                        &data->res.seq_res,
                        task);
@@ -9120,7 +8996,7 @@ struct nfs_free_stateid_data {
 static void nfs41_free_stateid_prepare(struct rpc_task *task, void *calldata)
 {
        struct nfs_free_stateid_data *data = calldata;
-       nfs41_setup_sequence(nfs4_get_session(data->server),
+       nfs4_setup_sequence(data->server->nfs_client,
                        &data->args.seq_args,
                        &data->res.seq_res,
                        task);
@@ -9232,10 +9108,8 @@ static bool nfs41_match_stateid(const nfs4_stateid *s1,
 
        if (s1->seqid == s2->seqid)
                return true;
-       if (s1->seqid == 0 || s2->seqid == 0)
-               return true;
 
-       return false;
+       return s1->seqid == 0 || s2->seqid == 0;
 }
 
 #endif /* CONFIG_NFS_V4_1 */
index 82e77198d17efdf656315f39c3d50c4d9aa568a9..1f8c2ae43a8dfb871b84f6cc7104655283d95ac3 100644 (file)
@@ -153,7 +153,7 @@ void nfs4_set_lease_period(struct nfs_client *clp,
        spin_unlock(&clp->cl_lock);
 
        /* Cap maximum reconnect timeout at 1/2 lease period */
-       rpc_cap_max_reconnect_timeout(clp->cl_rpcclient, lease >> 1);
+       rpc_set_connect_timeout(clp->cl_rpcclient, lease, lease >> 1);
 }
 
 /*
index dae3855000050f758380cc779d1c775abd305478..dfae4880eacb9884539d62cb2167a78f6429b7db 100644 (file)
@@ -103,6 +103,11 @@ static inline bool nfs4_test_locked_slot(const struct nfs4_slot_table *tbl,
        return !!test_bit(slotid, tbl->used_slots);
 }
 
+static inline struct nfs4_session *nfs4_get_session(const struct nfs_client *clp)
+{
+       return clp->cl_session;
+}
+
 #if defined(CONFIG_NFS_V4_1)
 extern void nfs41_set_target_slotid(struct nfs4_slot_table *tbl,
                u32 target_highest_slotid);
@@ -170,6 +175,8 @@ static inline int nfs4_has_persistent_session(const struct nfs_client *clp)
        return 0;
 }
 
+#define nfs_session_id_hash(session) (0)
+
 #endif /* defined(CONFIG_NFS_V4_1) */
 #endif /* IS_ENABLED(CONFIG_NFS_V4) */
 #endif /* __LINUX_FS_NFS_NFS4SESSION_H */
index daeb94e3acd49bd6553601bd15adb8f72236825b..8156bad6b441095199878a900e35594863cad571 100644 (file)
@@ -868,7 +868,7 @@ static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_
        
        for(;;) {
                spin_lock(&state->state_lock);
-               lsp = __nfs4_find_lock_state(state, owner, 0);
+               lsp = __nfs4_find_lock_state(state, owner, NULL);
                if (lsp != NULL)
                        break;
                if (new != NULL) {
index cfb8f7ce5cf6dbda09066ebc1cd21b0f6ee5757d..845d0eadefc94f48dc6410b3bbb3a0df89caca18 100644 (file)
@@ -241,38 +241,6 @@ DEFINE_NFS4_CLIENTID_EVENT(nfs4_bind_conn_to_session);
 DEFINE_NFS4_CLIENTID_EVENT(nfs4_sequence);
 DEFINE_NFS4_CLIENTID_EVENT(nfs4_reclaim_complete);
 
-TRACE_EVENT(nfs4_setup_sequence,
-               TP_PROTO(
-                       const struct nfs4_session *session,
-                       const struct nfs4_sequence_args *args
-               ),
-               TP_ARGS(session, args),
-
-               TP_STRUCT__entry(
-                       __field(unsigned int, session)
-                       __field(unsigned int, slot_nr)
-                       __field(unsigned int, seq_nr)
-                       __field(unsigned int, highest_used_slotid)
-               ),
-
-               TP_fast_assign(
-                       const struct nfs4_slot *sa_slot = args->sa_slot;
-                       __entry->session = nfs_session_id_hash(&session->sess_id);
-                       __entry->slot_nr = sa_slot->slot_nr;
-                       __entry->seq_nr = sa_slot->seq_nr;
-                       __entry->highest_used_slotid =
-                                       sa_slot->table->highest_used_slotid;
-               ),
-               TP_printk(
-                       "session=0x%08x slot_nr=%u seq_nr=%u "
-                       "highest_used_slotid=%u",
-                       __entry->session,
-                       __entry->slot_nr,
-                       __entry->seq_nr,
-                       __entry->highest_used_slotid
-               )
-);
-
 #define show_nfs4_sequence_status_flags(status) \
        __print_flags((unsigned long)status, "|", \
                { SEQ4_STATUS_CB_PATH_DOWN, "CB_PATH_DOWN" }, \
@@ -382,6 +350,38 @@ TRACE_EVENT(nfs4_cb_sequence,
 );
 #endif /* CONFIG_NFS_V4_1 */
 
+TRACE_EVENT(nfs4_setup_sequence,
+               TP_PROTO(
+                       const struct nfs4_session *session,
+                       const struct nfs4_sequence_args *args
+               ),
+               TP_ARGS(session, args),
+
+               TP_STRUCT__entry(
+                       __field(unsigned int, session)
+                       __field(unsigned int, slot_nr)
+                       __field(unsigned int, seq_nr)
+                       __field(unsigned int, highest_used_slotid)
+               ),
+
+               TP_fast_assign(
+                       const struct nfs4_slot *sa_slot = args->sa_slot;
+                       __entry->session = session ? nfs_session_id_hash(&session->sess_id) : 0;
+                       __entry->slot_nr = sa_slot->slot_nr;
+                       __entry->seq_nr = sa_slot->seq_nr;
+                       __entry->highest_used_slotid =
+                                       sa_slot->table->highest_used_slotid;
+               ),
+               TP_printk(
+                       "session=0x%08x slot_nr=%u seq_nr=%u "
+                       "highest_used_slotid=%u",
+                       __entry->session,
+                       __entry->slot_nr,
+                       __entry->seq_nr,
+                       __entry->highest_used_slotid
+               )
+);
+
 DECLARE_EVENT_CLASS(nfs4_open_event,
                TP_PROTO(
                        const struct nfs_open_context *ctx,
index e9255cb453e664c385c9a94969f69bc3514024b1..f0369e36275341404db0684aebb4e9bdba273205 100644 (file)
@@ -169,8 +169,10 @@ static int nfs4_stat_to_errno(int);
                                open_owner_id_maxsz + \
                                encode_opentype_maxsz + \
                                encode_claim_null_maxsz)
+#define decode_space_limit_maxsz       (3)
 #define decode_ace_maxsz       (3 + nfs4_owner_maxsz)
 #define decode_delegation_maxsz        (1 + decode_stateid_maxsz + 1 + \
+                               decode_space_limit_maxsz + \
                                decode_ace_maxsz)
 #define decode_change_info_maxsz       (5)
 #define decode_open_maxsz      (op_decode_hdr_maxsz + \
@@ -924,34 +926,22 @@ static __be32 *reserve_space(struct xdr_stream *xdr, size_t nbytes)
 
 static void encode_opaque_fixed(struct xdr_stream *xdr, const void *buf, size_t len)
 {
-       __be32 *p;
-
-       p = xdr_reserve_space(xdr, len);
-       xdr_encode_opaque_fixed(p, buf, len);
+       WARN_ON_ONCE(xdr_stream_encode_opaque_fixed(xdr, buf, len) < 0);
 }
 
 static void encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 4 + len);
-       xdr_encode_opaque(p, str, len);
+       WARN_ON_ONCE(xdr_stream_encode_opaque(xdr, str, len) < 0);
 }
 
 static void encode_uint32(struct xdr_stream *xdr, u32 n)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 4);
-       *p = cpu_to_be32(n);
+       WARN_ON_ONCE(xdr_stream_encode_u32(xdr, n) < 0);
 }
 
 static void encode_uint64(struct xdr_stream *xdr, u64 n)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 8);
-       xdr_encode_hyper(p, n);
+       WARN_ON_ONCE(xdr_stream_encode_u64(xdr, n) < 0);
 }
 
 static void encode_nfs4_seqid(struct xdr_stream *xdr,
@@ -2524,7 +2514,7 @@ static void nfs4_xdr_enc_getacl(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);
-       replen = hdr.replen + op_decode_hdr_maxsz + 1;
+       replen = hdr.replen + op_decode_hdr_maxsz;
        encode_getattr_two(xdr, FATTR4_WORD0_ACL, 0, &hdr);
 
        xdr_inline_pages(&req->rq_rcv_buf, replen << 2,
@@ -3062,20 +3052,15 @@ static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
 
 static int decode_opaque_inline(struct xdr_stream *xdr, unsigned int *len, char **string)
 {
-       __be32 *p;
-
-       p = xdr_inline_decode(xdr, 4);
-       if (unlikely(!p))
-               goto out_overflow;
-       *len = be32_to_cpup(p);
-       p = xdr_inline_decode(xdr, *len);
-       if (unlikely(!p))
-               goto out_overflow;
-       *string = (char *)p;
+       ssize_t ret = xdr_stream_decode_opaque_inline(xdr, (void **)string,
+                       NFS4_OPAQUE_LIMIT);
+       if (unlikely(ret < 0)) {
+               if (ret == -EBADMSG)
+                       print_overflow_msg(__func__, xdr);
+               return -EIO;
+       }
+       *len = ret;
        return 0;
-out_overflow:
-       print_overflow_msg(__func__, xdr);
-       return -EIO;
 }
 
 static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
@@ -3142,7 +3127,7 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
 }
 
 /* Dummy routine */
-static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs_client *clp)
+static int decode_ace(struct xdr_stream *xdr, void *ace)
 {
        __be32 *p;
        unsigned int strlen;
@@ -3890,45 +3875,50 @@ out_overflow:
        return -EIO;
 }
 
+static ssize_t decode_nfs4_string(struct xdr_stream *xdr,
+               struct nfs4_string *name, gfp_t gfp_flags)
+{
+       ssize_t ret;
+
+       ret = xdr_stream_decode_string_dup(xdr, &name->data,
+                       XDR_MAX_NETOBJ, gfp_flags);
+       name->len = 0;
+       if (ret > 0)
+               name->len = ret;
+       return ret;
+}
+
 static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap,
                const struct nfs_server *server, kuid_t *uid,
                struct nfs4_string *owner_name)
 {
-       uint32_t len;
-       __be32 *p;
-       int ret = 0;
+       ssize_t len;
+       char *p;
 
        *uid = make_kuid(&init_user_ns, -2);
        if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER - 1U)))
                return -EIO;
-       if (likely(bitmap[1] & FATTR4_WORD1_OWNER)) {
-               p = xdr_inline_decode(xdr, 4);
-               if (unlikely(!p))
-                       goto out_overflow;
-               len = be32_to_cpup(p);
-               p = xdr_inline_decode(xdr, len);
-               if (unlikely(!p))
-                       goto out_overflow;
-               if (owner_name != NULL) {
-                       owner_name->data = kmemdup(p, len, GFP_NOWAIT);
-                       if (owner_name->data != NULL) {
-                               owner_name->len = len;
-                               ret = NFS_ATTR_FATTR_OWNER_NAME;
-                       }
-               } else if (len < XDR_MAX_NETOBJ) {
-                       if (nfs_map_name_to_uid(server, (char *)p, len, uid) == 0)
-                               ret = NFS_ATTR_FATTR_OWNER;
-                       else
-                               dprintk("%s: nfs_map_name_to_uid failed!\n",
-                                               __func__);
-               } else
-                       dprintk("%s: name too long (%u)!\n",
-                                       __func__, len);
-               bitmap[1] &= ~FATTR4_WORD1_OWNER;
+       if (!(bitmap[1] & FATTR4_WORD1_OWNER))
+               return 0;
+       bitmap[1] &= ~FATTR4_WORD1_OWNER;
+
+       if (owner_name != NULL) {
+               len = decode_nfs4_string(xdr, owner_name, GFP_NOWAIT);
+               if (len <= 0)
+                       goto out;
+               dprintk("%s: name=%s\n", __func__, owner_name->data);
+               return NFS_ATTR_FATTR_OWNER_NAME;
+       } else {
+               len = xdr_stream_decode_opaque_inline(xdr, (void **)&p,
+                               XDR_MAX_NETOBJ);
+               if (len <= 0 || nfs_map_name_to_uid(server, p, len, uid) != 0)
+                       goto out;
+               dprintk("%s: uid=%d\n", __func__, (int)from_kuid(&init_user_ns, *uid));
+               return NFS_ATTR_FATTR_OWNER;
        }
-       dprintk("%s: uid=%d\n", __func__, (int)from_kuid(&init_user_ns, *uid));
-       return ret;
-out_overflow:
+out:
+       if (len != -EBADMSG)
+               return 0;
        print_overflow_msg(__func__, xdr);
        return -EIO;
 }
@@ -3937,41 +3927,33 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap,
                const struct nfs_server *server, kgid_t *gid,
                struct nfs4_string *group_name)
 {
-       uint32_t len;
-       __be32 *p;
-       int ret = 0;
+       ssize_t len;
+       char *p;
 
        *gid = make_kgid(&init_user_ns, -2);
        if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER_GROUP - 1U)))
                return -EIO;
-       if (likely(bitmap[1] & FATTR4_WORD1_OWNER_GROUP)) {
-               p = xdr_inline_decode(xdr, 4);
-               if (unlikely(!p))
-                       goto out_overflow;
-               len = be32_to_cpup(p);
-               p = xdr_inline_decode(xdr, len);
-               if (unlikely(!p))
-                       goto out_overflow;
-               if (group_name != NULL) {
-                       group_name->data = kmemdup(p, len, GFP_NOWAIT);
-                       if (group_name->data != NULL) {
-                               group_name->len = len;
-                               ret = NFS_ATTR_FATTR_GROUP_NAME;
-                       }
-               } else if (len < XDR_MAX_NETOBJ) {
-                       if (nfs_map_group_to_gid(server, (char *)p, len, gid) == 0)
-                               ret = NFS_ATTR_FATTR_GROUP;
-                       else
-                               dprintk("%s: nfs_map_group_to_gid failed!\n",
-                                               __func__);
-               } else
-                       dprintk("%s: name too long (%u)!\n",
-                                       __func__, len);
-               bitmap[1] &= ~FATTR4_WORD1_OWNER_GROUP;
+       if (!(bitmap[1] & FATTR4_WORD1_OWNER_GROUP))
+               return 0;
+       bitmap[1] &= ~FATTR4_WORD1_OWNER_GROUP;
+
+       if (group_name != NULL) {
+               len = decode_nfs4_string(xdr, group_name, GFP_NOWAIT);
+               if (len <= 0)
+                       goto out;
+               dprintk("%s: name=%s\n", __func__, group_name->data);
+               return NFS_ATTR_FATTR_OWNER_NAME;
+       } else {
+               len = xdr_stream_decode_opaque_inline(xdr, (void **)&p,
+                               XDR_MAX_NETOBJ);
+               if (len <= 0 || nfs_map_group_to_gid(server, p, len, gid) != 0)
+                       goto out;
+               dprintk("%s: gid=%d\n", __func__, (int)from_kgid(&init_user_ns, *gid));
+               return NFS_ATTR_FATTR_GROUP;
        }
-       dprintk("%s: gid=%d\n", __func__, (int)from_kgid(&init_user_ns, *gid));
-       return ret;
-out_overflow:
+out:
+       if (len != -EBADMSG)
+               return 0;
        print_overflow_msg(__func__, xdr);
        return -EIO;
 }
@@ -4294,15 +4276,12 @@ out_overflow:
 
 static int decode_opaque_fixed(struct xdr_stream *xdr, void *buf, size_t len)
 {
-       __be32 *p;
-
-       p = xdr_inline_decode(xdr, len);
-       if (likely(p)) {
-               memcpy(buf, p, len);
-               return 0;
+       ssize_t ret = xdr_stream_decode_opaque_fixed(xdr, buf, len);
+       if (unlikely(ret < 0)) {
+               print_overflow_msg(__func__, xdr);
+               return -EIO;
        }
-       print_overflow_msg(__func__, xdr);
-       return -EIO;
+       return 0;
 }
 
 static int decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
@@ -5093,7 +5072,7 @@ static int decode_rw_delegation(struct xdr_stream *xdr,
                if (decode_space_limit(xdr, &res->pagemod_limit) < 0)
                                return -EIO;
        }
-       return decode_ace(xdr, NULL, res->server->nfs_client);
+       return decode_ace(xdr, NULL);
 out_overflow:
        print_overflow_msg(__func__, xdr);
        return -EIO;
@@ -5660,8 +5639,6 @@ static int decode_exchange_id(struct xdr_stream *xdr,
        status = decode_opaque_inline(xdr, &dummy, &dummy_str);
        if (unlikely(status))
                return status;
-       if (unlikely(dummy > NFS4_OPAQUE_LIMIT))
-               return -EIO;
        memcpy(res->server_owner->major_id, dummy_str, dummy);
        res->server_owner->major_id_sz = dummy;
 
@@ -5669,8 +5646,6 @@ static int decode_exchange_id(struct xdr_stream *xdr,
        status = decode_opaque_inline(xdr, &dummy, &dummy_str);
        if (unlikely(status))
                return status;
-       if (unlikely(dummy > NFS4_OPAQUE_LIMIT))
-               return -EIO;
        memcpy(res->server_scope->server_scope, dummy_str, dummy);
        res->server_scope->server_scope_sz = dummy;
 
@@ -5685,16 +5660,12 @@ static int decode_exchange_id(struct xdr_stream *xdr,
                status = decode_opaque_inline(xdr, &dummy, &dummy_str);
                if (unlikely(status))
                        return status;
-               if (unlikely(dummy > NFS4_OPAQUE_LIMIT))
-                       return -EIO;
                memcpy(res->impl_id->domain, dummy_str, dummy);
 
                /* nii_name */
                status = decode_opaque_inline(xdr, &dummy, &dummy_str);
                if (unlikely(status))
                        return status;
-               if (unlikely(dummy > NFS4_OPAQUE_LIMIT))
-                       return -EIO;
                memcpy(res->impl_id->name, dummy_str, dummy);
 
                /* nii_date */
index 6bca17883b9368865253103b2df3f26320430d2d..54e0f9f2dd94903d2d6d96de46287ebc31fe1b6e 100644 (file)
@@ -531,39 +531,32 @@ static void nfs_show_mountd_netid(struct seq_file *m, struct nfs_server *nfss,
                                  int showdefaults)
 {
        struct sockaddr *sap = (struct sockaddr *) &nfss->mountd_address;
+       char *proto = NULL;
 
-       seq_printf(m, ",mountproto=");
        switch (sap->sa_family) {
        case AF_INET:
                switch (nfss->mountd_protocol) {
                case IPPROTO_UDP:
-                       seq_printf(m, RPCBIND_NETID_UDP);
+                       proto = RPCBIND_NETID_UDP;
                        break;
                case IPPROTO_TCP:
-                       seq_printf(m, RPCBIND_NETID_TCP);
+                       proto = RPCBIND_NETID_TCP;
                        break;
-               default:
-                       if (showdefaults)
-                               seq_printf(m, "auto");
                }
                break;
        case AF_INET6:
                switch (nfss->mountd_protocol) {
                case IPPROTO_UDP:
-                       seq_printf(m, RPCBIND_NETID_UDP6);
+                       proto = RPCBIND_NETID_UDP6;
                        break;
                case IPPROTO_TCP:
-                       seq_printf(m, RPCBIND_NETID_TCP6);
+                       proto = RPCBIND_NETID_TCP6;
                        break;
-               default:
-                       if (showdefaults)
-                               seq_printf(m, "auto");
                }
                break;
-       default:
-               if (showdefaults)
-                       seq_printf(m, "auto");
        }
+       if (proto || showdefaults)
+               seq_printf(m, ",mountproto=%s", proto ?: "auto");
 }
 
 static void nfs_show_mountd_options(struct seq_file *m, struct nfs_server *nfss,
index 006068526542760358b8450d76a8bf9e62f4f216..e75b056f46f43583b84da4a423cbafedb850c630 100644 (file)
@@ -1785,7 +1785,7 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data)
                if (status < 0) {
                        nfs_context_set_write_error(req->wb_context, status);
                        nfs_inode_remove_request(req);
-                       dprintk(", error = %d\n", status);
+                       dprintk_cont(", error = %d\n", status);
                        goto next;
                }
 
@@ -1794,11 +1794,11 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data)
                if (!nfs_write_verifier_cmp(&req->wb_verf, &data->verf.verifier)) {
                        /* We have a match */
                        nfs_inode_remove_request(req);
-                       dprintk(" OK\n");
+                       dprintk_cont(" OK\n");
                        goto next;
                }
                /* We have a mismatch. Write the page again */
-               dprintk(" mismatch\n");
+               dprintk_cont(" mismatch\n");
                nfs_mark_request_dirty(req);
                set_bit(NFS_CONTEXT_RESEND_WRITES, &req->wb_context->flags);
        next:
index c15373894a42a01a8c135a9b55619e3dbf5673a0..b37dee3acaba4c152fc2c0c928f4f312c74cc778 100644 (file)
@@ -355,7 +355,8 @@ static inline int nlm_privileged_requester(const struct svc_rqst *rqstp)
 static inline int nlm_compare_locks(const struct file_lock *fl1,
                                    const struct file_lock *fl2)
 {
-       return  fl1->fl_pid   == fl2->fl_pid
+       return file_inode(fl1->fl_file) == file_inode(fl2->fl_file)
+            && fl1->fl_pid   == fl2->fl_pid
             && fl1->fl_owner == fl2->fl_owner
             && fl1->fl_start == fl2->fl_start
             && fl1->fl_end   == fl2->fl_end
index b1bc62ba20a26d56df1d43794023a60e80e1ffef..8fd3504946ad5abbac6e502ea1b3f4ee0e439f48 100644 (file)
@@ -32,6 +32,7 @@
  */
 #define UNX_MAXNODENAME        __NEW_UTS_LEN
 #define UNX_CALLSLACK  (21 + XDR_QUADLEN(UNX_MAXNODENAME))
+#define UNX_NGROUPS    16
 
 struct rpcsec_gss_info;
 
@@ -63,9 +64,6 @@ struct rpc_cred {
        struct rcu_head         cr_rcu;
        struct rpc_auth *       cr_auth;
        const struct rpc_credops *cr_ops;
-#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
-       unsigned long           cr_magic;       /* 0x0f4aa4f0 */
-#endif
        unsigned long           cr_expire;      /* when to gc */
        unsigned long           cr_flags;       /* various flags */
        atomic_t                cr_count;       /* ref count */
@@ -79,8 +77,6 @@ struct rpc_cred {
 #define RPCAUTH_CRED_HASHED    2
 #define RPCAUTH_CRED_NEGATIVE  3
 
-#define RPCAUTH_CRED_MAGIC     0x0f4aa4f0
-
 /* rpc_auth au_flags */
 #define RPCAUTH_AUTH_NO_CRKEY_TIMEOUT  0x0001 /* underlying cred has no key timeout */
 
index 20d157a518a7dcb14763f5bfd7e317c0a6537387..270bad0e1bed137e9ce44727d9d79fde830e0006 100644 (file)
@@ -63,15 +63,6 @@ struct cache_head {
 
 #define        CACHE_NEW_EXPIRY 120    /* keep new things pending confirmation for 120 seconds */
 
-struct cache_detail_procfs {
-       struct proc_dir_entry   *proc_ent;
-       struct proc_dir_entry   *flush_ent, *channel_ent, *content_ent;
-};
-
-struct cache_detail_pipefs {
-       struct dentry *dir;
-};
-
 struct cache_detail {
        struct module *         owner;
        int                     hash_size;
@@ -123,9 +114,9 @@ struct cache_detail {
        time_t                  last_warn;              /* when we last warned about no readers */
 
        union {
-               struct cache_detail_procfs procfs;
-               struct cache_detail_pipefs pipefs;
-       } u;
+               struct proc_dir_entry   *procfs;
+               struct dentry           *pipefs;
+       };
        struct net              *net;
 };
 
index 333ad11b3dd9cf11a8ee2fc2f10bece31c543444..6095ecba0ddee9193ae1a96ecf21bf903584c52b 100644 (file)
@@ -182,7 +182,6 @@ int         rpc_protocol(struct rpc_clnt *);
 struct net *   rpc_net_ns(struct rpc_clnt *);
 size_t         rpc_max_payload(struct rpc_clnt *);
 size_t         rpc_max_bc_payload(struct rpc_clnt *);
-unsigned long  rpc_get_timeout(struct rpc_clnt *clnt);
 void           rpc_force_rebind(struct rpc_clnt *);
 size_t         rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t);
 const char     *rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t);
@@ -202,8 +201,9 @@ int         rpc_clnt_add_xprt(struct rpc_clnt *, struct xprt_create *,
                                struct rpc_xprt *,
                                void *),
                        void *data);
-void           rpc_cap_max_reconnect_timeout(struct rpc_clnt *clnt,
-                       unsigned long timeo);
+void           rpc_set_connect_timeout(struct rpc_clnt *clnt,
+                       unsigned long connect_timeout,
+                       unsigned long reconnect_timeout);
 
 int            rpc_clnt_setup_test_and_add_xprt(struct rpc_clnt *,
                        struct rpc_xprt_switch *,
index 59a7889e15db51c3b24bc771dbe5d0b1c965212d..8da0f37f3bdc2622cb378c04acf2ec43c882a3af 100644 (file)
@@ -20,33 +20,55 @@ extern unsigned int         nfsd_debug;
 extern unsigned int            nlm_debug;
 #endif
 
-#define dprintk(args...)       dfprintk(FACILITY, ## args)
-#define dprintk_rcu(args...)   dfprintk_rcu(FACILITY, ## args)
+#define dprintk(fmt, ...)                                              \
+       dfprintk(FACILITY, fmt, ##__VA_ARGS__)
+#define dprintk_cont(fmt, ...)                                         \
+       dfprintk_cont(FACILITY, fmt, ##__VA_ARGS__)
+#define dprintk_rcu(fmt, ...)                                          \
+       dfprintk_rcu(FACILITY, fmt, ##__VA_ARGS__)
+#define dprintk_rcu_cont(fmt, ...)                                     \
+       dfprintk_rcu_cont(FACILITY, fmt, ##__VA_ARGS__)
 
 #undef ifdebug
 #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
 # define ifdebug(fac)          if (unlikely(rpc_debug & RPCDBG_##fac))
 
-# define dfprintk(fac, args...)        \
-       do { \
-               ifdebug(fac) \
-                       printk(KERN_DEFAULT args); \
-       } while (0)
-
-# define dfprintk_rcu(fac, args...)    \
-       do { \
-               ifdebug(fac) { \
-                       rcu_read_lock(); \
-                       printk(KERN_DEFAULT args); \
-                       rcu_read_unlock(); \
-               } \
-       } while (0)
+# define dfprintk(fac, fmt, ...)                                       \
+do {                                                                   \
+       ifdebug(fac)                                                    \
+               printk(KERN_DEFAULT fmt, ##__VA_ARGS__);                \
+} while (0)
+
+# define dfprintk_cont(fac, fmt, ...)                                  \
+do {                                                                   \
+       ifdebug(fac)                                                    \
+               printk(KERN_CONT fmt, ##__VA_ARGS__);                   \
+} while (0)
+
+# define dfprintk_rcu(fac, fmt, ...)                                   \
+do {                                                                   \
+       ifdebug(fac) {                                                  \
+               rcu_read_lock();                                        \
+               printk(KERN_DEFAULT fmt, ##__VA_ARGS__);                \
+               rcu_read_unlock();                                      \
+       }                                                               \
+} while (0)
+
+# define dfprintk_rcu_cont(fac, fmt, ...)                              \
+do {                                                                   \
+       ifdebug(fac) {                                                  \
+               rcu_read_lock();                                        \
+               printk(KERN_CONT fmt, ##__VA_ARGS__);                   \
+               rcu_read_unlock();                                      \
+       }                                                               \
+} while (0)
 
 # define RPC_IFDEBUG(x)                x
 #else
 # define ifdebug(fac)          if (0)
-# define dfprintk(fac, args...)        do {} while (0)
-# define dfprintk_rcu(fac, args...)    do {} while (0)
+# define dfprintk(fac, fmt, ...)       do {} while (0)
+# define dfprintk_cont(fac, fmt, ...)  do {} while (0)
+# define dfprintk_rcu(fac, fmt, ...)   do {} while (0)
 # define RPC_IFDEBUG(x)
 #endif
 
index 56c48c884a242daadbed87dcea6ab1121884b742..054c8cde18f33bb1179fa1c90c699c9a120db7a5 100644 (file)
@@ -242,6 +242,185 @@ extern unsigned int xdr_read_pages(struct xdr_stream *xdr, unsigned int len);
 extern void xdr_enter_page(struct xdr_stream *xdr, unsigned int len);
 extern int xdr_process_buf(struct xdr_buf *buf, unsigned int offset, unsigned int len, int (*actor)(struct scatterlist *, void *), void *data);
 
+ssize_t xdr_stream_decode_string_dup(struct xdr_stream *xdr, char **str,
+               size_t maxlen, gfp_t gfp_flags);
+/**
+ * xdr_align_size - Calculate padded size of an object
+ * @n: Size of an object being XDR encoded (in bytes)
+ *
+ * Return value:
+ *   Size (in bytes) of the object including xdr padding
+ */
+static inline size_t
+xdr_align_size(size_t n)
+{
+       const size_t mask = sizeof(__u32) - 1;
+
+       return (n + mask) & ~mask;
+}
+
+/**
+ * xdr_stream_encode_u32 - Encode a 32-bit integer
+ * @xdr: pointer to xdr_stream
+ * @n: integer to encode
+ *
+ * Return values:
+ *   On success, returns length in bytes of XDR buffer consumed
+ *   %-EMSGSIZE on XDR buffer overflow
+ */
+static inline ssize_t
+xdr_stream_encode_u32(struct xdr_stream *xdr, __u32 n)
+{
+       const size_t len = sizeof(n);
+       __be32 *p = xdr_reserve_space(xdr, len);
+
+       if (unlikely(!p))
+               return -EMSGSIZE;
+       *p = cpu_to_be32(n);
+       return len;
+}
+
+/**
+ * xdr_stream_encode_u64 - Encode a 64-bit integer
+ * @xdr: pointer to xdr_stream
+ * @n: 64-bit integer to encode
+ *
+ * Return values:
+ *   On success, returns length in bytes of XDR buffer consumed
+ *   %-EMSGSIZE on XDR buffer overflow
+ */
+static inline ssize_t
+xdr_stream_encode_u64(struct xdr_stream *xdr, __u64 n)
+{
+       const size_t len = sizeof(n);
+       __be32 *p = xdr_reserve_space(xdr, len);
+
+       if (unlikely(!p))
+               return -EMSGSIZE;
+       xdr_encode_hyper(p, n);
+       return len;
+}
+
+/**
+ * xdr_stream_encode_opaque_fixed - Encode fixed length opaque xdr data
+ * @xdr: pointer to xdr_stream
+ * @ptr: pointer to opaque data object
+ * @len: size of object pointed to by @ptr
+ *
+ * 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_fixed(struct xdr_stream *xdr, const void *ptr, size_t len)
+{
+       __be32 *p = xdr_reserve_space(xdr, len);
+
+       if (unlikely(!p))
+               return -EMSGSIZE;
+       xdr_encode_opaque_fixed(p, ptr, len);
+       return xdr_align_size(len);
+}
+
+/**
+ * xdr_stream_encode_opaque - Encode variable length opaque xdr data
+ * @xdr: pointer to xdr_stream
+ * @ptr: pointer to opaque data object
+ * @len: size of object pointed to by @ptr
+ *
+ * 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(struct xdr_stream *xdr, const void *ptr, size_t len)
+{
+       size_t count = sizeof(__u32) + xdr_align_size(len);
+       __be32 *p = xdr_reserve_space(xdr, count);
+
+       if (unlikely(!p))
+               return -EMSGSIZE;
+       xdr_encode_opaque(p, ptr, len);
+       return count;
+}
+
+/**
+ * xdr_stream_decode_u32 - Decode a 32-bit integer
+ * @xdr: pointer to xdr_stream
+ * @ptr: location to store integer
+ *
+ * Return values:
+ *   %0 on success
+ *   %-EBADMSG on XDR buffer overflow
+ */
+static inline ssize_t
+xdr_stream_decode_u32(struct xdr_stream *xdr, __u32 *ptr)
+{
+       const size_t count = sizeof(*ptr);
+       __be32 *p = xdr_inline_decode(xdr, count);
+
+       if (unlikely(!p))
+               return -EBADMSG;
+       *ptr = be32_to_cpup(p);
+       return 0;
+}
+
+/**
+ * xdr_stream_decode_opaque_fixed - Decode fixed length opaque xdr data
+ * @xdr: pointer to xdr_stream
+ * @ptr: location to store data
+ * @len: size of buffer pointed to by @ptr
+ *
+ * Return values:
+ *   On success, returns size of object stored in @ptr
+ *   %-EBADMSG on XDR buffer overflow
+ */
+static inline ssize_t
+xdr_stream_decode_opaque_fixed(struct xdr_stream *xdr, void *ptr, size_t len)
+{
+       __be32 *p = xdr_inline_decode(xdr, len);
+
+       if (unlikely(!p))
+               return -EBADMSG;
+       xdr_decode_opaque_fixed(p, ptr, len);
+       return len;
+}
+
+/**
+ * xdr_stream_decode_opaque_inline - Decode variable length opaque xdr data
+ * @xdr: pointer to xdr_stream
+ * @ptr: location to store pointer to opaque data
+ * @maxlen: maximum acceptable object size
+ *
+ * Note: the pointer stored in @ptr cannot be assumed valid after the XDR
+ * buffer has been destroyed, or even after calling xdr_inline_decode()
+ * on @xdr. It is therefore expected that the object it points to should
+ * be processed immediately.
+ *
+ * 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
+ */
+static inline ssize_t
+xdr_stream_decode_opaque_inline(struct xdr_stream *xdr, void **ptr, size_t maxlen)
+{
+       __be32 *p;
+       __u32 len;
+
+       *ptr = NULL;
+       if (unlikely(xdr_stream_decode_u32(xdr, &len) < 0))
+               return -EBADMSG;
+       if (len != 0) {
+               p = xdr_inline_decode(xdr, len);
+               if (unlikely(!p))
+                       return -EBADMSG;
+               if (unlikely(len > maxlen))
+                       return -EMSGSIZE;
+               *ptr = p;
+       }
+       return len;
+}
 #endif /* __KERNEL__ */
 
 #endif /* _SUNRPC_XDR_H_ */
index a5da60b24d83ec79fb75bae8cd91ae52b6bcccc8..eab1c749e192b5ba37b050d5fb5592e825d61682 100644 (file)
@@ -137,6 +137,9 @@ struct rpc_xprt_ops {
        void            (*release_request)(struct rpc_task *task);
        void            (*close)(struct rpc_xprt *xprt);
        void            (*destroy)(struct rpc_xprt *xprt);
+       void            (*set_connect_timeout)(struct rpc_xprt *xprt,
+                                       unsigned long connect_timeout,
+                                       unsigned long reconnect_timeout);
        void            (*print_stats)(struct rpc_xprt *xprt, struct seq_file *seq);
        int             (*enable_swap)(struct rpc_xprt *xprt);
        void            (*disable_swap)(struct rpc_xprt *xprt);
@@ -221,6 +224,7 @@ struct rpc_xprt {
        struct timer_list       timer;
        unsigned long           last_used,
                                idle_timeout,
+                               connect_timeout,
                                max_reconnect_timeout;
 
        /*
index bef3fb0abb8f4a6fa713ff7fe774630779c88803..c9959d7e3579b5a4bfe49a74519c4a53cd707132 100644 (file)
@@ -55,6 +55,8 @@ struct sock_xprt {
        size_t                  rcvsize,
                                sndsize;
 
+       struct rpc_timeout      tcp_timeout;
+
        /*
         * Saved socket callback addresses
         */
@@ -81,6 +83,7 @@ struct sock_xprt {
 
 #define XPRT_SOCK_CONNECTING   1U
 #define XPRT_SOCK_DATA_READY   (2)
+#define XPRT_SOCK_UPD_TIMEOUT  (3)
 
 #endif /* __KERNEL__ */
 
index 2bff63a73cf8a98aab11e3f6cbb2154988907557..a1ee933e3029b32f46e4352e1499ba6bdf22818a 100644 (file)
@@ -464,8 +464,10 @@ rpcauth_prune_expired(struct list_head *free, int nr_to_scan)
                 * Note that the cred_unused list must be time-ordered.
                 */
                if (time_in_range(cred->cr_expire, expired, jiffies) &&
-                   test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0)
+                   test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) {
+                       freed = SHRINK_STOP;
                        break;
+               }
 
                list_del_init(&cred->cr_lru);
                number_cred_unused--;
@@ -520,7 +522,7 @@ static unsigned long
 rpcauth_cache_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
 
 {
-       return (number_cred_unused / 100) * sysctl_vfs_cache_pressure;
+       return number_cred_unused * sysctl_vfs_cache_pressure / 100;
 }
 
 static void
@@ -646,9 +648,6 @@ rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred,
        cred->cr_auth = auth;
        cred->cr_ops = ops;
        cred->cr_expire = jiffies;
-#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
-       cred->cr_magic = RPCAUTH_CRED_MAGIC;
-#endif
        cred->cr_uid = acred->uid;
 }
 EXPORT_SYMBOL_GPL(rpcauth_init_cred);
@@ -876,8 +875,12 @@ int __init rpcauth_init_module(void)
        err = rpc_init_generic_auth();
        if (err < 0)
                goto out2;
-       register_shrinker(&rpc_cred_shrinker);
+       err = register_shrinker(&rpc_cred_shrinker);
+       if (err < 0)
+               goto out3;
        return 0;
+out3:
+       rpc_destroy_generic_auth();
 out2:
        rpc_destroy_authunix();
 out1:
index 4d17376b2acb118fc1f17f2981f22eea676e3667..5f3d527dff65c0d9cf354d0d2488b955bd1452e1 100644 (file)
@@ -139,7 +139,4 @@ struct rpc_cred null_cred = {
        .cr_ops         = &null_credops,
        .cr_count       = ATOMIC_INIT(1),
        .cr_flags       = 1UL << RPCAUTH_CRED_UPTODATE,
-#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
-       .cr_magic       = RPCAUTH_CRED_MAGIC,
-#endif
 };
index 306fc0f545967a1643a4b80c6d787637a9950329..82337e1ec9cdc76cdcd30fe9fda0684814c95258 100644 (file)
 #include <linux/sunrpc/auth.h>
 #include <linux/user_namespace.h>
 
-#define NFS_NGROUPS    16
-
 struct unx_cred {
        struct rpc_cred         uc_base;
        kgid_t                  uc_gid;
-       kgid_t                  uc_gids[NFS_NGROUPS];
+       kgid_t                  uc_gids[UNX_NGROUPS];
 };
 #define uc_uid                 uc_base.cr_uid
 
@@ -82,13 +80,13 @@ unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags, gfp_t
 
        if (acred->group_info != NULL)
                groups = acred->group_info->ngroups;
-       if (groups > NFS_NGROUPS)
-               groups = NFS_NGROUPS;
+       if (groups > UNX_NGROUPS)
+               groups = UNX_NGROUPS;
 
        cred->uc_gid = acred->gid;
        for (i = 0; i < groups; i++)
                cred->uc_gids[i] = acred->group_info->gid[i];
-       if (i < NFS_NGROUPS)
+       if (i < UNX_NGROUPS)
                cred->uc_gids[i] = INVALID_GID;
 
        return &cred->uc_base;
@@ -132,12 +130,12 @@ unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int flags)
 
        if (acred->group_info != NULL)
                groups = acred->group_info->ngroups;
-       if (groups > NFS_NGROUPS)
-               groups = NFS_NGROUPS;
+       if (groups > UNX_NGROUPS)
+               groups = UNX_NGROUPS;
        for (i = 0; i < groups ; i++)
                if (!gid_eq(cred->uc_gids[i], acred->group_info->gid[i]))
                        return 0;
-       if (groups < NFS_NGROUPS && gid_valid(cred->uc_gids[groups]))
+       if (groups < UNX_NGROUPS && gid_valid(cred->uc_gids[groups]))
                return 0;
        return 1;
 }
@@ -166,7 +164,7 @@ unx_marshal(struct rpc_task *task, __be32 *p)
        *p++ = htonl((u32) from_kuid(&init_user_ns, cred->uc_uid));
        *p++ = htonl((u32) from_kgid(&init_user_ns, cred->uc_gid));
        hold = p++;
-       for (i = 0; i < 16 && gid_valid(cred->uc_gids[i]); i++)
+       for (i = 0; i < UNX_NGROUPS && gid_valid(cred->uc_gids[i]); i++)
                *p++ = htonl((u32) from_kgid(&init_user_ns, cred->uc_gids[i]));
        *hold = htonl(p - hold - 1);            /* gid array length */
        *base = htonl((p - base - 1) << 2);     /* cred length */
index d8639da06d9cd4815a407ef4dec4340bee68caf4..79d55d949d9a794a1501aee45f4807e76c7bfa1d 100644 (file)
@@ -728,7 +728,7 @@ void cache_clean_deferred(void *owner)
 /*
  * communicate with user-space
  *
- * We have a magic /proc file - /proc/sunrpc/<cachename>/channel.
+ * We have a magic /proc file - /proc/net/rpc/<cachename>/channel.
  * On read, you get a full request, or block.
  * On write, an update request is processed.
  * Poll works if anything to read, and always allows write.
@@ -1283,7 +1283,7 @@ EXPORT_SYMBOL_GPL(qword_get);
 
 
 /*
- * support /proc/sunrpc/cache/$CACHENAME/content
+ * support /proc/net/rpc/$CACHENAME/content
  * as a seqfile.
  * We call ->cache_show passing NULL for the item to
  * get a header, then pass each real item in the cache
@@ -1438,20 +1438,11 @@ static ssize_t read_flush(struct file *file, char __user *buf,
                          struct cache_detail *cd)
 {
        char tbuf[22];
-       unsigned long p = *ppos;
        size_t len;
 
-       snprintf(tbuf, sizeof(tbuf), "%lu\n", convert_to_wallclock(cd->flush_time));
-       len = strlen(tbuf);
-       if (p >= len)
-               return 0;
-       len -= p;
-       if (len > count)
-               len = count;
-       if (copy_to_user(buf, (void*)(tbuf+p), len))
-               return -EFAULT;
-       *ppos += len;
-       return len;
+       len = snprintf(tbuf, sizeof(tbuf), "%lu\n",
+                       convert_to_wallclock(cd->flush_time));
+       return simple_read_from_buffer(buf, count, ppos, tbuf, len);
 }
 
 static ssize_t write_flush(struct file *file, const char __user *buf,
@@ -1611,21 +1602,12 @@ static const struct file_operations cache_flush_operations_procfs = {
        .llseek         = no_llseek,
 };
 
-static void remove_cache_proc_entries(struct cache_detail *cd, struct net *net)
+static void remove_cache_proc_entries(struct cache_detail *cd)
 {
-       struct sunrpc_net *sn;
-
-       if (cd->u.procfs.proc_ent == NULL)
-               return;
-       if (cd->u.procfs.flush_ent)
-               remove_proc_entry("flush", cd->u.procfs.proc_ent);
-       if (cd->u.procfs.channel_ent)
-               remove_proc_entry("channel", cd->u.procfs.proc_ent);
-       if (cd->u.procfs.content_ent)
-               remove_proc_entry("content", cd->u.procfs.proc_ent);
-       cd->u.procfs.proc_ent = NULL;
-       sn = net_generic(net, sunrpc_net_id);
-       remove_proc_entry(cd->name, sn->proc_net_rpc);
+       if (cd->procfs) {
+               proc_remove(cd->procfs);
+               cd->procfs = NULL;
+       }
 }
 
 #ifdef CONFIG_PROC_FS
@@ -1635,38 +1617,30 @@ static int create_cache_proc_entries(struct cache_detail *cd, struct net *net)
        struct sunrpc_net *sn;
 
        sn = net_generic(net, sunrpc_net_id);
-       cd->u.procfs.proc_ent = proc_mkdir(cd->name, sn->proc_net_rpc);
-       if (cd->u.procfs.proc_ent == NULL)
+       cd->procfs = proc_mkdir(cd->name, sn->proc_net_rpc);
+       if (cd->procfs == NULL)
                goto out_nomem;
-       cd->u.procfs.channel_ent = NULL;
-       cd->u.procfs.content_ent = NULL;
 
        p = proc_create_data("flush", S_IFREG|S_IRUSR|S_IWUSR,
-                            cd->u.procfs.proc_ent,
-                            &cache_flush_operations_procfs, cd);
-       cd->u.procfs.flush_ent = p;
+                            cd->procfs, &cache_flush_operations_procfs, cd);
        if (p == NULL)
                goto out_nomem;
 
        if (cd->cache_request || cd->cache_parse) {
                p = proc_create_data("channel", S_IFREG|S_IRUSR|S_IWUSR,
-                                    cd->u.procfs.proc_ent,
-                                    &cache_file_operations_procfs, cd);
-               cd->u.procfs.channel_ent = p;
+                               cd->procfs, &cache_file_operations_procfs, cd);
                if (p == NULL)
                        goto out_nomem;
        }
        if (cd->cache_show) {
                p = proc_create_data("content", S_IFREG|S_IRUSR,
-                               cd->u.procfs.proc_ent,
-                               &content_file_operations_procfs, cd);
-               cd->u.procfs.content_ent = p;
+                               cd->procfs, &content_file_operations_procfs, cd);
                if (p == NULL)
                        goto out_nomem;
        }
        return 0;
 out_nomem:
-       remove_cache_proc_entries(cd, net);
+       remove_cache_proc_entries(cd);
        return -ENOMEM;
 }
 #else /* CONFIG_PROC_FS */
@@ -1695,7 +1669,7 @@ EXPORT_SYMBOL_GPL(cache_register_net);
 
 void cache_unregister_net(struct cache_detail *cd, struct net *net)
 {
-       remove_cache_proc_entries(cd, net);
+       remove_cache_proc_entries(cd);
        sunrpc_destroy_cache_detail(cd);
 }
 EXPORT_SYMBOL_GPL(cache_unregister_net);
@@ -1854,15 +1828,17 @@ int sunrpc_cache_register_pipefs(struct dentry *parent,
        struct dentry *dir = rpc_create_cache_dir(parent, name, umode, cd);
        if (IS_ERR(dir))
                return PTR_ERR(dir);
-       cd->u.pipefs.dir = dir;
+       cd->pipefs = dir;
        return 0;
 }
 EXPORT_SYMBOL_GPL(sunrpc_cache_register_pipefs);
 
 void sunrpc_cache_unregister_pipefs(struct cache_detail *cd)
 {
-       rpc_remove_cache_dir(cd->u.pipefs.dir);
-       cd->u.pipefs.dir = NULL;
+       if (cd->pipefs) {
+               rpc_remove_cache_dir(cd->pipefs);
+               cd->pipefs = NULL;
+       }
 }
 EXPORT_SYMBOL_GPL(sunrpc_cache_unregister_pipefs);
 
index 1dc9f3bac0997384a9b3daab33d8ceeda3d726d9..52da3ce54bb53c8434f0acc276c0003e385486e7 100644 (file)
@@ -1452,21 +1452,6 @@ size_t rpc_max_bc_payload(struct rpc_clnt *clnt)
 }
 EXPORT_SYMBOL_GPL(rpc_max_bc_payload);
 
-/**
- * rpc_get_timeout - Get timeout for transport in units of HZ
- * @clnt: RPC client to query
- */
-unsigned long rpc_get_timeout(struct rpc_clnt *clnt)
-{
-       unsigned long ret;
-
-       rcu_read_lock();
-       ret = rcu_dereference(clnt->cl_xprt)->timeout->to_initval;
-       rcu_read_unlock();
-       return ret;
-}
-EXPORT_SYMBOL_GPL(rpc_get_timeout);
-
 /**
  * rpc_force_rebind - force transport to check that remote port is unchanged
  * @clnt: client to rebind
@@ -2699,6 +2684,7 @@ int rpc_clnt_add_xprt(struct rpc_clnt *clnt,
 {
        struct rpc_xprt_switch *xps;
        struct rpc_xprt *xprt;
+       unsigned long connect_timeout;
        unsigned long reconnect_timeout;
        unsigned char resvport;
        int ret = 0;
@@ -2711,6 +2697,7 @@ int rpc_clnt_add_xprt(struct rpc_clnt *clnt,
                return -EAGAIN;
        }
        resvport = xprt->resvport;
+       connect_timeout = xprt->connect_timeout;
        reconnect_timeout = xprt->max_reconnect_timeout;
        rcu_read_unlock();
 
@@ -2720,7 +2707,10 @@ int rpc_clnt_add_xprt(struct rpc_clnt *clnt,
                goto out_put_switch;
        }
        xprt->resvport = resvport;
-       xprt->max_reconnect_timeout = reconnect_timeout;
+       if (xprt->ops->set_connect_timeout != NULL)
+               xprt->ops->set_connect_timeout(xprt,
+                               connect_timeout,
+                               reconnect_timeout);
 
        rpc_xprt_switch_set_roundrobin(xps);
        if (setup) {
@@ -2737,26 +2727,39 @@ out_put_switch:
 }
 EXPORT_SYMBOL_GPL(rpc_clnt_add_xprt);
 
+struct connect_timeout_data {
+       unsigned long connect_timeout;
+       unsigned long reconnect_timeout;
+};
+
 static int
-rpc_xprt_cap_max_reconnect_timeout(struct rpc_clnt *clnt,
+rpc_xprt_set_connect_timeout(struct rpc_clnt *clnt,
                struct rpc_xprt *xprt,
                void *data)
 {
-       unsigned long timeout = *((unsigned long *)data);
+       struct connect_timeout_data *timeo = data;
 
-       if (timeout < xprt->max_reconnect_timeout)
-               xprt->max_reconnect_timeout = timeout;
+       if (xprt->ops->set_connect_timeout)
+               xprt->ops->set_connect_timeout(xprt,
+                               timeo->connect_timeout,
+                               timeo->reconnect_timeout);
        return 0;
 }
 
 void
-rpc_cap_max_reconnect_timeout(struct rpc_clnt *clnt, unsigned long timeo)
+rpc_set_connect_timeout(struct rpc_clnt *clnt,
+               unsigned long connect_timeout,
+               unsigned long reconnect_timeout)
 {
+       struct connect_timeout_data timeout = {
+               .connect_timeout = connect_timeout,
+               .reconnect_timeout = reconnect_timeout,
+       };
        rpc_clnt_iterate_for_each_xprt(clnt,
-                       rpc_xprt_cap_max_reconnect_timeout,
-                       &timeo);
+                       rpc_xprt_set_connect_timeout,
+                       &timeout);
 }
-EXPORT_SYMBOL_GPL(rpc_cap_max_reconnect_timeout);
+EXPORT_SYMBOL_GPL(rpc_set_connect_timeout);
 
 void rpc_clnt_xprt_switch_put(struct rpc_clnt *clnt)
 {
index e7b4d93566df42dfa5ecf985152235e539ed9933..c8fd0b6c16189dfd21aaf2373b3fa72fa6c39860 100644 (file)
@@ -16,11 +16,6 @@ static struct dentry *rpc_xprt_dir;
 
 unsigned int rpc_inject_disconnect;
 
-struct rpc_clnt_iter {
-       struct rpc_clnt *clnt;
-       loff_t          pos;
-};
-
 static int
 tasks_show(struct seq_file *f, void *v)
 {
@@ -47,12 +42,10 @@ static void *
 tasks_start(struct seq_file *f, loff_t *ppos)
        __acquires(&clnt->cl_lock)
 {
-       struct rpc_clnt_iter *iter = f->private;
+       struct rpc_clnt *clnt = f->private;
        loff_t pos = *ppos;
-       struct rpc_clnt *clnt = iter->clnt;
        struct rpc_task *task;
 
-       iter->pos = pos + 1;
        spin_lock(&clnt->cl_lock);
        list_for_each_entry(task, &clnt->cl_tasks, tk_task)
                if (pos-- == 0)
@@ -63,12 +56,10 @@ tasks_start(struct seq_file *f, loff_t *ppos)
 static void *
 tasks_next(struct seq_file *f, void *v, loff_t *pos)
 {
-       struct rpc_clnt_iter *iter = f->private;
-       struct rpc_clnt *clnt = iter->clnt;
+       struct rpc_clnt *clnt = f->private;
        struct rpc_task *task = v;
        struct list_head *next = task->tk_task.next;
 
-       ++iter->pos;
        ++*pos;
 
        /* If there's another task on list, return it */
@@ -81,9 +72,7 @@ static void
 tasks_stop(struct seq_file *f, void *v)
        __releases(&clnt->cl_lock)
 {
-       struct rpc_clnt_iter *iter = f->private;
-       struct rpc_clnt *clnt = iter->clnt;
-
+       struct rpc_clnt *clnt = f->private;
        spin_unlock(&clnt->cl_lock);
 }
 
@@ -96,17 +85,13 @@ static const struct seq_operations tasks_seq_operations = {
 
 static int tasks_open(struct inode *inode, struct file *filp)
 {
-       int ret = seq_open_private(filp, &tasks_seq_operations,
-                                       sizeof(struct rpc_clnt_iter));
-
+       int ret = seq_open(filp, &tasks_seq_operations);
        if (!ret) {
                struct seq_file *seq = filp->private_data;
-               struct rpc_clnt_iter *iter = seq->private;
-
-               iter->clnt = inode->i_private;
+               struct rpc_clnt *clnt = seq->private = inode->i_private;
 
-               if (!atomic_inc_not_zero(&iter->clnt->cl_count)) {
-                       seq_release_private(inode, filp);
+               if (!atomic_inc_not_zero(&clnt->cl_count)) {
+                       seq_release(inode, filp);
                        ret = -EINVAL;
                }
        }
@@ -118,10 +103,10 @@ static int
 tasks_release(struct inode *inode, struct file *filp)
 {
        struct seq_file *seq = filp->private_data;
-       struct rpc_clnt_iter *iter = seq->private;
+       struct rpc_clnt *clnt = seq->private;
 
-       rpc_release_client(iter->clnt);
-       return seq_release_private(inode, filp);
+       rpc_release_client(clnt);
+       return seq_release(inode, filp);
 }
 
 static const struct file_operations tasks_fops = {
index 64af4f034de693f921faf3f818d833e868b0a2e2..f81eaa8e08888a1a16041548521a5908bf8a9a50 100644 (file)
@@ -403,7 +403,7 @@ svcauth_unix_info_release(struct svc_xprt *xpt)
 /****************************************************************************
  * auth.unix.gid cache
  * simple cache to map a UID to a list of GIDs
- * because AUTH_UNIX aka AUTH_SYS has a max of 16
+ * because AUTH_UNIX aka AUTH_SYS has a max of UNX_NGROUPS
  */
 #define        GID_HASHBITS    8
 #define        GID_HASHMAX     (1<<GID_HASHBITS)
@@ -810,7 +810,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
        cred->cr_uid = make_kuid(&init_user_ns, svc_getnl(argv)); /* uid */
        cred->cr_gid = make_kgid(&init_user_ns, svc_getnl(argv)); /* gid */
        slen = svc_getnl(argv);                 /* gids length */
-       if (slen > 16 || (len -= (slen + 2)*4) < 0)
+       if (slen > UNX_NGROUPS || (len -= (slen + 2)*4) < 0)
                goto badcred;
        cred->cr_group_info = groups_alloc(slen);
        if (cred->cr_group_info == NULL)
index 7f1071e103cafd7e4fadd75969cad8d5235fa927..1f7082144e0168070a9e8ed703ca044f9700b8dc 100644 (file)
@@ -1518,3 +1518,37 @@ out:
 }
 EXPORT_SYMBOL_GPL(xdr_process_buf);
 
+/**
+ * xdr_stream_decode_string_dup - Decode and duplicate variable length string
+ * @xdr: pointer to xdr_stream
+ * @str: location to store pointer to string
+ * @maxlen: maximum acceptable string length
+ * @gfp_flags: GFP mask to use
+ *
+ * Return values:
+ *   On success, returns length of NUL-terminated string stored in *@ptr
+ *   %-EBADMSG on XDR buffer overflow
+ *   %-EMSGSIZE if the size of the string would exceed @maxlen
+ *   %-ENOMEM on memory allocation failure
+ */
+ssize_t xdr_stream_decode_string_dup(struct xdr_stream *xdr, char **str,
+               size_t maxlen, gfp_t gfp_flags)
+{
+       void *p;
+       ssize_t ret;
+
+       ret = xdr_stream_decode_opaque_inline(xdr, &p, maxlen);
+       if (ret > 0) {
+               char *s = kmalloc(ret + 1, gfp_flags);
+               if (s != NULL) {
+                       memcpy(s, p, ret);
+                       s[ret] = '\0';
+                       *str = s;
+                       return strlen(s);
+               }
+               ret = -ENOMEM;
+       }
+       *str = NULL;
+       return ret;
+}
+EXPORT_SYMBOL_GPL(xdr_stream_decode_string_dup);
index 9a6be030ca7d21dbfee63664536872cc395bdc55..b530a2852ba87ac042baec67bf64a3e57e1232b5 100644 (file)
@@ -897,13 +897,11 @@ static void xprt_timer(struct rpc_task *task)
                return;
        dprintk("RPC: %5u xprt_timer\n", task->tk_pid);
 
-       spin_lock_bh(&xprt->transport_lock);
        if (!req->rq_reply_bytes_recvd) {
                if (xprt->ops->timer)
                        xprt->ops->timer(xprt, task);
        } else
                task->tk_status = 0;
-       spin_unlock_bh(&xprt->transport_lock);
 }
 
 /**
index 1ebb09e1ac4f8766cd99037b5d02b3b2b3965fae..59e64025ed96b52a0cb618638034de8282317c21 100644 (file)
@@ -310,10 +310,7 @@ fmr_op_unmap_safe(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req,
        struct rpcrdma_mw *mw;
 
        while (!list_empty(&req->rl_registered)) {
-               mw = list_first_entry(&req->rl_registered,
-                                     struct rpcrdma_mw, mw_list);
-               list_del_init(&mw->mw_list);
-
+               mw = rpcrdma_pop_mw(&req->rl_registered);
                if (sync)
                        fmr_op_recover_mr(mw);
                else
index 47bed5333c7ff20652af8dcb31f11ba1947927f6..f81dd93176c0767cd783328710a042ffe22aff6d 100644 (file)
@@ -466,8 +466,8 @@ frwr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
        struct ib_send_wr *first, **prev, *last, *bad_wr;
        struct rpcrdma_rep *rep = req->rl_reply;
        struct rpcrdma_ia *ia = &r_xprt->rx_ia;
-       struct rpcrdma_mw *mw, *tmp;
        struct rpcrdma_frmr *f;
+       struct rpcrdma_mw *mw;
        int count, rc;
 
        dprintk("RPC:       %s: req %p\n", __func__, req);
@@ -534,10 +534,10 @@ frwr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
         * them to the free MW list.
         */
 unmap:
-       list_for_each_entry_safe(mw, tmp, &req->rl_registered, mw_list) {
+       while (!list_empty(&req->rl_registered)) {
+               mw = rpcrdma_pop_mw(&req->rl_registered);
                dprintk("RPC:       %s: DMA unmapping frmr %p\n",
                        __func__, &mw->frmr);
-               list_del_init(&mw->mw_list);
                ib_dma_unmap_sg(ia->ri_device,
                                mw->mw_sg, mw->mw_nents, mw->mw_dir);
                rpcrdma_put_mw(r_xprt, mw);
@@ -571,10 +571,7 @@ frwr_op_unmap_safe(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req,
        struct rpcrdma_mw *mw;
 
        while (!list_empty(&req->rl_registered)) {
-               mw = list_first_entry(&req->rl_registered,
-                                     struct rpcrdma_mw, mw_list);
-               list_del_init(&mw->mw_list);
-
+               mw = rpcrdma_pop_mw(&req->rl_registered);
                if (sync)
                        frwr_op_recover_mr(mw);
                else
index c52e0f2ffe527dd2b5a99b8dc94c3c86818730a9..a044be2d6ad726eccfbd991038086aefc746df47 100644 (file)
@@ -125,14 +125,34 @@ void rpcrdma_set_max_header_sizes(struct rpcrdma_xprt *r_xprt)
 /* The client can send a request inline as long as the RPCRDMA header
  * plus the RPC call fit under the transport's inline limit. If the
  * combined call message size exceeds that limit, the client must use
- * the read chunk list for this operation.
+ * a Read chunk for this operation.
+ *
+ * A Read chunk is also required if sending the RPC call inline would
+ * exceed this device's max_sge limit.
  */
 static bool rpcrdma_args_inline(struct rpcrdma_xprt *r_xprt,
                                struct rpc_rqst *rqst)
 {
-       struct rpcrdma_ia *ia = &r_xprt->rx_ia;
+       struct xdr_buf *xdr = &rqst->rq_snd_buf;
+       unsigned int count, remaining, offset;
+
+       if (xdr->len > r_xprt->rx_ia.ri_max_inline_write)
+               return false;
+
+       if (xdr->page_len) {
+               remaining = xdr->page_len;
+               offset = xdr->page_base & ~PAGE_MASK;
+               count = 0;
+               while (remaining) {
+                       remaining -= min_t(unsigned int,
+                                          PAGE_SIZE - offset, remaining);
+                       offset = 0;
+                       if (++count > r_xprt->rx_ia.ri_max_send_sges)
+                               return false;
+               }
+       }
 
-       return rqst->rq_snd_buf.len <= ia->ri_max_inline_write;
+       return true;
 }
 
 /* The client can't know how large the actual reply will be. Thus it
@@ -186,9 +206,9 @@ rpcrdma_convert_kvec(struct kvec *vec, struct rpcrdma_mr_seg *seg, int n)
  */
 
 static int
-rpcrdma_convert_iovs(struct xdr_buf *xdrbuf, unsigned int pos,
-       enum rpcrdma_chunktype type, struct rpcrdma_mr_seg *seg,
-       bool reminv_expected)
+rpcrdma_convert_iovs(struct rpcrdma_xprt *r_xprt, struct xdr_buf *xdrbuf,
+                    unsigned int pos, enum rpcrdma_chunktype type,
+                    struct rpcrdma_mr_seg *seg)
 {
        int len, n, p, page_base;
        struct page **ppages;
@@ -226,22 +246,21 @@ rpcrdma_convert_iovs(struct xdr_buf *xdrbuf, unsigned int pos,
        if (len && n == RPCRDMA_MAX_SEGS)
                goto out_overflow;
 
-       /* When encoding the read list, the tail is always sent inline */
-       if (type == rpcrdma_readch)
+       /* When encoding a Read chunk, the tail iovec contains an
+        * XDR pad and may be omitted.
+        */
+       if (type == rpcrdma_readch && r_xprt->rx_ia.ri_implicit_roundup)
                return n;
 
-       /* When encoding the Write list, some servers need to see an extra
-        * segment for odd-length Write chunks. The upper layer provides
-        * space in the tail iovec for this purpose.
+       /* When encoding a Write chunk, some servers need to see an
+        * extra segment for non-XDR-aligned Write chunks. The upper
+        * layer provides space in the tail iovec that may be used
+        * for this purpose.
         */
-       if (type == rpcrdma_writech && reminv_expected)
+       if (type == rpcrdma_writech && r_xprt->rx_ia.ri_implicit_roundup)
                return n;
 
        if (xdrbuf->tail[0].iov_len) {
-               /* the rpcrdma protocol allows us to omit any trailing
-                * xdr pad bytes, saving the server an RDMA operation. */
-               if (xdrbuf->tail[0].iov_len < 4 && xprt_rdma_pad_optimize)
-                       return n;
                n = rpcrdma_convert_kvec(&xdrbuf->tail[0], seg, n);
                if (n == RPCRDMA_MAX_SEGS)
                        goto out_overflow;
@@ -293,7 +312,8 @@ rpcrdma_encode_read_list(struct rpcrdma_xprt *r_xprt,
        if (rtype == rpcrdma_areadch)
                pos = 0;
        seg = req->rl_segments;
-       nsegs = rpcrdma_convert_iovs(&rqst->rq_snd_buf, pos, rtype, seg, false);
+       nsegs = rpcrdma_convert_iovs(r_xprt, &rqst->rq_snd_buf, pos,
+                                    rtype, seg);
        if (nsegs < 0)
                return ERR_PTR(nsegs);
 
@@ -302,7 +322,7 @@ rpcrdma_encode_read_list(struct rpcrdma_xprt *r_xprt,
                                                 false, &mw);
                if (n < 0)
                        return ERR_PTR(n);
-               list_add(&mw->mw_list, &req->rl_registered);
+               rpcrdma_push_mw(mw, &req->rl_registered);
 
                *iptr++ = xdr_one;      /* item present */
 
@@ -355,10 +375,9 @@ rpcrdma_encode_write_list(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req,
        }
 
        seg = req->rl_segments;
-       nsegs = rpcrdma_convert_iovs(&rqst->rq_rcv_buf,
+       nsegs = rpcrdma_convert_iovs(r_xprt, &rqst->rq_rcv_buf,
                                     rqst->rq_rcv_buf.head[0].iov_len,
-                                    wtype, seg,
-                                    r_xprt->rx_ia.ri_reminv_expected);
+                                    wtype, seg);
        if (nsegs < 0)
                return ERR_PTR(nsegs);
 
@@ -371,7 +390,7 @@ rpcrdma_encode_write_list(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req,
                                                 true, &mw);
                if (n < 0)
                        return ERR_PTR(n);
-               list_add(&mw->mw_list, &req->rl_registered);
+               rpcrdma_push_mw(mw, &req->rl_registered);
 
                iptr = xdr_encode_rdma_segment(iptr, mw);
 
@@ -423,8 +442,7 @@ rpcrdma_encode_reply_chunk(struct rpcrdma_xprt *r_xprt,
        }
 
        seg = req->rl_segments;
-       nsegs = rpcrdma_convert_iovs(&rqst->rq_rcv_buf, 0, wtype, seg,
-                                    r_xprt->rx_ia.ri_reminv_expected);
+       nsegs = rpcrdma_convert_iovs(r_xprt, &rqst->rq_rcv_buf, 0, wtype, seg);
        if (nsegs < 0)
                return ERR_PTR(nsegs);
 
@@ -437,7 +455,7 @@ rpcrdma_encode_reply_chunk(struct rpcrdma_xprt *r_xprt,
                                                 true, &mw);
                if (n < 0)
                        return ERR_PTR(n);
-               list_add(&mw->mw_list, &req->rl_registered);
+               rpcrdma_push_mw(mw, &req->rl_registered);
 
                iptr = xdr_encode_rdma_segment(iptr, mw);
 
@@ -741,13 +759,13 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst)
        iptr = headerp->rm_body.rm_chunks;
        iptr = rpcrdma_encode_read_list(r_xprt, req, rqst, iptr, rtype);
        if (IS_ERR(iptr))
-               goto out_unmap;
+               goto out_err;
        iptr = rpcrdma_encode_write_list(r_xprt, req, rqst, iptr, wtype);
        if (IS_ERR(iptr))
-               goto out_unmap;
+               goto out_err;
        iptr = rpcrdma_encode_reply_chunk(r_xprt, req, rqst, iptr, wtype);
        if (IS_ERR(iptr))
-               goto out_unmap;
+               goto out_err;
        hdrlen = (unsigned char *)iptr - (unsigned char *)headerp;
 
        dprintk("RPC: %5u %s: %s/%s: hdrlen %zd rpclen %zd\n",
@@ -758,12 +776,14 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst)
        if (!rpcrdma_prepare_send_sges(&r_xprt->rx_ia, req, hdrlen,
                                       &rqst->rq_snd_buf, rtype)) {
                iptr = ERR_PTR(-EIO);
-               goto out_unmap;
+               goto out_err;
        }
        return 0;
 
-out_unmap:
-       r_xprt->rx_ia.ri_ops->ro_unmap_safe(r_xprt, req, false);
+out_err:
+       pr_err("rpcrdma: rpcrdma_marshal_req failed, status %ld\n",
+              PTR_ERR(iptr));
+       r_xprt->rx_stats.failed_marshal_count++;
        return PTR_ERR(iptr);
 }
 
index 534c178d2a7e2e283074c60561099fd7d3444139..c717f54107768902db7c571ce65f4019624c7bcc 100644 (file)
@@ -67,7 +67,7 @@ unsigned int xprt_rdma_max_inline_read = RPCRDMA_DEF_INLINE;
 static unsigned int xprt_rdma_max_inline_write = RPCRDMA_DEF_INLINE;
 static unsigned int xprt_rdma_inline_write_padding;
 static unsigned int xprt_rdma_memreg_strategy = RPCRDMA_FRMR;
-               int xprt_rdma_pad_optimize = 1;
+               int xprt_rdma_pad_optimize = 0;
 
 #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
 
@@ -709,10 +709,6 @@ xprt_rdma_send_request(struct rpc_task *task)
        return 0;
 
 failed_marshal:
-       dprintk("RPC:       %s: rpcrdma_marshal_req failed, status %i\n",
-               __func__, rc);
-       if (rc == -EIO)
-               r_xprt->rx_stats.failed_marshal_count++;
        if (rc != -ENOTCONN)
                return rc;
 drop_connection:
index 11d07748f699aeb76f6e7d495ad248fb09dcca79..81cd31acf690f41573e5fedd9b837376543f5ce9 100644 (file)
@@ -54,6 +54,7 @@
 #include <linux/sunrpc/svc_rdma.h>
 #include <asm/bitops.h>
 #include <linux/module.h> /* try_module_get()/module_put() */
+#include <rdma/ib_cm.h>
 
 #include "xprt_rdma.h"
 
@@ -208,6 +209,7 @@ rpcrdma_update_connect_private(struct rpcrdma_xprt *r_xprt,
 
        /* Default settings for RPC-over-RDMA Version One */
        r_xprt->rx_ia.ri_reminv_expected = false;
+       r_xprt->rx_ia.ri_implicit_roundup = xprt_rdma_pad_optimize;
        rsize = RPCRDMA_V1_DEF_INLINE_SIZE;
        wsize = RPCRDMA_V1_DEF_INLINE_SIZE;
 
@@ -215,6 +217,7 @@ rpcrdma_update_connect_private(struct rpcrdma_xprt *r_xprt,
            pmsg->cp_magic == rpcrdma_cmp_magic &&
            pmsg->cp_version == RPCRDMA_CMP_VERSION) {
                r_xprt->rx_ia.ri_reminv_expected = true;
+               r_xprt->rx_ia.ri_implicit_roundup = true;
                rsize = rpcrdma_decode_buffer_size(pmsg->cp_send_size);
                wsize = rpcrdma_decode_buffer_size(pmsg->cp_recv_size);
        }
@@ -277,7 +280,14 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event)
                connstate = -ENETDOWN;
                goto connected;
        case RDMA_CM_EVENT_REJECTED:
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
+               pr_info("rpcrdma: connection to %pIS:%u on %s rejected: %s\n",
+                       sap, rpc_get_port(sap), ia->ri_device->name,
+                       rdma_reject_msg(id, event->status));
+#endif
                connstate = -ECONNREFUSED;
+               if (event->status == IB_CM_REJ_STALE_CONN)
+                       connstate = -EAGAIN;
                goto connected;
        case RDMA_CM_EVENT_DISCONNECTED:
                connstate = -ECONNABORTED;
@@ -486,18 +496,19 @@ rpcrdma_ia_close(struct rpcrdma_ia *ia)
  */
 int
 rpcrdma_ep_create(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia,
-                               struct rpcrdma_create_data_internal *cdata)
+                 struct rpcrdma_create_data_internal *cdata)
 {
        struct rpcrdma_connect_private *pmsg = &ep->rep_cm_private;
+       unsigned int max_qp_wr, max_sge;
        struct ib_cq *sendcq, *recvcq;
-       unsigned int max_qp_wr;
        int rc;
 
-       if (ia->ri_device->attrs.max_sge < RPCRDMA_MAX_SEND_SGES) {
-               dprintk("RPC:       %s: insufficient sge's available\n",
-                       __func__);
+       max_sge = min(ia->ri_device->attrs.max_sge, RPCRDMA_MAX_SEND_SGES);
+       if (max_sge < RPCRDMA_MIN_SEND_SGES) {
+               pr_warn("rpcrdma: HCA provides only %d send SGEs\n", max_sge);
                return -ENOMEM;
        }
+       ia->ri_max_send_sges = max_sge - RPCRDMA_MIN_SEND_SGES;
 
        if (ia->ri_device->attrs.max_qp_wr <= RPCRDMA_BACKWARD_WRS) {
                dprintk("RPC:       %s: insufficient wqe's available\n",
@@ -522,7 +533,7 @@ rpcrdma_ep_create(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia,
        ep->rep_attr.cap.max_recv_wr = cdata->max_requests;
        ep->rep_attr.cap.max_recv_wr += RPCRDMA_BACKWARD_WRS;
        ep->rep_attr.cap.max_recv_wr += 1;      /* drain cqe */
-       ep->rep_attr.cap.max_send_sge = RPCRDMA_MAX_SEND_SGES;
+       ep->rep_attr.cap.max_send_sge = max_sge;
        ep->rep_attr.cap.max_recv_sge = 1;
        ep->rep_attr.cap.max_inline_data = 0;
        ep->rep_attr.sq_sig_type = IB_SIGNAL_REQ_WR;
@@ -640,20 +651,21 @@ rpcrdma_ep_destroy(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
 int
 rpcrdma_ep_connect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
 {
+       struct rpcrdma_xprt *r_xprt = container_of(ia, struct rpcrdma_xprt,
+                                                  rx_ia);
        struct rdma_cm_id *id, *old;
+       struct sockaddr *sap;
+       unsigned int extras;
        int rc = 0;
-       int retry_count = 0;
 
        if (ep->rep_connected != 0) {
-               struct rpcrdma_xprt *xprt;
 retry:
                dprintk("RPC:       %s: reconnecting...\n", __func__);
 
                rpcrdma_ep_disconnect(ep, ia);
 
-               xprt = container_of(ia, struct rpcrdma_xprt, rx_ia);
-               id = rpcrdma_create_id(xprt, ia,
-                               (struct sockaddr *)&xprt->rx_data.addr);
+               sap = (struct sockaddr *)&r_xprt->rx_data.addr;
+               id = rpcrdma_create_id(r_xprt, ia, sap);
                if (IS_ERR(id)) {
                        rc = -EHOSTUNREACH;
                        goto out;
@@ -708,51 +720,18 @@ retry:
        }
 
        wait_event_interruptible(ep->rep_connect_wait, ep->rep_connected != 0);
-
-       /*
-        * Check state. A non-peer reject indicates no listener
-        * (ECONNREFUSED), which may be a transient state. All
-        * others indicate a transport condition which has already
-        * undergone a best-effort.
-        */
-       if (ep->rep_connected == -ECONNREFUSED &&
-           ++retry_count <= RDMA_CONNECT_RETRY_MAX) {
-               dprintk("RPC:       %s: non-peer_reject, retry\n", __func__);
-               goto retry;
-       }
        if (ep->rep_connected <= 0) {
-               /* Sometimes, the only way to reliably connect to remote
-                * CMs is to use same nonzero values for ORD and IRD. */
-               if (retry_count++ <= RDMA_CONNECT_RETRY_MAX + 1 &&
-                   (ep->rep_remote_cma.responder_resources == 0 ||
-                    ep->rep_remote_cma.initiator_depth !=
-                               ep->rep_remote_cma.responder_resources)) {
-                       if (ep->rep_remote_cma.responder_resources == 0)
-                               ep->rep_remote_cma.responder_resources = 1;
-                       ep->rep_remote_cma.initiator_depth =
-                               ep->rep_remote_cma.responder_resources;
+               if (ep->rep_connected == -EAGAIN)
                        goto retry;
-               }
                rc = ep->rep_connected;
-       } else {
-               struct rpcrdma_xprt *r_xprt;
-               unsigned int extras;
-
-               dprintk("RPC:       %s: connected\n", __func__);
-
-               r_xprt = container_of(ia, struct rpcrdma_xprt, rx_ia);
-               extras = r_xprt->rx_buf.rb_bc_srv_max_requests;
-
-               if (extras) {
-                       rc = rpcrdma_ep_post_extra_recv(r_xprt, extras);
-                       if (rc) {
-                               pr_warn("%s: rpcrdma_ep_post_extra_recv: %i\n",
-                                       __func__, rc);
-                               rc = 0;
-                       }
-               }
+               goto out;
        }
 
+       dprintk("RPC:       %s: connected\n", __func__);
+       extras = r_xprt->rx_buf.rb_bc_srv_max_requests;
+       if (extras)
+               rpcrdma_ep_post_extra_recv(r_xprt, extras);
+
 out:
        if (rc)
                ep->rep_connected = rc;
@@ -797,9 +776,7 @@ rpcrdma_mr_recovery_worker(struct work_struct *work)
 
        spin_lock(&buf->rb_recovery_lock);
        while (!list_empty(&buf->rb_stale_mrs)) {
-               mw = list_first_entry(&buf->rb_stale_mrs,
-                                     struct rpcrdma_mw, mw_list);
-               list_del_init(&mw->mw_list);
+               mw = rpcrdma_pop_mw(&buf->rb_stale_mrs);
                spin_unlock(&buf->rb_recovery_lock);
 
                dprintk("RPC:       %s: recovering MR %p\n", __func__, mw);
@@ -817,7 +794,7 @@ rpcrdma_defer_mr_recovery(struct rpcrdma_mw *mw)
        struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
 
        spin_lock(&buf->rb_recovery_lock);
-       list_add(&mw->mw_list, &buf->rb_stale_mrs);
+       rpcrdma_push_mw(mw, &buf->rb_stale_mrs);
        spin_unlock(&buf->rb_recovery_lock);
 
        schedule_delayed_work(&buf->rb_recovery_worker, 0);
@@ -1093,11 +1070,8 @@ rpcrdma_get_mw(struct rpcrdma_xprt *r_xprt)
        struct rpcrdma_mw *mw = NULL;
 
        spin_lock(&buf->rb_mwlock);
-       if (!list_empty(&buf->rb_mws)) {
-               mw = list_first_entry(&buf->rb_mws,
-                                     struct rpcrdma_mw, mw_list);
-               list_del_init(&mw->mw_list);
-       }
+       if (!list_empty(&buf->rb_mws))
+               mw = rpcrdma_pop_mw(&buf->rb_mws);
        spin_unlock(&buf->rb_mwlock);
 
        if (!mw)
@@ -1120,7 +1094,7 @@ rpcrdma_put_mw(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mw *mw)
        struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
 
        spin_lock(&buf->rb_mwlock);
-       list_add_tail(&mw->mw_list, &buf->rb_mws);
+       rpcrdma_push_mw(mw, &buf->rb_mws);
        spin_unlock(&buf->rb_mwlock);
 }
 
index e35efd4ac1e4b6267349702a3286cbdd96435030..171a35116de911878ce88402c3bac2979740af63 100644 (file)
@@ -74,7 +74,9 @@ struct rpcrdma_ia {
        unsigned int            ri_max_frmr_depth;
        unsigned int            ri_max_inline_write;
        unsigned int            ri_max_inline_read;
+       unsigned int            ri_max_send_sges;
        bool                    ri_reminv_expected;
+       bool                    ri_implicit_roundup;
        enum ib_mr_type         ri_mrtype;
        struct ib_qp_attr       ri_qp_attr;
        struct ib_qp_init_attr  ri_qp_init_attr;
@@ -303,15 +305,19 @@ struct rpcrdma_mr_seg {           /* chunk descriptors */
        char            *mr_offset;     /* kva if no page, else offset */
 };
 
-/* Reserve enough Send SGEs to send a maximum size inline request:
+/* The Send SGE array is provisioned to send a maximum size
+ * inline request:
  * - RPC-over-RDMA header
  * - xdr_buf head iovec
- * - RPCRDMA_MAX_INLINE bytes, possibly unaligned, in pages
+ * - RPCRDMA_MAX_INLINE bytes, in pages
  * - xdr_buf tail iovec
+ *
+ * The actual number of array elements consumed by each RPC
+ * depends on the device's max_sge limit.
  */
 enum {
-       RPCRDMA_MAX_SEND_PAGES = PAGE_SIZE + RPCRDMA_MAX_INLINE - 1,
-       RPCRDMA_MAX_PAGE_SGES = (RPCRDMA_MAX_SEND_PAGES >> PAGE_SHIFT) + 1,
+       RPCRDMA_MIN_SEND_SGES = 3,
+       RPCRDMA_MAX_PAGE_SGES = RPCRDMA_MAX_INLINE >> PAGE_SHIFT,
        RPCRDMA_MAX_SEND_SGES = 1 + 1 + RPCRDMA_MAX_PAGE_SGES + 1,
 };
 
@@ -348,6 +354,22 @@ rpcr_to_rdmar(struct rpc_rqst *rqst)
        return rqst->rq_xprtdata;
 }
 
+static inline void
+rpcrdma_push_mw(struct rpcrdma_mw *mw, struct list_head *list)
+{
+       list_add_tail(&mw->mw_list, list);
+}
+
+static inline struct rpcrdma_mw *
+rpcrdma_pop_mw(struct list_head *list)
+{
+       struct rpcrdma_mw *mw;
+
+       mw = list_first_entry(list, struct rpcrdma_mw, mw_list);
+       list_del(&mw->mw_list);
+       return mw;
+}
+
 /*
  * struct rpcrdma_buffer -- holds list/queue of pre-registered memory for
  * inline requests/replies, and client/server credits.
index 956c7bce80d1b2184c6a61708052d33b7e9bea2d..16aff8ddc16f8f3e66e31a86ce227b3ac49857bf 100644 (file)
@@ -52,6 +52,8 @@
 #include "sunrpc.h"
 
 static void xs_close(struct rpc_xprt *xprt);
+static void xs_tcp_set_socket_timeouts(struct rpc_xprt *xprt,
+               struct socket *sock);
 
 /*
  * xprtsock tunables
@@ -666,6 +668,9 @@ static int xs_tcp_send_request(struct rpc_task *task)
        if (task->tk_flags & RPC_TASK_SENT)
                zerocopy = false;
 
+       if (test_bit(XPRT_SOCK_UPD_TIMEOUT, &transport->sock_state))
+               xs_tcp_set_socket_timeouts(xprt, transport->sock);
+
        /* Continue transmitting the packet/record. We must be careful
         * to cope with writespace callbacks arriving _after_ we have
         * called sendmsg(). */
@@ -1734,7 +1739,9 @@ static void xs_udp_set_buffer_size(struct rpc_xprt *xprt, size_t sndsize, size_t
  */
 static void xs_udp_timer(struct rpc_xprt *xprt, struct rpc_task *task)
 {
+       spin_lock_bh(&xprt->transport_lock);
        xprt_adjust_cwnd(xprt, task, -ETIMEDOUT);
+       spin_unlock_bh(&xprt->transport_lock);
 }
 
 static unsigned short xs_get_random_port(void)
@@ -2235,6 +2242,66 @@ static void xs_tcp_shutdown(struct rpc_xprt *xprt)
                xs_reset_transport(transport);
 }
 
+static void xs_tcp_set_socket_timeouts(struct rpc_xprt *xprt,
+               struct socket *sock)
+{
+       struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
+       unsigned int keepidle;
+       unsigned int keepcnt;
+       unsigned int opt_on = 1;
+       unsigned int timeo;
+
+       spin_lock_bh(&xprt->transport_lock);
+       keepidle = DIV_ROUND_UP(xprt->timeout->to_initval, HZ);
+       keepcnt = xprt->timeout->to_retries + 1;
+       timeo = jiffies_to_msecs(xprt->timeout->to_initval) *
+               (xprt->timeout->to_retries + 1);
+       clear_bit(XPRT_SOCK_UPD_TIMEOUT, &transport->sock_state);
+       spin_unlock_bh(&xprt->transport_lock);
+
+       /* TCP Keepalive options */
+       kernel_setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
+                       (char *)&opt_on, sizeof(opt_on));
+       kernel_setsockopt(sock, SOL_TCP, TCP_KEEPIDLE,
+                       (char *)&keepidle, sizeof(keepidle));
+       kernel_setsockopt(sock, SOL_TCP, TCP_KEEPINTVL,
+                       (char *)&keepidle, sizeof(keepidle));
+       kernel_setsockopt(sock, SOL_TCP, TCP_KEEPCNT,
+                       (char *)&keepcnt, sizeof(keepcnt));
+
+       /* TCP user timeout (see RFC5482) */
+       kernel_setsockopt(sock, SOL_TCP, TCP_USER_TIMEOUT,
+                       (char *)&timeo, sizeof(timeo));
+}
+
+static void xs_tcp_set_connect_timeout(struct rpc_xprt *xprt,
+               unsigned long connect_timeout,
+               unsigned long reconnect_timeout)
+{
+       struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
+       struct rpc_timeout to;
+       unsigned long initval;
+
+       spin_lock_bh(&xprt->transport_lock);
+       if (reconnect_timeout < xprt->max_reconnect_timeout)
+               xprt->max_reconnect_timeout = reconnect_timeout;
+       if (connect_timeout < xprt->connect_timeout) {
+               memcpy(&to, xprt->timeout, sizeof(to));
+               initval = DIV_ROUND_UP(connect_timeout, to.to_retries + 1);
+               /* Arbitrary lower limit */
+               if (initval <  XS_TCP_INIT_REEST_TO << 1)
+                       initval = XS_TCP_INIT_REEST_TO << 1;
+               to.to_initval = initval;
+               to.to_maxval = initval;
+               memcpy(&transport->tcp_timeout, &to,
+                               sizeof(transport->tcp_timeout));
+               xprt->timeout = &transport->tcp_timeout;
+               xprt->connect_timeout = connect_timeout;
+       }
+       set_bit(XPRT_SOCK_UPD_TIMEOUT, &transport->sock_state);
+       spin_unlock_bh(&xprt->transport_lock);
+}
+
 static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
 {
        struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
@@ -2242,22 +2309,8 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
 
        if (!transport->inet) {
                struct sock *sk = sock->sk;
-               unsigned int keepidle = xprt->timeout->to_initval / HZ;
-               unsigned int keepcnt = xprt->timeout->to_retries + 1;
-               unsigned int opt_on = 1;
-               unsigned int timeo;
                unsigned int addr_pref = IPV6_PREFER_SRC_PUBLIC;
 
-               /* TCP Keepalive options */
-               kernel_setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
-                               (char *)&opt_on, sizeof(opt_on));
-               kernel_setsockopt(sock, SOL_TCP, TCP_KEEPIDLE,
-                               (char *)&keepidle, sizeof(keepidle));
-               kernel_setsockopt(sock, SOL_TCP, TCP_KEEPINTVL,
-                               (char *)&keepidle, sizeof(keepidle));
-               kernel_setsockopt(sock, SOL_TCP, TCP_KEEPCNT,
-                               (char *)&keepcnt, sizeof(keepcnt));
-
                /* Avoid temporary address, they are bad for long-lived
                 * connections such as NFS mounts.
                 * RFC4941, section 3.6 suggests that:
@@ -2268,11 +2321,7 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
                kernel_setsockopt(sock, SOL_IPV6, IPV6_ADDR_PREFERENCES,
                                (char *)&addr_pref, sizeof(addr_pref));
 
-               /* TCP user timeout (see RFC5482) */
-               timeo = jiffies_to_msecs(xprt->timeout->to_initval) *
-                       (xprt->timeout->to_retries + 1);
-               kernel_setsockopt(sock, SOL_TCP, TCP_USER_TIMEOUT,
-                               (char *)&timeo, sizeof(timeo));
+               xs_tcp_set_socket_timeouts(xprt, sock);
 
                write_lock_bh(&sk->sk_callback_lock);
 
@@ -2721,6 +2770,7 @@ static struct rpc_xprt_ops xs_tcp_ops = {
        .set_retrans_timeout    = xprt_set_retrans_timeout_def,
        .close                  = xs_tcp_shutdown,
        .destroy                = xs_destroy,
+       .set_connect_timeout    = xs_tcp_set_connect_timeout,
        .print_stats            = xs_tcp_print_stats,
        .enable_swap            = xs_enable_swap,
        .disable_swap           = xs_disable_swap,
@@ -3007,6 +3057,8 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args)
        xprt->timeout = &xs_tcp_default_timeout;
 
        xprt->max_reconnect_timeout = xprt->timeout->to_maxval;
+       xprt->connect_timeout = xprt->timeout->to_initval *
+               (xprt->timeout->to_retries + 1);
 
        INIT_WORK(&transport->recv_worker, xs_tcp_data_receive_workfn);
        INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_setup_socket);
@@ -3209,7 +3261,9 @@ static int param_set_uint_minmax(const char *val,
        if (!val)
                return -EINVAL;
        ret = kstrtouint(val, 0, &num);
-       if (ret == -EINVAL || num < min || num > max)
+       if (ret)
+               return ret;
+       if (num < min || num > max)
                return -EINVAL;
        *((unsigned int *)kp->arg) = num;
        return 0;