fix(cgroup): stop swallowing inotify read errors in the memory monitor
wait_and_drain treated every read() <= 0 as "queue drained", so a real error (bad fd, EINVAL) silently ended the drain and the monitor kept polling a broken fd. Distinguish the cases: EAGAIN ends the drain, EINTR retries, and any other error propagates. monitor_loop logs the error before exiting so a dead memory monitor is visible in the session log.
This commit is contained in:
@@ -127,8 +127,8 @@ mod linux {
|
|||||||
|
|
||||||
async fn wait_and_drain(&self) -> std::io::Result<()> {
|
async fn wait_and_drain(&self) -> std::io::Result<()> {
|
||||||
let mut guard = self.fd.readable().await?;
|
let mut guard = self.fd.readable().await?;
|
||||||
// Drain all pending inotify events; the fd is non-blocking, so the
|
// Drain all pending inotify events so the next readiness wakeup
|
||||||
// read returns <= 0 once the queue is empty.
|
// corresponds to a fresh modification.
|
||||||
let mut buf = [0u8; 4096];
|
let mut buf = [0u8; 4096];
|
||||||
loop {
|
loop {
|
||||||
// SAFETY: writing at most `buf.len()` bytes into `buf`, through
|
// SAFETY: writing at most `buf.len()` bytes into `buf`, through
|
||||||
@@ -143,7 +143,16 @@ mod linux {
|
|||||||
if n > 0 {
|
if n > 0 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
if n == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let err = std::io::Error::last_os_error();
|
||||||
|
match err.kind() {
|
||||||
|
// The fd is non-blocking: the queue is empty.
|
||||||
|
std::io::ErrorKind::WouldBlock => break,
|
||||||
|
std::io::ErrorKind::Interrupted => continue,
|
||||||
|
_ => return Err(err),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
guard.clear_ready();
|
guard.clear_ready();
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -304,7 +313,10 @@ mod linux {
|
|||||||
let mut last_high_count = Self::read_high_counter(&events_path).await.unwrap_or(0);
|
let mut last_high_count = Self::read_high_counter(&events_path).await.unwrap_or(0);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if inotify.wait_and_drain().await.is_err() {
|
if let Err(e) = inotify.wait_and_drain().await {
|
||||||
|
tracing::warn!(
|
||||||
|
"memory.events inotify read failed; stopping memory monitor: {e}"
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user