[Devel] [PATCH vz10 v2] selftests/uevent: do not fail on a netlink receive buffer overrun
Konstantin Khorenko
khorenko at virtuozzo.com
Mon Aug 24 16:09:22 MSK 2026
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;
--
2.47.1
More information about the Devel
mailing list