diff options
author | kib <kib@FreeBSD.org> | 2013-09-08 17:51:22 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2013-09-08 17:51:22 +0000 |
commit | 56cc6860588a887bdad5d45e3e73e38a523b6c52 (patch) | |
tree | aa83ae142c669cae8ce8a5da7fe0736576976183 /sys/kern | |
parent | a496157a2f1aae0a7a8510bcfe7ed2a0428968eb (diff) | |
download | FreeBSD-src-56cc6860588a887bdad5d45e3e73e38a523b6c52.zip FreeBSD-src-56cc6860588a887bdad5d45e3e73e38a523b6c52.tar.gz |
Drain for the xbusy state for two places which potentially do
pmap_remove_all(). Not doing the drain allows the pmap_enter() to
proceed in parallel, making the pmap_remove_all() effects void.
The race results in an invalidated page mapped wired by usermode.
Reported and tested by: pho
Reviewed by: alc
Sponsored by: The FreeBSD Foundation
Approved by: re (glebius)
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/vfs_bio.c | 6 |
1 files changed, 6 insertions, 0 deletions
diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c index 37ef663..ea8a002 100644 --- a/sys/kern/vfs_bio.c +++ b/sys/kern/vfs_bio.c @@ -1693,6 +1693,12 @@ brelse(struct buf *bp) KASSERT(presid >= 0, ("brelse: extra page")); VM_OBJECT_WLOCK(obj); + while (vm_page_xbusied(m)) { + vm_page_lock(m); + VM_OBJECT_WUNLOCK(obj); + vm_page_busy_sleep(m, "mbncsh"); + VM_OBJECT_WLOCK(obj); + } if (pmap_page_wired_mappings(m) == 0) vm_page_set_invalid(m, poffset, presid); VM_OBJECT_WUNLOCK(obj); |