From a83a42df71c235c5f9f8eaeb3b62053a75fe30c7 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Tue, 29 Sep 2026 14:41:14 -0400 Subject: kernel: grace window for untranslatable GR entries; tools: coalesce window pin output The first GR window pin landed ~2 s after the pump consumed the freshly created channels' GPFIFO entries on the first failed read, so the pushes (and the tracking-semaphore releases they carry) were lost. GR entries with an unresolvable push page now stay pending for sema_gr_grace_ms (default 8 s) before the stale-entry consume; a pin landing in that window makes the entry readable and it executes normally. The completion counter is still published from put at the end of every pass, so the client's counter wait is not delayed. guest_pmap_win.py coalesces contiguous VA+PA pages into run lines, so a 15k-page window transfers as ~200 lines instead of ~15k and the pin batch lands within a second of the pages appearing. --- tools/guest-diag/guest_pmap_win.py | 38 +++++++++++++++++++++++++++++++------- tools/guest-diag/pin_gr_window.py | 13 +++++++++---- 2 files changed, 40 insertions(+), 11 deletions(-) (limited to 'tools') diff --git a/tools/guest-diag/guest_pmap_win.py b/tools/guest-diag/guest_pmap_win.py index a9b74a7..f6ca85c 100644 --- a/tools/guest-diag/guest_pmap_win.py +++ b/tools/guest-diag/guest_pmap_win.py @@ -4,8 +4,9 @@ # pread) so a 256 MB window takes about a second, not minutes. # # Usage: sudo python3 guest_pmap_win.py [max-pairs] [pa-max-hex] -# Output: one "0x,0x" line per present page (ascending VA), capped at -# max-pairs. PAs of 0 are skipped; pages above pa-max are skipped unless 0. +# Output: one "0x,0x," line per contiguous run (ascending VA), +# capped at max-pairs pages. PAs of 0 are skipped; pages at/above pa-max are +# skipped unless pa-max is 0. import os import sys @@ -17,6 +18,16 @@ pa_max = int(sys.argv[5], 16) if len(sys.argv) > 5 else 0 BATCH = 512 out = [] +run_va = run_pa = None +run_n = 0 +pairs = 0 + + +def flush(): + if run_n: + out.append('0x%x,0x%x,%d' % (run_va, run_pa, run_n)) + + fd = os.open('/proc/%d/pagemap' % pid, os.O_RDONLY) try: va = lo @@ -29,19 +40,32 @@ try: got = len(data) // 8 for i in range(got): e = int.from_bytes(data[i * 8:i * 8 + 8], 'little') + page_va = va + i * 0x1000 if not ((e >> 63) & 1): + flush() + run_va = run_pa = None + run_n = 0 continue pfn = e & ((1 << 55) - 1) pa = pfn << 12 - if not pa: - continue - if pa_max and pa >= pa_max: + if not pa or (pa_max and pa >= pa_max): + flush() + run_va = run_pa = None + run_n = 0 continue - out.append('0x%x,0x%x' % (va + i * 0x1000, pa)) - if len(out) >= maxp: + if (run_va is not None and page_va == run_va + run_n * 0x1000 + and pa == run_pa + run_n * 0x1000): + run_n += 1 + else: + flush() + run_va, run_pa, run_n = page_va, pa, 1 + pairs += 1 + if pairs >= maxp: + flush() print('\n'.join(out)) sys.exit(0) va += got * 0x1000 finally: os.close(fd) +flush() print('\n'.join(out)) diff --git a/tools/guest-diag/pin_gr_window.py b/tools/guest-diag/pin_gr_window.py index 4a968c9..26083f7 100644 --- a/tools/guest-diag/pin_gr_window.py +++ b/tools/guest-diag/pin_gr_window.py @@ -77,9 +77,14 @@ def scan(pid): % (pid, LO, HI, MAXP, PAMAX), 90) pairs = [] for line in out.splitlines(): - m = re.match(r"^(0x[0-9a-f]+),(0x[0-9a-f]+)$", line.strip()) - if m: - pairs.append((int(m.group(1), 16), int(m.group(2), 16))) + m = re.match(r"^(0x[0-9a-f]+),(0x[0-9a-f]+)(?:,(\d+))?$", line.strip()) + if not m: + continue + va = int(m.group(1), 16) + pa = int(m.group(2), 16) + n = int(m.group(3)) if m.group(3) else 1 + for i in range(n): + pairs.append((va + i * 0x1000, pa + i * 0x1000)) return pairs @@ -125,7 +130,7 @@ def probe(va): def main(): - interval = float(sys.argv[1]) if len(sys.argv) > 1 else 2.0 + interval = float(sys.argv[1]) if len(sys.argv) > 1 else 1.0 if not push_helper(): log("FATAL: could not push guest helper") return 1 -- cgit v1.2.3