]>
Commit | Line | Data |
---|---|---|
a26ebad5 SR |
1 | //! Tokio-based watchdog that shuts down the VM if not pinged for TIMEOUT |
2 | use std::sync::atomic::{AtomicI64, Ordering}; | |
3 | use proxmox::tools::time::epoch_i64; | |
4 | ||
5 | const TIMEOUT: i64 = 600; // seconds | |
6 | static TRIGGERED: AtomicI64 = AtomicI64::new(0); | |
1fde4167 SR |
7 | static INHIBITORS: AtomicI64 = AtomicI64::new(0); |
8 | ||
9 | pub struct WatchdogInhibitor {} | |
a26ebad5 SR |
10 | |
11 | fn handle_expired() -> ! { | |
12 | use nix::sys::reboot; | |
13 | println!("watchdog expired, shutting down"); | |
14 | let err = reboot::reboot(reboot::RebootMode::RB_POWER_OFF).unwrap_err(); | |
15 | println!("'reboot' syscall failed: {}", err); | |
16 | std::process::exit(1); | |
17 | } | |
18 | ||
19 | async fn watchdog_loop() { | |
20 | use tokio::time::{sleep, Duration}; | |
21 | loop { | |
22 | let remaining = watchdog_remaining(); | |
23 | if remaining <= 0 { | |
24 | handle_expired(); | |
25 | } | |
26 | sleep(Duration::from_secs(remaining as u64)).await; | |
27 | } | |
28 | } | |
29 | ||
30 | /// Initialize watchdog | |
31 | pub fn watchdog_init() { | |
32 | watchdog_ping(); | |
33 | tokio::spawn(watchdog_loop()); | |
34 | } | |
35 | ||
36 | /// Trigger watchdog keepalive | |
37 | pub fn watchdog_ping() { | |
38 | TRIGGERED.fetch_max(epoch_i64(), Ordering::AcqRel); | |
39 | } | |
40 | ||
41 | /// Returns the remaining time before watchdog expiry in seconds | |
42 | pub fn watchdog_remaining() -> i64 { | |
1fde4167 SR |
43 | if INHIBITORS.load(Ordering::Acquire) > 0 { |
44 | TIMEOUT | |
45 | } else { | |
46 | TIMEOUT - (epoch_i64() - TRIGGERED.load(Ordering::Acquire)) | |
47 | } | |
48 | } | |
49 | ||
50 | /// Returns an object that inhibts watchdog expiry for its lifetime, it will issue a ping on Drop | |
51 | pub fn watchdog_inhibit() -> WatchdogInhibitor { | |
52 | let prev = INHIBITORS.fetch_add(1, Ordering::AcqRel); | |
53 | log::info!("Inhibit added: {}", prev + 1); | |
54 | WatchdogInhibitor {} | |
55 | } | |
56 | ||
57 | impl Drop for WatchdogInhibitor { | |
58 | fn drop(&mut self) { | |
59 | watchdog_ping(); | |
60 | let prev = INHIBITORS.fetch_sub(1, Ordering::AcqRel); | |
61 | log::info!("Inhibit dropped: {}", prev - 1); | |
62 | } | |
a26ebad5 | 63 | } |