Page MenuHomeFreeBSD

D31464.id93929.diff
No OneTemporary

D31464.id93929.diff

diff --git a/sys/fs/msdosfs/denode.h b/sys/fs/msdosfs/denode.h
--- a/sys/fs/msdosfs/denode.h
+++ b/sys/fs/msdosfs/denode.h
@@ -173,7 +173,6 @@
#define DE_CREATE 0x0008 /* Creation time update */
#define DE_ACCESS 0x0010 /* Access time update */
#define DE_MODIFIED 0x0020 /* Denode has been modified */
-#define DE_RENAME 0x0040 /* Denode is in the process of being renamed */
/* Maximum size of a file on a FAT filesystem */
#define MSDOSFS_FILESIZE_MAX 0xFFFFFFFFLL
@@ -267,13 +266,15 @@
int msdosfs_lookup(struct vop_cachedlookup_args *);
int msdosfs_inactive(struct vop_inactive_args *);
int msdosfs_reclaim(struct vop_reclaim_args *);
+int msdosfs_lookup_ino(struct vnode *vdp, struct vnode **vpp,
+ struct componentname *cnp, daddr_t *scnp, u_long *blkoffp);
#endif
/*
* Internal service routine prototypes.
*/
struct componentname;
-int deget(struct msdosfsmount *, u_long, u_long, struct denode **);
+int deget(struct msdosfsmount *, u_long, u_long, int, struct denode **);
int uniqdosname(struct denode *, struct componentname *, u_char *);
int readep(struct msdosfsmount *pmp, u_long dirclu, u_long dirofs, struct buf **bpp, struct direntry **epp);
@@ -286,6 +287,7 @@
int deupdat(struct denode *dep, int waitfor);
int removede(struct denode *pdep, struct denode *dep);
int detrunc(struct denode *dep, u_long length, int flags, struct ucred *cred);
-int doscheckpath( struct denode *source, struct denode *target);
+int doscheckpath( struct denode *source, struct denode *target,
+ daddr_t *wait_scn);
#endif /* _KERNEL || MAKEFS */
#endif /* !_FS_MSDOSFS_DENODE_H_ */
diff --git a/sys/fs/msdosfs/msdosfs_denode.c b/sys/fs/msdosfs/msdosfs_denode.c
--- a/sys/fs/msdosfs/msdosfs_denode.c
+++ b/sys/fs/msdosfs/msdosfs_denode.c
@@ -92,11 +92,12 @@
* diroffset is relative to the beginning of the root directory,
* otherwise it is cluster relative.
* diroffset - offset past begin of cluster of denode we want
+ * lkflags - locking flags (LK_NOWAIT)
* depp - returns the address of the gotten denode.
*/
int
deget(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset,
- struct denode **depp)
+ int lkflags, struct denode **depp)
{
int error;
uint64_t inode;
@@ -107,9 +108,11 @@
struct buf *bp;
#ifdef MSDOSFS_DEBUG
- printf("deget(pmp %p, dirclust %lu, diroffset %lx, depp %p)\n",
- pmp, dirclust, diroffset, depp);
+ printf("deget(pmp %p, dirclust %lu, diroffset %lx, flags %#x, "
+ "depp %p)\n",
+ pmp, dirclust, diroffset, flags, depp);
#endif
+ MPASS((lkflags & LK_TYPE_MASK) == LK_EXCLUSIVE);
/*
* On FAT32 filesystems, root is a (more or less) normal
@@ -133,7 +136,7 @@
*/
inode = (uint64_t)pmp->pm_bpcluster * dirclust + diroffset;
- error = vfs_hash_get(mntp, inode, LK_EXCLUSIVE, curthread, &nvp,
+ error = vfs_hash_get(mntp, inode, lkflags, curthread, &nvp,
de_vncmpf, &inode);
if (error)
return (error);
@@ -164,6 +167,7 @@
ldep->de_inode = inode;
cluster_init_vn(&ldep->de_clusterw);
lockmgr(nvp->v_vnlock, LK_EXCLUSIVE, NULL);
+ VN_LOCK_AREC(nvp); /* for doscheckpath */
fc_purge(ldep, 0); /* init the FAT cache for this denode */
error = insmntque(nvp, mntp);
if (error != 0) {
@@ -171,7 +175,7 @@
*depp = NULL;
return (error);
}
- error = vfs_hash_insert(nvp, inode, LK_EXCLUSIVE, curthread, &xvp,
+ error = vfs_hash_insert(nvp, inode, lkflags, curthread, &xvp,
de_vncmpf, &inode);
if (error) {
*depp = NULL;
diff --git a/sys/fs/msdosfs/msdosfs_lookup.c b/sys/fs/msdosfs/msdosfs_lookup.c
--- a/sys/fs/msdosfs/msdosfs_lookup.c
+++ b/sys/fs/msdosfs/msdosfs_lookup.c
@@ -63,14 +63,12 @@
#include <fs/msdosfs/fat.h>
#include <fs/msdosfs/msdosfsmount.h>
-static int msdosfs_lookup_(struct vnode *vdp, struct vnode **vpp,
- struct componentname *cnp, uint64_t *inum);
-
int
msdosfs_lookup(struct vop_cachedlookup_args *ap)
{
- return (msdosfs_lookup_(ap->a_dvp, ap->a_vpp, ap->a_cnp, NULL));
+ return (msdosfs_lookup_ino(ap->a_dvp, ap->a_vpp, ap->a_cnp, NULL,
+ NULL));
}
struct deget_dotdot {
@@ -89,7 +87,8 @@
pmp = VFSTOMSDOSFS(mp);
dd_arg = arg;
- error = deget(pmp, dd_arg->cluster, dd_arg->blkoff, &rdp);
+ error = deget(pmp, dd_arg->cluster, dd_arg->blkoff,
+ LK_EXCLUSIVE, &rdp);
if (error == 0)
*rvp = DETOV(rdp);
return (error);
@@ -110,9 +109,9 @@
* out to disk. This way disk blocks containing directory entries and in
* memory denode's will be in synch.
*/
-static int
-msdosfs_lookup_(struct vnode *vdp, struct vnode **vpp,
- struct componentname *cnp, uint64_t *dd_inum)
+int
+msdosfs_lookup_ino(struct vnode *vdp, struct vnode **vpp, struct componentname
+ *cnp, daddr_t *scnp, u_long *blkoffp)
{
struct mbnambuf nb;
daddr_t bn;
@@ -121,11 +120,11 @@
int slotoffset = 0;
int frcn;
u_long cluster;
- int blkoff;
+ u_long blkoff;
int diroff;
int blsize;
int isadir; /* ~0 if found direntry is a directory */
- u_long scn; /* starting cluster number */
+ daddr_t scn; /* starting cluster number */
struct vnode *pdp;
struct denode *dp;
struct denode *tdp;
@@ -466,8 +465,9 @@
if (FAT32(pmp) && scn == MSDOSFSROOT)
scn = pmp->pm_rootdirblk;
- if (dd_inum != NULL) {
- *dd_inum = (uint64_t)pmp->pm_bpcluster * scn + blkoff;
+ if (scnp != NULL) {
+ *scnp = scn;
+ *blkoffp = blkoff;
return (0);
}
@@ -498,7 +498,7 @@
*vpp = vdp;
return (0);
}
- error = deget(pmp, cluster, blkoff, &tdp);
+ error = deget(pmp, cluster, blkoff, LK_EXCLUSIVE, &tdp);
if (error)
return (error);
*vpp = DETOV(tdp);
@@ -526,7 +526,8 @@
if (dp->de_StartCluster == scn && isadir)
return (EISDIR);
- if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
+ if ((error = deget(pmp, cluster, blkoff, LK_EXCLUSIVE,
+ &tdp)) != 0)
return (error);
*vpp = DETOV(tdp);
cnp->cn_flags |= SAVENAME;
@@ -558,12 +559,13 @@
* Recheck that ".." still points to the inode we
* looked up before pdp lock was dropped.
*/
- error = msdosfs_lookup_(pdp, NULL, cnp, &inode1);
+ error = msdosfs_lookup_ino(pdp, NULL, cnp, &scn, &blkoff);
if (error) {
vput(*vpp);
*vpp = NULL;
return (error);
}
+ inode1 = scn * pmp->pm_bpcluster + blkoff;
if (VTODE(*vpp)->de_inode != inode1) {
vput(*vpp);
goto restart;
@@ -572,7 +574,8 @@
VREF(vdp); /* we want ourself, ie "." */
*vpp = vdp;
} else {
- if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
+ if ((error = deget(pmp, cluster, blkoff, LK_EXCLUSIVE,
+ &tdp)) != 0)
return (error);
*vpp = DETOV(tdp);
}
@@ -711,7 +714,7 @@
else
diroffset = 0;
}
- return deget(pmp, dirclust, diroffset, depp);
+ return (deget(pmp, dirclust, diroffset, LK_EXCLUSIVE, depp));
}
return 0;
@@ -794,10 +797,9 @@
*
* Returns 0 if target is NOT a subdirectory of source.
* Otherwise returns a non-zero error number.
- * The target inode is always unlocked on return.
*/
int
-doscheckpath(struct denode *source, struct denode *target)
+doscheckpath(struct denode *source, struct denode *target, daddr_t *wait_scn)
{
daddr_t scn;
struct msdosfsmount *pmp;
@@ -806,26 +808,26 @@
struct buf *bp = NULL;
int error = 0;
- dep = target;
+ *wait_scn = 0;
+
+ pmp = target->de_pmp;
+ lockmgr_assert(&pmp->pm_checkpath_lock, KA_XLOCKED);
+ KASSERT(pmp == source->de_pmp,
+ ("doscheckpath: source and target on different filesystems"));
+
if ((target->de_Attributes & ATTR_DIRECTORY) == 0 ||
- (source->de_Attributes & ATTR_DIRECTORY) == 0) {
- error = ENOTDIR;
- goto out;
- }
- if (dep->de_StartCluster == source->de_StartCluster) {
- error = EEXIST;
- goto out;
- }
- if (dep->de_StartCluster == MSDOSFSROOT)
- goto out;
- pmp = dep->de_pmp;
-#ifdef DIAGNOSTIC
- if (pmp != source->de_pmp)
- panic("doscheckpath: source and target on different filesystems");
-#endif
- if (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)
- goto out;
+ (source->de_Attributes & ATTR_DIRECTORY) == 0)
+ return (ENOTDIR);
+
+ if (target->de_StartCluster == source->de_StartCluster)
+ return (EEXIST);
+ if (target->de_StartCluster == MSDOSFSROOT ||
+ (FAT32(pmp) && target->de_StartCluster == pmp->pm_rootdirblk))
+ return (0);
+
+ dep = target;
+ vget(DETOV(dep), LK_EXCLUSIVE);
for (;;) {
if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) {
error = ENOTDIR;
@@ -833,19 +835,22 @@
}
scn = dep->de_StartCluster;
error = bread(pmp->pm_devvp, cntobn(pmp, scn),
- pmp->pm_bpcluster, NOCRED, &bp);
- if (error)
+ pmp->pm_bpcluster, NOCRED, &bp);
+ if (error != 0)
break;
- ep = (struct direntry *) bp->b_data + 1;
+ ep = (struct direntry *)bp->b_data + 1;
if ((ep->deAttributes & ATTR_DIRECTORY) == 0 ||
bcmp(ep->deName, ".. ", 11) != 0) {
error = ENOTDIR;
+ brelse(bp);
break;
}
+
scn = getushort(ep->deStartCluster);
if (FAT32(pmp))
scn |= getushort(ep->deHighClust) << 16;
+ brelse(bp);
if (scn == source->de_StartCluster) {
error = EINVAL;
@@ -862,15 +867,14 @@
}
vput(DETOV(dep));
- brelse(bp);
- bp = NULL;
+ dep = NULL;
/* NOTE: deget() clears dep on error */
- if ((error = deget(pmp, scn, 0, &dep)) != 0)
+ error = deget(pmp, scn, 0, LK_EXCLUSIVE | LK_NOWAIT, &dep);
+ if (error != 0) {
+ *wait_scn = scn;
break;
+ }
}
-out:;
- if (bp)
- brelse(bp);
#ifdef MSDOSFS_DEBUG
if (error == ENOTDIR)
printf("doscheckpath(): .. not a directory?\n");
diff --git a/sys/fs/msdosfs/msdosfs_vfsops.c b/sys/fs/msdosfs/msdosfs_vfsops.c
--- a/sys/fs/msdosfs/msdosfs_vfsops.c
+++ b/sys/fs/msdosfs/msdosfs_vfsops.c
@@ -469,6 +469,7 @@
pmp->pm_bo = bo;
lockinit(&pmp->pm_fatlock, 0, msdosfs_lock_msg, 0, 0);
+ lockinit(&pmp->pm_checkpath_lock, 0, "msdoscp", 0, 0);
/*
* Initialize ownerships and permissions, since nothing else will
@@ -740,6 +741,7 @@
}
if (pmp) {
lockdestroy(&pmp->pm_fatlock);
+ lockdestroy(&pmp->pm_checkpath_lock);
free(pmp->pm_inusemap, M_MSDOSFSFAT);
free(pmp, M_MSDOSFSMNT);
mp->mnt_data = NULL;
@@ -829,6 +831,7 @@
dev_rel(pmp->pm_dev);
free(pmp->pm_inusemap, M_MSDOSFSFAT);
lockdestroy(&pmp->pm_fatlock);
+ lockdestroy(&pmp->pm_checkpath_lock);
free(pmp, M_MSDOSFSMNT);
mp->mnt_data = NULL;
MNT_ILOCK(mp);
@@ -847,7 +850,7 @@
#ifdef MSDOSFS_DEBUG
printf("msdosfs_root(); mp %p, pmp %p\n", mp, pmp);
#endif
- error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep);
+ error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, LK_EXCLUSIVE, &ndep);
if (error)
return (error);
*vpp = DETOV(ndep);
@@ -988,7 +991,8 @@
struct denode *dep;
int error;
- error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, &dep);
+ error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs,
+ LK_EXCLUSIVE, &dep);
if (error) {
*vpp = NULLVP;
return (error);
diff --git a/sys/fs/msdosfs/msdosfs_vnops.c b/sys/fs/msdosfs/msdosfs_vnops.c
--- a/sys/fs/msdosfs/msdosfs_vnops.c
+++ b/sys/fs/msdosfs/msdosfs_vnops.c
@@ -937,24 +937,27 @@
static int
msdosfs_rename(struct vop_rename_args *ap)
{
- struct vnode *tdvp = ap->a_tdvp;
- struct vnode *fvp = ap->a_fvp;
- struct vnode *fdvp = ap->a_fdvp;
- struct vnode *tvp = ap->a_tvp;
- struct componentname *tcnp = ap->a_tcnp;
- struct componentname *fcnp = ap->a_fcnp;
- struct denode *ip, *xp, *dp, *zp;
+ struct vnode *fdvp, *fvp, *tdvp, *tvp, *vp;
+ struct componentname *fcnp, *tcnp;
+ struct denode *fdip, *fip, *tdip, *tip, *nip;
u_char toname[12], oldname[11];
u_long from_diroffset, to_diroffset;
+ bool checkpath_locked, doingdirectory, newparent;
u_char to_count;
- int doingdirectory = 0, newparent = 0;
int error;
- u_long cn, pcl;
- daddr_t bn;
+ u_long cn, pcl, blkoff;
+ daddr_t bn, wait_scn, scn;
struct msdosfsmount *pmp;
+ struct mount *mp;
struct direntry *dotdotp;
struct buf *bp;
+ tdvp = ap->a_tdvp;
+ fvp = ap->a_fvp;
+ fdvp = ap->a_fdvp;
+ tvp = ap->a_tvp;
+ tcnp = ap->a_tcnp;
+ fcnp = ap->a_fcnp;
pmp = VFSTOMSDOSFS(fdvp->v_mount);
#ifdef DIAGNOSTIC
@@ -965,19 +968,11 @@
/*
* Check for cross-device rename.
*/
+ mp = fvp->v_mount;
if (fvp->v_mount != tdvp->v_mount ||
- (tvp && fvp->v_mount != tvp->v_mount)) {
+ (tvp != NULL && fvp->v_mount != tvp->v_mount)) {
error = EXDEV;
-abortit:
- if (tdvp == tvp)
- vrele(tdvp);
- else
- vput(tdvp);
- if (tvp)
- vput(tvp);
- vrele(fdvp);
- vrele(fvp);
- return (error);
+ goto abortit;
}
/*
@@ -988,11 +983,92 @@
goto abortit;
}
- error = vn_lock(fvp, LK_EXCLUSIVE);
- if (error)
- goto abortit;
- dp = VTODE(fdvp);
- ip = VTODE(fvp);
+ /*
+ * When the target exists, both the directory
+ * and target vnodes are passed locked.
+ */
+ VOP_UNLOCK(tdvp);
+ if (tvp != NULL && tvp != tdvp)
+ VOP_UNLOCK(tvp);
+
+ checkpath_locked = false;
+
+relock:
+ doingdirectory = newparent = false;
+
+ error = vn_lock(fdvp, LK_EXCLUSIVE);
+ if (error != 0)
+ goto releout;
+ if (vn_lock(tdvp, LK_EXCLUSIVE | LK_NOWAIT) != 0) {
+ VOP_UNLOCK(fdvp);
+ error = vn_lock(tdvp, LK_EXCLUSIVE);
+ if (error != 0)
+ goto releout;
+ VOP_UNLOCK(tdvp);
+ goto relock;
+ }
+
+ error = msdosfs_lookup_ino(fdvp, NULL, fcnp, &scn, &blkoff);
+ if (error != 0) {
+ VOP_UNLOCK(fdvp);
+ VOP_UNLOCK(tdvp);
+ goto releout;
+ }
+ error = deget(pmp, scn, blkoff, LK_EXCLUSIVE | LK_NOWAIT, &nip);
+ if (error != 0) {
+ VOP_UNLOCK(fdvp);
+ VOP_UNLOCK(tdvp);
+ if (error != EBUSY)
+ goto releout;
+ error = deget(pmp, scn, blkoff, LK_EXCLUSIVE, &nip);
+ if (error != 0)
+ goto releout;
+ vp = fvp;
+ fvp = DETOV(nip);
+ VOP_UNLOCK(fvp);
+ vrele(vp);
+ goto relock;
+ }
+ vrele(fvp);
+ fvp = DETOV(nip);
+
+ error = msdosfs_lookup_ino(tdvp, NULL, tcnp, &scn, &blkoff);
+ if (error != 0 && error != EJUSTRETURN) {
+ VOP_UNLOCK(fdvp);
+ VOP_UNLOCK(tdvp);
+ VOP_UNLOCK(fvp);
+ goto releout;
+ }
+ if (error == EJUSTRETURN && tvp != NULL) {
+ vrele(tvp);
+ tvp = NULL;
+ }
+ if (error == 0) {
+ nip = NULL;
+ error = deget(pmp, scn, blkoff, LK_EXCLUSIVE | LK_NOWAIT,
+ &nip);
+ if (tvp != NULL) {
+ vrele(tvp);
+ tvp = NULL;
+ }
+ if (error != 0) {
+ VOP_UNLOCK(fdvp);
+ VOP_UNLOCK(tdvp);
+ VOP_UNLOCK(fvp);
+ if (error != EBUSY)
+ goto releout;
+ error = deget(pmp, scn, blkoff, LK_EXCLUSIVE,
+ &nip);
+ if (error != 0)
+ goto releout;
+ vput(DETOV(nip));
+ goto relock;
+ }
+ tvp = DETOV(nip);
+ }
+
+ fdip = VTODE(fdvp);
+ fip = VTODE(fvp);
/*
* Be sure we are not renaming ".", "..", or an alias of ".". This
@@ -1000,34 +1076,28 @@
* "ls" or "pwd" with the "." directory entry missing, and "cd .."
* doesn't work if the ".." entry is missing.
*/
- if (ip->de_Attributes & ATTR_DIRECTORY) {
+ if ((fip->de_Attributes & ATTR_DIRECTORY) != 0) {
/*
* Avoid ".", "..", and aliases of "." for obvious reasons.
*/
if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
- dp == ip ||
- (fcnp->cn_flags & ISDOTDOT) ||
- (tcnp->cn_flags & ISDOTDOT) ||
- (ip->de_flag & DE_RENAME)) {
- VOP_UNLOCK(fvp);
+ fdip == fip ||
+ (fcnp->cn_flags & ISDOTDOT) != 0 ||
+ (tcnp->cn_flags & ISDOTDOT) != 0) {
error = EINVAL;
- goto abortit;
+ goto unlock;
}
- ip->de_flag |= DE_RENAME;
- doingdirectory++;
+ doingdirectory = true;
}
- /*
- * When the target exists, both the directory
- * and target vnodes are returned locked.
- */
- dp = VTODE(tdvp);
- xp = tvp ? VTODE(tvp) : NULL;
+ tdip = VTODE(tdvp);
+ tip = tvp != NULL ? VTODE(tvp) : NULL;
+
/*
* Remember direntry place to use for destination
*/
- to_diroffset = dp->de_fndoffset;
- to_count = dp->de_fndcnt;
+ to_diroffset = tdip->de_fndoffset;
+ to_count = tdip->de_fndcnt;
/*
* If ".." must be changed (ie the directory gets a new
@@ -1040,55 +1110,61 @@
* call to doscheckpath().
*/
error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_thread);
- VOP_UNLOCK(fvp);
- if (VTODE(fdvp)->de_StartCluster != VTODE(tdvp)->de_StartCluster)
- newparent = 1;
+ if (fdip->de_StartCluster != tdip->de_StartCluster)
+ newparent = true;
if (doingdirectory && newparent) {
- if (error) /* write access check above */
- goto bad;
- if (xp != NULL)
- vput(tvp);
- /*
- * doscheckpath() vput()'s dp,
- * so we have to do a relookup afterwards
- */
- error = doscheckpath(ip, dp);
- if (error)
- goto out;
+ if (error != 0) /* write access check above */
+ goto unlock;
+ lockmgr(&pmp->pm_checkpath_lock, LK_EXCLUSIVE, NULL);
+ checkpath_locked = true;
+ error = doscheckpath(fip, tdip, &wait_scn);
+ if (wait_scn != 0) {
+ lockmgr(&pmp->pm_checkpath_lock, LK_RELEASE, NULL);
+ checkpath_locked = false;
+ VOP_UNLOCK(fdvp);
+ VOP_UNLOCK(tdvp);
+ VOP_UNLOCK(fvp);
+ if (tvp != NULL && tvp != tdvp)
+ VOP_UNLOCK(tvp);
+ error = deget(pmp, wait_scn, 0, LK_EXCLUSIVE,
+ &nip);
+ if (error == 0) {
+ vput(DETOV(nip));
+ goto relock;
+ }
+ }
+ if (error != 0)
+ goto unlock;
if ((tcnp->cn_flags & SAVESTART) == 0)
panic("msdosfs_rename: lost to startdir");
- error = relookup(tdvp, &tvp, tcnp);
- if (error)
- goto out;
- dp = VTODE(tdvp);
- xp = tvp ? VTODE(tvp) : NULL;
}
- if (xp != NULL) {
+ if (tip != NULL) {
/*
* Target must be empty if a directory and have no links
* to it. Also, ensure source and target are compatible
* (both directories, or both not directories).
*/
- if (xp->de_Attributes & ATTR_DIRECTORY) {
- if (!dosdirempty(xp)) {
+ if ((tip->de_Attributes & ATTR_DIRECTORY) != 0) {
+ if (!dosdirempty(tip)) {
error = ENOTEMPTY;
- goto bad;
+ goto unlock;
}
if (!doingdirectory) {
error = ENOTDIR;
- goto bad;
+ goto unlock;
}
cache_purge(tdvp);
} else if (doingdirectory) {
error = EISDIR;
- goto bad;
+ goto unlock;
}
- error = removede(dp, xp);
- if (error)
- goto bad;
+ error = removede(tdip, tip);
+ if (error != 0)
+ goto unlock;
vput(tvp);
- xp = NULL;
+ tvp = NULL;
+ tip = NULL;
}
/*
@@ -1096,146 +1172,84 @@
* into the denode and directory entry for the destination
* file/directory.
*/
- error = uniqdosname(VTODE(tdvp), tcnp, toname);
- if (error)
- goto abortit;
+ error = uniqdosname(tdip, tcnp, toname);
+ if (error != 0)
+ goto unlock;
+
+ from_diroffset = fdip->de_fndoffset;
/*
- * Since from wasn't locked at various places above,
- * have to do a relookup here.
+ * First write a new entry in the destination
+ * directory and mark the entry in the source directory
+ * as deleted. Then move the denode to the correct hash
+ * chain for its new location in the filesystem. And, if
+ * we moved a directory, then update its .. entry to point
+ * to the new parent directory.
*/
- fcnp->cn_flags &= ~MODMASK;
- fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
- if ((fcnp->cn_flags & SAVESTART) == 0)
- panic("msdosfs_rename: lost from startdir");
- if (!newparent)
- VOP_UNLOCK(tdvp);
- if (relookup(fdvp, &fvp, fcnp) == 0)
- vrele(fdvp);
- if (fvp == NULL) {
- /*
- * From name has disappeared.
- */
- if (doingdirectory)
- panic("rename: lost dir entry");
- if (newparent)
- VOP_UNLOCK(tdvp);
- vrele(tdvp);
- vrele(ap->a_fvp);
- /*
- * fdvp may be locked and has a reference. We need to
- * release the lock and reference, unless to and from
- * directories are the same. In that case it is already
- * unlocked.
- */
- if (tdvp != fdvp)
- vput(fdvp);
- return 0;
+ memcpy(oldname, fip->de_Name, 11);
+ memcpy(fip->de_Name, toname, 11); /* update denode */
+ tdip->de_fndoffset = to_diroffset;
+ tdip->de_fndcnt = to_count;
+ error = createde(fip, tdip, NULL, tcnp);
+ if (error != 0) {
+ memcpy(fip->de_Name, oldname, 11);
+ goto unlock;
}
- xp = VTODE(fvp);
- zp = VTODE(fdvp);
- from_diroffset = zp->de_fndoffset;
/*
- * Ensure that the directory entry still exists and has not
- * changed till now. If the source is a file the entry may
- * have been unlinked or renamed. In either case there is
- * no further work to be done. If the source is a directory
- * then it cannot have been rmdir'ed or renamed; this is
- * prohibited by the DE_RENAME flag.
+ * If fip is for a directory, then its name should always
+ * be "." since it is for the directory entry in the
+ * directory itself (msdosfs_lookup() always translates
+ * to the "." entry so as to get a unique denode, except
+ * for the root directory there are different
+ * complications). However, we just corrupted its name
+ * to pass the correct name to createde(). Undo this.
*/
- if (xp != ip) {
- if (doingdirectory)
- panic("rename: lost dir entry");
- if (newparent)
- VOP_UNLOCK(fdvp);
- vrele(ap->a_fvp);
- xp = NULL;
- } else {
- vrele(fvp);
- xp = NULL;
-
- /*
- * First write a new entry in the destination
- * directory and mark the entry in the source directory
- * as deleted. Then move the denode to the correct hash
- * chain for its new location in the filesystem. And, if
- * we moved a directory, then update its .. entry to point
- * to the new parent directory.
- */
- memcpy(oldname, ip->de_Name, 11);
- memcpy(ip->de_Name, toname, 11); /* update denode */
- dp->de_fndoffset = to_diroffset;
- dp->de_fndcnt = to_count;
- error = createde(ip, dp, (struct denode **)0, tcnp);
- if (error) {
- memcpy(ip->de_Name, oldname, 11);
- if (newparent)
- VOP_UNLOCK(fdvp);
- VOP_UNLOCK(fvp);
- goto bad;
- }
- /*
- * If ip is for a directory, then its name should always
- * be "." since it is for the directory entry in the
- * directory itself (msdosfs_lookup() always translates
- * to the "." entry so as to get a unique denode, except
- * for the root directory there are different
- * complications). However, we just corrupted its name
- * to pass the correct name to createde(). Undo this.
- */
- if ((ip->de_Attributes & ATTR_DIRECTORY) != 0)
- memcpy(ip->de_Name, oldname, 11);
- ip->de_refcnt++;
- zp->de_fndoffset = from_diroffset;
- error = removede(zp, ip);
- if (error) {
- /* XXX should downgrade to ro here, fs is corrupt */
- if (newparent)
- VOP_UNLOCK(fdvp);
- VOP_UNLOCK(fvp);
- goto bad;
- }
- if (!doingdirectory) {
- error = pcbmap(dp, de_cluster(pmp, to_diroffset), 0,
- &ip->de_dirclust, 0);
- if (error) {
- /* XXX should downgrade to ro here, fs is corrupt */
- if (newparent)
- VOP_UNLOCK(fdvp);
- VOP_UNLOCK(fvp);
- goto bad;
- }
- if (ip->de_dirclust == MSDOSFSROOT)
- ip->de_diroffset = to_diroffset;
- else
- ip->de_diroffset = to_diroffset & pmp->pm_crbomask;
+ if ((fip->de_Attributes & ATTR_DIRECTORY) != 0)
+ memcpy(fip->de_Name, oldname, 11);
+ fip->de_refcnt++;
+ fdip->de_fndoffset = from_diroffset;
+ error = removede(fdip, fip);
+ if (error != 0) {
+ /* XXX should downgrade to ro here, fs is corrupt */
+ goto unlock;
+ }
+ if (!doingdirectory) {
+ error = pcbmap(tdip, de_cluster(pmp, to_diroffset), 0,
+ &fip->de_dirclust, 0);
+ if (error != 0) {
+ /*
+ * XXX should downgrade to ro here,
+ * fs is corrupt
+ */
+ goto unlock;
}
- reinsert(ip);
- if (newparent)
- VOP_UNLOCK(fdvp);
+ if (fip->de_dirclust == MSDOSFSROOT)
+ fip->de_diroffset = to_diroffset;
+ else
+ fip->de_diroffset = to_diroffset & pmp->pm_crbomask;
}
+ reinsert(fip);
/*
* If we moved a directory to a new parent directory, then we must
* fixup the ".." entry in the moved directory.
*/
if (doingdirectory && newparent) {
- cn = ip->de_StartCluster;
+ cn = fip->de_StartCluster;
if (cn == MSDOSFSROOT) {
/* this should never happen */
panic("msdosfs_rename(): updating .. in root directory?");
} else
bn = cntobn(pmp, cn);
error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster,
- NOCRED, &bp);
- if (error) {
+ NOCRED, &bp);
+ if (error != 0) {
/* XXX should downgrade to ro here, fs is corrupt */
- VOP_UNLOCK(fvp);
- goto bad;
+ goto unlock;
}
dotdotp = (struct direntry *)bp->b_data + 1;
- pcl = dp->de_StartCluster;
+ pcl = tdip->de_StartCluster;
if (FAT32(pmp) && pcl == pmp->pm_rootdirblk)
pcl = MSDOSFSROOT;
putushort(dotdotp->deStartCluster, pcl);
@@ -1245,8 +1259,7 @@
bdwrite(bp);
else if ((error = bwrite(bp)) != 0) {
/* XXX should downgrade to ro here, fs is corrupt */
- VOP_UNLOCK(fvp);
- goto bad;
+ goto unlock;
}
}
@@ -1258,17 +1271,38 @@
* namecache entries that were installed for this direntry.
*/
cache_purge(fvp);
- VOP_UNLOCK(fvp);
-bad:
- if (xp)
- vput(tvp);
+
+unlock:
+ if (checkpath_locked)
+ lockmgr(&pmp->pm_checkpath_lock, LK_RELEASE, NULL);
+ vput(fdvp);
+ vput(fvp);
+ if (tvp != NULL) {
+ if (tvp != tdvp)
+ vput(tvp);
+ else
+ vrele(tvp);
+ }
vput(tdvp);
-out:
- ip->de_flag &= ~DE_RENAME;
+ return (error);
+releout:
+ MPASS(!checkpath_locked);
+ vrele(tdvp);
+ if (tvp != NULL)
+ vrele(tvp);
+ vrele(fdvp);
+ vrele(fvp);
+ return (error);
+abortit:
+ if (tdvp == tvp)
+ vrele(tdvp);
+ else
+ vput(tdvp);
+ if (tvp != NULL)
+ vput(tvp);
vrele(fdvp);
vrele(fvp);
return (error);
-
}
static struct {
@@ -1428,7 +1462,7 @@
* non-empty.)
*/
error = 0;
- if (!dosdirempty(ip) || ip->de_flag & DE_RENAME) {
+ if (!dosdirempty(ip)) {
error = ENOTEMPTY;
goto out;
}
diff --git a/sys/fs/msdosfs/msdosfsmount.h b/sys/fs/msdosfs/msdosfsmount.h
--- a/sys/fs/msdosfs/msdosfsmount.h
+++ b/sys/fs/msdosfs/msdosfsmount.h
@@ -114,6 +114,7 @@
void *pm_d2u; /* DOS->Local iconv handle */
#ifndef MAKEFS
struct lock pm_fatlock; /* lockmgr protecting allocations */
+ struct lock pm_checkpath_lock; /* protects doscheckpath result */
#endif
};
diff --git a/sys/kern/vfs_hash.c b/sys/kern/vfs_hash.c
--- a/sys/kern/vfs_hash.c
+++ b/sys/kern/vfs_hash.c
@@ -93,8 +93,14 @@
error = vget_finish(vp, flags, vs);
if (error == ENOENT && (flags & LK_NOWAIT) == 0)
break;
- if (error)
+ if (error != 0)
return (error);
+ if (vp->v_hash != hash ||
+ (fn != NULL && fn(vp, arg))) {
+ vput(vp);
+ /* Restart the bucket walk. */
+ break;
+ }
*vpp = vp;
return (0);
}
@@ -190,6 +196,7 @@
void
vfs_hash_rehash(struct vnode *vp, u_int hash)
{
+ ASSERT_VOP_ELOCKED(vp, "rehash requires excl lock");
rw_wlock(&vfs_hash_lock);
LIST_REMOVE(vp, v_hashlist);

File Metadata

Mime Type
text/plain
Expires
Sun, Feb 8, 9:12 PM (17 h, 8 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28498105
Default Alt Text
D31464.id93929.diff (25 KB)

Event Timeline