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