summaryrefslogtreecommitdiffstats
path: root/sys/vm/vm_fault.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/vm/vm_fault.c')
-rw-r--r--sys/vm/vm_fault.c65
1 files changed, 61 insertions, 4 deletions
diff --git a/sys/vm/vm_fault.c b/sys/vm/vm_fault.c
index a1bad69..f31f12b 100644
--- a/sys/vm/vm_fault.c
+++ b/sys/vm/vm_fault.c
@@ -81,6 +81,8 @@
#include <sys/vnode.h>
#include <sys/resourcevar.h>
#include <sys/vmmeter.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
@@ -134,6 +136,8 @@ unlock_map(struct faultstate *fs)
static void
_unlock_things(struct faultstate *fs, int dealloc)
{
+
+ mtx_assert(&vm_mtx, MA_OWNED);
vm_object_pip_wakeup(fs->object);
if (fs->object != fs->first_object) {
vm_page_free(fs->first_m);
@@ -145,8 +149,15 @@ _unlock_things(struct faultstate *fs, int dealloc)
}
unlock_map(fs);
if (fs->vp != NULL) {
- vput(fs->vp);
+ struct vnode *vp;
+
+ vp = fs->vp;
fs->vp = NULL;
+ mtx_unlock(&vm_mtx);
+ mtx_lock(&Giant);
+ vput(vp);
+ mtx_unlock(&Giant);
+ mtx_lock(&vm_mtx);
}
}
@@ -179,10 +190,41 @@ _unlock_things(struct faultstate *fs, int dealloc)
*
*
* The map in question must be referenced, and remains so.
- * Caller may hold no locks.
+ * Caller may hold no locks except the vm_mtx which will be
+ * locked if needed.
*/
+static int vm_fault1 __P((vm_map_t, vm_offset_t, vm_prot_t, int));
+
+static int vm_faults_no_vm_mtx;
+SYSCTL_INT(_vm, OID_AUTO, vm_faults_no_vm_mtx, CTLFLAG_RW,
+ &vm_faults_no_vm_mtx, 0, "");
+
+static int vm_faults_no_giant;
+SYSCTL_INT(_vm, OID_AUTO, vm_faults_no_giant, CTLFLAG_RW,
+ &vm_faults_no_giant, 0, "");
+
int
-vm_fault(vm_map_t map, vm_offset_t vaddr, vm_prot_t fault_type, int fault_flags)
+vm_fault(vm_map_t map, vm_offset_t vaddr, vm_prot_t fault_type,
+ int fault_flags)
+{
+ int hadvmlock, ret;
+
+ hadvmlock = mtx_owned(&vm_mtx);
+ if (!hadvmlock) {
+ mtx_lock(&vm_mtx);
+ vm_faults_no_vm_mtx++;
+ if (!mtx_owned(&Giant))
+ vm_faults_no_giant++;
+ }
+ ret = vm_fault1(map, vaddr, fault_type, fault_flags);
+ if (!hadvmlock)
+ mtx_unlock(&vm_mtx);
+ return (ret);
+}
+
+static int
+vm_fault1(vm_map_t map, vm_offset_t vaddr, vm_prot_t fault_type,
+ int fault_flags)
{
vm_prot_t prot;
int result;
@@ -194,7 +236,8 @@ vm_fault(vm_map_t map, vm_offset_t vaddr, vm_prot_t fault_type, int fault_flags)
int faultcount;
struct faultstate fs;
- cnt.v_vm_faults++; /* needs lock XXX */
+ mtx_assert(&vm_mtx, MA_OWNED);
+ cnt.v_vm_faults++;
hardfault = 0;
RetryFault:;
@@ -251,7 +294,11 @@ RetryFault:;
vm_object_reference(fs.first_object);
vm_object_pip_add(fs.first_object, 1);
+ mtx_unlock(&vm_mtx);
+ mtx_lock(&Giant);
fs.vp = vnode_pager_lock(fs.first_object);
+ mtx_unlock(&Giant);
+ mtx_lock(&vm_mtx);
if ((fault_type & VM_PROT_WRITE) &&
(fs.first_object->type == OBJT_VNODE)) {
vm_freeze_copyopts(fs.first_object,
@@ -723,7 +770,11 @@ readrest:
*/
if (fs.vp != NULL) {
+ mtx_unlock(&vm_mtx);
+ mtx_lock(&Giant);
vput(fs.vp);
+ mtx_unlock(&Giant);
+ mtx_lock(&vm_mtx);
fs.vp = NULL;
}
@@ -940,6 +991,7 @@ vm_fault_user_wire(map, start, end)
register pmap_t pmap;
int rv;
+ mtx_assert(&vm_mtx, MA_OWNED);
pmap = vm_map_pmap(map);
/*
@@ -1112,6 +1164,9 @@ vm_fault_copy_entry(dst_map, src_map, dst_entry, src_entry)
*
* Return value:
* number of pages in marray
+ *
+ * This routine can't block.
+ * vm_mtx must be held.
*/
static int
vm_fault_additional_pages(m, rbehind, rahead, marray, reqpage)
@@ -1127,6 +1182,8 @@ vm_fault_additional_pages(m, rbehind, rahead, marray, reqpage)
vm_page_t rtm;
int cbehind, cahead;
+ mtx_assert(&vm_mtx, MA_OWNED);
+
object = m->object;
pindex = m->pindex;
OpenPOWER on IntegriCloud