FreeBSD/sys/fs/tmpfs/tmpfs_subr.c
/*
 * Allocates a new node of type 'type' inside the 'tmp' mount point, with
 * its owner set to 'uid', its group to 'gid' and its mode set to 'mode',
 * using the credentials of the process 'p'.
 *
 * If the node type is set to 'VDIR', then the parent parameter must point
 * to the parent directory of the node being created.  It may only be NULL
 * while allocating the root node.
 *
 * If the node type is set to 'VBLK' or 'VCHR', then the rdev parameter
 * specifies the device the node represents.
 *
 * If the node type is set to 'VLNK', then the parameter target specifies
 * the file name of the target file for the symbolic link that is being
 * created.
 *
 * Note that new nodes are retrieved from the available list if it has
 * items or, if it is empty, from the node pool as long as there is enough
 * space to create them.
 *
 * Returns zero on success or an appropriate error code on failure.
 */


If the node type is set to 'VDIR', then the parent parameter must point
to the parent directory of the node being created.  It may only be NULL
while allocating the root node.

If the node type is set to 'VBLK' or 'VCHR', then the rdev parameter
specifies the device the node represents.

If the node type is set to 'VLNK', then the parameter target specifies
the file name of the target file for the symbolic link that is being
created.

Note that new nodes are retrieved from the available list if it has
items or, if it is empty, from the node pool as long as there is enough
space to create them.

