summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Unangst <tedu@cvs.openbsd.org>2015-02-06 09:04:35 +0000
committerTed Unangst <tedu@cvs.openbsd.org>2015-02-06 09:04:35 +0000
commit81af2d60fb4a82e33fcd18fd5b6a938ee9fc29ec (patch)
treeb62be1b8be8206f63548d9c58f917adc6e1f1d97
parentd17919ba1c2db29af84edc86081481e7f698ac41 (diff)
make vm_map_lock lock when it's supposed to. add mutex to protect flags
and then double check we didn't lose the unavoidable race. ok beck guenther kettenis miod
-rw-r--r--sys/uvm/uvm_map.c36
-rw-r--r--sys/uvm/uvm_map.h6
2 files changed, 37 insertions, 5 deletions
diff --git a/sys/uvm/uvm_map.c b/sys/uvm/uvm_map.c
index 29032ea4b00..55598e149c7 100644
--- a/sys/uvm/uvm_map.c
+++ b/sys/uvm/uvm_map.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvm_map.c,v 1.182 2014/12/23 02:01:57 tedu Exp $ */
+/* $OpenBSD: uvm_map.c,v 1.183 2015/02/06 09:04:34 tedu Exp $ */
/* $NetBSD: uvm_map.c,v 1.86 2000/11/27 08:40:03 chs Exp $ */
/*
@@ -2122,13 +2122,13 @@ uvm_map_pageable_all(struct vm_map *map, int flags, vsize_t limit)
uvm_map_pageable_pgon(map, RB_MIN(uvm_map_addr, &map->addr),
NULL, map->min_offset, map->max_offset);
- atomic_clearbits_int(&map->flags, VM_MAP_WIREFUTURE);
+ vm_map_modflags(map, 0, VM_MAP_WIREFUTURE);
vm_map_unlock(map);
return 0;
}
if (flags & MCL_FUTURE)
- atomic_setbits_int(&map->flags, VM_MAP_WIREFUTURE);
+ vm_map_modflags(map, VM_MAP_WIREFUTURE, 0);
if (!(flags & MCL_CURRENT)) {
vm_map_unlock(map);
return 0;
@@ -2209,6 +2209,7 @@ uvm_map_setup(struct vm_map *map, vaddr_t min, vaddr_t max, int flags)
map->flags = flags;
map->timestamp = 0;
rw_init(&map->lock, "vmmaplk");
+ mtx_init(&map->flags_lock, IPL_VM);
/* Configure the allocators. */
if (flags & VM_MAP_ISVMSPACE)
@@ -4775,10 +4776,22 @@ vm_map_lock_try_ln(struct vm_map *map, char *file, int line)
if (map->flags & VM_MAP_INTRSAFE) {
rv = TRUE;
} else {
+ mtx_enter(&map->flags_lock);
if (map->flags & VM_MAP_BUSY) {
+ mtx_leave(&map->flags_lock);
return (FALSE);
}
+ mtx_leave(&map->flags_lock);
rv = (rw_enter(&map->lock, RW_WRITE|RW_NOSLEEP) == 0);
+ /* check if the lock is busy and back out if we won the race */
+ if (rv) {
+ mtx_enter(&map->flags_lock);
+ if (map->flags & VM_MAP_BUSY) {
+ rw_exit(&map->lock);
+ rv = FALSE;
+ }
+ mtx_leave(&map->flags_lock);
+ }
}
if (rv) {
@@ -4796,11 +4809,22 @@ vm_map_lock_ln(struct vm_map *map, char *file, int line)
{
if ((map->flags & VM_MAP_INTRSAFE) == 0) {
do {
+ mtx_enter(&map->flags_lock);
+tryagain:
while (map->flags & VM_MAP_BUSY) {
map->flags |= VM_MAP_WANTLOCK;
- tsleep(&map->flags, PVM, (char *)vmmapbsy, 0);
+ msleep(&map->flags, &map->flags_lock,
+ PVM, vmmapbsy, 0);
}
+ mtx_leave(&map->flags_lock);
} while (rw_enter(&map->lock, RW_WRITE|RW_SLEEPFAIL) != 0);
+ /* check if the lock is busy and back out if we won the race */
+ mtx_enter(&map->flags_lock);
+ if (map->flags & VM_MAP_BUSY) {
+ rw_exit(&map->lock);
+ goto tryagain;
+ }
+ mtx_leave(&map->flags_lock);
}
map->timestamp++;
@@ -4867,7 +4891,9 @@ vm_map_upgrade_ln(struct vm_map *map, char *file, int line)
void
vm_map_busy_ln(struct vm_map *map, char *file, int line)
{
+ mtx_enter(&map->flags_lock);
map->flags |= VM_MAP_BUSY;
+ mtx_leave(&map->flags_lock);
}
void
@@ -4875,8 +4901,10 @@ vm_map_unbusy_ln(struct vm_map *map, char *file, int line)
{
int oflags;
+ mtx_enter(&map->flags_lock);
oflags = map->flags;
map->flags &= ~(VM_MAP_BUSY|VM_MAP_WANTLOCK);
+ mtx_leave(&map->flags_lock);
if (oflags & VM_MAP_WANTLOCK)
wakeup(&map->flags);
}
diff --git a/sys/uvm/uvm_map.h b/sys/uvm/uvm_map.h
index 70c23e8c56b..df132b17459 100644
--- a/sys/uvm/uvm_map.h
+++ b/sys/uvm/uvm_map.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvm_map.h,v 1.52 2014/12/05 04:12:48 uebayasi Exp $ */
+/* $OpenBSD: uvm_map.h,v 1.53 2015/02/06 09:04:34 tedu Exp $ */
/* $NetBSD: uvm_map.h,v 1.24 2001/02/18 21:19:08 chs Exp $ */
/*
@@ -80,6 +80,7 @@
#ifndef _UVM_UVM_MAP_H_
#define _UVM_UVM_MAP_H_
+#include <sys/mutex.h>
#include <sys/rwlock.h>
#ifdef _KERNEL
@@ -293,6 +294,7 @@ struct vm_map {
vsize_t size; /* virtual size */
int ref_count; /* Reference count */
int flags; /* flags */
+ struct mutex flags_lock; /* flags lock */
unsigned int timestamp; /* Version number */
vaddr_t min_offset; /* First address in map. */
@@ -348,7 +350,9 @@ struct vm_map {
#ifdef _KERNEL
#define vm_map_modflags(map, set, clear) \
do { \
+ mtx_enter(&(map)->flags_lock); \
(map)->flags = ((map)->flags | (set)) & ~(clear); \
+ mtx_leave(&(map)->flags_lock); \
} while (0)
#endif /* _KERNEL */