diff options
author | alc <alc@FreeBSD.org> | 2010-01-23 18:42:28 +0000 |
---|---|---|
committer | alc <alc@FreeBSD.org> | 2010-01-23 18:42:28 +0000 |
commit | e7f49ffe6fa73438e9dce2450bd81c8974a8cabb (patch) | |
tree | 44241225b389fcb9bf08e49870509f4dc505c402 /sys/i386/include/pmap.h | |
parent | 3f4b8c890828e53d4cda96f6ebafb4b30e27d7aa (diff) | |
download | FreeBSD-src-e7f49ffe6fa73438e9dce2450bd81c8974a8cabb.zip FreeBSD-src-e7f49ffe6fa73438e9dce2450bd81c8974a8cabb.tar.gz |
Handle a race between pmap_kextract() and pmap_promote_pde(). This race is
known to cause a kernel crash in ZFS on i386 when superpage promotion is
enabled.
Tested by: netchild
MFC after: 1 week
Diffstat (limited to 'sys/i386/include/pmap.h')
-rw-r--r-- | sys/i386/include/pmap.h | 21 |
1 files changed, 19 insertions, 2 deletions
diff --git a/sys/i386/include/pmap.h b/sys/i386/include/pmap.h index c93ac34..ae7d79d 100644 --- a/sys/i386/include/pmap.h +++ b/sys/i386/include/pmap.h @@ -265,6 +265,16 @@ pte_load_store_ma(pt_entry_t *ptep, pt_entry_t v) #define pde_store_ma(ptep, pte) pte_load_store_ma((ptep), (pt_entry_t)pte) #elif !defined(XEN) + +/* + * KPTmap is a linear mapping of the kernel page table. It differs from the + * recursive mapping in two ways: (1) it only provides access to kernel page + * table pages, and not user page table pages, and (2) it provides access to + * a kernel page table page after the corresponding virtual addresses have + * been promoted to a 2/4MB page mapping. + */ +extern pt_entry_t *KPTmap; + /* * Routine: pmap_kextract * Function: @@ -279,10 +289,17 @@ pmap_kextract(vm_offset_t va) if ((pa = PTD[va >> PDRSHIFT]) & PG_PS) { pa = (pa & PG_PS_FRAME) | (va & PDRMASK); } else { - pa = *vtopte(va); + /* + * Beware of a concurrent promotion that changes the PDE at + * this point! For example, vtopte() must not be used to + * access the PTE because it would use the new PDE. It is, + * however, safe to use the old PDE because the page table + * page is preserved by the promotion. + */ + pa = KPTmap[i386_btop(va)]; pa = (pa & PG_FRAME) | (va & PAGE_MASK); } - return pa; + return (pa); } #define PT_UPDATES_FLUSH() |