sys/vfs/union/union_vnops.c
static int
union_lookup1(struct vnode *udvp, struct vnode **pdvp, struct vnode **vpp,
	      struct componentname *cnp)
{
	int error;
	struct thread *td = cnp->cn_td;
	struct vnode *dvp = *pdvp;
	struct vnode *tdvp;
	struct mount *mp;

	/*
	 * If stepping up the directory tree, check for going
	 * back across the mount point, in which case do what
	 * lookup would do by stepping back down the mount
	 * hierarchy.
	 */
	if (cnp->cn_flags & CNP_ISDOTDOT) {
		while ((dvp != udvp) && (dvp->v_flag & VROOT)) {
			/*
			 * Don't do the NOCROSSMOUNT check
			 * at this level.  By definition,
			 * union fs deals with namespaces, not
			 * filesystems.
			 */
			tdvp = dvp;
			dvp = dvp->v_mount->mnt_vnodecovered;
			vref(dvp);
			vput(tdvp);
			vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
		}
	}

	/*
	 * Set return dvp to be the upperdvp 'parent directory.
	 */
	*pdvp = dvp;

	/*
	 * If the VOP_LOOKUP call generates an error, tdvp is invalid and no
	 * changes will have been made to dvp, so we are set to return.
	 */

        error = VOP_LOOKUP(dvp, &tdvp, cnp);
	if (error) {
		UDEBUG(("dvp %p error %d flags %lx\n", dvp, error, cnp->cn_flags));
		*vpp = NULL;
		return (error);
	}

	/*
	 * The parent directory will have been unlocked, unless lookup
	 * found the last component or if dvp == tdvp (tdvp must be locked).
	 *
	 * We want our dvp to remain locked and ref'd.  We also want tdvp
	 * to remain locked and ref'd.
	 */
	UDEBUG(("parentdir %p result %p flag %lx\n", dvp, tdvp, cnp->cn_flags));

#if 0
	if (dvp != tdvp && (cnp->cn_flags & CNP_XXXISLASTCN) == 0)
		vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
#endif

	/*
	 * Lastly check if the current node is a mount point in
	 * which case walk up the mount hierarchy making sure not to
	 * bump into the root of the mount tree (ie. dvp != udvp).
	 *
	 * We use dvp as a temporary variable here, it is no longer related
	 * to the dvp above.  However, we have to ensure that both *pdvp and
	 * tdvp are locked on return.
	 */

	dvp = tdvp;
	while (
	    dvp != udvp && 
	    (dvp->v_type == VDIR) &&
	    (mp = dvp->v_mountedhere)
	) {
		int relock_pdvp = 0;

		if (vfs_busy(mp, 0))
			continue;

		if (dvp == *pdvp)
			relock_pdvp = 1;
		vput(dvp);
		dvp = NULL;
		error = VFS_ROOT(mp, &dvp);

		vfs_unbusy(mp);

		if (relock_pdvp)
			vn_lock(*pdvp, LK_EXCLUSIVE | LK_RETRY);

		if (error) {
			*vpp = NULL;
			return (error);
		}
	}
	*vpp = dvp;
	return (0);
}
/*
 *	union_lookup:
 *
 *	udvp	must be exclusively locked on call and will remain 
 *		exclusively locked on return.  This is the mount point 
 *		for out filesystem.
 *
 *	dvp	Our base directory, locked and referenced.
 *		The passed dvp will be dereferenced and unlocked on return
 *		and a new dvp will be returned which is locked and 
 *		referenced in the same variable.
 *
 *	vpp	is filled in with the result if no error occured,
 *		locked and ref'd.
 *
 *		If an error is returned, *vpp is set to NULLVP.  If no
 *		error occurs, *vpp is returned with a reference and an
 *		exclusive lock.
 */
udvp    must be exclusively locked on call and will remain
exclusively locked on return.  This is the mount point
for out filesystem.

dvp     Our base directory, locked and referenced.
The passed dvp will be dereferenced and unlocked on return
and a new dvp will be returned which is locked and
referenced in the same variable.

vpp     is filled in with the result if no error occured,
locked and ref'd.

