summaryrefslogtreecommitdiffstats
path: root/tools/guest-diag/semfix_watch.py
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-29 13:19:25 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-29 13:19:25 -0400
commit7d2ea450bae8e2de2255b8d592de647ea4490507 (patch)
treee08433bfe74d0298d9399c97a2541f5c3c0890c2 /tools/guest-diag/semfix_watch.py
parent3031f72e6408a894c05d3cf1679e4bb7d074d989 (diff)
downloadopen-iov-7d2ea450bae8e2de2255b8d592de647ea4490507.tar.gz
open-iov-7d2ea450bae8e2de2255b8d592de647ea4490507.zip
guest-diag: per-page pushbuffer translation, per-client re-pin
Diffstat (limited to 'tools/guest-diag/semfix_watch.py')
-rw-r--r--tools/guest-diag/semfix_watch.py70
1 files changed, 40 insertions, 30 deletions
diff --git a/tools/guest-diag/semfix_watch.py b/tools/guest-diag/semfix_watch.py
index 8fd534d..c0ce072 100644
--- a/tools/guest-diag/semfix_watch.py
+++ b/tools/guest-diag/semfix_watch.py
@@ -197,16 +197,22 @@ def resolve_pushbuffer(q, sem):
def pin_pushbuffer(q, gpu_vas, cpu, gpa):
+ """Pin the whole pushbuffer with *per-page* translations (the layout is
+ not linear across the allocation: page 32 jumped on a real client)."""
pinned = 0
for gv in gpu_vas:
+ miss = 0
for i in range(PUSHBUF_MAX_PAGES):
- if i in (0, 1, 2, 3, 8, 32, 128, 512):
- g = q.gva2gpa(cpu + i * 0x1000)
- if g != gpa - i * 0x1000:
- print("semfix: pushbuf va=0x%x: page %d not linear (gpa=%s), stop at %d"
- % (gv, i, hex(g) if g else None, pinned), flush=True)
+ g = q.gva2gpa(cpu + i * 0x1000)
+ if not g:
+ miss += 1
+ if miss >= 32:
+ print("semfix: pushbuf va=0x%x: 32 unmapped pages at %d, stop (%d pinned)"
+ % (gv, i, pinned), flush=True)
return pinned
- if not pin(gv + i * 0x1000, gpa - i * 0x1000):
+ continue
+ miss = 0
+ if not pin(gv + i * 0x1000, g):
print("semfix: pushbuf va=0x%x: pin failed at page %d" % (gv, i), flush=True)
return pinned
pinned += 1
@@ -220,22 +226,28 @@ def main():
q = Qmp(QMP_SOCK)
seen = set()
seen_pb = set()
- pb_done = False
+ pinned_ranges = set()
+
+ def pin_range_once(gpu_vas, cpu, gpa):
+ key = tuple(gpu_vas), cpu
+ if key in pinned_ranges:
+ return
+ pinned_ranges.add(key)
+ pin_pushbuffer(q, gpu_vas, cpu, gpa)
+
print("semfix: watching (interval %.1fs)" % interval, flush=True)
while True:
sems, pbs = guest_trace()
- if not pb_done:
- for pb in pbs - seen_pb:
- seen_pb.add(pb)
- try:
- gpu_vas, cpu, gpa = resolve_pb_ptr(q, pb)
- except Exception as e:
- print("semfix: pb=0x%x resolve failed: %s" % (pb, e), flush=True)
- continue
- if gpu_vas:
- pin_pushbuffer(q, gpu_vas, cpu, gpa)
- pb_done = True
- break
+ for pb in pbs - seen_pb:
+ seen_pb.add(pb)
+ try:
+ gpu_vas, cpu, gpa = resolve_pb_ptr(q, pb)
+ except Exception as e:
+ print("semfix: pb=0x%x resolve failed: %s" % (pb, e), flush=True)
+ continue
+ if gpu_vas:
+ pin_range_once(gpu_vas, cpu, gpa)
+ else:
print("semfix: pb=0x%x no pushbuffer rm_mem (retry)" % pb, flush=True)
for sem in sems - seen:
try:
@@ -251,17 +263,15 @@ def main():
ok = pin(gv, gpa)
print("semfix: sem=0x%x va=0x%x -> gpa=0x%x pin=%s"
% (sem, gv, gpa, "ok" if ok else "FAILED"), flush=True)
- if not pb_done:
- try:
- gpu_vas, cpu, gpa = resolve_pushbuffer(q, sem)
- except Exception as e:
- print("semfix: pushbuf resolve failed: %s" % e, flush=True)
- gpu_vas = []
- if gpu_vas:
- pin_pushbuffer(q, gpu_vas, cpu, gpa)
- pb_done = True
- else:
- print("semfix: pushbuf not found near sem=0x%x (retry)" % sem, flush=True)
+ try:
+ gpu_vas, cpu, gpa = resolve_pushbuffer(q, sem)
+ except Exception as e:
+ print("semfix: pushbuf resolve failed: %s" % e, flush=True)
+ gpu_vas = []
+ if gpu_vas:
+ pin_range_once(gpu_vas, cpu, gpa)
+ else:
+ print("semfix: pushbuf not found near sem=0x%x (retry)" % sem, flush=True)
time.sleep(interval)