From 1d475b1dbf22dac4a9fda3ebb444b0343392c5c3 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 28 May 2026 15:02:07 +1000 Subject: tcp_splice: Simplify EPOLLRDHUP / eof / FIN handling There are two ways we can tell one of our sockets has received a FIN. We can either see an EPOLLRDHUP epoll event, or we can get a zero-length read (EOF) on the socket. We currently use both, in a mildly confusing way: we only set the FIN_RCVD() flag based on the EPOLLRDHUP event, but then some other close out logic is based on seeing an EOF. Simplify this by setting the flag based on only the EOF. To make sure we don't miss an event if we get an EPOLLRDHUP with no data, we trigger the forwarding path for EPOLLRDHUP as well as EPOLLIN. Signed-off-by: David Gibson Signed-off-by: Stefano Brivio --- tcp_splice.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/tcp_splice.c b/tcp_splice.c index c066d68..25e5d09 100644 --- a/tcp_splice.c +++ b/tcp_splice.c @@ -477,7 +477,6 @@ static int tcp_splice_forward(struct ctx *c, uint8_t lowat_set_flag = RCVLOWAT_SET(fromsidei); uint8_t lowat_act_flag = RCVLOWAT_ACT(fromsidei); int never_read = 1; - int eof = 0; while (1) { ssize_t readlen, written; @@ -501,7 +500,7 @@ retry: flow_trace(conn, "%zi from read-side call", readlen); if (!readlen) { - eof = 1; + conn_event(conn, FIN_RCVD(fromsidei)); } else if (readlen > 0) { never_read = 0; @@ -551,11 +550,12 @@ retry: written < conn->pending[fromsidei]) goto retry; - if (eof) + if (conn->events & FIN_RCVD(fromsidei)) break; } - if (!conn->pending[fromsidei] && eof) { + if (!conn->pending[fromsidei] && + conn->events & FIN_RCVD(fromsidei)) { unsigned sidei; flow_foreach_sidei(sidei) { @@ -620,17 +620,13 @@ void tcp_splice_sock_handler(struct ctx *c, union epoll_ref ref, goto reset; } - if (events & EPOLLRDHUP) - /* For side 0 this is fake, but implied */ - conn_event(conn, FIN_RCVD(evsidei)); - if (events & EPOLLOUT) { if (tcp_splice_forward(c, conn, !evsidei, now)) goto reset; conn_event(conn, ~OUT_WAIT(evsidei)); } - if (events & EPOLLIN) { + if (events & (EPOLLIN | EPOLLRDHUP)) { if (tcp_splice_forward(c, conn, evsidei, now)) goto reset; } -- cgit v1.2.3