From: Chuck Lever <cel@kernel.org>
To: Trond Myklebust <trondmy@kernel.org>,
Anna Schumaker <anna@kernel.org>, Chuck Lever <cel@kernel.org>,
Jeff Layton <jlayton@kernel.org>, NeilBrown <neil@brown.name>,
Olga Kornievskaia <okorniev@redhat.com>,
Dai Ngo <Dai.Ngo@oracle.com>, Tom Talpey <tom@talpey.com>
Cc: linux-nfs@vger.kernel.org, netdev@vger.kernel.org
Subject: [PATCH v2 4/8] SUNRPC: resume receiving after a TLS control record
Date: Thu, 06 Aug 2026 16:20:19 -0400 [thread overview]
Message-ID: <20260806-svcsock-cmsg-fixes-v2-4-ef1b1fa7219a@kernel.org> (raw)
In-Reply-To: <20260806-svcsock-cmsg-fixes-v2-0-ef1b1fa7219a@kernel.org>
A TLS control record delivers no payload to the RPC layer.
svc_tcp_recvfrom() clears XPT_DATA before the receive, and
svc_tcp_sock_recv_cmsg() returns -EAGAIN for the record it consumed.
Nothing marks the transport ready again. kTLS raises data_ready for
arriving TCP segments, not for records it has already decrypted. An
RPC Call queued behind an alert or a KeyUpdate waits until the client
sends more. The client blocks until its RPC timeout expires.
The receive takes only the first two octets of the record. kTLS holds
the remainder on its receive list, where each later receive takes two
octets more.
Drain a record that is not an alert, then mark the transport ready
once a control record has been consumed.
Fixes: 5e052dda121e ("SUNRPC: Recognize control messages in server-side TCP socket code")
Signed-off-by: Chuck Lever <cel@kernel.org>
---
net/sunrpc/svcsock.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 52 insertions(+), 3 deletions(-)
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 756db84e4aec..6fee54f4290c 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -238,6 +238,39 @@ static int svc_one_sock_name(struct svc_sock *svsk, char *buf, int remaining)
return len;
}
+/*
+ * kTLS delivers a record only up to the caller's buffer and keeps
+ * the remainder on its receive list, where no further data_ready
+ * announces it. Consume the whole record.
+ */
+static void
+svc_tcp_sock_drain_record(struct socket *sock)
+{
+ union {
+ struct cmsghdr cmsg;
+ u8 buf[CMSG_SPACE(sizeof(u8))];
+ } u;
+ u8 discard[64];
+ struct kvec discard_kvec = {
+ .iov_base = discard,
+ .iov_len = sizeof(discard),
+ };
+
+ for (;;) {
+ struct msghdr msg = {
+ .msg_control = &u,
+ .msg_controllen = sizeof(u),
+ };
+
+ iov_iter_kvec(&msg.msg_iter, ITER_DEST, &discard_kvec, 1,
+ discard_kvec.iov_len);
+ if (sock_recvmsg(sock, &msg, MSG_DONTWAIT) <= 0)
+ break;
+ if (msg.msg_flags & MSG_EOR)
+ break;
+ }
+}
+
static int
svc_tcp_sock_process_cmsg(struct socket *sock, struct msghdr *msg,
struct cmsghdr *cmsg, int ret)
@@ -303,12 +336,20 @@ svc_tcp_sock_recv_cmsg(struct socket *sock, unsigned int *msg_flags)
* kTLS filled in u.cmsg.
*/
if (ret >= 0 && msg.msg_controllen < sizeof(u)) {
+ u8 content_type = tls_get_record_type(sock->sk, &u.cmsg);
+
/* Returning the count would credit the RPC stream with
* octets that never reached the caller's buffer.
*/
- if (tls_get_record_type(sock->sk, &u.cmsg) !=
- TLS_RECORD_TYPE_ALERT)
+ if (content_type != TLS_RECORD_TYPE_ALERT) {
+ /* Draining an application data record would
+ * discard the RPC stream.
+ */
+ if (content_type != TLS_RECORD_TYPE_DATA &&
+ !(msg.msg_flags & MSG_EOR))
+ svc_tcp_sock_drain_record(sock);
return -EAGAIN;
+ }
/* An Alert record carries exactly one two-octet message
* (RFC 8446 Section 5.1). alert_kvec caps the receive at two,
* so a longer record produces the same count. MSG_EOR appears
@@ -331,8 +372,16 @@ svc_tcp_sock_recvmsg(struct svc_sock *svsk, struct msghdr *msg)
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)
+ if (ret == 0 || ret == -EIO) {
ret = svc_tcp_sock_recv_cmsg(sock, &msg->msg_flags);
+ /* A control record delivers nothing to the caller,
+ * and kTLS announces no data_ready for records it
+ * already holds. Mark the transport ready so that
+ * the records behind this one can be received.
+ */
+ if (ret == -EAGAIN)
+ set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
+ }
}
return ret;
}
--
2.54.0
next prev parent reply other threads:[~2026-08-06 20:20 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-06 20:20 [PATCH v2 0/8] SUNRPC: Fix TLS control record handling Chuck Lever
2026-08-06 20:20 ` [PATCH v2 1/8] SUNRPC: do not credit control-record octets to the RPC stream Chuck Lever
2026-08-06 20:20 ` [PATCH v2 2/8] SUNRPC: reject a TLS alert record that is not two octets Chuck Lever
2026-08-06 20:20 ` [PATCH v2 3/8] SUNRPC: treat every TLS error alert as fatal Chuck Lever
2026-08-06 20:20 ` Chuck Lever [this message]
2026-08-06 20:20 ` [PATCH v2 5/8] SUNRPC: fold svc_tcp_sock_process_cmsg() into its only caller Chuck Lever
2026-08-06 20:20 ` [PATCH v2 6/8] SUNRPC: reject a client-side TLS alert record that is not two octets Chuck Lever
2026-08-06 20:20 ` [PATCH v2 7/8] SUNRPC: treat every client-side TLS error alert as fatal Chuck Lever
2026-08-06 20:20 ` [PATCH v2 8/8] SUNRPC: fold xs_sock_process_cmsg() into its only caller Chuck Lever
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260806-svcsock-cmsg-fixes-v2-4-ef1b1fa7219a@kernel.org \
--to=cel@kernel.org \
--cc=Dai.Ngo@oracle.com \
--cc=anna@kernel.org \
--cc=jlayton@kernel.org \
--cc=linux-nfs@vger.kernel.org \
--cc=neil@brown.name \
--cc=netdev@vger.kernel.org \
--cc=okorniev@redhat.com \
--cc=tom@talpey.com \
--cc=trondmy@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox