diff options
| author | David Gibson <david@gibson.dropbear.id.au> | 2026-06-05 10:34:16 +1000 |
|---|---|---|
| committer | Stefano Brivio <sbrivio@redhat.com> | 2026-06-05 09:46:52 +0200 |
| commit | 21f4d13c4cd4db24b65926265c98d5f41f0c6a9b (patch) | |
| tree | 626b588bbfa5081430a4d71283b5dc225f93389a | |
| parent | 31d0893d47e3d147b3a1597bbede7de65281a62f (diff) | |
| download | passt-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 | |
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.c | 21 |
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 |
