[Devel] [PATCH vz10 v2] selftests/uevent: do not fail on a netlink receive buffer overrun
Eva Kurchatova (Virtuozzo)
eva.kurchatova at virtuozzo.com
Wed Aug 26 22:32:52 MSK 2026
On 8/24/26 16:09, Konstantin Khorenko wrote:
> SO_RCVBUF is set to __UEVENT_BUFFER_SIZE, 4KB, which a busy machine
> overruns while the test is listening:
>
> No buffer space available - Failed to receive uevent
>
> Two things are wrong here.
>
> The socket queue is sized after a single message, while do_test()
> deliberately triggers ten uevents "to account for the case where the
> kernel might drop some", so the queue has to hold more than one.
>
> Give it its own size and leave the message buffer alone: the kernel caps
> a single uevent at UEVENT_BUFFER_SIZE, 2048 bytes, so 4KB per message is
> already generous.
>
> The receive loop then treats every error as fatal, ENOBUFS included,
> which defeats those ten uevents. Netlink clears the error after
> reporting it once, so the copies still queued, or still on their way,
> are perfectly receivable. Retry instead.
>
> do_test() bounds the listener with a two second sigtimedwait(), so a
> retry cannot hang the test.
>
> https://virtuozzo.atlassian.net/browse/VSTOR-139674
> Feature: fix selftests
> Reported-by: Eva Kurchatova <eva.kurchatova at virtuozzo.com>
> Signed-off-by: Konstantin Khorenko <khorenko at virtuozzo.com>
> ---
> Changes in v2:
> - keep __UEVENT_BUFFER_SIZE at 4KB and give SO_RCVBUF its own
> __UEVENT_RCVBUF_SIZE. v1 raised the shared macro, which sized the
> socket queue correctly but also turned the per message buffer into a
> 128KB zero initialized array on the stack, while the kernel caps a
> single uevent at UEVENT_BUFFER_SIZE, 2048 bytes.
> - retry recvmsg() on ENOBUFS instead of failing. v1 only made the
> overrun less likely; the test still died on the first one, even
> though do_test() triggers ten uevents precisely so that drops are
> tolerated.
> - subject and commit message updated accordingly.
>
> tools/testing/selftests/uevent/uevent_filtering.c | 13 ++++++++++++-
> 1 file changed, 12 insertions(+), 1 deletion(-)
>
> diff --git a/tools/testing/selftests/uevent/uevent_filtering.c b/tools/testing/selftests/uevent/uevent_filtering.c
> index 8062804ff759..735eb8138c44 100644
> --- a/tools/testing/selftests/uevent/uevent_filtering.c
> +++ b/tools/testing/selftests/uevent/uevent_filtering.c
> @@ -23,6 +23,11 @@
>
> #define __DEV_FULL "/sys/devices/virtual/mem/full/uevent"
> #define __UEVENT_BUFFER_SIZE (2048 * 2)
> +/*
> + * The socket queue has to hold more than a single message: the test
> + * triggers ten uevents and a busy machine overruns a small buffer.
> + */
> +#define __UEVENT_RCVBUF_SIZE (2048 * 64)
> #define __UEVENT_HEADER "add@/devices/virtual/mem/full"
> #define __UEVENT_HEADER_LEN sizeof("add@/devices/virtual/mem/full")
> #define __UEVENT_LISTEN_ALL -1
> @@ -78,7 +83,7 @@ static int uevent_listener(unsigned long post_flags, bool expect_uevent,
> {
> int sk_fd, ret;
> socklen_t sk_addr_len;
> - int rcv_buf_sz = __UEVENT_BUFFER_SIZE;
> + int rcv_buf_sz = __UEVENT_RCVBUF_SIZE;
> uint64_t sync_add = 1;
> struct sockaddr_nl sk_addr = { 0 }, rcv_addr = { 0 };
> char buf[__UEVENT_BUFFER_SIZE] = { 0 };
> @@ -158,6 +163,12 @@ static int uevent_listener(unsigned long post_flags, bool expect_uevent,
> ssize_t r;
>
> r = recvmsg(sk_fd, &hdr, 0);
> + /*
> + * The queue overran. The kernel clears the error after
> + * reporting it once and more uevents are on their way.
> + */
> + if (r < 0 && errno == ENOBUFS)
> + continue;
> if (r <= 0) {
> fprintf(stderr, "%s - Failed to receive uevent\n", strerror(errno));
> ret = -1;
I was originally concerned about spinning on recvmsg(), but considering
the socket is blocking, and recvmsg() should consume the error once,
this should be fine.
Otherwise, this is a good improvement over the v1.
Acknowledged-by: Eva Kurchatova <eva.kurchatova at virtuozzo.com>
More information about the Devel
mailing list