Skip to content

Commit

Permalink
Fix autofs triggering problem. Assume you have an NFS server,
Browse files Browse the repository at this point in the history
192.168.1.1, with share "share". This commit fixes a problem
where "mkdir /net/192.168.1.1/share/meh" would return spurious
error instead of creating the directory if the target filesystem
wasn't mounted yet; subsequent attempts would work correctly.

The failure scenario is kind of complicated to explain, but it all
boils down to calling VOP_MKDIR() for the target filesystem (NFS)
with wrong dvp - the autofs vnode instead of the filesystem root
mounted over it.

Reviewed by:	kib@
MFC after:	1 month
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D5442
  • Loading branch information
trasz committed Mar 12, 2016
1 parent 6d3eca2 commit 213ed83
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 16 deletions.
22 changes: 6 additions & 16 deletions sys/fs/autofs/autofs_vnops.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ autofs_lookup(struct vop_lookup_args *ap)
struct autofs_mount *amp;
struct autofs_node *anp, *child;
struct componentname *cnp;
int error, lock_flags;
int error;

dvp = ap->a_dvp;
vpp = ap->a_vpp;
Expand Down Expand Up @@ -257,23 +257,13 @@ autofs_lookup(struct vop_lookup_args *ap)
return (error);

if (newvp != NULL) {
error = VOP_LOOKUP(newvp, ap->a_vpp, ap->a_cnp);

/*
* Instead of figuring out whether our vnode should
* be locked or not given the error and cnp flags,
* just "copy" the lock status from vnode returned
* by mounted filesystem's VOP_LOOKUP(). Get rid
* of that new vnode afterwards.
* The target filesystem got automounted.
* Let the lookup(9) go around with the same
* path component.
*/
lock_flags = VOP_ISLOCKED(newvp);
if (lock_flags == 0) {
VOP_UNLOCK(dvp, 0);
vrele(newvp);
} else {
vput(newvp);
}
return (error);
vput(newvp);
return (ERELOOKUP);
}
}

Expand Down
19 changes: 19 additions & 0 deletions sys/kern/vfs_lookup.c
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,7 @@ lookup(struct nameidata *ndp)
int rdonly; /* lookup read-only flag bit */
int error = 0;
int dpunlocked = 0; /* dp has already been unlocked */
int relookup = 0; /* do not consume the path component */
struct componentname *cnp = &ndp->ni_cnd;
int lkflags_save;
int ni_dvp_unlocked;
Expand Down Expand Up @@ -745,6 +746,14 @@ lookup(struct nameidata *ndp)
goto unionlookup;
}

if (error == ERELOOKUP) {
vref(dp);
ndp->ni_vp = dp;
error = 0;
relookup = 1;
goto good;
}

if (error != EJUSTRETURN)
goto bad;
/*
Expand Down Expand Up @@ -777,6 +786,8 @@ lookup(struct nameidata *ndp)
goto success;
} else
cnp->cn_lkflags = lkflags_save;

good:
#ifdef NAMEI_DIAGNOSTIC
printf("found\n");
#endif
Expand Down Expand Up @@ -856,6 +867,14 @@ lookup(struct nameidata *ndp)
*/
KASSERT((cnp->cn_flags & ISLASTCN) || *ndp->ni_next == '/',
("lookup: invalid path state."));
if (relookup) {
relookup = 0;
if (ndp->ni_dvp != dp)
vput(ndp->ni_dvp);
else
vrele(ndp->ni_dvp);
goto dirloop;
}
if (*ndp->ni_next == '/') {
cnp->cn_nameptr = ndp->ni_next;
while (*cnp->cn_nameptr == '/') {
Expand Down
1 change: 1 addition & 0 deletions sys/sys/errno.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ __END_DECLS
#define EJUSTRETURN (-2) /* don't modify regs, just return */
#define ENOIOCTL (-3) /* ioctl not handled by this layer */
#define EDIRIOCTL (-4) /* do direct ioctl in GEOM */
#define ERELOOKUP (-5) /* retry the directory lookup */
#endif

#endif

0 comments on commit 213ed83

Please sign in to comment.