diff options
author | alc <alc@FreeBSD.org> | 2003-12-06 05:45:32 +0000 |
---|---|---|
committer | alc <alc@FreeBSD.org> | 2003-12-06 05:45:32 +0000 |
commit | 3b8e185f65b43a35fd03a8c1e33517c56dafd196 (patch) | |
tree | 560c9b455e9d0e51f3d5cfe4b3698382da778053 /sys/vm/vm_mmap.c | |
parent | b7377409b878fdfc3f6ec9283862d597e7a898a0 (diff) | |
download | FreeBSD-src-3b8e185f65b43a35fd03a8c1e33517c56dafd196.zip FreeBSD-src-3b8e185f65b43a35fd03a8c1e33517c56dafd196.tar.gz |
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
Diffstat (limited to 'sys/vm/vm_mmap.c')
-rw-r--r-- | sys/vm/vm_mmap.c | 17 |
1 files 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); } |