]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: pin file descriptor of persistent storage
authorYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 15 Mar 2024 15:38:06 +0000 (00:38 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 15 Mar 2024 16:12:05 +0000 (01:12 +0900)
This also drop the support of /run/systemd/netif/persistent-storage-ready,
as the file is anyway removed when networkd is stopped.
Let's use $SYSTEMD_NETWORK_PERSISTENT_STORAGE_READY=1 instead on testing.

docs/ENVIRONMENT.md
src/network/networkd-dhcp-server.c
src/network/networkd-manager-varlink.c
src/network/networkd-manager.c
src/network/networkd-manager.h
test/networkd-test.py

index cd6d66a81f1118205c9729d4ba09ec1640507edc..e5768eb971acaae98146cbcf4658cc10a2edc359 100644 (file)
@@ -618,6 +618,13 @@ SYSTEMD_HOME_DEBUG_SUFFIX=foo \
   `nftables`. Selects the firewall backend to use. If not specified tries to
   use `nftables` and falls back to `iptables` if that's not available.
 
+`systemd-networkd`:
+
+* `$SYSTEMD_NETWORK_PERSISTENT_STORAGE_READY` – takes a boolean. If true,
+  systemd-networkd tries to open the persistent storage on start. To make this
+  work, ProtectSystem=strict in systemd-networkd.service needs to be downgraded
+  or disabled.
+
 `systemd-storagetm`:
 
 * `$SYSTEMD_NVME_MODEL`, `$SYSTEMD_NVME_FIRMWARE`, `$SYSTEMD_NVME_SERIAL`,
index b7bae37a4dd9da01de8d75dfacb1b5de805ccda0..b0887cc95e3b38205fc450e0b97a90481f454ced 100644 (file)
@@ -160,7 +160,7 @@ int link_start_dhcp4_server(Link *link) {
          * the realtime clock in not usable in the early boot stage, and all saved leases may be wrongly
          * handled as expired and dropped. */
         if (!sd_dhcp_server_is_in_relay_mode(link->dhcp_server) &&
-            !link->manager->persistent_storage_is_ready)
+            link->manager->persistent_storage_fd < 0)
                 return 0;
 
         r = sd_dhcp_server_start(link->dhcp_server);
index c86505b039d53590929fd53466044955d9b38f81..69c7a81339c590cbba6461061b3a9a064b6191e9 100644 (file)
@@ -3,7 +3,7 @@
 #include <unistd.h>
 
 #include "bus-polkit.h"
-#include "fs-util.h"
+#include "fd-util.h"
 #include "lldp-rx-internal.h"
 #include "networkd-dhcp-server.h"
 #include "networkd-manager-varlink.h"
@@ -185,11 +185,17 @@ static int vl_method_set_persistent_storage(Varlink *vlink, JsonVariant *paramet
                 return r;
 
         if (ready) {
-                r = path_is_read_only_fs("/var/lib/systemd/network/");
+                _cleanup_close_ int fd = -EBADF;
+
+                fd = open("/var/lib/systemd/network/", O_CLOEXEC | O_DIRECTORY | O_PATH);
+                if (fd < 0)
+                        return log_warning_errno(errno, "Failed to open /var/lib/systemd/network/: %m");
+
+                r = fd_is_read_only_fs(fd);
                 if (r < 0)
-                        return log_warning_errno(r, "Failed to check if /var/lib/systemd/network/ is writable: %m");
+                        return log_warning_errno(r, "Failed to check if the persistent storage is writable: %m");
                 if (r > 0) {
-                        log_warning("The directory /var/lib/systemd/network/ is read-only.");
+                        log_warning("The persistent storage is on read-only filesystem.");
                         return varlink_error(vlink, "io.systemd.Network.StorageReadOnly", NULL);
                 }
         }
@@ -203,16 +209,16 @@ static int vl_method_set_persistent_storage(Varlink *vlink, JsonVariant *paramet
         if (r <= 0)
                 return r;
 
-        manager->persistent_storage_is_ready = ready;
-
         if (ready) {
-                r = touch("/run/systemd/netif/persistent-storage-ready");
-                if (r < 0)
-                        log_debug_errno(r, "Failed to create /run/systemd/netif/persistent-storage-ready, ignoring: %m");
-        } else {
-                if (unlink("/run/systemd/netif/persistent-storage-ready") < 0 && errno != ENOENT)
-                        log_debug_errno(errno, "Failed to remove /run/systemd/netif/persistent-storage-ready, ignoring: %m");
-        }
+                _cleanup_close_ int fd = -EBADF;
+
+                fd = open("/var/lib/systemd/network/", O_CLOEXEC | O_DIRECTORY | O_PATH);
+                if (fd < 0)
+                        return log_warning_errno(errno, "Failed to open /var/lib/systemd/network/: %m");
+
+                close_and_replace(manager->persistent_storage_fd, fd);
+        } else
+                manager->persistent_storage_fd = safe_close(manager->persistent_storage_fd);
 
         manager_toggle_dhcp4_server_state(manager, ready);
 
index 2545521b991b6ca5879f7a195d8a3f62e43d11bb..5c50b3c98a26321e60e03719302fa31ffe765803 100644 (file)
@@ -23,6 +23,7 @@
 #include "device-private.h"
 #include "device-util.h"
 #include "dns-domain.h"
+#include "env-util.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "firewall-util.h"
@@ -557,27 +558,27 @@ int manager_setup(Manager *m) {
         return 0;
 }
 
-static bool persistent_storage_is_ready(void) {
+static int persistent_storage_open(void) {
+        _cleanup_close_ int fd = -EBADF;
         int r;
 
-        if (access("/run/systemd/netif/persistent-storage-ready", F_OK) < 0) {
-                if (errno != ENOENT)
-                        log_debug_errno(errno, "Failed to check if /run/systemd/netif/persistent-storage-ready exists, assuming not: %m");
-                return false;
-        }
+        r = getenv_bool("SYSTEMD_NETWORK_PERSISTENT_STORAGE_READY");
+        if (r < 0 && r != -ENXIO)
+                return log_debug_errno(r, "Failed to parse $SYSTEMD_NETWORK_PERSISTENT_STORAGE_READY environment variable, ignoring: %m");
+        if (r <= 0)
+                return -EBADF;
 
-        r = path_is_read_only_fs("/var/lib/systemd/network/");
-        if (r == 0)
-                return true;
-        if (r < 0)
-                log_debug_errno(r, "Failed to check if /var/lib/systemd/network/ is writable: %m");
-        else
-                log_debug("The directory /var/lib/systemd/network/ is read-only.");
+        fd = open("/var/lib/systemd/network/", O_CLOEXEC | O_DIRECTORY | O_PATH);
+        if (fd < 0)
+                return log_debug_errno(errno, "Failed to open /var/lib/systemd/network/, ignoring: %m");
 
-        if (unlink("/run/systemd/netif/persistent-storage-ready") < 0 && errno != ENOENT)
-                log_debug_errno(errno, "Failed to remove /run/systemd/netif/persistent-storage-ready, ignoring: %m");
+        r = fd_is_read_only_fs(fd);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to check if /var/lib/systemd/network/ is writable: %m");
+        if (r > 0)
+                return log_debug_errno(SYNTHETIC_ERRNO(EROFS), "The directory /var/lib/systemd/network/ is on read-only filesystem.");
 
-        return false;
+        return TAKE_FD(fd);
 }
 
 int manager_new(Manager **ret, bool test_mode) {
@@ -591,13 +592,13 @@ int manager_new(Manager **ret, bool test_mode) {
                 .keep_configuration = _KEEP_CONFIGURATION_INVALID,
                 .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO,
                 .test_mode = test_mode,
-                .persistent_storage_is_ready = persistent_storage_is_ready(),
                 .speed_meter_interval_usec = SPEED_METER_DEFAULT_TIME_INTERVAL,
                 .online_state = _LINK_ONLINE_STATE_INVALID,
                 .manage_foreign_routes = true,
                 .manage_foreign_rules = true,
                 .manage_foreign_nexthops = true,
                 .ethtool_fd = -EBADF,
+                .persistent_storage_fd = persistent_storage_open(),
                 .dhcp_duid.type = DUID_TYPE_EN,
                 .dhcp6_duid.type = DUID_TYPE_EN,
                 .duid_product_uuid.type = DUID_TYPE_UUID,
@@ -672,6 +673,7 @@ Manager* manager_free(Manager *m) {
         free(m->dynamic_hostname);
 
         safe_close(m->ethtool_fd);
+        safe_close(m->persistent_storage_fd);
 
         m->fw_ctx = fw_ctx_free(m->fw_ctx);
 
index 320b859bfd839526a53e5aeed0f165f7a02c79ab..fd9ab341c83545af7d0253dc0f901e5fc72ca1d7 100644 (file)
@@ -30,6 +30,7 @@ struct Manager {
         sd_device_monitor *device_monitor;
         Hashmap *polkit_registry;
         int ethtool_fd;
+        int persistent_storage_fd;
 
         KeepConfiguration keep_configuration;
         IPv6PrivacyExtensions ipv6_privacy_extensions;
@@ -41,7 +42,6 @@ struct Manager {
         bool manage_foreign_routes;
         bool manage_foreign_rules;
         bool manage_foreign_nexthops;
-        bool persistent_storage_is_ready;
 
         Set *dirty_links;
         Set *new_wlan_ifindices;
index ab30928c27185893b9470b4a9616b36bf1fe879f..4ea76e1a94fb45964e64e07fb382087512efc8ba 100755 (executable)
@@ -921,7 +921,7 @@ EOF
 
 # For the networkd instance invoked below cannot support varlink connection.
 # Hence, 'networkctl persistent-storage yes' cannot be used.
-touch /run/systemd/netif/persistent-storage-ready
+export SYSTEMD_NETWORK_PERSISTENT_STORAGE_READY=1
 
 # run networkd as in systemd-networkd.service
 exec $(systemctl cat systemd-networkd.service | sed -n '/^ExecStart=/ {{ s/^.*=//; s/^[@+-]//; s/^!*//; p}}')