Every existing splice call in this file either passes SPLICE_F_NONBLOCK or runs on a blocking socket, so nothing exercises the socket's own O_NONBLOCK on the splice path. A change that stops consulting sock->file->f_flags puts splice(2) and sendfile(2) back to sleeping in tls_rx_rec_wait() while a peer streams empty records, and the suite still reports pass. Run the zero-length record variants a second time with O_NONBLOCK set on the socket and SPLICE_F_NONBLOCK left out of the splice flags. The two forms are required to reach the same outcome, so the existing per-variant expectations carry over unchanged. A kernel that ignores the socket flag sleeps in the EAGAIN variant until the harness timeout rather than returning. Only the flags the two forms pass differ, so the body of the existing test moves into zero_len_do_splice() and both call it. The check that a successful splice consumed the empty records ahead of the payload now covers the nonblocking socket as well. Signed-off-by: Chuck Lever --- tools/testing/selftests/net/tls.c | 41 +++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c index af47d9a6098c..7c178541edf4 100644 --- a/tools/testing/selftests/net/tls.c +++ b/tools/testing/selftests/net/tls.c @@ -2743,23 +2743,24 @@ FIXTURE_TEARDOWN(zero_len_splice) * A control record behind the run reports EINVAL, the error splice * already reports for a control record it meets first. */ -TEST_F(zero_len_splice, test) +static void +zero_len_do_splice(struct __test_metadata *_metadata, + struct _test_data_zero_len_splice *self, + const struct _fixture_variant_zero_len_splice *variant, + unsigned int splice_flags) { const struct raw_rec *payload; unsigned char buf[128]; ssize_t ret; int p[2]; - if (self->notls) - SKIP(return, "no TLS support"); - ASSERT_GE(pipe(p), 0); payload = zero_len_send_recs(_metadata, self->fd, variant->recs); if (variant->splice_ret < 0) { ret = splice(self->cfd, NULL, p[1], NULL, sizeof(buf), - SPLICE_F_NONBLOCK); + splice_flags); EXPECT_EQ(ret, -1); if (ret == -1) EXPECT_EQ(errno, -variant->splice_ret); @@ -2769,7 +2770,7 @@ TEST_F(zero_len_splice, test) * would then block until the harness timeout. */ ASSERT_EQ(splice(self->cfd, NULL, p[1], NULL, sizeof(buf), - SPLICE_F_NONBLOCK), variant->splice_ret); + splice_flags), variant->splice_ret); ret = read(p[0], buf, sizeof(buf)); EXPECT_EQ(ret, variant->splice_ret); if (ret == variant->splice_ret) @@ -2789,6 +2790,34 @@ TEST_F(zero_len_splice, test) close(p[1]); } +TEST_F(zero_len_splice, test) +{ + if (self->notls) + SKIP(return, "no TLS support"); + + zero_len_do_splice(_metadata, self, variant, SPLICE_F_NONBLOCK); +} + +/* The socket's own O_NONBLOCK governs the record wait, as it does on a + * plain TCP socket, so a splice that omits SPLICE_F_NONBLOCK reaches + * the same outcome as one that sets it. An unfixed kernel derives the + * wait from SPLICE_F_NONBLOCK alone and sleeps here until the harness + * timeout. + */ +TEST_F(zero_len_splice, nonblock_socket) +{ + int sflags; + + if (self->notls) + SKIP(return, "no TLS support"); + + sflags = fcntl(self->cfd, F_GETFL, 0); + ASSERT_GE(sflags, 0); + ASSERT_EQ(fcntl(self->cfd, F_SETFL, sflags | O_NONBLOCK), 0); + + zero_len_do_splice(_metadata, self, variant, 0); +} + FIXTURE(tls_err) { int fd, cfd; -- 2.54.0