diff options
author | tegge <tegge@FreeBSD.org> | 2006-03-02 22:13:28 +0000 |
---|---|---|
committer | tegge <tegge@FreeBSD.org> | 2006-03-02 22:13:28 +0000 |
commit | 774f51ad2c9890088551e2fef8c7c2ec8bc1e446 (patch) | |
tree | a136dfc347b9ef7b044439ec33fe997d02fb4061 /sys/ufs/ffs | |
parent | 29fc266dddf27264a642495e94c044465289b437 (diff) | |
download | FreeBSD-src-774f51ad2c9890088551e2fef8c7c2ec8bc1e446.zip FreeBSD-src-774f51ad2c9890088551e2fef8c7c2ec8bc1e446.tar.gz |
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.
Diffstat (limited to 'sys/ufs/ffs')
-rw-r--r-- | sys/ufs/ffs/ffs_rawread.c | 12 |
1 files changed, 11 insertions, 1 deletions
diff --git a/sys/ufs/ffs/ffs_rawread.c b/sys/ufs/ffs/ffs_rawread.c index 3afa6c3..ec0d4fe 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); |