The branch main has been updated by kib:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=95d42526e92cb2a9842d71d3c585aabf32da7534

commit 95d42526e92cb2a9842d71d3c585aabf32da7534
Author:     Konstantin Belousov <[email protected]>
AuthorDate: 2021-08-01 17:46:59 +0000
Commit:     Konstantin Belousov <[email protected]>
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;
        }
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to