FreeBSD/sys/dev/xen/blkback/blkback.c
/**
 * Get Kernel Virtual Address space for mapping requests.
 *
 * \param xbb         Per-instance xbb configuration structure.
 * \param nr_pages    Number of pages needed.
 * \param check_only  If set, check for free KVA but don't allocate it.
 * \param have_lock   If set, xbb lock is already held.
 *
 * \return  On success, a pointer to the allocated KVA region.  Otherwise NULL.
 *
 * Note:  This should be unnecessary once we have either chaining or
 * scatter/gather support for struct bio.  At that point we'll be able to
 * put multiple addresses and lengths in one bio/bio chain and won't need
 * to map everything into one virtual segment.
 */
Get Kernel Virtual Address space for mapping requests.
\param xbb         Per-instance xbb configuration structure.
\param nr_pages    Number of pages needed.
\param check_only  If set, check for free KVA but don't allocate it.
\param have_lock   If set, xbb lock is already held.

\return  On success, a pointer to the allocated KVA region.  Otherwise NULL.

This should be unnecessary once we have either chaining or
scatter/gather support for struct bio.  At that point we'll be able to
put multiple addresses and lengths in one bio/bio chain and won't need
to map everything into one virtual segment.
Get Kernel Virtual Address space for mapping requests . \ param xbb Per - instance xbb configuration structure . \ param nr_pages Number of pages needed . \ param check_only If set check for free KVA but don ' t allocate it . \ param have_lock If set xbb lock is already held . \ return On success a pointer to the allocated KVA region . Otherwise NULL . This should be unnecessary once we have either chaining or scatter / gather support for struct bio . At that point we ' ll be able to put multiple addresses and lengths in one bio / bio chain and won ' t need to map everything into one virtual segment .
static uint8_t *
xbb_get_kva(struct xbb_softc *xbb, int nr_pages)
{
	int first_clear;
	int num_clear;
	uint8_t *free_kva;
	int      i;
	KASSERT(nr_pages != 0, ("xbb_get_kva of zero length"));
	first_clear = 0;
	free_kva = NULL;
	mtx_lock(&xbb->lock);
	bit_ffc(xbb->kva_free, xbb->reqlist_kva_pages, &first_clear);
	if (first_clear == -1)
		goto bailout;
	for (i = first_clear, num_clear = 0; i < xbb->reqlist_kva_pages; i++) {
		if (bit_test(xbb->kva_free, i)) {
			num_clear = 0;
			first_clear = -1;
			continue;
		}
		if (first_clear == -1)
			first_clear = i;
		if (++num_clear == nr_pages) {
			bit_nset(xbb->kva_free, first_clear,
				 first_clear + nr_pages - 1);
			free_kva = xbb->kva +
				(uint8_t *)((intptr_t)first_clear * PAGE_SIZE);
			KASSERT(free_kva >= (uint8_t *)xbb->kva &&
				free_kva + (nr_pages * PAGE_SIZE) <=
				(uint8_t *)xbb->ring_config.va,
				("Free KVA %p len %d out of range, "
				 "kva = %#jx, ring VA = %#jx\n", free_kva,
				 nr_pages * PAGE_SIZE, (uintmax_t)xbb->kva,
				 (uintmax_t)xbb->ring_config.va));
			break;
		}
	}
bailout:
	if (free_kva == NULL) {
		xbb->flags |= XBBF_RESOURCE_SHORTAGE;
		xbb->kva_shortages++;
	}
	mtx_unlock(&xbb->lock);
	return (free_kva);
}
static uint8_t * xbb_get_kva ( struct xbb_softc * xbb , int nr_pages ) { int first_clear ; int num_clear ; uint8_t * free_kva ; int i ; KASSERT ( nr_pages != 0 , ( " " ) ) ; first_clear = 0 ; free_kva = NULL ; mtx_lock ( & xbb -> lock ) ; bit_ffc ( xbb -> kva_free , xbb -> reqlist_kva_pages , & first_clear ) ; if ( first_clear == -1 ) goto bailout ; for ( i = first_clear , num_clear = 0 ; i < xbb -> reqlist_kva_pages ; i ++ ) { if ( bit_test ( xbb -> kva_free , i ) ) { num_clear = 0 ; first_clear = -1 ; continue ; } if ( first_clear == -1 ) first_clear = i ; if ( ++ num_clear == nr_pages ) { bit_nset ( xbb -> kva_free , first_clear , first_clear + nr_pages - 1 ) ; free_kva = xbb -> kva + ( uint8_t * ) ( ( intptr_t ) first_clear * PAGE_SIZE ) ; KASSERT ( free_kva >= ( uint8_t * ) xbb -> kva && free_kva + ( nr_pages * PAGE_SIZE ) <= ( uint8_t * ) xbb -> ring_config . va , ( " " " \n " , free_kva , nr_pages * PAGE_SIZE , ( uintmax_t ) xbb -> kva , ( uintmax_t ) xbb -> ring_config . va ) ) ; break ; } } bailout : if ( free_kva == NULL ) { xbb -> flags |= XBBF_RESOURCE_SHORTAGE ; xbb -> kva_shortages ++ ; } mtx_unlock ( & xbb -> lock ) ; return ( free_kva ) ; }
Get Kernel Virtual Address space for mapping requests.
Get Kernel Virtual Address space for mapping requests .
/*
	 * Look for the first available page.  If there are none, we're done.
	 */ /*
	 * Starting at the first available page, look for consecutive free
	 * pages that will satisfy the user's request.
	 */ /*
		 * If this is true, the page is used, so we have to reset
		 * the number of clear pages and the first clear page
		 * (since it pointed to a region with an insufficient number
		 * of clear pages).
		 */ /*
		 * If this is true, we've found a large enough free region
		 * to satisfy the request.
		 */