diff options
| author | Jessica Clarke <jrtc27@FreeBSD.org> | 2021-07-22 19:02:14 +0000 |
|---|---|---|
| committer | Jessica Clarke <jrtc27@FreeBSD.org> | 2021-09-07 12:06:49 +0000 |
| commit | 2e3c6024a476f622e43e68243445168aa40a8d8e (patch) | |
| tree | d4bc250c26eb13fb9307c0a6d60ada861e5a69a5 | |
| parent | 16ee8fe56b8bbe394cee55ca0d0e50f9b7a69ba8 (diff) | |
| download | src-2e3c6024a476f622e43e68243445168aa40a8d8e.tar.gz src-2e3c6024a476f622e43e68243445168aa40a8d8e.zip | |
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
(cherry picked from commit 4a235049082ee1cb044873ad9aff12cf73d0fd3b)
| -rw-r--r-- | sys/riscv/riscv/pmap.c | 17 |
1 files changed, 13 insertions, 4 deletions
diff --git a/sys/riscv/riscv/pmap.c b/sys/riscv/riscv/pmap.c index 93e9525963f7..075a2d4e84c8 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)); |
