From: Chuck Lever 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 --- 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 */ @@ -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