From 774f51ad2c9890088551e2fef8c7c2ec8bc1e446 Mon Sep 17 00:00:00 2001 From: tegge Date: Thu, 2 Mar 2006 22:13:28 +0000 Subject: [PATCH] Eliminate a deadlock when creating snapshots. Blocking vn_start_write() must be called without any vnode locks held. Remove calls to vn_start_write() and vn_finished_write() in vnode_pager_putpages() and add these calls before the vnode lock is obtained to most of the callers that don't already have them. --- sys/kern/vfs_subr.c | 2 ++ sys/security/mac/mac_process.c | 3 +++ sys/ufs/ffs/ffs_rawread.c | 12 +++++++++++- sys/vm/vm_contig.c | 3 +++ sys/vm/vm_object.c | 3 +++ sys/vm/vnode_pager.c | 2 -- 6 files changed, 22 insertions(+), 3 deletions(-) diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index bcb9c94e0cff..add699118f22 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -2801,6 +2801,7 @@ vfs_msync(struct mount *mp, int flags) struct vnode *vp, *mvp; struct vm_object *obj; + (void) vn_start_write(NULL, &mp, V_WAIT); MNT_ILOCK(mp); MNT_VNODE_FOREACH(vp, mp, mvp) { VI_LOCK(vp); @@ -2831,6 +2832,7 @@ vfs_msync(struct mount *mp, int flags) VI_UNLOCK(vp); } MNT_IUNLOCK(mp); + vn_finished_write(mp); } /* diff --git a/sys/security/mac/mac_process.c b/sys/security/mac/mac_process.c index 9b72cbd5cc04..b805545ac1f4 100644 --- a/sys/security/mac/mac_process.c +++ b/sys/security/mac/mac_process.c @@ -330,6 +330,7 @@ mac_cred_mmapped_drop_perms_recurse(struct thread *td, struct ucred *cred, vm_object_t backing_object, object; vm_ooffset_t offset; struct vnode *vp; + struct mount *mp; if (!mac_mmap_revocation) return; @@ -407,6 +408,7 @@ mac_cred_mmapped_drop_perms_recurse(struct thread *td, struct ucred *cred, * copy-on-write. */ vm_object_reference(object); + (void) vn_start_write(vp, &mp, V_WAIT); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); VM_OBJECT_LOCK(object); vm_object_page_clean(object, @@ -416,6 +418,7 @@ mac_cred_mmapped_drop_perms_recurse(struct thread *td, struct ucred *cred, OBJPC_SYNC); VM_OBJECT_UNLOCK(object); VOP_UNLOCK(vp, 0, td); + vn_finished_write(mp); vm_object_deallocate(object); /* * Why bother if there's no read permissions diff --git a/sys/ufs/ffs/ffs_rawread.c b/sys/ufs/ffs/ffs_rawread.c index 3afa6c3bd119..ec0d4fe53087 100644 --- a/sys/ufs/ffs/ffs_rawread.c +++ b/sys/ufs/ffs/ffs_rawread.c @@ -101,6 +101,7 @@ ffs_rawread_sync(struct vnode *vp, struct thread *td) int error; int upgraded; struct bufobj *bo; + struct mount *mp; /* Check for dirty mmap, pending writes and dirty buffers */ spl = splbio(); @@ -112,7 +113,15 @@ ffs_rawread_sync(struct vnode *vp, struct thread *td) splx(spl); VI_UNLOCK(vp); - if (VOP_ISLOCKED(vp, td) != LK_EXCLUSIVE) { + if (vn_start_write(vp, &mp, V_NOWAIT) != 0) { + if (VOP_ISLOCKED(vp, td) != LK_EXCLUSIVE) + upgraded = 1; + else + upgraded = 0; + VOP_UNLOCK(vp, 0, td); + (void) vn_start_write(vp, &mp, V_WAIT); + VOP_LOCK(vp, LK_EXCLUSIVE, td); + } else if (VOP_ISLOCKED(vp, td) != LK_EXCLUSIVE) { upgraded = 1; /* Upgrade to exclusive lock, this might block */ VOP_LOCK(vp, LK_UPGRADE, td); @@ -161,6 +170,7 @@ ffs_rawread_sync(struct vnode *vp, struct thread *td) VI_UNLOCK(vp); if (upgraded != 0) VOP_LOCK(vp, LK_DOWNGRADE, td); + vn_finished_write(mp); } else { splx(spl); VI_UNLOCK(vp); diff --git a/sys/vm/vm_contig.c b/sys/vm/vm_contig.c index 488a16c76597..c8768850dc92 100644 --- a/sys/vm/vm_contig.c +++ b/sys/vm/vm_contig.c @@ -91,6 +91,7 @@ vm_contig_launder_page(vm_page_t m) vm_object_t object; vm_page_t m_tmp; struct vnode *vp; + struct mount *mp; object = m->object; if (!VM_OBJECT_TRYLOCK(object)) @@ -109,12 +110,14 @@ vm_contig_launder_page(vm_page_t m) vp = object->handle; vm_object_reference_locked(object); VM_OBJECT_UNLOCK(object); + (void) vn_start_write(vp, &mp, V_WAIT); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curthread); VM_OBJECT_LOCK(object); vm_object_page_clean(object, 0, 0, OBJPC_SYNC); VM_OBJECT_UNLOCK(object); VOP_UNLOCK(vp, 0, curthread); vm_object_deallocate(object); + vn_finished_write(mp); vm_page_lock_queues(); return (0); } else if (object->type == OBJT_SWAP || diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c index 5321b537b5bb..845752988ca4 100644 --- a/sys/vm/vm_object.c +++ b/sys/vm/vm_object.c @@ -993,6 +993,7 @@ vm_object_sync(vm_object_t object, vm_ooffset_t offset, vm_size_t size, { vm_object_t backing_object; struct vnode *vp; + struct mount *mp; int flags; if (object == NULL) @@ -1023,6 +1024,7 @@ vm_object_sync(vm_object_t object, vm_ooffset_t offset, vm_size_t size, int vfslocked; vp = object->handle; VM_OBJECT_UNLOCK(object); + (void) vn_start_write(vp, &mp, V_WAIT); vfslocked = VFS_LOCK_GIANT(vp->v_mount); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curthread); flags = (syncio || invalidate) ? OBJPC_SYNC : 0; @@ -1035,6 +1037,7 @@ vm_object_sync(vm_object_t object, vm_ooffset_t offset, vm_size_t size, VM_OBJECT_UNLOCK(object); VOP_UNLOCK(vp, 0, curthread); VFS_UNLOCK_GIANT(vfslocked); + vn_finished_write(mp); VM_OBJECT_LOCK(object); } if ((object->type == OBJT_VNODE || diff --git a/sys/vm/vnode_pager.c b/sys/vm/vnode_pager.c index aafdea168e41..8532bbf2fe76 100644 --- a/sys/vm/vnode_pager.c +++ b/sys/vm/vnode_pager.c @@ -1017,11 +1017,9 @@ vnode_pager_putpages(object, m, count, sync, rtvals) VM_OBJECT_UNLOCK(object); if (vp->v_type != VREG) mp = NULL; - (void)vn_start_write(vp, &mp, V_WAIT); rtval = VOP_PUTPAGES(vp, m, bytes, sync, rtvals, 0); KASSERT(rtval != EOPNOTSUPP, ("vnode_pager: stale FS putpages\n")); - vn_finished_write(mp); VM_OBJECT_LOCK(object); }