FreeBSD/sys/fs/tmpfs/tmpfs_subr.c
/*
 * Allocates a new vnode for the node node or returns a new reference to
 * an existing one if the node had already a vnode referencing it.  The
 * resulting locked vnode is returned in *vpp.
 *
 * Returns zero on success or an appropriate error code on failure.
 */
Allocates a new vnode for the node node or returns a new reference to
an existing one if the node had already a vnode referencing it.  The
resulting locked vnode is returned in *vpp.

Returns zero on success or an appropriate error code on failure.
Allocates a new vnode for the node node or returns a new reference to an existing one if the node had already a vnode referencing it . The resulting locked vnode is returned in * vpp . Returns zero on success or an appropriate error code on failure .
int
tmpfs_alloc_vp(struct mount *mp, struct tmpfs_node *node, int lkflag,
    struct vnode **vpp)
{
	struct vnode *vp;
	vm_object_t object;
	int error;
	error = 0;
loop:
	TMPFS_NODE_LOCK(node);
loop1:
	if ((vp = node->tn_vnode) != NULL) {
		MPASS((node->tn_vpstate & TMPFS_VNODE_DOOMED) == 0);
		VI_LOCK(vp);
		if ((node->tn_type == VDIR && node->tn_dir.tn_parent == NULL) ||
		    ((vp->v_iflag & VI_DOOMED) != 0 &&
		    (lkflag & LK_NOWAIT) != 0)) {
			VI_UNLOCK(vp);
			TMPFS_NODE_UNLOCK(node);
			error = ENOENT;
			vp = NULL;
			goto out;
		}
		if ((vp->v_iflag & VI_DOOMED) != 0) {
			VI_UNLOCK(vp);
			node->tn_vpstate |= TMPFS_VNODE_WRECLAIM;
			while ((node->tn_vpstate & TMPFS_VNODE_WRECLAIM) != 0) {
				msleep(&node->tn_vnode, TMPFS_NODE_MTX(node),
				    0, "tmpfsE", 0);
			}
			goto loop1;
		}
		TMPFS_NODE_UNLOCK(node);
		error = vget(vp, lkflag | LK_INTERLOCK, curthread);
		if (error == ENOENT)
			goto loop;
		if (error != 0) {
			vp = NULL;
			goto out;
		}
		if (node->tn_vnode == NULL || node->tn_vnode != vp) {
			vput(vp);
			goto loop;
		}
		goto out;
	}
	if ((node->tn_vpstate & TMPFS_VNODE_DOOMED) ||
	    (node->tn_type == VDIR && node->tn_dir.tn_parent == NULL)) {
		TMPFS_NODE_UNLOCK(node);
		error = ENOENT;
		vp = NULL;
		goto out;
	}
	if (node->tn_vpstate & TMPFS_VNODE_ALLOCATING) {
		node->tn_vpstate |= TMPFS_VNODE_WANT;
		error = msleep((caddr_t) &node->tn_vpstate,
		    TMPFS_NODE_MTX(node), PDROP | PCATCH,
		    "tmpfs_alloc_vp", 0);
		if (error)
			return error;
		goto loop;
	} else
		node->tn_vpstate |= TMPFS_VNODE_ALLOCATING;
	TMPFS_NODE_UNLOCK(node);
	error = getnewvnode("tmpfs", mp, &tmpfs_vnodeop_entries, &vp);
	if (error != 0)
		goto unlock;
	MPASS(vp != NULL);
	(void) vn_lock(vp, lkflag | LK_RETRY);
	vp->v_data = node;
	vp->v_type = node->tn_type;
	switch (node->tn_type) {
	case VBLK:
	case VCHR:
	case VLNK:
	case VSOCK:
		break;
	case VFIFO:
		vp->v_op = &tmpfs_fifoop_entries;
		break;
	case VREG:
		object = node->tn_reg.tn_aobj;
		VM_OBJECT_WLOCK(object);
		VI_LOCK(vp);
		KASSERT(vp->v_object == NULL, ("Not NULL v_object in tmpfs"));
		vp->v_object = object;
		object->un_pager.swp.swp_tmpfs = vp;
		vm_object_set_flag(object, OBJ_TMPFS);
		VI_UNLOCK(vp);
		VM_OBJECT_WUNLOCK(object);
		break;
	case VDIR:
		MPASS(node->tn_dir.tn_parent != NULL);
		if (node->tn_dir.tn_parent == node)
			vp->v_vflag |= VV_ROOT;
		break;
	default:
		panic("tmpfs_alloc_vp: type %p %d", node, (int)node->tn_type);
	}
	if (vp->v_type != VFIFO)
		VN_LOCK_ASHARE(vp);
	error = insmntque1(vp, mp, tmpfs_insmntque_dtr, NULL);
	if (error)
		vp = NULL;
unlock:
	TMPFS_NODE_LOCK(node);
	MPASS(node->tn_vpstate & TMPFS_VNODE_ALLOCATING);
	node->tn_vpstate &= ~TMPFS_VNODE_ALLOCATING;
	node->tn_vnode = vp;
	if (node->tn_vpstate & TMPFS_VNODE_WANT) {
		node->tn_vpstate &= ~TMPFS_VNODE_WANT;
		TMPFS_NODE_UNLOCK(node);
		wakeup((caddr_t) &node->tn_vpstate);
	} else
		TMPFS_NODE_UNLOCK(node);
out:
	*vpp = vp;
#ifdef INVARIANTS
	if (error == 0) {
		MPASS(*vpp != NULL && VOP_ISLOCKED(*vpp));
		TMPFS_NODE_LOCK(node);
		MPASS(*vpp == node->tn_vnode);
		TMPFS_NODE_UNLOCK(node);
	}
#endif
	return error;
}
int tmpfs_alloc_vp ( struct mount * mp , struct tmpfs_node * node , int lkflag , struct vnode * * vpp ) { struct vnode * vp ; vm_object_t object ; int error ; error = 0 ; loop : TMPFS_NODE_LOCK ( node ) ; loop1 : if ( ( vp = node -> tn_vnode ) != NULL ) { MPASS ( ( node -> tn_vpstate & TMPFS_VNODE_DOOMED ) == 0 ) ; VI_LOCK ( vp ) ; if ( ( node -> tn_type == VDIR && node -> tn_dir . tn_parent == NULL ) || ( ( vp -> v_iflag & VI_DOOMED ) != 0 && ( lkflag & LK_NOWAIT ) != 0 ) ) { VI_UNLOCK ( vp ) ; TMPFS_NODE_UNLOCK ( node ) ; error = ENOENT ; vp = NULL ; goto out ; } if ( ( vp -> v_iflag & VI_DOOMED ) != 0 ) { VI_UNLOCK ( vp ) ; node -> tn_vpstate |= TMPFS_VNODE_WRECLAIM ; while ( ( node -> tn_vpstate & TMPFS_VNODE_WRECLAIM ) != 0 ) { msleep ( & node -> tn_vnode , TMPFS_NODE_MTX ( node ) , 0 , " " , 0 ) ; } goto loop1 ; } TMPFS_NODE_UNLOCK ( node ) ; error = vget ( vp , lkflag | LK_INTERLOCK , curthread ) ; if ( error == ENOENT ) goto loop ; if ( error != 0 ) { vp = NULL ; goto out ; } if ( node -> tn_vnode == NULL || node -> tn_vnode != vp ) { vput ( vp ) ; goto loop ; } goto out ; } if ( ( node -> tn_vpstate & TMPFS_VNODE_DOOMED ) || ( node -> tn_type == VDIR && node -> tn_dir . tn_parent == NULL ) ) { TMPFS_NODE_UNLOCK ( node ) ; error = ENOENT ; vp = NULL ; goto out ; } if ( node -> tn_vpstate & TMPFS_VNODE_ALLOCATING ) { node -> tn_vpstate |= TMPFS_VNODE_WANT ; error = msleep ( ( caddr_t ) & node -> tn_vpstate , TMPFS_NODE_MTX ( node ) , PDROP | PCATCH , " " , 0 ) ; if ( error ) return error ; goto loop ; } else node -> tn_vpstate |= TMPFS_VNODE_ALLOCATING ; TMPFS_NODE_UNLOCK ( node ) ; error = getnewvnode ( " " , mp , & tmpfs_vnodeop_entries , & vp ) ; if ( error != 0 ) goto unlock ; MPASS ( vp != NULL ) ; ( void ) vn_lock ( vp , lkflag | LK_RETRY ) ; vp -> v_data = node ; vp -> v_type = node -> tn_type ; switch ( node -> tn_type ) { case VBLK : case VCHR : case VLNK : case VSOCK : break ; case VFIFO : vp -> v_op = & tmpfs_fifoop_entries ; break ; case VREG : object = node -> tn_reg . tn_aobj ; VM_OBJECT_WLOCK ( object ) ; VI_LOCK ( vp ) ; KASSERT ( vp -> v_object == NULL , ( " " ) ) ; vp -> v_object = object ; object -> un_pager . swp . swp_tmpfs = vp ; vm_object_set_flag ( object , OBJ_TMPFS ) ; VI_UNLOCK ( vp ) ; VM_OBJECT_WUNLOCK ( object ) ; break ; case VDIR : MPASS ( node -> tn_dir . tn_parent != NULL ) ; if ( node -> tn_dir . tn_parent == node ) vp -> v_vflag |= VV_ROOT ; break ; default : panic ( " " , node , ( int ) node -> tn_type ) ; } if ( vp -> v_type != VFIFO ) VN_LOCK_ASHARE ( vp ) ; error = insmntque1 ( vp , mp , tmpfs_insmntque_dtr , NULL ) ; if ( error ) vp = NULL ; unlock : TMPFS_NODE_LOCK ( node ) ; MPASS ( node -> tn_vpstate & TMPFS_VNODE_ALLOCATING ) ; node -> tn_vpstate &= ~ TMPFS_VNODE_ALLOCATING ; node -> tn_vnode = vp ; if ( node -> tn_vpstate & TMPFS_VNODE_WANT ) { node -> tn_vpstate &= ~ TMPFS_VNODE_WANT ; TMPFS_NODE_UNLOCK ( node ) ; wakeup ( ( caddr_t ) & node -> tn_vpstate ) ; } else TMPFS_NODE_UNLOCK ( node ) ; out : * vpp = vp ; #ifdef INVARIANTS if ( error == 0 ) { MPASS ( * vpp != NULL && VOP_ISLOCKED ( * vpp ) ) ; TMPFS_NODE_LOCK ( node ) ; MPASS ( * vpp == node -> tn_vnode ) ; TMPFS_NODE_UNLOCK ( node ) ; } #endif return error ; }
Allocates a new vnode for the node node or returns a new reference to
 an existing one if the node had already a vnode referencing it.
Allocates a new vnode for the node node or returns a new reference to an existing one if the node had already a vnode referencing it .
/*
		 * Make sure the vnode is still there after
		 * getting the interlock to avoid racing a free.
		 */ /*
	 * otherwise lock the vp list while we call getnewvnode
	 * since that can block.
	 */ /* Get a new vnode and associate it with our node. */ /* lkflag is ignored, the lock is exclusive */ /* Type-specific initialization. */ /* FALLTHROUGH */ /* FALLTHROUGH */ /* FALLTHROUGH */