summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortegge <tegge@FreeBSD.org>2006-03-19 21:29:20 +0000
committertegge <tegge@FreeBSD.org>2006-03-19 21:29:20 +0000
commit1ca5876d84247d6404476edeb824b6794e4df4e0 (patch)
treec8d2511affa869a2f93aff85ec87f1a19d5eb105
parentc8c59a31e247d512b3a0d1eea9196fcd1a90b37a (diff)
downloadFreeBSD-src-1ca5876d84247d6404476edeb824b6794e4df4e0.zip
FreeBSD-src-1ca5876d84247d6404476edeb824b6794e4df4e0.tar.gz
Add kludge to avoid deadlock when unlinking snapshot.
-rw-r--r--sys/ufs/ufs/ufs_vnops.c16
1 files changed, 16 insertions, 0 deletions
diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c
index b26756c..a76d6ba 100644
--- a/sys/ufs/ufs/ufs_vnops.c
+++ b/sys/ufs/ufs/ufs_vnops.c
@@ -756,7 +756,9 @@ ufs_remove(ap)
struct vnode *vp = ap->a_vp;
struct vnode *dvp = ap->a_dvp;
int error;
+ struct thread *td;
+ td = curthread;
ip = VTOI(vp);
if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
(VTOI(dvp)->i_flags & APPEND)) {
@@ -766,6 +768,20 @@ ufs_remove(ap)
error = ufs_dirremove(dvp, ip, ap->a_cnp->cn_flags, 0);
if (ip->i_nlink <= 0)
vp->v_vflag |= VV_NOSYNC;
+ if ((ip->i_flags & SF_SNAPSHOT) != 0) {
+ /*
+ * Avoid deadlock where another thread is trying to
+ * update the inodeblock for dvp and is waiting on
+ * snaplk. Temporary unlock the vnode lock for the
+ * unlinked file and sync the directory. This should
+ * allow vput() of the directory to not block later on
+ * while holding the snapshot vnode locked, assuming
+ * that the directory hasn't been unlinked too.
+ */
+ VOP_UNLOCK(vp, 0, td);
+ (void) VOP_FSYNC(dvp, MNT_WAIT, td);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
+ }
out:
return (error);
}
OpenPOWER on IntegriCloud