summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-29 16:20:42 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-29 16:20:42 -0400
commit09a729ac2a8c6f1865d5ef3bfd2b4df55d43764a (patch)
tree27f2abde9511a73f73239a87359f714da4fa4fab /kernel
parent6b445171b4c50ed74f19272f5bff7c0f42887e6d (diff)
downloadopen-iov-09a729ac2a8c6f1865d5ef3bfd2b4df55d43764a.tar.gz
open-iov-09a729ac2a8c6f1865d5ef3bfd2b4df55d43764a.zip
sema-svc: never consume a CE entry whose release was not delivered
The fake-release fallback acknowledged unreadable CE pushes even when the tracking-semaphore pool page had no translation yet, so the GPFIFO entry was consumed without writing the semaphore the client waits on (observed: client stuck in UVM_GPU_REGISTER while CE channel 2's release never landed, its push-buffer pin arriving ~2 s later). - svc_fake_release now reports failure when the pool page cannot be translated/read/written instead of pretending success. - CE channels with the fallback enabled leave the entry pending (no multi-second RAM rescue) until the pool pin lands; the skip path only consumes an entry when the release was actually delivered.
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_sema_service.c69
1 files changed, 59 insertions, 10 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 5bff6ca..21f0de0 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -3990,13 +3990,24 @@ static bool svc_fake_release(struct nv_vgpu_device *vgpu, struct svc_channel *ch
pool_va = ch->last_rel_va ? ch->last_rel_va :
0x121000000ULL + 4ULL * ch->ce_index;
- if (!svc_lookup_trusted(vgpu, pool_va, &spa, &sap) &&
- !svc_read_ap(vgpu, spa, sap, &scur, sizeof(scur)) &&
- scur < ch->expected_sem_payload) {
+ /*
+ * The release can only be delivered when the pool page translates.
+ * A missing translation is transient (the client's pool page is pinned
+ * a moment after the channel appears), so report failure and let the
+ * caller keep the GPFIFO entry pending: consuming it without writing
+ * the semaphore leaves the client waiting forever.
+ */
+ if (svc_lookup_trusted(vgpu, pool_va, &spa, &sap))
+ return false;
+ if (svc_read_ap(vgpu, spa, sap, &scur, sizeof(scur)))
+ return false;
+
+ if (scur < ch->expected_sem_payload) {
u32 nv = ch->expected_sem_payload;
- if (!svc_write_ap(vgpu, spa, sap, &nv, sizeof(nv)))
- svc.releases_applied++;
+ if (svc_write_ap(vgpu, spa, sap, &nv, sizeof(nv)))
+ return false;
+ svc.releases_applied++;
}
svc.releases_faked++;
ch->expected_sem_payload++;
@@ -4212,8 +4223,8 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
* progress waits expire. Acknowledge
* the release and move on.
*/
- if (gsp_sema_fake_rel &&
- svc_fake_release(vgpu, ch)) {
+if (gsp_sema_fake_rel &&
+ svc_fake_release(vgpu, ch)) {
ch->last_get = (idx + 1) %
ch->gpfifo_entries;
svc.gpfifo_skipped++;
@@ -4221,6 +4232,29 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
kfree(pb);
continue;
}
+ if (gsp_sema_fake_rel &&
+ ch->engine_type) {
+ /*
+ * CE channel and the
+ * pool page is not
+ * translated yet: the
+ * pin lands a moment
+ * later, so keep the
+ * entry pending
+ * instead of burning a
+ * multi-second RAM
+ * rescue. Consuming it
+ * now would drop the
+ * release the client
+ * waits on.
+ */
+ if (!ch->defer_since)
+ ch->defer_since =
+ jiffies;
+ svc.gpfifo_nomap++;
+ kfree(pb);
+ break;
+ }
if (svc.false_trans && svc.false_trans < 8)
pr_info("sema-svc: false translation for push va=0x%llx (h=0x%x len=%u) - rescuing\n",
va, ch->h_object, len);
@@ -4305,11 +4339,26 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
pr_info("sema-chan: skipping stale entry h=0x%x va=0x%llx len=%u after %u failed rescues\n",
ch->h_object, va, len,
ch->rescue_fail);
+ if (gsp_sema_fake_rel &&
+ !svc_fake_release(vgpu, ch)) {
+ /*
+ * The release could not be
+ * delivered (pool page not
+ * translated yet): keep the
+ * entry pending so a pin that
+ * lands shortly still applies
+ * it instead of silently
+ * dropping the client's wait.
+ */
+ if (!ch->defer_since)
+ ch->defer_since =
+ jiffies;
+ svc.gpfifo_nomap++;
+ kfree(pb);
+ break;
+ }
ch->rescue_fail = 0;
ch->defer_since = 0;
- if (gsp_sema_fake_rel)
- svc_fake_release(vgpu,
- ch);
ch->last_get = (idx + 1) %
ch->gpfifo_entries;
svc.gpfifo_skipped++;