aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJessica Clarke <jrtc27@FreeBSD.org>2021-07-22 19:02:14 +0000
committerJessica Clarke <jrtc27@FreeBSD.org>2021-07-22 19:02:14 +0000
commit4a235049082ee1cb044873ad9aff12cf73d0fd3b (patch)
tree8b23b572d4a8674738aaa7e2df84436ff3b08a3a
parentd5341d72a11be200e536ac7d8967449a3f521792 (diff)
riscv: Fix pmap_kextract racing with concurrent superpage promotion/demotion
This repeats amd64's cfcbf8c6fd3b (r180498) and i386's cf3508519c5e (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
-rw-r--r--sys/riscv/riscv/pmap.c17
1 files changed, 13 insertions, 4 deletions
diff --git a/sys/riscv/riscv/pmap.c b/sys/riscv/riscv/pmap.c
index 39595b10d7b2..0bb22bd13bbe 100644
--- a/sys/riscv/riscv/pmap.c
+++ b/sys/riscv/riscv/pmap.c
@@ -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));