diff options
author | alc <alc@FreeBSD.org> | 2010-05-16 23:45:10 +0000 |
---|---|---|
committer | alc <alc@FreeBSD.org> | 2010-05-16 23:45:10 +0000 |
commit | f6c07c5b87dfdddf4b4438ac3df38c4c83125281 (patch) | |
tree | 5d19152403395b71d9fe26760d1b05201ce13b02 /sys/i386 | |
parent | 9090794d6cc9b8867376522131d6ff69824038a7 (diff) | |
download | FreeBSD-src-f6c07c5b87dfdddf4b4438ac3df38c4c83125281.zip FreeBSD-src-f6c07c5b87dfdddf4b4438ac3df38c4c83125281.tar.gz |
On entry to pmap_enter(), assert that the page is busy. While I'm
here, make the style of assertion used by pmap_enter() consistent
across all architectures.
On entry to pmap_remove_write(), assert that the page is neither
unmanaged nor fictitious, since we cannot remove write access to
either kind of page.
With the push down of the page queues lock, pmap_remove_write() cannot
condition its behavior on the state of the PG_WRITEABLE flag if the
page is busy. Assert that the object containing the page is locked.
This allows us to know that the page will neither become busy nor will
PG_WRITEABLE be set on it while pmap_remove_write() is running.
Correct a long-standing bug in vm_page_cowsetup(). We cannot possibly
do copy-on-write-based zero-copy transmit on unmanaged or fictitious
pages, so don't even try. Previously, the call to pmap_remove_write()
would have failed silently.
Diffstat (limited to 'sys/i386')
-rw-r--r-- | sys/i386/i386/pmap.c | 16 | ||||
-rw-r--r-- | sys/i386/xen/pmap.c | 23 |
2 files changed, 30 insertions, 9 deletions
diff --git a/sys/i386/i386/pmap.c b/sys/i386/i386/pmap.c index 4b87922..591aed8 100644 --- a/sys/i386/i386/pmap.c +++ b/sys/i386/i386/pmap.c @@ -3268,7 +3268,10 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_prot_t access, vm_page_t m, va = trunc_page(va); KASSERT(va <= VM_MAX_KERNEL_ADDRESS, ("pmap_enter: toobig")); KASSERT(va < UPT_MIN_ADDRESS || va >= UPT_MAX_ADDRESS, - ("pmap_enter: invalid to pmap_enter page table pages (va: 0x%x)", va)); + ("pmap_enter: invalid to pmap_enter page table pages (va: 0x%x)", + va)); + KASSERT((m->oflags & VPO_BUSY) != 0, + ("pmap_enter: page %p is not busy", m)); mpte = NULL; @@ -4410,7 +4413,16 @@ pmap_remove_write(vm_page_t m) pt_entry_t oldpte, *pte; vm_offset_t va; - if ((m->flags & PG_FICTITIOUS) != 0 || + KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + ("pmap_remove_write: page %p is not managed", m)); + + /* + * If the page is not VPO_BUSY, then PG_WRITEABLE cannot be set by + * another thread while the object is locked. Thus, if PG_WRITEABLE + * is clear, no page table entries need updating. + */ + VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); + if ((m->oflags & VPO_BUSY) == 0 && (m->flags & PG_WRITEABLE) == 0) return; vm_page_lock_queues(); diff --git a/sys/i386/xen/pmap.c b/sys/i386/xen/pmap.c index 42fdff9..ac1a17d 100644 --- a/sys/i386/xen/pmap.c +++ b/sys/i386/xen/pmap.c @@ -2682,12 +2682,12 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_prot_t access, vm_page_t m, CTR6(KTR_PMAP, "pmap_enter: pmap=%08p va=0x%08x access=0x%x ma=0x%08x prot=0x%x wired=%d", pmap, va, access, xpmap_ptom(VM_PAGE_TO_PHYS(m)), prot, wired); va = trunc_page(va); -#ifdef PMAP_DIAGNOSTIC - if (va > VM_MAX_KERNEL_ADDRESS) - panic("pmap_enter: toobig"); - if ((va >= UPT_MIN_ADDRESS) && (va < UPT_MAX_ADDRESS)) - panic("pmap_enter: invalid to pmap_enter page table pages (va: 0x%x)", va); -#endif + KASSERT(va <= VM_MAX_KERNEL_ADDRESS, ("pmap_enter: toobig")); + KASSERT(va < UPT_MIN_ADDRESS || va >= UPT_MAX_ADDRESS, + ("pmap_enter: invalid to pmap_enter page table pages (va: 0x%x)", + va)); + KASSERT((m->oflags & VPO_BUSY) != 0, + ("pmap_enter: page %p is not busy", m)); mpte = NULL; @@ -3780,7 +3780,16 @@ pmap_remove_write(vm_page_t m) pmap_t pmap; pt_entry_t oldpte, *pte; - if ((m->flags & PG_FICTITIOUS) != 0 || + KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + ("pmap_remove_write: page %p is not managed", m)); + + /* + * If the page is not VPO_BUSY, then PG_WRITEABLE cannot be set by + * another thread while the object is locked. Thus, if PG_WRITEABLE + * is clear, no page table entries need updating. + */ + VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); + if ((m->oflags & VPO_BUSY) == 0 && (m->flags & PG_WRITEABLE) == 0) return; vm_page_lock_queues(); |