[PATCH net-next v9 5/5] tls: Flush backlog before waiting for a new record
Chuck Lever <[email protected]> Wed, 29 Apr 2026 17:48:12 -0400
| Newsgroups | dev.linux.lists.kernel-tls-handshake,org.kernel.vger.netdev |
|---|---|
| Message-ID | <[email protected]> |
From: Chuck Lever <[email protected]> While lock_sock is held, incoming TCP segments land on sk->sk_backlog rather than sk->sk_receive_queue. tls_rx_rec_wait() inspects only sk_receive_queue, so backlog data remains invisible. For non-blocking callers (read_sock, and recvmsg or splice_read with MSG_DONTWAIT) this causes a spurious -EAGAIN. For blocking callers it forces an unnecessary sleep/wakeup cycle. Flush the backlog inside tls_rx_rec_wait() before checking sk_receive_queue so the strparser can parse newly-arrived segments immediately. On the next loop iteration tls_read_flush_backlog() may redundantly flush, but this path is cold and the cost is negligible. Backlog processing can run tcp_reset(), which sets both sk->sk_err = ECONNRESET and (via tcp_done()) sk->sk_shutdown = SHUTDOWN_MASK. The pre-existing top-of-loop sk_err check already ran before the flush, so without further care the freshly-set error would be masked by the next-line sk_shutdown test returning 0 (EOF). Re-check sk_err immediately before the sk_shutdown test so a connection abort surfaces as -ECONNRESET rather than a clean EOF. Suggested-by: Sabrina Dubroca <[email protected]> Reviewed-by: Hannes Reinecke <[email protected]> Signed-off-by: Chuck Lever <[email protected]> --- net/tls/tls_sw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index cbb068266bab..b888aaa505c0 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -1382,6 +1382,8 @@ tls_rx_rec_wait(struct sock *sk, struct sk_psock *psock, bool nonblock, if (ret < 0) return ret; + if (sk_flush_backlog(sk)) + released = true; if (!skb_queue_empty(&sk->sk_receive_queue)) { /* Defer notification to the exit point; * this thread will consume the record @@ -1392,6 +1394,8 @@ tls_rx_rec_wait(struct sock *sk, struct sk_psock *psock, bool nonblock, break; } + if (sk->sk_err) + return sock_error(sk); if (sk->sk_shutdown & RCV_SHUTDOWN) return 0; -- 2.53.0