From: Chuck Lever <[email protected]>

The svcsock TCP receive path maintains two code paths: one
using read_sock/read_sock_rectype and a legacy path using
sock_recvmsg. Plain TCP sockets already provide read_sock
(tcp_read_sock) in their proto_ops, so a single
read_sock-based receive path handles all cases relevant to
NFSD, using read_sock_rectype under kTLS and read_sock
otherwise.

Signed-off-by: Chuck Lever <[email protected]>
---
 net/sunrpc/svcsock.c | 329 ++++-----------------------------------------------
 1 file changed, 26 insertions(+), 303 deletions(-)

diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index e40931d11491..9b9e0da9e73c 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -8,15 +8,6 @@
  * evenly when servicing a single client. May need to modify the
  * svc_xprt_enqueue procedure...
  *
- * TCP support is largely untested and may be a little slow. The problem
- * is that we currently do two separate recvfrom's, one for the 4-byte
- * record length, and the second for the actual record. This could possibly
- * be improved by always reading a minimum size of around 100 bytes and
- * tucking any superfluous bytes away in a temporary store. Still, that
- * leaves write requests out in the rain. An alternative may be to peek at
- * the first skb in the queue, and if it matches the next TCP sequence
- * number, to extract the record marker. Yuck.
- *
  * Copyright (C) 1995, 1996 Olaf Kirch <[email protected]>
  */
 
@@ -238,138 +229,6 @@ static int svc_one_sock_name(struct svc_sock *svsk, char 
*buf, int remaining)
        return len;
 }
 
-static int
-svc_tcp_sock_process_cmsg(struct socket *sock, struct msghdr *msg,
-                         struct cmsghdr *cmsg, int ret)
-{
-       u8 content_type = tls_get_record_type(sock->sk, cmsg);
-       u8 level, description;
-
-       switch (content_type) {
-       case 0:
-               break;
-       case TLS_RECORD_TYPE_DATA:
-               /* TLS sets EOR at the end of each application data
-                * record, even though there might be more frames
-                * waiting to be decrypted.
-                */
-               msg->msg_flags &= ~MSG_EOR;
-               break;
-       case TLS_RECORD_TYPE_ALERT:
-               tls_alert_recv(sock->sk, msg, &level, &description);
-               ret = (level == TLS_ALERT_LEVEL_FATAL) ?
-                       -ENOTCONN : -EAGAIN;
-               break;
-       default:
-               /* discard this record type */
-               ret = -EAGAIN;
-       }
-       return ret;
-}
-
-static int
-svc_tcp_sock_recv_cmsg(struct socket *sock, unsigned int *msg_flags)
-{
-       union {
-               struct cmsghdr  cmsg;
-               u8              buf[CMSG_SPACE(sizeof(u8))];
-       } u;
-       u8 alert[2];
-       struct kvec alert_kvec = {
-               .iov_base = alert,
-               .iov_len = sizeof(alert),
-       };
-       struct msghdr msg = {
-               .msg_flags = *msg_flags,
-               .msg_control = &u,
-               .msg_controllen = sizeof(u),
-       };
-       int ret;
-
-       iov_iter_kvec(&msg.msg_iter, ITER_DEST, &alert_kvec, 1,
-                     alert_kvec.iov_len);
-       ret = sock_recvmsg(sock, &msg, MSG_DONTWAIT);
-       if (ret > 0 &&
-           tls_get_record_type(sock->sk, &u.cmsg) == TLS_RECORD_TYPE_ALERT) {
-               iov_iter_revert(&msg.msg_iter, ret);
-               ret = svc_tcp_sock_process_cmsg(sock, &msg, &u.cmsg, -EAGAIN);
-       }
-       return ret;
-}
-
-static int
-svc_tcp_sock_recvmsg(struct svc_sock *svsk, struct msghdr *msg)
-{
-       int ret;
-       struct socket *sock = svsk->sk_sock;
-
-       ret = sock_recvmsg(sock, msg, MSG_DONTWAIT);
-       if (msg->msg_flags & MSG_CTRUNC) {
-               msg->msg_flags &= ~(MSG_CTRUNC | MSG_EOR);
-               if (ret == 0 || ret == -EIO)
-                       ret = svc_tcp_sock_recv_cmsg(sock, &msg->msg_flags);
-       }
-       return ret;
-}
-
-#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
-static void svc_flush_bvec(const struct bio_vec *bvec, size_t size, size_t 
seek)
-{
-       struct bvec_iter bi = {
-               .bi_size        = size + seek,
-       };
-       struct bio_vec bv;
-
-       bvec_iter_advance(bvec, &bi, seek & PAGE_MASK);
-       for_each_bvec(bv, bvec, bi, bi)
-               flush_dcache_page(bv.bv_page);
-}
-#else
-static inline void svc_flush_bvec(const struct bio_vec *bvec, size_t size,
-                                 size_t seek)
-{
-}
-#endif
-
-/*
- * Read from @rqstp's transport socket. The incoming message fills whole
- * pages in @rqstp's rq_pages array until the last page of the message
- * has been received into a partial page.
- */
-static ssize_t svc_tcp_read_msg(struct svc_rqst *rqstp, size_t buflen,
-                               size_t seek)
-{
-       struct svc_sock *svsk =
-               container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
-       struct bio_vec *bvec = rqstp->rq_bvec;
-       struct msghdr msg = { NULL };
-       unsigned int i;
-       ssize_t len;
-       size_t t;
-
-       clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
-
-       for (i = 0, t = 0; t < buflen; i++, t += PAGE_SIZE)
-               bvec_set_page(&bvec[i], rqstp->rq_pages[i], PAGE_SIZE, 0);
-
-       iov_iter_bvec(&msg.msg_iter, ITER_DEST, bvec, i, buflen);
-       if (seek) {
-               iov_iter_advance(&msg.msg_iter, seek);
-               buflen -= seek;
-       }
-       len = svc_tcp_sock_recvmsg(svsk, &msg);
-       if (len > 0)
-               svc_flush_bvec(bvec, len, seek);
-
-       /* If we read a full record, then assume there may be more
-        * data to read (stream based sockets only!)
-        */
-       if (len == buflen)
-               set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
-
-       return len;
-}
-
 /*
  * Set socket snd and rcv buffer lengths
  */
@@ -1048,50 +907,6 @@ static void svc_tcp_clear_pages(struct svc_sock *svsk)
        svsk->sk_datalen = 0;
 }
 
-/*
- * Receive fragment record header into sk_marker.
- */
-static ssize_t svc_tcp_read_marker(struct svc_sock *svsk,
-                                  struct svc_rqst *rqstp)
-{
-       ssize_t want, len;
-
-       /* If we haven't gotten the record length yet,
-        * get the next four bytes.
-        */
-       if (svsk->sk_tcplen < sizeof(rpc_fraghdr)) {
-               struct msghdr   msg = { NULL };
-               struct kvec     iov;
-
-               want = sizeof(rpc_fraghdr) - svsk->sk_tcplen;
-               iov.iov_base = ((char *)&svsk->sk_marker) + svsk->sk_tcplen;
-               iov.iov_len  = want;
-               iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, want);
-               len = svc_tcp_sock_recvmsg(svsk, &msg);
-               if (len < 0)
-                       return len;
-               svsk->sk_tcplen += len;
-               if (len < want) {
-                       /* call again to read the remaining bytes */
-                       goto err_short;
-               }
-               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)
-                       goto err_too_large;
-       }
-       return svc_sock_reclen(svsk);
-
-err_too_large:
-       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);
-       svc_xprt_deferred_close(&svsk->sk_xprt);
-err_short:
-       return -EAGAIN;
-}
-
 static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp)
 {
        struct rpc_xprt *bc_xprt = svsk->sk_xprt.xpt_bc_xprt;
@@ -1135,10 +950,10 @@ static void svc_tcp_fragment_received(struct svc_sock 
*svsk)
 }
 
 /*
- * read_sock_rectype data actor: receives decrypted application data
- * from the TLS layer, parsing the RPC record stream (fragment
- * headers and message bodies) and assembling complete RPC messages
- * into rqstp->rq_pages.
+ * read_sock data actor: receives application data from the
+ * transport socket, parsing the RPC record stream (fragment
+ * headers and message bodies) and assembling complete RPC
+ * messages into rqstp->rq_pages.
  */
 static int svc_tcp_recv_actor(read_descriptor_t *desc,
                              struct sk_buff *skb,
@@ -1266,7 +1081,21 @@ static int svc_tcp_rectype_actor(read_descriptor_t *desc,
        return 0;
 }
 
-static int svc_tcp_recvfrom_readsock(struct svc_rqst *rqstp)
+/**
+ * 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.
+ *
+ * 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);
@@ -1286,9 +1115,13 @@ static int svc_tcp_recvfrom_readsock(struct svc_rqst 
*rqstp)
 
        desc.count = serv->sv_max_mesg;
        lock_sock(sk);
-       len = svsk->sk_sock->ops->read_sock_rectype(sk, &desc,
-                                                   svc_tcp_recv_actor,
-                                                   svc_tcp_rectype_actor);
+       if (svsk->sk_sock->ops->read_sock_rectype)
+               len = svsk->sk_sock->ops->read_sock_rectype(sk, &desc,
+                                                           svc_tcp_recv_actor,
+                                                           
svc_tcp_rectype_actor);
+       else
+               len = svsk->sk_sock->ops->read_sock(sk, &desc,
+                                                    svc_tcp_recv_actor);
        release_sock(sk);
 
        if (desc.error < 0) {
@@ -1375,116 +1208,6 @@ static int svc_tcp_recvfrom_readsock(struct svc_rqst 
*rqstp)
        return 0;
 }
 
-/**
- * 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.
- *
- * Read the 4-byte stream record marker, then use the record length
- * in that marker to set up exactly the resources needed to receive
- * the next RPC message into @rqstp.
- *
- * 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;
-       size_t want, base;
-       ssize_t len;
-       __be32 *p;
-       __be32 calldir;
-
-       if (svsk->sk_sock->ops->read_sock_rectype)
-               return svc_tcp_recvfrom_readsock(rqstp);
-
-       clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
-       len = svc_tcp_read_marker(svsk, rqstp);
-       if (len < 0)
-               goto error;
-
-       base = svc_tcp_restore_pages(svsk, rqstp);
-       want = len - (svsk->sk_tcplen - sizeof(rpc_fraghdr));
-       len = svc_tcp_read_msg(rqstp, base + want, base);
-       if (len >= 0) {
-               trace_svcsock_tcp_recv(&svsk->sk_xprt, len);
-               svsk->sk_tcplen += len;
-               svsk->sk_datalen += len;
-       }
-       if (len != want || !svc_sock_final_rec(svsk))
-               goto err_incomplete;
-       if (svsk->sk_datalen < 8)
-               goto err_nuts;
-
-       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;
-       if (test_bit(XPT_LOCAL, &svsk->sk_xprt.xpt_flags))
-               set_bit(RQ_LOCAL, &rqstp->rq_flags);
-       else
-               clear_bit(RQ_LOCAL, &rqstp->rq_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 (len == want)
-               svc_tcp_fragment_received(svsk);
-       else
-               trace_svcsock_tcp_recv_short(&svsk->sk_xprt,
-                               svc_sock_reclen(svsk),
-                               svsk->sk_tcplen - sizeof(rpc_fraghdr));
-       goto err_noclose;
-error:
-       if (len != -EAGAIN)
-               goto err_delete;
-       trace_svcsock_tcp_recv_eagain(&svsk->sk_xprt, 0);
-       goto err_noclose;
-err_nuts:
-       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

-- 
2.54.0


Reply via email to