Page MenuHomeFreeBSD

D40851.id124121.diff
No OneTemporary

D40851.id124121.diff

diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c
--- a/sys/kern/vfs_lookup.c
+++ b/sys/kern/vfs_lookup.c
@@ -1166,20 +1166,17 @@
char *lastchar; /* location of the last character */
struct vnode *dp = NULL; /* the directory we are searching */
struct vnode *tdp; /* saved dp */
- struct mount *mp; /* mount table entry */
struct prison *pr;
size_t prev_ni_pathlen; /* saved ndp->ni_pathlen */
int docache; /* == 0 do not cache last component */
int wantparent; /* 1 => wantparent or lockparent flag */
int rdonly; /* lookup read-only flag bit */
int error = 0;
- int dpunlocked = 0; /* dp has already been unlocked */
+ bool dp_put = false; /* vput() already called on dp */
int relookup = 0; /* do not consume the path component */
struct componentname *cnp = &ndp->ni_cnd;
int lkflags_save;
int ni_dvp_unlocked;
- int crosslkflags;
- bool crosslock;
/*
* Setup: break out flag bits into variables.
@@ -1531,70 +1528,49 @@
ni_dvp_unlocked = 1;
}
goto success;
- } else if ((vn_irflag_read(dp) & VIRF_MOUNTPOINT) != 0) {
- if ((cnp->cn_flags & NOCROSSMOUNT) != 0)
- goto nextname;
- } else
+ }
+
+ /* From here: Not a symlink we have to follow. */
+
+ if ((cnp->cn_flags & NOCROSSMOUNT) != 0)
goto nextname;
/*
- * Check to see if the vnode has been mounted on;
- * if so find the root of the mounted filesystem.
+ * Cross the mounts, if any.
*/
- do {
- mp = dp->v_mountedhere;
- KASSERT(mp != NULL,
- ("%s: NULL mountpoint for VIRF_MOUNTPOINT vnode", __func__));
- crosslock = (dp->v_vflag & VV_CROSSLOCK) != 0;
- crosslkflags = enforce_lkflags(mp, cnp->cn_lkflags);
- if (__predict_false(crosslock)) {
- /*
- * We are going to be holding the vnode lock, which
- * in this case is shared by the root vnode of the
- * filesystem mounted at mp, across the call to
- * VFS_ROOT(). Make the situation clear to the
- * filesystem by passing LK_CANRECURSE if the
- * lock is held exclusive, or by clearinng
- * LK_NODDLKTREAT to allow recursion on the shared
- * lock in the presence of an exclusive waiter.
- */
- if (VOP_ISLOCKED(dp) == LK_EXCLUSIVE) {
- crosslkflags &= ~LK_SHARED;
- crosslkflags |= LK_EXCLUSIVE | LK_CANRECURSE;
- } else if ((crosslkflags & LK_EXCLUSIVE) != 0) {
- vn_lock(dp, LK_UPGRADE | LK_RETRY);
- if (VN_IS_DOOMED(dp)) {
- error = ENOENT;
- goto bad2;
- }
- if (dp->v_mountedhere != mp) {
- continue;
- }
- } else
- crosslkflags &= ~LK_NODDLKTREAT;
- }
- if (vfs_busy(mp, 0) != 0)
- continue;
- if (__predict_true(!crosslock))
- vput(dp);
- if (dp != ndp->ni_dvp)
+ error = vn_cross_mounts(dp, cnp->cn_lkflags, &dp);
+ if (__predict_false(error != 0)) {
+ /*
+ * If 'error' is ENOENT, during crossing, 'dp' was unlocked and
+ * is now doomed, which, given the pre-existing active
+ * reference, can only happen on a forced unmount. We could
+ * climb to the "parent" directory (in the resolution, i.e.,
+ * 'ni_dvp'), but this is likely to be useless (if on the same
+ * mount it can have been doomed already, and if not, it
+ * currently is equal to 'vp_crossmp' anyway) and problematic
+ * semantically if done standalone. The most sensible
+ * alternative would be to restart the whole resolution, but we
+ * are not there yet.
+ */
+ dp_put = true;
+ goto bad2;
+ }
+
+ if (dp != ndp->ni_vp) {
+ /* We effectively crossed some mounts. Release 'ni_dvp', which
+ * is going to be replaced by 'vp_crossmp'. */
+ if (ndp->ni_dvp != ndp->ni_vp)
vput(ndp->ni_dvp);
else
vrele(ndp->ni_dvp);
+
+ ndp->ni_vp = dp;
+
vrefact(vp_crossmp);
- ndp->ni_dvp = vp_crossmp;
- error = VFS_ROOT(mp, crosslkflags, &tdp);
- vfs_unbusy(mp);
- if (__predict_false(crosslock))
- vput(dp);
if (vn_lock(vp_crossmp, LK_SHARED | LK_NOWAIT))
panic("vp_crossmp exclusively locked or reclaimed");
- if (error != 0) {
- dpunlocked = 1;
- goto bad2;
- }
- ndp->ni_vp = dp = tdp;
- } while ((vn_irflag_read(dp) & VIRF_MOUNTPOINT) != 0);
+ ndp->ni_dvp = vp_crossmp;
+ }
nextname:
/*
@@ -1704,7 +1680,7 @@
vrele(ndp->ni_dvp);
}
bad:
- if (!dpunlocked)
+ if (!dp_put)
vput(dp);
bad_unlocked:
ndp->ni_vp = NULL;

File Metadata

Mime Type
text/plain
Expires
Thu, Aug 27, 3:33 PM (11 h, 7 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37397762
Default Alt Text
D40851.id124121.diff (4 KB)

Event Timeline