summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_sema_service.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/gsp_sema_service.c')
-rw-r--r--kernel/gsp_sema_service.c87
1 files changed, 49 insertions, 38 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 9d116ad..a04a3c2 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -2667,45 +2667,28 @@ static void svc_apply_pending(struct nv_vgpu_device *vgpu)
static u32 svc_apply_page_data(struct nv_vgpu_device *vgpu, const u8 *buf,
u64 pa_page)
{
- u32 off, applied = 0;
- bool any = false;
- unsigned long flags;
- int ci;
-
/*
- * No live channel: no client can be waiting on a release, so a
- * "release" decoded from an arbitrary swept page can only be a false
- * positive, and its write lands through whatever translation the VA
- * happens to have (observed: 2 applied writes while the guest kernel
- * was booting corrupted a task's CPU field and panicked the guest
- * scheduler). Only apply swept-page releases while a client exists;
- * real releases are carried by the channels' readable pushes then.
+ * DISABLED: releases decoded from swept pages are false positives that
+ * write through whatever translation the VA happens to have and corrupt
+ * live guest memory. Two confirmed incidents: during guest boot (a
+ * task's CPU field, guest scheduler panic) and while channels were
+ * valid (PAGE_FLAGS_CHECK_AT_FREE / bad rss-counter, counter-page
+ * slots polluted with payloads like 0x10000). Real releases are
+ * applied only from pushes the pump reads through a channel's GPFIFO
+ * translation, with svc_fake_release / svc_counter_release_apply as
+ * the channel-anchored fallbacks. This function stays as the single
+ * place that would re-enable page-content heuristics.
*/
- spin_lock_irqsave(&svc.chan_lock, flags);
- for (ci = 0; ci < SVC_MAX_CHANNELS; ci++) {
- if (svc.chan[ci].valid) {
- any = true;
- break;
- }
- }
- spin_unlock_irqrestore(&svc.chan_lock, flags);
- if (!any)
- return 0;
+ (void)vgpu;
+ (void)buf;
+ (void)pa_page;
+ return 0;
+}
- /*
- * Decoded execution: walk the page as a method stream and perform the
- * pushed work (PTE memsets, semaphore releases) for pushes that are
- * still pending.
- *
- * This page was reached by sweeping raw guest RAM, so the data is
- * arbitrary: only the bounded semaphore-release writes below may be
- * attempted. Executing fills/copies decoded from a swept page is what
- * made the sweep corrupt live guest kernel memory (65M pages scanned,
- * fabricated "pushes" executing memsets); work execution is limited
- * to pushes the pump read through a trusted ring translation.
- */
- svc_decode_stream(vgpu, buf, SEMA_PAGE_SIZE, pa_page, false, 0, 0, 0,
- false);
+static u32 __maybe_unused __svc_apply_page_data_disabled(struct nv_vgpu_device *vgpu,
+ const u8 *buf, u64 pa_page)
+{
+ u32 off, applied = 0;
for (off = 0; off + 16 <= SEMA_PAGE_SIZE; off += 4) {
u32 hdr, hi, lo, payload;
@@ -4682,6 +4665,8 @@ static int svc_thread(void *arg)
pr_info("sema-svc: thread started\n");
while (!kthread_should_stop() && !svc.stop) {
+ bool pumped = false;
+
vgpu = NULL;
mutex_lock(&nv_vgpu_driver.lock);
{
@@ -4718,8 +4703,13 @@ static int svc_thread(void *arg)
* time it takes the fallback scan to find the push. A doorbell
* token means a channel was just scheduled; run everything now.
*/
- svc.doorbell_pending = false;
- svc_pump_channels(vgpu);
+ {
+ u64 done_before = svc.gpfifo_entries_done;
+
+ svc.doorbell_pending = false;
+ svc_pump_channels(vgpu);
+ pumped = (svc.gpfifo_entries_done != done_before);
+ }
/*
* Releases whose target VA was not translatable when the scan
@@ -4737,6 +4727,18 @@ static int svc_thread(void *arg)
svc_apply_sweep_slice(vgpu);
/*
+ * While the pump is making progress the client is streaming
+ * pushes and waiting on their releases: loop tightly and skip
+ * the discovery/sweep passes, which otherwise dominate the pass
+ * period (the pump cadence is what the client's context init
+ * deadline sees). Scans resume the first pass without progress.
+ */
+ if (pumped) {
+ msleep(1);
+ continue;
+ }
+
+ /*
* Push-buffer base discovery: a chunked walk of guest RAM
* finds the pages whose first push names a channel, so a
* channel that appears with work already waiting is pinned and
@@ -4798,6 +4800,15 @@ void gsp_sema_service_doorbell(u32 token)
svc.doorbell_count++;
svc.doorbell_pending = true;
+ /*
+ * Wake the service thread: a doorbell means a channel just became
+ * runnable, and the loop's rolling scans can otherwise delay the pump
+ * by the whole pass period. This is called from the VFIO write path
+ * (atomic context), where wake_up_process is allowed.
+ */
+ if (svc.task)
+ wake_up_process(svc.task);
+
if (svc.doorbell_log < 64) {
pr_info("sema-svc: doorbell token=0x%x runlist=%u vector=%u (count=%llu)\n",
token, (token >> 16) & 0x7f, token & 0xfff,