diff options
author | Luca Boccassi <bluca@debian.org> | 2024-11-04 13:12:31 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-11-04 13:12:31 +0100 |
commit | 867e2c2a60128a394dc5bfee6c11f7e0028b1ff4 (patch) | |
tree | 7bf2d991947c30768a0c1572822bb59583a4fa33 | |
parent | network: cleanups for IPv4LL (#34995) (diff) | |
parent | network: free DHCP client and friends in link_free() (diff) | |
download | systemd-867e2c2a60128a394dc5bfee6c11f7e0028b1ff4.tar.xz systemd-867e2c2a60128a394dc5bfee6c11f7e0028b1ff4.zip |
network: refuse new requests on stop (#35004)
split-out of #34989..
-rw-r--r-- | src/network/networkd-link.c | 2 | ||||
-rw-r--r-- | src/network/networkd-link.h | 1 | ||||
-rw-r--r-- | src/network/networkd-manager.c | 4 | ||||
-rw-r--r-- | src/network/networkd-netlabel.c | 3 | ||||
-rw-r--r-- | src/network/networkd-queue.c | 15 | ||||
-rw-r--r-- | src/network/networkd-route.c | 3 | ||||
-rw-r--r-- | src/network/networkd-state-file.c | 5 |
7 files changed, 28 insertions, 5 deletions
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index be8826b49c..432084038f 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -222,7 +222,7 @@ void link_dns_settings_clear(Link *link) { link->dnssec_negative_trust_anchors = set_free_free(link->dnssec_negative_trust_anchors); } -void link_free_engines(Link *link) { +static void link_free_engines(Link *link) { if (!link) return; diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 86aba9556b..5efe226084 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -253,7 +253,6 @@ int link_ipv6ll_gained(Link *link); bool link_has_ipv6_connectivity(Link *link); int link_stop_engines(Link *link, bool may_keep_dhcp); -void link_free_engines(Link *link); const char* link_state_to_string(LinkState s) _const_; LinkState link_state_from_string(const char *s) _pure_; diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 6639d59b32..15a309c82f 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -475,10 +475,8 @@ static int manager_stop(Manager *manager, ManagerState state) { manager->state = state; Link *link; - HASHMAP_FOREACH(link, manager->links_by_index) { + HASHMAP_FOREACH(link, manager->links_by_index) (void) link_stop_engines(link, /* may_keep_dhcp = */ true); - link_free_engines(link); - } return 0; } diff --git a/src/network/networkd-netlabel.c b/src/network/networkd-netlabel.c index 94bf8f5d26..f153a929e3 100644 --- a/src/network/networkd-netlabel.c +++ b/src/network/networkd-netlabel.c @@ -38,6 +38,9 @@ static int netlabel_command(uint16_t command, const char *label, const Address * assert(address->link->manager->genl); assert(IN_SET(address->family, AF_INET, AF_INET6)); + if (address->link->manager->state == MANAGER_STOPPED) + return 0; /* We cannot call link_ref() below. */ + r = sd_genl_message_new(address->link->manager->genl, NETLBL_NLTYPE_UNLABELED_NAME, command, &m); if (r < 0) return r; diff --git a/src/network/networkd-queue.c b/src/network/networkd-queue.c index e898ea6e85..f5ad748397 100644 --- a/src/network/networkd-queue.c +++ b/src/network/networkd-queue.c @@ -142,6 +142,15 @@ static int request_new( assert(manager); assert(process); + /* Note, requests will be processed only when the manager is in MANAGER_RUNNING. If a new operation + * is requested when the manager is in MANAGER_TERMINATING or MANAGER_RESTARTING, the request will be + * successfully queued but will never be processed. Then, here why we refuse new requests when the + * manager is in MANAGER_STOPPED? This is because we cannot call link_ref() in that case, as this may + * be called during link_free(), that means the reference counter of the link is already 0 and + * calling link_ref() below triggers assertion. */ + if (manager->state == MANAGER_STOPPED) + return -EBUSY; + req = new(Request, 1); if (!req) return -ENOMEM; @@ -426,6 +435,12 @@ int remove_request_add( assert(netlink); assert(message); + /* Unlike request_new(), remove requests will be also processed when the manager is in + * MANAGER_TERMINATING or MANAGER_RESTARTING. When the manager is in MANAGER_STOPPED, we cannot + * queue new remove requests anymore with the same reason explained in request_new(). */ + if (manager->state == MANAGER_STOPPED) + return 0; + req = new(RemoveRequest, 1); if (!req) return -ENOMEM; diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 3be737ae49..6aa4d0547b 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -574,6 +574,9 @@ int route_remove(Route *route, Manager *manager) { assert(route); assert(manager); + if (manager->state == MANAGER_STOPPED) + return 0; /* The remove request will not be queued anyway. Suppress logging below. */ + /* If the route is remembered, then use the remembered object. */ (void) route_get(manager, route, &route); diff --git a/src/network/networkd-state-file.c b/src/network/networkd-state-file.c index 337eaa5447..0c9e530128 100644 --- a/src/network/networkd-state-file.c +++ b/src/network/networkd-state-file.c @@ -948,6 +948,11 @@ void link_dirty(Link *link) { assert(link); assert(link->manager); + /* When the manager is in MANAGER_STOPPED, it is not necessary to update state files anymore, as they + * will be removed soon anyway. Moreover, we cannot call link_ref() in that case. */ + if (link->manager->state == MANAGER_STOPPED) + return; + /* The serialized state in /run is no longer up-to-date. */ /* Also mark manager dirty as link is dirty */ |