If an error is returned, *vpp is set to NULLVP.  If no
error occurs, *vpp is returned with a reference and an
exclusive lock.
udvp must be exclusively locked on call and will remain exclusively locked on return . This is the mount point for out filesystem . dvp Our base directory locked and referenced . The passed dvp will be dereferenced and unlocked on return and a new dvp will be returned which is locked and referenced in the same variable . vpp is filled in with the result if no error occured locked and ref ' d . If an error is returned * vpp is set to NULLVP . If no error occurs * vpp is returned with a reference and an exclusive lock .
static int
union_lookup1(struct vnode *udvp, struct vnode **pdvp, struct vnode **vpp,
	      struct componentname *cnp)
{
	int error;
	struct thread *td = cnp->cn_td;
	struct vnode *dvp = *pdvp;
	struct vnode *tdvp;
	struct mount *mp;
	if (cnp->cn_flags & CNP_ISDOTDOT) {
		while ((dvp != udvp) && (dvp->v_flag & VROOT)) {
			tdvp = dvp;
			dvp = dvp->v_mount->mnt_vnodecovered;
			vref(dvp);
			vput(tdvp);
			vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
		}
	}
	*pdvp = dvp;
        error = VOP_LOOKUP(dvp, &tdvp, cnp);
	if (error) {
		UDEBUG(("dvp %p error %d flags %lx\n", dvp, error, cnp->cn_flags));
		*vpp = NULL;
		return (error);
	}
	UDEBUG(("parentdir %p result %p flag %lx\n", dvp, tdvp, cnp->cn_flags));
#if 0
	if (dvp != tdvp && (cnp->cn_flags & CNP_XXXISLASTCN) == 0)
		vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
#endif
	dvp = tdvp;
	while (
	    dvp != udvp && 
	    (dvp->v_type == VDIR) &&
	    (mp = dvp->v_mountedhere)
	) {
		int relock_pdvp = 0;
		if (vfs_busy(mp, 0))
			continue;
		if (dvp == *pdvp)
			relock_pdvp = 1;
		vput(dvp);
		dvp = NULL;
		error = VFS_ROOT(mp, &dvp);
		vfs_unbusy(mp);
		if (relock_pdvp)
			vn_lock(*pdvp, LK_EXCLUSIVE | LK_RETRY);
		if (error) {
			*vpp = NULL;
			return (error);
		}
	}
	*vpp = dvp;
	return (0);
}
static int union_lookup1 ( struct vnode * udvp , struct vnode * * pdvp , struct vnode * * vpp , struct componentname * cnp ) { int error ; struct thread * td = cnp -> cn_td ; struct vnode * dvp = * pdvp ; struct vnode * tdvp ; struct mount * mp ; if ( cnp -> cn_flags & CNP_ISDOTDOT ) { while ( ( dvp != udvp ) && ( dvp -> v_flag & VROOT ) ) { tdvp = dvp ; dvp = dvp -> v_mount -> mnt_vnodecovered ; vref ( dvp ) ; vput ( tdvp ) ; vn_lock ( dvp , LK_EXCLUSIVE | LK_RETRY ) ; } } * pdvp = dvp ; error = VOP_LOOKUP ( dvp , & tdvp , cnp ) ; if ( error ) { UDEBUG ( ( " \n " , dvp , error , cnp -> cn_flags ) ) ; * vpp = NULL ; return ( error ) ; } UDEBUG ( ( " \n " , dvp , tdvp , cnp -> cn_flags ) ) ; #if 0 if ( dvp != tdvp && ( cnp -> cn_flags & CNP_XXXISLASTCN ) == 0 ) vn_lock ( dvp , LK_EXCLUSIVE | LK_RETRY ) ; #endif dvp = tdvp ; while ( dvp != udvp && ( dvp -> v_type == VDIR ) && ( mp = dvp -> v_mountedhere ) ) { int relock_pdvp = 0 ; if ( vfs_busy ( mp , 0 ) ) continue ; if ( dvp == * pdvp ) relock_pdvp = 1 ; vput ( dvp ) ; dvp = NULL ; error = VFS_ROOT ( mp , & dvp ) ; vfs_unbusy ( mp ) ; if ( relock_pdvp ) vn_lock ( * pdvp , LK_EXCLUSIVE | LK_RETRY ) ; if ( error ) { * vpp = NULL ; return ( error ) ; } } * vpp = dvp ; return ( 0 ) ; }
union_lookup:
      udvp    must be exclusively locked on call and will remain
              exclusively locked on return.
union_lookup : udvp must be exclusively locked on call and will remain exclusively locked on return .
/*
	 * If stepping up the directory tree, check for going
	 * back across the mount point, in which case do what
	 * lookup would do by stepping back down the mount
	 * hierarchy.
	 */ /*
			 * Don't do the NOCROSSMOUNT check
			 * at this level.  By definition,
			 * union fs deals with namespaces, not
			 * filesystems.
			 */ /*
	 * Set return dvp to be the upperdvp 'parent directory.
	 */ /*
	 * If the VOP_LOOKUP call generates an error, tdvp is invalid and no
	 * changes will have been made to dvp, so we are set to return.
	 */ /*
	 * The parent directory will have been unlocked, unless lookup
	 * found the last component or if dvp == tdvp (tdvp must be locked).
	 *
	 * We want our dvp to remain locked and ref'd.  We also want tdvp
	 * to remain locked and ref'd.
	 */ /*
	 * Lastly check if the current node is a mount point in
	 * which case walk up the mount hierarchy making sure not to
	 * bump into the root of the mount tree (ie. dvp != udvp).
	 *
	 * We use dvp as a temporary variable here, it is no longer related
	 * to the dvp above.  However, we have to ensure that both *pdvp and
	 * tdvp are locked on return.
	 */