aboutgitcodebugslistschat
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2026-06-05 10:34:16 +1000
committerStefano Brivio <sbrivio@redhat.com>2026-06-05 09:46:52 +0200
commit21f4d13c4cd4db24b65926265c98d5f41f0c6a9b (patch)
tree626b588bbfa5081430a4d71283b5dc225f93389a
parent31d0893d47e3d147b3a1597bbede7de65281a62f (diff)
downloadpasst-21f4d13c4cd4db24b65926265c98d5f41f0c6a9b.tar
passt-21f4d13c4cd4db24b65926265c98d5f41f0c6a9b.tar.gz
passt-21f4d13c4cd4db24b65926265c98d5f41f0c6a9b.tar.bz2
passt-21f4d13c4cd4db24b65926265c98d5f41f0c6a9b.tar.lz
passt-21f4d13c4cd4db24b65926265c98d5f41f0c6a9b.tar.xz
passt-21f4d13c4cd4db24b65926265c98d5f41f0c6a9b.tar.zst
passt-21f4d13c4cd4db24b65926265c98d5f41f0c6a9b.zip
tcp_splice: Improve EOF and read stall exit conditionsHEADmaster
At the end of our loop we have a conditional 'break' that exits if we're at EOF on the read side and have nothing left in the pipe. This makes sense: at EOF there's nothing left to do read-side and with nothing in the pipe there's nothing to do write side either. The same is true if the read side hit an EAGAIN and the pipe is empty: there's nothing we can do (for now) read side, and with an empty pipe nothing write side either. So, generalise the condition to exit on either EOF or EAGAIN read side. Furthermore, if the read side is at EOF or EAGAIN and there's already nothing in the pipe before the write-side splice(), then that write side splice() can't accomplish anything, so exit the loop early in that case avoiding a harmless but unnecessary write-splice(). Signed-off-by: David Gibson <david@gibson.dropbear.id.au> [sbrivio: Minor comment fix] Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
-rw-r--r--tcp_splice.c21
1 files changed, 16 insertions, 5 deletions
diff --git a/tcp_splice.c b/tcp_splice.c
index 565596d..3fd33a1 100644
--- a/tcp_splice.c
+++ b/tcp_splice.c
@@ -497,9 +497,17 @@ static int tcp_splice_forward(struct ctx *c,
flow_trace(conn, "%zi from read-side call", readlen);
- if (!readlen) {
- conn_event(conn, FIN_RCVD(fromsidei));
- } else if (readlen > 0) {
+ if (readlen <= 0) {
+ if (!readlen) /* EOF */
+ conn_event(conn, FIN_RCVD(fromsidei));
+
+ /* We're either blocked or at EOF on the read side, and
+ * there's nothing in the pipe so there's nothing to do
+ * write side either.
+ */
+ if (!conn->pending[fromsidei])
+ break;
+ } else {
conn->pending[fromsidei] += readlen;
if (readlen >= (long)c->tcp.pipe_size * 90 / 100)
@@ -531,9 +539,12 @@ static int tcp_splice_forward(struct ctx *c,
conn->pending[fromsidei] -= written;
- if (conn->events & FIN_RCVD(fromsidei) &&
- !conn->pending[fromsidei])
+ if (!conn->pending[fromsidei] && readlen <= 0) {
+ /* Read side is EOF or EAGAIN, and we emptied the pipe.
+ * No more we can do for now.
+ */
break;
+ }
}
/* We need write-side wakeups if and only if we have data in the pipe to