summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/gsp_sema_service.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 1b77ea0..7f61c57 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -1068,6 +1068,7 @@ struct svc_scrub {
u32 put_last;
u64 submitted; /* blocks submitted since seeding */
u64 authored; /* last authored finish value */
+ u32 authored_gen; /* pa_gen at the last authored write */
u32 pa_gen; /* scanner registration generation (logged) */
u32 session_gen; /* m176: session generation of the last registration */
u32 log_budget;
@@ -45344,8 +45345,17 @@ static void svc_scrub_pass(struct nv_vgpu_device *vgpu)
u64 pa = 0;
int ap = SVC_APERTURE_SYS;
- if (svc_lookup(vgpu, hva, &pa, &ap) || !pa) {
- if (svc_walk_vaspaces(vgpu, hva, &pa, &ap) || !pa)
+ /*
+ * r1667: resolve through the GPU page tables FIRST. The learned
+ * VA->PA pair map can name a stale page for a reused VA (the guest
+ * polls its scrubber finish word through the kernel VAS h=0xc,
+ * which the walk resolves correctly, while svc_lookup returned an
+ * old page from a previous allocation and the scrub wait never
+ * completed). Fall back to the pair map only when no walkable VAS
+ * maps the VA.
+ */
+ if (svc_walk_vaspaces(vgpu, hva, &pa, &ap) || !pa) {
+ if (svc_lookup(vgpu, hva, &pa, &ap) || !pa)
pa = 0;
}
/* The scrub words are guest RAM; an FB translation is not. */
@@ -45412,7 +45422,8 @@ static void svc_scrub_pass(struct nv_vgpu_device *vgpu)
delta = s->entries; /* exact wrap */
s->submitted += delta;
s->put_last = put;
- } else if (s->submitted == s->authored) {
+ } else if (s->submitted == s->authored &&
+ s->authored_gen == s->pa_gen) {
return; /* nothing new; no guest writes */
}
@@ -45438,6 +45449,7 @@ static void svc_scrub_pass(struct nv_vgpu_device *vgpu)
sizeof(fin));
}
s->authored = s->submitted;
+ s->authored_gen = s->pa_gen;
}
/*