FreeBSD/sys/fs/unionfs/union_subr.c
/*
 * Make a new or get existing unionfs node.
 * 
 * uppervp and lowervp should be unlocked. Because if new unionfs vnode is
 * locked, uppervp or lowervp is locked too. In order to prevent dead lock,
 * you should not lock plurality simultaneously.
 */
Make a new or get existing unionfs node.

uppervp and lowervp should be unlocked. Because if new unionfs vnode is
locked, uppervp or lowervp is locked too. In order to prevent dead lock,
you should not lock plurality simultaneously.
Make a new or get existing unionfs node . uppervp and lowervp should be unlocked . Because if new unionfs vnode is locked uppervp or lowervp is locked too . In order to prevent dead lock you should not lock plurality simultaneously .
int
unionfs_nodeget(struct mount *mp, struct vnode *uppervp,
		struct vnode *lowervp, struct vnode *dvp,
		struct vnode **vpp, struct componentname *cnp,
		struct thread *td)
{
	struct unionfs_mount *ump;
	struct unionfs_node *unp;
	struct vnode   *vp;
	int		error;
	int		lkflags;
	enum vtype	vt;
	char	       *path;
	ump = MOUNTTOUNIONFSMOUNT(mp);
	lkflags = (cnp ? cnp->cn_lkflags : 0);
	path = (cnp ? cnp->cn_nameptr : NULL);
	*vpp = NULLVP;
	if (uppervp == NULLVP && lowervp == NULLVP)
		panic("unionfs_nodeget: upper and lower is null");
	vt = (uppervp != NULLVP ? uppervp->v_type : lowervp->v_type);
	if (cnp && !(cnp->cn_flags & ISLASTCN))
		path = NULL;
	if (path != NULL && dvp != NULLVP && vt == VDIR) {
		vp = unionfs_get_cached_vnode(uppervp, lowervp, dvp, path);
		if (vp != NULLVP) {
			vref(vp);
			*vpp = vp;
			goto unionfs_nodeget_out;
		}
	}
	if ((uppervp == NULLVP || ump->um_uppervp != uppervp) ||
	    (lowervp == NULLVP || ump->um_lowervp != lowervp)) {
		if (dvp == NULLVP)
			return (EINVAL);
	}
	unp = malloc(sizeof(struct unionfs_node),
	    M_UNIONFSNODE, M_WAITOK | M_ZERO);
	error = getnewvnode("unionfs", mp, &unionfs_vnodeops, &vp);
	if (error != 0) {
		free(unp, M_UNIONFSNODE);
		return (error);
	}
	error = insmntque(vp, mp);	
	if (error != 0) {
		free(unp, M_UNIONFSNODE);
		return (error);
	}
	if (dvp != NULLVP)
		vref(dvp);
	if (uppervp != NULLVP)
		vref(uppervp);
	if (lowervp != NULLVP)
		vref(lowervp);
	if (vt == VDIR)
		unp->un_hashtbl = hashinit(NUNIONFSNODECACHE, M_UNIONFSHASH,
		    &(unp->un_hashmask));
	unp->un_vnode = vp;
	unp->un_uppervp = uppervp;
	unp->un_lowervp = lowervp;
	unp->un_dvp = dvp;
	if (uppervp != NULLVP)
		vp->v_vnlock = uppervp->v_vnlock;
	else
		vp->v_vnlock = lowervp->v_vnlock;
	if (path != NULL) {
		unp->un_path = (char *)
		    malloc(cnp->cn_namelen +1, M_UNIONFSPATH, M_WAITOK|M_ZERO);
		bcopy(cnp->cn_nameptr, unp->un_path, cnp->cn_namelen);
		unp->un_path[cnp->cn_namelen] = '\0';
	}
	vp->v_type = vt;
	vp->v_data = unp;
	if ((uppervp != NULLVP && ump->um_uppervp == uppervp) &&
	    (lowervp != NULLVP && ump->um_lowervp == lowervp))
		vp->v_vflag |= VV_ROOT;
	if (path != NULL && dvp != NULLVP && vt == VDIR)
		*vpp = unionfs_ins_cached_vnode(unp, dvp, path);
	if ((*vpp) != NULLVP) {
		if (dvp != NULLVP)
			vrele(dvp);
		if (uppervp != NULLVP)
			vrele(uppervp);
		if (lowervp != NULLVP)
			vrele(lowervp);
		unp->un_uppervp = NULLVP;
		unp->un_lowervp = NULLVP;
		unp->un_dvp = NULLVP;
		vrele(vp);
		vp = *vpp;
		vref(vp);
	} else
		*vpp = vp;
unionfs_nodeget_out:
	if (lkflags & LK_TYPE_MASK)
		vn_lock(vp, lkflags | LK_RETRY);
	return (0);
}
int unionfs_nodeget ( struct mount * mp , struct vnode * uppervp , struct vnode * lowervp , struct vnode * dvp , struct vnode * * vpp , struct componentname * cnp , struct thread * td ) { struct unionfs_mount * ump ; struct unionfs_node * unp ; struct vnode * vp ; int error ; int lkflags ; enum vtype vt ; char * path ; ump = MOUNTTOUNIONFSMOUNT ( mp ) ; lkflags = ( cnp ? cnp -> cn_lkflags : 0 ) ; path = ( cnp ? cnp -> cn_nameptr : NULL ) ; * vpp = NULLVP ; if ( uppervp == NULLVP && lowervp == NULLVP ) panic ( " " ) ; vt = ( uppervp != NULLVP ? uppervp -> v_type : lowervp -> v_type ) ; if ( cnp && ! ( cnp -> cn_flags & ISLASTCN ) ) path = NULL ; if ( path != NULL && dvp != NULLVP && vt == VDIR ) { vp = unionfs_get_cached_vnode ( uppervp , lowervp , dvp , path ) ; if ( vp != NULLVP ) { vref ( vp ) ; * vpp = vp ; goto unionfs_nodeget_out ; } } if ( ( uppervp == NULLVP || ump -> um_uppervp != uppervp ) || ( lowervp == NULLVP || ump -> um_lowervp != lowervp ) ) { if ( dvp == NULLVP ) return ( EINVAL ) ; } unp = malloc ( sizeof ( struct unionfs_node ) , M_UNIONFSNODE , M_WAITOK | M_ZERO ) ; error = getnewvnode ( " " , mp , & unionfs_vnodeops , & vp ) ; if ( error != 0 ) { free ( unp , M_UNIONFSNODE ) ; return ( error ) ; } error = insmntque ( vp , mp ) ; if ( error != 0 ) { free ( unp , M_UNIONFSNODE ) ; return ( error ) ; } if ( dvp != NULLVP ) vref ( dvp ) ; if ( uppervp != NULLVP ) vref ( uppervp ) ; if ( lowervp != NULLVP ) vref ( lowervp ) ; if ( vt == VDIR ) unp -> un_hashtbl = hashinit ( NUNIONFSNODECACHE , M_UNIONFSHASH , & ( unp -> un_hashmask ) ) ; unp -> un_vnode = vp ; unp -> un_uppervp = uppervp ; unp -> un_lowervp = lowervp ; unp -> un_dvp = dvp ; if ( uppervp != NULLVP ) vp -> v_vnlock = uppervp -> v_vnlock ; else vp -> v_vnlock = lowervp -> v_vnlock ; if ( path != NULL ) { unp -> un_path = ( char * ) malloc ( cnp -> cn_namelen + 1 , M_UNIONFSPATH , M_WAITOK | M_ZERO ) ; bcopy ( cnp -> cn_nameptr , unp -> un_path , cnp -> cn_namelen ) ; unp -> un_path [ cnp -> cn_namelen ] = ' \0 ' ; } vp -> v_type = vt ; vp -> v_data = unp ; if ( ( uppervp != NULLVP && ump -> um_uppervp == uppervp ) && ( lowervp != NULLVP && ump -> um_lowervp == lowervp ) ) vp -> v_vflag |= VV_ROOT ; if ( path != NULL && dvp != NULLVP && vt == VDIR ) * vpp = unionfs_ins_cached_vnode ( unp , dvp , path ) ; if ( ( * vpp ) != NULLVP ) { if ( dvp != NULLVP ) vrele ( dvp ) ; if ( uppervp != NULLVP ) vrele ( uppervp ) ; if ( lowervp != NULLVP ) vrele ( lowervp ) ; unp -> un_uppervp = NULLVP ; unp -> un_lowervp = NULLVP ; unp -> un_dvp = NULLVP ; vrele ( vp ) ; vp = * vpp ; vref ( vp ) ; } else * vpp = vp ; unionfs_nodeget_out : if ( lkflags & LK_TYPE_MASK ) vn_lock ( vp , lkflags | LK_RETRY ) ; return ( 0 ) ; }
Make a new or get existing unionfs node.
Make a new or get existing unionfs node .
/* If it has no ISLASTCN flag, path check is skipped. */ /* check the cache */ /* dvp will be NULLVP only in case of root vnode. */ /* XXX: Too early for mpsafe fs */