* [PATCH v2 1/4] tcp_splice: Improve error reporting
2026-05-21 6:37 [PATCH v2 0/4] Fix race condition while closing spliced connections David Gibson
@ 2026-05-21 6:37 ` David Gibson
2026-05-21 6:37 ` [PATCH v2 2/4] tcp_splice: Avoid missing EOF recognition while forwarding David Gibson
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: David Gibson @ 2026-05-21 6:37 UTC (permalink / raw)
To: passt-dev, Stefano Brivio; +Cc: Paul Holzinger, David Gibson
A number of things can, at least theoretically, go wrong when forwarding
data across a spliced connection. We generally handle this by resetting
the connection on both sides. However, in many cases we don't log any
message about why the connection was reset, which can make it hard to
debug why this is happening.
Add a bunch of debug and error logging to make this easier to figure out.
We ratelimit for safety, which requires some tweaks to make the ratelimit
logic work with the flow specific log functions.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
flow.h | 7 +++++++
log.h | 19 ++++++++++---------
passt.c | 2 +-
tcp_splice.c | 45 ++++++++++++++++++++++++++++++++++-----------
tcp_splice.h | 2 +-
5 files changed, 53 insertions(+), 22 deletions(-)
diff --git a/flow.h b/flow.h
index 897c9ea8..6c6a9260 100644
--- a/flow.h
+++ b/flow.h
@@ -311,4 +311,11 @@ void flow_log_details_(const struct flow_common *f, int pri,
#define flow_dbg_details(f_) flow_log_details((f_), LOG_DEBUG)
#define flow_err_details(f_) flow_log_details((f_), LOG_ERR)
+#define flow_dbg_ratelimit(f, now, ...) \
+ logmsg_ratelimit(flow_dbg, debug, now, f, __VA_ARGS__)
+#define flow_err_ratelimit(f, now, ...) \
+ logmsg_ratelimit(flow_err, err, now, f, __VA_ARGS__)
+#define flow_perror_ratelimit(f, now, ...) \
+ logmsg_ratelimit(flow_perror, err, now, f, __VA_ARGS__)
+
#endif /* FLOW_H */
diff --git a/log.h b/log.h
index c6befe3a..69cfb507 100644
--- a/log.h
+++ b/log.h
@@ -103,9 +103,10 @@ void logmsg_perror(int pri, const char *format, ...)
/**
* logmsg_ratelimit() - Log a message with rate limiting
* @fn: Logging function name (e.g. warn, info, debug)
+ * @fn_s: Logging function name for suppression messages
* @now: Current timestamp
*/
-#define logmsg_ratelimit(fn, now, ...) \
+#define logmsg_ratelimit(fn, fn_s, now, ...) \
do { \
static unsigned int rl_suppressed_; \
static unsigned int rl_printed_; \
@@ -119,27 +120,27 @@ void logmsg_perror(int pri, const char *format, ...)
if (rl_printed_ < LOG_RATELIMIT_BURST) { \
fn(__VA_ARGS__); \
if (rl_suppressed_) { \
- fn("(suppressed %u similar messages)", \
- rl_suppressed_); \
+ fn_s("(suppressed %u similar messages)", \
+ rl_suppressed_); \
rl_suppressed_ = 0; \
} \
rl_printed_++; \
if (rl_printed_ == LOG_RATELIMIT_BURST) \
- fn("(suppressing further similar" \
- " messages)"); \
+ fn_s("(suppressing further similar" \
+ " messages)"); \
} else { \
rl_suppressed_++; \
} \
} while (0)
#define err_ratelimit(now, ...) \
- logmsg_ratelimit(err, now, __VA_ARGS__)
+ logmsg_ratelimit(err, err, now, __VA_ARGS__)
#define warn_ratelimit(now, ...) \
- logmsg_ratelimit(warn, now, __VA_ARGS__)
+ logmsg_ratelimit(warn, warn, now, __VA_ARGS__)
#define info_ratelimit(now, ...) \
- logmsg_ratelimit(info, now, __VA_ARGS__)
+ logmsg_ratelimit(info, info, now, __VA_ARGS__)
#define debug_ratelimit(now, ...) \
- logmsg_ratelimit(debug, now, __VA_ARGS__)
+ logmsg_ratelimit(debug, debug, now, __VA_ARGS__)
extern int log_file;
extern int log_trace;
diff --git a/passt.c b/passt.c
index bc42ea33..b6fc12d4 100644
--- a/passt.c
+++ b/passt.c
@@ -273,7 +273,7 @@ static void passt_worker(void *opaque, int nfds, struct epoll_event *events)
tcp_sock_handler(c, ref, eventmask);
break;
case EPOLL_TYPE_TCP_SPLICE:
- tcp_splice_sock_handler(c, ref, eventmask);
+ tcp_splice_sock_handler(c, ref, eventmask, &now);
break;
case EPOLL_TYPE_TCP_LISTEN:
tcp_listen_handler(c, ref, &now);
diff --git a/tcp_splice.c b/tcp_splice.c
index 42ee8abc..915ac114 100644
--- a/tcp_splice.c
+++ b/tcp_splice.c
@@ -478,11 +478,12 @@ void tcp_splice_conn_from_sock(const struct ctx *c, union flow *flow, int s0)
* @c: Execution context
* @ref: epoll reference
* @events: epoll events bitmap
+ * @now: Current timestamp
*
* #syscalls:pasta splice
*/
void tcp_splice_sock_handler(struct ctx *c, union epoll_ref ref,
- uint32_t events)
+ uint32_t events, const struct timespec *now)
{
struct tcp_splice_conn *conn = conn_at_sidx(ref.flowside);
unsigned evsidei = ref.flowside.sidei, fromsidei;
@@ -499,18 +500,25 @@ void tcp_splice_sock_handler(struct ctx *c, union epoll_ref ref,
socklen_t sl = sizeof(err);
rc = getsockopt(ref.fd, SOL_SOCKET, SO_ERROR, &err, &sl);
- if (rc)
+ if (rc) {
flow_perror(conn, "Error retrieving SO_ERROR");
- else
- flow_trace(conn, "Error event on socket: %s",
- strerror_(err));
-
+ } else {
+ flow_dbg_ratelimit(conn, now,
+ "Error event on %s socket: %s",
+ pif_name(conn->f.pif[evsidei]),
+ strerror_(err));
+ }
goto reset;
}
if (conn->events == SPLICE_CONNECT) {
- if (!(events & EPOLLOUT))
+ if (!(events & EPOLLOUT)) {
+ flow_err_ratelimit(
+ conn, now,
+ "Unexpected events 0x%x during connect",
+ events);
goto reset;
+ }
if (tcp_splice_connect_finish(c, conn))
goto reset;
}
@@ -545,8 +553,12 @@ retry:
SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
while (readlen < 0 && errno == EINTR);
- if (readlen < 0 && errno != EAGAIN)
+ if (readlen < 0 && errno != EAGAIN) {
+ flow_perror_ratelimit(
+ conn, now, "Splicing from %s socket",
+ pif_name(conn->f.pif[fromsidei]));
goto reset;
+ }
flow_trace(conn, "%zi from read-side call", readlen);
@@ -569,8 +581,12 @@ retry:
SPLICE_F_MOVE | more | SPLICE_F_NONBLOCK);
while (written < 0 && errno == EINTR);
- if (written < 0 && errno != EAGAIN)
+ if (written < 0 && errno != EAGAIN) {
+ flow_perror_ratelimit(
+ conn, now, "Splicing to %s socket",
+ pif_name(conn->f.pif[!fromsidei]));
goto reset;
+ }
flow_trace(conn, "%zi from write-side call (passed %zi)",
written, c->tcp.pipe_size);
@@ -627,8 +643,12 @@ retry:
flow_foreach_sidei(sidei) {
if ((conn->events & FIN_RCVD(sidei)) &&
!(conn->events & FIN_SENT(!sidei))) {
- if (shutdown(conn->s[!sidei], SHUT_WR) < 0)
+ if (shutdown(conn->s[!sidei], SHUT_WR) < 0) {
+ flow_perror_ratelimit(
+ conn, now, "shutdown() on %s",
+ pif_name(conn->f.pif[!sidei]));
goto reset;
+ }
conn_event(conn, FIN_SENT(!sidei));
}
}
@@ -647,8 +667,11 @@ retry:
goto swap;
}
- if (events & EPOLLHUP)
+ if (events & EPOLLHUP) {
+ flow_dbg_ratelimit(conn, now, "Hangup from %s socket",
+ pif_name(conn->f.pif[evsidei]));
goto reset;
+ }
return;
diff --git a/tcp_splice.h b/tcp_splice.h
index dbfd55db..8a1a1f67 100644
--- a/tcp_splice.h
+++ b/tcp_splice.h
@@ -12,7 +12,7 @@ struct tcp_splice_conn;
union sockaddr_inany;
void tcp_splice_sock_handler(struct ctx *c, union epoll_ref ref,
- uint32_t events);
+ uint32_t events, const struct timespec *now);
void tcp_splice_conn_from_sock(const struct ctx *c, union flow *flow, int s0);
void tcp_splice_init(struct ctx *c);
--
2.54.0
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH v2 2/4] tcp_splice: Avoid missing EOF recognition while forwarding
2026-05-21 6:37 [PATCH v2 0/4] Fix race condition while closing spliced connections David Gibson
2026-05-21 6:37 ` [PATCH v2 1/4] tcp_splice: Improve error reporting David Gibson
@ 2026-05-21 6:37 ` David Gibson
2026-05-21 6:37 ` [PATCH v2 3/4] tcp_splice: Clean up flow control path for splice forwarding David Gibson
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: David Gibson @ 2026-05-21 6:37 UTC (permalink / raw)
To: passt-dev, Stefano Brivio; +Cc: Paul Holzinger, David Gibson
tcp_splice_sock_handler() has an optimised path for the common case where
the amount we splice(2) into the pipe is exactly the same as the amount we
splice(2) out again. If the pipe is empty at that point, we stop
forwarding until we get another epoll event.
However, via a subtle chain of events, this can cause a bug for a
half-closed connection. Suppose the connection is already half-closed in
the other direction - that is, we've already called shutdown(SHUT_WR) on
the socket for which we're getting the event. In this event we're getting
the last batch of data in the other direction, and also a FIN. This can
result in EPOLLIN, EPOLLRDHUP and EPOLLHUP events simultaneously.
We read the last data from the socket and successfully splice it to the
other side. Since there is no data in the pipe, we exit the forwarding
loop. However, because we did read data, we don't set the eof flag.
Because we don't set eof, we don't (yet) propagate the FIN to the other
side, or set FIN_SENT_(!fromsidei). Therefore we don't (yet) recognize
this as a clean termination and set the CLOSING flag. We would correct
this when we get our next event, however before we can do so we process
the EPOLLHUP event. Because we haven't recognized this as a clean close
we assume it is an abrupt close and send an RST to the other side.
To avoid this, don't stop attempting to forward data on this path.
Continue for at least one more loop. If we're at EOF, we'll recognize it
on the next splice(2). If not it gives us an opportunity to forward more
data without returning to the mail epoll loop.
Reported-by: Paul Holzinger <pholzing@redhat.com>
Link: https://bugs.passt.top/show_bug.cgi?id=202
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
tcp_splice.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tcp_splice.c b/tcp_splice.c
index 915ac114..762a058e 100644
--- a/tcp_splice.c
+++ b/tcp_splice.c
@@ -612,7 +612,7 @@ retry:
}
}
- break;
+ continue;
}
conn->read[fromsidei] += readlen > 0 ? readlen : 0;
--
2.54.0
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH v2 3/4] tcp_splice: Clean up flow control path for splice forwarding
2026-05-21 6:37 [PATCH v2 0/4] Fix race condition while closing spliced connections David Gibson
2026-05-21 6:37 ` [PATCH v2 1/4] tcp_splice: Improve error reporting David Gibson
2026-05-21 6:37 ` [PATCH v2 2/4] tcp_splice: Avoid missing EOF recognition while forwarding David Gibson
@ 2026-05-21 6:37 ` David Gibson
2026-05-21 6:37 ` [PATCH v2 4/4] tcp_splice: Simplify tracking of read/written bytes David Gibson
2026-05-21 18:05 ` [PATCH v2 0/4] Fix race condition while closing spliced connections Stefano Brivio
4 siblings, 0 replies; 6+ messages in thread
From: David Gibson @ 2026-05-21 6:37 UTC (permalink / raw)
To: passt-dev, Stefano Brivio; +Cc: Paul Holzinger, David Gibson
Splice forwarding can be blocked either waiting for data from one side
or waiting for space on the other. For that reason,
tcp_splice_sock_handler() on either socket can forward data in either or
both directions, depending on whether we have EPOLLIN, EPOLLOUT or both
events.
The flow control for this is quite hard to follow though, since we forward
in one direction, then sometimes loop back with a goto to do it in the
other direction. Simplify this by adding a tcp_splice_forward() function
with the logic to forward in one direction and calling it either once or
twice from tcp_splice_sock_handler().
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
tcp_splice.c | 148 +++++++++++++++++++++++++++------------------------
1 file changed, 78 insertions(+), 70 deletions(-)
diff --git a/tcp_splice.c b/tcp_splice.c
index 762a058e..ae92bbd9 100644
--- a/tcp_splice.c
+++ b/tcp_splice.c
@@ -474,72 +474,24 @@ void tcp_splice_conn_from_sock(const struct ctx *c, union flow *flow, int s0)
}
/**
- * tcp_splice_sock_handler() - Handler for socket mapped to spliced connection
+ * tcp_splice_forward() - Forward data in one direction using splice()
* @c: Execution context
- * @ref: epoll reference
- * @events: epoll events bitmap
+ * @conn: Connection to forward data for
+ * @fromsidei: Side to forward data from
* @now: Current timestamp
*
+ * Return: 0 on success, -1 on error (connection should be reset)
+ *
* #syscalls:pasta splice
*/
-void tcp_splice_sock_handler(struct ctx *c, union epoll_ref ref,
- uint32_t events, const struct timespec *now)
+static int tcp_splice_forward(struct ctx *c,
+ struct tcp_splice_conn *conn, unsigned fromsidei,
+ const struct timespec *now)
{
- struct tcp_splice_conn *conn = conn_at_sidx(ref.flowside);
- unsigned evsidei = ref.flowside.sidei, fromsidei;
- uint8_t lowat_set_flag, lowat_act_flag;
- int eof, never_read;
-
- assert(conn->f.type == FLOW_TCP_SPLICE);
-
- if (conn->events == SPLICE_CLOSED)
- return;
-
- if (events & EPOLLERR) {
- int err, rc;
- socklen_t sl = sizeof(err);
-
- rc = getsockopt(ref.fd, SOL_SOCKET, SO_ERROR, &err, &sl);
- if (rc) {
- flow_perror(conn, "Error retrieving SO_ERROR");
- } else {
- flow_dbg_ratelimit(conn, now,
- "Error event on %s socket: %s",
- pif_name(conn->f.pif[evsidei]),
- strerror_(err));
- }
- goto reset;
- }
-
- if (conn->events == SPLICE_CONNECT) {
- if (!(events & EPOLLOUT)) {
- flow_err_ratelimit(
- conn, now,
- "Unexpected events 0x%x during connect",
- events);
- goto reset;
- }
- if (tcp_splice_connect_finish(c, conn))
- goto reset;
- }
-
- if (events & EPOLLOUT) {
- fromsidei = !evsidei;
- conn_event(conn, ~OUT_WAIT(evsidei));
- } else {
- fromsidei = evsidei;
- }
-
- if (events & EPOLLRDHUP)
- /* For side 0 this is fake, but implied */
- conn_event(conn, FIN_RCVD(evsidei));
-
-swap:
- eof = 0;
- never_read = 1;
-
- lowat_set_flag = RCVLOWAT_SET(fromsidei);
- lowat_act_flag = RCVLOWAT_ACT(fromsidei);
+ 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, pending;
@@ -557,7 +509,7 @@ retry:
flow_perror_ratelimit(
conn, now, "Splicing from %s socket",
pif_name(conn->f.pif[fromsidei]));
- goto reset;
+ return -1;
}
flow_trace(conn, "%zi from read-side call", readlen);
@@ -585,7 +537,7 @@ retry:
flow_perror_ratelimit(
conn, now, "Splicing to %s socket",
pif_name(conn->f.pif[!fromsidei]));
- goto reset;
+ return -1;
}
flow_trace(conn, "%zi from write-side call (passed %zi)",
@@ -647,24 +599,80 @@ retry:
flow_perror_ratelimit(
conn, now, "shutdown() on %s",
pif_name(conn->f.pif[!sidei]));
- goto reset;
+ return -1;
}
conn_event(conn, FIN_SENT(!sidei));
}
}
}
- if (CONN_HAS(conn, FIN_SENT(0) | FIN_SENT(1))) {
- /* Clean close, no reset */
- conn_flag(conn, CLOSING);
+ return 0;
+}
+
+/**
+ * tcp_splice_sock_handler() - Handler for socket mapped to spliced connection
+ * @c: Execution context
+ * @ref: epoll reference
+ * @events: epoll events bitmap
+ * @now: Current timestamp
+ */
+void tcp_splice_sock_handler(struct ctx *c, union epoll_ref ref,
+ uint32_t events, const struct timespec *now)
+{
+ struct tcp_splice_conn *conn = conn_at_sidx(ref.flowside);
+ unsigned evsidei = ref.flowside.sidei;
+
+ assert(conn->f.type == FLOW_TCP_SPLICE);
+
+ if (conn->events == SPLICE_CLOSED)
return;
+
+ if (events & EPOLLERR) {
+ int err, rc;
+ socklen_t sl = sizeof(err);
+
+ rc = getsockopt(ref.fd, SOL_SOCKET, SO_ERROR, &err, &sl);
+ if (rc)
+ flow_perror(conn, "Error retrieving SO_ERROR");
+ else
+ flow_dbg_ratelimit(conn, now,
+ "Error event on %s socket: %s",
+ pif_name(conn->f.pif[evsidei]),
+ strerror_(err));
+ goto reset;
}
- if ((events & (EPOLLIN | EPOLLOUT)) == (EPOLLIN | EPOLLOUT)) {
- events = EPOLLIN;
+ if (conn->events == SPLICE_CONNECT) {
+ if (!(events & EPOLLOUT)) {
+ flow_err_ratelimit(
+ conn, now,
+ "Unexpected events 0x%x during connect",
+ events);
+ goto reset;
+ }
+ if (tcp_splice_connect_finish(c, conn))
+ goto reset;
+ }
- fromsidei = !fromsidei;
- goto swap;
+ 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 (tcp_splice_forward(c, conn, evsidei, now))
+ goto reset;
+ }
+
+ if (CONN_HAS(conn, FIN_SENT(0) | FIN_SENT(1))) {
+ /* Clean close, no reset */
+ conn_flag(conn, CLOSING);
+ return;
}
if (events & EPOLLHUP) {
--
2.54.0
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH v2 4/4] tcp_splice: Simplify tracking of read/written bytes
2026-05-21 6:37 [PATCH v2 0/4] Fix race condition while closing spliced connections David Gibson
` (2 preceding siblings ...)
2026-05-21 6:37 ` [PATCH v2 3/4] tcp_splice: Clean up flow control path for splice forwarding David Gibson
@ 2026-05-21 6:37 ` David Gibson
2026-05-21 18:05 ` [PATCH v2 0/4] Fix race condition while closing spliced connections Stefano Brivio
4 siblings, 0 replies; 6+ messages in thread
From: David Gibson @ 2026-05-21 6:37 UTC (permalink / raw)
To: passt-dev, Stefano Brivio; +Cc: Paul Holzinger, David Gibson
For each each direction of each spliced connection, we keep track of how
many bytes we've read from one socket and written to the other. However,
we never actually care about the absolute values of these, only the
difference between them, which represents how much data is currently "in
flight" in the splicing pipe.
Simplify the handling by having a single variable tracking the number of
bytes in the pipe.
As a bonus, the new scheme makes it clearer that we don't need to worry
about overflows: pending can never become larger than the maximum pipe
bufffer size, well within 32-bits.
I _think_ the old scheme was safe in the case of overflow - again under
the assumption that read/written can never be further apart than the pipe
buffer size. However, it's much harder to reason about this case. It's
certainly plausible that an overflow could occur - sending 4GiB through
a local socket is entirely achievable.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
tcp_conn.h | 6 ++----
tcp_splice.c | 18 +++++++++---------
2 files changed, 11 insertions(+), 13 deletions(-)
diff --git a/tcp_conn.h b/tcp_conn.h
index 9f5bee03..c8381aa7 100644
--- a/tcp_conn.h
+++ b/tcp_conn.h
@@ -206,8 +206,7 @@ struct tcp_tap_transfer_ext {
* @f: Generic flow information
* @s: File descriptor for sockets
* @pipe: File descriptors for pipes
- * @read: Bytes read (not fully written to other side in one shot)
- * @written: Bytes written (not fully written from one other side read)
+ * @pending: Bytes currently in each pipe
* @events: Events observed/actions performed on connection
* @flags: Connection flags (attributes, not events)
*/
@@ -218,8 +217,7 @@ struct tcp_splice_conn {
int s[SIDES];
int pipe[SIDES][2];
- uint32_t read[SIDES];
- uint32_t written[SIDES];
+ uint32_t pending[SIDES];
uint8_t events;
#define SPLICE_CLOSED 0
diff --git a/tcp_splice.c b/tcp_splice.c
index ae92bbd9..af50e715 100644
--- a/tcp_splice.c
+++ b/tcp_splice.c
@@ -292,7 +292,7 @@ bool tcp_splice_flow_defer(struct tcp_splice_conn *conn)
conn->s[sidei] = -1;
}
- conn->read[sidei] = conn->written[sidei] = 0;
+ conn->pending[sidei] = 0;
}
conn->events = SPLICE_CLOSED;
@@ -494,7 +494,7 @@ static int tcp_splice_forward(struct ctx *c,
int eof = 0;
while (1) {
- ssize_t readlen, written, pending;
+ ssize_t readlen, written;
int more = 0;
retry:
@@ -543,7 +543,7 @@ retry:
flow_trace(conn, "%zi from write-side call (passed %zi)",
written, c->tcp.pipe_size);
- /* Most common case: skip updating counters. */
+ /* Most common case: skip updating count of pending bytes */
if (readlen > 0 && readlen == written) {
if (readlen >= (long)c->tcp.pipe_size * 10 / 100)
continue;
@@ -567,11 +567,11 @@ retry:
continue;
}
- conn->read[fromsidei] += readlen > 0 ? readlen : 0;
- conn->written[fromsidei] += written > 0 ? written : 0;
+ conn->pending[fromsidei] += readlen > 0 ? readlen : 0;
+ conn->pending[fromsidei] -= written > 0 ? written : 0;
if (written < 0) {
- if (conn->read[fromsidei] == conn->written[fromsidei])
+ if (!conn->pending[fromsidei])
break;
conn_event(conn, OUT_WAIT(!fromsidei));
@@ -581,15 +581,15 @@ retry:
if (never_read && written == (long)(c->tcp.pipe_size))
goto retry;
- pending = conn->read[fromsidei] - conn->written[fromsidei];
- if (!never_read && written > 0 && written < pending)
+ if (!never_read && written > 0 &&
+ written < conn->pending[fromsidei])
goto retry;
if (eof)
break;
}
- if (conn->read[fromsidei] == conn->written[fromsidei] && eof) {
+ if (!conn->pending[fromsidei] && eof) {
unsigned sidei;
flow_foreach_sidei(sidei) {
--
2.54.0
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [PATCH v2 0/4] Fix race condition while closing spliced connections
2026-05-21 6:37 [PATCH v2 0/4] Fix race condition while closing spliced connections David Gibson
` (3 preceding siblings ...)
2026-05-21 6:37 ` [PATCH v2 4/4] tcp_splice: Simplify tracking of read/written bytes David Gibson
@ 2026-05-21 18:05 ` Stefano Brivio
4 siblings, 0 replies; 6+ messages in thread
From: Stefano Brivio @ 2026-05-21 18:05 UTC (permalink / raw)
To: David Gibson; +Cc: passt-dev, Paul Holzinger
On Thu, 21 May 2026 16:37:41 +1000
David Gibson <david@gibson.dropbear.id.au> wrote:
> Fix bug 202, where a race condition could cause connections to be
> incorrectly reset in certain circumstances.
>
> Patch 2/4 is the bug fix proper. 1/4 improves error reporting and
> debugging messages in the vicinity. Patches 3..4/4 are some small
> cleanups I noticed in the area while working on the fix.
>
> Link: https://bugs.passt.top/show_bug.cgi?id=202
>
> v2:
> * Formatting and comment fixes, per Stefano's review
> * Dropped patches 5 & 6 for now. I still think they're worthwhile,
> but are closely related to other oddities that need some work. I
> didn't want to delay the bugfix itself.
I couldn't push this yet as we need to find a solution for the
rampstream_in test breakage first, but it all looks good to me and I
applied it to my own tree for the moment.
--
Stefano
^ permalink raw reply [flat|nested] 6+ messages in thread