Merge pull request #5177 from Alexays/fix/recent-issue-bugs

fix: backlight I/O flooding (#5020) + network IP recovery after link flap (#5122)
This commit is contained in:
Alexis Rouillard
2026-07-05 11:28:24 +02:00
committed by GitHub
2 changed files with 41 additions and 2 deletions
+27
View File
@@ -183,6 +183,12 @@ void waybar::modules::Network::createEventSocket() {
if (nl_socket_set_nonblocking(ev_sock_)) { if (nl_socket_set_nonblocking(ev_sock_)) {
throw std::runtime_error("Can't set non-blocking on network socket"); throw std::runtime_error("Can't set non-blocking on network socket");
} }
// Enlarge the socket receive buffer so that a burst of link/address/route
// change notifications (e.g. a router reboot or a PPPoE redial) is less likely
// to overflow it and make the kernel drop messages (ENOBUFS). Overruns are
// still handled in worker() by resynchronising the state, but a larger buffer
// avoids most of them. The kernel caps the request at net.core.rmem_max.
nl_socket_set_buffer_size(ev_sock_, 1024 * 1024, 0);
nl_socket_add_memberships(ev_sock_, RTNLGRP_LINK, RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR, 0); nl_socket_add_memberships(ev_sock_, RTNLGRP_LINK, RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR, 0);
if (!config_["interface"].isString()) { if (!config_["interface"].isString()) {
nl_socket_add_memberships(ev_sock_, RTNLGRP_IPV4_ROUTE, RTNLGRP_IPV6_ROUTE, 0); nl_socket_add_memberships(ev_sock_, RTNLGRP_IPV4_ROUTE, RTNLGRP_IPV6_ROUTE, 0);
@@ -277,6 +283,27 @@ void waybar::modules::Network::worker() {
rc = 0; rc = 0;
break; break;
} }
if (rc == -NLE_NOMEM || errno == ENOBUFS) {
// The kernel dropped multicast notifications because our receive
// buffer overflowed. This happens during a burst of
// link/address/route changes such as a router reboot or a PPPoE
// redial. We have lost track of the current state -- in
// particular the RTM_NEWADDR carrying the interface's new IP
// address may have been dropped -- so request a fresh dump to
// resynchronise. Without this the address (cleared by the
// preceding RTM_DELADDR) would stay blank until Waybar is
// restarted, because nothing else re-queries it (#5122).
spdlog::warn("network: netlink receive buffer overrun, resyncing state");
want_link_dump_ = true;
want_addr_dump_ = true;
if (!config_["interface"].isString()) {
want_route_dump_ = true;
}
askForStateDump();
// Keep draining; the next recv proceeds normally now that the
// overrun has been reported.
continue;
}
} }
if (rc < 0) { if (rc < 0) {
spdlog::error("nl_recvmsgs_default error: {}", nl_geterror(-rc)); spdlog::error("nl_recvmsgs_default error: {}", nl_geterror(-rc));
+14 -2
View File
@@ -230,9 +230,21 @@ BacklightBackend::BacklightBackend(std::chrono::milliseconds interval,
upsert_device(devices, dev.get()); upsert_device(devices, dev.get());
} }
// Refresh state if timed out // Refresh state if timed out. Only re-read the sysfs attributes of the
// devices we already track instead of re-enumerating the whole udev tree
// (udev_enumerate_scan_devices), which walks all of /sys/class/backlight
// and /sys/class/leds and floods the filesystem with open/close syscalls
// on every polling tick (#5020). Device add/remove is already delivered
// by the udev monitor above, so a periodic full re-scan is redundant.
if (event_count == 0) { if (event_count == 0) {
enumerate_devices(devices, udev.get()); for (const auto& device : devices) {
std::unique_ptr<udev_device, UdevDeviceDeleter> dev{
udev_device_new_from_subsystem_sysname(udev.get(), device.subsystem().c_str(),
device.name().c_str())};
if (dev) {
upsert_device(devices, dev.get());
}
}
} }
{ {
std::scoped_lock<std::mutex> lock(udev_thread_mutex_); std::scoped_lock<std::mutex> lock(udev_thread_mutex_);