git: 95d42526e92c - main - msdosfs: fix rename
Konstantin Belousov
kib at FreeBSD.org
Fri Aug 27 15:39:57 UTC 2021
The branch main has been updated by kib:
URL: https://cgit.FreeBSD.org/src/commit/?id=95d42526e92cb2a9842d71d3c585aabf32da7534
commit 95d42526e92cb2a9842d71d3c585aabf32da7534
Author: Konstantin Belousov <kib at FreeBSD.org>
AuthorDate: 2021-08-01 17:46:59 +0000
Commit: Konstantin Belousov <kib at FreeBSD.org>
CommitDate: 2021-08-27 15:39:45 +0000
msdosfs: fix rename
Use the same locking algorithm for msdosfs_rename() as used by ufs_rename().
Convert doscheckpath() to non-sleeping version.
Reported by: trasz
PR: 257522
In collaboration with: pho
Reviewed by: mckusick
Sponsored by: The FreeBSD Foundation
MFC after: 1 week
Differential revision: https://reviews.freebsd.org/D31464
---
sys/fs/msdosfs/denode.h | 5 +-
sys/fs/msdosfs/msdosfs_denode.c | 1 +
sys/fs/msdosfs/msdosfs_lookup.c | 79 ++++----
sys/fs/msdosfs/msdosfs_vnops.c | 430 +++++++++++++++++++++-------------------
4 files changed, 274 insertions(+), 241 deletions(-)
diff --git a/sys/fs/msdosfs/denode.h b/sys/fs/msdosfs/denode.h
index 80ebf250febf..67ffa522000a 100644
--- a/sys/fs/msdosfs/denode.h
+++ b/sys/fs/msdosfs/denode.h
@@ -268,7 +268,7 @@ 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, uint64_t *inum);
+ struct componentname *cnp, daddr_t *scnp, u_long *blkoffp);
#endif
/*
@@ -288,6 +288,7 @@ int createde(struct denode *dep, struct denode *ddep, struct denode **depp, stru
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
index d97e61f7932c..64f75c267959 100644
--- a/sys/fs/msdosfs/msdosfs_denode.c
+++ b/sys/fs/msdosfs/msdosfs_denode.c
@@ -167,6 +167,7 @@ deget(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset,
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) {
diff --git a/sys/fs/msdosfs/msdosfs_lookup.c b/sys/fs/msdosfs/msdosfs_lookup.c
index d47f2969904b..2c3d02db37a0 100644
--- a/sys/fs/msdosfs/msdosfs_lookup.c
+++ b/sys/fs/msdosfs/msdosfs_lookup.c
@@ -67,7 +67,8 @@ int
msdosfs_lookup(struct vop_cachedlookup_args *ap)
{
- return (msdosfs_lookup_ino(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 {
@@ -109,8 +110,8 @@ msdosfs_deget_dotdot(struct mount *mp, void *arg, int lkflags,
* memory denode's will be in synch.
*/
int
-msdosfs_lookup_ino(struct vnode *vdp, struct vnode **vpp,
- struct componentname *cnp, uint64_t *dd_inum)
+msdosfs_lookup_ino(struct vnode *vdp, struct vnode **vpp, struct componentname
+ *cnp, daddr_t *scnp, u_long *blkoffp)
{
struct mbnambuf nb;
daddr_t bn;
@@ -119,11 +120,11 @@ msdosfs_lookup_ino(struct vnode *vdp, struct vnode **vpp,
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;
@@ -464,8 +465,9 @@ foundroot:
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 = cluster;
+ *blkoffp = blkoff;
return (0);
}
@@ -557,12 +559,15 @@ foundroot:
* Recheck that ".." still points to the inode we
* looked up before pdp lock was dropped.
*/
- error = msdosfs_lookup_ino(pdp, NULL, cnp, &inode1);
+ error = msdosfs_lookup_ino(pdp, NULL, cnp, &scn, &blkoff);
if (error) {
vput(*vpp);
*vpp = NULL;
return (error);
}
+ if (FAT32(pmp) && scn == MSDOSFSROOT)
+ scn = pmp->pm_rootdirblk;
+ inode1 = scn * pmp->pm_bpcluster + blkoff;
if (VTODE(*vpp)->de_inode != inode1) {
vput(*vpp);
goto restart;
@@ -794,10 +799,9 @@ dosdirempty(struct denode *dep)
*
* 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 +810,25 @@ doscheckpath(struct denode *source, struct denode *target)
struct buf *bp = NULL;
int error = 0;
- dep = target;
+ *wait_scn = 0;
+
+ pmp = target->de_pmp;
+ 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 +836,22 @@ doscheckpath(struct denode *source, struct denode *target)
}
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 +868,14 @@ doscheckpath(struct denode *source, struct denode *target)
}
vput(DETOV(dep));
- brelse(bp);
- bp = NULL;
+ dep = NULL;
/* NOTE: deget() clears dep on error */
- if ((error = deget(pmp, scn, 0, LK_EXCLUSIVE, &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_vnops.c b/sys/fs/msdosfs/msdosfs_vnops.c
index 5cd2c27cb46b..c81e192a6158 100644
--- a/sys/fs/msdosfs/msdosfs_vnops.c
+++ b/sys/fs/msdosfs/msdosfs_vnops.c
@@ -937,24 +937,27 @@ msdosfs_link(struct vop_link_args *ap)
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 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 @@ msdosfs_rename(struct vop_rename_args *ap)
/*
* 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,99 @@ abortit:
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);
+
+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);
+ from_diroffset = fdip->de_fndoffset;
+
+ 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);
+ tdip = VTODE(tdvp);
+ tip = tvp != NULL ? VTODE(tvp) : NULL;
+
+ /*
+ * Remember direntry place to use for destination
+ */
+ to_diroffset = tdip->de_fndoffset;
+ to_count = tdip->de_fndcnt;
/*
* Be sure we are not renaming ".", "..", or an alias of ".". This
@@ -1000,35 +1083,20 @@ abortit:
* "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;
- /*
- * Remember direntry place to use for destination
- */
- to_diroffset = dp->de_fndoffset;
- to_count = dp->de_fndcnt;
-
/*
* If ".." must be changed (ie the directory gets a new
* parent) then the source directory must not be in the
@@ -1040,55 +1108,59 @@ abortit:
* 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;
+ error = doscheckpath(fip, tdip, &wait_scn);
+ if (wait_scn != 0) {
+ 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 = msdosfs_lookup_ino(tdvp, NULL, tcnp, &scn, &blkoff);
+ MPASS(error == 0);
+ error = removede(tdip, tip);
+ if (error != 0)
+ goto unlock;
vput(tvp);
- xp = NULL;
+ tvp = NULL;
+ tip = NULL;
}
/*
@@ -1096,146 +1168,83 @@ abortit:
* 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;
/*
- * 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 */
+ error = msdosfs_lookup_ino(tdvp, NULL, tcnp, &scn, &blkoff);
+ MPASS(error == EJUSTRETURN);
+ 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++;
+ error = msdosfs_lookup_ino(fdvp, NULL, fcnp, &scn, &blkoff);
+ MPASS(error == 0);
+ 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 +1254,7 @@ abortit:
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 +1266,35 @@ abortit:
* namecache entries that were installed for this direntry.
*/
cache_purge(fvp);
- VOP_UNLOCK(fvp);
-bad:
- if (xp)
- vput(tvp);
+
+unlock:
+ 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:
+ 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 +1454,7 @@ msdosfs_rmdir(struct vop_rmdir_args *ap)
* non-empty.)
*/
error = 0;
- if (!dosdirempty(ip) || ip->de_flag & DE_RENAME) {
+ if (!dosdirempty(ip)) {
error = ENOTEMPTY;
goto out;
}
More information about the dev-commits-src-main
mailing list