FreeBSD/sys/kern/subr_vmem.c
/*
 * vmem_bt_alloc:  Allocate a new page of boundary tags.
 *
 * On architectures with uma_small_alloc there is no recursion; no address
 * space need be allocated to allocate boundary tags.  For the others, we
 * must handle recursion.  Boundary tags are necessary to allocate new
 * boundary tags.
 *
 * UMA guarantees that enough tags are held in reserve to allocate a new
 * page of kva.  We dip into this reserve by specifying M_USE_RESERVE only
 * when allocating the page to hold new boundary tags.  In this way the
 * reserve is automatically filled by the allocation that uses the reserve.
 * 
 * We still have to guarantee that the new tags are allocated atomically since
 * many threads may try concurrently.  The bt_lock provides this guarantee.
 * We convert WAITOK allocations to NOWAIT and then handle the blocking here
 * on failure.  It's ok to return NULL for a WAITOK allocation as UMA will
 * loop again after checking to see if we lost the race to allocate.
 *
 * There is a small race between vmem_bt_alloc() returning the page and the
 * zone lock being acquired to add the page to the zone.  For WAITOK
 * allocations we just pause briefly.  NOWAIT may experience a transient
 * failure.  To alleviate this we permit a small number of simultaneous
 * fills to proceed concurrently so NOWAIT is less likely to fail unless
 * we are really out of KVA.
 */
Allocate a new page of boundary tags.
On architectures with uma_small_alloc there is no recursion; no address
space need be allocated to allocate boundary tags.  For the others, we
must handle recursion.  Boundary tags are necessary to allocate new
boundary tags.

UMA guarantees that enough tags are held in reserve to allocate a new
page of kva.  We dip into this reserve by specifying M_USE_RESERVE only
when allocating the page to hold new boundary tags.  In this way the
reserve is automatically filled by the allocation that uses the reserve.

We still have to guarantee that the new tags are allocated atomically since
many threads may try concurrently.  The bt_lock provides this guarantee.
We convert WAITOK allocations to NOWAIT and then handle the blocking here
on failure.  It's ok to return NULL for a WAITOK allocation as UMA will
loop again after checking to see if we lost the race to allocate.

There is a small race between vmem_bt_alloc() returning the page and the
zone lock being acquired to add the page to the zone.  For WAITOK
allocations we just pause briefly.  NOWAIT may experience a transient
failure.  To alleviate this we permit a small number of simultaneous
fills to proceed concurrently so NOWAIT is less likely to fail unless
we are really out of KVA.
Allocate a new page of boundary tags . On architectures with uma_small_alloc there is no recursion ; no address space need be allocated to allocate boundary tags . For the others we must handle recursion . Boundary tags are necessary to allocate new boundary tags . UMA guarantees that enough tags are held in reserve to allocate a new page of kva . We dip into this reserve by specifying M_USE_RESERVE only when allocating the page to hold new boundary tags . In this way the reserve is automatically filled by the allocation that uses the reserve . We still have to guarantee that the new tags are allocated atomically since many threads may try concurrently . The bt_lock provides this guarantee . We convert WAITOK allocations to NOWAIT and then handle the blocking here on failure . It ' s ok to return NULL for a WAITOK allocation as UMA will loop again after checking to see if we lost the race to allocate . There is a small race between vmem_bt_alloc () returning the page and the zone lock being acquired to add the page to the zone . For WAITOK allocations we just pause briefly . NOWAIT may experience a transient failure . To alleviate this we permit a small number of simultaneous fills to proceed concurrently so NOWAIT is less likely to fail unless we are really out of KVA .
static void *
vmem_bt_alloc(uma_zone_t zone, vm_size_t bytes, uint8_t *pflag, int wait)
{
	vmem_addr_t addr;
	*pflag = UMA_SLAB_KMEM;
	mtx_lock(&vmem_bt_lock);
	if (vmem_xalloc(kmem_arena, bytes, 0, 0, 0, VMEM_ADDR_MIN,
	    VMEM_ADDR_MAX, M_NOWAIT | M_NOVM | M_USE_RESERVE | M_BESTFIT,
	    &addr) == 0) {
		if (kmem_back(kmem_object, addr, bytes,
		    M_NOWAIT | M_USE_RESERVE) == 0) {
			mtx_unlock(&vmem_bt_lock);
			return ((void *)addr);
		}
		vmem_xfree(kmem_arena, addr, bytes);
		mtx_unlock(&vmem_bt_lock);
		if (wait & M_WAITOK)
			VM_WAIT;
		return (NULL);
	}
	mtx_unlock(&vmem_bt_lock);
	if (wait & M_WAITOK)
		pause("btalloc", 1);
	return (NULL);
}
static void * vmem_bt_alloc ( uma_zone_t zone , vm_size_t bytes , uint8_t * pflag , int wait ) { vmem_addr_t addr ; * pflag = UMA_SLAB_KMEM ; mtx_lock ( & vmem_bt_lock ) ; if ( vmem_xalloc ( kmem_arena , bytes , 0 , 0 , 0 , VMEM_ADDR_MIN , VMEM_ADDR_MAX , M_NOWAIT | M_NOVM | M_USE_RESERVE | M_BESTFIT , & addr ) == 0 ) { if ( kmem_back ( kmem_object , addr , bytes , M_NOWAIT | M_USE_RESERVE ) == 0 ) { mtx_unlock ( & vmem_bt_lock ) ; return ( ( void * ) addr ) ; } vmem_xfree ( kmem_arena , addr , bytes ) ; mtx_unlock ( & vmem_bt_lock ) ; if ( wait & M_WAITOK ) VM_WAIT ; return ( NULL ) ; } mtx_unlock ( & vmem_bt_lock ) ; if ( wait & M_WAITOK ) pause ( " " , 1 ) ; return ( NULL ) ; }
vmem_bt_alloc:  Allocate a new page of boundary tags.
vmem_bt_alloc : Allocate a new page of boundary tags .
/*
	 * Single thread boundary tag allocation so that the address space
	 * and memory are added in one atomic operation.
	 */ /*
		 * Out of memory, not address space.  This may not even be
		 * possible due to M_USE_RESERVE page allocation.
		 */ /*
	 * We're either out of address space or lost a fill race.
	 */