diff options
author | Ted Unangst <tedu@cvs.openbsd.org> | 2015-02-06 09:04:35 +0000 |
---|---|---|
committer | Ted Unangst <tedu@cvs.openbsd.org> | 2015-02-06 09:04:35 +0000 |
commit | 81af2d60fb4a82e33fcd18fd5b6a938ee9fc29ec (patch) | |
tree | b62be1b8be8206f63548d9c58f917adc6e1f1d97 | |
parent | d17919ba1c2db29af84edc86081481e7f698ac41 (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.c | 36 | ||||
-rw-r--r-- | sys/uvm/uvm_map.h | 6 |
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 */ |