summaryrefslogtreecommitdiff
path: root/net/sunrpc
diff options
context:
space:
mode:
Diffstat (limited to 'net/sunrpc')
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c59
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_unseal.c8
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_wrap.c10
-rw-r--r--net/sunrpc/auth_gss/gss_rpc_upcall.c3
-rw-r--r--net/sunrpc/auth_gss/gss_rpc_xdr.c29
-rw-r--r--net/sunrpc/auth_gss/svcauth_gss.c4
-rw-r--r--net/sunrpc/clnt.c177
-rw-r--r--net/sunrpc/rpc_pipe.c23
-rw-r--r--net/sunrpc/svc.c2
-rw-r--r--net/sunrpc/svcsock.c4
-rw-r--r--net/sunrpc/xprt.c63
-rw-r--r--net/sunrpc/xprtsock.c75
12 files changed, 146 insertions, 311 deletions
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 42fdfc6..0846566 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -420,53 +420,41 @@ static void gss_encode_v0_msg(struct gss_upcall_msg *gss_msg)
memcpy(gss_msg->databuf, &uid, sizeof(uid));
gss_msg->msg.data = gss_msg->databuf;
gss_msg->msg.len = sizeof(uid);
-
- BUILD_BUG_ON(sizeof(uid) > sizeof(gss_msg->databuf));
+ BUG_ON(sizeof(uid) > UPCALL_BUF_LEN);
}
-static int gss_encode_v1_msg(struct gss_upcall_msg *gss_msg,
+static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg,
const char *service_name,
const char *target_name)
{
struct gss_api_mech *mech = gss_msg->auth->mech;
char *p = gss_msg->databuf;
- size_t buflen = sizeof(gss_msg->databuf);
- int len;
-
- len = scnprintf(p, buflen, "mech=%s uid=%d ", mech->gm_name,
- from_kuid(&init_user_ns, gss_msg->uid));
- buflen -= len;
- p += len;
- gss_msg->msg.len = len;
+ int len = 0;
+
+ gss_msg->msg.len = sprintf(gss_msg->databuf, "mech=%s uid=%d ",
+ mech->gm_name,
+ from_kuid(&init_user_ns, gss_msg->uid));
+ p += gss_msg->msg.len;
if (target_name) {
- len = scnprintf(p, buflen, "target=%s ", target_name);
- buflen -= len;
+ len = sprintf(p, "target=%s ", target_name);
p += len;
gss_msg->msg.len += len;
}
if (service_name != NULL) {
- len = scnprintf(p, buflen, "service=%s ", service_name);
- buflen -= len;
+ len = sprintf(p, "service=%s ", service_name);
p += len;
gss_msg->msg.len += len;
}
if (mech->gm_upcall_enctypes) {
- len = scnprintf(p, buflen, "enctypes=%s ",
- mech->gm_upcall_enctypes);
- buflen -= len;
+ len = sprintf(p, "enctypes=%s ", mech->gm_upcall_enctypes);
p += len;
gss_msg->msg.len += len;
}
- len = scnprintf(p, buflen, "\n");
- if (len == 0)
- goto out_overflow;
+ len = sprintf(p, "\n");
gss_msg->msg.len += len;
gss_msg->msg.data = gss_msg->databuf;
- return 0;
-out_overflow:
- WARN_ON_ONCE(1);
- return -ENOMEM;
+ BUG_ON(gss_msg->msg.len > UPCALL_BUF_LEN);
}
static struct gss_upcall_msg *
@@ -475,15 +463,15 @@ gss_alloc_msg(struct gss_auth *gss_auth,
{
struct gss_upcall_msg *gss_msg;
int vers;
- int err = -ENOMEM;
gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS);
if (gss_msg == NULL)
- goto err;
+ return ERR_PTR(-ENOMEM);
vers = get_pipe_version(gss_auth->net);
- err = vers;
- if (err < 0)
- goto err_free_msg;
+ if (vers < 0) {
+ kfree(gss_msg);
+ return ERR_PTR(vers);
+ }
gss_msg->pipe = gss_auth->gss_pipe[vers]->pipe;
INIT_LIST_HEAD(&gss_msg->list);
rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq");
@@ -494,17 +482,10 @@ gss_alloc_msg(struct gss_auth *gss_auth,
switch (vers) {
case 0:
gss_encode_v0_msg(gss_msg);
- break;
default:
- err = gss_encode_v1_msg(gss_msg, service_name, gss_auth->target_name);
- if (err)
- goto err_free_msg;
+ gss_encode_v1_msg(gss_msg, service_name, gss_auth->target_name);
};
return gss_msg;
-err_free_msg:
- kfree(gss_msg);
-err:
- return ERR_PTR(err);
}
static struct gss_upcall_msg *
@@ -1517,7 +1498,7 @@ out:
static int
gss_refresh_null(struct rpc_task *task)
{
- return 0;
+ return -EACCES;
}
static __be32 *
diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c
index 6c981dd..6cd930f 100644
--- a/net/sunrpc/auth_gss/gss_krb5_unseal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c
@@ -150,6 +150,7 @@ gss_verify_mic_v2(struct krb5_ctx *ctx,
struct xdr_netobj cksumobj = {.len = sizeof(cksumdata),
.data = cksumdata};
s32 now;
+ u64 seqnum;
u8 *ptr = read_token->data;
u8 *cksumkey;
u8 flags;
@@ -196,10 +197,9 @@ gss_verify_mic_v2(struct krb5_ctx *ctx,
if (now > ctx->endtime)
return GSS_S_CONTEXT_EXPIRED;
- /*
- * NOTE: the sequence number at ptr + 8 is skipped, rpcsec_gss
- * doesn't want it checked; see page 6 of rfc 2203.
- */
+ /* do sequencing checks */
+
+ seqnum = be64_to_cpup((__be64 *)ptr + 8);
return GSS_S_COMPLETE;
}
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index 42560e5..1da52d1 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -489,6 +489,7 @@ static u32
gss_unwrap_kerberos_v2(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
{
s32 now;
+ u64 seqnum;
u8 *ptr;
u8 flags = 0x00;
u16 ec, rrc;
@@ -524,10 +525,7 @@ gss_unwrap_kerberos_v2(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
ec = be16_to_cpup((__be16 *)(ptr + 4));
rrc = be16_to_cpup((__be16 *)(ptr + 6));
- /*
- * NOTE: the sequence number at ptr + 8 is skipped, rpcsec_gss
- * doesn't want it checked; see page 6 of rfc 2203.
- */
+ seqnum = be64_to_cpup((__be64 *)(ptr + 8));
if (rrc != 0)
rotate_left(offset + 16, buf, rrc);
@@ -576,8 +574,8 @@ gss_unwrap_kerberos_v2(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
buf->head[0].iov_len -= GSS_KRB5_TOK_HDR_LEN + headskip;
buf->len -= GSS_KRB5_TOK_HDR_LEN + headskip;
- /* Trim off the trailing "extra count" and checksum blob */
- xdr_buf_trim(buf, ec + GSS_KRB5_TOK_HDR_LEN + tailskip);
+ /* Trim off the checksum blob */
+ xdr_buf_trim(buf, GSS_KRB5_TOK_HDR_LEN + tailskip);
return GSS_S_COMPLETE;
}
diff --git a/net/sunrpc/auth_gss/gss_rpc_upcall.c b/net/sunrpc/auth_gss/gss_rpc_upcall.c
index 458f85e..f1eb0d1 100644
--- a/net/sunrpc/auth_gss/gss_rpc_upcall.c
+++ b/net/sunrpc/auth_gss/gss_rpc_upcall.c
@@ -298,8 +298,7 @@ int gssp_accept_sec_context_upcall(struct net *net,
if (res.context_handle) {
data->out_handle = rctxh.exported_context_token;
data->mech_oid.len = rctxh.mech.len;
- if (rctxh.mech.data)
- memcpy(data->mech_oid.data, rctxh.mech.data,
+ memcpy(data->mech_oid.data, rctxh.mech.data,
data->mech_oid.len);
client_name = rctxh.src_name.display_name;
}
diff --git a/net/sunrpc/auth_gss/gss_rpc_xdr.c b/net/sunrpc/auth_gss/gss_rpc_xdr.c
index 1ec19f6..f0f78c5 100644
--- a/net/sunrpc/auth_gss/gss_rpc_xdr.c
+++ b/net/sunrpc/auth_gss/gss_rpc_xdr.c
@@ -559,8 +559,6 @@ static int gssx_enc_cred(struct xdr_stream *xdr,
/* cred->elements */
err = dummy_enc_credel_array(xdr, &cred->elements);
- if (err)
- return err;
/* cred->cred_handle_reference */
err = gssx_enc_buffer(xdr, &cred->cred_handle_reference);
@@ -742,20 +740,22 @@ void gssx_enc_accept_sec_context(struct rpc_rqst *req,
goto done;
/* arg->context_handle */
- if (arg->context_handle)
+ if (arg->context_handle) {
err = gssx_enc_ctx(xdr, arg->context_handle);
- else
+ if (err)
+ goto done;
+ } else {
err = gssx_enc_bool(xdr, 0);
- if (err)
- goto done;
+ }
/* arg->cred_handle */
- if (arg->cred_handle)
+ if (arg->cred_handle) {
err = gssx_enc_cred(xdr, arg->cred_handle);
- else
+ if (err)
+ goto done;
+ } else {
err = gssx_enc_bool(xdr, 0);
- if (err)
- goto done;
+ }
/* arg->input_token */
err = gssx_enc_in_token(xdr, &arg->input_token);
@@ -763,12 +763,13 @@ void gssx_enc_accept_sec_context(struct rpc_rqst *req,
goto done;
/* arg->input_cb */
- if (arg->input_cb)
+ if (arg->input_cb) {
err = gssx_enc_cb(xdr, arg->input_cb);
- else
+ if (err)
+ goto done;
+ } else {
err = gssx_enc_bool(xdr, 0);
- if (err)
- goto done;
+ }
err = gssx_enc_bool(xdr, arg->ret_deleg_cred);
if (err)
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 008cdad..09fb638 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -1167,8 +1167,8 @@ static int gss_proxy_save_rsc(struct cache_detail *cd,
if (!ud->found_creds) {
/* userspace seem buggy, we should always get at least a
* mapping to nobody */
- dprintk("RPC: No creds found!\n");
- goto out;
+ dprintk("RPC: No creds found, marking Negative!\n");
+ set_bit(CACHE_NEGATIVE, &rsci.h.flags);
} else {
/* steal creds */
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index f09b7db..7747960 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -25,12 +25,12 @@
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/slab.h>
-#include <linux/rcupdate.h>
#include <linux/utsname.h>
#include <linux/workqueue.h>
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/un.h>
+#include <linux/rcupdate.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/addr.h>
@@ -264,26 +264,6 @@ void rpc_clients_notifier_unregister(void)
return rpc_pipefs_notifier_unregister(&rpc_clients_block);
}
-static struct rpc_xprt *rpc_clnt_set_transport(struct rpc_clnt *clnt,
- struct rpc_xprt *xprt,
- const struct rpc_timeout *timeout)
-{
- struct rpc_xprt *old;
-
- spin_lock(&clnt->cl_lock);
- old = rcu_dereference_protected(clnt->cl_xprt,
- lockdep_is_held(&clnt->cl_lock));
-
- if (!xprt_bound(xprt))
- clnt->cl_autobind = 1;
-
- clnt->cl_timeout = timeout;
- rcu_assign_pointer(clnt->cl_xprt, xprt);
- spin_unlock(&clnt->cl_lock);
-
- return old;
-}
-
static void rpc_clnt_set_nodename(struct rpc_clnt *clnt, const char *nodename)
{
clnt->cl_nodelen = strlen(nodename);
@@ -292,13 +272,12 @@ static void rpc_clnt_set_nodename(struct rpc_clnt *clnt, const char *nodename)
memcpy(clnt->cl_nodename, nodename, clnt->cl_nodelen);
}
-static int rpc_client_register(struct rpc_clnt *clnt,
- rpc_authflavor_t pseudoflavor,
- const char *client_name)
+static int rpc_client_register(const struct rpc_create_args *args,
+ struct rpc_clnt *clnt)
{
struct rpc_auth_create_args auth_args = {
- .pseudoflavor = pseudoflavor,
- .target_name = client_name,
+ .pseudoflavor = args->authflavor,
+ .target_name = args->client_name,
};
struct rpc_auth *auth;
struct net *net = rpc_net_ns(clnt);
@@ -319,7 +298,7 @@ static int rpc_client_register(struct rpc_clnt *clnt,
auth = rpcauth_create(&auth_args, clnt);
if (IS_ERR(auth)) {
dprintk("RPC: Couldn't create auth handle (flavor %u)\n",
- pseudoflavor);
+ args->authflavor);
err = PTR_ERR(auth);
goto err_auth;
}
@@ -358,8 +337,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args,
{
const struct rpc_program *program = args->program;
const struct rpc_version *version;
- struct rpc_clnt *clnt = NULL;
- const struct rpc_timeout *timeout;
+ struct rpc_clnt *clnt = NULL;
int err;
/* sanity check the name before trying to print it */
@@ -387,6 +365,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args,
if (err)
goto out_no_clid;
+ rcu_assign_pointer(clnt->cl_xprt, xprt);
clnt->cl_procinfo = version->procs;
clnt->cl_maxproc = version->nrprocs;
clnt->cl_prog = args->prognumber ? : program->number;
@@ -401,15 +380,16 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args,
INIT_LIST_HEAD(&clnt->cl_tasks);
spin_lock_init(&clnt->cl_lock);
- timeout = xprt->timeout;
+ if (!xprt_bound(xprt))
+ clnt->cl_autobind = 1;
+
+ clnt->cl_timeout = xprt->timeout;
if (args->timeout != NULL) {
memcpy(&clnt->cl_timeout_default, args->timeout,
sizeof(clnt->cl_timeout_default));
- timeout = &clnt->cl_timeout_default;
+ clnt->cl_timeout = &clnt->cl_timeout_default;
}
- rpc_clnt_set_transport(clnt, xprt, timeout);
-
clnt->cl_rtt = &clnt->cl_rtt_default;
rpc_init_rtt(&clnt->cl_rtt_default, clnt->cl_timeout->to_initval);
@@ -418,7 +398,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args,
/* save the nodename */
rpc_clnt_set_nodename(clnt, utsname()->nodename);
- err = rpc_client_register(clnt, args->authflavor, args->client_name);
+ err = rpc_client_register(args, clnt);
if (err)
goto out_no_path;
if (parent)
@@ -620,80 +600,6 @@ rpc_clone_client_set_auth(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
}
EXPORT_SYMBOL_GPL(rpc_clone_client_set_auth);
-/**
- * rpc_switch_client_transport: switch the RPC transport on the fly
- * @clnt: pointer to a struct rpc_clnt
- * @args: pointer to the new transport arguments
- * @timeout: pointer to the new timeout parameters
- *
- * This function allows the caller to switch the RPC transport for the
- * rpc_clnt structure 'clnt' to allow it to connect to a mirrored NFS
- * server, for instance. It assumes that the caller has ensured that
- * there are no active RPC tasks by using some form of locking.
- *
- * Returns zero if "clnt" is now using the new xprt. Otherwise a
- * negative errno is returned, and "clnt" continues to use the old
- * xprt.
- */
-int rpc_switch_client_transport(struct rpc_clnt *clnt,
- struct xprt_create *args,
- const struct rpc_timeout *timeout)
-{
- const struct rpc_timeout *old_timeo;
- rpc_authflavor_t pseudoflavor;
- struct rpc_xprt *xprt, *old;
- struct rpc_clnt *parent;
- int err;
-
- xprt = xprt_create_transport(args);
- if (IS_ERR(xprt)) {
- dprintk("RPC: failed to create new xprt for clnt %p\n",
- clnt);
- return PTR_ERR(xprt);
- }
-
- pseudoflavor = clnt->cl_auth->au_flavor;
-
- old_timeo = clnt->cl_timeout;
- old = rpc_clnt_set_transport(clnt, xprt, timeout);
-
- rpc_unregister_client(clnt);
- __rpc_clnt_remove_pipedir(clnt);
-
- /*
- * A new transport was created. "clnt" therefore
- * becomes the root of a new cl_parent tree. clnt's
- * children, if it has any, still point to the old xprt.
- */
- parent = clnt->cl_parent;
- clnt->cl_parent = clnt;
-
- /*
- * The old rpc_auth cache cannot be re-used. GSS
- * contexts in particular are between a single
- * client and server.
- */
- err = rpc_client_register(clnt, pseudoflavor, NULL);
- if (err)
- goto out_revert;
-
- synchronize_rcu();
- if (parent != clnt)
- rpc_release_client(parent);
- xprt_put(old);
- dprintk("RPC: replaced xprt for clnt %p\n", clnt);
- return 0;
-
-out_revert:
- rpc_clnt_set_transport(clnt, old, old_timeo);
- clnt->cl_parent = parent;
- rpc_client_register(clnt, pseudoflavor, NULL);
- xprt_put(xprt);
- dprintk("RPC: failed to switch xprt for clnt %p\n", clnt);
- return err;
-}
-EXPORT_SYMBOL_GPL(rpc_switch_client_transport);
-
/*
* Kill all tasks for the given client.
* XXX: kill their descendants as well?
@@ -750,16 +656,14 @@ EXPORT_SYMBOL_GPL(rpc_shutdown_client);
/*
* Free an RPC client
*/
-static struct rpc_clnt *
+static void
rpc_free_client(struct rpc_clnt *clnt)
{
- struct rpc_clnt *parent = NULL;
-
dprintk_rcu("RPC: destroying %s client for %s\n",
clnt->cl_program->name,
rcu_dereference(clnt->cl_xprt)->servername);
if (clnt->cl_parent != clnt)
- parent = clnt->cl_parent;
+ rpc_release_client(clnt->cl_parent);
rpc_clnt_remove_pipedir(clnt);
rpc_unregister_client(clnt);
rpc_free_iostats(clnt->cl_metrics);
@@ -768,17 +672,18 @@ rpc_free_client(struct rpc_clnt *clnt)
rpciod_down();
rpc_free_clid(clnt);
kfree(clnt);
- return parent;
}
/*
* Free an RPC client
*/
-static struct rpc_clnt *
+static void
rpc_free_auth(struct rpc_clnt *clnt)
{
- if (clnt->cl_auth == NULL)
- return rpc_free_client(clnt);
+ if (clnt->cl_auth == NULL) {
+ rpc_free_client(clnt);
+ return;
+ }
/*
* Note: RPCSEC_GSS may need to send NULL RPC calls in order to
@@ -789,8 +694,7 @@ rpc_free_auth(struct rpc_clnt *clnt)
rpcauth_release(clnt->cl_auth);
clnt->cl_auth = NULL;
if (atomic_dec_and_test(&clnt->cl_count))
- return rpc_free_client(clnt);
- return NULL;
+ rpc_free_client(clnt);
}
/*
@@ -801,13 +705,10 @@ rpc_release_client(struct rpc_clnt *clnt)
{
dprintk("RPC: rpc_release_client(%p)\n", clnt);
- do {
- if (list_empty(&clnt->cl_tasks))
- wake_up(&destroy_wait);
- if (!atomic_dec_and_test(&clnt->cl_count))
- break;
- clnt = rpc_free_auth(clnt);
- } while (clnt != NULL);
+ if (list_empty(&clnt->cl_tasks))
+ wake_up(&destroy_wait);
+ if (atomic_dec_and_test(&clnt->cl_count))
+ rpc_free_auth(clnt);
}
EXPORT_SYMBOL_GPL(rpc_release_client);
@@ -871,8 +772,6 @@ void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt)
atomic_inc(&clnt->cl_count);
if (clnt->cl_softrtry)
task->tk_flags |= RPC_TASK_SOFT;
- if (clnt->cl_noretranstimeo)
- task->tk_flags |= RPC_TASK_NO_RETRANS_TIMEOUT;
if (sk_memalloc_socks()) {
struct rpc_xprt *xprt;
@@ -1791,7 +1690,6 @@ call_connect_status(struct rpc_task *task)
dprint_status(task);
trace_rpc_connect_status(task, status);
- task->tk_status = 0;
switch (status) {
/* if soft mounted, test if we've timed out */
case -ETIMEDOUT:
@@ -1800,14 +1698,12 @@ call_connect_status(struct rpc_task *task)
case -ECONNREFUSED:
case -ECONNRESET:
case -ENETUNREACH:
- /* retry with existing socket, after a delay */
- rpc_delay(task, 3*HZ);
if (RPC_IS_SOFTCONN(task))
break;
- case -EAGAIN:
- task->tk_action = call_bind;
- return;
+ /* retry with existing socket, after a delay */
case 0:
+ case -EAGAIN:
+ task->tk_status = 0;
clnt->cl_stats->netreconn++;
task->tk_action = call_transmit;
return;
@@ -1821,14 +1717,13 @@ call_connect_status(struct rpc_task *task)
static void
call_transmit(struct rpc_task *task)
{
- int is_retrans = RPC_WAS_SENT(task);
-
dprint_status(task);
task->tk_action = call_status;
if (task->tk_status < 0)
return;
- if (!xprt_prepare_transmit(task))
+ task->tk_status = xprt_prepare_transmit(task);
+ if (task->tk_status != 0)
return;
task->tk_action = call_transmit_status;
/* Encode here so that rpcsec_gss can use correct sequence number. */
@@ -1847,8 +1742,6 @@ call_transmit(struct rpc_task *task)
xprt_transmit(task);
if (task->tk_status < 0)
return;
- if (is_retrans)
- task->tk_client->cl_stats->rpcretrans++;
/*
* On success, ensure that we call xprt_end_transmit() before sleeping
* in order to allow access to the socket to other RPC requests.
@@ -1918,7 +1811,8 @@ call_bc_transmit(struct rpc_task *task)
{
struct rpc_rqst *req = task->tk_rqstp;
- if (!xprt_prepare_transmit(task)) {
+ task->tk_status = xprt_prepare_transmit(task);
+ if (task->tk_status == -EAGAIN) {
/*
* Could not reserve the transport. Try again after the
* transport is released.
@@ -2006,8 +1900,7 @@ call_status(struct rpc_task *task)
rpc_delay(task, 3*HZ);
case -ETIMEDOUT:
task->tk_action = call_timeout;
- if (!(task->tk_flags & RPC_TASK_NO_RETRANS_TIMEOUT)
- && task->tk_client->cl_discrtry)
+ if (task->tk_client->cl_discrtry)
xprt_conditional_disconnect(req->rq_xprt,
req->rq_connect_cookie);
break;
@@ -2089,6 +1982,7 @@ call_timeout(struct rpc_task *task)
rpcauth_invalcred(task);
retry:
+ clnt->cl_stats->rpcretrans++;
task->tk_action = call_bind;
task->tk_status = 0;
}
@@ -2131,6 +2025,7 @@ call_decode(struct rpc_task *task)
if (req->rq_rcv_buf.len < 12) {
if (!RPC_IS_SOFT(task)) {
task->tk_action = call_bind;
+ clnt->cl_stats->rpcretrans++;
goto out_retry;
}
dprintk("RPC: %s: too small RPC reply size (%d bytes)\n",
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index bf04b30..f94567b 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -471,6 +471,15 @@ struct rpc_filelist {
umode_t mode;
};
+static int rpc_delete_dentry(const struct dentry *dentry)
+{
+ return 1;
+}
+
+static const struct dentry_operations rpc_dentry_operations = {
+ .d_delete = rpc_delete_dentry,
+};
+
static struct inode *
rpc_get_inode(struct super_block *sb, umode_t mode)
{
@@ -510,8 +519,8 @@ static int __rpc_create_common(struct inode *dir, struct dentry *dentry,
d_add(dentry, inode);
return 0;
out_err:
- printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %pd\n",
- __FILE__, __func__, dentry);
+ printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n",
+ __FILE__, __func__, dentry->d_name.name);
dput(dentry);
return -ENOMEM;
}
@@ -746,8 +755,8 @@ static int rpc_populate(struct dentry *parent,
out_bad:
__rpc_depopulate(parent, files, start, eof);
mutex_unlock(&dir->i_mutex);
- printk(KERN_WARNING "%s: %s failed to populate directory %pd\n",
- __FILE__, __func__, parent);
+ printk(KERN_WARNING "%s: %s failed to populate directory %s\n",
+ __FILE__, __func__, parent->d_name.name);
return err;
}
@@ -843,8 +852,8 @@ out:
return dentry;
out_err:
dentry = ERR_PTR(err);
- printk(KERN_WARNING "%s: %s() failed to create pipe %pd/%s (errno = %d)\n",
- __FILE__, __func__, parent, name,
+ printk(KERN_WARNING "%s: %s() failed to create pipe %s/%s (errno = %d)\n",
+ __FILE__, __func__, parent->d_name.name, name,
err);
goto out;
}
@@ -1257,7 +1266,7 @@ rpc_fill_super(struct super_block *sb, void *data, int silent)
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
sb->s_magic = RPCAUTH_GSSMAGIC;
sb->s_op = &s_ops;
- sb->s_d_op = &simple_dentry_operations;
+ sb->s_d_op = &rpc_dentry_operations;
sb->s_time_gran = 1;
inode = rpc_get_inode(sb, S_IFDIR | S_IRUGO | S_IXUGO);
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index e7fbe36..b974571 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -1104,6 +1104,8 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
rqstp->rq_vers = vers = svc_getnl(argv); /* version number */
rqstp->rq_proc = proc = svc_getnl(argv); /* procedure number */
+ progp = serv->sv_program;
+
for (progp = serv->sv_program; progp; progp = progp->pg_next)
if (prog == progp->pg_prog)
break;
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index b6e59f0..9c9caaa 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -291,14 +291,12 @@ static int svc_one_sock_name(struct svc_sock *svsk, char *buf, int remaining)
&inet_sk(sk)->inet_rcv_saddr,
inet_sk(sk)->inet_num);
break;
-#if IS_ENABLED(CONFIG_IPV6)
case PF_INET6:
len = snprintf(buf, remaining, "ipv6 %s %pI6 %d\n",
proto_name,
- &sk->sk_v6_rcv_saddr,
+ &inet6_sk(sk)->rcv_saddr,
inet_sk(sk)->inet_num);
break;
-#endif
default:
len = snprintf(buf, remaining, "*unknown-%d*\n",
sk->sk_family);
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 04199bc..095363e 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -205,8 +205,10 @@ int xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task)
goto out_sleep;
}
xprt->snd_task = task;
- if (req != NULL)
+ if (req != NULL) {
+ req->rq_bytes_sent = 0;
req->rq_ntrans++;
+ }
return 1;
@@ -261,6 +263,7 @@ int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task)
}
if (__xprt_get_cong(xprt, task)) {
xprt->snd_task = task;
+ req->rq_bytes_sent = 0;
req->rq_ntrans++;
return 1;
}
@@ -297,8 +300,10 @@ static bool __xprt_lock_write_func(struct rpc_task *task, void *data)
req = task->tk_rqstp;
xprt->snd_task = task;
- if (req)
+ if (req) {
+ req->rq_bytes_sent = 0;
req->rq_ntrans++;
+ }
return true;
}
@@ -324,6 +329,7 @@ static bool __xprt_lock_write_cong_func(struct rpc_task *task, void *data)
}
if (__xprt_get_cong(xprt, task)) {
xprt->snd_task = task;
+ req->rq_bytes_sent = 0;
req->rq_ntrans++;
return true;
}
@@ -352,11 +358,6 @@ out_unlock:
void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task)
{
if (xprt->snd_task == task) {
- if (task != NULL) {
- struct rpc_rqst *req = task->tk_rqstp;
- if (req != NULL)
- req->rq_bytes_sent = 0;
- }
xprt_clear_locked(xprt);
__xprt_lock_write_next(xprt);
}
@@ -374,11 +375,6 @@ EXPORT_SYMBOL_GPL(xprt_release_xprt);
void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task)
{
if (xprt->snd_task == task) {
- if (task != NULL) {
- struct rpc_rqst *req = task->tk_rqstp;
- if (req != NULL)
- req->rq_bytes_sent = 0;
- }
xprt_clear_locked(xprt);
__xprt_lock_write_next_cong(xprt);
}
@@ -858,36 +854,24 @@ static inline int xprt_has_timer(struct rpc_xprt *xprt)
* @task: RPC task about to send a request
*
*/
-bool xprt_prepare_transmit(struct rpc_task *task)
+int xprt_prepare_transmit(struct rpc_task *task)
{
struct rpc_rqst *req = task->tk_rqstp;
struct rpc_xprt *xprt = req->rq_xprt;
- bool ret = false;
+ int err = 0;
dprintk("RPC: %5u xprt_prepare_transmit\n", task->tk_pid);
spin_lock_bh(&xprt->transport_lock);
- if (!req->rq_bytes_sent) {
- if (req->rq_reply_bytes_recvd) {
- task->tk_status = req->rq_reply_bytes_recvd;
- goto out_unlock;
- }
- if ((task->tk_flags & RPC_TASK_NO_RETRANS_TIMEOUT)
- && xprt_connected(xprt)
- && req->rq_connect_cookie == xprt->connect_cookie) {
- xprt->ops->set_retrans_timeout(task);
- rpc_sleep_on(&xprt->pending, task, xprt_timer);
- goto out_unlock;
- }
- }
- if (!xprt->ops->reserve_xprt(xprt, task)) {
- task->tk_status = -EAGAIN;
+ if (req->rq_reply_bytes_recvd && !req->rq_bytes_sent) {
+ err = req->rq_reply_bytes_recvd;
goto out_unlock;
}
- ret = true;
+ if (!xprt->ops->reserve_xprt(xprt, task))
+ err = -EAGAIN;
out_unlock:
spin_unlock_bh(&xprt->transport_lock);
- return ret;
+ return err;
}
void xprt_end_transmit(struct rpc_task *task)
@@ -928,6 +912,7 @@ void xprt_transmit(struct rpc_task *task)
} else if (!req->rq_bytes_sent)
return;
+ req->rq_connect_cookie = xprt->connect_cookie;
req->rq_xtime = ktime_get();
status = xprt->ops->send_request(task);
if (status != 0) {
@@ -953,14 +938,12 @@ void xprt_transmit(struct rpc_task *task)
/* Don't race with disconnect */
if (!xprt_connected(xprt))
task->tk_status = -ENOTCONN;
- else {
+ else if (!req->rq_reply_bytes_recvd && rpc_reply_expected(task)) {
/*
* Sleep on the pending queue since
* we're expecting a reply.
*/
- if (!req->rq_reply_bytes_recvd && rpc_reply_expected(task))
- rpc_sleep_on(&xprt->pending, task, xprt_timer);
- req->rq_connect_cookie = xprt->connect_cookie;
+ rpc_sleep_on(&xprt->pending, task, xprt_timer);
}
spin_unlock_bh(&xprt->transport_lock);
}
@@ -1104,9 +1087,11 @@ struct rpc_xprt *xprt_alloc(struct net *net, size_t size,
for (i = 0; i < num_prealloc; i++) {
req = kzalloc(sizeof(struct rpc_rqst), GFP_KERNEL);
if (!req)
- goto out_free;
+ break;
list_add(&req->rq_list, &xprt->free);
}
+ if (i < num_prealloc)
+ goto out_free;
if (max_alloc > num_prealloc)
xprt->max_reqs = max_alloc;
else
@@ -1201,12 +1186,6 @@ static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt)
req->rq_xprt = xprt;
req->rq_buffer = NULL;
req->rq_xid = xprt_alloc_xid(xprt);
- req->rq_connect_cookie = xprt->connect_cookie - 1;
- req->rq_bytes_sent = 0;
- req->rq_snd_buf.len = 0;
- req->rq_snd_buf.buflen = 0;
- req->rq_rcv_buf.len = 0;
- req->rq_rcv_buf.buflen = 0;
req->rq_release_snd_buf = NULL;
xprt_reset_majortimeo(req);
dprintk("RPC: %5u reserved req %p xid %08x\n", task->tk_pid,
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index dd9d295..ee03d35 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -393,10 +393,8 @@ static int xs_send_kvec(struct socket *sock, struct sockaddr *addr, int addrlen,
return kernel_sendmsg(sock, &msg, NULL, 0, 0);
}
-static int xs_send_pagedata(struct socket *sock, struct xdr_buf *xdr, unsigned int base, int more, bool zerocopy)
+static int xs_send_pagedata(struct socket *sock, struct xdr_buf *xdr, unsigned int base, int more)
{
- ssize_t (*do_sendpage)(struct socket *sock, struct page *page,
- int offset, size_t size, int flags);
struct page **ppage;
unsigned int remainder;
int err, sent = 0;
@@ -405,9 +403,6 @@ static int xs_send_pagedata(struct socket *sock, struct xdr_buf *xdr, unsigned i
base += xdr->page_base;
ppage = xdr->pages + (base >> PAGE_SHIFT);
base &= ~PAGE_MASK;
- do_sendpage = sock->ops->sendpage;
- if (!zerocopy)
- do_sendpage = sock_no_sendpage;
for(;;) {
unsigned int len = min_t(unsigned int, PAGE_SIZE - base, remainder);
int flags = XS_SENDMSG_FLAGS;
@@ -415,7 +410,7 @@ static int xs_send_pagedata(struct socket *sock, struct xdr_buf *xdr, unsigned i
remainder -= len;
if (remainder != 0 || more)
flags |= MSG_MORE;
- err = do_sendpage(sock, *ppage, base, len, flags);
+ err = sock->ops->sendpage(sock, *ppage, base, len, flags);
if (remainder == 0 || err != len)
break;
sent += err;
@@ -436,10 +431,9 @@ static int xs_send_pagedata(struct socket *sock, struct xdr_buf *xdr, unsigned i
* @addrlen: UDP only -- length of destination address
* @xdr: buffer containing this request
* @base: starting position in the buffer
- * @zerocopy: true if it is safe to use sendpage()
*
*/
-static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, struct xdr_buf *xdr, unsigned int base, bool zerocopy)
+static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, struct xdr_buf *xdr, unsigned int base)
{
unsigned int remainder = xdr->len - base;
int err, sent = 0;
@@ -467,7 +461,7 @@ static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen,
if (base < xdr->page_len) {
unsigned int len = xdr->page_len - base;
remainder -= len;
- err = xs_send_pagedata(sock, xdr, base, remainder != 0, zerocopy);
+ err = xs_send_pagedata(sock, xdr, base, remainder != 0);
if (remainder == 0 || err != len)
goto out;
sent += err;
@@ -570,7 +564,7 @@ static int xs_local_send_request(struct rpc_task *task)
req->rq_svec->iov_base, req->rq_svec->iov_len);
status = xs_sendpages(transport->sock, NULL, 0,
- xdr, req->rq_bytes_sent, true);
+ xdr, req->rq_bytes_sent);
dprintk("RPC: %s(%u) = %d\n",
__func__, xdr->len - req->rq_bytes_sent, status);
if (likely(status >= 0)) {
@@ -626,7 +620,7 @@ static int xs_udp_send_request(struct rpc_task *task)
status = xs_sendpages(transport->sock,
xs_addr(xprt),
xprt->addrlen, xdr,
- req->rq_bytes_sent, true);
+ req->rq_bytes_sent);
dprintk("RPC: xs_udp_send_request(%u) = %d\n",
xdr->len - req->rq_bytes_sent, status);
@@ -699,7 +693,6 @@ static int xs_tcp_send_request(struct rpc_task *task)
struct rpc_xprt *xprt = req->rq_xprt;
struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
struct xdr_buf *xdr = &req->rq_snd_buf;
- bool zerocopy = true;
int status;
xs_encode_stream_record_marker(&req->rq_snd_buf);
@@ -707,20 +700,13 @@ static int xs_tcp_send_request(struct rpc_task *task)
xs_pktdump("packet data:",
req->rq_svec->iov_base,
req->rq_svec->iov_len);
- /* Don't use zero copy if this is a resend. If the RPC call
- * completes while the socket holds a reference to the pages,
- * then we may end up resending corrupted data.
- */
- if (task->tk_flags & RPC_TASK_SENT)
- zerocopy = false;
/* Continue transmitting the packet/record. We must be careful
* to cope with writespace callbacks arriving _after_ we have
* called sendmsg(). */
while (1) {
status = xs_sendpages(transport->sock,
- NULL, 0, xdr, req->rq_bytes_sent,
- zerocopy);
+ NULL, 0, xdr, req->rq_bytes_sent);
dprintk("RPC: xs_tcp_send_request(%u) = %d\n",
xdr->len - req->rq_bytes_sent, status);
@@ -849,8 +835,6 @@ static void xs_close(struct rpc_xprt *xprt)
dprintk("RPC: xs_close xprt %p\n", xprt);
- cancel_delayed_work_sync(&transport->connect_worker);
-
xs_reset_transport(transport);
xprt->reestablish_timeout = 0;
@@ -870,6 +854,14 @@ static void xs_tcp_close(struct rpc_xprt *xprt)
xs_tcp_shutdown(xprt);
}
+static void xs_local_destroy(struct rpc_xprt *xprt)
+{
+ xs_close(xprt);
+ xs_free_peer_addresses(xprt);
+ xprt_free(xprt);
+ module_put(THIS_MODULE);
+}
+
/**
* xs_destroy - prepare to shutdown a transport
* @xprt: doomed transport
@@ -877,12 +869,13 @@ static void xs_tcp_close(struct rpc_xprt *xprt)
*/
static void xs_destroy(struct rpc_xprt *xprt)
{
+ struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
+
dprintk("RPC: xs_destroy xprt %p\n", xprt);
- xs_close(xprt);
- xs_free_peer_addresses(xprt);
- xprt_free(xprt);
- module_put(THIS_MODULE);
+ cancel_delayed_work_sync(&transport->connect_worker);
+
+ xs_local_destroy(xprt);
}
static inline struct rpc_xprt *xprt_from_sock(struct sock *sk)
@@ -1518,7 +1511,6 @@ static void xs_tcp_state_change(struct sock *sk)
transport->tcp_copied = 0;
transport->tcp_flags =
TCP_RCV_COPY_FRAGHDR | TCP_RCV_COPY_XID;
- xprt->connect_cookie++;
xprt_wake_pending_tasks(xprt, -EAGAIN);
}
@@ -1824,10 +1816,6 @@ static inline void xs_reclassify_socket(int family, struct socket *sock)
}
#endif
-static void xs_dummy_setup_socket(struct work_struct *work)
-{
-}
-
static struct socket *xs_create_sock(struct rpc_xprt *xprt,
struct sock_xprt *transport, int family, int type, int protocol)
{
@@ -2124,19 +2112,6 @@ 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;
-
- /* 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));
write_lock_bh(&sk->sk_callback_lock);
@@ -2176,6 +2151,7 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
case 0:
case -EINPROGRESS:
/* SYN_SENT! */
+ xprt->connect_cookie++;
if (xprt->reestablish_timeout < XS_TCP_INIT_REEST_TO)
xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO;
}
@@ -2522,7 +2498,7 @@ static struct rpc_xprt_ops xs_local_ops = {
.send_request = xs_local_send_request,
.set_retrans_timeout = xprt_set_retrans_timeout_def,
.close = xs_close,
- .destroy = xs_destroy,
+ .destroy = xs_local_destroy,
.print_stats = xs_local_print_stats,
};
@@ -2679,9 +2655,6 @@ static struct rpc_xprt *xs_setup_local(struct xprt_create *args)
xprt->ops = &xs_local_ops;
xprt->timeout = &xs_local_default_timeout;
- INIT_DELAYED_WORK(&transport->connect_worker,
- xs_dummy_setup_socket);
-
switch (sun->sun_family) {
case AF_LOCAL:
if (sun->sun_path[0] != '/') {
@@ -2886,8 +2859,8 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
if (args->bc_xprt->xpt_bc_xprt) {
/*
* This server connection already has a backchannel
- * transport; we can't create a new one, as we wouldn't
- * be able to match replies based on xid any more. So,
+ * export; we can't create a new one, as we wouldn't be
+ * able to match replies based on xid any more. So,
* reuse the already-existing one:
*/
return args->bc_xprt->xpt_bc_xprt;