diff options
author | tegge <tegge@FreeBSD.org> | 2006-03-19 21:29:20 +0000 |
---|---|---|
committer | tegge <tegge@FreeBSD.org> | 2006-03-19 21:29:20 +0000 |
commit | 1ca5876d84247d6404476edeb824b6794e4df4e0 (patch) | |
tree | c8d2511affa869a2f93aff85ec87f1a19d5eb105 | |
parent | c8c59a31e247d512b3a0d1eea9196fcd1a90b37a (diff) | |
download | FreeBSD-src-1ca5876d84247d6404476edeb824b6794e4df4e0.zip FreeBSD-src-1ca5876d84247d6404476edeb824b6794e4df4e0.tar.gz |
Add kludge to avoid deadlock when unlinking snapshot.
-rw-r--r-- | sys/ufs/ufs/ufs_vnops.c | 16 |
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); } |