Returns zero on success or an appropriate error code on failure.
If the node type is set to ' VDIR ' then the parent parameter must point to the parent directory of the node being created . It may only be NULL while allocating the root node . If the node type is set to ' VBLK ' or ' VCHR ' then the rdev parameter specifies the device the node represents . If the node type is set to ' VLNK ' then the parameter target specifies the file name of the target file for the symbolic link that is being created . Note that new nodes are retrieved from the available list if it has items or if it is empty from the node pool as long as there is enough space to create them . Returns zero on success or an appropriate error code on failure .
int
tmpfs_alloc_node(struct mount *mp, struct tmpfs_mount *tmp, enum vtype type,
    uid_t uid, gid_t gid, mode_t mode, struct tmpfs_node *parent,
    char *target, dev_t rdev, struct tmpfs_node **node)
{
	struct tmpfs_node *nnode;
	vm_object_t obj;
	MPASS(IMPLIES(tmp->tm_root == NULL, parent == NULL && type == VDIR));
	KASSERT(tmp->tm_root == NULL || mp->mnt_writeopcount > 0,
	    ("creating node not under vn_start_write"));
	MPASS(IFF(type == VLNK, target != NULL));
	MPASS(IFF(type == VBLK || type == VCHR, rdev != VNOVAL));
	if (tmp->tm_nodes_inuse >= tmp->tm_nodes_max)
		return (ENOSPC);
	if (tmpfs_pages_check_avail(tmp, 1) == 0)
		return (ENOSPC);
	if ((mp->mnt_kern_flag & MNTK_UNMOUNT) != 0) {
		return (EBUSY);
	}
	nnode = (struct tmpfs_node *)uma_zalloc_arg(
				tmp->tm_node_pool, tmp, M_WAITOK);
	nnode->tn_type = type;
	vfs_timestamp(&nnode->tn_atime);
	nnode->tn_birthtime = nnode->tn_ctime = nnode->tn_mtime =
	    nnode->tn_atime;
	nnode->tn_uid = uid;
	nnode->tn_gid = gid;
	nnode->tn_mode = mode;
	nnode->tn_id = alloc_unr(tmp->tm_ino_unr);
	switch (nnode->tn_type) {
	case VBLK:
	case VCHR:
		nnode->tn_rdev = rdev;
		break;
	case VDIR:
		RB_INIT(&nnode->tn_dir.tn_dirhead);
		LIST_INIT(&nnode->tn_dir.tn_dupindex);
		MPASS(parent != nnode);
		MPASS(IMPLIES(parent == NULL, tmp->tm_root == NULL));
		nnode->tn_dir.tn_parent = (parent == NULL) ? nnode : parent;
		nnode->tn_dir.tn_readdir_lastn = 0;
		nnode->tn_dir.tn_readdir_lastp = NULL;
		nnode->tn_links++;
		TMPFS_NODE_LOCK(nnode->tn_dir.tn_parent);
		nnode->tn_dir.tn_parent->tn_links++;
		TMPFS_NODE_UNLOCK(nnode->tn_dir.tn_parent);
		break;
	case VFIFO:
	case VSOCK:
		break;
	case VLNK:
		MPASS(strlen(target) < MAXPATHLEN);
		nnode->tn_size = strlen(target);
		nnode->tn_link = malloc(nnode->tn_size, M_TMPFSNAME,
		    M_WAITOK);
		memcpy(nnode->tn_link, target, nnode->tn_size);
		break;
	case VREG:
		obj = nnode->tn_reg.tn_aobj =
		    vm_pager_allocate(OBJT_SWAP, NULL, 0, VM_PROT_DEFAULT, 0,
			NULL );
		VM_OBJECT_WLOCK(obj);
		vm_object_set_flag(obj, OBJ_NOSPLIT | OBJ_TMPFS_NODE);
		vm_object_clear_flag(obj, OBJ_ONEMAPPING);
		VM_OBJECT_WUNLOCK(obj);
		break;
	default:
		panic("tmpfs_alloc_node: type %p %d", nnode, (int)nnode->tn_type);
	}
	TMPFS_LOCK(tmp);
	LIST_INSERT_HEAD(&tmp->tm_nodes_used, nnode, tn_entries);
	tmp->tm_nodes_inuse++;
	TMPFS_UNLOCK(tmp);
	*node = nnode;
	return 0;
}
int tmpfs_alloc_node ( struct mount * mp , struct tmpfs_mount * tmp , enum vtype type , uid_t uid , gid_t gid , mode_t mode , struct tmpfs_node * parent , char * target , dev_t rdev , struct tmpfs_node * * node ) { struct tmpfs_node * nnode ; vm_object_t obj ; MPASS ( IMPLIES ( tmp -> tm_root == NULL , parent == NULL && type == VDIR ) ) ; KASSERT ( tmp -> tm_root == NULL || mp -> mnt_writeopcount > 0 , ( " " ) ) ; MPASS ( IFF ( type == VLNK , target != NULL ) ) ; MPASS ( IFF ( type == VBLK || type == VCHR , rdev != VNOVAL ) ) ; if ( tmp -> tm_nodes_inuse >= tmp -> tm_nodes_max ) return ( ENOSPC ) ; if ( tmpfs_pages_check_avail ( tmp , 1 ) == 0 ) return ( ENOSPC ) ; if ( ( mp -> mnt_kern_flag & MNTK_UNMOUNT ) != 0 ) { return ( EBUSY ) ; } nnode = ( struct tmpfs_node * ) uma_zalloc_arg ( tmp -> tm_node_pool , tmp , M_WAITOK ) ; nnode -> tn_type = type ; vfs_timestamp ( & nnode -> tn_atime ) ; nnode -> tn_birthtime = nnode -> tn_ctime = nnode -> tn_mtime = nnode -> tn_atime ; nnode -> tn_uid = uid ; nnode -> tn_gid = gid ; nnode -> tn_mode = mode ; nnode -> tn_id = alloc_unr ( tmp -> tm_ino_unr ) ; switch ( nnode -> tn_type ) { case VBLK : case VCHR : nnode -> tn_rdev = rdev ; break ; case VDIR : RB_INIT ( & nnode -> tn_dir . tn_dirhead ) ; LIST_INIT ( & nnode -> tn_dir . tn_dupindex ) ; MPASS ( parent != nnode ) ; MPASS ( IMPLIES ( parent == NULL , tmp -> tm_root == NULL ) ) ; nnode -> tn_dir . tn_parent = ( parent == NULL ) ? nnode : parent ; nnode -> tn_dir . tn_readdir_lastn = 0 ; nnode -> tn_dir . tn_readdir_lastp = NULL ; nnode -> tn_links ++ ; TMPFS_NODE_LOCK ( nnode -> tn_dir . tn_parent ) ; nnode -> tn_dir . tn_parent -> tn_links ++ ; TMPFS_NODE_UNLOCK ( nnode -> tn_dir . tn_parent ) ; break ; case VFIFO : case VSOCK : break ; case VLNK : MPASS ( strlen ( target ) < MAXPATHLEN ) ; nnode -> tn_size = strlen ( target ) ; nnode -> tn_link = malloc ( nnode -> tn_size , M_TMPFSNAME , M_WAITOK ) ; memcpy ( nnode -> tn_link , target , nnode -> tn_size ) ; break ; case VREG : obj = nnode -> tn_reg . tn_aobj = vm_pager_allocate ( OBJT_SWAP , NULL , 0 , VM_PROT_DEFAULT , 0 , NULL ) ; VM_OBJECT_WLOCK ( obj ) ; vm_object_set_flag ( obj , OBJ_NOSPLIT | OBJ_TMPFS_NODE ) ; vm_object_clear_flag ( obj , OBJ_ONEMAPPING ) ; VM_OBJECT_WUNLOCK ( obj ) ; break ; default : panic ( " " , nnode , ( int ) nnode -> tn_type ) ; } TMPFS_LOCK ( tmp ) ; LIST_INSERT_HEAD ( & tmp -> tm_nodes_used , nnode , tn_entries ) ; tmp -> tm_nodes_inuse ++ ; TMPFS_UNLOCK ( tmp ) ; * node = nnode ; return 0 ; }
Allocates a new node of type 'type' inside the 'tmp' mount point, with
 its owner set to 'uid', its group to 'gid' and its mode set to 'mode',
 using the credentials of the process 'p'.
Allocates a new node of type ' type ' inside the ' tmp ' mount point with its owner set to ' uid ' its group to ' gid ' and its mode set to ' mode ' using the credentials of the process ' p ' .
/* If the root directory of the 'tmp' file system is not yet
	 * allocated, this must be the request to do it. */ /*
		 * When a new tmpfs node is created for fully
		 * constructed mount point, there must be a parent
		 * node, which vnode is locked exclusively.  As
		 * consequence, if the unmount is executing in
		 * parallel, vflush() cannot reclaim the parent vnode.
		 * Due to this, the check for MNTK_UNMOUNT flag is not
		 * racy: if we did not see MNTK_UNMOUNT flag, then tmp
		 * cannot be destroyed until node construction is
		 * finished and the parent vnode unlocked.
		 *
		 * Tmpfs does not need to instantiate new nodes during
		 * unmount.
		 */ /* Generic initialization. */ /* Type-specific initialization. */ /* FALLTHROUGH */ /* XXXKIB - tmpfs needs swap reservation */ /* OBJ_TMPFS is set together with the setting of vp->v_object */