diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-23 16:13:24 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-23 16:13:24 -0400 |
| commit | cc60d6dcce1c6ee956c43a5c6d2bb639660ac5ec (patch) | |
| tree | fac215f80806780fb9a5c46ec7b777fc48c6667d | |
| parent | 4094a7ea7e8ed92f323e856fcac3717df0f4b401 (diff) | |
| download | open-iov-cc60d6dcce1c6ee956c43a5c6d2bb639660ac5ec.tar.gz open-iov-cc60d6dcce1c6ee956c43a5c6d2bb639660ac5ec.zip | |
vgsp-sema r561: bound the pin-injection drain per service pass (starved ring walk)
r559 soak2 evidence (victory_saxpy, 167 s at 100% CPU, module alive and
printing stats but consuming no GPFIFO entries): the guest pin stream
flooded the injection queue (svc_handle_map_add: 1867-6101 callbacks
suppressed per burst, several bursts per 10 s) and the unbounded for(;;)
drain spent every service pass processing injections, so the ring walk
never ran - work_guard counters froze (deferred=513 applied=50 unchanged
for minutes) and the client spun.
Process at most 64 queued requests per svc_handle_map_add() call. The
drain runs again on every service pass and from svc_gr_request/
svc_run_ops, so nothing is lost; under a flood the ring walk now gets its
cycles every pass. Bounded batches are the same fairness rule the ring
walk itself already uses.
| -rw-r--r-- | kernel/gsp_sema_service.c | 15 |
1 files changed, 15 insertions, 0 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index d3a7e31..127f995 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -24492,17 +24492,32 @@ static bool svc_va_hits_chan_ring(u64 va) return hit; } +/* + * r561: the drain is BOUNDED per call. r559 soak evidence (victory_saxpy, + * 167 s at 100% CPU, pump alive but consuming nothing): the guest pin + * stream flooded the injection queue (svc_handle_map_add: 1867-6101 + * callbacks suppressed per burst) and the old unbounded for(;;) drain + * spent every service pass processing injections - the ring walk never + * ran, no GPFIFO entry was consumed, and the client spun. The queue is + * drained again on every pass (and from svc_gr_request / svc_run_ops), so + * a bounded batch loses nothing; it just guarantees the ring walk gets + * its cycles under an injection flood. + */ +#define SVC_MAP_ADD_BATCH 64u static void svc_handle_map_add(void) { unsigned long flags; bool rewound = false; u32 i; + u32 batch = 0; for (;;) { struct svc_map_add_req req; u32 ap; u64 off; + if (batch++ >= SVC_MAP_ADD_BATCH) + break; spin_lock_irqsave(&svc_map_add_lock, flags); if (svc_map_add_tail == svc_map_add_head) { spin_unlock_irqrestore(&svc_map_add_lock, flags); |
