From 509552725f2e8b871c2a472f8ff56d25a70436eb Mon Sep 17 00:00:00 2001 From: vasilito Date: Mon, 27 Jul 2026 21:56:37 +0900 Subject: [PATCH] driver-manager: crash-aware reap + error_channel fd cleanup (N18 Q2+Bug4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Splits `reap_pid` into the `reap_pid_inner(crashed: bool)` private helper plus two public entry points: - `reap_pid(pid)` — crash path. Calls `crash_tracker().record_failure` after the maps are cleared, which advances the auto-blacklist counter. - `reap_pid_clean(pid)` — clean exit path. Calls `crash_tracker().record_success` so the device's backoff is reset; a future crash starts the count from 1, not from where the previous clean-exit backoff ended. Both paths also call `error_channel::global().remove(&key)` to close the sidecar UnixStream fd (Bug4: each crash previously leaked one fd; ~1024 crashes exhausted the manager's fd table). This is the kernel of N18-Q2+Bug4; the call-site change in `main.rs` that interprets the waitpid status was committed in the prior Q1+Q2+S3 commit. --- .../driver-manager/source/src/config.rs | 56 +++++++++++++------ 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/local/recipes/system/driver-manager/source/src/config.rs b/local/recipes/system/driver-manager/source/src/config.rs index ea5c5b7676..b2f9f59066 100644 --- a/local/recipes/system/driver-manager/source/src/config.rs +++ b/local/recipes/system/driver-manager/source/src/config.rs @@ -1259,16 +1259,25 @@ impl DriverConfig { Ok(configs) } - /// Remove a dead-pid entry from both `spawned` and `pid_to_device` - /// maps. Called by the SIGCHLD reaper when a spawned child has - /// been observed as exited. Idempotent — a no-op if the pid is not - /// present. - /// - /// F1 integration: every reap is treated as a spawn failure for - /// crash-tracking purposes. If the failure count crosses the - /// threshold, emit a WARN with the BDF + last exit so operators - /// can correlate with kernel/daemon logs. + /// Reap a child known to have exited via crash (non-zero exit code, + /// or a signal other than SIGTERM/SIGINT). Removes the device from + /// the spawned/pid_to_device maps, closes the error_channel fd, and + /// advances the CrashTracker. After `threshold` consecutive crashes + /// the device is auto-blacklisted. pub fn reap_pid(&self, pid: u32) { + self.reap_pid_inner(pid, /*crashed=*/ true); + } + + /// Reap a child known to have exited cleanly (exit code 0, or + /// SIGTERM/SIGINT from our own `remove()`). Removes the device from + /// the maps and closes the error_channel fd, but does NOT advance + /// the crash tracker — this prevents the 5-consecutive-exits + /// autoblacklist from triggering on intentional driver reloads. + pub fn reap_pid_clean(&self, pid: u32) { + self.reap_pid_inner(pid, /*crashed=*/ false); + } + + fn reap_pid_inner(&self, pid: u32, crashed: bool) { let device_key = if let Ok(mut p2d) = self.pid_to_device.lock() { if let Some(key) = p2d.remove(&pid) { if let Ok(mut spawned) = self.spawned.lock() { @@ -1282,15 +1291,26 @@ impl DriverConfig { None }; if let Some(key) = device_key { - if let Some(count) = crash_tracker().record_failure(&key) { - log::warn!( - "crash-threshold: driver={} device={} consecutive_failures={} \ - auto-blacklisted (override via /etc/driver-manager.d/disable-.toml \ - or REDBEAR_DRIVER_CRASH_THRESHOLD override)", - self.name, - key, - count - ); + // N18 Bug4: close the error_channel fd on every reap path so + // a crashed or cleanly-exited daemon doesn't leak a UnixStream + // until process exit. + crate::error_channel::global().remove(&key); + if crashed { + if let Some(count) = crash_tracker().record_failure(&key) { + log::warn!( + "crash-threshold: driver={} device={} consecutive_failures={} \ + auto-blacklisted (override via /etc/driver-manager.d/disable-.toml \ + or REDBEAR_DRIVER_CRASH_THRESHOLD override)", + self.name, + key, + count + ); + } + } else { + // Clean exit: clear any backoff the device was in so a + // later crash starts the count from 1, not from where the + // previous clean-exit backoff ended. + crash_tracker().record_success(&key); } } }