From 3b8e185f65b43a35fd03a8c1e33517c56dafd196 Mon Sep 17 00:00:00 2001 From: alc Date: Sat, 6 Dec 2003 05:45:32 +0000 Subject: Fix a deadlock between vm_fault() and vm_mmap(): The expected lock ordering between vm_map and vnode locks is that vm_map locks are acquired first. In revision 1.150 mmap(2) was changed to pass a locked vnode into vm_mmap(). This creates a lock-order reversal when vm_mmap() calls one of the vm_map routines that acquires a vm_map lock. The solution implemented herein is to release the vnode lock in mmap() before calling vm_mmap() and reacquire this lock if necessary in vm_mmap(). Approved by: re (scottl) Reviewed by: jeff, kan, rwatson --- sys/vm/vm_mmap.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c index be2aad3..c210a8d 100644 --- a/sys/vm/vm_mmap.c +++ b/sys/vm/vm_mmap.c @@ -433,7 +433,6 @@ mmap(td, uap) goto done; } - mtx_unlock(&Giant); error = 0; #ifdef MAC if (handle != NULL && (flags & MAP_SHARED) != 0) { @@ -441,6 +440,11 @@ mmap(td, uap) (struct vnode *)handle, prot); } #endif + if (vp != NULL) { + vput(vp); + vp = NULL; + } + mtx_unlock(&Giant); if (error == 0) error = vm_mmap(&vms->vm_map, &addr, size, prot, maxprot, flags, handle, pos); @@ -1164,7 +1168,7 @@ vm_mmap(vm_map_t map, vm_offset_t *addr, vm_size_t size, vm_prot_t prot, objtype_t type; int rv = KERN_SUCCESS; vm_ooffset_t objsize; - int docow; + int docow, error; struct thread *td = curthread; if (size == 0) @@ -1211,16 +1215,20 @@ vm_mmap(vm_map_t map, vm_offset_t *addr, vm_size_t size, vm_prot_t prot, } else { vp = (struct vnode *) handle; mtx_lock(&Giant); - ASSERT_VOP_LOCKED(vp, "vm_mmap"); + error = vget(vp, LK_EXCLUSIVE, td); + if (error) { + mtx_unlock(&Giant); + return (error); + } if (vp->v_type == VCHR) { type = OBJT_DEVICE; handle = vp->v_rdev; } else { struct vattr vat; - int error; error = VOP_GETATTR(vp, &vat, td->td_ucred, td); if (error) { + vput(vp); mtx_unlock(&Giant); return (error); } @@ -1234,6 +1242,7 @@ vm_mmap(vm_map_t map, vm_offset_t *addr, vm_size_t size, vm_prot_t prot, flags |= MAP_NOSYNC; } } + vput(vp); mtx_unlock(&Giant); } -- cgit v1.1