Commit 0961f0c0 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'nfs-for-5.15-1' of git://git.linux-nfs.org/projects/anna/linux-nfs

Pull NFS client updates from Anna Schumaker:
 "New Features:
   - Better client responsiveness when server isn't replying
   - Use refcount_t in sunrpc rpc_client refcount tracking
   - Add srcaddr and dst_port to the sunrpc sysfs info files
   - Add basic support for connection sharing between servers with multiple NICs`

  Bugfixes and Cleanups:
   - Sunrpc tracepoint cleanups
   - Disconnect after ib_post_send() errors to avoid deadlocks
   - Fix for tearing down rpcrdma_reps
   - Fix a potential pNFS layoutget livelock loop
   - pNFS layout barrier fixes
   - Fix a potential memory corruption in rpc_wake_up_queued_task_set_status()
   - Fix reconnection locking
   - Fix return value of get_srcport()
   - Remove rpcrdma_post_sends()
   - Remove pNFS dead code
   - Remove copy size restriction for inter-server copies
   - Overhaul the NFS callback service
   - Clean up sunrpc TCP socket shutdowns
   - Always provide aligned buffers to RPC read layers"

* tag 'nfs-for-5.15-1' of git://git.linux-nfs.org/projects/anna/linux-nfs: (39 commits)
  NFS: Always provide aligned buffers to the RPC read layers
  NFSv4.1 add network transport when session trunking is detected
  SUNRPC enforce creation of no more than max_connect xprts
  NFSv4 introduce max_connect mount options
  SUNRPC add xps_nunique_destaddr_xprts to xprt_switch_info in sysfs
  SUNRPC keep track of number of transports to unique addresses
  NFSv3: Delete duplicate judgement in nfs3_async_handle_jukebox
  SUNRPC: Tweak TCP socket shutdown in the RPC client
  SUNRPC: Simplify socket shutdown when not reusing TCP ports
  NFSv4.2: remove restriction of copy size for inter-server copy.
  NFS: Clean up the synopsis of callback process_op()
  NFS: Extract the xdr_init_encode/decode() calls from decode_compound
  NFS: Remove unused callback void decoder
  NFS: Add a private local dispatcher for NFSv4 callback operations
  SUNRPC: Eliminate the RQ_AUTHERR flag
  SUNRPC: Set rq_auth_stat in the pg_authenticate() callout
  SUNRPC: Add svc_rqst::rq_auth_stat
  SUNRPC: Add dst_port to the sysfs xprt info file
  SUNRPC: Add srcaddr as a file in sysfs
  sunrpc: Fix return value of get_srcport()
  ...
parents f1583cb1 8cfb9015
...@@ -649,6 +649,7 @@ static int lockd_authenticate(struct svc_rqst *rqstp) ...@@ -649,6 +649,7 @@ static int lockd_authenticate(struct svc_rqst *rqstp)
switch (rqstp->rq_authop->flavour) { switch (rqstp->rq_authop->flavour) {
case RPC_AUTH_NULL: case RPC_AUTH_NULL:
case RPC_AUTH_UNIX: case RPC_AUTH_UNIX:
rqstp->rq_auth_stat = rpc_auth_ok;
if (rqstp->rq_proc == 0) if (rqstp->rq_proc == 0)
return SVC_OK; return SVC_OK;
if (is_callback(rqstp->rq_proc)) { if (is_callback(rqstp->rq_proc)) {
...@@ -659,6 +660,7 @@ static int lockd_authenticate(struct svc_rqst *rqstp) ...@@ -659,6 +660,7 @@ static int lockd_authenticate(struct svc_rqst *rqstp)
} }
return svc_set_client(rqstp); return svc_set_client(rqstp);
} }
rqstp->rq_auth_stat = rpc_autherr_badcred;
return SVC_DENIED; return SVC_DENIED;
} }
......
...@@ -429,6 +429,8 @@ check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp) ...@@ -429,6 +429,8 @@ check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp)
*/ */
static int nfs_callback_authenticate(struct svc_rqst *rqstp) static int nfs_callback_authenticate(struct svc_rqst *rqstp)
{ {
rqstp->rq_auth_stat = rpc_autherr_badcred;
switch (rqstp->rq_authop->flavour) { switch (rqstp->rq_authop->flavour) {
case RPC_AUTH_NULL: case RPC_AUTH_NULL:
if (rqstp->rq_proc != CB_NULL) if (rqstp->rq_proc != CB_NULL)
...@@ -439,6 +441,8 @@ static int nfs_callback_authenticate(struct svc_rqst *rqstp) ...@@ -439,6 +441,8 @@ static int nfs_callback_authenticate(struct svc_rqst *rqstp)
if (svc_is_backchannel(rqstp)) if (svc_is_backchannel(rqstp))
return SVC_DENIED; return SVC_DENIED;
} }
rqstp->rq_auth_stat = rpc_auth_ok;
return SVC_OK; return SVC_OK;
} }
......
...@@ -63,11 +63,10 @@ static __be32 nfs4_callback_null(struct svc_rqst *rqstp) ...@@ -63,11 +63,10 @@ static __be32 nfs4_callback_null(struct svc_rqst *rqstp)
return htonl(NFS4_OK); return htonl(NFS4_OK);
} }
static int nfs4_decode_void(struct svc_rqst *rqstp, __be32 *p) /*
{ * svc_process_common() looks for an XDR encoder to know when
return xdr_argsize_check(rqstp, p); * not to drop a Reply.
} */
static int nfs4_encode_void(struct svc_rqst *rqstp, __be32 *p) static int nfs4_encode_void(struct svc_rqst *rqstp, __be32 *p)
{ {
return xdr_ressize_check(rqstp, p); return xdr_ressize_check(rqstp, p);
...@@ -864,17 +863,16 @@ preprocess_nfs4_op(unsigned int op_nr, struct callback_op **op) ...@@ -864,17 +863,16 @@ preprocess_nfs4_op(unsigned int op_nr, struct callback_op **op)
} }
static __be32 process_op(int nop, struct svc_rqst *rqstp, static __be32 process_op(int nop, struct svc_rqst *rqstp,
struct xdr_stream *xdr_in, void *argp,
struct xdr_stream *xdr_out, void *resp,
struct cb_process_state *cps) struct cb_process_state *cps)
{ {
struct xdr_stream *xdr_out = &rqstp->rq_res_stream;
struct callback_op *op = &callback_ops[0]; struct callback_op *op = &callback_ops[0];
unsigned int op_nr; unsigned int op_nr;
__be32 status; __be32 status;
long maxlen; long maxlen;
__be32 res; __be32 res;
status = decode_op_hdr(xdr_in, &op_nr); status = decode_op_hdr(&rqstp->rq_arg_stream, &op_nr);
if (unlikely(status)) if (unlikely(status))
return status; return status;
...@@ -904,9 +902,11 @@ static __be32 process_op(int nop, struct svc_rqst *rqstp, ...@@ -904,9 +902,11 @@ static __be32 process_op(int nop, struct svc_rqst *rqstp,
maxlen = xdr_out->end - xdr_out->p; maxlen = xdr_out->end - xdr_out->p;
if (maxlen > 0 && maxlen < PAGE_SIZE) { if (maxlen > 0 && maxlen < PAGE_SIZE) {
status = op->decode_args(rqstp, xdr_in, argp); status = op->decode_args(rqstp, &rqstp->rq_arg_stream,
rqstp->rq_argp);
if (likely(status == 0)) if (likely(status == 0))
status = op->process_op(argp, resp, cps); status = op->process_op(rqstp->rq_argp, rqstp->rq_resp,
cps);
} else } else
status = htonl(NFS4ERR_RESOURCE); status = htonl(NFS4ERR_RESOURCE);
...@@ -915,7 +915,7 @@ static __be32 process_op(int nop, struct svc_rqst *rqstp, ...@@ -915,7 +915,7 @@ static __be32 process_op(int nop, struct svc_rqst *rqstp,
if (unlikely(res)) if (unlikely(res))
return res; return res;
if (op->encode_res != NULL && status == 0) if (op->encode_res != NULL && status == 0)
status = op->encode_res(rqstp, xdr_out, resp); status = op->encode_res(rqstp, xdr_out, rqstp->rq_resp);
return status; return status;
} }
...@@ -926,22 +926,15 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp) ...@@ -926,22 +926,15 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp)
{ {
struct cb_compound_hdr_arg hdr_arg = { 0 }; struct cb_compound_hdr_arg hdr_arg = { 0 };
struct cb_compound_hdr_res hdr_res = { NULL }; struct cb_compound_hdr_res hdr_res = { NULL };
struct xdr_stream xdr_in, xdr_out;
__be32 *p, status;
struct cb_process_state cps = { struct cb_process_state cps = {
.drc_status = 0, .drc_status = 0,
.clp = NULL, .clp = NULL,
.net = SVC_NET(rqstp), .net = SVC_NET(rqstp),
}; };
unsigned int nops = 0; unsigned int nops = 0;
__be32 status;
xdr_init_decode(&xdr_in, &rqstp->rq_arg, status = decode_compound_hdr_arg(&rqstp->rq_arg_stream, &hdr_arg);
rqstp->rq_arg.head[0].iov_base, NULL);
p = (__be32*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len);
xdr_init_encode(&xdr_out, &rqstp->rq_res, p, NULL);
status = decode_compound_hdr_arg(&xdr_in, &hdr_arg);
if (status == htonl(NFS4ERR_RESOURCE)) if (status == htonl(NFS4ERR_RESOURCE))
return rpc_garbage_args; return rpc_garbage_args;
...@@ -961,15 +954,13 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp) ...@@ -961,15 +954,13 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp)
cps.minorversion = hdr_arg.minorversion; cps.minorversion = hdr_arg.minorversion;
hdr_res.taglen = hdr_arg.taglen; hdr_res.taglen = hdr_arg.taglen;
hdr_res.tag = hdr_arg.tag; hdr_res.tag = hdr_arg.tag;
if (encode_compound_hdr_res(&xdr_out, &hdr_res) != 0) { if (encode_compound_hdr_res(&rqstp->rq_res_stream, &hdr_res) != 0) {
if (cps.clp) if (cps.clp)
nfs_put_client(cps.clp); nfs_put_client(cps.clp);
return rpc_system_err; return rpc_system_err;
} }
while (status == 0 && nops != hdr_arg.nops) { while (status == 0 && nops != hdr_arg.nops) {
status = process_op(nops, rqstp, &xdr_in, status = process_op(nops, rqstp, &cps);
rqstp->rq_argp, &xdr_out, rqstp->rq_resp,
&cps);
nops++; nops++;
} }
...@@ -988,7 +979,20 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp) ...@@ -988,7 +979,20 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp)
out_invalidcred: out_invalidcred:
pr_warn_ratelimited("NFS: NFSv4 callback contains invalid cred\n"); pr_warn_ratelimited("NFS: NFSv4 callback contains invalid cred\n");
return svc_return_autherr(rqstp, rpc_autherr_badcred); rqstp->rq_auth_stat = rpc_autherr_badcred;
return rpc_success;
}
static int
nfs_callback_dispatch(struct svc_rqst *rqstp, __be32 *statp)
{
const struct svc_procedure *procp = rqstp->rq_procinfo;
svcxdr_init_decode(rqstp);
svcxdr_init_encode(rqstp);
*statp = procp->pc_func(rqstp);
return 1;
} }
/* /*
...@@ -1057,7 +1061,6 @@ static struct callback_op callback_ops[] = { ...@@ -1057,7 +1061,6 @@ static struct callback_op callback_ops[] = {
static const struct svc_procedure nfs4_callback_procedures1[] = { static const struct svc_procedure nfs4_callback_procedures1[] = {
[CB_NULL] = { [CB_NULL] = {
.pc_func = nfs4_callback_null, .pc_func = nfs4_callback_null,
.pc_decode = nfs4_decode_void,
.pc_encode = nfs4_encode_void, .pc_encode = nfs4_encode_void,
.pc_xdrressize = 1, .pc_xdrressize = 1,
.pc_name = "NULL", .pc_name = "NULL",
...@@ -1079,7 +1082,7 @@ const struct svc_version nfs4_callback_version1 = { ...@@ -1079,7 +1082,7 @@ const struct svc_version nfs4_callback_version1 = {
.vs_proc = nfs4_callback_procedures1, .vs_proc = nfs4_callback_procedures1,
.vs_count = nfs4_callback_count1, .vs_count = nfs4_callback_count1,
.vs_xdrsize = NFS4_CALLBACK_XDRSIZE, .vs_xdrsize = NFS4_CALLBACK_XDRSIZE,
.vs_dispatch = NULL, .vs_dispatch = nfs_callback_dispatch,
.vs_hidden = true, .vs_hidden = true,
.vs_need_cong_ctrl = true, .vs_need_cong_ctrl = true,
}; };
...@@ -1091,7 +1094,7 @@ const struct svc_version nfs4_callback_version4 = { ...@@ -1091,7 +1094,7 @@ const struct svc_version nfs4_callback_version4 = {
.vs_proc = nfs4_callback_procedures1, .vs_proc = nfs4_callback_procedures1,
.vs_count = nfs4_callback_count4, .vs_count = nfs4_callback_count4,
.vs_xdrsize = NFS4_CALLBACK_XDRSIZE, .vs_xdrsize = NFS4_CALLBACK_XDRSIZE,
.vs_dispatch = NULL, .vs_dispatch = nfs_callback_dispatch,
.vs_hidden = true, .vs_hidden = true,
.vs_need_cong_ctrl = true, .vs_need_cong_ctrl = true,
}; };
...@@ -179,6 +179,7 @@ struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init) ...@@ -179,6 +179,7 @@ struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init)
clp->cl_proto = cl_init->proto; clp->cl_proto = cl_init->proto;
clp->cl_nconnect = cl_init->nconnect; clp->cl_nconnect = cl_init->nconnect;
clp->cl_max_connect = cl_init->max_connect ? cl_init->max_connect : 1;
clp->cl_net = get_net(cl_init->net); clp->cl_net = get_net(cl_init->net);
clp->cl_principal = "*"; clp->cl_principal = "*";
...@@ -540,6 +541,7 @@ int nfs_create_rpc_client(struct nfs_client *clp, ...@@ -540,6 +541,7 @@ int nfs_create_rpc_client(struct nfs_client *clp,
clnt->cl_principal = clp->cl_principal; clnt->cl_principal = clp->cl_principal;
clp->cl_rpcclient = clnt; clp->cl_rpcclient = clnt;
clnt->cl_max_connect = clp->cl_max_connect;
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(nfs_create_rpc_client); EXPORT_SYMBOL_GPL(nfs_create_rpc_client);
......
...@@ -60,6 +60,7 @@ enum nfs_param { ...@@ -60,6 +60,7 @@ enum nfs_param {
Opt_mountvers, Opt_mountvers,
Opt_namelen, Opt_namelen,
Opt_nconnect, Opt_nconnect,
Opt_max_connect,
Opt_port, Opt_port,
Opt_posix, Opt_posix,
Opt_proto, Opt_proto,
...@@ -158,6 +159,7 @@ static const struct fs_parameter_spec nfs_fs_parameters[] = { ...@@ -158,6 +159,7 @@ static const struct fs_parameter_spec nfs_fs_parameters[] = {
fsparam_u32 ("mountvers", Opt_mountvers), fsparam_u32 ("mountvers", Opt_mountvers),
fsparam_u32 ("namlen", Opt_namelen), fsparam_u32 ("namlen", Opt_namelen),
fsparam_u32 ("nconnect", Opt_nconnect), fsparam_u32 ("nconnect", Opt_nconnect),
fsparam_u32 ("max_connect", Opt_max_connect),
fsparam_string("nfsvers", Opt_vers), fsparam_string("nfsvers", Opt_vers),
fsparam_u32 ("port", Opt_port), fsparam_u32 ("port", Opt_port),
fsparam_flag_no("posix", Opt_posix), fsparam_flag_no("posix", Opt_posix),
...@@ -770,6 +772,11 @@ static int nfs_fs_context_parse_param(struct fs_context *fc, ...@@ -770,6 +772,11 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
goto out_of_bounds; goto out_of_bounds;
ctx->nfs_server.nconnect = result.uint_32; ctx->nfs_server.nconnect = result.uint_32;
break; break;
case Opt_max_connect:
if (result.uint_32 < 1 || result.uint_32 > NFS_MAX_TRANSPORTS)
goto out_of_bounds;
ctx->nfs_server.max_connect = result.uint_32;
break;
case Opt_lookupcache: case Opt_lookupcache:
switch (result.uint_32) { switch (result.uint_32) {
case Opt_lookupcache_all: case Opt_lookupcache_all:
......
...@@ -67,6 +67,7 @@ struct nfs_client_initdata { ...@@ -67,6 +67,7 @@ struct nfs_client_initdata {
int proto; int proto;
u32 minorversion; u32 minorversion;
unsigned int nconnect; unsigned int nconnect;
unsigned int max_connect;
struct net *net; struct net *net;
const struct rpc_timeout *timeparms; const struct rpc_timeout *timeparms;
const struct cred *cred; const struct cred *cred;
...@@ -121,6 +122,7 @@ struct nfs_fs_context { ...@@ -121,6 +122,7 @@ struct nfs_fs_context {
int port; int port;
unsigned short protocol; unsigned short protocol;
unsigned short nconnect; unsigned short nconnect;
unsigned short max_connect;
unsigned short export_path_len; unsigned short export_path_len;
} nfs_server; } nfs_server;
......
...@@ -49,7 +49,6 @@ nfs3_async_handle_jukebox(struct rpc_task *task, struct inode *inode) ...@@ -49,7 +49,6 @@ nfs3_async_handle_jukebox(struct rpc_task *task, struct inode *inode)
{ {
if (task->tk_status != -EJUKEBOX) if (task->tk_status != -EJUKEBOX)
return 0; return 0;
if (task->tk_status == -EJUKEBOX)
nfs_inc_stats(inode, NFSIOS_DELAY); nfs_inc_stats(inode, NFSIOS_DELAY);
task->tk_status = 0; task->tk_status = 0;
rpc_restart_call(task); rpc_restart_call(task);
......
...@@ -402,6 +402,33 @@ static int nfs4_init_client_minor_version(struct nfs_client *clp) ...@@ -402,6 +402,33 @@ static int nfs4_init_client_minor_version(struct nfs_client *clp)
return nfs4_init_callback(clp); return nfs4_init_callback(clp);
} }
static void nfs4_add_trunk(struct nfs_client *clp, struct nfs_client *old)
{
struct sockaddr_storage clp_addr, old_addr;
struct sockaddr *clp_sap = (struct sockaddr *)&clp_addr;
struct sockaddr *old_sap = (struct sockaddr *)&old_addr;
size_t clp_salen;
struct xprt_create xprt_args = {
.ident = old->cl_proto,
.net = old->cl_net,
.servername = old->cl_hostname,
};
if (clp->cl_proto != old->cl_proto)
return;
clp_salen = rpc_peeraddr(clp->cl_rpcclient, clp_sap, sizeof(clp_addr));
rpc_peeraddr(old->cl_rpcclient, old_sap, sizeof(old_addr));
if (clp_addr.ss_family != old_addr.ss_family)
return;
xprt_args.dstaddr = clp_sap;
xprt_args.addrlen = clp_salen;
rpc_clnt_add_xprt(old->cl_rpcclient, &xprt_args,
rpc_clnt_test_and_add_xprt, NULL);
}
/** /**
* nfs4_init_client - Initialise an NFS4 client record * nfs4_init_client - Initialise an NFS4 client record
* *
...@@ -436,6 +463,8 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp, ...@@ -436,6 +463,8 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,
* won't try to use it. * won't try to use it.
*/ */
nfs_mark_client_ready(clp, -EPERM); nfs_mark_client_ready(clp, -EPERM);
if (old->cl_mvops->session_trunk)
nfs4_add_trunk(clp, old);
} }
clear_bit(NFS_CS_TSM_POSSIBLE, &clp->cl_flags); clear_bit(NFS_CS_TSM_POSSIBLE, &clp->cl_flags);
nfs_put_client(clp); nfs_put_client(clp);
...@@ -865,6 +894,7 @@ static int nfs4_set_client(struct nfs_server *server, ...@@ -865,6 +894,7 @@ static int nfs4_set_client(struct nfs_server *server,
const char *ip_addr, const char *ip_addr,
int proto, const struct rpc_timeout *timeparms, int proto, const struct rpc_timeout *timeparms,
u32 minorversion, unsigned int nconnect, u32 minorversion, unsigned int nconnect,
unsigned int max_connect,
struct net *net) struct net *net)
{ {
struct nfs_client_initdata cl_init = { struct nfs_client_initdata cl_init = {
...@@ -883,6 +913,8 @@ static int nfs4_set_client(struct nfs_server *server, ...@@ -883,6 +913,8 @@ static int nfs4_set_client(struct nfs_server *server,
if (minorversion == 0) if (minorversion == 0)
__set_bit(NFS_CS_REUSEPORT, &cl_init.init_flags); __set_bit(NFS_CS_REUSEPORT, &cl_init.init_flags);
else
cl_init.max_connect = max_connect;
if (proto == XPRT_TRANSPORT_TCP) if (proto == XPRT_TRANSPORT_TCP)
cl_init.nconnect = nconnect; cl_init.nconnect = nconnect;
...@@ -952,8 +984,10 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_server *mds_srv, ...@@ -952,8 +984,10 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_server *mds_srv,
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
cl_init.hostname = buf; cl_init.hostname = buf;
if (mds_clp->cl_nconnect > 1 && ds_proto == XPRT_TRANSPORT_TCP) if (mds_clp->cl_nconnect > 1 && ds_proto == XPRT_TRANSPORT_TCP) {
cl_init.nconnect = mds_clp->cl_nconnect; cl_init.nconnect = mds_clp->cl_nconnect;
cl_init.max_connect = NFS_MAX_TRANSPORTS;
}
if (mds_srv->flags & NFS_MOUNT_NORESVPORT) if (mds_srv->flags & NFS_MOUNT_NORESVPORT)
__set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags); __set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
...@@ -1122,6 +1156,7 @@ static int nfs4_init_server(struct nfs_server *server, struct fs_context *fc) ...@@ -1122,6 +1156,7 @@ static int nfs4_init_server(struct nfs_server *server, struct fs_context *fc)
&timeparms, &timeparms,
ctx->minorversion, ctx->minorversion,
ctx->nfs_server.nconnect, ctx->nfs_server.nconnect,
ctx->nfs_server.max_connect,
fc->net_ns); fc->net_ns);
if (error < 0) if (error < 0)
return error; return error;
...@@ -1211,6 +1246,7 @@ struct nfs_server *nfs4_create_referral_server(struct fs_context *fc) ...@@ -1211,6 +1246,7 @@ struct nfs_server *nfs4_create_referral_server(struct fs_context *fc)
parent_server->client->cl_timeout, parent_server->client->cl_timeout,
parent_client->cl_mvops->minor_version, parent_client->cl_mvops->minor_version,
parent_client->cl_nconnect, parent_client->cl_nconnect,
parent_client->cl_max_connect,
parent_client->cl_net); parent_client->cl_net);
if (!error) if (!error)
goto init_server; goto init_server;
...@@ -1226,6 +1262,7 @@ struct nfs_server *nfs4_create_referral_server(struct fs_context *fc) ...@@ -1226,6 +1262,7 @@ struct nfs_server *nfs4_create_referral_server(struct fs_context *fc)
parent_server->client->cl_timeout, parent_server->client->cl_timeout,
parent_client->cl_mvops->minor_version, parent_client->cl_mvops->minor_version,
parent_client->cl_nconnect, parent_client->cl_nconnect,
parent_client->cl_max_connect,
parent_client->cl_net); parent_client->cl_net);
if (error < 0) if (error < 0)
goto error; goto error;
...@@ -1323,7 +1360,7 @@ int nfs4_update_server(struct nfs_server *server, const char *hostname, ...@@ -1323,7 +1360,7 @@ int nfs4_update_server(struct nfs_server *server, const char *hostname,
error = nfs4_set_client(server, hostname, sap, salen, buf, error = nfs4_set_client(server, hostname, sap, salen, buf,
clp->cl_proto, clnt->cl_timeout, clp->cl_proto, clnt->cl_timeout,
clp->cl_minorversion, clp->cl_minorversion,
clp->cl_nconnect, net); clp->cl_nconnect, clp->cl_max_connect, net);
clear_bit(NFS_MIG_TSM_POSSIBLE, &server->mig_status); clear_bit(NFS_MIG_TSM_POSSIBLE, &server->mig_status);
if (error != 0) { if (error != 0) {
nfs_server_insert_lists(server); nfs_server_insert_lists(server);
......
...@@ -158,13 +158,11 @@ static ssize_t __nfs4_copy_file_range(struct file *file_in, loff_t pos_in, ...@@ -158,13 +158,11 @@ static ssize_t __nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
sync = true; sync = true;
retry: retry:
if (!nfs42_files_from_same_server(file_in, file_out)) { if (!nfs42_files_from_same_server(file_in, file_out)) {
/* for inter copy, if copy size if smaller than 12 RPC /*
* payloads, fallback to traditional copy. There are * for inter copy, if copy size is too small
* 14 RPCs during an NFSv4.x mount between source/dest * then fallback to generic copy.
* servers.
*/ */
if (sync || if (sync)
count <= 14 * NFS_SERVER(file_inode(file_in))->rsize)
return -EOPNOTSUPP; return -EOPNOTSUPP;
cn_resp = kzalloc(sizeof(struct nfs42_copy_notify_res), cn_resp = kzalloc(sizeof(struct nfs42_copy_notify_res),
GFP_NOFS); GFP_NOFS);
......
...@@ -335,7 +335,7 @@ static bool pnfs_seqid_is_newer(u32 s1, u32 s2) ...@@ -335,7 +335,7 @@ static bool pnfs_seqid_is_newer(u32 s1, u32 s2)
static void pnfs_barrier_update(struct pnfs_layout_hdr *lo, u32 newseq) static void pnfs_barrier_update(struct pnfs_layout_hdr *lo, u32 newseq)
{ {
if (pnfs_seqid_is_newer(newseq, lo->plh_barrier)) if (pnfs_seqid_is_newer(newseq, lo->plh_barrier) || !lo->plh_barrier)
lo->plh_barrier = newseq; lo->plh_barrier = newseq;
} }
...@@ -347,11 +347,15 @@ pnfs_set_plh_return_info(struct pnfs_layout_hdr *lo, enum pnfs_iomode iomode, ...@@ -347,11 +347,15 @@ pnfs_set_plh_return_info(struct pnfs_layout_hdr *lo, enum pnfs_iomode iomode,
iomode = IOMODE_ANY; iomode = IOMODE_ANY;
lo->plh_return_iomode = iomode; lo->plh_return_iomode = iomode;
set_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags); set_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags);
if (seq != 0) { /*
WARN_ON_ONCE(lo->plh_return_seq != 0 && lo->plh_return_seq != seq); * We must set lo->plh_return_seq to avoid livelocks with
* pnfs_layout_need_return()
*/
if (seq == 0)
seq = be32_to_cpu(lo->plh_stateid.seqid);
if (!lo->plh_return_seq || pnfs_seqid_is_newer(seq, lo->plh_return_seq))
lo->plh_return_seq = seq; lo->plh_return_seq = seq;
pnfs_barrier_update(lo, seq); pnfs_barrier_update(lo, seq);
}
} }
static void static void
...@@ -592,10 +596,6 @@ pnfs_put_lseg(struct pnfs_layout_segment *lseg) ...@@ -592,10 +596,6 @@ pnfs_put_lseg(struct pnfs_layout_segment *lseg)
inode = lo->plh_inode; inode = lo->plh_inode;
if (refcount_dec_and_lock(&lseg->pls_refcount, &inode->i_lock)) { if (refcount_dec_and_lock(&lseg->pls_refcount, &inode->i_lock)) {
if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags)) {
spin_unlock(&inode->i_lock);
return;
}
pnfs_get_layout_hdr(lo); pnfs_get_layout_hdr(lo);
pnfs_layout_remove_lseg(lo, lseg); pnfs_layout_remove_lseg(lo, lseg);
if (pnfs_cache_lseg_for_layoutreturn(lo, lseg)) if (pnfs_cache_lseg_for_layoutreturn(lo, lseg))
...@@ -1000,7 +1000,7 @@ pnfs_layout_stateid_blocked(const struct pnfs_layout_hdr *lo, ...@@ -1000,7 +1000,7 @@ pnfs_layout_stateid_blocked(const struct pnfs_layout_hdr *lo,
{ {
u32 seqid = be32_to_cpu(stateid->seqid); u32 seqid = be32_to_cpu(stateid->seqid);
return !pnfs_seqid_is_newer(seqid, lo->plh_barrier) && lo->plh_barrier; return lo->plh_barrier && pnfs_seqid_is_newer(lo->plh_barrier, seqid);
} }
/* lget is set to 1 if called from inside send_layoutget call chain */ /* lget is set to 1 if called from inside send_layoutget call chain */
......
...@@ -293,15 +293,19 @@ static int ...@@ -293,15 +293,19 @@ static int
readpage_async_filler(void *data, struct page *page) readpage_async_filler(void *data, struct page *page)
{ {
struct nfs_readdesc *desc = data; struct nfs_readdesc *desc = data;
struct inode *inode = page_file_mapping(page)->host;
unsigned int rsize = NFS_SERVER(inode)->rsize;
struct nfs_page *new; struct nfs_page *new;
unsigned int len; unsigned int len, aligned_len;
int error; int error;
len = nfs_page_length(page); len = nfs_page_length(page);
if (len == 0) if (len == 0)
return nfs_return_empty_page(page); return nfs_return_empty_page(page);
new = nfs_create_request(desc->ctx, page, 0, len); aligned_len = min_t(unsigned int, ALIGN(len, rsize), PAGE_SIZE);
new = nfs_create_request(desc->ctx, page, 0, aligned_len);
if (IS_ERR(new)) if (IS_ERR(new))
goto out_error; goto out_error;
......
...@@ -480,6 +480,8 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, ...@@ -480,6 +480,8 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
if (clp->cl_nconnect > 0) if (clp->cl_nconnect > 0)
seq_printf(m, ",nconnect=%u", clp->cl_nconnect); seq_printf(m, ",nconnect=%u", clp->cl_nconnect);
if (version == 4) { if (version == 4) {
if (clp->cl_max_connect > 1)
seq_printf(m, ",max_connect=%u", clp->cl_max_connect);
if (nfss->port != NFS_PORT) if (nfss->port != NFS_PORT)
seq_printf(m, ",port=%u", nfss->port); seq_printf(m, ",port=%u", nfss->port);
} else } else
......
...@@ -40,6 +40,11 @@ ...@@ -40,6 +40,11 @@
#include <linux/mempool.h> #include <linux/mempool.h>
/*
* These are the default for number of transports to different server IPs
*/
#define NFS_MAX_TRANSPORTS 16
/* /*
* These are the default flags for swap requests * These are the default flags for swap requests
*/ */
......
...@@ -62,6 +62,7 @@ struct nfs_client { ...@@ -62,6 +62,7 @@ struct nfs_client {
u32 cl_minorversion;/* NFSv4 minorversion */ u32 cl_minorversion;/* NFSv4 minorversion */
unsigned int cl_nconnect; /* Number of connections */ unsigned int cl_nconnect; /* Number of connections */
unsigned int cl_max_connect; /* max number of xprts allowed */
const char * cl_principal; /* used for machine cred */ const char * cl_principal; /* used for machine cred */
#if IS_ENABLED(CONFIG_NFS_V4) #if IS_ENABLED(CONFIG_NFS_V4)
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/socket.h> #include <linux/socket.h>
#include <linux/in.h> #include <linux/in.h>
#include <linux/in6.h> #include <linux/in6.h>
#include <linux/refcount.h>
#include <linux/sunrpc/msg_prot.h> #include <linux/sunrpc/msg_prot.h>
#include <linux/sunrpc/sched.h> #include <linux/sunrpc/sched.h>
...@@ -35,7 +36,7 @@ struct rpc_sysfs_client; ...@@ -35,7 +36,7 @@ struct rpc_sysfs_client;
* The high-level client handle * The high-level client handle
*/ */
struct rpc_clnt { struct rpc_clnt {
atomic_t cl_count; /* Number of references */ refcount_t cl_count; /* Number of references */
unsigned int cl_clid; /* client id */ unsigned int cl_clid; /* client id */
struct list_head cl_clients; /* Global list of clients */ struct list_head cl_clients; /* Global list of clients */
struct list_head cl_tasks; /* List of tasks */ struct list_head cl_tasks; /* List of tasks */
...@@ -81,6 +82,7 @@ struct rpc_clnt { ...@@ -81,6 +82,7 @@ struct rpc_clnt {
struct work_struct cl_work; struct work_struct cl_work;
}; };
const struct cred *cl_cred; const struct cred *cl_cred;
unsigned int cl_max_connect; /* max number of transports not to the same IP */
}; };
/* /*
...@@ -135,6 +137,7 @@ struct rpc_create_args { ...@@ -135,6 +137,7 @@ struct rpc_create_args {
char *client_name; char *client_name;
struct svc_xprt *bc_xprt; /* NFSv4.1 backchannel */ struct svc_xprt *bc_xprt; /* NFSv4.1 backchannel */
const struct cred *cred; const struct cred *cred;
unsigned int max_connect;
}; };
struct rpc_add_xprt_test { struct rpc_add_xprt_test {
......
...@@ -277,13 +277,13 @@ struct svc_rqst { ...@@ -277,13 +277,13 @@ struct svc_rqst {
#define RQ_VICTIM (5) /* about to be shut down */ #define RQ_VICTIM (5) /* about to be shut down */
#define RQ_BUSY (6) /* request is busy */ #define RQ_BUSY (6) /* request is busy */
#define RQ_DATA (7) /* request has data */ #define RQ_DATA (7) /* request has data */
#define RQ_AUTHERR (8) /* Request status is auth error */
unsigned long rq_flags; /* flags field */ unsigned long rq_flags; /* flags field */
ktime_t rq_qtime; /* enqueue time */ ktime_t rq_qtime; /* enqueue time */
void * rq_argp; /* decoded arguments */ void * rq_argp; /* decoded arguments */
void * rq_resp; /* xdr'd results */ void * rq_resp; /* xdr'd results */
void * rq_auth_data; /* flavor-specific data */ void * rq_auth_data; /* flavor-specific data */
__be32 rq_auth_stat; /* authentication status */
int rq_auth_slack; /* extra space xdr code int rq_auth_slack; /* extra space xdr code
* should leave in head * should leave in head
* for krb5i, krb5p. * for krb5i, krb5p.
...@@ -537,7 +537,6 @@ unsigned int svc_fill_write_vector(struct svc_rqst *rqstp, ...@@ -537,7 +537,6 @@ unsigned int svc_fill_write_vector(struct svc_rqst *rqstp,
char *svc_fill_symlink_pathname(struct svc_rqst *rqstp, char *svc_fill_symlink_pathname(struct svc_rqst *rqstp,
struct kvec *first, void *p, struct kvec *first, void *p,
size_t total); size_t total);
__be32 svc_return_autherr(struct svc_rqst *rqstp, __be32 auth_err);
__be32 svc_generic_init_request(struct svc_rqst *rqstp, __be32 svc_generic_init_request(struct svc_rqst *rqstp,
const struct svc_program *progp, const struct svc_program *progp,
struct svc_process_info *procinfo); struct svc_process_info *procinfo);
......
...@@ -127,7 +127,7 @@ struct auth_ops { ...@@ -127,7 +127,7 @@ struct auth_ops {
char * name; char * name;
struct module *owner; struct module *owner;
int flavour; int flavour;
int (*accept)(struct svc_rqst *rq, __be32 *authp); int (*accept)(struct svc_rqst *rq);
int (*release)(struct svc_rqst *rq); int (*release)(struct svc_rqst *rq);
void (*domain_release)(struct auth_domain *); void (*domain_release)(struct auth_domain *);
int (*set_client)(struct svc_rqst *rq); int (*set_client)(struct svc_rqst *rq);
...@@ -149,7 +149,7 @@ struct auth_ops { ...@@ -149,7 +149,7 @@ struct auth_ops {
struct svc_xprt; struct svc_xprt;
extern int svc_authenticate(struct svc_rqst *rqstp, __be32 *authp); extern int svc_authenticate(struct svc_rqst *rqstp);
extern int svc_authorise(struct svc_rqst *rqstp); extern int svc_authorise(struct svc_rqst *rqstp);
extern int svc_set_client(struct svc_rqst *rqstp); extern int svc_set_client(struct svc_rqst *rqstp);
extern int svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops); extern int svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops);
......
...@@ -431,6 +431,7 @@ void xprt_release_write(struct rpc_xprt *, struct rpc_task *); ...@@ -431,6 +431,7 @@ void xprt_release_write(struct rpc_xprt *, struct rpc_task *);
#define XPRT_CONGESTED (9) #define XPRT_CONGESTED (9)
#define XPRT_CWND_WAIT (10) #define XPRT_CWND_WAIT (10)
#define XPRT_WRITE_SPACE (11) #define XPRT_WRITE_SPACE (11)
#define XPRT_SND_IS_COOKIE (12)
static inline void xprt_set_connected(struct rpc_xprt *xprt) static inline void xprt_set_connected(struct rpc_xprt *xprt)
{ {
......
...@@ -18,6 +18,7 @@ struct rpc_xprt_switch { ...@@ -18,6 +18,7 @@ struct rpc_xprt_switch {
unsigned int xps_id; unsigned int xps_id;
unsigned int xps_nxprts; unsigned int xps_nxprts;
unsigned int xps_nactive; unsigned int xps_nactive;
unsigned int xps_nunique_destaddr_xprts;
atomic_long_t xps_queuelen; atomic_long_t xps_queuelen;
struct list_head xps_xprt_list; struct list_head xps_xprt_list;
......
...@@ -793,6 +793,39 @@ TRACE_EVENT(xprtrdma_post_send, ...@@ -793,6 +793,39 @@ TRACE_EVENT(xprtrdma_post_send,
) )
); );
TRACE_EVENT(xprtrdma_post_send_err,
TP_PROTO(
const struct rpcrdma_xprt *r_xprt,
const struct rpcrdma_req *req,
int rc
),
TP_ARGS(r_xprt, req, rc),
TP_STRUCT__entry(
__field(u32, cq_id)
__field(unsigned int, task_id)
__field(unsigned int, client_id)
__field(int, rc)
),
TP_fast_assign(
const struct rpc_rqst *rqst = &req->rl_slot;
const struct rpcrdma_ep *ep = r_xprt->rx_ep;
__entry->cq_id = ep ? ep->re_attr.recv_cq->res.id : 0;
__entry->task_id = rqst->rq_task->tk_pid;
__entry->client_id = rqst->rq_task->tk_client ?
rqst->rq_task->tk_client->cl_clid : -1;
__entry->rc = rc;
),
TP_printk("task:%u@%u cq.id=%u rc=%d",
__entry->task_id, __entry->client_id,
__entry->cq_id, __entry->rc
)
);
TRACE_EVENT(xprtrdma_post_recv, TRACE_EVENT(xprtrdma_post_recv,
TP_PROTO( TP_PROTO(
const struct rpcrdma_rep *rep const struct rpcrdma_rep *rep
...@@ -818,16 +851,14 @@ TRACE_EVENT(xprtrdma_post_recv, ...@@ -818,16 +851,14 @@ TRACE_EVENT(xprtrdma_post_recv,
TRACE_EVENT(xprtrdma_post_recvs, TRACE_EVENT(xprtrdma_post_recvs,
TP_PROTO( TP_PROTO(
const struct rpcrdma_xprt *r_xprt, const struct rpcrdma_xprt *r_xprt,
unsigned int count, unsigned int count
int status
), ),
TP_ARGS(r_xprt, count, status), TP_ARGS(r_xprt, count),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(u32, cq_id) __field(u32, cq_id)
__field(unsigned int, count) __field(unsigned int, count)
__field(int, status)
__field(int, posted) __field(int, posted)
__string(addr, rpcrdma_addrstr(r_xprt)) __string(addr, rpcrdma_addrstr(r_xprt))
__string(port, rpcrdma_portstr(r_xprt)) __string(port, rpcrdma_portstr(r_xprt))
...@@ -838,15 +869,44 @@ TRACE_EVENT(xprtrdma_post_recvs, ...@@ -838,15 +869,44 @@ TRACE_EVENT(xprtrdma_post_recvs,
__entry->cq_id = ep->re_attr.recv_cq->res.id; __entry->cq_id = ep->re_attr.recv_cq->res.id;
__entry->count = count; __entry->count = count;
__entry->status = status;
__entry->posted = ep->re_receive_count; __entry->posted = ep->re_receive_count;
__assign_str(addr, rpcrdma_addrstr(r_xprt)); __assign_str(addr, rpcrdma_addrstr(r_xprt));
__assign_str(port, rpcrdma_portstr(r_xprt)); __assign_str(port, rpcrdma_portstr(r_xprt));
), ),
TP_printk("peer=[%s]:%s cq.id=%d %u new recvs, %d active (rc %d)", TP_printk("peer=[%s]:%s cq.id=%d %u new recvs, %d active",
__get_str(addr), __get_str(port), __entry->cq_id,
__entry->count, __entry->posted
)
);
TRACE_EVENT(xprtrdma_post_recvs_err,
TP_PROTO(
const struct rpcrdma_xprt *r_xprt,
int status
),
TP_ARGS(r_xprt, status),
TP_STRUCT__entry(
__field(u32, cq_id)
__field(int, status)
__string(addr, rpcrdma_addrstr(r_xprt))
__string(port, rpcrdma_portstr(r_xprt))
),
TP_fast_assign(
const struct rpcrdma_ep *ep = r_xprt->rx_ep;
__entry->cq_id = ep->re_attr.recv_cq->res.id;
__entry->status = status;
__assign_str(addr, rpcrdma_addrstr(r_xprt));
__assign_str(port, rpcrdma_portstr(r_xprt));
),
TP_printk("peer=[%s]:%s cq.id=%d rc=%d",
__get_str(addr), __get_str(port), __entry->cq_id, __get_str(addr), __get_str(port), __entry->cq_id,
__entry->count, __entry->posted, __entry->status __entry->status
) )
); );
......
...@@ -295,25 +295,11 @@ TRACE_EVENT(rpc_request, ...@@ -295,25 +295,11 @@ TRACE_EVENT(rpc_request,
) )
); );
TRACE_DEFINE_ENUM(RPC_TASK_ASYNC);
TRACE_DEFINE_ENUM(RPC_TASK_SWAPPER);
TRACE_DEFINE_ENUM(RPC_TASK_NULLCREDS);
TRACE_DEFINE_ENUM(RPC_CALL_MAJORSEEN);
TRACE_DEFINE_ENUM(RPC_TASK_ROOTCREDS);
TRACE_DEFINE_ENUM(RPC_TASK_DYNAMIC);
TRACE_DEFINE_ENUM(RPC_TASK_NO_ROUND_ROBIN);
TRACE_DEFINE_ENUM(RPC_TASK_SOFT);
TRACE_DEFINE_ENUM(RPC_TASK_SOFTCONN);
TRACE_DEFINE_ENUM(RPC_TASK_SENT);
TRACE_DEFINE_ENUM(RPC_TASK_TIMEOUT);
TRACE_DEFINE_ENUM(RPC_TASK_NOCONNECT);
TRACE_DEFINE_ENUM(RPC_TASK_NO_RETRANS_TIMEOUT);
TRACE_DEFINE_ENUM(RPC_TASK_CRED_NOREF);
#define rpc_show_task_flags(flags) \ #define rpc_show_task_flags(flags) \
__print_flags(flags, "|", \ __print_flags(flags, "|", \
{ RPC_TASK_ASYNC, "ASYNC" }, \ { RPC_TASK_ASYNC, "ASYNC" }, \
{ RPC_TASK_SWAPPER, "SWAPPER" }, \ { RPC_TASK_SWAPPER, "SWAPPER" }, \
{ RPC_TASK_MOVEABLE, "MOVEABLE" }, \
{ RPC_TASK_NULLCREDS, "NULLCREDS" }, \ { RPC_TASK_NULLCREDS, "NULLCREDS" }, \
{ RPC_CALL_MAJORSEEN, "MAJORSEEN" }, \ { RPC_CALL_MAJORSEEN, "MAJORSEEN" }, \
{ RPC_TASK_ROOTCREDS, "ROOTCREDS" }, \ { RPC_TASK_ROOTCREDS, "ROOTCREDS" }, \
...@@ -327,14 +313,6 @@ TRACE_DEFINE_ENUM(RPC_TASK_CRED_NOREF); ...@@ -327,14 +313,6 @@ TRACE_DEFINE_ENUM(RPC_TASK_CRED_NOREF);
{ RPC_TASK_NO_RETRANS_TIMEOUT, "NORTO" }, \ { RPC_TASK_NO_RETRANS_TIMEOUT, "NORTO" }, \
{ RPC_TASK_CRED_NOREF, "CRED_NOREF" }) { RPC_TASK_CRED_NOREF, "CRED_NOREF" })
TRACE_DEFINE_ENUM(RPC_TASK_RUNNING);
TRACE_DEFINE_ENUM(RPC_TASK_QUEUED);
TRACE_DEFINE_ENUM(RPC_TASK_ACTIVE);
TRACE_DEFINE_ENUM(RPC_TASK_NEED_XMIT);
TRACE_DEFINE_ENUM(RPC_TASK_NEED_RECV);
TRACE_DEFINE_ENUM(RPC_TASK_MSG_PIN_WAIT);
TRACE_DEFINE_ENUM(RPC_TASK_SIGNALLED);
#define rpc_show_runstate(flags) \ #define rpc_show_runstate(flags) \
__print_flags(flags, "|", \ __print_flags(flags, "|", \
{ (1UL << RPC_TASK_RUNNING), "RUNNING" }, \ { (1UL << RPC_TASK_RUNNING), "RUNNING" }, \
...@@ -945,17 +923,6 @@ TRACE_EVENT(rpc_socket_nospace, ...@@ -945,17 +923,6 @@ TRACE_EVENT(rpc_socket_nospace,
) )
); );
TRACE_DEFINE_ENUM(XPRT_LOCKED);
TRACE_DEFINE_ENUM(XPRT_CONNECTED);
TRACE_DEFINE_ENUM(XPRT_CONNECTING);
TRACE_DEFINE_ENUM(XPRT_CLOSE_WAIT);
TRACE_DEFINE_ENUM(XPRT_BOUND);
TRACE_DEFINE_ENUM(XPRT_BINDING);
TRACE_DEFINE_ENUM(XPRT_CLOSING);
TRACE_DEFINE_ENUM(XPRT_CONGESTED);
TRACE_DEFINE_ENUM(XPRT_CWND_WAIT);
TRACE_DEFINE_ENUM(XPRT_WRITE_SPACE);
#define rpc_show_xprt_state(x) \ #define rpc_show_xprt_state(x) \
__print_flags(x, "|", \ __print_flags(x, "|", \
{ (1UL << XPRT_LOCKED), "LOCKED"}, \ { (1UL << XPRT_LOCKED), "LOCKED"}, \
...@@ -965,6 +932,8 @@ TRACE_DEFINE_ENUM(XPRT_WRITE_SPACE); ...@@ -965,6 +932,8 @@ TRACE_DEFINE_ENUM(XPRT_WRITE_SPACE);
{ (1UL << XPRT_BOUND), "BOUND"}, \ { (1UL << XPRT_BOUND), "BOUND"}, \
{ (1UL << XPRT_BINDING), "BINDING"}, \ { (1UL << XPRT_BINDING), "BINDING"}, \
{ (1UL << XPRT_CLOSING), "CLOSING"}, \ { (1UL << XPRT_CLOSING), "CLOSING"}, \
{ (1UL << XPRT_OFFLINE), "OFFLINE"}, \
{ (1UL << XPRT_REMOVE), "REMOVE"}, \
{ (1UL << XPRT_CONGESTED), "CONGESTED"}, \ { (1UL << XPRT_CONGESTED), "CONGESTED"}, \
{ (1UL << XPRT_CWND_WAIT), "CWND_WAIT"}, \ { (1UL << XPRT_CWND_WAIT), "CWND_WAIT"}, \
{ (1UL << XPRT_WRITE_SPACE), "WRITE_SPACE"}) { (1UL << XPRT_WRITE_SPACE), "WRITE_SPACE"})
...@@ -1092,10 +1061,10 @@ TRACE_EVENT(xprt_retransmit, ...@@ -1092,10 +1061,10 @@ TRACE_EVENT(xprt_retransmit,
__field(u32, xid) __field(u32, xid)
__field(int, ntrans) __field(int, ntrans)
__field(int, version) __field(int, version)
__field(unsigned long, timeout)
__string(progname, __string(progname,
rqst->rq_task->tk_client->cl_program->name) rqst->rq_task->tk_client->cl_program->name)
__string(procedure, __string(procname, rpc_proc_name(rqst->rq_task))
rqst->rq_task->tk_msg.rpc_proc->p_name)
), ),
TP_fast_assign( TP_fast_assign(
...@@ -1106,17 +1075,19 @@ TRACE_EVENT(xprt_retransmit, ...@@ -1106,17 +1075,19 @@ TRACE_EVENT(xprt_retransmit,
task->tk_client->cl_clid : -1; task->tk_client->cl_clid : -1;
__entry->xid = be32_to_cpu(rqst->rq_xid); __entry->xid = be32_to_cpu(rqst->rq_xid);
__entry->ntrans = rqst->rq_ntrans; __entry->ntrans = rqst->rq_ntrans;
__entry->timeout = task->tk_timeout;
__assign_str(progname, __assign_str(progname,
task->tk_client->cl_program->name); task->tk_client->cl_program->name);
__entry->version = task->tk_client->cl_vers; __entry->version = task->tk_client->cl_vers;
__assign_str(procedure, task->tk_msg.rpc_proc->p_name); __assign_str(procname, rpc_proc_name(task));
), ),
TP_printk( TP_printk(
"task:%u@%u xid=0x%08x %sv%d %s ntrans=%d", "task:%u@%u xid=0x%08x %sv%d %s ntrans=%d timeout=%lu",
__entry->task_id, __entry->client_id, __entry->xid, __entry->task_id, __entry->client_id, __entry->xid,
__get_str(progname), __entry->version, __get_str(procedure), __get_str(progname), __entry->version, __get_str(procname),
__entry->ntrans) __entry->ntrans, __entry->timeout
)
); );
TRACE_EVENT(xprt_ping, TRACE_EVENT(xprt_ping,
...@@ -1568,8 +1539,7 @@ DEFINE_SVCXDRBUF_EVENT(sendto); ...@@ -1568,8 +1539,7 @@ DEFINE_SVCXDRBUF_EVENT(sendto);
svc_rqst_flag(SPLICE_OK) \ svc_rqst_flag(SPLICE_OK) \
svc_rqst_flag(VICTIM) \ svc_rqst_flag(VICTIM) \
svc_rqst_flag(BUSY) \ svc_rqst_flag(BUSY) \
svc_rqst_flag(DATA) \ svc_rqst_flag_end(DATA)
svc_rqst_flag_end(AUTHERR)
#undef svc_rqst_flag #undef svc_rqst_flag
#undef svc_rqst_flag_end #undef svc_rqst_flag_end
...@@ -1611,9 +1581,9 @@ TRACE_DEFINE_ENUM(SVC_COMPLETE); ...@@ -1611,9 +1581,9 @@ TRACE_DEFINE_ENUM(SVC_COMPLETE);
{ SVC_COMPLETE, "SVC_COMPLETE" }) { SVC_COMPLETE, "SVC_COMPLETE" })
TRACE_EVENT(svc_authenticate, TRACE_EVENT(svc_authenticate,
TP_PROTO(const struct svc_rqst *rqst, int auth_res, __be32 auth_stat), TP_PROTO(const struct svc_rqst *rqst, int auth_res),
TP_ARGS(rqst, auth_res, auth_stat), TP_ARGS(rqst, auth_res),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(u32, xid) __field(u32, xid)
...@@ -1624,7 +1594,7 @@ TRACE_EVENT(svc_authenticate, ...@@ -1624,7 +1594,7 @@ TRACE_EVENT(svc_authenticate,
TP_fast_assign( TP_fast_assign(
__entry->xid = be32_to_cpu(rqst->rq_xid); __entry->xid = be32_to_cpu(rqst->rq_xid);
__entry->svc_status = auth_res; __entry->svc_status = auth_res;
__entry->auth_stat = be32_to_cpu(auth_stat); __entry->auth_stat = be32_to_cpu(rqst->rq_auth_stat);
), ),
TP_printk("xid=0x%08x auth_res=%s auth_stat=%s", TP_printk("xid=0x%08x auth_res=%s auth_stat=%s",
......
...@@ -160,7 +160,7 @@ static struct rpc_clnt *get_gssp_clnt(struct sunrpc_net *sn) ...@@ -160,7 +160,7 @@ static struct rpc_clnt *get_gssp_clnt(struct sunrpc_net *sn)
mutex_lock(&sn->gssp_lock); mutex_lock(&sn->gssp_lock);
clnt = sn->gssp_clnt; clnt = sn->gssp_clnt;
if (clnt) if (clnt)
atomic_inc(&clnt->cl_count); refcount_inc(&clnt->cl_count);
mutex_unlock(&sn->gssp_lock); mutex_unlock(&sn->gssp_lock);
return clnt; return clnt;
} }
......
...@@ -707,11 +707,11 @@ svc_safe_putnetobj(struct kvec *resv, struct xdr_netobj *o) ...@@ -707,11 +707,11 @@ svc_safe_putnetobj(struct kvec *resv, struct xdr_netobj *o)
/* /*
* Verify the checksum on the header and return SVC_OK on success. * Verify the checksum on the header and return SVC_OK on success.
* Otherwise, return SVC_DROP (in the case of a bad sequence number) * Otherwise, return SVC_DROP (in the case of a bad sequence number)
* or return SVC_DENIED and indicate error in authp. * or return SVC_DENIED and indicate error in rqstp->rq_auth_stat.
*/ */
static int static int
gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci, gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci,
__be32 *rpcstart, struct rpc_gss_wire_cred *gc, __be32 *authp) __be32 *rpcstart, struct rpc_gss_wire_cred *gc)
{ {
struct gss_ctx *ctx_id = rsci->mechctx; struct gss_ctx *ctx_id = rsci->mechctx;
struct xdr_buf rpchdr; struct xdr_buf rpchdr;
...@@ -725,7 +725,7 @@ gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci, ...@@ -725,7 +725,7 @@ gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci,
iov.iov_len = (u8 *)argv->iov_base - (u8 *)rpcstart; iov.iov_len = (u8 *)argv->iov_base - (u8 *)rpcstart;
xdr_buf_from_iov(&iov, &rpchdr); xdr_buf_from_iov(&iov, &rpchdr);
*authp = rpc_autherr_badverf; rqstp->rq_auth_stat = rpc_autherr_badverf;
if (argv->iov_len < 4) if (argv->iov_len < 4)
return SVC_DENIED; return SVC_DENIED;
flavor = svc_getnl(argv); flavor = svc_getnl(argv);
...@@ -737,13 +737,13 @@ gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci, ...@@ -737,13 +737,13 @@ gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci,
if (rqstp->rq_deferred) /* skip verification of revisited request */ if (rqstp->rq_deferred) /* skip verification of revisited request */
return SVC_OK; return SVC_OK;
if (gss_verify_mic(ctx_id, &rpchdr, &checksum) != GSS_S_COMPLETE) { if (gss_verify_mic(ctx_id, &rpchdr, &checksum) != GSS_S_COMPLETE) {
*authp = rpcsec_gsserr_credproblem; rqstp->rq_auth_stat = rpcsec_gsserr_credproblem;
return SVC_DENIED; return SVC_DENIED;
} }
if (gc->gc_seq > MAXSEQ) { if (gc->gc_seq > MAXSEQ) {
trace_rpcgss_svc_seqno_large(rqstp, gc->gc_seq); trace_rpcgss_svc_seqno_large(rqstp, gc->gc_seq);
*authp = rpcsec_gsserr_ctxproblem; rqstp->rq_auth_stat = rpcsec_gsserr_ctxproblem;
return SVC_DENIED; return SVC_DENIED;
} }
if (!gss_check_seq_num(rqstp, rsci, gc->gc_seq)) if (!gss_check_seq_num(rqstp, rsci, gc->gc_seq))
...@@ -1038,6 +1038,8 @@ svcauth_gss_set_client(struct svc_rqst *rqstp) ...@@ -1038,6 +1038,8 @@ svcauth_gss_set_client(struct svc_rqst *rqstp)
struct rpc_gss_wire_cred *gc = &svcdata->clcred; struct rpc_gss_wire_cred *gc = &svcdata->clcred;
int stat; int stat;
rqstp->rq_auth_stat = rpc_autherr_badcred;
/* /*
* A gss export can be specified either by: * A gss export can be specified either by:
* export *(sec=krb5,rw) * export *(sec=krb5,rw)
...@@ -1053,6 +1055,8 @@ svcauth_gss_set_client(struct svc_rqst *rqstp) ...@@ -1053,6 +1055,8 @@ svcauth_gss_set_client(struct svc_rqst *rqstp)
stat = svcauth_unix_set_client(rqstp); stat = svcauth_unix_set_client(rqstp);
if (stat == SVC_DROP || stat == SVC_CLOSE) if (stat == SVC_DROP || stat == SVC_CLOSE)
return stat; return stat;
rqstp->rq_auth_stat = rpc_auth_ok;
return SVC_OK; return SVC_OK;
} }
...@@ -1142,7 +1146,7 @@ static void gss_free_in_token_pages(struct gssp_in_token *in_token) ...@@ -1142,7 +1146,7 @@ static void gss_free_in_token_pages(struct gssp_in_token *in_token)
} }
static int gss_read_proxy_verf(struct svc_rqst *rqstp, static int gss_read_proxy_verf(struct svc_rqst *rqstp,
struct rpc_gss_wire_cred *gc, __be32 *authp, struct rpc_gss_wire_cred *gc,
struct xdr_netobj *in_handle, struct xdr_netobj *in_handle,
struct gssp_in_token *in_token) struct gssp_in_token *in_token)
{ {
...@@ -1151,7 +1155,7 @@ static int gss_read_proxy_verf(struct svc_rqst *rqstp, ...@@ -1151,7 +1155,7 @@ static int gss_read_proxy_verf(struct svc_rqst *rqstp,
int pages, i, res, pgto, pgfrom; int pages, i, res, pgto, pgfrom;
size_t inlen, to_offs, from_offs; size_t inlen, to_offs, from_offs;
res = gss_read_common_verf(gc, argv, authp, in_handle); res = gss_read_common_verf(gc, argv, &rqstp->rq_auth_stat, in_handle);
if (res) if (res)
return res; return res;
...@@ -1227,7 +1231,7 @@ gss_write_resv(struct kvec *resv, size_t size_limit, ...@@ -1227,7 +1231,7 @@ gss_write_resv(struct kvec *resv, size_t size_limit,
* Otherwise, drop the request pending an answer to the upcall. * Otherwise, drop the request pending an answer to the upcall.
*/ */
static int svcauth_gss_legacy_init(struct svc_rqst *rqstp, static int svcauth_gss_legacy_init(struct svc_rqst *rqstp,
struct rpc_gss_wire_cred *gc, __be32 *authp) struct rpc_gss_wire_cred *gc)
{ {
struct kvec *argv = &rqstp->rq_arg.head[0]; struct kvec *argv = &rqstp->rq_arg.head[0];
struct kvec *resv = &rqstp->rq_res.head[0]; struct kvec *resv = &rqstp->rq_res.head[0];
...@@ -1236,7 +1240,7 @@ static int svcauth_gss_legacy_init(struct svc_rqst *rqstp, ...@@ -1236,7 +1240,7 @@ static int svcauth_gss_legacy_init(struct svc_rqst *rqstp,
struct sunrpc_net *sn = net_generic(SVC_NET(rqstp), sunrpc_net_id); struct sunrpc_net *sn = net_generic(SVC_NET(rqstp), sunrpc_net_id);
memset(&rsikey, 0, sizeof(rsikey)); memset(&rsikey, 0, sizeof(rsikey));
ret = gss_read_verf(gc, argv, authp, ret = gss_read_verf(gc, argv, &rqstp->rq_auth_stat,
&rsikey.in_handle, &rsikey.in_token); &rsikey.in_handle, &rsikey.in_token);
if (ret) if (ret)
return ret; return ret;
...@@ -1339,7 +1343,7 @@ static int gss_proxy_save_rsc(struct cache_detail *cd, ...@@ -1339,7 +1343,7 @@ static int gss_proxy_save_rsc(struct cache_detail *cd,
} }
static int svcauth_gss_proxy_init(struct svc_rqst *rqstp, static int svcauth_gss_proxy_init(struct svc_rqst *rqstp,
struct rpc_gss_wire_cred *gc, __be32 *authp) struct rpc_gss_wire_cred *gc)
{ {
struct kvec *resv = &rqstp->rq_res.head[0]; struct kvec *resv = &rqstp->rq_res.head[0];
struct xdr_netobj cli_handle; struct xdr_netobj cli_handle;
...@@ -1351,8 +1355,7 @@ static int svcauth_gss_proxy_init(struct svc_rqst *rqstp, ...@@ -1351,8 +1355,7 @@ static int svcauth_gss_proxy_init(struct svc_rqst *rqstp,
struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
memset(&ud, 0, sizeof(ud)); memset(&ud, 0, sizeof(ud));
ret = gss_read_proxy_verf(rqstp, gc, authp, ret = gss_read_proxy_verf(rqstp, gc, &ud.in_handle, &ud.in_token);
&ud.in_handle, &ud.in_token);
if (ret) if (ret)
return ret; return ret;
...@@ -1525,7 +1528,7 @@ static void destroy_use_gss_proxy_proc_entry(struct net *net) {} ...@@ -1525,7 +1528,7 @@ static void destroy_use_gss_proxy_proc_entry(struct net *net) {}
* response here and return SVC_COMPLETE. * response here and return SVC_COMPLETE.
*/ */
static int static int
svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) svcauth_gss_accept(struct svc_rqst *rqstp)
{ {
struct kvec *argv = &rqstp->rq_arg.head[0]; struct kvec *argv = &rqstp->rq_arg.head[0];
struct kvec *resv = &rqstp->rq_res.head[0]; struct kvec *resv = &rqstp->rq_res.head[0];
...@@ -1538,7 +1541,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) ...@@ -1538,7 +1541,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
int ret; int ret;
struct sunrpc_net *sn = net_generic(SVC_NET(rqstp), sunrpc_net_id); struct sunrpc_net *sn = net_generic(SVC_NET(rqstp), sunrpc_net_id);
*authp = rpc_autherr_badcred; rqstp->rq_auth_stat = rpc_autherr_badcred;
if (!svcdata) if (!svcdata)
svcdata = kmalloc(sizeof(*svcdata), GFP_KERNEL); svcdata = kmalloc(sizeof(*svcdata), GFP_KERNEL);
if (!svcdata) if (!svcdata)
...@@ -1575,22 +1578,22 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) ...@@ -1575,22 +1578,22 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
if ((gc->gc_proc != RPC_GSS_PROC_DATA) && (rqstp->rq_proc != 0)) if ((gc->gc_proc != RPC_GSS_PROC_DATA) && (rqstp->rq_proc != 0))
goto auth_err; goto auth_err;
*authp = rpc_autherr_badverf; rqstp->rq_auth_stat = rpc_autherr_badverf;
switch (gc->gc_proc) { switch (gc->gc_proc) {
case RPC_GSS_PROC_INIT: case RPC_GSS_PROC_INIT:
case RPC_GSS_PROC_CONTINUE_INIT: case RPC_GSS_PROC_CONTINUE_INIT:
if (use_gss_proxy(SVC_NET(rqstp))) if (use_gss_proxy(SVC_NET(rqstp)))
return svcauth_gss_proxy_init(rqstp, gc, authp); return svcauth_gss_proxy_init(rqstp, gc);
else else
return svcauth_gss_legacy_init(rqstp, gc, authp); return svcauth_gss_legacy_init(rqstp, gc);
case RPC_GSS_PROC_DATA: case RPC_GSS_PROC_DATA:
case RPC_GSS_PROC_DESTROY: case RPC_GSS_PROC_DESTROY:
/* Look up the context, and check the verifier: */ /* Look up the context, and check the verifier: */
*authp = rpcsec_gsserr_credproblem; rqstp->rq_auth_stat = rpcsec_gsserr_credproblem;
rsci = gss_svc_searchbyctx(sn->rsc_cache, &gc->gc_ctx); rsci = gss_svc_searchbyctx(sn->rsc_cache, &gc->gc_ctx);
if (!rsci) if (!rsci)
goto auth_err; goto auth_err;
switch (gss_verify_header(rqstp, rsci, rpcstart, gc, authp)) { switch (gss_verify_header(rqstp, rsci, rpcstart, gc)) {
case SVC_OK: case SVC_OK:
break; break;
case SVC_DENIED: case SVC_DENIED:
...@@ -1600,7 +1603,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) ...@@ -1600,7 +1603,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
} }
break; break;
default: default:
*authp = rpc_autherr_rejectedcred; rqstp->rq_auth_stat = rpc_autherr_rejectedcred;
goto auth_err; goto auth_err;
} }
...@@ -1616,13 +1619,13 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) ...@@ -1616,13 +1619,13 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
svc_putnl(resv, RPC_SUCCESS); svc_putnl(resv, RPC_SUCCESS);
goto complete; goto complete;
case RPC_GSS_PROC_DATA: case RPC_GSS_PROC_DATA:
*authp = rpcsec_gsserr_ctxproblem; rqstp->rq_auth_stat = rpcsec_gsserr_ctxproblem;
svcdata->verf_start = resv->iov_base + resv->iov_len; svcdata->verf_start = resv->iov_base + resv->iov_len;
if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq)) if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq))
goto auth_err; goto auth_err;
rqstp->rq_cred = rsci->cred; rqstp->rq_cred = rsci->cred;
get_group_info(rsci->cred.cr_group_info); get_group_info(rsci->cred.cr_group_info);
*authp = rpc_autherr_badcred; rqstp->rq_auth_stat = rpc_autherr_badcred;
switch (gc->gc_svc) { switch (gc->gc_svc) {
case RPC_GSS_SVC_NONE: case RPC_GSS_SVC_NONE:
break; break;
......
...@@ -167,7 +167,7 @@ static int rpc_clnt_skip_event(struct rpc_clnt *clnt, unsigned long event) ...@@ -167,7 +167,7 @@ static int rpc_clnt_skip_event(struct rpc_clnt *clnt, unsigned long event)
case RPC_PIPEFS_MOUNT: case RPC_PIPEFS_MOUNT:
if (clnt->cl_pipedir_objects.pdh_dentry != NULL) if (clnt->cl_pipedir_objects.pdh_dentry != NULL)
return 1; return 1;
if (atomic_read(&clnt->cl_count) == 0) if (refcount_read(&clnt->cl_count) == 0)
return 1; return 1;
break; break;
case RPC_PIPEFS_UMOUNT: case RPC_PIPEFS_UMOUNT:
...@@ -419,7 +419,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, ...@@ -419,7 +419,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args,
clnt->cl_rtt = &clnt->cl_rtt_default; clnt->cl_rtt = &clnt->cl_rtt_default;
rpc_init_rtt(&clnt->cl_rtt_default, clnt->cl_timeout->to_initval); rpc_init_rtt(&clnt->cl_rtt_default, clnt->cl_timeout->to_initval);
atomic_set(&clnt->cl_count, 1); refcount_set(&clnt->cl_count, 1);
if (nodename == NULL) if (nodename == NULL)
nodename = utsname()->nodename; nodename = utsname()->nodename;
...@@ -431,7 +431,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, ...@@ -431,7 +431,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args,
if (err) if (err)
goto out_no_path; goto out_no_path;
if (parent) if (parent)
atomic_inc(&parent->cl_count); refcount_inc(&parent->cl_count);
trace_rpc_clnt_new(clnt, xprt, program->name, args->servername); trace_rpc_clnt_new(clnt, xprt, program->name, args->servername);
return clnt; return clnt;
...@@ -918,18 +918,16 @@ rpc_free_client(struct rpc_clnt *clnt) ...@@ -918,18 +918,16 @@ rpc_free_client(struct rpc_clnt *clnt)
static struct rpc_clnt * static struct rpc_clnt *
rpc_free_auth(struct rpc_clnt *clnt) rpc_free_auth(struct rpc_clnt *clnt)
{ {
if (clnt->cl_auth == NULL)
return rpc_free_client(clnt);
/* /*
* Note: RPCSEC_GSS may need to send NULL RPC calls in order to * Note: RPCSEC_GSS may need to send NULL RPC calls in order to
* release remaining GSS contexts. This mechanism ensures * release remaining GSS contexts. This mechanism ensures
* that it can do so safely. * that it can do so safely.
*/ */
atomic_inc(&clnt->cl_count); if (clnt->cl_auth != NULL) {
rpcauth_release(clnt->cl_auth); rpcauth_release(clnt->cl_auth);
clnt->cl_auth = NULL; clnt->cl_auth = NULL;
if (atomic_dec_and_test(&clnt->cl_count)) }
if (refcount_dec_and_test(&clnt->cl_count))
return rpc_free_client(clnt); return rpc_free_client(clnt);
return NULL; return NULL;
} }
...@@ -943,7 +941,7 @@ rpc_release_client(struct rpc_clnt *clnt) ...@@ -943,7 +941,7 @@ rpc_release_client(struct rpc_clnt *clnt)
do { do {
if (list_empty(&clnt->cl_tasks)) if (list_empty(&clnt->cl_tasks))
wake_up(&destroy_wait); wake_up(&destroy_wait);
if (!atomic_dec_and_test(&clnt->cl_count)) if (refcount_dec_not_one(&clnt->cl_count))
break; break;
clnt = rpc_free_auth(clnt); clnt = rpc_free_auth(clnt);
} while (clnt != NULL); } while (clnt != NULL);
...@@ -1082,7 +1080,7 @@ void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt) ...@@ -1082,7 +1080,7 @@ void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt)
if (clnt != NULL) { if (clnt != NULL) {
rpc_task_set_transport(task, clnt); rpc_task_set_transport(task, clnt);
task->tk_client = clnt; task->tk_client = clnt;
atomic_inc(&clnt->cl_count); refcount_inc(&clnt->cl_count);
if (clnt->cl_softrtry) if (clnt->cl_softrtry)
task->tk_flags |= RPC_TASK_SOFT; task->tk_flags |= RPC_TASK_SOFT;
if (clnt->cl_softerr) if (clnt->cl_softerr)
...@@ -2694,17 +2692,18 @@ static const struct rpc_procinfo rpcproc_null = { ...@@ -2694,17 +2692,18 @@ static const struct rpc_procinfo rpcproc_null = {
.p_decode = rpcproc_decode_null, .p_decode = rpcproc_decode_null,
}; };
static int rpc_ping(struct rpc_clnt *clnt) static void
rpc_null_call_prepare(struct rpc_task *task, void *data)
{ {
struct rpc_message msg = { task->tk_flags &= ~RPC_TASK_NO_RETRANS_TIMEOUT;
.rpc_proc = &rpcproc_null, rpc_call_start(task);
};
int err;
err = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT | RPC_TASK_SOFTCONN |
RPC_TASK_NULLCREDS);
return err;
} }
static const struct rpc_call_ops rpc_null_ops = {
.rpc_call_prepare = rpc_null_call_prepare,
.rpc_call_done = rpc_default_callback,
};
static static
struct rpc_task *rpc_call_null_helper(struct rpc_clnt *clnt, struct rpc_task *rpc_call_null_helper(struct rpc_clnt *clnt,
struct rpc_xprt *xprt, struct rpc_cred *cred, int flags, struct rpc_xprt *xprt, struct rpc_cred *cred, int flags,
...@@ -2718,7 +2717,7 @@ struct rpc_task *rpc_call_null_helper(struct rpc_clnt *clnt, ...@@ -2718,7 +2717,7 @@ struct rpc_task *rpc_call_null_helper(struct rpc_clnt *clnt,
.rpc_xprt = xprt, .rpc_xprt = xprt,
.rpc_message = &msg, .rpc_message = &msg,
.rpc_op_cred = cred, .rpc_op_cred = cred,
.callback_ops = (ops != NULL) ? ops : &rpc_default_ops, .callback_ops = ops ?: &rpc_null_ops,
.callback_data = data, .callback_data = data,
.flags = flags | RPC_TASK_SOFT | RPC_TASK_SOFTCONN | .flags = flags | RPC_TASK_SOFT | RPC_TASK_SOFTCONN |
RPC_TASK_NULLCREDS, RPC_TASK_NULLCREDS,
...@@ -2733,6 +2732,19 @@ struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, int ...@@ -2733,6 +2732,19 @@ struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, int
} }
EXPORT_SYMBOL_GPL(rpc_call_null); EXPORT_SYMBOL_GPL(rpc_call_null);
static int rpc_ping(struct rpc_clnt *clnt)
{
struct rpc_task *task;
int status;
task = rpc_call_null_helper(clnt, NULL, NULL, 0, NULL, NULL);
if (IS_ERR(task))
return PTR_ERR(task);
status = task->tk_status;
rpc_put_task(task);
return status;
}
struct rpc_cb_add_xprt_calldata { struct rpc_cb_add_xprt_calldata {
struct rpc_xprt_switch *xps; struct rpc_xprt_switch *xps;
struct rpc_xprt *xprt; struct rpc_xprt *xprt;
...@@ -2756,6 +2768,7 @@ static void rpc_cb_add_xprt_release(void *calldata) ...@@ -2756,6 +2768,7 @@ static void rpc_cb_add_xprt_release(void *calldata)
} }
static const struct rpc_call_ops rpc_cb_add_xprt_call_ops = { static const struct rpc_call_ops rpc_cb_add_xprt_call_ops = {
.rpc_call_prepare = rpc_null_call_prepare,
.rpc_call_done = rpc_cb_add_xprt_done, .rpc_call_done = rpc_cb_add_xprt_done,
.rpc_release = rpc_cb_add_xprt_release, .rpc_release = rpc_cb_add_xprt_release,
}; };
...@@ -2774,6 +2787,15 @@ int rpc_clnt_test_and_add_xprt(struct rpc_clnt *clnt, ...@@ -2774,6 +2787,15 @@ int rpc_clnt_test_and_add_xprt(struct rpc_clnt *clnt,
struct rpc_cb_add_xprt_calldata *data; struct rpc_cb_add_xprt_calldata *data;
struct rpc_task *task; struct rpc_task *task;
if (xps->xps_nunique_destaddr_xprts + 1 > clnt->cl_max_connect) {
rcu_read_lock();
pr_warn("SUNRPC: reached max allowed number (%d) did not add "
"transport to server: %s\n", clnt->cl_max_connect,
rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR));
rcu_read_unlock();
return -EINVAL;
}
data = kmalloc(sizeof(*data), GFP_NOFS); data = kmalloc(sizeof(*data), GFP_NOFS);
if (!data) if (!data)
return -ENOMEM; return -ENOMEM;
...@@ -2786,7 +2808,7 @@ int rpc_clnt_test_and_add_xprt(struct rpc_clnt *clnt, ...@@ -2786,7 +2808,7 @@ int rpc_clnt_test_and_add_xprt(struct rpc_clnt *clnt,
task = rpc_call_null_helper(clnt, xprt, NULL, RPC_TASK_ASYNC, task = rpc_call_null_helper(clnt, xprt, NULL, RPC_TASK_ASYNC,
&rpc_cb_add_xprt_call_ops, data); &rpc_cb_add_xprt_call_ops, data);
data->xps->xps_nunique_destaddr_xprts++;
rpc_put_task(task); rpc_put_task(task);
success: success:
return 1; return 1;
......
...@@ -90,7 +90,7 @@ static int tasks_open(struct inode *inode, struct file *filp) ...@@ -90,7 +90,7 @@ static int tasks_open(struct inode *inode, struct file *filp)
struct seq_file *seq = filp->private_data; struct seq_file *seq = filp->private_data;
struct rpc_clnt *clnt = seq->private = inode->i_private; struct rpc_clnt *clnt = seq->private = inode->i_private;
if (!atomic_inc_not_zero(&clnt->cl_count)) { if (!refcount_inc_not_zero(&clnt->cl_count)) {
seq_release(inode, filp); seq_release(inode, filp);
ret = -EINVAL; ret = -EINVAL;
} }
......
...@@ -423,7 +423,7 @@ rpc_info_open(struct inode *inode, struct file *file) ...@@ -423,7 +423,7 @@ rpc_info_open(struct inode *inode, struct file *file)
spin_lock(&file->f_path.dentry->d_lock); spin_lock(&file->f_path.dentry->d_lock);
if (!d_unhashed(file->f_path.dentry)) if (!d_unhashed(file->f_path.dentry))
clnt = RPC_I(inode)->private; clnt = RPC_I(inode)->private;
if (clnt != NULL && atomic_inc_not_zero(&clnt->cl_count)) { if (clnt != NULL && refcount_inc_not_zero(&clnt->cl_count)) {
spin_unlock(&file->f_path.dentry->d_lock); spin_unlock(&file->f_path.dentry->d_lock);
m->private = clnt; m->private = clnt;
} else { } else {
......
...@@ -1186,22 +1186,6 @@ void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) ...@@ -1186,22 +1186,6 @@ void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...)
static __printf(2,3) void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) {} static __printf(2,3) void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) {}
#endif #endif
__be32
svc_return_autherr(struct svc_rqst *rqstp, __be32 auth_err)
{
set_bit(RQ_AUTHERR, &rqstp->rq_flags);
return auth_err;
}
EXPORT_SYMBOL_GPL(svc_return_autherr);
static __be32
svc_get_autherr(struct svc_rqst *rqstp, __be32 *statp)
{
if (test_and_clear_bit(RQ_AUTHERR, &rqstp->rq_flags))
return *statp;
return rpc_auth_ok;
}
static int static int
svc_generic_dispatch(struct svc_rqst *rqstp, __be32 *statp) svc_generic_dispatch(struct svc_rqst *rqstp, __be32 *statp)
{ {
...@@ -1225,7 +1209,7 @@ svc_generic_dispatch(struct svc_rqst *rqstp, __be32 *statp) ...@@ -1225,7 +1209,7 @@ svc_generic_dispatch(struct svc_rqst *rqstp, __be32 *statp)
test_bit(RQ_DROPME, &rqstp->rq_flags)) test_bit(RQ_DROPME, &rqstp->rq_flags))
return 0; return 0;
if (test_bit(RQ_AUTHERR, &rqstp->rq_flags)) if (rqstp->rq_auth_stat != rpc_auth_ok)
return 1; return 1;
if (*statp != rpc_success) if (*statp != rpc_success)
...@@ -1306,7 +1290,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) ...@@ -1306,7 +1290,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
struct svc_process_info process; struct svc_process_info process;
__be32 *statp; __be32 *statp;
u32 prog, vers; u32 prog, vers;
__be32 auth_stat, rpc_stat; __be32 rpc_stat;
int auth_res; int auth_res;
__be32 *reply_statp; __be32 *reply_statp;
...@@ -1349,14 +1333,12 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) ...@@ -1349,14 +1333,12 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
* We do this before anything else in order to get a decent * We do this before anything else in order to get a decent
* auth verifier. * auth verifier.
*/ */
auth_res = svc_authenticate(rqstp, &auth_stat); auth_res = svc_authenticate(rqstp);
/* Also give the program a chance to reject this call: */ /* Also give the program a chance to reject this call: */
if (auth_res == SVC_OK && progp) { if (auth_res == SVC_OK && progp)
auth_stat = rpc_autherr_badcred;
auth_res = progp->pg_authenticate(rqstp); auth_res = progp->pg_authenticate(rqstp);
}
if (auth_res != SVC_OK) if (auth_res != SVC_OK)
trace_svc_authenticate(rqstp, auth_res, auth_stat); trace_svc_authenticate(rqstp, auth_res);
switch (auth_res) { switch (auth_res) {
case SVC_OK: case SVC_OK:
break; break;
...@@ -1415,15 +1397,15 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) ...@@ -1415,15 +1397,15 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
goto release_dropit; goto release_dropit;
if (*statp == rpc_garbage_args) if (*statp == rpc_garbage_args)
goto err_garbage; goto err_garbage;
auth_stat = svc_get_autherr(rqstp, statp);
if (auth_stat != rpc_auth_ok)
goto err_release_bad_auth;
} else { } else {
dprintk("svc: calling dispatcher\n"); dprintk("svc: calling dispatcher\n");
if (!process.dispatch(rqstp, statp)) if (!process.dispatch(rqstp, statp))
goto release_dropit; /* Release reply info */ goto release_dropit; /* Release reply info */
} }
if (rqstp->rq_auth_stat != rpc_auth_ok)
goto err_release_bad_auth;
/* Check RPC status result */ /* Check RPC status result */
if (*statp != rpc_success) if (*statp != rpc_success)
resv->iov_len = ((void*)statp) - resv->iov_base + 4; resv->iov_len = ((void*)statp) - resv->iov_base + 4;
...@@ -1473,13 +1455,14 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) ...@@ -1473,13 +1455,14 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
if (procp->pc_release) if (procp->pc_release)
procp->pc_release(rqstp); procp->pc_release(rqstp);
err_bad_auth: err_bad_auth:
dprintk("svc: authentication failed (%d)\n", ntohl(auth_stat)); dprintk("svc: authentication failed (%d)\n",
be32_to_cpu(rqstp->rq_auth_stat));
serv->sv_stats->rpcbadauth++; serv->sv_stats->rpcbadauth++;
/* Restore write pointer to location of accept status: */ /* Restore write pointer to location of accept status: */
xdr_ressize_check(rqstp, reply_statp); xdr_ressize_check(rqstp, reply_statp);
svc_putnl(resv, 1); /* REJECT */ svc_putnl(resv, 1); /* REJECT */
svc_putnl(resv, 1); /* AUTH_ERROR */ svc_putnl(resv, 1); /* AUTH_ERROR */
svc_putnl(resv, ntohl(auth_stat)); /* status */ svc_putu32(resv, rqstp->rq_auth_stat); /* status */
goto sendit; goto sendit;
err_bad_prog: err_bad_prog:
......
...@@ -59,12 +59,12 @@ svc_put_auth_ops(struct auth_ops *aops) ...@@ -59,12 +59,12 @@ svc_put_auth_ops(struct auth_ops *aops)
} }
int int
svc_authenticate(struct svc_rqst *rqstp, __be32 *authp) svc_authenticate(struct svc_rqst *rqstp)
{ {
rpc_authflavor_t flavor; rpc_authflavor_t flavor;
struct auth_ops *aops; struct auth_ops *aops;
*authp = rpc_auth_ok; rqstp->rq_auth_stat = rpc_auth_ok;
flavor = svc_getnl(&rqstp->rq_arg.head[0]); flavor = svc_getnl(&rqstp->rq_arg.head[0]);
...@@ -72,7 +72,7 @@ svc_authenticate(struct svc_rqst *rqstp, __be32 *authp) ...@@ -72,7 +72,7 @@ svc_authenticate(struct svc_rqst *rqstp, __be32 *authp)
aops = svc_get_auth_ops(flavor); aops = svc_get_auth_ops(flavor);
if (aops == NULL) { if (aops == NULL) {
*authp = rpc_autherr_badcred; rqstp->rq_auth_stat = rpc_autherr_badcred;
return SVC_DENIED; return SVC_DENIED;
} }
...@@ -80,7 +80,7 @@ svc_authenticate(struct svc_rqst *rqstp, __be32 *authp) ...@@ -80,7 +80,7 @@ svc_authenticate(struct svc_rqst *rqstp, __be32 *authp)
init_svc_cred(&rqstp->rq_cred); init_svc_cred(&rqstp->rq_cred);
rqstp->rq_authop = aops; rqstp->rq_authop = aops;
return aops->accept(rqstp, authp); return aops->accept(rqstp);
} }
EXPORT_SYMBOL_GPL(svc_authenticate); EXPORT_SYMBOL_GPL(svc_authenticate);
......
...@@ -681,8 +681,9 @@ svcauth_unix_set_client(struct svc_rqst *rqstp) ...@@ -681,8 +681,9 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
rqstp->rq_client = NULL; rqstp->rq_client = NULL;
if (rqstp->rq_proc == 0) if (rqstp->rq_proc == 0)
return SVC_OK; goto out;
rqstp->rq_auth_stat = rpc_autherr_badcred;
ipm = ip_map_cached_get(xprt); ipm = ip_map_cached_get(xprt);
if (ipm == NULL) if (ipm == NULL)
ipm = __ip_map_lookup(sn->ip_map_cache, rqstp->rq_server->sv_program->pg_class, ipm = __ip_map_lookup(sn->ip_map_cache, rqstp->rq_server->sv_program->pg_class,
...@@ -719,13 +720,16 @@ svcauth_unix_set_client(struct svc_rqst *rqstp) ...@@ -719,13 +720,16 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
put_group_info(cred->cr_group_info); put_group_info(cred->cr_group_info);
cred->cr_group_info = gi; cred->cr_group_info = gi;
} }
out:
rqstp->rq_auth_stat = rpc_auth_ok;
return SVC_OK; return SVC_OK;
} }
EXPORT_SYMBOL_GPL(svcauth_unix_set_client); EXPORT_SYMBOL_GPL(svcauth_unix_set_client);
static int static int
svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp) svcauth_null_accept(struct svc_rqst *rqstp)
{ {
struct kvec *argv = &rqstp->rq_arg.head[0]; struct kvec *argv = &rqstp->rq_arg.head[0];
struct kvec *resv = &rqstp->rq_res.head[0]; struct kvec *resv = &rqstp->rq_res.head[0];
...@@ -736,12 +740,12 @@ svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp) ...@@ -736,12 +740,12 @@ svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp)
if (svc_getu32(argv) != 0) { if (svc_getu32(argv) != 0) {
dprintk("svc: bad null cred\n"); dprintk("svc: bad null cred\n");
*authp = rpc_autherr_badcred; rqstp->rq_auth_stat = rpc_autherr_badcred;
return SVC_DENIED; return SVC_DENIED;
} }
if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) { if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) {
dprintk("svc: bad null verf\n"); dprintk("svc: bad null verf\n");
*authp = rpc_autherr_badverf; rqstp->rq_auth_stat = rpc_autherr_badverf;
return SVC_DENIED; return SVC_DENIED;
} }
...@@ -785,7 +789,7 @@ struct auth_ops svcauth_null = { ...@@ -785,7 +789,7 @@ struct auth_ops svcauth_null = {
static int static int
svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp) svcauth_unix_accept(struct svc_rqst *rqstp)
{ {
struct kvec *argv = &rqstp->rq_arg.head[0]; struct kvec *argv = &rqstp->rq_arg.head[0];
struct kvec *resv = &rqstp->rq_res.head[0]; struct kvec *resv = &rqstp->rq_res.head[0];
...@@ -827,7 +831,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp) ...@@ -827,7 +831,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
} }
groups_sort(cred->cr_group_info); groups_sort(cred->cr_group_info);
if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) { if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) {
*authp = rpc_autherr_badverf; rqstp->rq_auth_stat = rpc_autherr_badverf;
return SVC_DENIED; return SVC_DENIED;
} }
...@@ -839,7 +843,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp) ...@@ -839,7 +843,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
return SVC_OK; return SVC_OK;
badcred: badcred:
*authp = rpc_autherr_badcred; rqstp->rq_auth_stat = rpc_autherr_badcred;
return SVC_DENIED; return SVC_DENIED;
} }
......
...@@ -100,6 +100,28 @@ static ssize_t rpc_sysfs_xprt_dstaddr_show(struct kobject *kobj, ...@@ -100,6 +100,28 @@ static ssize_t rpc_sysfs_xprt_dstaddr_show(struct kobject *kobj,
return ret + 1; return ret + 1;
} }
static ssize_t rpc_sysfs_xprt_srcaddr_show(struct kobject *kobj,
struct kobj_attribute *attr,
char *buf)
{
struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
struct sockaddr_storage saddr;
struct sock_xprt *sock;
ssize_t ret = -1;
if (!xprt)
return 0;
sock = container_of(xprt, struct sock_xprt, xprt);
if (kernel_getsockname(sock->sock, (struct sockaddr *)&saddr) < 0)
goto out;
ret = sprintf(buf, "%pISc\n", &saddr);
out:
xprt_put(xprt);
return ret + 1;
}
static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj, static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj,
struct kobj_attribute *attr, struct kobj_attribute *attr,
char *buf) char *buf)
...@@ -114,14 +136,16 @@ static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj, ...@@ -114,14 +136,16 @@ static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj,
"max_num_slots=%u\nmin_num_slots=%u\nnum_reqs=%u\n" "max_num_slots=%u\nmin_num_slots=%u\nnum_reqs=%u\n"
"binding_q_len=%u\nsending_q_len=%u\npending_q_len=%u\n" "binding_q_len=%u\nsending_q_len=%u\npending_q_len=%u\n"
"backlog_q_len=%u\nmain_xprt=%d\nsrc_port=%u\n" "backlog_q_len=%u\nmain_xprt=%d\nsrc_port=%u\n"
"tasks_queuelen=%ld\n", "tasks_queuelen=%ld\ndst_port=%s\n",
xprt->last_used, xprt->cong, xprt->cwnd, xprt->max_reqs, xprt->last_used, xprt->cong, xprt->cwnd, xprt->max_reqs,
xprt->min_reqs, xprt->num_reqs, xprt->binding.qlen, xprt->min_reqs, xprt->num_reqs, xprt->binding.qlen,
xprt->sending.qlen, xprt->pending.qlen, xprt->sending.qlen, xprt->pending.qlen,
xprt->backlog.qlen, xprt->main, xprt->backlog.qlen, xprt->main,
(xprt->xprt_class->ident == XPRT_TRANSPORT_TCP) ? (xprt->xprt_class->ident == XPRT_TRANSPORT_TCP) ?
get_srcport(xprt) : 0, get_srcport(xprt) : 0,
atomic_long_read(&xprt->queuelen)); atomic_long_read(&xprt->queuelen),
(xprt->xprt_class->ident == XPRT_TRANSPORT_TCP) ?
xprt->address_strings[RPC_DISPLAY_PORT] : "0");
xprt_put(xprt); xprt_put(xprt);
return ret + 1; return ret + 1;
} }
...@@ -183,8 +207,10 @@ static ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj, ...@@ -183,8 +207,10 @@ static ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj,
if (!xprt_switch) if (!xprt_switch)
return 0; return 0;
ret = sprintf(buf, "num_xprts=%u\nnum_active=%u\nqueue_len=%ld\n", ret = sprintf(buf, "num_xprts=%u\nnum_active=%u\n"
"num_unique_destaddr=%u\nqueue_len=%ld\n",
xprt_switch->xps_nxprts, xprt_switch->xps_nactive, xprt_switch->xps_nxprts, xprt_switch->xps_nactive,
xprt_switch->xps_nunique_destaddr_xprts,
atomic_long_read(&xprt_switch->xps_queuelen)); atomic_long_read(&xprt_switch->xps_queuelen));
xprt_switch_put(xprt_switch); xprt_switch_put(xprt_switch);
return ret + 1; return ret + 1;
...@@ -376,6 +402,9 @@ static const void *rpc_sysfs_xprt_namespace(struct kobject *kobj) ...@@ -376,6 +402,9 @@ static const void *rpc_sysfs_xprt_namespace(struct kobject *kobj)
static struct kobj_attribute rpc_sysfs_xprt_dstaddr = __ATTR(dstaddr, static struct kobj_attribute rpc_sysfs_xprt_dstaddr = __ATTR(dstaddr,
0644, rpc_sysfs_xprt_dstaddr_show, rpc_sysfs_xprt_dstaddr_store); 0644, rpc_sysfs_xprt_dstaddr_show, rpc_sysfs_xprt_dstaddr_store);
static struct kobj_attribute rpc_sysfs_xprt_srcaddr = __ATTR(srcaddr,
0644, rpc_sysfs_xprt_srcaddr_show, NULL);
static struct kobj_attribute rpc_sysfs_xprt_info = __ATTR(xprt_info, static struct kobj_attribute rpc_sysfs_xprt_info = __ATTR(xprt_info,
0444, rpc_sysfs_xprt_info_show, NULL); 0444, rpc_sysfs_xprt_info_show, NULL);
...@@ -384,6 +413,7 @@ static struct kobj_attribute rpc_sysfs_xprt_change_state = __ATTR(xprt_state, ...@@ -384,6 +413,7 @@ static struct kobj_attribute rpc_sysfs_xprt_change_state = __ATTR(xprt_state,
static struct attribute *rpc_sysfs_xprt_attrs[] = { static struct attribute *rpc_sysfs_xprt_attrs[] = {
&rpc_sysfs_xprt_dstaddr.attr, &rpc_sysfs_xprt_dstaddr.attr,
&rpc_sysfs_xprt_srcaddr.attr,
&rpc_sysfs_xprt_info.attr, &rpc_sysfs_xprt_info.attr,
&rpc_sysfs_xprt_change_state.attr, &rpc_sysfs_xprt_change_state.attr,
NULL, NULL,
......
...@@ -761,6 +761,20 @@ void xprt_disconnect_done(struct rpc_xprt *xprt) ...@@ -761,6 +761,20 @@ void xprt_disconnect_done(struct rpc_xprt *xprt)
} }
EXPORT_SYMBOL_GPL(xprt_disconnect_done); EXPORT_SYMBOL_GPL(xprt_disconnect_done);
/**
* xprt_schedule_autoclose_locked - Try to schedule an autoclose RPC call
* @xprt: transport to disconnect
*/
static void xprt_schedule_autoclose_locked(struct rpc_xprt *xprt)
{
set_bit(XPRT_CLOSE_WAIT, &xprt->state);
if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0)
queue_work(xprtiod_workqueue, &xprt->task_cleanup);
else if (xprt->snd_task && !test_bit(XPRT_SND_IS_COOKIE, &xprt->state))
rpc_wake_up_queued_task_set_status(&xprt->pending,
xprt->snd_task, -ENOTCONN);
}
/** /**
* xprt_force_disconnect - force a transport to disconnect * xprt_force_disconnect - force a transport to disconnect
* @xprt: transport to disconnect * @xprt: transport to disconnect
...@@ -772,13 +786,7 @@ void xprt_force_disconnect(struct rpc_xprt *xprt) ...@@ -772,13 +786,7 @@ void xprt_force_disconnect(struct rpc_xprt *xprt)
/* Don't race with the test_bit() in xprt_clear_locked() */ /* Don't race with the test_bit() in xprt_clear_locked() */
spin_lock(&xprt->transport_lock); spin_lock(&xprt->transport_lock);
set_bit(XPRT_CLOSE_WAIT, &xprt->state); xprt_schedule_autoclose_locked(xprt);
/* Try to schedule an autoclose RPC call */
if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0)
queue_work(xprtiod_workqueue, &xprt->task_cleanup);
else if (xprt->snd_task)
rpc_wake_up_queued_task_set_status(&xprt->pending,
xprt->snd_task, -ENOTCONN);
spin_unlock(&xprt->transport_lock); spin_unlock(&xprt->transport_lock);
} }
EXPORT_SYMBOL_GPL(xprt_force_disconnect); EXPORT_SYMBOL_GPL(xprt_force_disconnect);
...@@ -818,11 +826,7 @@ void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie) ...@@ -818,11 +826,7 @@ void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie)
goto out; goto out;
if (test_bit(XPRT_CLOSING, &xprt->state)) if (test_bit(XPRT_CLOSING, &xprt->state))
goto out; goto out;
set_bit(XPRT_CLOSE_WAIT, &xprt->state); xprt_schedule_autoclose_locked(xprt);
/* Try to schedule an autoclose RPC call */
if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0)
queue_work(xprtiod_workqueue, &xprt->task_cleanup);
xprt_wake_pending_tasks(xprt, -EAGAIN);
out: out:
spin_unlock(&xprt->transport_lock); spin_unlock(&xprt->transport_lock);
} }
...@@ -880,12 +884,14 @@ bool xprt_lock_connect(struct rpc_xprt *xprt, ...@@ -880,12 +884,14 @@ bool xprt_lock_connect(struct rpc_xprt *xprt,
goto out; goto out;
if (xprt->snd_task != task) if (xprt->snd_task != task)
goto out; goto out;
set_bit(XPRT_SND_IS_COOKIE, &xprt->state);
xprt->snd_task = cookie; xprt->snd_task = cookie;
ret = true; ret = true;
out: out:
spin_unlock(&xprt->transport_lock); spin_unlock(&xprt->transport_lock);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(xprt_lock_connect);
void xprt_unlock_connect(struct rpc_xprt *xprt, void *cookie) void xprt_unlock_connect(struct rpc_xprt *xprt, void *cookie)
{ {
...@@ -895,12 +901,14 @@ void xprt_unlock_connect(struct rpc_xprt *xprt, void *cookie) ...@@ -895,12 +901,14 @@ void xprt_unlock_connect(struct rpc_xprt *xprt, void *cookie)
if (!test_bit(XPRT_LOCKED, &xprt->state)) if (!test_bit(XPRT_LOCKED, &xprt->state))
goto out; goto out;
xprt->snd_task =NULL; xprt->snd_task =NULL;
clear_bit(XPRT_SND_IS_COOKIE, &xprt->state);
xprt->ops->release_xprt(xprt, NULL); xprt->ops->release_xprt(xprt, NULL);
xprt_schedule_autodisconnect(xprt); xprt_schedule_autodisconnect(xprt);
out: out:
spin_unlock(&xprt->transport_lock); spin_unlock(&xprt->transport_lock);
wake_up_bit(&xprt->state, XPRT_LOCKED); wake_up_bit(&xprt->state, XPRT_LOCKED);
} }
EXPORT_SYMBOL_GPL(xprt_unlock_connect);
/** /**
* xprt_connect - schedule a transport connect operation * xprt_connect - schedule a transport connect operation
......
...@@ -139,6 +139,7 @@ struct rpc_xprt_switch *xprt_switch_alloc(struct rpc_xprt *xprt, ...@@ -139,6 +139,7 @@ struct rpc_xprt_switch *xprt_switch_alloc(struct rpc_xprt *xprt,
xps->xps_iter_ops = &rpc_xprt_iter_singular; xps->xps_iter_ops = &rpc_xprt_iter_singular;
rpc_sysfs_xprt_switch_setup(xps, xprt, gfp_flags); rpc_sysfs_xprt_switch_setup(xps, xprt, gfp_flags);
xprt_switch_add_xprt_locked(xps, xprt); xprt_switch_add_xprt_locked(xps, xprt);
xps->xps_nunique_destaddr_xprts = 1;
rpc_sysfs_xprt_setup(xps, xprt, gfp_flags); rpc_sysfs_xprt_setup(xps, xprt, gfp_flags);
} }
......
...@@ -115,7 +115,7 @@ int xprt_rdma_bc_send_reply(struct rpc_rqst *rqst) ...@@ -115,7 +115,7 @@ int xprt_rdma_bc_send_reply(struct rpc_rqst *rqst)
if (rc < 0) if (rc < 0)
goto failed_marshal; goto failed_marshal;
if (rpcrdma_post_sends(r_xprt, req)) if (frwr_send(r_xprt, req))
goto drop_connection; goto drop_connection;
return 0; return 0;
......
...@@ -394,6 +394,7 @@ int frwr_send(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req) ...@@ -394,6 +394,7 @@ int frwr_send(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
struct rpcrdma_ep *ep = r_xprt->rx_ep; struct rpcrdma_ep *ep = r_xprt->rx_ep;
struct rpcrdma_mr *mr; struct rpcrdma_mr *mr;
unsigned int num_wrs; unsigned int num_wrs;
int ret;
num_wrs = 1; num_wrs = 1;
post_wr = send_wr; post_wr = send_wr;
...@@ -420,7 +421,10 @@ int frwr_send(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req) ...@@ -420,7 +421,10 @@ int frwr_send(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
} }
trace_xprtrdma_post_send(req); trace_xprtrdma_post_send(req);
return ib_post_send(ep->re_id->qp, post_wr, NULL); ret = ib_post_send(ep->re_id->qp, post_wr, NULL);
if (ret)
trace_xprtrdma_post_send_err(r_xprt, req, ret);
return ret;
} }
/** /**
...@@ -557,6 +561,10 @@ void frwr_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req) ...@@ -557,6 +561,10 @@ void frwr_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
/* On error, the MRs get destroyed once the QP has drained. */ /* On error, the MRs get destroyed once the QP has drained. */
trace_xprtrdma_post_linv_err(req, rc); trace_xprtrdma_post_linv_err(req, rc);
/* Force a connection loss to ensure complete recovery.
*/
rpcrdma_force_disconnect(ep);
} }
/** /**
...@@ -653,4 +661,8 @@ void frwr_unmap_async(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req) ...@@ -653,4 +661,8 @@ void frwr_unmap_async(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
* retransmission. * retransmission.
*/ */
rpcrdma_unpin_rqst(req->rl_reply); rpcrdma_unpin_rqst(req->rl_reply);
/* Force a connection loss to ensure complete recovery.
*/
rpcrdma_force_disconnect(ep);
} }
...@@ -250,12 +250,9 @@ xprt_rdma_connect_worker(struct work_struct *work) ...@@ -250,12 +250,9 @@ xprt_rdma_connect_worker(struct work_struct *work)
xprt->stat.connect_start; xprt->stat.connect_start;
xprt_set_connected(xprt); xprt_set_connected(xprt);
rc = -EAGAIN; rc = -EAGAIN;
} else { } else
/* Force a call to xprt_rdma_close to clean up */ rpcrdma_xprt_disconnect(r_xprt);
spin_lock(&xprt->transport_lock); xprt_unlock_connect(xprt, r_xprt);
set_bit(XPRT_CLOSE_WAIT, &xprt->state);
spin_unlock(&xprt->transport_lock);
}
xprt_wake_pending_tasks(xprt, rc); xprt_wake_pending_tasks(xprt, rc);
} }
...@@ -489,6 +486,8 @@ xprt_rdma_connect(struct rpc_xprt *xprt, struct rpc_task *task) ...@@ -489,6 +486,8 @@ xprt_rdma_connect(struct rpc_xprt *xprt, struct rpc_task *task)
struct rpcrdma_ep *ep = r_xprt->rx_ep; struct rpcrdma_ep *ep = r_xprt->rx_ep;
unsigned long delay; unsigned long delay;
WARN_ON_ONCE(!xprt_lock_connect(xprt, task, r_xprt));
delay = 0; delay = 0;
if (ep && ep->re_connect_status != 0) { if (ep && ep->re_connect_status != 0) {
delay = xprt_reconnect_delay(xprt); delay = xprt_reconnect_delay(xprt);
...@@ -661,7 +660,7 @@ xprt_rdma_send_request(struct rpc_rqst *rqst) ...@@ -661,7 +660,7 @@ xprt_rdma_send_request(struct rpc_rqst *rqst)
goto drop_connection; goto drop_connection;
rqst->rq_xtime = ktime_get(); rqst->rq_xtime = ktime_get();
if (rpcrdma_post_sends(r_xprt, req)) if (frwr_send(r_xprt, req))
goto drop_connection; goto drop_connection;
rqst->rq_xmit_bytes_sent += rqst->rq_snd_buf.len; rqst->rq_xmit_bytes_sent += rqst->rq_snd_buf.len;
......
...@@ -124,7 +124,7 @@ static void rpcrdma_xprt_drain(struct rpcrdma_xprt *r_xprt) ...@@ -124,7 +124,7 @@ static void rpcrdma_xprt_drain(struct rpcrdma_xprt *r_xprt)
* connection is closed or lost. (The important thing is it needs * connection is closed or lost. (The important thing is it needs
* to be invoked "at least" once). * to be invoked "at least" once).
*/ */
static void rpcrdma_force_disconnect(struct rpcrdma_ep *ep) void rpcrdma_force_disconnect(struct rpcrdma_ep *ep)
{ {
if (atomic_add_unless(&ep->re_force_disconnect, 1, 1)) if (atomic_add_unless(&ep->re_force_disconnect, 1, 1))
xprt_force_disconnect(ep->re_xprt); xprt_force_disconnect(ep->re_xprt);
...@@ -1349,21 +1349,6 @@ static void rpcrdma_regbuf_free(struct rpcrdma_regbuf *rb) ...@@ -1349,21 +1349,6 @@ static void rpcrdma_regbuf_free(struct rpcrdma_regbuf *rb)
kfree(rb); kfree(rb);
} }
/**
* rpcrdma_post_sends - Post WRs to a transport's Send Queue
* @r_xprt: controlling transport instance
* @req: rpcrdma_req containing the Send WR to post
*
* Returns 0 if the post was successful, otherwise -ENOTCONN
* is returned.
*/
int rpcrdma_post_sends(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
{
if (frwr_send(r_xprt, req))
return -ENOTCONN;
return 0;
}
/** /**
* rpcrdma_post_recvs - Refill the Receive Queue * rpcrdma_post_recvs - Refill the Receive Queue
* @r_xprt: controlling transport instance * @r_xprt: controlling transport instance
...@@ -1416,12 +1401,8 @@ void rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, int needed, bool temp) ...@@ -1416,12 +1401,8 @@ void rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, int needed, bool temp)
rc = ib_post_recv(ep->re_id->qp, wr, rc = ib_post_recv(ep->re_id->qp, wr,
(const struct ib_recv_wr **)&bad_wr); (const struct ib_recv_wr **)&bad_wr);
if (atomic_dec_return(&ep->re_receiving) > 0)
complete(&ep->re_done);
out:
trace_xprtrdma_post_recvs(r_xprt, count, rc);
if (rc) { if (rc) {
trace_xprtrdma_post_recvs_err(r_xprt, rc);
for (wr = bad_wr; wr;) { for (wr = bad_wr; wr;) {
struct rpcrdma_rep *rep; struct rpcrdma_rep *rep;
...@@ -1431,6 +1412,11 @@ void rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, int needed, bool temp) ...@@ -1431,6 +1412,11 @@ void rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, int needed, bool temp)
--count; --count;
} }
} }
if (atomic_dec_return(&ep->re_receiving) > 0)
complete(&ep->re_done);
out:
trace_xprtrdma_post_recvs(r_xprt, count);
ep->re_receive_count += count; ep->re_receive_count += count;
return; return;
} }
...@@ -454,11 +454,11 @@ extern unsigned int xprt_rdma_memreg_strategy; ...@@ -454,11 +454,11 @@ extern unsigned int xprt_rdma_memreg_strategy;
/* /*
* Endpoint calls - xprtrdma/verbs.c * Endpoint calls - xprtrdma/verbs.c
*/ */
void rpcrdma_force_disconnect(struct rpcrdma_ep *ep);
void rpcrdma_flush_disconnect(struct rpcrdma_xprt *r_xprt, struct ib_wc *wc); void rpcrdma_flush_disconnect(struct rpcrdma_xprt *r_xprt, struct ib_wc *wc);
int rpcrdma_xprt_connect(struct rpcrdma_xprt *r_xprt); int rpcrdma_xprt_connect(struct rpcrdma_xprt *r_xprt);
void rpcrdma_xprt_disconnect(struct rpcrdma_xprt *r_xprt); void rpcrdma_xprt_disconnect(struct rpcrdma_xprt *r_xprt);
int rpcrdma_post_sends(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req);
void rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, int needed, bool temp); void rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, int needed, bool temp);
/* /*
......
...@@ -1656,7 +1656,7 @@ static int xs_get_srcport(struct sock_xprt *transport) ...@@ -1656,7 +1656,7 @@ static int xs_get_srcport(struct sock_xprt *transport)
unsigned short get_srcport(struct rpc_xprt *xprt) unsigned short get_srcport(struct rpc_xprt *xprt)
{ {
struct sock_xprt *sock = container_of(xprt, struct sock_xprt, xprt); struct sock_xprt *sock = container_of(xprt, struct sock_xprt, xprt);
return sock->srcport; return xs_sock_getport(sock->sock);
} }
EXPORT_SYMBOL(get_srcport); EXPORT_SYMBOL(get_srcport);
...@@ -2099,13 +2099,20 @@ static void xs_tcp_shutdown(struct rpc_xprt *xprt) ...@@ -2099,13 +2099,20 @@ static void xs_tcp_shutdown(struct rpc_xprt *xprt)
if (sock == NULL) if (sock == NULL)
return; return;
if (!xprt->reuseport) {
xs_close(xprt);
return;
}
switch (skst) { switch (skst) {
default: case TCP_FIN_WAIT1:
case TCP_FIN_WAIT2:
break;
case TCP_ESTABLISHED:
case TCP_CLOSE_WAIT:
kernel_sock_shutdown(sock, SHUT_RDWR); kernel_sock_shutdown(sock, SHUT_RDWR);
trace_rpc_socket_shutdown(xprt, sock); trace_rpc_socket_shutdown(xprt, sock);
break; break;
case TCP_CLOSE: default:
case TCP_TIME_WAIT:
xs_reset_transport(transport); xs_reset_transport(transport);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment