diff --git a/src/modules/network.cpp b/src/modules/network.cpp index 72a367fc..d3adfbe5 100644 --- a/src/modules/network.cpp +++ b/src/modules/network.cpp @@ -183,6 +183,12 @@ void waybar::modules::Network::createEventSocket() { if (nl_socket_set_nonblocking(ev_sock_)) { 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); if (!config_["interface"].isString()) { nl_socket_add_memberships(ev_sock_, RTNLGRP_IPV4_ROUTE, RTNLGRP_IPV6_ROUTE, 0); @@ -277,6 +283,27 @@ void waybar::modules::Network::worker() { rc = 0; 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) { spdlog::error("nl_recvmsgs_default error: {}", nl_geterror(-rc)); diff --git a/src/util/backlight_backend.cpp b/src/util/backlight_backend.cpp index bf669f15..9ccf7250 100644 --- a/src/util/backlight_backend.cpp +++ b/src/util/backlight_backend.cpp @@ -230,9 +230,21 @@ BacklightBackend::BacklightBackend(std::chrono::milliseconds interval, 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) { - enumerate_devices(devices, udev.get()); + for (const auto& device : devices) { + std::unique_ptr 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 lock(udev_thread_mutex_);