summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2008-11-22 13:11:11 +0000
committerkib <kib@FreeBSD.org>2008-11-22 13:11:11 +0000
commit371d0216fb21251f9f5b42ed163852c5b93816f1 (patch)
tree126ed6af1c61e60f164eac00ea5ed291ddcc111a
parent8fad2283b3211a15c495b42689a5b65d91b96f3b (diff)
downloadFreeBSD-src-371d0216fb21251f9f5b42ed163852c5b93816f1.zip
FreeBSD-src-371d0216fb21251f9f5b42ed163852c5b93816f1.tar.gz
Busy ufs filesystem around block of code that does ".." lookup. Since
mnt_lock is before lock of any vnode on the mp, it uses LK_NOWAIT. Since MNTK_UNMOUNT may be transient, pdp lock is dropped when vfs_busy() failed, and operation is retried after some time. This way, ffs_vget() is not called on the mp that may be in the process of being destroyed by unmount. Check for the VI_DOOMED flag on pdp after its lock is reacquired, to better detect some situations where directory containing ".." entry is removed during the lookup. Reviewed by: tegge, attilio (previous version) Tested by: pho MFC after: 1 month
-rw-r--r--sys/ufs/ufs/ufs_lookup.c27
1 files changed, 26 insertions, 1 deletions
diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c
index 042ecd0..d464e00 100644
--- a/sys/ufs/ufs/ufs_lookup.c
+++ b/sys/ufs/ufs/ufs_lookup.c
@@ -157,6 +157,8 @@ ufs_lookup(ap)
int nameiop = cnp->cn_nameiop;
ino_t ino;
int ltype;
+ int pdoomed;
+ struct mount *mp;
bp = NULL;
slotoffset = -1;
@@ -578,9 +580,32 @@ found:
pdp = vdp;
if (flags & ISDOTDOT) {
ltype = VOP_ISLOCKED(pdp);
+ mp = pdp->v_mount;
+ for (;;) {
+ error = vfs_busy(mp, MBF_NOWAIT);
+ if (error == 0)
+ break;
+ VOP_UNLOCK(pdp, 0);
+ pause("ufs_dd", 1);
+ vn_lock(pdp, ltype | LK_RETRY);
+ VI_LOCK(pdp);
+ pdoomed = pdp->v_iflag & VI_DOOMED;
+ VI_UNLOCK(pdp);
+ if (pdoomed)
+ return (ENOENT);
+ }
VOP_UNLOCK(pdp, 0); /* race to get the inode */
- error = VFS_VGET(pdp->v_mount, ino, cnp->cn_lkflags, &tdp);
+ error = VFS_VGET(mp, ino, cnp->cn_lkflags, &tdp);
+ vfs_unbusy(mp);
vn_lock(pdp, ltype | LK_RETRY);
+ VI_LOCK(pdp);
+ pdoomed = pdp->v_iflag & VI_DOOMED;
+ VI_UNLOCK(pdp);
+ if (pdoomed) {
+ if (error == 0)
+ vput(tdp);
+ error = ENOENT;
+ }
if (error)
return (error);
*vpp = tdp;
OpenPOWER on IntegriCloud