forked from Minki/linux
SUNRPC: Teach server to use xprt_sock_sendmsg for socket sends
xprt_sock_sendmsg uses the more efficient iov_iter-enabled kernel socket API, and is a pre-requisite for server send-side support for TLS. Note that svc_process no longer needs to reserve a word for the stream record marker, since the TCP transport now provides the record marker automatically in a separate buffer. The dprintk() in svc_send_common is also removed. It didn't seem crucial for field troubleshooting. If more is needed there, a trace point could be added in xprt_sock_sendmsg(). Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
This commit is contained in:
parent
9e55eef4ab
commit
da1661b93b
@ -50,10 +50,6 @@ static inline int sock_is_loopback(struct sock *sk)
|
|||||||
return loopback;
|
return loopback;
|
||||||
}
|
}
|
||||||
|
|
||||||
int svc_send_common(struct socket *sock, struct xdr_buf *xdr,
|
|
||||||
struct page *headpage, unsigned long headoffset,
|
|
||||||
struct page *tailpage, unsigned long tailoffset);
|
|
||||||
|
|
||||||
int rpc_clients_notifier_register(void);
|
int rpc_clients_notifier_register(void);
|
||||||
void rpc_clients_notifier_unregister(void);
|
void rpc_clients_notifier_unregister(void);
|
||||||
#endif /* _NET_SUNRPC_SUNRPC_H */
|
#endif /* _NET_SUNRPC_SUNRPC_H */
|
||||||
|
@ -1529,10 +1529,6 @@ svc_process(struct svc_rqst *rqstp)
|
|||||||
goto out_drop;
|
goto out_drop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reserve space for the record marker */
|
|
||||||
if (rqstp->rq_prot == IPPROTO_TCP)
|
|
||||||
svc_putnl(resv, 0);
|
|
||||||
|
|
||||||
/* Returns 1 for send, 0 for drop */
|
/* Returns 1 for send, 0 for drop */
|
||||||
if (likely(svc_process_common(rqstp, argv, resv)))
|
if (likely(svc_process_common(rqstp, argv, resv)))
|
||||||
return svc_send(rqstp);
|
return svc_send(rqstp);
|
||||||
|
@ -175,111 +175,6 @@ static void svc_set_cmsg_data(struct svc_rqst *rqstp, struct cmsghdr *cmh)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* send routine intended to be shared by the fore- and back-channel
|
|
||||||
*/
|
|
||||||
int svc_send_common(struct socket *sock, struct xdr_buf *xdr,
|
|
||||||
struct page *headpage, unsigned long headoffset,
|
|
||||||
struct page *tailpage, unsigned long tailoffset)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
int size;
|
|
||||||
struct page **ppage = xdr->pages;
|
|
||||||
size_t base = xdr->page_base;
|
|
||||||
unsigned int pglen = xdr->page_len;
|
|
||||||
unsigned int flags = MSG_MORE | MSG_SENDPAGE_NOTLAST;
|
|
||||||
int slen;
|
|
||||||
int len = 0;
|
|
||||||
|
|
||||||
slen = xdr->len;
|
|
||||||
|
|
||||||
/* send head */
|
|
||||||
if (slen == xdr->head[0].iov_len)
|
|
||||||
flags = 0;
|
|
||||||
len = kernel_sendpage(sock, headpage, headoffset,
|
|
||||||
xdr->head[0].iov_len, flags);
|
|
||||||
if (len != xdr->head[0].iov_len)
|
|
||||||
goto out;
|
|
||||||
slen -= xdr->head[0].iov_len;
|
|
||||||
if (slen == 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/* send page data */
|
|
||||||
size = PAGE_SIZE - base < pglen ? PAGE_SIZE - base : pglen;
|
|
||||||
while (pglen > 0) {
|
|
||||||
if (slen == size)
|
|
||||||
flags = 0;
|
|
||||||
result = kernel_sendpage(sock, *ppage, base, size, flags);
|
|
||||||
if (result > 0)
|
|
||||||
len += result;
|
|
||||||
if (result != size)
|
|
||||||
goto out;
|
|
||||||
slen -= size;
|
|
||||||
pglen -= size;
|
|
||||||
size = PAGE_SIZE < pglen ? PAGE_SIZE : pglen;
|
|
||||||
base = 0;
|
|
||||||
ppage++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* send tail */
|
|
||||||
if (xdr->tail[0].iov_len) {
|
|
||||||
result = kernel_sendpage(sock, tailpage, tailoffset,
|
|
||||||
xdr->tail[0].iov_len, 0);
|
|
||||||
if (result > 0)
|
|
||||||
len += result;
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Generic sendto routine
|
|
||||||
*/
|
|
||||||
static int svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr)
|
|
||||||
{
|
|
||||||
struct svc_sock *svsk =
|
|
||||||
container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
|
|
||||||
struct socket *sock = svsk->sk_sock;
|
|
||||||
union {
|
|
||||||
struct cmsghdr hdr;
|
|
||||||
long all[SVC_PKTINFO_SPACE / sizeof(long)];
|
|
||||||
} buffer;
|
|
||||||
struct cmsghdr *cmh = &buffer.hdr;
|
|
||||||
int len = 0;
|
|
||||||
unsigned long tailoff;
|
|
||||||
unsigned long headoff;
|
|
||||||
RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
|
|
||||||
|
|
||||||
if (rqstp->rq_prot == IPPROTO_UDP) {
|
|
||||||
struct msghdr msg = {
|
|
||||||
.msg_name = &rqstp->rq_addr,
|
|
||||||
.msg_namelen = rqstp->rq_addrlen,
|
|
||||||
.msg_control = cmh,
|
|
||||||
.msg_controllen = sizeof(buffer),
|
|
||||||
.msg_flags = MSG_MORE,
|
|
||||||
};
|
|
||||||
|
|
||||||
svc_set_cmsg_data(rqstp, cmh);
|
|
||||||
|
|
||||||
if (sock_sendmsg(sock, &msg) < 0)
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
tailoff = ((unsigned long)xdr->tail[0].iov_base) & (PAGE_SIZE-1);
|
|
||||||
headoff = 0;
|
|
||||||
len = svc_send_common(sock, xdr, rqstp->rq_respages[0], headoff,
|
|
||||||
rqstp->rq_respages[0], tailoff);
|
|
||||||
|
|
||||||
out:
|
|
||||||
dprintk("svc: socket %p sendto([%p %zu... ], %d) = %d (addr %s)\n",
|
|
||||||
svsk, xdr->head[0].iov_base, xdr->head[0].iov_len,
|
|
||||||
xdr->len, len, svc_print_addr(rqstp, buf, sizeof(buf)));
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int svc_sock_read_payload(struct svc_rqst *rqstp, unsigned int offset,
|
static int svc_sock_read_payload(struct svc_rqst *rqstp, unsigned int offset,
|
||||||
unsigned int length)
|
unsigned int length)
|
||||||
{
|
{
|
||||||
@ -607,17 +502,43 @@ out_free:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
/**
|
||||||
svc_udp_sendto(struct svc_rqst *rqstp)
|
* svc_udp_sendto - Send out a reply on a UDP socket
|
||||||
|
* @rqstp: completed svc_rqst
|
||||||
|
*
|
||||||
|
* Returns the number of bytes sent, or a negative errno.
|
||||||
|
*/
|
||||||
|
static int svc_udp_sendto(struct svc_rqst *rqstp)
|
||||||
{
|
{
|
||||||
int error;
|
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_controllen = sizeof(buffer),
|
||||||
|
};
|
||||||
|
unsigned int uninitialized_var(sent);
|
||||||
|
int err;
|
||||||
|
|
||||||
error = svc_sendto(rqstp, &rqstp->rq_res);
|
svc_set_cmsg_data(rqstp, cmh);
|
||||||
if (error == -ECONNREFUSED)
|
|
||||||
|
err = xprt_sock_sendmsg(svsk->sk_sock, &msg, xdr, 0, 0, &sent);
|
||||||
|
xdr_free_bvec(xdr);
|
||||||
|
if (err == -ECONNREFUSED) {
|
||||||
/* ICMP error on earlier request. */
|
/* ICMP error on earlier request. */
|
||||||
error = svc_sendto(rqstp, &rqstp->rq_res);
|
err = xprt_sock_sendmsg(svsk->sk_sock, &msg, xdr, 0, 0, &sent);
|
||||||
|
xdr_free_bvec(xdr);
|
||||||
return error;
|
}
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
return sent;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int svc_udp_has_wspace(struct svc_xprt *xprt)
|
static int svc_udp_has_wspace(struct svc_xprt *xprt)
|
||||||
@ -1136,35 +1057,39 @@ err_noclose:
|
|||||||
return 0; /* record not complete */
|
return 0; /* record not complete */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Send out data on TCP socket.
|
* svc_tcp_sendto - Send out a reply on a TCP socket
|
||||||
|
* @rqstp: completed svc_rqst
|
||||||
|
*
|
||||||
|
* Returns the number of bytes sent, or a negative errno.
|
||||||
*/
|
*/
|
||||||
static int svc_tcp_sendto(struct svc_rqst *rqstp)
|
static int svc_tcp_sendto(struct svc_rqst *rqstp)
|
||||||
{
|
{
|
||||||
struct xdr_buf *xbufp = &rqstp->rq_res;
|
struct svc_xprt *xprt = rqstp->rq_xprt;
|
||||||
int sent;
|
struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
|
||||||
__be32 reclen;
|
struct xdr_buf *xdr = &rqstp->rq_res;
|
||||||
|
rpc_fraghdr marker = cpu_to_be32(RPC_LAST_STREAM_FRAGMENT |
|
||||||
|
(u32)xdr->len);
|
||||||
|
struct msghdr msg = {
|
||||||
|
.msg_flags = 0,
|
||||||
|
};
|
||||||
|
unsigned int uninitialized_var(sent);
|
||||||
|
int err;
|
||||||
|
|
||||||
/* Set up the first element of the reply kvec.
|
err = xprt_sock_sendmsg(svsk->sk_sock, &msg, xdr, 0, marker, &sent);
|
||||||
* Any other kvecs that may be in use have been taken
|
xdr_free_bvec(xdr);
|
||||||
* care of by the server implementation itself.
|
if (err < 0 || sent != (xdr->len + sizeof(marker)))
|
||||||
*/
|
goto out_close;
|
||||||
reclen = htonl(0x80000000|((xbufp->len ) - 4));
|
|
||||||
memcpy(xbufp->head[0].iov_base, &reclen, 4);
|
|
||||||
|
|
||||||
sent = svc_sendto(rqstp, &rqstp->rq_res);
|
|
||||||
if (sent != xbufp->len) {
|
|
||||||
printk(KERN_NOTICE
|
|
||||||
"rpc-srv/tcp: %s: %s %d when sending %d bytes "
|
|
||||||
"- shutting down socket\n",
|
|
||||||
rqstp->rq_xprt->xpt_server->sv_name,
|
|
||||||
(sent<0)?"got error":"sent only",
|
|
||||||
sent, xbufp->len);
|
|
||||||
set_bit(XPT_CLOSE, &rqstp->rq_xprt->xpt_flags);
|
|
||||||
svc_xprt_enqueue(rqstp->rq_xprt);
|
|
||||||
sent = -EAGAIN;
|
|
||||||
}
|
|
||||||
return sent;
|
return sent;
|
||||||
|
|
||||||
|
out_close:
|
||||||
|
pr_notice("rpc-srv/tcp: %s: %s %d when sending %d bytes - shutting down socket\n",
|
||||||
|
xprt->xpt_server->sv_name,
|
||||||
|
(err < 0) ? "got error" : "sent",
|
||||||
|
(err < 0) ? err : sent, xdr->len);
|
||||||
|
set_bit(XPT_CLOSE, &xprt->xpt_flags);
|
||||||
|
svc_xprt_enqueue(xprt);
|
||||||
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct svc_xprt *svc_tcp_create(struct svc_serv *serv,
|
static struct svc_xprt *svc_tcp_create(struct svc_serv *serv,
|
||||||
|
@ -2527,46 +2527,25 @@ static void bc_free(struct rpc_task *task)
|
|||||||
free_page((unsigned long)buf);
|
free_page((unsigned long)buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Use the svc_sock to send the callback. Must be called with svsk->sk_mutex
|
|
||||||
* held. Borrows heavily from svc_tcp_sendto and xs_tcp_send_request.
|
|
||||||
*/
|
|
||||||
static int bc_sendto(struct rpc_rqst *req)
|
static int bc_sendto(struct rpc_rqst *req)
|
||||||
{
|
{
|
||||||
int len;
|
struct xdr_buf *xdr = &req->rq_snd_buf;
|
||||||
struct xdr_buf *xbufp = &req->rq_snd_buf;
|
|
||||||
struct sock_xprt *transport =
|
struct sock_xprt *transport =
|
||||||
container_of(req->rq_xprt, struct sock_xprt, xprt);
|
container_of(req->rq_xprt, struct sock_xprt, xprt);
|
||||||
unsigned long headoff;
|
|
||||||
unsigned long tailoff;
|
|
||||||
struct page *tailpage;
|
|
||||||
struct msghdr msg = {
|
struct msghdr msg = {
|
||||||
.msg_flags = MSG_MORE
|
.msg_flags = 0,
|
||||||
};
|
};
|
||||||
rpc_fraghdr marker = cpu_to_be32(RPC_LAST_STREAM_FRAGMENT |
|
rpc_fraghdr marker = cpu_to_be32(RPC_LAST_STREAM_FRAGMENT |
|
||||||
(u32)xbufp->len);
|
(u32)xdr->len);
|
||||||
struct kvec iov = {
|
unsigned int sent = 0;
|
||||||
.iov_base = &marker,
|
int err;
|
||||||
.iov_len = sizeof(marker),
|
|
||||||
};
|
|
||||||
|
|
||||||
req->rq_xtime = ktime_get();
|
req->rq_xtime = ktime_get();
|
||||||
|
err = xprt_sock_sendmsg(transport->sock, &msg, xdr, 0, marker, &sent);
|
||||||
len = kernel_sendmsg(transport->sock, &msg, &iov, 1, iov.iov_len);
|
xdr_free_bvec(xdr);
|
||||||
if (len != iov.iov_len)
|
if (err < 0 || sent != (xdr->len + sizeof(marker)))
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
return sent;
|
||||||
tailpage = NULL;
|
|
||||||
if (xbufp->tail[0].iov_len)
|
|
||||||
tailpage = virt_to_page(xbufp->tail[0].iov_base);
|
|
||||||
tailoff = (unsigned long)xbufp->tail[0].iov_base & ~PAGE_MASK;
|
|
||||||
headoff = (unsigned long)xbufp->head[0].iov_base & ~PAGE_MASK;
|
|
||||||
len = svc_send_common(transport->sock, xbufp,
|
|
||||||
virt_to_page(xbufp->head[0].iov_base), headoff,
|
|
||||||
tailpage, tailoff);
|
|
||||||
if (len != xbufp->len)
|
|
||||||
return -EAGAIN;
|
|
||||||
return len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user