diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-15 10:44:19 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-15 10:44:19 -0400 |
| commit | 02249afd91f4ee02589a07657d130b9b9411debd (patch) | |
| tree | de9cc2d6c23e78593fe1fbbab4c831e420ae59ab | |
| parent | 5a446c10c3ffa9180328180318163b46cb00a16d (diff) | |
| download | open-iov-02249afd91f4ee02589a07657d130b9b9411debd.tar.gz open-iov-02249afd91f4ee02589a07657d130b9b9411debd.zip | |
vgsp-gr: m153 retry only on zero writes (drop wrong-place heuristic)
Live r153 evidence: the highest-reloc data entry (bi=204) is a
UVM-internal buffer that correct launches never write, so the
'top operand untouched' condition fired on correct executions and
re-executed them up to 3x - a correctness hazard for side-effecting
kernels (atomics/printf) and pure waste otherwise. The honest execution
witness is the retirement wait's changed count; only zero-writes retries
now (safe by construction: a kernel that wrote nothing has nothing to
duplicate). Read-only kernels pay the bounded extra polls.
| -rw-r--r-- | kernel/gsp_phys_booter.c | 73 |
1 files changed, 18 insertions, 55 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c index 9c19efb..123f93d 100644 --- a/kernel/gsp_phys_booter.c +++ b/kernel/gsp_phys_booter.c @@ -18351,72 +18351,35 @@ gr_page_unmapped: * gsp_phys_gr_output_retire_wait(). * * m153: outcome-verifying retry. The intermittent per-boot - * mis-execution classes (engine wrote nothing at all; or it wrote - * into a lower operand window while the highest - output - operand - * stayed untouched) both complete with qmd_rel/ch_rel satisfied, so - * they cannot be caught by the completion poll. The retirement wait - * is the only execution witness. When it saw zero writes, or writes - * that skipped the highest-reloc operand (n_data >= 2), refill the - * bounce window from the guest inputs, re-publish the same method - * block on a fresh ring entry, re-issue the schedule and re-poll, - * then re-wait - bounded by the same attempt budget as the timeout - * path. After the budget the launch proceeds to copy-out with - * whatever the engine produced (a genuinely read-only kernel is - * indistinguishable here and simply pays the bounded extra polls). + * no-execution class (qmd_rel/ch_rel satisfied but the engine wrote + * nothing at all) cannot be caught by the completion poll; the + * retirement wait is the only execution witness. On zero writes, + * refill the bounce window from the guest inputs, re-publish the + * same method block on a fresh ring entry, re-issue the schedule and + * re-poll, then re-wait - bounded by the same attempt budget as the + * timeout path. After the budget the launch proceeds to copy-out + * with whatever the engine produced: a genuinely read-only kernel is + * indistinguishable from a no-execution here and simply pays the + * bounded extra polls (safe to re-execute by construction - a kernel + * that writes nothing has no side effects to duplicate). A + * wrong-place write detector was tried and removed: the highest-reloc + * data entry is often a UVM-internal buffer, not the output, so it + * false-fired on correct launches and would re-execute + * side-effecting kernels (atomics) up to 3x. */ if (req->n_data && boot_stage.rmcall_gr_bounce.pages) { u32 wrote = gsp_phys_gr_output_retire_wait(req, bounce_csum_in); if (gsp_phys_rmcall_gr_nowrite_retry_value()) { - u64 top_reloc = 0; - u32 top_bi = 0xffffffffu, di2; - - for (di2 = 0; di2 < req->n_data; di2++) { - u64 rv = req->data[di2].reloc_va; - u32 bi2; - - if (!rv || rv <= top_reloc) - continue; - bi2 = (u32)((rv - - GSP_PHYS_RMCALL_GR_BOUNCE_VA0) >> - 12); - if (bi2 >= GSP_PHYS_RMCALL_GR_MAIL_SLOT) - continue; - top_reloc = rv; - top_bi = bi2; - } while (attempts < GSP_PHYS_RMCALL_GR_ATTEMPTS) { - bool top_changed = false; - - if (top_bi != 0xffffffffu) { - const u8 *tp = - gsp_phys_chunk_page_va( - &boot_stage - .rmcall_gr_bounce, - top_bi); - - if (tp) { - u32 ti, tc = 0; - - for (ti = 0; - ti < GSP_PHYS_PAGE_SIZE; - ti += 4) - tc += get_unaligned_le32( - tp + ti); - top_changed = - (tc != - bounce_csum_in[top_bi]); - } - } - if (wrote > 0 && - (req->n_data < 2 || top_changed)) + if (wrote > 0) break; attempts++; if (attempts > GSP_PHYS_RMCALL_GR_ATTEMPTS) break; - pr_info("vgsp-gr: outcome retry %u/%u (wrote=%u top_bi=%u top_changed=%u): refill + re-publish\n", + pr_info("vgsp-gr: outcome retry %u/%u (wrote=%u): refill + re-publish\n", attempts, GSP_PHYS_RMCALL_GR_ATTEMPTS, - wrote, top_bi, top_changed); + wrote); gsp_phys_gr_fill_bounce(req, bounce_csum_in); mutex_lock(&gsp_phys_rm_lock); ret = gsp_phys_rmcall_publish_locked( |
