diff options
authorMark Johnston <markj@FreeBSD.org>2022-02-08 18:15:54 +0000
committerMark Johnston <markj@FreeBSD.org>2022-02-08 18:31:55 +0000
commitc862d5f2a789925efe70fc64247caa5148e98a54 (patch)
parent5de79eeddb9de079d108d1312148bcbefce45c27 (diff)
riscv: Fix a race in pmap_pinit()
All pmaps share the top half of the address space. With 3-level page tables, the top-level kernel map entries are not static: they might change if the kernel map is extended (via pmap_growkernel()) or a 1GB mapping in the direct map is demoted (not implemented yet). Thus the riscv pmap maintains the allpmaps list to synchronize updates to top-level entries. When a pmap is created, it is inserted into this list after copying top-level entries from the kernel pmap. The copying is done without holding the allpmaps lock, and it is possible for pmap_pinit() to race with kernel map updates. In particular, if a thread is modifying L1 entries, and a concurrent pmap_pinit() copies the old version of the entries, it might not receive the update. Fix the problem by copying the kernel map entries after inserting the pmap into the list. This ensures that the nascent pmap always receives updates, though pmap_distribute_l1() may race with the page copy. Reviewed by: mhorne, jhb MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D34158
1 files changed, 2 insertions, 4 deletions
diff --git a/sys/riscv/riscv/pmap.c b/sys/riscv/riscv/pmap.c
index 1dc62418b165..0607b82c88e6 100644
--- a/sys/riscv/riscv/pmap.c
+++ b/sys/riscv/riscv/pmap.c
@@ -1231,14 +1231,12 @@ pmap_pinit(pmap_t pmap)
- /* Install kernel pagetables */
- memcpy(pmap->pm_l1, kernel_pmap->pm_l1, PAGE_SIZE);
- /* Add to the list of all user pmaps */
LIST_INSERT_HEAD(&allpmaps, pmap, pm_list);
+ memcpy(pmap->pm_l1, kernel_pmap->pm_l1, PAGE_SIZE);
return (1);