Index: sys/fs/autofs/autofs.h =================================================================== --- sys/fs/autofs/autofs.h +++ sys/fs/autofs/autofs.h @@ -41,6 +41,7 @@ extern int autofs_debug; extern int autofs_mount_on_stat; +extern int autofs_obsolete_lookup; #define AUTOFS_DEBUG(X, ...) \ do { \ Index: sys/fs/autofs/autofs.c =================================================================== --- sys/fs/autofs/autofs.c +++ sys/fs/autofs/autofs.c @@ -148,6 +148,11 @@ TUNABLE_INT("vfs.autofs.interruptible", &autofs_interruptible); SYSCTL_INT(_vfs_autofs, OID_AUTO, interruptible, CTLFLAG_RWTUN, &autofs_interruptible, 1, "Allow requests to be interrupted by signal"); +int autofs_obsolete_lookup = 0; +TUNABLE_INT("vfs.autofs.obsolete_lookup", &autofs_obsolete_lookup); +SYSCTL_INT(_vfs_autofs, OID_AUTO, obsolete_lookup, CTLFLAG_RWTUN, + &autofs_obsolete_lookup, 0, "Use the old way of interacting " + "with lookup(9)"); int autofs_init(struct vfsconf *vfsp) Index: sys/fs/autofs/autofs_vnops.c =================================================================== --- sys/fs/autofs/autofs_vnops.c +++ sys/fs/autofs/autofs_vnops.c @@ -257,23 +257,33 @@ return (error); if (newvp != NULL) { - error = VOP_LOOKUP(newvp, ap->a_vpp, ap->a_cnp); + if (autofs_obsolete_lookup) { + 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. - */ - lock_flags = VOP_ISLOCKED(newvp); - if (lock_flags == 0) { - VOP_UNLOCK(dvp, 0); - vrele(newvp); + /* + * 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. + */ + lock_flags = VOP_ISLOCKED(newvp); + if (lock_flags == 0) { + VOP_UNLOCK(dvp, 0); + vrele(newvp); + } else { + vput(newvp); + } + return (error); } else { + /* + * The target filesystem got automounted. + * Let the lookup(9) go around with the same + * path component. + */ vput(newvp); + return (ERELOOKUP); } - return (error); } } Index: sys/fs/nullfs/null_vnops.c =================================================================== --- sys/fs/nullfs/null_vnops.c +++ sys/fs/nullfs/null_vnops.c @@ -429,6 +429,16 @@ *ap->a_vpp = vp; } } + + if (error == ERELOOKUP) { + /* + * Nullfs is not supposed to cross mount points, and returning + * ERELOOKUP here would end up triggering an inifinite lookup + * loop anyway; explicitly disallow this case. + */ + error = EOPNOTSUPP; + } + return (error); } Index: sys/fs/unionfs/union_vnops.c =================================================================== --- sys/fs/unionfs/union_vnops.c +++ sys/fs/unionfs/union_vnops.c @@ -174,6 +174,15 @@ if (udvp != NULLVP) { uerror = VOP_LOOKUP(udvp, &uvp, cnp); + if (uerror == ERELOOKUP) { + /* + * Unionfs is not supposed to cross mount points, and returning + * ERELOOKUP here would end up triggering an inifinite lookup + * loop anyway; explicitly disallow this case. + */ + uerror = EOPNOTSUPP; + } + if (uerror == 0) { if (udvp == uvp) { /* is dot */ vrele(uvp); @@ -213,6 +222,15 @@ lerror = VOP_LOOKUP(ldvp, &lvp, cnp); + if (lerror == ERELOOKUP) { + /* + * Unionfs is not supposed to cross mount points, and returning + * ERELOOKUP here would end up triggering an inifinite lookup + * loop anyway; explicitly disallow this case. + */ + lerror = EOPNOTSUPP; + } + cnp->cn_nameiop = nameiop; if (udvp != NULLVP && (uerror == 0 || uerror == EJUSTRETURN)) cnp->cn_flags = cnflagsbk; Index: sys/kern/vfs_lookup.c =================================================================== --- sys/kern/vfs_lookup.c +++ sys/kern/vfs_lookup.c @@ -495,6 +495,7 @@ 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; @@ -732,6 +733,13 @@ #ifdef NAMEI_DIAGNOSTIC printf("not found\n"); #endif + if (error == ERELOOKUP) { + vref(dp); + ndp->ni_vp = dp; + error = 0; + relookup = 1; + goto good; + } if ((error == ENOENT) && (dp->v_vflag & VV_ROOT) && (dp->v_mount != NULL) && (dp->v_mount->mnt_flag & MNT_UNION)) { @@ -777,6 +785,8 @@ goto success; } else cnp->cn_lkflags = lkflags_save; + +good: #ifdef NAMEI_DIAGNOSTIC printf("found\n"); #endif @@ -856,6 +866,14 @@ */ 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 == '/') { Index: sys/sys/errno.h =================================================================== --- sys/sys/errno.h +++ sys/sys/errno.h @@ -190,6 +190,7 @@ #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