summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2013-09-08 17:51:22 +0000
committerkib <kib@FreeBSD.org>2013-09-08 17:51:22 +0000
commit56cc6860588a887bdad5d45e3e73e38a523b6c52 (patch)
treeaa83ae142c669cae8ce8a5da7fe0736576976183
parenta496157a2f1aae0a7a8510bcfe7ed2a0428968eb (diff)
downloadFreeBSD-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)
-rw-r--r--sys/kern/vfs_bio.c6
-rw-r--r--sys/vm/vm_object.c6
2 files changed, 12 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);
diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c
index 1d7f321..9dea3a1 100644
--- a/sys/vm/vm_object.c
+++ b/sys/vm/vm_object.c
@@ -1910,6 +1910,12 @@ again:
* not specified.
*/
vm_page_lock(p);
+ if (vm_page_xbusied(p)) {
+ VM_OBJECT_WUNLOCK(object);
+ vm_page_busy_sleep(p, "vmopax");
+ VM_OBJECT_WLOCK(object);
+ goto again;
+ }
if ((wirings = p->wire_count) != 0 &&
(wirings = pmap_page_wired_mappings(p)) != p->wire_count) {
if ((options & (OBJPR_NOTWIRED | OBJPR_NOTMAPPED)) ==
OpenPOWER on IntegriCloud