MFC r204474:
Fix the race between dotdot lookup and forced unmount, by using msdosfs-specific variant of vn_vget_ino(), msdosfs_deget_dotdot(). As was done for UFS, relookup the dotdot denode after the call to msdosfs_deget_dotdot(), because vnode lock is dropped and directory might be moved. MFC r204675: When returning error from msdosfs_lookup(), make sure that *vpp is NULL.
This commit is contained in:
parent
7825951721
commit
a8428ad0f1
@ -61,6 +61,18 @@
|
|||||||
#include <fs/msdosfs/fat.h>
|
#include <fs/msdosfs/fat.h>
|
||||||
#include <fs/msdosfs/msdosfsmount.h>
|
#include <fs/msdosfs/msdosfsmount.h>
|
||||||
|
|
||||||
|
static int msdosfs_lookup_(struct vnode *vdp, struct vnode **vpp,
|
||||||
|
struct componentname *cnp, u_int64_t *inum);
|
||||||
|
static int msdosfs_deget_dotdot(struct vnode *vp, u_long cluster, int blkoff,
|
||||||
|
struct vnode **rvp);
|
||||||
|
|
||||||
|
int
|
||||||
|
msdosfs_lookup(struct vop_cachedlookup_args *ap)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (msdosfs_lookup_(ap->a_dvp, ap->a_vpp, ap->a_cnp, NULL));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When we search a directory the blocks containing directory entries are
|
* When we search a directory the blocks containing directory entries are
|
||||||
* read and examined. The directory entries contain information that would
|
* read and examined. The directory entries contain information that would
|
||||||
@ -76,18 +88,11 @@
|
|||||||
* out to disk. This way disk blocks containing directory entries and in
|
* out to disk. This way disk blocks containing directory entries and in
|
||||||
* memory denode's will be in synch.
|
* memory denode's will be in synch.
|
||||||
*/
|
*/
|
||||||
int
|
static int
|
||||||
msdosfs_lookup(ap)
|
msdosfs_lookup_(struct vnode *vdp, struct vnode **vpp,
|
||||||
struct vop_cachedlookup_args /* {
|
struct componentname *cnp, u_int64_t *dd_inum)
|
||||||
struct vnode *a_dvp;
|
|
||||||
struct vnode **a_vpp;
|
|
||||||
struct componentname *a_cnp;
|
|
||||||
} */ *ap;
|
|
||||||
{
|
{
|
||||||
struct mbnambuf nb;
|
struct mbnambuf nb;
|
||||||
struct vnode *vdp = ap->a_dvp;
|
|
||||||
struct vnode **vpp = ap->a_vpp;
|
|
||||||
struct componentname *cnp = ap->a_cnp;
|
|
||||||
daddr_t bn;
|
daddr_t bn;
|
||||||
int error;
|
int error;
|
||||||
int slotcount;
|
int slotcount;
|
||||||
@ -109,6 +114,7 @@ msdosfs_lookup(ap)
|
|||||||
int flags = cnp->cn_flags;
|
int flags = cnp->cn_flags;
|
||||||
int nameiop = cnp->cn_nameiop;
|
int nameiop = cnp->cn_nameiop;
|
||||||
int unlen;
|
int unlen;
|
||||||
|
u_int64_t inode1;
|
||||||
|
|
||||||
int wincnt = 1;
|
int wincnt = 1;
|
||||||
int chksum = -1, chksum_ok;
|
int chksum = -1, chksum_ok;
|
||||||
@ -119,12 +125,14 @@ msdosfs_lookup(ap)
|
|||||||
#endif
|
#endif
|
||||||
dp = VTODE(vdp);
|
dp = VTODE(vdp);
|
||||||
pmp = dp->de_pmp;
|
pmp = dp->de_pmp;
|
||||||
*vpp = NULL;
|
|
||||||
#ifdef MSDOSFS_DEBUG
|
#ifdef MSDOSFS_DEBUG
|
||||||
printf("msdosfs_lookup(): vdp %p, dp %p, Attr %02x\n",
|
printf("msdosfs_lookup(): vdp %p, dp %p, Attr %02x\n",
|
||||||
vdp, dp, dp->de_Attributes);
|
vdp, dp, dp->de_Attributes);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
restart:
|
||||||
|
if (vpp != NULL)
|
||||||
|
*vpp = NULL;
|
||||||
/*
|
/*
|
||||||
* If they are going after the . or .. entry in the root directory,
|
* If they are going after the . or .. entry in the root directory,
|
||||||
* they won't find it. DOS filesystems don't have them in the root
|
* they won't find it. DOS filesystems don't have them in the root
|
||||||
@ -436,6 +444,11 @@ foundroot:
|
|||||||
if (FAT32(pmp) && scn == MSDOSFSROOT)
|
if (FAT32(pmp) && scn == MSDOSFSROOT)
|
||||||
scn = pmp->pm_rootdirblk;
|
scn = pmp->pm_rootdirblk;
|
||||||
|
|
||||||
|
if (dd_inum != NULL) {
|
||||||
|
*dd_inum = (uint64_t)pmp->pm_bpcluster * scn + blkoff;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If deleting, and at end of pathname, return
|
* If deleting, and at end of pathname, return
|
||||||
* parameters which can be used to remove file.
|
* parameters which can be used to remove file.
|
||||||
@ -508,23 +521,28 @@ foundroot:
|
|||||||
* inodes from the root, moving down the directory tree. Thus
|
* inodes from the root, moving down the directory tree. Thus
|
||||||
* when following backward pointers ".." we must unlock the
|
* when following backward pointers ".." we must unlock the
|
||||||
* parent directory before getting the requested directory.
|
* parent directory before getting the requested directory.
|
||||||
* There is a potential race condition here if both the current
|
|
||||||
* and parent directories are removed before the VFS_VGET for the
|
|
||||||
* inode associated with ".." returns. We hope that this occurs
|
|
||||||
* infrequently since we cannot avoid this race condition without
|
|
||||||
* implementing a sophisticated deadlock detection algorithm.
|
|
||||||
* Note also that this simple deadlock detection scheme will not
|
|
||||||
* work if the filesystem has any hard links other than ".."
|
|
||||||
* that point backwards in the directory structure.
|
|
||||||
*/
|
*/
|
||||||
pdp = vdp;
|
pdp = vdp;
|
||||||
if (flags & ISDOTDOT) {
|
if (flags & ISDOTDOT) {
|
||||||
VOP_UNLOCK(pdp, 0);
|
error = msdosfs_deget_dotdot(pdp, cluster, blkoff, vpp);
|
||||||
error = deget(pmp, cluster, blkoff, &tdp);
|
if (error) {
|
||||||
vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY);
|
*vpp = NULL;
|
||||||
if (error)
|
|
||||||
return (error);
|
return (error);
|
||||||
*vpp = DETOV(tdp);
|
}
|
||||||
|
/*
|
||||||
|
* Recheck that ".." still points to the inode we
|
||||||
|
* looked up before pdp lock was dropped.
|
||||||
|
*/
|
||||||
|
error = msdosfs_lookup_(pdp, NULL, cnp, &inode1);
|
||||||
|
if (error) {
|
||||||
|
vput(*vpp);
|
||||||
|
*vpp = NULL;
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
if (VTODE(*vpp)->de_inode != inode1) {
|
||||||
|
vput(*vpp);
|
||||||
|
goto restart;
|
||||||
|
}
|
||||||
} else if (dp->de_StartCluster == scn && isadir) {
|
} else if (dp->de_StartCluster == scn && isadir) {
|
||||||
VREF(vdp); /* we want ourself, ie "." */
|
VREF(vdp); /* we want ourself, ie "." */
|
||||||
*vpp = vdp;
|
*vpp = vdp;
|
||||||
@ -542,6 +560,49 @@ foundroot:
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
msdosfs_deget_dotdot(struct vnode *vp, u_long cluster, int blkoff,
|
||||||
|
struct vnode **rvp)
|
||||||
|
{
|
||||||
|
struct mount *mp;
|
||||||
|
struct msdosfsmount *pmp;
|
||||||
|
struct denode *rdp;
|
||||||
|
int ltype, error;
|
||||||
|
|
||||||
|
mp = vp->v_mount;
|
||||||
|
pmp = VFSTOMSDOSFS(mp);
|
||||||
|
ltype = VOP_ISLOCKED(vp);
|
||||||
|
KASSERT(ltype == LK_EXCLUSIVE || ltype == LK_SHARED,
|
||||||
|
("msdosfs_deget_dotdot: vp not locked"));
|
||||||
|
|
||||||
|
error = vfs_busy(mp, MBF_NOWAIT);
|
||||||
|
if (error != 0) {
|
||||||
|
vfs_ref(mp);
|
||||||
|
VOP_UNLOCK(vp, 0);
|
||||||
|
error = vfs_busy(mp, 0);
|
||||||
|
vn_lock(vp, ltype | LK_RETRY);
|
||||||
|
vfs_rel(mp);
|
||||||
|
if (error != 0)
|
||||||
|
return (ENOENT);
|
||||||
|
if (vp->v_iflag & VI_DOOMED) {
|
||||||
|
vfs_unbusy(mp);
|
||||||
|
return (ENOENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VOP_UNLOCK(vp, 0);
|
||||||
|
error = deget(pmp, cluster, blkoff, &rdp);
|
||||||
|
vfs_unbusy(mp);
|
||||||
|
if (error == 0)
|
||||||
|
*rvp = DETOV(rdp);
|
||||||
|
vn_lock(vp, ltype | LK_RETRY);
|
||||||
|
if (vp->v_iflag & VI_DOOMED) {
|
||||||
|
if (error == 0)
|
||||||
|
vput(*rvp);
|
||||||
|
error = ENOENT;
|
||||||
|
}
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* dep - directory entry to copy into the directory
|
* dep - directory entry to copy into the directory
|
||||||
* ddep - directory to add to
|
* ddep - directory to add to
|
||||||
|
Loading…
x
Reference in New Issue
Block a user