@@ -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 bio_vec sk_recv_bvec[RPCSVC_MAXPAGES]
@@ -1247,29 +1247,28 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
static int svc_tcp_sendmsg(struct svc_sock *svsk, struct xdr_buf *xdr,
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 *tmp;
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;
-
- count = svc_sock_xdr_to_bvecs(svsk->sk_send_bvec, xdr);
- msg.msg_flags = MSG_SPLICE_PAGES;
+ /* The stream record marker is copied into a temporary page
+ * buffer so that it can be included in sk_send_bvec.
+ */
+ tmp = page_frag_alloc(&svsk->sk_frag_cache, sizeof(marker),
+ GFP_KERNEL);
+ if (!tmp)
+ return -ENOMEM;
+ memcpy(tmp, &marker, sizeof(marker));
+ bvec_set_virt(svsk->sk_send_bvec, tmp, sizeof(marker));
+
+ count = svc_sock_xdr_to_bvecs(svsk->sk_send_bvec + 1, xdr);
iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, svsk->sk_send_bvec,
- count, xdr->len);
+ 1 + count, sizeof(marker) + xdr->len);
ret = sock_sendmsg(svsk->sk_sock, &msg);
if (ret < 0)
return ret;
@@ -1648,6 +1647,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);
@@ -1657,5 +1657,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);
}