From 70a7f8dce0b4134ad5fca7aff8244b76cac1888a Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Thu, 2 Apr 2026 21:31:53 +0200 Subject: [PATCH] MEDIUM: haterm: Prepare support for splicing by initializing a master pipe Now the zero-copy data forwarding is supported, we will add the splicing support. To do so, we first create a master pipe with vmsplice() during haterm startup. It is only performed if the splicing is supported. And its size can be configured by setting "tune.pipesize" global parameter. This master pipe will be used to fill the pipe with the client. --- src/haterm.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++ src/haterm_init.c | 4 ++++ 2 files changed, 64 insertions(+) diff --git a/src/haterm.c b/src/haterm.c index d4a2e80a4..e66c41f23 100644 --- a/src/haterm.c +++ b/src/haterm.c @@ -1,3 +1,6 @@ +#define _GNU_SOURCE +#include + #include #include #include @@ -6,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -62,6 +66,11 @@ static char common_chunk_resp[RESPSIZE]; static char *random_resp; static int random_resp_len = RESPSIZE; +#if defined(USE_LINUX_SPLICE) +struct pipe *master_pipe = NULL; +size_t master_pipesize = 0; +#endif + static size_t hstream_add_ff_data(struct hstream *hs, struct sedesc *sd, unsigned long long len); static size_t hstream_add_htx_data(struct hstream *hs, struct htx *htx, unsigned long long len); @@ -1158,4 +1167,55 @@ static int hstream_build_responses(void) return 1; } +#if defined(USE_LINUX_SPLICE) +static void hstream_init_splicing(void) +{ + if (!(global.tune.options & GTUNE_USE_SPLICE)) + return; + + if (!global.tune.pipesize) + global.tune.pipesize = 65536 * 5 / 4; + + master_pipe = get_pipe(); + if (master_pipe) { + struct iovec v = { .iov_base = common_response, + .iov_len = sizeof(common_response) }; + int total, ret; + + total = ret = 0; + do { + ret = vmsplice(master_pipe->prod, &v, 1, SPLICE_F_NONBLOCK); + if (ret > 0) + total += ret; + } while (ret > 0 && total < global.tune.pipesize); + master_pipesize = total; + + if (master_pipesize < global.tune.pipesize) { + if (master_pipesize < 60*1024) { + /* Older kernels were limited to around 60-61 kB */ + ha_warning("Failed to vmsplice response buffer after %lu bytes, splicing disabled\n", master_pipesize); + global.tune.options &= ~GTUNE_USE_SPLICE; + put_pipe(master_pipe); + master_pipe = NULL; + } + else + ha_warning("Splicing is limited to %lu bytes (too old kernel)\n", master_pipesize); + } + } + else { + ha_warning("Unable to allocate master pipe for splicing, splicing disabled\n"); + global.tune.options &= ~GTUNE_USE_SPLICE; + } +} + +static void hstream_deinit(void) +{ + if (master_pipe) + put_pipe(master_pipe); +} + +REGISTER_POST_DEINIT(hstream_deinit); +INITCALL0(STG_INIT_2, hstream_init_splicing); +#endif + REGISTER_POST_CHECK(hstream_build_responses); diff --git a/src/haterm_init.c b/src/haterm_init.c index 94e8a96a1..797e636d2 100644 --- a/src/haterm_init.c +++ b/src/haterm_init.c @@ -186,6 +186,10 @@ void haproxy_init_args(int argc, char **argv) /* save the arguments */ sargc = argc; sargv = argv; +#if defined(USE_LINUX_SPLICE) + global.tune.options |= GTUNE_USE_SPLICE; +#endif + /* THIS PART MUST NOT MODIFY THE ARGUMENTS */ /* Parse the arguments which must be reused to build the conf. */ while (argc > 0) {