]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: refuse further requests when manager is in MANAGER_STOPPED
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sat, 2 Nov 2024 19:56:32 +0000 (04:56 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 3 Nov 2024 00:14:36 +0000 (09:14 +0900)
In that case, requests will never be processed anyway. But further more,
we cannot call link_ref() at that stage. Otherwise, we trigger assertion.

src/network/networkd-netlabel.c
src/network/networkd-queue.c
src/network/networkd-route.c
src/network/networkd-state-file.c

index 94bf8f5d268bb05a0165e6fec6485a56e7927bbc..f153a929e33e3f7f51b9afc1adfd9ec82db10760 100644 (file)
@@ -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;
index e898ea6e85406ab8422d7c2069f77faf4a41a430..f5ad7483976e2ca38df1332ee6d174a801f80e92 100644 (file)
@@ -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;
index 3be737ae49e4db9bbca5c8cde1c16993f5199a58..6aa4d0547bb5d4f6663186da90800cadd320ec65 100644 (file)
@@ -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);
 
index 337eaa5447e5c9153fb9cd9fe8a338db9cbaf23e..0c9e530128a58221187a5c7ae28adb5679b96c79 100644 (file)
@@ -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 */