From 52b2c7c109ee3018853f0703de80d9bf039f7e6e Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Sun, 11 Oct 2026 21:17:55 -0400 Subject: guest-diag: scanner EOF guard + exclude non-client nvidia fd holders Two failure modes found when the scanner detects clients by device fd: a transient boot nvidia-smi was picked and its exited pagemap read back EOF, and scan_window advanced by got=0 forever (busy spin, no stream); and non-client nvidia fd holders must never be committed to. Break on got<=0 in scan_window (scan_range already did), skip nvidia-smi/ persistenced/Xorg, and prefer /dev/nvidia-uvm holders. --- tools/guest-diag/guest_pin_stream.py | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'tools') diff --git a/tools/guest-diag/guest_pin_stream.py b/tools/guest-diag/guest_pin_stream.py index 29ef114..04aba73 100644 --- a/tools/guest-diag/guest_pin_stream.py +++ b/tools/guest-diag/guest_pin_stream.py @@ -659,6 +659,10 @@ def nvidia_fds(pid): def cdt_pid(): prefixes = tuple(p for p in os.environ.get("CLIENT_PREFIXES", "cdt,va,victory").split(",") if p) + # Processes that hold a /dev/nvidia* fd but are not CUDA clients; the + # scanner must never commit to them (a transient nvidia-smi at boot was + # picked once and its exited pagemap read back EOF forever). + non_clients = ("nvidia-smi", "nvidia-persistenced", "Xorg", "X") best = None uvm = None gpu = None @@ -679,6 +683,8 @@ def cdt_pid(): if any(name.startswith(p) for p in prefixes): best = int(d) continue + if any(name.startswith(p) for p in non_clients): + continue # Arbitrary CUDA binaries (any comm) are clients too: match by # the CUDA device they hold open so streaming never depends on # the binary's name. Prefer a UVM holder (compute client) over a @@ -710,6 +716,11 @@ def scan_window(fd, lo, hi, span, out): os.lseek(fd, (va // 4096) * 8, 0) data = os.read(fd, n * 8) got = len(data) // 8 + # EOF: the process's address space (or the pagemap of an exited + # pid) does not reach this VA. Without this the loop reads the + # same offset forever (got == 0 -> va never advances). + if got <= 0: + break for i in range(got): e = int.from_bytes(data[i * 8:i * 8 + 8], 'little') if not ((e >> 63) & 1): -- cgit v1.2.3