diff --git a/pkgs/by-name/sw/switch-to-configuration-ng/src/src/main.rs b/pkgs/by-name/sw/switch-to-configuration-ng/src/src/main.rs index 6d13b3c7605f..22d5f4954faf 100644 --- a/pkgs/by-name/sw/switch-to-configuration-ng/src/src/main.rs +++ b/pkgs/by-name/sw/switch-to-configuration-ng/src/src/main.rs @@ -87,6 +87,12 @@ const DRY_RELOAD_BY_ACTIVATION_LIST_FILE: &str = "/run/nixos/dry-activation-relo // Reuse the same default timeout that systemd uses. See https://github.com/systemd/systemd/blob/8b4278d12ec55cc3f96764bc8197e1055fbb6d3f/src/libsystemd/sd-bus/bus-internal.h#L312 const BUS_TIMEOUT: Duration = Duration::from_secs(25); +// Reuse the same daemon reload/reexecute timeout that systemd uses. See https://github.com/systemd/systemd/blob/5366dbdbd44ba4dc0c914dd4daa1a5297e0b2bde/src/basic/constants.h#L18 +const DAEMON_RELOAD_TIMEOUT: Duration = Duration::from_secs(180); + +// Used during times of waiting for D-Bus to process messages. +const DBUS_PROCESS_TIME: Duration = Duration::from_millis(500); + #[derive(Debug, Clone, PartialEq)] enum Action { Switch, @@ -932,7 +938,7 @@ fn block_on_jobs( "waiting for submitted jobs to finish, still have {} job(s)", submitted_jobs.borrow().len() ); - _ = conn.process(Duration::from_millis(500)); + _ = conn.process(DBUS_PROCESS_TIME); } } @@ -987,7 +993,7 @@ fn do_user_switch(parent_exe: String) -> anyhow::Result<()> { log::debug!("waiting for nixos activation to finish"); while !*nixos_activation_done.borrow() { _ = dbus_conn - .process(Duration::from_secs(500)) + .process(DBUS_PROCESS_TIME) .context("Failed to process dbus messages")?; } @@ -1158,19 +1164,19 @@ won't take effect until you reboot the system. let submitted_jobs = Rc::new(RefCell::new(HashMap::new())); let finished_jobs = Rc::new(RefCell::new(HashMap::new())); - let systemd_reload_status = Rc::new(RefCell::new(false)); + let systemd_is_reloading = Rc::new(RefCell::new(false)); systemd .subscribe() .context("Failed to subscribe to systemd dbus messages")?; - let _systemd_reload_status = systemd_reload_status.clone(); + let _systemd_is_reloading = systemd_is_reloading.clone(); let reloading_token = systemd .match_signal( move |signal: OrgFreedesktopSystemd1ManagerReloading, _: &LocalConnection, _msg: &Message| { - *_systemd_reload_status.borrow_mut() = signal.active; + *_systemd_is_reloading.borrow_mut() = signal.active; true }, @@ -1690,13 +1696,23 @@ won't take effect until you reboot the system. // just in case the new one has trouble communicating with the running pid 1. if restart_systemd { eprintln!("restarting systemd..."); + *systemd_is_reloading.borrow_mut() = true; _ = systemd.reexecute(); // we don't get a dbus reply here log::debug!("waiting for systemd restart to finish"); - while !*systemd_reload_status.borrow() { + + let mut reexec_time_waited = Duration::from_secs(0); + while *systemd_is_reloading.borrow() { _ = dbus_conn - .process(Duration::from_millis(500)) + .process(DBUS_PROCESS_TIME) .context("Failed to process dbus messages")?; + reexec_time_waited += DBUS_PROCESS_TIME; + if reexec_time_waited >= DAEMON_RELOAD_TIMEOUT { + anyhow::bail!( + "systemd daemon reexecute failed, timeout after {:?}", + DAEMON_RELOAD_TIMEOUT + ); + } } } @@ -1706,12 +1722,22 @@ won't take effect until you reboot the system. .context("Failed to reset failed units")?; // Make systemd reload its units. + *systemd_is_reloading.borrow_mut() = true; _ = systemd.reload(); // we don't get a dbus reply here log::debug!("waiting for systemd reload to finish"); - while !*systemd_reload_status.borrow() { + + let mut reload_time_waited = Duration::from_secs(0); + while *systemd_is_reloading.borrow() { _ = dbus_conn - .process(Duration::from_millis(500)) + .process(DBUS_PROCESS_TIME) .context("Failed to process dbus messages")?; + reload_time_waited += DBUS_PROCESS_TIME; + if reload_time_waited >= DAEMON_RELOAD_TIMEOUT { + anyhow::bail!( + "systemd daemon reload failed, timeout after {:?}", + DAEMON_RELOAD_TIMEOUT + ); + } } dbus_conn