If a packet build was asked to probe the peer with frames which have just
been acked, the frames build run by qc_build_frms() could be cancelled by
qc_stream_frm_is_acked() whose aim is to check that current frames to
be built have not been already acknowledged. In this case the packet build run
by qc_do_build_pkt() is not interrupted, leading to the build of an empty packet
which should be ack-eliciting.
This is a bug detected by the BUG_ON() statement in qc_do_build_pk():
BUG_ON(qel->pktns->tx.pto_probe &&
!(pkt->flags & QUIC_FL_TX_PACKET_ACK_ELICITING));
Thank you to @Tristan971 for having reported this issue in GH #2709
This is an old bug which must be backported as far as 2.6.
quic-cc-algo is a bind keyword which is used to specify the congestion
control algorithm. It is parsed via function bind_parse_quic_cc_algo().
The parsing function was too laxed as it used strncmp for algo token
matching. This could cause surprise if specifying an invalid algorithm
but starting identically to another entry. Especially if extra
parameters are specified in parenthesis, as in this case parameters
value will be completely ignored and default value used instead.
To fix this, convert algo argument to ist. Then, use istsplit() to
extract algo token from the optional extra arguments and compare the
whole value with isteq().
Let's move mworker_reexec() and mworker_reload() in mworker.c. mworker_reload()
is called only within the functions, which are already in mworker.c. So, this
reorganization allows to declare mworker_reload() as a static.
mworker_run_master() is called only in master mode. mworker_loop() is static
and called only in mworker_run_master(). So let's move these both functions in
mworker.c.
We also need here to make run_thread_poll_loop() accessible from other units,
as it's used in mworker_loop().
This commit prepares the move of mworker_run_master() in mworker.c.
Let's remove from it's definition the code, which adjusts verbosity in
dependency of other global run time modes (daemon or foreground). This part
should stay in main(), where all verbosity modes are handeled for
different mode combinations.
mworker_prepare_master() performs some preparation routines for the new worker
process, which will be forked during the startup. It's called only in
master-worker mode, so let's move it in mworker.c.
mworker_on_new_child_failure() performs some routines for the worker process,
if it has failed the reload. As it's called only in mworker_catch_sigchld()
from mworker.c, let's move mworker_on_new_child_failure() in mworker.c as well.
Like this it could also be declared as a static.
This patch prepares the moving of on_new_child_failure definition into
mworker.c. So, let's rename it accordingly and let's also update its
description.
In master-worker mode, worker process uses now send_fd_uxst() to send
'_send_status' command to master. Since refactoring, this started to trigger
the following Valgrind reports:
==810584== Syscall param sendmsg(msg.msg_iov[0]) points to uninitialised byte(s)
==810584== at 0x4AAC99D: __libc_sendmsg (sendmsg.c:28)
==810584== by 0x4AAC99D: sendmsg (sendmsg.c:25)
==810584== by 0x56350F: send_fd_uxst (proto_sockpair.c:271)
==810584== by 0x3AA25C: main (haproxy.c:4151)
==810584== Address 0x1ffefffbfe is on thread 1's stack
==810584== in frame #1, created by send_fd_uxst (proto_sockpair.c:241)
==810584==
==810584== Syscall param sendmsg(msg.msg_control) points to uninitialised byte(s)
==810584== at 0x4AAC99D: __libc_sendmsg (sendmsg.c:28)
==810584== by 0x4AAC99D: sendmsg (sendmsg.c:25)
==810584== by 0x56350F: send_fd_uxst (proto_sockpair.c:271)
==810584== by 0x3AA25C: main (haproxy.c:4151)
==810584== Address 0x1ffefffc14 is on thread 1's stack
==810584== in frame #1, created by send_fd_uxst (proto_sockpair.c:241)
==810584==
So, let's initialize with zeros all buffers, which are passed to sendmsg
syscall(), used in send_fd_uxst() to avoid these Valgrind messages. They
increase Valgrind output and could make unnoticeable some other, more important
reports.
The QUIC pacing options changed a few times during their development.
For example the unit is now in datagrams not bytes. Also a few
sentences were slightly ambiguous so let's reword this.
No backport is needed.
Add 'workflow_dispatch' on the remaining scheduled build jobs that does
not have it.
This keyword allows to start manually a job from the "Actions" interface
in github.
var_fc_counter is not used on Illumos and emit a warning
src/tcp_sample.c:291:12: warning: ‘var_fc_counter’ defined but not used [-Wunused-function]
291 | static int var_fc_counter(struct arg *args, char **err)
| ^~~~~~~~~~~~~~
Let's add an ifdef to build it.
QUIC pacing was recently implemented to limit burst and improve overall
bandwidth. This is used only for MUX STREAM emission. Pacing requires
nanosecond resolution. As such, it used now_cpu_time() which relies on
clock_gettime() syscall.
The usage of clock_gettime() has several drawbacks :
* it is a syscall and thus requires a context-switch which may hurt
performance
* it is not be available on all systems
* timestamp is retrieved multiple times during a single task execution,
thus yielding different values which may tamper pacing calculation
Improve this by using task_mono_time() instead. This returns task call
time from the scheduler thread context. It requires the flag
TASK_F_WANTS_TIME on QUIC MUX tasklet to force the scheduler to update
call time with now_mono_time(). This solves every limitations listed
above :
* syscall invokation is only performed once before tasklet execution,
thus reducing context-switch impact
* on non compatible system, a millisecond timer is used as a fallback
which should ensure that pacing works decently for them
* timer value is now guaranteed to be fixed duing task execution
qc_prep_pkts() is a QUIC transport level function which encodes one or
several datagrams in a buffer before sending them. It returns the number
of encoded datagram. This is especially important when pacing is used to
limit packet bursts.
This datagram accounting was not trivial as qc_prep_pkts() used several
code paths depending on the condition of the current encoded packet.
Thus, there were several places were the local variable dgram_cnt could
have been incremented. This was implemented by the following commit :
commit 5cb8f8a622
MINOR: quic: support a max number of built packet per send iteration
However, there is a bug due to a missing increment when all frames from
the current QEL have been encoded. In this case, the encoding continue
in the same datagram to coalesce a futur packet. However, if this is the
last QEL, encoding loop will then break. As first_pkt is not NULL,
qc_txb_store() is called outside but dgram_cnt is yet not incremented.
In particular, this causes qc_prep_pkts() to return 0 when there is only
small STREAM frames to emit for application QEL. In qc_send(), this is
interpreted as a value which prevents further emission for the current
invokation. Thus, it may hurts performance, both without and with
pacing.
To fix this, removing multiple dgram_cnt increment. Now, it is modified
only in a single place which should cover every case, and render the
code easier to validate.
The most notable case where the bug is visible is when using cubic with
pacing without any burst, with quic-cc-algo cubic(,1). First, transfer
bandwidth in average was suboptimal, with significant variation. Worst,
it could sometimes fall dramatically for a particular stream without
recovering before returning to an expected level on the next one.
No need to backport.
On show quic, each MUX streams are listed with their various indicator
for buffering on Rx and Tx. In particular, txoff displays in parenthesis
the current level of data prepared by the upper stream instance not yet
emitted by QUIC transport layer.
This value is only accessible after a substract operation. However,
there was a typo which caused the result to be always 0. Fix this by
reusing the correct offsets in the calculation.
This should be backported up to 3.0.
In 3.1-dev10, commit 8dd4efe42f ("MAJOR: mworker: move master-worker
fork in init()"), the FD associated to /dev/null was made CLOEXEC
using O_CLOEXEC. Unfortunately this is not portable on older OSes,
doesn't build on Solaris for example, and was even reported as breaking
moderately old Linux OSes for other projects. Better not use it unless
absolutely certain it will work (currently we only use it for Linux
namespaces, which are optional), and use the conventional FD_CLOEXEC
instead.
No backport is needed.
systemd.c doesn't build on Solaris / Illumos because it uses "sun" as
the field name in a structure, while "sun" is the name of the macro
used to detect Solaris:
src/systemd.c: In function 'sd_notify':
src/systemd.c:43:22: error: expected identifier or '(' before numeric constant
struct sockaddr_un sun;
^
src/systemd.c:44:2: warning: no semicolon at end of struct or union
} socket_addr = {
^
Admittedly, the OS could have instead defined "sun" to itself to avoid
this. Any other name will work, let's just use "ux" for the short form
of "unix".
The problem appeared in 3.0-dev with commit aa3632962f ("MEDIUM:
mworker: get rid of libsystemd"), though by then this file was only
built when USE_SYSTEMD was set, which was not the case for non-linux
platforms. However since 3.1-dev14 with commit 15845247db ("MEDIUM:
mworker: remove USE_SYSTEMD requirement for -Ws"), all platforms
now build this file.
No backport is needed even though it will not hurt to have it in 3.0
for completeness.
Like the AWS-LC job, add a CI job which looks for the latest WolfSSL
version and tries to build it.
The patch adds a function which determines the latest version of WolfSSL
from the github tag, and the yml which describes the job.
Miroslav mentioned below that he's currently working on an OpenTelemetry
replacement for the OpenTracing filter since OpenTracing itself is no
longer maintained nor supported:
https://github.com/haproxy/haproxy/issues/2782#issuecomment-2493576327
Given that he aims for 3.2, let's already settle on an upcoming deprecation
of the filter for 3.3 with a removal for 3.5. This will leave time to finish
the development and permit users to switch smoothly. At this point no warning
is emitted (since the users have no alternative) but better mention this plan
in the doc to make them aware of future changes.
The per-packet delivery rate sample is applied to ack-eliciting packet only
calling ->drs_on_transmit() BBR callback. So, ->on_pkt_lost() which inspects the
delivery rate sampling information during packet loss detection must not be
called for non ack-eliciting packet. If not, it would be facing with non
initialized variables with big chance to trigger a BUG_ON().
As BBR is implemented in the current developement version, there is
no need to backport this patch.
A "return NULL" statement was placed for error handling in the
posix_memalign() handler instead of an int errno value, by recent
commit 5ddc8b3ad4 ("MINOR: activity/memprofile: monitor non-portable
calls as well"). Surprisingly the warning only triggered on gcc-4.8.
Let's use ENOMEM instead. No backport needed.
The formatting of the first-line, for a request or a response, does not
properly handle the wrapping of the output buffer. This may lead to a data
corruption for the current response or eventually for the previous one.
Utility functions used to format the first-line of the request or the
response rely on the chunk API. So it is not expected to pass a buffer that
wraps. Unfortunatly, because of a change performed during the 2.9 dev cycle,
the output buffer was direclty used instead of a non-wrapping buffer created
from it with b_make() function. It is not an issue for the request because
its start-line is always the first block formatted in the output buffer. But
for the response, the output may be not empty and may wrap. In that case,
the response start-line is dumped at a random position in the buffer,
corrupting data. AFAIK, it is only an issue if the HTTP request pipelining
is used.
To fix the issue, we now take care to create a non-wapping buffer from the
output buffer.
This patch should fix issues #2779 and #2996. It must be backported as far as
2.9.
Released version 3.1-dev14 with the following main changes :
- MINOR: acl: export find_acl_default()
- MINOR: sample: extend the "when" converter to support an ACL
- MINOR: cfgparse: parse tune.{rcvbuf,sndbuf}.{client,server} as sizes
- MINOR: cfgparse: parse tune.{rcvbuf,sndbuf}.{frontend,backend} as sizes
- MINOR: cfgparse: parse tune.pipesize as a size
- MINOR: cfgparse: parse tune.recv_enough as a size
- MINOR: cfgparse: parse tune.bufsize as a size
- MINOR: cfgparse: parse tune.bufsize.small as a size
- REGTESTS: silence the "log format ignored" warnings
- REGTESTS: silence warning "previous 'http-response' action is final"
- REGTESTS: make the unit explicit for very short timeouts
- REGTESTS: silence warnings about content-type being ignored
- REGTESTS: remove a duplicate "option httpslog" in the defaults section
- REGTESTS: silence warning "L6 sample fetches ignored" in cond_set_var
- REGTESTS: add missing timeouts to 30 tests
- REGTESTS: only use tune.ssl.default-dh-param when not using AWS-LC
- REGTESTS: enable -dW on almost all tests to fail on warnings
- MEDIUM: config: warn on unitless timeouts < 100 ms
- MINOR: tools: make parse_size_err() support 32/64 bits
- MINOR: ring: support unit suffixes in the size
- MINOR: cfgparse-global: parse options to allow non std keywords in discovery mode
- BUG/MINOR: mworker-prog: don't warn about deprecated section with expose-deprecated-directives
- MINOR: cli: make "show env" accessible via master CLI without enabling debug
- MINOR: config: show HAPROXY_BRANCH in "show env" output
- MINOR: http-ana: Add option to keep query-string on a localtion-based redirect
- MINOR: http-ana: Add support for "set-cookie-fmt" option to redirect rules
- MINOR: agent-check: Be able to set absolute weight via an agent
- MINOR: stream: Add an option to "show sess" command to dump the captured URI
- DOC: config: A a space before ':' for {bs,fs}.aborted and {bs,fs}.rst_code
- DOC: config: Fix a typo in "1.3.1. The Request line"
- MINOR: http: Add support for HTTP 414/431 status codes
- DEV: phash: Update 414 and 431 status codes to phash
- MINIR: mux-h1: Return 414 or 431 when appropriate
- BUG/MINOR: http_ana: Report -1 for %Tr for invalid response only
- DOC: config: Slightly improve the %Tr documentation
- DOC: config: Move wait_end in section about internal samples
- DOC: config: Move fs.* and bs.* in section about L5 samples
- MINOR: stats-file: add the filename in the warning
- MEDIUM: stats-file: explicitely ignore comments starting by //
- DOC: quic: rename max-window-size as with default prefix
- MINOR: mux-quic: add missing values for show flags
- MINOR: quic: simplify qc_prep_pkts() exit path
- MINOR: quic: support a max number of built packet per send iteration
- MINOR: quic: extend qc_send_mux() return type with a dedicated enum
- MINOR: quic: define quic_pacing module
- MINOR: quic/pacing: implement quic_pacer engine
- MINOR: quic/pacing: support pacing emission on quic_conn layer
- MINOR: quic/pacing: add burst support
- MINOR: mux-quic: define a tx STREAM frame list member
- MINOR: mux-quic: encapsulate QCC tasklet wakeup
- MAJOR: mux-quic: support pacing emission
- MINOR: quic: use dynamic cc_algo on bind_conf
- MINOR: quic: extend quic-cc-algo optional parameters
- MEDIUM: quic: define cubic-pacing congestion algorithm
- MINOR: mux_quic/pacing: display pacing info on show quic
- MEDIUM: stats-file: silently ignore be/fe mistmatch
- REGTESTS: use -dW by default on every reg-tests
- DOC: lua: fix yield-dependent methods expected contexts
- DOC: sched: add missing scheduler API documentation for tasklet_wakeup_after()
- DOC: sched: document the missing TASK_F_UEVT* flags
- CLEANUP: tinfo: move sched_*_date/*_mono_time to the thread-local area
- MINOR: stream: don't update s->lat_time when the wakeup date is not set
- MINOR: tinfo/clock: turn sched_call_date to 64-bits
- MINOR: sched: add TASK_F_WANTS_TIME to make the scheduler update the call date
- MINOR: tools: add new macro DEFZERO to provide a default zero argument
- MINOR: tasklet: make the low-level tasklet API take a flag
- MINOR: tasklet: support an optional set of wakeup flags to tasklet_wakeup_on()
- DOC: configuration: explain the rules regarding spaces in arguments
- DOC: configuration: explain quotes and spaces in conditional blocks
- DOC: configuration: wrap long line for "strstr()" conditional expression
- BUG/MINOR: http-ana: Adjust the server status before the L7 retries
- MINOR: http-fetch: Add an option to 'query" to get the QS with the '?'
- BUG/MINOR: cfgparse-quic: fix renaming of max-window-size
- MEDIUM: mworker: remove USE_SYSTEMD requirement for -Ws
- CI: vtest: temporarily build from the sd-notify PR
- MINOR: systemd: replace SOCK_CLOEXEC by fcntl call to FD_CLOEXEC
- BUILD: makefile: make ERR apply to build options as well
- MINOR: startup: set HAPROXY_LOCALPEER only once
- DOC: configuration: update "Environment variables" chapter
- DOC: config: indent the list of environment variables
- OPTION: map/hlua: make core.set_map() lookup more efficient
- REGTESTS: switch to -Ws for master-worker reg-tests
- REGTESTS: disable temporarly mworker test on OSX
- MINOR: quic: Add the congestion window initial value to QUIC path
- MINOR: window_filter: Implement windowed filter (only max)
- MINOR: quic: implement delivery rate sampling algorithm
- MINOR: quic: implement BBR congestion control algorithm for QUIC
- MINOR: quic: quic_cc modifications to support BBR
- MINOR: quic: quic_loss modifications to support BBR
- MINOR: quic: RX part modifications to support BBR
- MINOR: quic: TX part modifications to support BBR.
- MINOR: quic: add "bbr" new "quic-cc-algo" option
- BUG/MEDIUM: mux-h2: Increase max number of headers when encoding HEADERS frames
- BUG/MEDIUM: mux-h2: Check the number of headers in HEADERS frame after decoding
- BUG/MEDIUM: h3: Properly limit the number of headers received
- BUG/MEDIUM: h3: Increase max number of headers when sending headers
- DOC: config: Improve documentation of tune.http.maxhdr directive
- DOC: management: Clearly state "show errors" only reports malformed H1 messages
- BUILD: makefile: build flags.c before haproxy to speed up the build
- BUILD: makefile: reorder object files by build time
- MINOR: config: Improve warnings on misplaced rules by adding an optional arg
- CLEANUP: cfgparse: Add direction in functions name that warn on misplaced rules
- MINOR: cfgparse: Emit a warning for misplaced "tcp-response content" rules
- BUG/MINOR: cfgparse-quic: fix bbr initialization
- MINOR: cfgparse-quic: activate pacing only via burst argument
- MINOR: quic: Useless rate sample member initialization
- BUG/MINOR: cfgparse-quic: fix warning for cc-aglo with 0 burst
- MINOR: quic: support pacing for newreno and nocc
- BUG/MINOR: quic: Missing application limitations tracking for BBR
- MINOR: cfgparse-global: add cfg_parse_global_chroot
- MINOR: cfgparse-global: add more checks for "chroot" argument
- BUG/MINOR: startup: fix UAF when set the default for log_tag
- MINOR: capabilities: rename program_name argument to progname
- MINOR: startup: use global progname variable
- MINOR: cfgparse-global: add cfg_parse_global_localpeer
- BUG/MINOR: config: allow to check HAPROXY_LOCALPEER in config
- BUG/MINOR: startup: init_early: remove obsolete comment
- BUG/MEDIUM: debug: don't set the STUCK flag from debug_handler()
- BUG/MEDIUM: wdt: fix the stuck detection for warnings
- BUG/MINOR: activity/memprofile: reinitialize the free calls on DSO summary
- MINOR: activity/memprofile: offer a function to unregister stale info
- BUG/MEDIUM: pools/memprofile: always clean stale pool info on pool_destroy()
- MINOR: activity: better report nil than ffff in unknown callers
- CLEANUP: activity: better use a mask to tests freeing methods
- MINOR: activity/memprofile: also monitor strdup() activity
- MINOR: activity/memprofile: monitor non-portable calls as well
- MINOR: activity: interrupt the show profile dump more often
- MINOR: tools: resolve main() only once in resolve_sym_name()
- MINOR: tools: add a new function "resolve_dso_name" to find a symbol's DSO
- MINOR: activity/memprofile: use resolve_dso_name() for the DSO summary
- REGTESTS: relax strerror matching to avoid a failure on libmusl
- REGTESTS: don't rely on the base64 utility when openssl base64 is already used
Regtest ocsp_auto_update.vtc used to fail here on FreeBSD because the
base64 utility was not installed by default. Once installed it would
still fail because the utility doesn't support -w to wrap lines. Since
the regtest already relies on openssl base64 for a few commands, let's
just rely on it for the other ones. The only limitation is that openssl
freezes on lines longer than 1024 bytes, and doesn't seem to process more
than 255 chars at once, which might be the reason for using base64 -w 1000
in the first place (the script was probably tested like this). Instead
sed is efficient at wrapping long lines and does the job pretty well.
The output was fixed at 72 chars so that the output is also readable on
a terminal for debugging.
The regtest4be_1srv_smtpchk_httpchk_layer47errors.vtc fails on musl
because it reports "Network unreachable" for -EUNREACH while the
check matches "Network is unreachable" as on other OSes. Let's just
replace " is" with ".*". It now works on both glibc and musl.
In the memprofile summary per DSO, we currently have to pay a high price
by calling dladdr() on each symbol when doing the summary per DSO at the
end, while we're not interested in these details, we just want the DSO
name which can be made cheaper to obtain, and easier to manipulate. So
let's create resolve_dso_name() to only extract minimal information from
an address. At the moment it still uses dladdr() though it avoids all the
extra expensive work, and will further be able to leverage the same
mechanism as "show libs" to instantly spot DSO from address ranges.
resolv_sym_name() calls dladdr(main) for each symbol in order to compare
the first address with other symbols. But this is pointless and quite
expensive in outputs to "show profiling" for example. Let's just keep a
local copy and have a variable indicating if the resolution is needed/
in progress/done to save the value for subsequent calls.
The calls to resolv_sym_name() can be a bit expensive. Forcing to
yield more often is better for the latency and will avoid the
watchdog reporting warnings.
Note that it's still called in the sort at the end, but that one
cannot be avoided. At best we could try to rely on the list of libs
but that's not trivial and not always present.
Some dependencies might very well rely on posix_memalign(), strndup()
or other less portable callsn making us miss them when chasing memory
leaks, resulting in negative global allocation counters. Let's provide
the handlers for the following functions:
strndup() // _POSIX_C_SOURCE >= 200809L || glibc >= 2.10
valloc() // _BSD_SOURCE || _XOPEN_SOURCE>=500 || glibc >= 2.12
aligned_alloc() // _ISOC11_SOURCE
posix_memalign() // _POSIX_C_SOURCE >= 200112L
memalign() // obsolete
pvalloc() // obsolete
This time we don't fail if they're not found, we just silently forward
the calls.
Some memory profiling outputs have showed negative counters, very likely
due to some libs calling strdup(). Let's add it to the list of monitored
activities.
Actually even haproxy itself uses some. Having "profiling.memory on" in
the config reveals 35 call places.
In "show profiling memory", we need to distinguish methods which really
free memory from those which do not so that we don't account for the
free value twice. However for now it's done using multiple tests, which
are going to complicate the addition of new methods. Let's switch to a
bit field defined as a mask in a single place instead, as we don't
intend to use more than 32/64 methods!
For unknown callers we try to get the lowest known address and we
purposely ignore NULL during calculation of the min. But the side
effect is that we also report ffff in the per-DSO address. Better
catch this case and finally accept to report nil. Before it would
report this:
$ socat - /tmp/sock1 <<< "show profiling memory" |grep nil
50000 10 9600000 9440| (nil) [other] unknown(192) [delta=9590560] [pool=http_txn]
50000 10 9600000 9440| (nil) DSO:other; delta_calls=49990; delta_bytes=9590560
now it reports this:
$ socat - /tmp/sock1 <<< "show profiling memory" |grep nil
50000 11 9600000 9656| (nil) [other] unknown(192) [delta=9590344] [pool=connection]
50000 11 9600000 9656| (nil) DSO:other; delta_calls=49989; delta_bytes=9590344
There's actually a problem with memprofiles: the pool pointer is stored
in ->info but some pools are replaced during startup, such as the trash
pool, leaving a dangling pointer there, that may randomly report crap or
even crash during "show profile memory".
Let's make pool_destroy() call memprof_remove_stale_info() added
by previous patch so that these entries are properly unregistered.
This must be backported along with the previous patch (MINOR:
activity/memprofile: offer a function to unregister stale info) as
far as 2.8.
There's actually a problem with memprofiles: the pool pointer is stored
in ->info but some pools are replaced during startup, such as the trash
pool, leaving a dangling pointer there.
Let's complete the API with a new function memprof_remove_stale_info()
that will remove all stale references to this info pointer. It's also
present when USE_MEMORY_PROFILING is not set so as to ease the job on
callers.
In commit 401fb0e87a ("MINOR: activity/memprofile: show per-DSO stats")
we added a summary per DSO. However the free calls/tot were not initialized
when creating a new entry because initially they were applied to any entry,
but since we don't update free calls for non-free capable callers, we still
need to reinitialize these entries when reassigning one. Because of this
bug, a "show profiling memory" output can randomly show highly negative
values on the DSO lines if it turns out that the DSO entry was created on
an alloc instead of a realloc/free.
Since the commit above was backported to 2.9, this one must go there as
well.
If two slow tasks trigger one warning even a few seconds apart, the
watchdog code will mistakenly take this for a definite stuck task and
kill the process. The reason is that since commit 148eb5875f ("DEBUG:
wdt: better detect apparently locked up threads and warn about them")
the updated ctxsw count is not the correct one, instead of updating
the private counter it resets the public one, preventing it from making
progress and making the wdt believe that no progress was made. In
addition the initial value was read from [tid] instead of [thr].
Please note that another fix is needed in debug_handler() otherwise the
watchdog will fire early after the first warning or thread dump.
A simple test for this is to issue several of these commands back-to-back
on the CLI, which crashes an unfixed 3.1 very quickly:
$ socat /tmp/sock1 - <<< "expert-mode on; debug dev loop 1000"
This needs to be backported to 2.9 since the fix above was backported
there. The impact on 3.0 and 2.9 is almost inexistent since the watchdog
there doesn't apply the shorter warning delay, so the first call already
indicates that the thread is stuck.
Since 2.0 with commit e6a02fa65a ("MINOR: threads: add a "stuck" flag
to the thread_info struct"), the TH_FL_STUCK flag was set by the
debugger to flag that a thread was stuck and report it in the output.
However, two commits later (2bfefdbaef "MAJOR: watchdog: implement a
thread lockup detection mechanism"), this flag was used to detect that
a thread had already been reported as stuck. The problem is that it
seldom happens that a "show threads" command instantly crashes because
it calls debug_handler(), which sets the flag, and if the watchdog timer
was about to trigger before going back to the scheduler, the watchdog
believes that the thread has been stuck for a while and will kill the
process.
The issue was magnified in 3.1 with the lower-delay warning, because
it's possible for a thread to die on the next wakeup after the first
warning (which calls debug_handler() hence sets the STUCK flag).
One good approach would have been to use two distinct flags, one for
"stuck" as reported by the debug handler, and one for "stuck" as seen
by the watchdog. However, one could also argue that since the second
commit, given that the wdt monitors the threads, there's no point any
more for the debug handler to set the flag itself. Removing this code
means that two consecutive "show threads" will not report "stuck" until
the watchdog sets it, which aligns better with expectations.
This can be backported to all stable releases. This code has changed a
bit over time, the "if" block and the harmless variables just need to
be removed.
This fixes the commit d6ccd1738b
("MINOR: startup: set HAPROXY_LOCALPEER only once").
Comment "/* preset some environment variables */" is now useless here as
HAPROXY_LOCALPEER is set later during the initialization stage and only once.
This should not be backported, as related to the latest master-worker
refactoring.
This fixes the commit d6ccd1738b
("MINOR: startup: set HAPROXY_LOCALPEER only once"). HAPROXY_LOCALPEER could
be checked in the configuration to set some servers settings or listeners. So,
we need to set it just before we read the configuration at the second time.
Let's mark HAPROXY_LOCALPEER as "usable" in the configuration in the related
documentation chapter.
This should not be backported, as related to the latest master-worker
refactoring.