mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-10-26 10:57:38 +08:00
Pull nfsd updates from Chuck Lever: "Jeff Layton extended the netlink listener-set operation so that a management daemon can register NFSD's programs with rpcbind itself. This prevents an unresponsive rpcbind from stalling NFSD administration for a minute at a time. Bulk delegation recall now adjusts the number of delegations it wants returned, based on memory pressure. The previous mechanism was spec-conformant, but it requested all delegations to be returned at once. Clients are free to return few or none in such cases, but requesting smaller batches of delegations is more neighborly. In preparation for handling TLS KeyUpdate, the server's TCP receive path has been reworked to handle control records. In the process, the use of sock_recvmsg was replaced with ->read_sock, which contends less with other holders of the socket lock. NFSv2 XDR code is now generated by xdrgen, which mechanically generates the encoders and decoders from the RPC language specification for the protocol. Replacing hand-built XDR code makes prototyping new protocol elements faster, reduces errors, and improves memory safety. Replacement of XDR code for newer NFS versions will continue in subsequent releases of NFSD. The remaining bulk of changes in v7.4 is bug fixes, clean-ups, and small optimizations. Sincere thanks to all contributors, reviewers, testers, and bug reporters who participated in the v7.4 NFSD development cycle" * tag 'nfsd-7.4' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux: (184 commits) SUNRPC: use assign_bit() where applicable nfsd: Fix id-to-name cache entry leak in idtoname_parse() NFSD: Use xdrgen XDR functions for NFSv2 READDIR results NFSD: Refactor NFSv2 directory cookie encoding NFSD: Add a streaming directory reader NFSD: Use xdrgen XDR functions for NFSv2 READDIR arguments NFSD: Use xdrgen XDR functions for the NFSv2 STATFS procedure NFSD: Use xdrgen XDR functions for NFSv2 RMDIR procedure NFSD: Use xdrgen XDR functions for NFSv2 MKDIR procedure NFSD: Use xdrgen XDR functions for NFSv2 SYMLINK procedure NFSD: Use xdrgen XDR functions for the NFSv2 LINK procedure NFSD: Use xdrgen XDR functions for the NFSv2 RENAME procedure NFSD: Use xdrgen XDR functions for the NFSv2 REMOVE procedure NFSD: Use xdrgen XDR functions for NFSv2 CREATE procedure NFSD: Refactor nfsd_proc_create() NFSD: Use xdrgen XDR functions for NFSv2 WRITE procedure NFSD: Use xdrgen XDR functions for the NFSv2 WRITECACHE procedure NFSD: Use xdrgen XDR functions for NFSv2 READ procedure NFSD: Use xdrgen XDR functions for NFSv2 READLINK procedure NFSD: Use xdrgen XDR functions for the NFSv2 LOOKUP procedure ...
1804 lines
47 KiB
C
1804 lines
47 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* linux/net/sunrpc/svcsock.c
|
|
*
|
|
* These are the RPC server socket internals.
|
|
*
|
|
* The server scheduling algorithm does not always distribute the load
|
|
* evenly when servicing a single client. May need to modify the
|
|
* svc_xprt_enqueue procedure...
|
|
*
|
|
* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/module.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/fcntl.h>
|
|
#include <linux/net.h>
|
|
#include <linux/in.h>
|
|
#include <linux/inet.h>
|
|
#include <linux/udp.h>
|
|
#include <linux/tcp.h>
|
|
#include <linux/unistd.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/netdevice.h>
|
|
#include <linux/skbuff.h>
|
|
#include <linux/file.h>
|
|
#include <linux/freezer.h>
|
|
#include <linux/bvec.h>
|
|
|
|
#include <net/sock.h>
|
|
#include <net/checksum.h>
|
|
#include <net/ip.h>
|
|
#include <net/ipv6.h>
|
|
#include <net/udp.h>
|
|
#include <net/tcp.h>
|
|
#include <net/tcp_states.h>
|
|
#include <net/tls_prot.h>
|
|
#include <net/handshake.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/highmem.h>
|
|
#include <asm/ioctls.h>
|
|
#include <linux/key.h>
|
|
|
|
#include <linux/sunrpc/types.h>
|
|
#include <linux/sunrpc/clnt.h>
|
|
#include <linux/sunrpc/xdr.h>
|
|
#include <linux/sunrpc/msg_prot.h>
|
|
#include <linux/sunrpc/svcsock.h>
|
|
#include <linux/sunrpc/stats.h>
|
|
#include <linux/sunrpc/xprt.h>
|
|
|
|
#include <trace/events/sock.h>
|
|
#include <trace/events/sunrpc.h>
|
|
|
|
#include "socklib.h"
|
|
#include "sunrpc.h"
|
|
|
|
#define RPCDBG_FACILITY RPCDBG_SVCXPRT
|
|
|
|
/*
|
|
* For UDP:
|
|
* 1 for header page
|
|
* enough pages for RPCSVC_MAXPAYLOAD_UDP
|
|
* 1 in case payload is not aligned
|
|
* 1 for tail page
|
|
*/
|
|
enum {
|
|
SUNRPC_MAX_UDP_SENDPAGES = 1 + RPCSVC_MAXPAYLOAD_UDP / PAGE_SIZE + 1 + 1
|
|
};
|
|
|
|
/* To-do: to avoid tying up an nfsd thread while waiting for a
|
|
* handshake request, the request could instead be deferred.
|
|
*/
|
|
enum {
|
|
SVC_HANDSHAKE_TO = 5U * HZ
|
|
};
|
|
|
|
static struct svc_sock *svc_setup_socket(struct svc_serv *, struct socket *,
|
|
int flags);
|
|
static int svc_udp_recvfrom(struct svc_rqst *);
|
|
static int svc_udp_sendto(struct svc_rqst *);
|
|
static void svc_sock_detach(struct svc_xprt *);
|
|
static void svc_tcp_sock_detach(struct svc_xprt *);
|
|
static void svc_sock_free(struct svc_xprt *);
|
|
|
|
static struct svc_xprt *svc_create_socket(struct svc_serv *, int,
|
|
struct net *, struct sockaddr *,
|
|
int, int);
|
|
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
|
static struct lock_class_key svc_key[2];
|
|
static struct lock_class_key svc_slock_key[2];
|
|
|
|
static void svc_reclassify_socket(struct socket *sock)
|
|
{
|
|
struct sock *sk = sock->sk;
|
|
|
|
if (WARN_ON_ONCE(!sock_allow_reclassification(sk)))
|
|
return;
|
|
|
|
switch (sk->sk_family) {
|
|
case AF_INET:
|
|
sock_lock_init_class_and_name(sk, "slock-AF_INET-NFSD",
|
|
&svc_slock_key[0],
|
|
"sk_xprt.xpt_lock-AF_INET-NFSD",
|
|
&svc_key[0]);
|
|
break;
|
|
|
|
case AF_INET6:
|
|
sock_lock_init_class_and_name(sk, "slock-AF_INET6-NFSD",
|
|
&svc_slock_key[1],
|
|
"sk_xprt.xpt_lock-AF_INET6-NFSD",
|
|
&svc_key[1]);
|
|
break;
|
|
|
|
default:
|
|
BUG();
|
|
}
|
|
}
|
|
#else
|
|
static void svc_reclassify_socket(struct socket *sock)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* svc_tcp_release_ctxt - Release transport-related resources
|
|
* @xprt: the transport which owned the context
|
|
* @ctxt: the context from rqstp->rq_xprt_ctxt or dr->xprt_ctxt
|
|
*
|
|
*/
|
|
static void svc_tcp_release_ctxt(struct svc_xprt *xprt, void *ctxt)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* svc_udp_release_ctxt - Release transport-related resources
|
|
* @xprt: the transport which owned the context
|
|
* @ctxt: the context from rqstp->rq_xprt_ctxt or dr->xprt_ctxt
|
|
*
|
|
*/
|
|
static void svc_udp_release_ctxt(struct svc_xprt *xprt, void *ctxt)
|
|
{
|
|
struct sk_buff *skb = ctxt;
|
|
|
|
if (skb)
|
|
consume_skb(skb);
|
|
}
|
|
|
|
union svc_pktinfo_u {
|
|
struct in_pktinfo pkti;
|
|
struct in6_pktinfo pkti6;
|
|
};
|
|
#define SVC_PKTINFO_SPACE \
|
|
CMSG_SPACE(sizeof(union svc_pktinfo_u))
|
|
|
|
static void svc_set_cmsg_data(struct svc_rqst *rqstp, struct cmsghdr *cmh)
|
|
{
|
|
struct svc_sock *svsk =
|
|
container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
|
|
switch (svsk->sk_sk->sk_family) {
|
|
case AF_INET: {
|
|
struct in_pktinfo *pki = CMSG_DATA(cmh);
|
|
|
|
cmh->cmsg_level = SOL_IP;
|
|
cmh->cmsg_type = IP_PKTINFO;
|
|
pki->ipi_ifindex = 0;
|
|
pki->ipi_spec_dst.s_addr =
|
|
svc_daddr_in(rqstp)->sin_addr.s_addr;
|
|
cmh->cmsg_len = CMSG_LEN(sizeof(*pki));
|
|
}
|
|
break;
|
|
|
|
case AF_INET6: {
|
|
struct in6_pktinfo *pki = CMSG_DATA(cmh);
|
|
struct sockaddr_in6 *daddr = svc_daddr_in6(rqstp);
|
|
|
|
cmh->cmsg_level = SOL_IPV6;
|
|
cmh->cmsg_type = IPV6_PKTINFO;
|
|
pki->ipi6_ifindex = daddr->sin6_scope_id;
|
|
pki->ipi6_addr = daddr->sin6_addr;
|
|
cmh->cmsg_len = CMSG_LEN(sizeof(*pki));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int svc_sock_result_payload(struct svc_rqst *rqstp, unsigned int offset,
|
|
unsigned int length)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Report socket names for nfsdfs
|
|
*/
|
|
static int svc_one_sock_name(struct svc_sock *svsk, char *buf, int remaining)
|
|
{
|
|
const struct sock *sk = svsk->sk_sk;
|
|
const char *proto_name = sk->sk_protocol == IPPROTO_UDP ?
|
|
"udp" : "tcp";
|
|
int len;
|
|
|
|
switch (sk->sk_family) {
|
|
case PF_INET:
|
|
len = snprintf(buf, remaining, "ipv4 %s %pI4 %d\n",
|
|
proto_name,
|
|
&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,
|
|
inet_sk(sk)->inet_num);
|
|
break;
|
|
#endif
|
|
default:
|
|
len = snprintf(buf, remaining, "*unknown-%d*\n",
|
|
sk->sk_family);
|
|
}
|
|
|
|
if (len >= remaining) {
|
|
*buf = '\0';
|
|
return -ENAMETOOLONG;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
/*
|
|
* The ->read_sock data path invokes neither security_socket_recvmsg()
|
|
* nor the sock:sock_recv_length tracepoint. Dispatch ->recvmsg
|
|
* directly so the whole receive path behaves one way.
|
|
*/
|
|
static int svc_tcp_recv_cmsg(struct socket *sock, int flags,
|
|
struct kvec *payload, u8 *type,
|
|
unsigned int *msg_flags)
|
|
{
|
|
const struct proto_ops *ops = READ_ONCE(sock->ops);
|
|
union {
|
|
struct cmsghdr cmsg;
|
|
u8 buf[CMSG_SPACE(sizeof(u8))];
|
|
} u = {};
|
|
struct msghdr msg = {
|
|
.msg_control = &u,
|
|
.msg_controllen = sizeof(u),
|
|
};
|
|
int ret;
|
|
|
|
iov_iter_kvec(&msg.msg_iter, ITER_DEST, payload, 1, payload->iov_len);
|
|
ret = ops->recvmsg(sock, &msg, msg_data_left(&msg), flags);
|
|
if (ret < 0)
|
|
return ret;
|
|
*msg_flags = msg.msg_flags;
|
|
*type = tls_get_record_type(sock->sk, &u.cmsg);
|
|
if (!*type && ret)
|
|
return -EBADMSG;
|
|
return ret;
|
|
}
|
|
|
|
static int svc_tcp_recv_ctrl_record(struct svc_sock *svsk)
|
|
{
|
|
u8 alert[2], type, level, description;
|
|
struct socket *sock = svsk->sk_sock;
|
|
struct kvec recv_kvec = {
|
|
.iov_base = alert,
|
|
.iov_len = sizeof(alert),
|
|
};
|
|
unsigned int msg_flags;
|
|
struct msghdr msg = {};
|
|
int ret;
|
|
|
|
if (!test_bit(XPT_TLS_SESSION, &svsk->sk_xprt.xpt_flags))
|
|
return 0;
|
|
|
|
/* A data record can become ready between ->read_sock returning
|
|
* and this probe. A plain receive would take two octets of it
|
|
* as RPC payload, so peek.
|
|
*/
|
|
ret = svc_tcp_recv_cmsg(sock, MSG_DONTWAIT | MSG_PEEK,
|
|
&recv_kvec, &type, &msg_flags);
|
|
if (ret == -EAGAIN || (!ret && !type))
|
|
return 0;
|
|
if (ret < 0)
|
|
return ret;
|
|
if (type == TLS_RECORD_TYPE_DATA) {
|
|
/* The peek parks the decrypted record on ctx->rx_list,
|
|
* where it draws no further data_ready. Re-arm or the
|
|
* RPC hangs until the client times out.
|
|
*/
|
|
set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
|
|
return 0;
|
|
}
|
|
if (type != TLS_RECORD_TYPE_ALERT)
|
|
return -EPROTO;
|
|
|
|
ret = svc_tcp_recv_cmsg(sock, MSG_DONTWAIT, &recv_kvec, &type,
|
|
&msg_flags);
|
|
/* The peek found a record at the head, so an -EAGAIN here is
|
|
* spurious. Propagating it strands the record with no later
|
|
* announcement, so return -EBADMSG, which closes the transport.
|
|
*/
|
|
if (ret == -EAGAIN)
|
|
return -EBADMSG;
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
/* An Alert record carries exactly one two-octet message (RFC
|
|
* 8446 Section 5.1). recv_kvec caps the receive at two, so a
|
|
* longer record produces the same count. MSG_EOR appears only
|
|
* once kTLS has drained the whole record.
|
|
*/
|
|
if (ret != sizeof(alert) || !(msg_flags & MSG_EOR))
|
|
return -EBADMSG;
|
|
|
|
iov_iter_kvec(&msg.msg_iter, ITER_DEST, &recv_kvec, 1,
|
|
recv_kvec.iov_len);
|
|
tls_alert_recv(sock->sk, &msg, &level, &description);
|
|
|
|
/* RFC 8446 Section 6: every alert but a closure alert is
|
|
* an error alert. kTLS raises no data_ready for records it
|
|
* already holds, so re-arm for what sits behind the alert.
|
|
*/
|
|
switch (description) {
|
|
case TLS_ALERT_DESC_CLOSE_NOTIFY:
|
|
case TLS_ALERT_DESC_USER_CANCELED:
|
|
set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
|
|
return -EAGAIN;
|
|
default:
|
|
return -ENOTCONN;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Set socket snd and rcv buffer lengths
|
|
*/
|
|
static void svc_sock_setbufsize(struct svc_sock *svsk, unsigned int nreqs)
|
|
{
|
|
unsigned int max_mesg = svsk->sk_xprt.xpt_server->sv_max_mesg;
|
|
struct socket *sock = svsk->sk_sock;
|
|
|
|
nreqs = min(nreqs, INT_MAX / 2 / max_mesg);
|
|
|
|
lock_sock(sock->sk);
|
|
sock->sk->sk_sndbuf = nreqs * max_mesg * 2;
|
|
sock->sk->sk_rcvbuf = nreqs * max_mesg * 2;
|
|
sock->sk->sk_write_space(sock->sk);
|
|
release_sock(sock->sk);
|
|
}
|
|
|
|
static void svc_sock_secure_port(struct svc_rqst *rqstp)
|
|
{
|
|
assign_bit(RQ_SECURE, &rqstp->rq_flags,
|
|
svc_port_is_privileged(svc_addr(rqstp)));
|
|
}
|
|
|
|
/*
|
|
* INET callback when data has been received on the socket.
|
|
*/
|
|
static void svc_data_ready(struct sock *sk)
|
|
{
|
|
struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data;
|
|
|
|
trace_sk_data_ready(sk);
|
|
|
|
if (svsk) {
|
|
/* Refer to svc_setup_socket() for details. */
|
|
rmb();
|
|
svsk->sk_odata(sk);
|
|
trace_svcsock_data_ready(&svsk->sk_xprt, 0);
|
|
if (test_bit(XPT_HANDSHAKE, &svsk->sk_xprt.xpt_flags))
|
|
return;
|
|
if (!test_and_set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags))
|
|
svc_xprt_enqueue(&svsk->sk_xprt);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* INET callback when space is newly available on the socket.
|
|
*/
|
|
static void svc_write_space(struct sock *sk)
|
|
{
|
|
struct svc_sock *svsk = (struct svc_sock *)(sk->sk_user_data);
|
|
|
|
if (svsk) {
|
|
/* Refer to svc_setup_socket() for details. */
|
|
rmb();
|
|
trace_svcsock_write_space(&svsk->sk_xprt, 0);
|
|
svsk->sk_owspace(sk);
|
|
svc_xprt_enqueue(&svsk->sk_xprt);
|
|
}
|
|
}
|
|
|
|
static int svc_tcp_has_wspace(struct svc_xprt *xprt)
|
|
{
|
|
struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
|
|
|
|
if (test_bit(XPT_LISTENER, &xprt->xpt_flags))
|
|
return 1;
|
|
return !test_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
|
|
}
|
|
|
|
static void svc_tcp_kill_temp_xprt(struct svc_xprt *xprt)
|
|
{
|
|
struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
|
|
|
|
sock_no_linger(svsk->sk_sock->sk);
|
|
}
|
|
|
|
/**
|
|
* svc_tcp_handshake_done - Handshake completion handler
|
|
* @data: address of xprt to wake
|
|
* @status: status of handshake
|
|
* @peerid: serial number of key containing the remote peer's identity
|
|
*
|
|
* If a security policy is specified as an export option, we don't
|
|
* have a specific export here to check. So we set a "TLS session
|
|
* is present" flag on the xprt and let an upper layer enforce local
|
|
* security policy.
|
|
*/
|
|
static void svc_tcp_handshake_done(void *data, int status, key_serial_t peerid)
|
|
{
|
|
struct svc_xprt *xprt = data;
|
|
struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
|
|
|
|
if (!status) {
|
|
if (peerid != TLS_NO_PEERID)
|
|
set_bit(XPT_PEER_AUTH, &xprt->xpt_flags);
|
|
set_bit(XPT_TLS_SESSION, &xprt->xpt_flags);
|
|
}
|
|
clear_bit(XPT_HANDSHAKE, &xprt->xpt_flags);
|
|
complete_all(&svsk->sk_handshake_done);
|
|
svc_xprt_put(xprt);
|
|
}
|
|
|
|
/**
|
|
* svc_tcp_handshake - Perform a transport-layer security handshake
|
|
* @xprt: connected transport endpoint
|
|
*
|
|
*/
|
|
static void svc_tcp_handshake(struct svc_xprt *xprt)
|
|
{
|
|
struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
|
|
struct sock *sk = svsk->sk_sock->sk;
|
|
struct tls_handshake_args args = {
|
|
.ta_sock = svsk->sk_sock,
|
|
.ta_done = svc_tcp_handshake_done,
|
|
.ta_data = xprt,
|
|
};
|
|
int ret;
|
|
|
|
trace_svc_tls_upcall(xprt);
|
|
|
|
clear_bit(XPT_TLS_SESSION, &xprt->xpt_flags);
|
|
init_completion(&svsk->sk_handshake_done);
|
|
|
|
/* Pin the transport across the asynchronous handshake callback. */
|
|
svc_xprt_get(xprt);
|
|
|
|
ret = tls_server_hello_x509(&args, GFP_KERNEL);
|
|
if (ret) {
|
|
trace_svc_tls_not_started(xprt);
|
|
svc_xprt_put(xprt);
|
|
goto out_failed;
|
|
}
|
|
|
|
ret = wait_for_completion_interruptible_timeout(&svsk->sk_handshake_done,
|
|
SVC_HANDSHAKE_TO);
|
|
if (ret <= 0) {
|
|
if (tls_handshake_cancel(sk)) {
|
|
trace_svc_tls_timed_out(xprt);
|
|
svc_xprt_put(xprt);
|
|
goto out_close;
|
|
}
|
|
/* Cancellation lost to handshake_complete(): the
|
|
* callback is in flight and should finish quickly.
|
|
*/
|
|
wait_for_completion(&svsk->sk_handshake_done);
|
|
}
|
|
|
|
if (!test_bit(XPT_TLS_SESSION, &xprt->xpt_flags)) {
|
|
trace_svc_tls_unavailable(xprt);
|
|
goto out_close;
|
|
}
|
|
|
|
/* Mark the transport ready in case the remote sent RPC
|
|
* traffic before the kernel received the handshake
|
|
* completion downcall.
|
|
*/
|
|
set_bit(XPT_DATA, &xprt->xpt_flags);
|
|
svc_xprt_enqueue(xprt);
|
|
return;
|
|
|
|
out_close:
|
|
set_bit(XPT_CLOSE, &xprt->xpt_flags);
|
|
out_failed:
|
|
clear_bit(XPT_HANDSHAKE, &xprt->xpt_flags);
|
|
set_bit(XPT_DATA, &xprt->xpt_flags);
|
|
svc_xprt_enqueue(xprt);
|
|
}
|
|
|
|
/*
|
|
* See net/ipv6/ip_sockglue.c : ip_cmsg_recv_pktinfo
|
|
*/
|
|
static int svc_udp_get_dest_address4(struct svc_rqst *rqstp,
|
|
struct cmsghdr *cmh)
|
|
{
|
|
struct in_pktinfo *pki = CMSG_DATA(cmh);
|
|
struct sockaddr_in *daddr = svc_daddr_in(rqstp);
|
|
|
|
if (cmh->cmsg_type != IP_PKTINFO)
|
|
return 0;
|
|
|
|
daddr->sin_family = AF_INET;
|
|
daddr->sin_addr.s_addr = pki->ipi_spec_dst.s_addr;
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* See net/ipv6/datagram.c : ip6_datagram_recv_ctl
|
|
*/
|
|
static int svc_udp_get_dest_address6(struct svc_rqst *rqstp,
|
|
struct cmsghdr *cmh)
|
|
{
|
|
struct in6_pktinfo *pki = CMSG_DATA(cmh);
|
|
struct sockaddr_in6 *daddr = svc_daddr_in6(rqstp);
|
|
|
|
if (cmh->cmsg_type != IPV6_PKTINFO)
|
|
return 0;
|
|
|
|
daddr->sin6_family = AF_INET6;
|
|
daddr->sin6_addr = pki->ipi6_addr;
|
|
daddr->sin6_scope_id = pki->ipi6_ifindex;
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Copy the UDP datagram's destination address to the rqstp structure.
|
|
* The 'destination' address in this case is the address to which the
|
|
* peer sent the datagram, i.e. our local address. For multihomed
|
|
* hosts, this can change from msg to msg. Note that only the IP
|
|
* address changes, the port number should remain the same.
|
|
*/
|
|
static int svc_udp_get_dest_address(struct svc_rqst *rqstp,
|
|
struct cmsghdr *cmh)
|
|
{
|
|
switch (cmh->cmsg_level) {
|
|
case SOL_IP:
|
|
return svc_udp_get_dest_address4(rqstp, cmh);
|
|
case SOL_IPV6:
|
|
return svc_udp_get_dest_address6(rqstp, cmh);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* svc_udp_recvfrom - Receive a datagram from a UDP socket.
|
|
* @rqstp: request structure into which to receive an RPC Call
|
|
*
|
|
* Called in a loop when XPT_DATA has been set.
|
|
*
|
|
* Returns:
|
|
* On success, the number of bytes in a received RPC Call, or
|
|
* %0 if a complete RPC Call message was not ready to return
|
|
*/
|
|
static int svc_udp_recvfrom(struct svc_rqst *rqstp)
|
|
{
|
|
struct svc_sock *svsk =
|
|
container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
|
|
struct svc_serv *serv = svsk->sk_xprt.xpt_server;
|
|
struct sk_buff *skb;
|
|
union {
|
|
struct cmsghdr hdr;
|
|
long all[SVC_PKTINFO_SPACE / sizeof(long)];
|
|
} buffer;
|
|
struct cmsghdr *cmh = &buffer.hdr;
|
|
struct msghdr msg = {
|
|
.msg_name = svc_addr(rqstp),
|
|
.msg_control = cmh,
|
|
.msg_controllen = sizeof(buffer),
|
|
.msg_flags = MSG_DONTWAIT,
|
|
};
|
|
size_t len;
|
|
int err;
|
|
|
|
if (test_and_clear_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags))
|
|
/* udp sockets need large rcvbuf as all pending
|
|
* requests are still in that buffer. sndbuf must
|
|
* also be large enough that there is enough space
|
|
* for one reply per thread. We count all threads
|
|
* rather than threads in a particular pool, which
|
|
* provides an upper bound on the number of threads
|
|
* which will access the socket.
|
|
*/
|
|
svc_sock_setbufsize(svsk, serv->sv_nrthreads + 3);
|
|
|
|
clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
|
|
err = kernel_recvmsg(svsk->sk_sock, &msg, NULL,
|
|
0, 0, MSG_PEEK | MSG_DONTWAIT);
|
|
if (err < 0)
|
|
goto out_recv_err;
|
|
skb = skb_recv_udp(svsk->sk_sk, MSG_DONTWAIT, &err);
|
|
if (!skb)
|
|
goto out_recv_err;
|
|
|
|
len = svc_addr_len(svc_addr(rqstp));
|
|
rqstp->rq_addrlen = len;
|
|
if (skb->tstamp == 0) {
|
|
skb->tstamp = ktime_get_real();
|
|
/* Don't enable netstamp, sunrpc doesn't
|
|
need that much accuracy */
|
|
}
|
|
sock_write_timestamp(svsk->sk_sk, skb->tstamp);
|
|
set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); /* there may be more data... */
|
|
|
|
len = skb->len;
|
|
rqstp->rq_arg.len = len;
|
|
trace_svcsock_udp_recv(&svsk->sk_xprt, len);
|
|
|
|
rqstp->rq_prot = IPPROTO_UDP;
|
|
|
|
if (!svc_udp_get_dest_address(rqstp, cmh))
|
|
goto out_cmsg_err;
|
|
rqstp->rq_daddrlen = svc_addr_len(svc_daddr(rqstp));
|
|
|
|
if (skb_is_nonlinear(skb)) {
|
|
/* we have to copy */
|
|
local_bh_disable();
|
|
if (csum_partial_copy_to_xdr(&rqstp->rq_arg, skb))
|
|
goto out_bh_enable;
|
|
local_bh_enable();
|
|
consume_skb(skb);
|
|
} else {
|
|
/* we can use it in-place */
|
|
rqstp->rq_arg.head[0].iov_base = skb->data;
|
|
rqstp->rq_arg.head[0].iov_len = len;
|
|
if (skb_checksum_complete(skb))
|
|
goto out_free;
|
|
rqstp->rq_xprt_ctxt = skb;
|
|
}
|
|
|
|
rqstp->rq_arg.page_base = 0;
|
|
if (len <= rqstp->rq_arg.head[0].iov_len) {
|
|
rqstp->rq_arg.head[0].iov_len = len;
|
|
rqstp->rq_arg.page_len = 0;
|
|
} else {
|
|
rqstp->rq_arg.page_len = len - rqstp->rq_arg.head[0].iov_len;
|
|
}
|
|
|
|
if (serv->sv_stats)
|
|
serv->sv_stats->netudpcnt++;
|
|
|
|
svc_sock_secure_port(rqstp);
|
|
svc_xprt_received(rqstp->rq_xprt);
|
|
return len;
|
|
|
|
out_recv_err:
|
|
if (err != -EAGAIN) {
|
|
/* possibly an icmp error */
|
|
set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
|
|
}
|
|
trace_svcsock_udp_recv_err(&svsk->sk_xprt, err);
|
|
goto out_clear_busy;
|
|
out_cmsg_err:
|
|
net_warn_ratelimited("svc: received unknown control message %d/%d; dropping RPC reply datagram\n",
|
|
cmh->cmsg_level, cmh->cmsg_type);
|
|
goto out_free;
|
|
out_bh_enable:
|
|
local_bh_enable();
|
|
out_free:
|
|
kfree_skb(skb);
|
|
out_clear_busy:
|
|
svc_xprt_received(rqstp->rq_xprt);
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* svc_udp_sendto - Send out a reply on a UDP socket
|
|
* @rqstp: completed svc_rqst
|
|
*
|
|
* xpt_mutex ensures @rqstp's whole message is written to the socket
|
|
* without interruption.
|
|
*
|
|
* Returns the number of bytes sent, or a negative errno.
|
|
*/
|
|
static int svc_udp_sendto(struct svc_rqst *rqstp)
|
|
{
|
|
struct svc_xprt *xprt = rqstp->rq_xprt;
|
|
struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
|
|
struct xdr_buf *xdr = &rqstp->rq_res;
|
|
union {
|
|
struct cmsghdr hdr;
|
|
long all[SVC_PKTINFO_SPACE / sizeof(long)];
|
|
} buffer;
|
|
struct cmsghdr *cmh = &buffer.hdr;
|
|
struct msghdr msg = {
|
|
.msg_name = &rqstp->rq_addr,
|
|
.msg_namelen = rqstp->rq_addrlen,
|
|
.msg_control = cmh,
|
|
.msg_flags = MSG_SPLICE_PAGES,
|
|
.msg_controllen = sizeof(buffer),
|
|
};
|
|
int count;
|
|
int err;
|
|
|
|
svc_udp_release_ctxt(xprt, rqstp->rq_xprt_ctxt);
|
|
rqstp->rq_xprt_ctxt = NULL;
|
|
|
|
svc_set_cmsg_data(rqstp, cmh);
|
|
|
|
mutex_lock(&xprt->xpt_mutex);
|
|
|
|
if (svc_xprt_is_dead(xprt))
|
|
goto out_notconn;
|
|
|
|
count = xdr_buf_to_bvec(svsk->sk_bvec, SUNRPC_MAX_UDP_SENDPAGES, xdr);
|
|
if (count < 0) {
|
|
err = count;
|
|
goto out_trace;
|
|
}
|
|
|
|
iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, svsk->sk_bvec,
|
|
count, rqstp->rq_res.len);
|
|
err = sock_sendmsg(svsk->sk_sock, &msg);
|
|
if (err == -ECONNREFUSED) {
|
|
/* ICMP error on earlier request. */
|
|
iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, svsk->sk_bvec,
|
|
count, rqstp->rq_res.len);
|
|
err = sock_sendmsg(svsk->sk_sock, &msg);
|
|
}
|
|
|
|
out_trace:
|
|
trace_svcsock_udp_send(xprt, err);
|
|
|
|
mutex_unlock(&xprt->xpt_mutex);
|
|
return err;
|
|
|
|
out_notconn:
|
|
mutex_unlock(&xprt->xpt_mutex);
|
|
return -ENOTCONN;
|
|
}
|
|
|
|
static int svc_udp_has_wspace(struct svc_xprt *xprt)
|
|
{
|
|
struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
|
|
struct svc_serv *serv = xprt->xpt_server;
|
|
unsigned long required;
|
|
|
|
/*
|
|
* Set the SOCK_NOSPACE flag before checking the available
|
|
* sock space.
|
|
*/
|
|
sk_set_nospace(svsk->sk_sk);
|
|
required = atomic_read(&svsk->sk_xprt.xpt_reserved) + serv->sv_max_mesg;
|
|
if (required*2 > sock_wspace(svsk->sk_sk))
|
|
return 0;
|
|
sk_clear_nospace(svsk->sk_sk);
|
|
return 1;
|
|
}
|
|
|
|
static struct svc_xprt *svc_udp_accept(struct svc_xprt *xprt)
|
|
{
|
|
BUG();
|
|
return NULL;
|
|
}
|
|
|
|
static void svc_udp_kill_temp_xprt(struct svc_xprt *xprt)
|
|
{
|
|
}
|
|
|
|
static struct svc_xprt *svc_udp_create(struct svc_serv *serv,
|
|
struct net *net,
|
|
struct sockaddr *sa, int salen,
|
|
int flags)
|
|
{
|
|
return svc_create_socket(serv, IPPROTO_UDP, net, sa, salen, flags);
|
|
}
|
|
|
|
static const struct svc_xprt_ops svc_udp_ops = {
|
|
.xpo_create = svc_udp_create,
|
|
.xpo_recvfrom = svc_udp_recvfrom,
|
|
.xpo_sendto = svc_udp_sendto,
|
|
.xpo_result_payload = svc_sock_result_payload,
|
|
.xpo_release_ctxt = svc_udp_release_ctxt,
|
|
.xpo_detach = svc_sock_detach,
|
|
.xpo_free = svc_sock_free,
|
|
.xpo_has_wspace = svc_udp_has_wspace,
|
|
.xpo_accept = svc_udp_accept,
|
|
.xpo_kill_temp_xprt = svc_udp_kill_temp_xprt,
|
|
};
|
|
|
|
static struct svc_xprt_class svc_udp_class = {
|
|
.xcl_name = "udp",
|
|
.xcl_owner = THIS_MODULE,
|
|
.xcl_ops = &svc_udp_ops,
|
|
.xcl_max_payload = RPCSVC_MAXPAYLOAD_UDP,
|
|
.xcl_ident = XPRT_TRANSPORT_UDP,
|
|
.xcl_flags = SVC_XPRT_FLAG_WSPACE_RESERVE,
|
|
};
|
|
|
|
static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv)
|
|
{
|
|
svc_xprt_init(sock_net(svsk->sk_sock->sk), &svc_udp_class,
|
|
&svsk->sk_xprt, serv);
|
|
clear_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags);
|
|
svsk->sk_sk->sk_data_ready = svc_data_ready;
|
|
svsk->sk_sk->sk_write_space = svc_write_space;
|
|
|
|
/* initialise setting must have enough space to
|
|
* receive and respond to one request.
|
|
* svc_udp_recvfrom will re-adjust if necessary
|
|
*/
|
|
svc_sock_setbufsize(svsk, 3);
|
|
|
|
/* data might have come in before data_ready set up */
|
|
set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
|
|
set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
|
|
set_bit(XPT_RPCB_UNREG, &svsk->sk_xprt.xpt_flags);
|
|
|
|
/* make sure we get destination address info */
|
|
switch (svsk->sk_sk->sk_family) {
|
|
case AF_INET:
|
|
ip_sock_set_pktinfo(svsk->sk_sock->sk);
|
|
break;
|
|
case AF_INET6:
|
|
ip6_sock_set_recvpktinfo(svsk->sk_sock->sk);
|
|
break;
|
|
default:
|
|
BUG();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* A data_ready event on a listening socket means there's a connection
|
|
* pending. Do not use state_change as a substitute for it.
|
|
*/
|
|
static void svc_tcp_listen_data_ready(struct sock *sk)
|
|
{
|
|
struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data;
|
|
|
|
trace_sk_data_ready(sk);
|
|
|
|
/*
|
|
* This callback may called twice when a new connection
|
|
* is established as a child socket inherits everything
|
|
* from a parent LISTEN socket.
|
|
* 1) data_ready method of the parent socket will be called
|
|
* when one of child sockets become ESTABLISHED.
|
|
* 2) data_ready method of the child socket may be called
|
|
* when it receives data before the socket is accepted.
|
|
* In case of 2, we should ignore it silently and DO NOT
|
|
* dereference svsk.
|
|
*/
|
|
if (sk->sk_state != TCP_LISTEN)
|
|
return;
|
|
|
|
if (svsk) {
|
|
/* Refer to svc_setup_socket() for details. */
|
|
rmb();
|
|
svsk->sk_odata(sk);
|
|
set_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags);
|
|
svc_xprt_enqueue(&svsk->sk_xprt);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* A state change on a connected socket means it's dying or dead.
|
|
*/
|
|
static void svc_tcp_state_change(struct sock *sk)
|
|
{
|
|
struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data;
|
|
|
|
if (svsk) {
|
|
/* Refer to svc_setup_socket() for details. */
|
|
rmb();
|
|
svsk->sk_ostate(sk);
|
|
trace_svcsock_tcp_state(&svsk->sk_xprt, svsk->sk_sock);
|
|
if (sk->sk_state != TCP_ESTABLISHED)
|
|
svc_xprt_deferred_close(&svsk->sk_xprt);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Accept a TCP connection
|
|
*/
|
|
static struct svc_xprt *svc_tcp_accept(struct svc_xprt *xprt)
|
|
{
|
|
struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
|
|
struct sockaddr_storage addr;
|
|
struct sockaddr *sin = (struct sockaddr *) &addr;
|
|
struct svc_serv *serv = svsk->sk_xprt.xpt_server;
|
|
struct socket *sock = svsk->sk_sock;
|
|
struct socket *newsock;
|
|
struct svc_sock *newsvsk;
|
|
int err, slen;
|
|
|
|
if (!sock)
|
|
return NULL;
|
|
|
|
clear_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags);
|
|
err = kernel_accept(sock, &newsock, O_NONBLOCK);
|
|
if (err < 0) {
|
|
if (err != -EAGAIN)
|
|
trace_svcsock_accept_err(xprt, serv->sv_name, err);
|
|
return NULL;
|
|
}
|
|
if (IS_ERR(sock_alloc_file(newsock, O_NONBLOCK, NULL)))
|
|
return NULL;
|
|
|
|
set_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags);
|
|
|
|
err = kernel_getpeername(newsock, sin);
|
|
if (err < 0) {
|
|
trace_svcsock_getpeername_err(xprt, serv->sv_name, err);
|
|
goto failed; /* aborted connection or whatever */
|
|
}
|
|
slen = err;
|
|
|
|
/* Reset the inherited callbacks before calling svc_setup_socket */
|
|
newsock->sk->sk_state_change = svsk->sk_ostate;
|
|
newsock->sk->sk_data_ready = svsk->sk_odata;
|
|
newsock->sk->sk_write_space = svsk->sk_owspace;
|
|
|
|
/* make sure that a write doesn't block forever when
|
|
* low on memory
|
|
*/
|
|
newsock->sk->sk_sndtimeo = HZ*30;
|
|
|
|
newsvsk = svc_setup_socket(serv, newsock,
|
|
(SVC_SOCK_ANONYMOUS | SVC_SOCK_TEMPORARY));
|
|
if (IS_ERR(newsvsk))
|
|
goto failed;
|
|
svc_xprt_set_remote(&newsvsk->sk_xprt, sin, slen);
|
|
err = kernel_getsockname(newsock, sin);
|
|
slen = err;
|
|
if (unlikely(err < 0))
|
|
slen = offsetof(struct sockaddr, sa_data);
|
|
svc_xprt_set_local(&newsvsk->sk_xprt, sin, slen);
|
|
|
|
assign_bit(XPT_LOCAL, &newsvsk->sk_xprt.xpt_flags,
|
|
sock_is_loopback(newsock->sk));
|
|
if (serv->sv_stats)
|
|
serv->sv_stats->nettcpconn++;
|
|
|
|
return &newsvsk->sk_xprt;
|
|
|
|
failed:
|
|
sockfd_put(newsock);
|
|
return NULL;
|
|
}
|
|
|
|
static void svc_tcp_restore_pages(struct svc_sock *svsk,
|
|
struct svc_rqst *rqstp)
|
|
{
|
|
size_t len = svsk->sk_datalen;
|
|
unsigned int i, npages;
|
|
|
|
if (!len)
|
|
return;
|
|
npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
|
for (i = 0; i < npages; i++) {
|
|
if (rqstp->rq_pages[i] != NULL)
|
|
svc_rqst_page_release(rqstp, rqstp->rq_pages[i]);
|
|
BUG_ON(svsk->sk_pages[i] == NULL);
|
|
rqstp->rq_pages[i] = svsk->sk_pages[i];
|
|
svsk->sk_pages[i] = NULL;
|
|
}
|
|
rqstp->rq_arg.head[0].iov_base = page_address(rqstp->rq_pages[0]);
|
|
}
|
|
|
|
static void svc_tcp_save_pages(struct svc_sock *svsk, struct svc_rqst *rqstp)
|
|
{
|
|
unsigned int i, len, npages;
|
|
|
|
if (svsk->sk_datalen == 0)
|
|
return;
|
|
len = svsk->sk_datalen;
|
|
npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
|
for (i = 0; i < npages; i++) {
|
|
svsk->sk_pages[i] = rqstp->rq_pages[i];
|
|
rqstp->rq_pages[i] = NULL;
|
|
}
|
|
rqstp->rq_pages_nfree = npages;
|
|
}
|
|
|
|
static void svc_tcp_clear_pages(struct svc_sock *svsk)
|
|
{
|
|
unsigned int i, len, npages;
|
|
|
|
if (svsk->sk_datalen == 0)
|
|
goto out;
|
|
len = svsk->sk_datalen;
|
|
npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
|
for (i = 0; i < npages; i++) {
|
|
if (svsk->sk_pages[i] == NULL) {
|
|
WARN_ON_ONCE(1);
|
|
continue;
|
|
}
|
|
put_page(svsk->sk_pages[i]);
|
|
svsk->sk_pages[i] = NULL;
|
|
}
|
|
out:
|
|
svsk->sk_tcplen = 0;
|
|
svsk->sk_datalen = 0;
|
|
}
|
|
|
|
static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp)
|
|
{
|
|
struct rpc_xprt *bc_xprt = svsk->sk_xprt.xpt_bc_xprt;
|
|
struct rpc_rqst *req = NULL;
|
|
struct kvec *src, *dst;
|
|
__be32 *p = (__be32 *)rqstp->rq_arg.head[0].iov_base;
|
|
__be32 xid = *p;
|
|
|
|
if (!bc_xprt)
|
|
return -EAGAIN;
|
|
spin_lock(&bc_xprt->queue_lock);
|
|
req = xprt_lookup_rqst(bc_xprt, xid);
|
|
if (!req)
|
|
goto unlock_eagain;
|
|
|
|
memcpy(&req->rq_private_buf, &req->rq_rcv_buf, sizeof(struct xdr_buf));
|
|
/*
|
|
* XXX!: cheating for now! Only copying HEAD.
|
|
* But we know this is good enough for now (in fact, for any
|
|
* callback reply in the forseeable future).
|
|
*/
|
|
dst = &req->rq_private_buf.head[0];
|
|
src = &rqstp->rq_arg.head[0];
|
|
if (dst->iov_len < src->iov_len)
|
|
goto unlock_eagain; /* whatever; just giving up. */
|
|
memcpy(dst->iov_base, src->iov_base, src->iov_len);
|
|
xprt_complete_rqst(req->rq_task, rqstp->rq_arg.len);
|
|
rqstp->rq_arg.len = 0;
|
|
spin_unlock(&bc_xprt->queue_lock);
|
|
return 0;
|
|
unlock_eagain:
|
|
spin_unlock(&bc_xprt->queue_lock);
|
|
return -EAGAIN;
|
|
}
|
|
|
|
static void svc_tcp_fragment_received(struct svc_sock *svsk)
|
|
{
|
|
svsk->sk_tcplen = 0;
|
|
svsk->sk_marker = xdr_zero;
|
|
}
|
|
|
|
/*
|
|
* A non-final fragment carries four octets of marker and may carry
|
|
* no payload at all. sk_datalen advances only by the payload, so a
|
|
* run of tiny fragments exhausts ->read_sock's byte budget before
|
|
* the sv_max_mesg check trips, and a run of empty ones never trips
|
|
* it. Cap the fragments per socket-lock hold. The cap leaves the
|
|
* record incomplete, and svc_tcp_recvfrom() resumes it on the next
|
|
* call.
|
|
*/
|
|
#define SVC_TCP_MAX_FRAGS 256
|
|
|
|
struct svc_tcp_recv_ctx {
|
|
struct svc_rqst *rqstp;
|
|
unsigned int frags;
|
|
bool complete;
|
|
};
|
|
|
|
/*
|
|
* Nothing reads the message body before the message is complete, and
|
|
* partial receives refill the same pages. Flush once here, after the
|
|
* socket lock is released, rather than once per copy in the actor.
|
|
*/
|
|
static void svc_tcp_flush_pages(struct svc_sock *svsk,
|
|
struct svc_rqst *rqstp)
|
|
{
|
|
unsigned int pg, pages = DIV_ROUND_UP(svsk->sk_datalen, PAGE_SIZE);
|
|
|
|
for (pg = 0; pg < pages; pg++)
|
|
flush_dcache_page(rqstp->rq_pages[pg]);
|
|
}
|
|
|
|
/*
|
|
* Mapping the message's unfilled remainder would re-map untouched
|
|
* pages on every call, at a cost that grows with the message rather
|
|
* than with the octets copied.
|
|
*/
|
|
static void svc_tcp_recv_iter_init(struct svc_rqst *rqstp,
|
|
struct iov_iter *iter, size_t body_off,
|
|
size_t len)
|
|
{
|
|
unsigned int first = body_off >> PAGE_SHIFT;
|
|
size_t seek = offset_in_page(body_off);
|
|
unsigned int i, pages = DIV_ROUND_UP(seek + len, PAGE_SIZE);
|
|
|
|
for (i = 0; i < pages; i++)
|
|
bvec_set_page(&rqstp->rq_bvec[i], rqstp->rq_pages[first + i],
|
|
PAGE_SIZE, 0);
|
|
|
|
iov_iter_bvec(iter, ITER_DEST, rqstp->rq_bvec, pages, seek + len);
|
|
iov_iter_advance(iter, seek);
|
|
}
|
|
|
|
/*
|
|
* ->read_sock actor, called under the socket lock. sk_datalen is both
|
|
* the count of body octets received so far and their write offset into
|
|
* rq_pages.
|
|
*/
|
|
static int svc_tcp_recv_actor(read_descriptor_t *desc, struct sk_buff *skb,
|
|
unsigned int offset, size_t len)
|
|
{
|
|
struct svc_tcp_recv_ctx *ctx = desc->arg.data;
|
|
struct svc_rqst *rqstp = ctx->rqstp;
|
|
struct svc_sock *svsk =
|
|
container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
|
|
size_t reclen, received, want, take, n;
|
|
size_t consumed = 0;
|
|
|
|
if (!desc->count)
|
|
return 0;
|
|
|
|
len = min(len, desc->count);
|
|
|
|
if (svsk->sk_tcplen < sizeof(rpc_fraghdr)) {
|
|
want = sizeof(rpc_fraghdr) - svsk->sk_tcplen;
|
|
n = min(want, len);
|
|
|
|
if (skb_copy_bits(skb, offset,
|
|
(char *)&svsk->sk_marker + svsk->sk_tcplen,
|
|
n))
|
|
goto fault;
|
|
svsk->sk_tcplen += n;
|
|
offset += n;
|
|
len -= n;
|
|
consumed += n;
|
|
desc->count -= n;
|
|
|
|
if (svsk->sk_tcplen < sizeof(rpc_fraghdr))
|
|
return consumed;
|
|
|
|
trace_svcsock_marker(&svsk->sk_xprt, svsk->sk_marker);
|
|
if (svc_sock_reclen(svsk) + svsk->sk_datalen >
|
|
svsk->sk_xprt.xpt_server->sv_max_mesg) {
|
|
net_notice_ratelimited("svc: %s oversized RPC fragment (%u octets) from %pISpc\n",
|
|
svsk->sk_xprt.xpt_server->sv_name,
|
|
svc_sock_reclen(svsk),
|
|
(struct sockaddr *)&svsk->sk_xprt.xpt_remote);
|
|
desc->error = -EMSGSIZE;
|
|
desc->count = 0;
|
|
return consumed;
|
|
}
|
|
}
|
|
|
|
reclen = svc_sock_reclen(svsk);
|
|
received = svsk->sk_tcplen - sizeof(rpc_fraghdr);
|
|
want = reclen - received;
|
|
take = min(want, len);
|
|
|
|
if (take) {
|
|
struct iov_iter iter;
|
|
|
|
svc_tcp_recv_iter_init(rqstp, &iter, svsk->sk_datalen, take);
|
|
if (skb_copy_datagram_iter(skb, offset, &iter, take))
|
|
goto fault;
|
|
svsk->sk_datalen += take;
|
|
svsk->sk_tcplen += take;
|
|
consumed += take;
|
|
desc->count -= take;
|
|
}
|
|
|
|
if (take == want) {
|
|
if (svc_sock_final_rec(svsk)) {
|
|
ctx->complete = true;
|
|
desc->count = 0;
|
|
} else {
|
|
svc_tcp_fragment_received(svsk);
|
|
if (++ctx->frags >= SVC_TCP_MAX_FRAGS)
|
|
desc->count = 0;
|
|
}
|
|
}
|
|
|
|
return consumed;
|
|
|
|
fault:
|
|
desc->error = -EFAULT;
|
|
desc->count = 0;
|
|
return consumed;
|
|
}
|
|
|
|
static bool svc_tcp_at_urg_mark(struct sock *sk)
|
|
{
|
|
const struct tcp_sock *tp = tcp_sk(sk);
|
|
|
|
return tp->urg_data && tp->urg_seq == tp->copied_seq;
|
|
}
|
|
|
|
/**
|
|
* svc_tcp_recvfrom - Receive data from a TCP socket
|
|
* @rqstp: request structure into which to receive an RPC Call
|
|
*
|
|
* Called in a loop when XPT_DATA has been set.
|
|
*
|
|
* Context: Process context. Takes and releases the socket lock.
|
|
*
|
|
* Returns:
|
|
* On success, the number of bytes in a received RPC Call, or
|
|
* %0 if a complete RPC Call message was not ready to return
|
|
*
|
|
* The zero return case handles partial receives and callback Replies.
|
|
* The state of a partial receive is preserved in the svc_sock for
|
|
* the next call to svc_tcp_recvfrom.
|
|
*/
|
|
static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
|
|
{
|
|
struct svc_sock *svsk =
|
|
container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
|
|
struct svc_serv *serv = svsk->sk_xprt.xpt_server;
|
|
struct svc_tcp_recv_ctx ctx = {
|
|
.rqstp = rqstp,
|
|
};
|
|
read_descriptor_t desc = {
|
|
.arg.data = &ctx,
|
|
.count = serv->sv_max_mesg + sizeof(rpc_fraghdr),
|
|
};
|
|
struct socket *sock = svsk->sk_sock;
|
|
ssize_t len;
|
|
__be32 *p;
|
|
__be32 calldir;
|
|
|
|
clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
|
|
svc_tcp_restore_pages(svsk, rqstp);
|
|
|
|
lock_sock(sock->sk);
|
|
len = sock->ops->read_sock(sock->sk, &desc, svc_tcp_recv_actor);
|
|
/* ->read_sock stops at urgent data and consumes none of it.
|
|
* Only recvmsg() clears the condition, and this path calls
|
|
* none, so every later read stops at the same octet. An RPC
|
|
* stream carries no urgent data, so close the connection.
|
|
*
|
|
* The read that first reaches the mark consumes the octets
|
|
* ahead of it, so the stop does not show up as a zero len. A
|
|
* record completed ahead of the mark is returned first. The
|
|
* XPT_DATA set below brings the next call back here with
|
|
* nothing left to consume.
|
|
*/
|
|
if (!ctx.complete && svc_tcp_at_urg_mark(sock->sk))
|
|
desc.error = -EPROTO;
|
|
release_sock(sock->sk);
|
|
|
|
/* ->read_sock returns the octets consumed before an actor
|
|
* failure, so a positive len can accompany desc.error.
|
|
*/
|
|
if (desc.error < 0) {
|
|
len = desc.error;
|
|
goto err_nuts;
|
|
}
|
|
if (len >= 0)
|
|
trace_svcsock_tcp_recv(&svsk->sk_xprt, len);
|
|
|
|
if (!ctx.complete) {
|
|
if (!desc.count) {
|
|
set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
|
|
goto err_incomplete;
|
|
}
|
|
/* A zero return leaves no record at the head to classify.
|
|
* -EINVAL means a control record sits there. Screen the
|
|
* other errors out first, because a probe calls
|
|
* sock_error(), whose xchg clears sk->sk_err as it reads.
|
|
*/
|
|
if (len <= 0 && len != -EINVAL)
|
|
goto err_incomplete;
|
|
|
|
len = svc_tcp_recv_ctrl_record(svsk);
|
|
goto err_incomplete;
|
|
}
|
|
if (svsk->sk_datalen < 8)
|
|
goto err_nuts;
|
|
|
|
svc_tcp_flush_pages(svsk, rqstp);
|
|
|
|
rqstp->rq_arg.len = svsk->sk_datalen;
|
|
rqstp->rq_arg.page_base = 0;
|
|
if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len) {
|
|
rqstp->rq_arg.head[0].iov_len = rqstp->rq_arg.len;
|
|
rqstp->rq_arg.page_len = 0;
|
|
} else
|
|
rqstp->rq_arg.page_len = rqstp->rq_arg.len - rqstp->rq_arg.head[0].iov_len;
|
|
|
|
rqstp->rq_xprt_ctxt = NULL;
|
|
rqstp->rq_prot = IPPROTO_TCP;
|
|
assign_bit(RQ_LOCAL, &rqstp->rq_flags,
|
|
test_bit(XPT_LOCAL, &svsk->sk_xprt.xpt_flags));
|
|
|
|
/* Completing one message stops ->read_sock with whatever
|
|
* follows still queued, and no path from here re-arms XPT_DATA.
|
|
* The queued message would wait for unrelated traffic.
|
|
*/
|
|
set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
|
|
|
|
p = (__be32 *)rqstp->rq_arg.head[0].iov_base;
|
|
calldir = p[1];
|
|
if (calldir)
|
|
len = receive_cb_reply(svsk, rqstp);
|
|
|
|
/* Reset TCP read info */
|
|
svsk->sk_datalen = 0;
|
|
svc_tcp_fragment_received(svsk);
|
|
|
|
if (len < 0)
|
|
goto error;
|
|
|
|
svc_xprt_copy_addrs(rqstp, &svsk->sk_xprt);
|
|
if (serv->sv_stats)
|
|
serv->sv_stats->nettcpcnt++;
|
|
|
|
svc_sock_secure_port(rqstp);
|
|
svc_xprt_received(rqstp->rq_xprt);
|
|
return rqstp->rq_arg.len;
|
|
|
|
err_incomplete:
|
|
svc_tcp_save_pages(svsk, rqstp);
|
|
if (len < 0 && len != -EAGAIN)
|
|
goto err_delete;
|
|
if (svsk->sk_tcplen >= sizeof(rpc_fraghdr))
|
|
trace_svcsock_tcp_recv_short(&svsk->sk_xprt,
|
|
svc_sock_reclen(svsk),
|
|
svsk->sk_tcplen - sizeof(rpc_fraghdr));
|
|
else
|
|
trace_svcsock_tcp_recv_eagain(&svsk->sk_xprt, 0);
|
|
goto err_noclose;
|
|
error:
|
|
trace_svcsock_tcp_recv_eagain(&svsk->sk_xprt, 0);
|
|
goto err_noclose;
|
|
err_nuts:
|
|
/* svc_tcp_save_pages() has not run, so svsk->sk_pages[] is
|
|
* empty. A non-zero sk_datalen makes the teardown-time
|
|
* svc_tcp_clear_pages() walk empty slots and WARN.
|
|
*/
|
|
svsk->sk_datalen = 0;
|
|
err_delete:
|
|
trace_svcsock_tcp_recv_err(&svsk->sk_xprt, len);
|
|
svc_xprt_deferred_close(&svsk->sk_xprt);
|
|
err_noclose:
|
|
svc_xprt_received(rqstp->rq_xprt);
|
|
return 0; /* record not complete */
|
|
}
|
|
|
|
/*
|
|
* MSG_SPLICE_PAGES is used exclusively to reduce the number of
|
|
* copy operations in this path. Therefore the caller must ensure
|
|
* that the pages backing @xdr are unchanging.
|
|
*/
|
|
static int svc_tcp_sendmsg(struct svc_sock *svsk, struct svc_rqst *rqstp,
|
|
rpc_fraghdr marker)
|
|
{
|
|
struct msghdr msg = {
|
|
.msg_flags = MSG_SPLICE_PAGES,
|
|
};
|
|
int count;
|
|
void *buf;
|
|
int ret;
|
|
|
|
/* The stream record marker is copied into a temporary page
|
|
* fragment buffer so that it can be included in sk_bvec.
|
|
*/
|
|
buf = page_frag_alloc(&svsk->sk_frag_cache, sizeof(marker),
|
|
GFP_KERNEL);
|
|
if (!buf)
|
|
return -ENOMEM;
|
|
memcpy(buf, &marker, sizeof(marker));
|
|
bvec_set_virt(svsk->sk_bvec, buf, sizeof(marker));
|
|
|
|
count = xdr_buf_to_bvec(svsk->sk_bvec + 1, rqstp->rq_maxpages,
|
|
&rqstp->rq_res);
|
|
if (count < 0) {
|
|
ret = count;
|
|
goto out;
|
|
}
|
|
|
|
iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, svsk->sk_bvec,
|
|
1 + count, sizeof(marker) + rqstp->rq_res.len);
|
|
ret = sock_sendmsg(svsk->sk_sock, &msg);
|
|
out:
|
|
page_frag_free(buf);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* svc_tcp_sendto - Send out a reply on a TCP socket
|
|
* @rqstp: completed svc_rqst
|
|
*
|
|
* xpt_mutex ensures @rqstp's whole message is written to the socket
|
|
* without interruption.
|
|
*
|
|
* Returns the number of bytes sent, or a negative errno.
|
|
*/
|
|
static int svc_tcp_sendto(struct svc_rqst *rqstp)
|
|
{
|
|
struct svc_xprt *xprt = rqstp->rq_xprt;
|
|
struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
|
|
struct xdr_buf *xdr = &rqstp->rq_res;
|
|
rpc_fraghdr marker = cpu_to_be32(RPC_LAST_STREAM_FRAGMENT |
|
|
(u32)xdr->len);
|
|
int sent;
|
|
|
|
svc_tcp_release_ctxt(xprt, rqstp->rq_xprt_ctxt);
|
|
rqstp->rq_xprt_ctxt = NULL;
|
|
|
|
mutex_lock(&xprt->xpt_mutex);
|
|
if (svc_xprt_is_dead(xprt))
|
|
goto out_notconn;
|
|
sent = svc_tcp_sendmsg(svsk, rqstp, marker);
|
|
trace_svcsock_tcp_send(xprt, sent);
|
|
if (sent < 0 || sent != (xdr->len + sizeof(marker)))
|
|
goto out_close;
|
|
mutex_unlock(&xprt->xpt_mutex);
|
|
return sent;
|
|
|
|
out_notconn:
|
|
mutex_unlock(&xprt->xpt_mutex);
|
|
return -ENOTCONN;
|
|
out_close:
|
|
pr_notice("rpc-srv/tcp: %s: %s %d when sending %zu bytes - shutting down socket\n",
|
|
xprt->xpt_server->sv_name,
|
|
(sent < 0) ? "got error" : "sent",
|
|
sent, xdr->len + sizeof(marker));
|
|
svc_xprt_deferred_close(xprt);
|
|
mutex_unlock(&xprt->xpt_mutex);
|
|
return -EAGAIN;
|
|
}
|
|
|
|
static struct svc_xprt *svc_tcp_create(struct svc_serv *serv,
|
|
struct net *net,
|
|
struct sockaddr *sa, int salen,
|
|
int flags)
|
|
{
|
|
return svc_create_socket(serv, IPPROTO_TCP, net, sa, salen, flags);
|
|
}
|
|
|
|
static const struct svc_xprt_ops svc_tcp_ops = {
|
|
.xpo_create = svc_tcp_create,
|
|
.xpo_recvfrom = svc_tcp_recvfrom,
|
|
.xpo_sendto = svc_tcp_sendto,
|
|
.xpo_result_payload = svc_sock_result_payload,
|
|
.xpo_release_ctxt = svc_tcp_release_ctxt,
|
|
.xpo_detach = svc_tcp_sock_detach,
|
|
.xpo_free = svc_sock_free,
|
|
.xpo_has_wspace = svc_tcp_has_wspace,
|
|
.xpo_accept = svc_tcp_accept,
|
|
.xpo_kill_temp_xprt = svc_tcp_kill_temp_xprt,
|
|
.xpo_handshake = svc_tcp_handshake,
|
|
};
|
|
|
|
static struct svc_xprt_class svc_tcp_class = {
|
|
.xcl_name = "tcp",
|
|
.xcl_owner = THIS_MODULE,
|
|
.xcl_ops = &svc_tcp_ops,
|
|
.xcl_max_payload = RPCSVC_MAXPAYLOAD_TCP,
|
|
.xcl_ident = XPRT_TRANSPORT_TCP,
|
|
};
|
|
|
|
void svc_init_xprt_sock(void)
|
|
{
|
|
svc_reg_xprt_class(&svc_tcp_class);
|
|
svc_reg_xprt_class(&svc_udp_class);
|
|
}
|
|
|
|
void svc_cleanup_xprt_sock(void)
|
|
{
|
|
svc_unreg_xprt_class(&svc_tcp_class);
|
|
svc_unreg_xprt_class(&svc_udp_class);
|
|
}
|
|
|
|
static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv)
|
|
{
|
|
struct sock *sk = svsk->sk_sk;
|
|
|
|
svc_xprt_init(sock_net(svsk->sk_sock->sk), &svc_tcp_class,
|
|
&svsk->sk_xprt, serv);
|
|
set_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags);
|
|
set_bit(XPT_CONG_CTRL, &svsk->sk_xprt.xpt_flags);
|
|
if (sk->sk_state == TCP_LISTEN) {
|
|
strcpy(svsk->sk_xprt.xpt_remotebuf, "listener");
|
|
set_bit(XPT_LISTENER, &svsk->sk_xprt.xpt_flags);
|
|
set_bit(XPT_RPCB_UNREG, &svsk->sk_xprt.xpt_flags);
|
|
sk->sk_data_ready = svc_tcp_listen_data_ready;
|
|
set_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags);
|
|
} else {
|
|
sk->sk_state_change = svc_tcp_state_change;
|
|
sk->sk_data_ready = svc_data_ready;
|
|
sk->sk_write_space = svc_write_space;
|
|
|
|
svsk->sk_marker = xdr_zero;
|
|
svsk->sk_tcplen = 0;
|
|
svsk->sk_datalen = 0;
|
|
memset(&svsk->sk_pages[0], 0,
|
|
svsk->sk_maxpages * sizeof(struct page *));
|
|
|
|
tcp_sock_set_nodelay(sk);
|
|
|
|
set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
|
|
switch (sk->sk_state) {
|
|
case TCP_SYN_RECV:
|
|
case TCP_ESTABLISHED:
|
|
break;
|
|
default:
|
|
svc_xprt_deferred_close(&svsk->sk_xprt);
|
|
}
|
|
}
|
|
}
|
|
|
|
void svc_sock_update_bufs(struct svc_serv *serv)
|
|
{
|
|
/*
|
|
* The number of server threads has changed. Update
|
|
* rcvbuf and sndbuf accordingly on all sockets
|
|
*/
|
|
struct svc_sock *svsk;
|
|
|
|
spin_lock_bh(&serv->sv_lock);
|
|
list_for_each_entry(svsk, &serv->sv_permsocks, sk_xprt.xpt_list)
|
|
set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
|
|
spin_unlock_bh(&serv->sv_lock);
|
|
}
|
|
|
|
static int svc_sock_sendpages(struct svc_serv *serv, struct socket *sock, int flags)
|
|
{
|
|
switch (sock->type) {
|
|
case SOCK_STREAM:
|
|
/* +1 for TCP record marker */
|
|
if (flags & SVC_SOCK_TEMPORARY)
|
|
return svc_serv_maxpages(serv) + 1;
|
|
return 0;
|
|
case SOCK_DGRAM:
|
|
return SUNRPC_MAX_UDP_SENDPAGES;
|
|
}
|
|
return -EINVAL;
|
|
}
|
|
|
|
/*
|
|
* Initialize socket for RPC use and create svc_sock struct
|
|
*/
|
|
static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
|
|
struct socket *sock,
|
|
int flags)
|
|
{
|
|
struct svc_sock *svsk;
|
|
struct sock *inet;
|
|
int pmap_register = !(flags & SVC_SOCK_ANONYMOUS);
|
|
int sendpages;
|
|
unsigned long pages;
|
|
|
|
sendpages = svc_sock_sendpages(serv, sock, flags);
|
|
if (sendpages < 0)
|
|
return ERR_PTR(sendpages);
|
|
|
|
pages = svc_serv_maxpages(serv);
|
|
svsk = kzalloc_flex(*svsk, sk_pages, pages);
|
|
if (!svsk)
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
if (sendpages) {
|
|
svsk->sk_bvec = kzalloc_objs(*svsk->sk_bvec, sendpages);
|
|
if (!svsk->sk_bvec) {
|
|
kfree(svsk);
|
|
return ERR_PTR(-ENOMEM);
|
|
}
|
|
}
|
|
|
|
svsk->sk_maxpages = pages;
|
|
|
|
inet = sock->sk;
|
|
|
|
if (pmap_register) {
|
|
int err;
|
|
|
|
err = svc_register(serv, sock_net(sock->sk), inet->sk_family,
|
|
inet->sk_protocol,
|
|
ntohs(inet_sk(inet)->inet_sport));
|
|
if (err < 0) {
|
|
kfree(svsk->sk_bvec);
|
|
kfree(svsk);
|
|
return ERR_PTR(err);
|
|
}
|
|
}
|
|
|
|
svsk->sk_sock = sock;
|
|
svsk->sk_sk = inet;
|
|
svsk->sk_ostate = inet->sk_state_change;
|
|
svsk->sk_odata = inet->sk_data_ready;
|
|
svsk->sk_owspace = inet->sk_write_space;
|
|
/*
|
|
* This barrier is necessary in order to prevent race condition
|
|
* with svc_data_ready(), svc_tcp_listen_data_ready(), and others
|
|
* when calling callbacks above.
|
|
*/
|
|
wmb();
|
|
inet->sk_user_data = svsk;
|
|
|
|
/* Initialize the socket */
|
|
if (sock->type == SOCK_DGRAM)
|
|
svc_udp_init(svsk, serv);
|
|
else
|
|
svc_tcp_init(svsk, serv);
|
|
|
|
trace_svcsock_new(svsk, sock);
|
|
return svsk;
|
|
}
|
|
|
|
/**
|
|
* svc_addsock - add a listener socket to an RPC service
|
|
* @serv: pointer to RPC service to which to add a new listener
|
|
* @net: caller's network namespace
|
|
* @fd: file descriptor of the new listener
|
|
* @name_return: pointer to buffer to fill in with name of listener
|
|
* @len: size of the buffer
|
|
* @cred: credential
|
|
*
|
|
* Fills in socket name and returns positive length of name if successful.
|
|
* Name is terminated with '\n'. On error, returns a negative errno
|
|
* value.
|
|
*/
|
|
int svc_addsock(struct svc_serv *serv, struct net *net, const int fd,
|
|
char *name_return, const size_t len, const struct cred *cred)
|
|
{
|
|
int err = 0;
|
|
struct socket *so = sockfd_lookup(fd, &err);
|
|
struct svc_sock *svsk = NULL;
|
|
struct sockaddr_storage addr;
|
|
struct sockaddr *sin = (struct sockaddr *)&addr;
|
|
int salen;
|
|
|
|
if (!so)
|
|
return err;
|
|
err = -EINVAL;
|
|
if (sock_net(so->sk) != net)
|
|
goto out;
|
|
err = -EAFNOSUPPORT;
|
|
if ((so->sk->sk_family != PF_INET) && (so->sk->sk_family != PF_INET6))
|
|
goto out;
|
|
err = -EPROTONOSUPPORT;
|
|
if (so->sk->sk_protocol != IPPROTO_TCP &&
|
|
so->sk->sk_protocol != IPPROTO_UDP)
|
|
goto out;
|
|
err = -EISCONN;
|
|
if (so->state > SS_UNCONNECTED)
|
|
goto out;
|
|
err = -EBUSY;
|
|
if (so->sk->sk_user_data)
|
|
goto out;
|
|
err = -ENOENT;
|
|
if (!try_module_get(THIS_MODULE))
|
|
goto out;
|
|
svsk = svc_setup_socket(serv, so, SVC_SOCK_DEFAULTS);
|
|
if (IS_ERR(svsk)) {
|
|
module_put(THIS_MODULE);
|
|
err = PTR_ERR(svsk);
|
|
goto out;
|
|
}
|
|
salen = kernel_getsockname(svsk->sk_sock, sin);
|
|
if (salen >= 0)
|
|
svc_xprt_set_local(&svsk->sk_xprt, sin, salen);
|
|
svsk->sk_xprt.xpt_cred = get_cred(cred);
|
|
svc_add_new_perm_xprt(serv, &svsk->sk_xprt);
|
|
return svc_one_sock_name(svsk, name_return, len);
|
|
out:
|
|
sockfd_put(so);
|
|
return err;
|
|
}
|
|
EXPORT_SYMBOL_GPL(svc_addsock);
|
|
|
|
/*
|
|
* Create socket for RPC service.
|
|
*/
|
|
static struct svc_xprt *svc_create_socket(struct svc_serv *serv,
|
|
int protocol,
|
|
struct net *net,
|
|
struct sockaddr *sin, int len,
|
|
int flags)
|
|
{
|
|
struct svc_sock *svsk;
|
|
struct socket *sock;
|
|
int error;
|
|
int type;
|
|
struct sockaddr_storage addr;
|
|
struct sockaddr *newsin = (struct sockaddr *)&addr;
|
|
int newlen;
|
|
int family;
|
|
|
|
if (protocol != IPPROTO_UDP && protocol != IPPROTO_TCP) {
|
|
printk(KERN_WARNING "svc: only UDP and TCP "
|
|
"sockets supported\n");
|
|
return ERR_PTR(-EINVAL);
|
|
}
|
|
|
|
type = (protocol == IPPROTO_UDP)? SOCK_DGRAM : SOCK_STREAM;
|
|
switch (sin->sa_family) {
|
|
case AF_INET6:
|
|
family = PF_INET6;
|
|
break;
|
|
case AF_INET:
|
|
family = PF_INET;
|
|
break;
|
|
default:
|
|
return ERR_PTR(-EINVAL);
|
|
}
|
|
|
|
error = __sock_create(net, family, type, protocol, &sock, 1);
|
|
if (error < 0)
|
|
return ERR_PTR(error);
|
|
|
|
svc_reclassify_socket(sock);
|
|
|
|
/*
|
|
* If this is an PF_INET6 listener, we want to avoid
|
|
* getting requests from IPv4 remotes. Those should
|
|
* be shunted to a PF_INET listener via rpcbind.
|
|
*/
|
|
if (family == PF_INET6)
|
|
ip6_sock_set_v6only(sock->sk);
|
|
if (type == SOCK_STREAM)
|
|
sock->sk->sk_reuse = SK_CAN_REUSE; /* allow address reuse */
|
|
error = kernel_bind(sock, (struct sockaddr_unsized *)sin, len);
|
|
if (error < 0)
|
|
goto bummer;
|
|
|
|
error = kernel_getsockname(sock, newsin);
|
|
if (error < 0)
|
|
goto bummer;
|
|
newlen = error;
|
|
|
|
if (protocol == IPPROTO_TCP) {
|
|
sk_net_refcnt_upgrade(sock->sk);
|
|
if ((error = kernel_listen(sock, SOMAXCONN)) < 0)
|
|
goto bummer;
|
|
}
|
|
|
|
svsk = svc_setup_socket(serv, sock, flags);
|
|
if (IS_ERR(svsk)) {
|
|
error = PTR_ERR(svsk);
|
|
goto bummer;
|
|
}
|
|
svc_xprt_set_local(&svsk->sk_xprt, newsin, newlen);
|
|
return (struct svc_xprt *)svsk;
|
|
bummer:
|
|
sock_release(sock);
|
|
return ERR_PTR(error);
|
|
}
|
|
|
|
/*
|
|
* Detach the svc_sock from the socket so that no
|
|
* more callbacks occur.
|
|
*/
|
|
static void svc_sock_detach(struct svc_xprt *xprt)
|
|
{
|
|
struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
|
|
struct sock *sk = svsk->sk_sk;
|
|
|
|
/* put back the old socket callbacks */
|
|
lock_sock(sk);
|
|
sk->sk_state_change = svsk->sk_ostate;
|
|
sk->sk_data_ready = svsk->sk_odata;
|
|
sk->sk_write_space = svsk->sk_owspace;
|
|
sk->sk_user_data = NULL;
|
|
release_sock(sk);
|
|
}
|
|
|
|
/*
|
|
* Disconnect the socket, and reset the callbacks
|
|
*/
|
|
static void svc_tcp_sock_detach(struct svc_xprt *xprt)
|
|
{
|
|
struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
|
|
|
|
tls_handshake_close(svsk->sk_sock);
|
|
|
|
svc_sock_detach(xprt);
|
|
|
|
if (!test_bit(XPT_LISTENER, &xprt->xpt_flags)) {
|
|
svc_tcp_clear_pages(svsk);
|
|
kernel_sock_shutdown(svsk->sk_sock, SHUT_RDWR);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Free the svc_sock's socket resources and the svc_sock itself.
|
|
*/
|
|
static void svc_sock_free(struct svc_xprt *xprt)
|
|
{
|
|
struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
|
|
struct socket *sock = svsk->sk_sock;
|
|
|
|
trace_svcsock_free(svsk, sock);
|
|
|
|
tls_handshake_cancel(sock->sk);
|
|
if (sock->file)
|
|
sockfd_put(sock);
|
|
else
|
|
sock_release(sock);
|
|
|
|
page_frag_cache_drain(&svsk->sk_frag_cache);
|
|
kfree(svsk->sk_bvec);
|
|
kfree(svsk);
|
|
}
|