From 1f267e77edf659b89f8779630712a82fda66f5e5 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 27 May 2024 11:08:33 +0900 Subject: [PATCH] sd-device: allow to restart device monitor Previously, sd_device_monitor_stop() closes socket, hence we cannot restart monitoring unless recreating sd_device_monitor object. Let's allow to restart monitor by sd_device_monitor_start(). --- src/libsystemd/sd-device/device-monitor.c | 81 +++++++++++++++++++++-- 1 file changed, 74 insertions(+), 7 deletions(-) diff --git a/src/libsystemd/sd-device/device-monitor.c b/src/libsystemd/sd-device/device-monitor.c index 5881d02540..49167c69f5 100644 --- a/src/libsystemd/sd-device/device-monitor.c +++ b/src/libsystemd/sd-device/device-monitor.c @@ -20,6 +20,7 @@ #include "fd-util.h" #include "format-util.h" #include "hashmap.h" +#include "io-util.h" #include "iovec-util.h" #include "missing_socket.h" #include "mountpoint-util.h" @@ -56,6 +57,10 @@ struct sd_device_monitor { Set *nomatch_parent_filter; bool filter_uptodate; + bool multicast_group_dropped; + size_t multicast_group_len; + uint32_t *multicast_groups; + sd_event *event; sd_event_source *event_source; char *description; @@ -253,13 +258,50 @@ _public_ int sd_device_monitor_is_running(sd_device_monitor *m) { return sd_event_source_get_enabled(m->event_source, NULL); } +static int device_monitor_update_multicast_groups(sd_device_monitor *m, bool add) { + int r, opt = add ? NETLINK_ADD_MEMBERSHIP : NETLINK_DROP_MEMBERSHIP; + + assert(m); + assert(m->sock >= 0); + + for (size_t i = 0; i < m->multicast_group_len; i++) + for (unsigned j = 0; j < sizeof(uint32_t) * 8; j++) + if (m->multicast_groups[i] & (1U << j)) { + unsigned group = i * sizeof(uint32_t) * 8 + j + 1; + + /* group is "unsigned", but netlink(7) says the argument is "int". */ + r = setsockopt_int(m->sock, SOL_NETLINK, opt, group); + if (r < 0) + return r; + } + + return 0; +} + _public_ int sd_device_monitor_stop(sd_device_monitor *m) { + int r; + assert_return(m, -EINVAL); + assert_return(m->sock >= 0, -ESTALE); - m->event_source = sd_event_source_unref(m->event_source); - (void) device_monitor_disconnect(m); + if (!m->multicast_group_dropped) { + m->multicast_group_len = 0; + m->multicast_groups = mfree(m->multicast_groups); - return 0; + /* Save multicast groups. */ + r = netlink_socket_get_multicast_groups(m->sock, &m->multicast_group_len, &m->multicast_groups); + if (r < 0 && r != -ENOPROTOOPT) + return r; + + /* Leave from all multicast groups to prevent the buffer is filled. */ + r = device_monitor_update_multicast_groups(m, /* add = */ false); + if (r < 0) + return r; + + m->multicast_group_dropped = true; + } + + return sd_event_source_set_enabled(m->event_source, SD_EVENT_OFF); } static int device_monitor_event_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) { @@ -283,6 +325,7 @@ _public_ int sd_device_monitor_start(sd_device_monitor *m, sd_device_monitor_han int r; assert_return(m, -EINVAL); + assert_return(m->sock >= 0, -ESTALE); if (!m->event) { r = sd_device_monitor_attach_event(m, NULL); @@ -297,19 +340,41 @@ _public_ int sd_device_monitor_start(sd_device_monitor *m, sd_device_monitor_han m->callback = callback; m->userdata = userdata; - r = sd_event_add_io(m->event, &m->event_source, m->sock, EPOLLIN, device_monitor_event_handler, m); + if (!m->event_source) { + /* The monitor has never started. Add IO event source. */ + r = sd_event_add_io(m->event, &m->event_source, m->sock, EPOLLIN, device_monitor_event_handler, m); + if (r < 0) + return r; + + (void) sd_event_source_set_description(m->event_source, m->description ?: "sd-device-monitor"); + return 0; + } + + r = sd_device_monitor_is_running(m); if (r < 0) return r; + if (r == 0) { + /* If the monitor was previously started but now it is stopped, flush anything queued during + * the monitor is stopped. */ + r = flush_fd(m->sock); + if (r < 0) + return r; - (void) sd_event_source_set_description(m->event_source, m->description ?: "sd-device-monitor"); + /* Then, join the saved broadcast groups again. */ + r = device_monitor_update_multicast_groups(m, /* add = */ true); + if (r < 0) + return r; - return 0; + m->multicast_group_dropped = false; + } + + return sd_event_source_set_enabled(m->event_source, SD_EVENT_ON); } _public_ int sd_device_monitor_detach_event(sd_device_monitor *m) { assert_return(m, -EINVAL); - (void) sd_device_monitor_stop(m); + m->event_source = sd_event_source_unref(m->event_source); m->event = sd_event_unref(m->event); return 0; @@ -371,6 +436,7 @@ static sd_device_monitor *device_monitor_free(sd_device_monitor *m) { assert(m); (void) sd_device_monitor_detach_event(m); + (void) device_monitor_disconnect(m); uid_range_free(m->mapped_userns_uid_range); free(m->description); @@ -380,6 +446,7 @@ static sd_device_monitor *device_monitor_free(sd_device_monitor *m) { hashmap_free(m->nomatch_sysattr_filter); set_free(m->match_parent_filter); set_free(m->nomatch_parent_filter); + free(m->multicast_groups); return mfree(m); } -- 2.25.1