From 013359ac65b406417e02441bfe87228d35998b06 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 16 Mar 2024 00:38:06 +0900 Subject: network: pin file descriptor of persistent storage 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 | 7 +++++++ src/network/networkd-dhcp-server.c | 2 +- src/network/networkd-manager-varlink.c | 32 ++++++++++++++++++------------ src/network/networkd-manager.c | 36 ++++++++++++++++++---------------- src/network/networkd-manager.h | 2 +- test/networkd-test.py | 2 +- 6 files changed, 48 insertions(+), 33 deletions(-) diff --git a/docs/ENVIRONMENT.md b/docs/ENVIRONMENT.md index cd6d66a81f..e5768eb971 100644 --- a/docs/ENVIRONMENT.md +++ b/docs/ENVIRONMENT.md @@ -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`, diff --git a/src/network/networkd-dhcp-server.c b/src/network/networkd-dhcp-server.c index b7bae37a4d..b0887cc95e 100644 --- a/src/network/networkd-dhcp-server.c +++ b/src/network/networkd-dhcp-server.c @@ -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); diff --git a/src/network/networkd-manager-varlink.c b/src/network/networkd-manager-varlink.c index c86505b039..69c7a81339 100644 --- a/src/network/networkd-manager-varlink.c +++ b/src/network/networkd-manager-varlink.c @@ -3,7 +3,7 @@ #include #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); diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 2545521b99..5c50b3c98a 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -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); diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h index 320b859bfd..fd9ab341c8 100644 --- a/src/network/networkd-manager.h +++ b/src/network/networkd-manager.h @@ -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; diff --git a/test/networkd-test.py b/test/networkd-test.py index ab30928c27..4ea76e1a94 100755 --- a/test/networkd-test.py +++ b/test/networkd-test.py @@ -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}}') -- cgit v1.2.3