[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