riscv: Fix pmap_kextract racing with concurrent superpage promotion/demotion

This repeats amd64's cfcbf8c6fd (r180498) and i386's cf3508519c
(r202894) but for riscv; pmap_kextract must be lock-free and so it can
race with superpage promotion and demotion, thus the L2 entry must only
be loaded once to avoid using inconsistent state.

PR:	250866
Reviewed by:	markj, mhorne
Tested by:	David Gilbert <dgilbert@daveg.ca>
MFC after:	1 week
Differential Revision:	https://reviews.freebsd.org/D31253
This commit is contained in:
Jessica Clarke 2021-07-22 20:02:14 +01:00
parent d5341d72a1
commit 4a23504908

View File

@ -872,7 +872,7 @@ pmap_extract_and_hold(pmap_t pmap, vm_offset_t va, vm_prot_t prot)
vm_paddr_t
pmap_kextract(vm_offset_t va)
{
pd_entry_t *l2;
pd_entry_t *l2, l2e;
pt_entry_t *l3;
vm_paddr_t pa;
@ -882,14 +882,23 @@ pmap_kextract(vm_offset_t va)
l2 = pmap_l2(kernel_pmap, va);
if (l2 == NULL)
panic("pmap_kextract: No l2");
if ((pmap_load(l2) & PTE_RX) != 0) {
l2e = pmap_load(l2);
/*
* Beware of concurrent promotion and demotion! We must
* use l2e rather than loading from l2 multiple times to
* ensure we see a consistent state, including the
* implicit load in pmap_l2_to_l3. It is, however, safe
* to use an old l2e because the L3 page is preserved by
* promotion.
*/
if ((l2e & PTE_RX) != 0) {
/* superpages */
pa = L2PTE_TO_PHYS(pmap_load(l2));
pa = L2PTE_TO_PHYS(l2e);
pa |= (va & L2_OFFSET);
return (pa);
}
l3 = pmap_l2_to_l3(l2, va);
l3 = pmap_l2_to_l3(&l2e, va);
if (l3 == NULL)
panic("pmap_kextract: No l3...");
pa = PTE_TO_PHYS(pmap_load(l3));