diff options
| -rw-r--r-- | kernel/gsp_sema_service.c | 18 |
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; } /* |
