Skip to content

Commit

Permalink
SUNRPC: Send RPC message on TCP with a single sock_sendmsg() call
Browse files Browse the repository at this point in the history
There is now enough infrastructure in place to combine the stream
record marker into the biovec array used to send each outgoing RPC
message on TCP. The whole message can be more efficiently sent with
a single call to sock_sendmsg() using a bio_vec iterator.

Note that this also helps with RPC-with-TLS: the TLS implementation
can now clearly see where the upper layer message boundaries are.
Before, it would send each component of the xdr_buf (record marker,
head, page payload, tail) in separate TLS records.

Suggested-by: David Howells <dhowells@redhat.com>
Reviewed-by: David Howells <dhowells@redhat.com>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
  • Loading branch information
Chuck Lever committed Aug 29, 2023
1 parent 2eb2b93 commit e18e157
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 15 deletions.
2 changes: 2 additions & 0 deletions include/linux/sunrpc/svcsock.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ struct svc_sock {
/* Number of queued send requests */
atomic_t sk_sendqlen;

struct page_frag_cache sk_frag_cache;

struct completion sk_handshake_done;

struct page * sk_pages[RPCSVC_MAXPAGES]; /* received data */
Expand Down
33 changes: 18 additions & 15 deletions net/sunrpc/svcsock.c
Original file line number Diff line number Diff line change
Expand Up @@ -1213,31 +1213,30 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
static int svc_tcp_sendmsg(struct svc_sock *svsk, struct svc_rqst *rqstp,
rpc_fraghdr marker, unsigned int *sentp)
{
struct kvec rm = {
.iov_base = &marker,
.iov_len = sizeof(marker),
};
struct msghdr msg = {
.msg_flags = MSG_MORE,
.msg_flags = MSG_SPLICE_PAGES,
};
unsigned int count;
void *buf;
int ret;

*sentp = 0;

ret = kernel_sendmsg(svsk->sk_sock, &msg, &rm, 1, rm.iov_len);
if (ret < 0)
return ret;
*sentp += ret;
if (ret != rm.iov_len)
return -EAGAIN;
/* The stream record marker is copied into a temporary page
* fragment buffer so that it can be included in rq_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(rqstp->rq_bvec, buf, sizeof(marker));

count = xdr_buf_to_bvec(rqstp->rq_bvec, ARRAY_SIZE(rqstp->rq_bvec),
&rqstp->rq_res);
count = xdr_buf_to_bvec(rqstp->rq_bvec + 1,
ARRAY_SIZE(rqstp->rq_bvec) - 1, &rqstp->rq_res);

msg.msg_flags = MSG_SPLICE_PAGES;
iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, rqstp->rq_bvec,
count, rqstp->rq_res.len);
1 + count, sizeof(marker) + rqstp->rq_res.len);
ret = sock_sendmsg(svsk->sk_sock, &msg);
if (ret < 0)
return ret;
Expand Down Expand Up @@ -1616,6 +1615,7 @@ static void svc_tcp_sock_detach(struct svc_xprt *xprt)
static void svc_sock_free(struct svc_xprt *xprt)
{
struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
struct page_frag_cache *pfc = &svsk->sk_frag_cache;
struct socket *sock = svsk->sk_sock;

trace_svcsock_free(svsk, sock);
Expand All @@ -1625,5 +1625,8 @@ static void svc_sock_free(struct svc_xprt *xprt)
sockfd_put(sock);
else
sock_release(sock);
if (pfc->va)
__page_frag_cache_drain(virt_to_head_page(pfc->va),
pfc->pagecnt_bias);
kfree(svsk);
}

0 comments on commit e18e157

Please sign in to comment.