xref: /dpdk/lib/eal/common/eal_common_fbarray.c (revision a744665d2149ba8707621c1214c798f807ec398e)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright(c) 2017-2018 Intel Corporation
399a2dd95SBruce Richardson  */
499a2dd95SBruce Richardson 
599a2dd95SBruce Richardson #include <inttypes.h>
699a2dd95SBruce Richardson #include <limits.h>
799a2dd95SBruce Richardson #include <stdint.h>
899a2dd95SBruce Richardson #include <errno.h>
999a2dd95SBruce Richardson #include <string.h>
1099a2dd95SBruce Richardson #include <unistd.h>
1199a2dd95SBruce Richardson 
1299a2dd95SBruce Richardson #include <rte_common.h>
1399a2dd95SBruce Richardson #include <rte_eal_paging.h>
1499a2dd95SBruce Richardson #include <rte_errno.h>
1599a2dd95SBruce Richardson #include <rte_log.h>
1699a2dd95SBruce Richardson #include <rte_spinlock.h>
1799a2dd95SBruce Richardson 
1899a2dd95SBruce Richardson #include "eal_filesystem.h"
1999a2dd95SBruce Richardson #include "eal_private.h"
2099a2dd95SBruce Richardson 
2199a2dd95SBruce Richardson #include "rte_fbarray.h"
2299a2dd95SBruce Richardson 
2399a2dd95SBruce Richardson #define MASK_SHIFT 6ULL
2499a2dd95SBruce Richardson #define MASK_ALIGN (1ULL << MASK_SHIFT)
2599a2dd95SBruce Richardson #define MASK_LEN_TO_IDX(x) ((x) >> MASK_SHIFT)
2699a2dd95SBruce Richardson #define MASK_LEN_TO_MOD(x) ((x) - RTE_ALIGN_FLOOR(x, MASK_ALIGN))
2799a2dd95SBruce Richardson #define MASK_GET_IDX(idx, mod) ((idx << MASK_SHIFT) + mod)
2899a2dd95SBruce Richardson 
2999a2dd95SBruce Richardson /*
3099a2dd95SBruce Richardson  * We use this to keep track of created/attached memory areas to prevent user
3199a2dd95SBruce Richardson  * errors in API usage.
3299a2dd95SBruce Richardson  */
3399a2dd95SBruce Richardson struct mem_area {
3499a2dd95SBruce Richardson 	TAILQ_ENTRY(mem_area) next;
3599a2dd95SBruce Richardson 	void *addr;
3699a2dd95SBruce Richardson 	size_t len;
3799a2dd95SBruce Richardson 	int fd;
3899a2dd95SBruce Richardson };
3999a2dd95SBruce Richardson TAILQ_HEAD(mem_area_head, mem_area);
4099a2dd95SBruce Richardson /* local per-process tailq */
4199a2dd95SBruce Richardson static struct mem_area_head mem_area_tailq =
4299a2dd95SBruce Richardson 	TAILQ_HEAD_INITIALIZER(mem_area_tailq);
4399a2dd95SBruce Richardson static rte_spinlock_t mem_area_lock = RTE_SPINLOCK_INITIALIZER;
4499a2dd95SBruce Richardson 
4599a2dd95SBruce Richardson /*
4699a2dd95SBruce Richardson  * This is a mask that is always stored at the end of array, to provide fast
4799a2dd95SBruce Richardson  * way of finding free/used spots without looping through each element.
4899a2dd95SBruce Richardson  */
4999a2dd95SBruce Richardson 
5099a2dd95SBruce Richardson struct used_mask {
5199a2dd95SBruce Richardson 	unsigned int n_masks;
5299a2dd95SBruce Richardson 	uint64_t data[];
5399a2dd95SBruce Richardson };
5499a2dd95SBruce Richardson 
5599a2dd95SBruce Richardson static size_t
calc_mask_size(unsigned int len)5699a2dd95SBruce Richardson calc_mask_size(unsigned int len)
5799a2dd95SBruce Richardson {
5899a2dd95SBruce Richardson 	/* mask must be multiple of MASK_ALIGN, even though length of array
5999a2dd95SBruce Richardson 	 * itself may not be aligned on that boundary.
6099a2dd95SBruce Richardson 	 */
6199a2dd95SBruce Richardson 	len = RTE_ALIGN_CEIL(len, MASK_ALIGN);
6299a2dd95SBruce Richardson 	return sizeof(struct used_mask) +
6399a2dd95SBruce Richardson 			sizeof(uint64_t) * MASK_LEN_TO_IDX(len);
6499a2dd95SBruce Richardson }
6599a2dd95SBruce Richardson 
6699a2dd95SBruce Richardson static size_t
calc_data_size(size_t page_sz,unsigned int elt_sz,unsigned int len)6799a2dd95SBruce Richardson calc_data_size(size_t page_sz, unsigned int elt_sz, unsigned int len)
6899a2dd95SBruce Richardson {
6999a2dd95SBruce Richardson 	size_t data_sz = elt_sz * len;
7099a2dd95SBruce Richardson 	size_t msk_sz = calc_mask_size(len);
7199a2dd95SBruce Richardson 	return RTE_ALIGN_CEIL(data_sz + msk_sz, page_sz);
7299a2dd95SBruce Richardson }
7399a2dd95SBruce Richardson 
7499a2dd95SBruce Richardson static struct used_mask *
get_used_mask(void * data,unsigned int elt_sz,unsigned int len)7599a2dd95SBruce Richardson get_used_mask(void *data, unsigned int elt_sz, unsigned int len)
7699a2dd95SBruce Richardson {
7799a2dd95SBruce Richardson 	return (struct used_mask *) RTE_PTR_ADD(data, elt_sz * len);
7899a2dd95SBruce Richardson }
7999a2dd95SBruce Richardson 
8099a2dd95SBruce Richardson static int
resize_and_map(int fd,const char * path,void * addr,size_t len)8199a2dd95SBruce Richardson resize_and_map(int fd, const char *path, void *addr, size_t len)
8299a2dd95SBruce Richardson {
8399a2dd95SBruce Richardson 	void *map_addr;
8499a2dd95SBruce Richardson 
8599a2dd95SBruce Richardson 	if (eal_file_truncate(fd, len)) {
86ae67895bSDavid Marchand 		EAL_LOG(ERR, "Cannot truncate %s", path);
8799a2dd95SBruce Richardson 		return -1;
8899a2dd95SBruce Richardson 	}
8999a2dd95SBruce Richardson 
9099a2dd95SBruce Richardson 	map_addr = rte_mem_map(addr, len, RTE_PROT_READ | RTE_PROT_WRITE,
9199a2dd95SBruce Richardson 			RTE_MAP_SHARED | RTE_MAP_FORCE_ADDRESS, fd, 0);
9299a2dd95SBruce Richardson 	if (map_addr != addr) {
9399a2dd95SBruce Richardson 		return -1;
9499a2dd95SBruce Richardson 	}
9599a2dd95SBruce Richardson 	return 0;
9699a2dd95SBruce Richardson }
9799a2dd95SBruce Richardson 
9899a2dd95SBruce Richardson static int
overlap(const struct mem_area * ma,const void * start,size_t len)9999a2dd95SBruce Richardson overlap(const struct mem_area *ma, const void *start, size_t len)
10099a2dd95SBruce Richardson {
10199a2dd95SBruce Richardson 	const void *end = RTE_PTR_ADD(start, len);
10299a2dd95SBruce Richardson 	const void *ma_start = ma->addr;
10399a2dd95SBruce Richardson 	const void *ma_end = RTE_PTR_ADD(ma->addr, ma->len);
10499a2dd95SBruce Richardson 
10599a2dd95SBruce Richardson 	/* start overlap? */
10699a2dd95SBruce Richardson 	if (start >= ma_start && start < ma_end)
10799a2dd95SBruce Richardson 		return 1;
10899a2dd95SBruce Richardson 	/* end overlap? */
10999a2dd95SBruce Richardson 	if (end > ma_start && end < ma_end)
11099a2dd95SBruce Richardson 		return 1;
11199a2dd95SBruce Richardson 	return 0;
11299a2dd95SBruce Richardson }
11399a2dd95SBruce Richardson 
11499a2dd95SBruce Richardson static int
find_next_n(const struct rte_fbarray * arr,unsigned int start,unsigned int n,bool used)11599a2dd95SBruce Richardson find_next_n(const struct rte_fbarray *arr, unsigned int start, unsigned int n,
11699a2dd95SBruce Richardson 	    bool used)
11799a2dd95SBruce Richardson {
11899a2dd95SBruce Richardson 	const struct used_mask *msk = get_used_mask(arr->data, arr->elt_sz,
11999a2dd95SBruce Richardson 			arr->len);
12099a2dd95SBruce Richardson 	unsigned int msk_idx, lookahead_idx, first, first_mod;
12199a2dd95SBruce Richardson 	unsigned int last, last_mod;
12299a2dd95SBruce Richardson 	uint64_t last_msk, ignore_msk;
12399a2dd95SBruce Richardson 
12499a2dd95SBruce Richardson 	/*
12599a2dd95SBruce Richardson 	 * mask only has granularity of MASK_ALIGN, but start may not be aligned
12699a2dd95SBruce Richardson 	 * on that boundary, so construct a special mask to exclude anything we
12799a2dd95SBruce Richardson 	 * don't want to see to avoid confusing ctz.
12899a2dd95SBruce Richardson 	 */
12999a2dd95SBruce Richardson 	first = MASK_LEN_TO_IDX(start);
13099a2dd95SBruce Richardson 	first_mod = MASK_LEN_TO_MOD(start);
13199a2dd95SBruce Richardson 	ignore_msk = ~((1ULL << first_mod) - 1);
13299a2dd95SBruce Richardson 
13399a2dd95SBruce Richardson 	/* array length may not be aligned, so calculate ignore mask for last
13499a2dd95SBruce Richardson 	 * mask index.
13599a2dd95SBruce Richardson 	 */
13699a2dd95SBruce Richardson 	last = MASK_LEN_TO_IDX(arr->len);
13799a2dd95SBruce Richardson 	last_mod = MASK_LEN_TO_MOD(arr->len);
13899a2dd95SBruce Richardson 	last_msk = ~(UINT64_MAX << last_mod);
13999a2dd95SBruce Richardson 
14099a2dd95SBruce Richardson 	for (msk_idx = first; msk_idx < msk->n_masks; msk_idx++) {
14199a2dd95SBruce Richardson 		uint64_t cur_msk, lookahead_msk;
14299a2dd95SBruce Richardson 		unsigned int run_start, clz, left;
14399a2dd95SBruce Richardson 		bool found = false;
14499a2dd95SBruce Richardson 		/*
14599a2dd95SBruce Richardson 		 * The process of getting n consecutive bits for arbitrary n is
14699a2dd95SBruce Richardson 		 * a bit involved, but here it is in a nutshell:
14799a2dd95SBruce Richardson 		 *
14899a2dd95SBruce Richardson 		 *  1. let n be the number of consecutive bits we're looking for
14999a2dd95SBruce Richardson 		 *  2. check if n can fit in one mask, and if so, do n-1
15099a2dd95SBruce Richardson 		 *     rshift-ands to see if there is an appropriate run inside
15199a2dd95SBruce Richardson 		 *     our current mask
15299a2dd95SBruce Richardson 		 *    2a. if we found a run, bail out early
15399a2dd95SBruce Richardson 		 *    2b. if we didn't find a run, proceed
15499a2dd95SBruce Richardson 		 *  3. invert the mask and count leading zeroes (that is, count
15599a2dd95SBruce Richardson 		 *     how many consecutive set bits we had starting from the
15699a2dd95SBruce Richardson 		 *     end of current mask) as k
15799a2dd95SBruce Richardson 		 *    3a. if k is 0, continue to next mask
15899a2dd95SBruce Richardson 		 *    3b. if k is not 0, we have a potential run
15999a2dd95SBruce Richardson 		 *  4. to satisfy our requirements, next mask must have n-k
16099a2dd95SBruce Richardson 		 *     consecutive set bits right at the start, so we will do
16199a2dd95SBruce Richardson 		 *     (n-k-1) rshift-ands and check if first bit is set.
16299a2dd95SBruce Richardson 		 *
16399a2dd95SBruce Richardson 		 * Step 4 will need to be repeated if (n-k) > MASK_ALIGN until
16499a2dd95SBruce Richardson 		 * we either run out of masks, lose the run, or find what we
16599a2dd95SBruce Richardson 		 * were looking for.
16699a2dd95SBruce Richardson 		 */
16799a2dd95SBruce Richardson 		cur_msk = msk->data[msk_idx];
16899a2dd95SBruce Richardson 		left = n;
16999a2dd95SBruce Richardson 
17099a2dd95SBruce Richardson 		/* if we're looking for free spaces, invert the mask */
17199a2dd95SBruce Richardson 		if (!used)
17299a2dd95SBruce Richardson 			cur_msk = ~cur_msk;
17399a2dd95SBruce Richardson 
17499a2dd95SBruce Richardson 		/* combine current ignore mask with last index ignore mask */
17599a2dd95SBruce Richardson 		if (msk_idx == last)
176*a744665dSAnatoly Burakov 			ignore_msk &= last_msk;
17799a2dd95SBruce Richardson 
17899a2dd95SBruce Richardson 		/* if we have an ignore mask, ignore once */
17999a2dd95SBruce Richardson 		if (ignore_msk) {
18099a2dd95SBruce Richardson 			cur_msk &= ignore_msk;
18199a2dd95SBruce Richardson 			ignore_msk = 0;
18299a2dd95SBruce Richardson 		}
18399a2dd95SBruce Richardson 
18499a2dd95SBruce Richardson 		/* if n can fit in within a single mask, do a search */
18599a2dd95SBruce Richardson 		if (n <= MASK_ALIGN) {
18699a2dd95SBruce Richardson 			uint64_t tmp_msk = cur_msk;
18799a2dd95SBruce Richardson 			unsigned int s_idx;
18899a2dd95SBruce Richardson 			for (s_idx = 0; s_idx < n - 1; s_idx++)
18999a2dd95SBruce Richardson 				tmp_msk &= tmp_msk >> 1ULL;
19099a2dd95SBruce Richardson 			/* we found what we were looking for */
19199a2dd95SBruce Richardson 			if (tmp_msk != 0) {
1923d4e27fdSDavid Marchand 				run_start = rte_ctz64(tmp_msk);
19399a2dd95SBruce Richardson 				return MASK_GET_IDX(msk_idx, run_start);
19499a2dd95SBruce Richardson 			}
19599a2dd95SBruce Richardson 		}
19699a2dd95SBruce Richardson 
19799a2dd95SBruce Richardson 		/*
19899a2dd95SBruce Richardson 		 * we didn't find our run within the mask, or n > MASK_ALIGN,
19999a2dd95SBruce Richardson 		 * so we're going for plan B.
20099a2dd95SBruce Richardson 		 */
20199a2dd95SBruce Richardson 
20299a2dd95SBruce Richardson 		/* count leading zeroes on inverted mask */
20399a2dd95SBruce Richardson 		if (~cur_msk == 0)
20499a2dd95SBruce Richardson 			clz = sizeof(cur_msk) * 8;
20599a2dd95SBruce Richardson 		else
2063d4e27fdSDavid Marchand 			clz = rte_clz64(~cur_msk);
20799a2dd95SBruce Richardson 
20899a2dd95SBruce Richardson 		/* if there aren't any runs at the end either, just continue */
20999a2dd95SBruce Richardson 		if (clz == 0)
21099a2dd95SBruce Richardson 			continue;
21199a2dd95SBruce Richardson 
21299a2dd95SBruce Richardson 		/* we have a partial run at the end, so try looking ahead */
21399a2dd95SBruce Richardson 		run_start = MASK_ALIGN - clz;
21499a2dd95SBruce Richardson 		left -= clz;
21599a2dd95SBruce Richardson 
21699a2dd95SBruce Richardson 		for (lookahead_idx = msk_idx + 1; lookahead_idx < msk->n_masks;
21799a2dd95SBruce Richardson 				lookahead_idx++) {
21899a2dd95SBruce Richardson 			unsigned int s_idx, need;
219a344719cSAnatoly Burakov 			uint64_t first_bit = 1;
220a344719cSAnatoly Burakov 
22199a2dd95SBruce Richardson 			lookahead_msk = msk->data[lookahead_idx];
22299a2dd95SBruce Richardson 
22399a2dd95SBruce Richardson 			/* if we're looking for free space, invert the mask */
22499a2dd95SBruce Richardson 			if (!used)
22599a2dd95SBruce Richardson 				lookahead_msk = ~lookahead_msk;
22699a2dd95SBruce Richardson 
22799a2dd95SBruce Richardson 			/* figure out how many consecutive bits we need here */
22899a2dd95SBruce Richardson 			need = RTE_MIN(left, MASK_ALIGN);
22999a2dd95SBruce Richardson 
230a344719cSAnatoly Burakov 			/* count number of shifts we performed */
231a344719cSAnatoly Burakov 			for (s_idx = 0; s_idx < need - 1; s_idx++) {
23299a2dd95SBruce Richardson 				lookahead_msk &= lookahead_msk >> 1ULL;
233a344719cSAnatoly Burakov 				/* did we lose the run yet? */
234a344719cSAnatoly Burakov 				if ((lookahead_msk & first_bit) == 0)
235a344719cSAnatoly Burakov 					break;
236a344719cSAnatoly Burakov 			}
23799a2dd95SBruce Richardson 
23899a2dd95SBruce Richardson 			/* if first bit is not set, we've lost the run */
239a344719cSAnatoly Burakov 			if ((lookahead_msk & first_bit) == 0) {
24099a2dd95SBruce Richardson 				/*
24199a2dd95SBruce Richardson 				 * we've scanned this far, so we know there are
24299a2dd95SBruce Richardson 				 * no runs in the space we've lookahead-scanned
24399a2dd95SBruce Richardson 				 * as well, so skip that on next iteration.
24499a2dd95SBruce Richardson 				 */
245a344719cSAnatoly Burakov 				ignore_msk = ~((1ULL << (s_idx + 1)) - 1);
2468c03a149SAnatoly Burakov 				/* outer loop will increment msk_idx so add 1 */
2478c03a149SAnatoly Burakov 				msk_idx = lookahead_idx - 1;
24899a2dd95SBruce Richardson 				break;
24999a2dd95SBruce Richardson 			}
25099a2dd95SBruce Richardson 
25199a2dd95SBruce Richardson 			left -= need;
25299a2dd95SBruce Richardson 
25399a2dd95SBruce Richardson 			/* check if we've found what we were looking for */
25499a2dd95SBruce Richardson 			if (left == 0) {
25599a2dd95SBruce Richardson 				found = true;
25699a2dd95SBruce Richardson 				break;
25799a2dd95SBruce Richardson 			}
25899a2dd95SBruce Richardson 		}
25999a2dd95SBruce Richardson 
26099a2dd95SBruce Richardson 		/* we didn't find anything, so continue */
26199a2dd95SBruce Richardson 		if (!found)
26299a2dd95SBruce Richardson 			continue;
26399a2dd95SBruce Richardson 
26499a2dd95SBruce Richardson 		return MASK_GET_IDX(msk_idx, run_start);
26599a2dd95SBruce Richardson 	}
26699a2dd95SBruce Richardson 	/* we didn't find anything */
26799a2dd95SBruce Richardson 	rte_errno = used ? ENOENT : ENOSPC;
26899a2dd95SBruce Richardson 	return -1;
26999a2dd95SBruce Richardson }
27099a2dd95SBruce Richardson 
27199a2dd95SBruce Richardson static int
find_next(const struct rte_fbarray * arr,unsigned int start,bool used)27299a2dd95SBruce Richardson find_next(const struct rte_fbarray *arr, unsigned int start, bool used)
27399a2dd95SBruce Richardson {
27499a2dd95SBruce Richardson 	const struct used_mask *msk = get_used_mask(arr->data, arr->elt_sz,
27599a2dd95SBruce Richardson 			arr->len);
27699a2dd95SBruce Richardson 	unsigned int idx, first, first_mod;
27799a2dd95SBruce Richardson 	unsigned int last, last_mod;
27899a2dd95SBruce Richardson 	uint64_t last_msk, ignore_msk;
27999a2dd95SBruce Richardson 
28099a2dd95SBruce Richardson 	/*
28199a2dd95SBruce Richardson 	 * mask only has granularity of MASK_ALIGN, but start may not be aligned
28299a2dd95SBruce Richardson 	 * on that boundary, so construct a special mask to exclude anything we
28399a2dd95SBruce Richardson 	 * don't want to see to avoid confusing ctz.
28499a2dd95SBruce Richardson 	 */
28599a2dd95SBruce Richardson 	first = MASK_LEN_TO_IDX(start);
28699a2dd95SBruce Richardson 	first_mod = MASK_LEN_TO_MOD(start);
28799a2dd95SBruce Richardson 	ignore_msk = ~((1ULL << first_mod) - 1ULL);
28899a2dd95SBruce Richardson 
28999a2dd95SBruce Richardson 	/* array length may not be aligned, so calculate ignore mask for last
29099a2dd95SBruce Richardson 	 * mask index.
29199a2dd95SBruce Richardson 	 */
29299a2dd95SBruce Richardson 	last = MASK_LEN_TO_IDX(arr->len);
29399a2dd95SBruce Richardson 	last_mod = MASK_LEN_TO_MOD(arr->len);
29499a2dd95SBruce Richardson 	last_msk = ~(-(1ULL) << last_mod);
29599a2dd95SBruce Richardson 
29699a2dd95SBruce Richardson 	for (idx = first; idx < msk->n_masks; idx++) {
29799a2dd95SBruce Richardson 		uint64_t cur = msk->data[idx];
29899a2dd95SBruce Richardson 		int found;
29999a2dd95SBruce Richardson 
30099a2dd95SBruce Richardson 		/* if we're looking for free entries, invert mask */
30199a2dd95SBruce Richardson 		if (!used)
30299a2dd95SBruce Richardson 			cur = ~cur;
30399a2dd95SBruce Richardson 
30499a2dd95SBruce Richardson 		if (idx == last)
30599a2dd95SBruce Richardson 			cur &= last_msk;
30699a2dd95SBruce Richardson 
30799a2dd95SBruce Richardson 		/* ignore everything before start on first iteration */
30899a2dd95SBruce Richardson 		if (idx == first)
30999a2dd95SBruce Richardson 			cur &= ignore_msk;
31099a2dd95SBruce Richardson 
31199a2dd95SBruce Richardson 		/* check if we have any entries */
31299a2dd95SBruce Richardson 		if (cur == 0)
31399a2dd95SBruce Richardson 			continue;
31499a2dd95SBruce Richardson 
31599a2dd95SBruce Richardson 		/*
31699a2dd95SBruce Richardson 		 * find first set bit - that will correspond to whatever it is
31799a2dd95SBruce Richardson 		 * that we're looking for.
31899a2dd95SBruce Richardson 		 */
3193d4e27fdSDavid Marchand 		found = rte_ctz64(cur);
32099a2dd95SBruce Richardson 		return MASK_GET_IDX(idx, found);
32199a2dd95SBruce Richardson 	}
32299a2dd95SBruce Richardson 	/* we didn't find anything */
32399a2dd95SBruce Richardson 	rte_errno = used ? ENOENT : ENOSPC;
32499a2dd95SBruce Richardson 	return -1;
32599a2dd95SBruce Richardson }
32699a2dd95SBruce Richardson 
32799a2dd95SBruce Richardson static int
find_contig(const struct rte_fbarray * arr,unsigned int start,bool used)32899a2dd95SBruce Richardson find_contig(const struct rte_fbarray *arr, unsigned int start, bool used)
32999a2dd95SBruce Richardson {
33099a2dd95SBruce Richardson 	const struct used_mask *msk = get_used_mask(arr->data, arr->elt_sz,
33199a2dd95SBruce Richardson 			arr->len);
33299a2dd95SBruce Richardson 	unsigned int idx, first, first_mod;
33399a2dd95SBruce Richardson 	unsigned int last, last_mod;
33499a2dd95SBruce Richardson 	uint64_t last_msk;
33599a2dd95SBruce Richardson 	unsigned int need_len, result = 0;
33699a2dd95SBruce Richardson 
33799a2dd95SBruce Richardson 	/* array length may not be aligned, so calculate ignore mask for last
33899a2dd95SBruce Richardson 	 * mask index.
33999a2dd95SBruce Richardson 	 */
34099a2dd95SBruce Richardson 	last = MASK_LEN_TO_IDX(arr->len);
34199a2dd95SBruce Richardson 	last_mod = MASK_LEN_TO_MOD(arr->len);
34299a2dd95SBruce Richardson 	last_msk = ~(-(1ULL) << last_mod);
34399a2dd95SBruce Richardson 
34499a2dd95SBruce Richardson 	first = MASK_LEN_TO_IDX(start);
34599a2dd95SBruce Richardson 	first_mod = MASK_LEN_TO_MOD(start);
34699a2dd95SBruce Richardson 	for (idx = first; idx < msk->n_masks; idx++, result += need_len) {
34799a2dd95SBruce Richardson 		uint64_t cur = msk->data[idx];
34899a2dd95SBruce Richardson 		unsigned int run_len;
34999a2dd95SBruce Richardson 
35099a2dd95SBruce Richardson 		need_len = MASK_ALIGN;
35199a2dd95SBruce Richardson 
35299a2dd95SBruce Richardson 		/* if we're looking for free entries, invert mask */
35399a2dd95SBruce Richardson 		if (!used)
35499a2dd95SBruce Richardson 			cur = ~cur;
35599a2dd95SBruce Richardson 
35699a2dd95SBruce Richardson 		/* if this is last mask, ignore everything after last bit */
35799a2dd95SBruce Richardson 		if (idx == last)
35899a2dd95SBruce Richardson 			cur &= last_msk;
35999a2dd95SBruce Richardson 
36099a2dd95SBruce Richardson 		/* ignore everything before start on first iteration */
36199a2dd95SBruce Richardson 		if (idx == first) {
36299a2dd95SBruce Richardson 			cur >>= first_mod;
36399a2dd95SBruce Richardson 			/* at the start, we don't need the full mask len */
36499a2dd95SBruce Richardson 			need_len -= first_mod;
36599a2dd95SBruce Richardson 		}
36699a2dd95SBruce Richardson 
36799a2dd95SBruce Richardson 		/* we will be looking for zeroes, so invert the mask */
36899a2dd95SBruce Richardson 		cur = ~cur;
36999a2dd95SBruce Richardson 
37099a2dd95SBruce Richardson 		/* if mask is zero, we have a complete run */
37199a2dd95SBruce Richardson 		if (cur == 0)
37299a2dd95SBruce Richardson 			continue;
37399a2dd95SBruce Richardson 
37499a2dd95SBruce Richardson 		/*
37599a2dd95SBruce Richardson 		 * see if current run ends before mask end.
37699a2dd95SBruce Richardson 		 */
3773d4e27fdSDavid Marchand 		run_len = rte_ctz64(cur);
37899a2dd95SBruce Richardson 
37999a2dd95SBruce Richardson 		/* add however many zeroes we've had in the last run and quit */
38099a2dd95SBruce Richardson 		if (run_len < need_len) {
38199a2dd95SBruce Richardson 			result += run_len;
38299a2dd95SBruce Richardson 			break;
38399a2dd95SBruce Richardson 		}
38499a2dd95SBruce Richardson 	}
38599a2dd95SBruce Richardson 	return result;
38699a2dd95SBruce Richardson }
38799a2dd95SBruce Richardson 
38899a2dd95SBruce Richardson static int
find_prev_n(const struct rte_fbarray * arr,unsigned int start,unsigned int n,bool used)38999a2dd95SBruce Richardson find_prev_n(const struct rte_fbarray *arr, unsigned int start, unsigned int n,
39099a2dd95SBruce Richardson 		bool used)
39199a2dd95SBruce Richardson {
39299a2dd95SBruce Richardson 	const struct used_mask *msk = get_used_mask(arr->data, arr->elt_sz,
39399a2dd95SBruce Richardson 			arr->len);
39499a2dd95SBruce Richardson 	unsigned int msk_idx, lookbehind_idx, first, first_mod;
39599a2dd95SBruce Richardson 	uint64_t ignore_msk;
39699a2dd95SBruce Richardson 
39799a2dd95SBruce Richardson 	/*
39899a2dd95SBruce Richardson 	 * mask only has granularity of MASK_ALIGN, but start may not be aligned
39999a2dd95SBruce Richardson 	 * on that boundary, so construct a special mask to exclude anything we
40099a2dd95SBruce Richardson 	 * don't want to see to avoid confusing ctz.
40199a2dd95SBruce Richardson 	 */
40299a2dd95SBruce Richardson 	first = MASK_LEN_TO_IDX(start);
40399a2dd95SBruce Richardson 	first_mod = MASK_LEN_TO_MOD(start);
40499a2dd95SBruce Richardson 	/* we're going backwards, so mask must start from the top */
40599a2dd95SBruce Richardson 	ignore_msk = first_mod == MASK_ALIGN - 1 ?
40699a2dd95SBruce Richardson 				UINT64_MAX : /* prevent overflow */
40799a2dd95SBruce Richardson 				~(UINT64_MAX << (first_mod + 1));
40899a2dd95SBruce Richardson 
40999a2dd95SBruce Richardson 	/* go backwards, include zero */
41099a2dd95SBruce Richardson 	msk_idx = first;
41199a2dd95SBruce Richardson 	do {
41299a2dd95SBruce Richardson 		uint64_t cur_msk, lookbehind_msk;
41399a2dd95SBruce Richardson 		unsigned int run_start, run_end, ctz, left;
41499a2dd95SBruce Richardson 		bool found = false;
41599a2dd95SBruce Richardson 		/*
41699a2dd95SBruce Richardson 		 * The process of getting n consecutive bits from the top for
41799a2dd95SBruce Richardson 		 * arbitrary n is a bit involved, but here it is in a nutshell:
41899a2dd95SBruce Richardson 		 *
41999a2dd95SBruce Richardson 		 *  1. let n be the number of consecutive bits we're looking for
42099a2dd95SBruce Richardson 		 *  2. check if n can fit in one mask, and if so, do n-1
42199a2dd95SBruce Richardson 		 *     lshift-ands to see if there is an appropriate run inside
42299a2dd95SBruce Richardson 		 *     our current mask
42399a2dd95SBruce Richardson 		 *    2a. if we found a run, bail out early
42499a2dd95SBruce Richardson 		 *    2b. if we didn't find a run, proceed
42599a2dd95SBruce Richardson 		 *  3. invert the mask and count trailing zeroes (that is, count
42699a2dd95SBruce Richardson 		 *     how many consecutive set bits we had starting from the
42799a2dd95SBruce Richardson 		 *     start of current mask) as k
42899a2dd95SBruce Richardson 		 *    3a. if k is 0, continue to next mask
42999a2dd95SBruce Richardson 		 *    3b. if k is not 0, we have a potential run
43099a2dd95SBruce Richardson 		 *  4. to satisfy our requirements, next mask must have n-k
43199a2dd95SBruce Richardson 		 *     consecutive set bits at the end, so we will do (n-k-1)
43299a2dd95SBruce Richardson 		 *     lshift-ands and check if last bit is set.
43399a2dd95SBruce Richardson 		 *
43499a2dd95SBruce Richardson 		 * Step 4 will need to be repeated if (n-k) > MASK_ALIGN until
43599a2dd95SBruce Richardson 		 * we either run out of masks, lose the run, or find what we
43699a2dd95SBruce Richardson 		 * were looking for.
43799a2dd95SBruce Richardson 		 */
43899a2dd95SBruce Richardson 		cur_msk = msk->data[msk_idx];
43999a2dd95SBruce Richardson 		left = n;
44099a2dd95SBruce Richardson 
44199a2dd95SBruce Richardson 		/* if we're looking for free spaces, invert the mask */
44299a2dd95SBruce Richardson 		if (!used)
44399a2dd95SBruce Richardson 			cur_msk = ~cur_msk;
44499a2dd95SBruce Richardson 
44599a2dd95SBruce Richardson 		/* if we have an ignore mask, ignore once */
44699a2dd95SBruce Richardson 		if (ignore_msk) {
44799a2dd95SBruce Richardson 			cur_msk &= ignore_msk;
44899a2dd95SBruce Richardson 			ignore_msk = 0;
44999a2dd95SBruce Richardson 		}
45099a2dd95SBruce Richardson 
45199a2dd95SBruce Richardson 		/* if n can fit in within a single mask, do a search */
45299a2dd95SBruce Richardson 		if (n <= MASK_ALIGN) {
45399a2dd95SBruce Richardson 			uint64_t tmp_msk = cur_msk;
45499a2dd95SBruce Richardson 			unsigned int s_idx;
45599a2dd95SBruce Richardson 			for (s_idx = 0; s_idx < n - 1; s_idx++)
45699a2dd95SBruce Richardson 				tmp_msk &= tmp_msk << 1ULL;
45799a2dd95SBruce Richardson 			/* we found what we were looking for */
45899a2dd95SBruce Richardson 			if (tmp_msk != 0) {
45999a2dd95SBruce Richardson 				/* clz will give us offset from end of mask, and
46099a2dd95SBruce Richardson 				 * we only get the end of our run, not start,
46199a2dd95SBruce Richardson 				 * so adjust result to point to where start
46299a2dd95SBruce Richardson 				 * would have been.
46399a2dd95SBruce Richardson 				 */
46499a2dd95SBruce Richardson 				run_start = MASK_ALIGN -
4653d4e27fdSDavid Marchand 						rte_clz64(tmp_msk) - n;
46699a2dd95SBruce Richardson 				return MASK_GET_IDX(msk_idx, run_start);
46799a2dd95SBruce Richardson 			}
46899a2dd95SBruce Richardson 		}
46999a2dd95SBruce Richardson 
47099a2dd95SBruce Richardson 		/*
47199a2dd95SBruce Richardson 		 * we didn't find our run within the mask, or n > MASK_ALIGN,
47299a2dd95SBruce Richardson 		 * so we're going for plan B.
47399a2dd95SBruce Richardson 		 */
47499a2dd95SBruce Richardson 
47599a2dd95SBruce Richardson 		/* count trailing zeroes on inverted mask */
47699a2dd95SBruce Richardson 		if (~cur_msk == 0)
47799a2dd95SBruce Richardson 			ctz = sizeof(cur_msk) * 8;
47899a2dd95SBruce Richardson 		else
4793d4e27fdSDavid Marchand 			ctz = rte_ctz64(~cur_msk);
48099a2dd95SBruce Richardson 
48199a2dd95SBruce Richardson 		/* if there aren't any runs at the start either, just
48299a2dd95SBruce Richardson 		 * continue
48399a2dd95SBruce Richardson 		 */
48499a2dd95SBruce Richardson 		if (ctz == 0)
48599a2dd95SBruce Richardson 			continue;
48699a2dd95SBruce Richardson 
48799a2dd95SBruce Richardson 		/* we have a partial run at the start, so try looking behind */
48899a2dd95SBruce Richardson 		run_end = MASK_GET_IDX(msk_idx, ctz);
48999a2dd95SBruce Richardson 		left -= ctz;
49099a2dd95SBruce Richardson 
49199a2dd95SBruce Richardson 		/* go backwards, include zero */
49299a2dd95SBruce Richardson 		lookbehind_idx = msk_idx - 1;
49399a2dd95SBruce Richardson 
49499a2dd95SBruce Richardson 		/* we can't lookbehind as we've run out of masks, so stop */
49599a2dd95SBruce Richardson 		if (msk_idx == 0)
49699a2dd95SBruce Richardson 			break;
49799a2dd95SBruce Richardson 
49899a2dd95SBruce Richardson 		do {
49999a2dd95SBruce Richardson 			const uint64_t last_bit = 1ULL << (MASK_ALIGN - 1);
50099a2dd95SBruce Richardson 			unsigned int s_idx, need;
50199a2dd95SBruce Richardson 
50299a2dd95SBruce Richardson 			lookbehind_msk = msk->data[lookbehind_idx];
50399a2dd95SBruce Richardson 
50499a2dd95SBruce Richardson 			/* if we're looking for free space, invert the mask */
50599a2dd95SBruce Richardson 			if (!used)
50699a2dd95SBruce Richardson 				lookbehind_msk = ~lookbehind_msk;
50799a2dd95SBruce Richardson 
50899a2dd95SBruce Richardson 			/* figure out how many consecutive bits we need here */
50999a2dd95SBruce Richardson 			need = RTE_MIN(left, MASK_ALIGN);
51099a2dd95SBruce Richardson 
5110c6e2781SAnatoly Burakov 			/* count number of shifts we performed */
5120c6e2781SAnatoly Burakov 			for (s_idx = 0; s_idx < need - 1; s_idx++) {
51399a2dd95SBruce Richardson 				lookbehind_msk &= lookbehind_msk << 1ULL;
5140c6e2781SAnatoly Burakov 				/* did we lose the run yet? */
5150c6e2781SAnatoly Burakov 				if ((lookbehind_msk & last_bit) == 0)
5160c6e2781SAnatoly Burakov 					break;
5170c6e2781SAnatoly Burakov 			}
51899a2dd95SBruce Richardson 
51999a2dd95SBruce Richardson 			/* if last bit is not set, we've lost the run */
52099a2dd95SBruce Richardson 			if ((lookbehind_msk & last_bit) == 0) {
52199a2dd95SBruce Richardson 				/*
52299a2dd95SBruce Richardson 				 * we've scanned this far, so we know there are
52399a2dd95SBruce Richardson 				 * no runs in the space we've lookbehind-scanned
52499a2dd95SBruce Richardson 				 * as well, so skip that on next iteration.
52599a2dd95SBruce Richardson 				 */
5260c6e2781SAnatoly Burakov 				ignore_msk = ~(UINT64_MAX << (MASK_ALIGN - s_idx - 1));
5278e371292SAnatoly Burakov 				/* outer loop will decrement msk_idx so add 1 */
5288e371292SAnatoly Burakov 				msk_idx = lookbehind_idx + 1;
52999a2dd95SBruce Richardson 				break;
53099a2dd95SBruce Richardson 			}
53199a2dd95SBruce Richardson 
53299a2dd95SBruce Richardson 			left -= need;
53399a2dd95SBruce Richardson 
53499a2dd95SBruce Richardson 			/* check if we've found what we were looking for */
53599a2dd95SBruce Richardson 			if (left == 0) {
53699a2dd95SBruce Richardson 				found = true;
53799a2dd95SBruce Richardson 				break;
53899a2dd95SBruce Richardson 			}
53999a2dd95SBruce Richardson 		} while ((lookbehind_idx--) != 0); /* decrement after check to
54099a2dd95SBruce Richardson 						    * include zero
54199a2dd95SBruce Richardson 						    */
54299a2dd95SBruce Richardson 
54399a2dd95SBruce Richardson 		/* we didn't find anything, so continue */
54499a2dd95SBruce Richardson 		if (!found)
54599a2dd95SBruce Richardson 			continue;
54699a2dd95SBruce Richardson 
54799a2dd95SBruce Richardson 		/* we've found what we were looking for, but we only know where
54899a2dd95SBruce Richardson 		 * the run ended, so calculate start position.
54999a2dd95SBruce Richardson 		 */
55099a2dd95SBruce Richardson 		return run_end - n;
55199a2dd95SBruce Richardson 	} while (msk_idx-- != 0); /* decrement after check to include zero */
55299a2dd95SBruce Richardson 	/* we didn't find anything */
55399a2dd95SBruce Richardson 	rte_errno = used ? ENOENT : ENOSPC;
55499a2dd95SBruce Richardson 	return -1;
55599a2dd95SBruce Richardson }
55699a2dd95SBruce Richardson 
55799a2dd95SBruce Richardson static int
find_prev(const struct rte_fbarray * arr,unsigned int start,bool used)55899a2dd95SBruce Richardson find_prev(const struct rte_fbarray *arr, unsigned int start, bool used)
55999a2dd95SBruce Richardson {
56099a2dd95SBruce Richardson 	const struct used_mask *msk = get_used_mask(arr->data, arr->elt_sz,
56199a2dd95SBruce Richardson 			arr->len);
56299a2dd95SBruce Richardson 	unsigned int idx, first, first_mod;
56399a2dd95SBruce Richardson 	uint64_t ignore_msk;
56499a2dd95SBruce Richardson 
56599a2dd95SBruce Richardson 	/*
56699a2dd95SBruce Richardson 	 * mask only has granularity of MASK_ALIGN, but start may not be aligned
56799a2dd95SBruce Richardson 	 * on that boundary, so construct a special mask to exclude anything we
56899a2dd95SBruce Richardson 	 * don't want to see to avoid confusing clz.
56999a2dd95SBruce Richardson 	 */
57099a2dd95SBruce Richardson 	first = MASK_LEN_TO_IDX(start);
57199a2dd95SBruce Richardson 	first_mod = MASK_LEN_TO_MOD(start);
57299a2dd95SBruce Richardson 	/* we're going backwards, so mask must start from the top */
57399a2dd95SBruce Richardson 	ignore_msk = first_mod == MASK_ALIGN - 1 ?
57499a2dd95SBruce Richardson 				UINT64_MAX : /* prevent overflow */
57599a2dd95SBruce Richardson 				~(UINT64_MAX << (first_mod + 1));
57699a2dd95SBruce Richardson 
57799a2dd95SBruce Richardson 	/* go backwards, include zero */
57899a2dd95SBruce Richardson 	idx = first;
57999a2dd95SBruce Richardson 	do {
58099a2dd95SBruce Richardson 		uint64_t cur = msk->data[idx];
58199a2dd95SBruce Richardson 		int found;
58299a2dd95SBruce Richardson 
58399a2dd95SBruce Richardson 		/* if we're looking for free entries, invert mask */
58499a2dd95SBruce Richardson 		if (!used)
58599a2dd95SBruce Richardson 			cur = ~cur;
58699a2dd95SBruce Richardson 
58799a2dd95SBruce Richardson 		/* ignore everything before start on first iteration */
58899a2dd95SBruce Richardson 		if (idx == first)
58999a2dd95SBruce Richardson 			cur &= ignore_msk;
59099a2dd95SBruce Richardson 
59199a2dd95SBruce Richardson 		/* check if we have any entries */
59299a2dd95SBruce Richardson 		if (cur == 0)
59399a2dd95SBruce Richardson 			continue;
59499a2dd95SBruce Richardson 
59599a2dd95SBruce Richardson 		/*
59699a2dd95SBruce Richardson 		 * find last set bit - that will correspond to whatever it is
59799a2dd95SBruce Richardson 		 * that we're looking for. we're counting trailing zeroes, thus
59899a2dd95SBruce Richardson 		 * the value we get is counted from end of mask, so calculate
59999a2dd95SBruce Richardson 		 * position from start of mask.
60099a2dd95SBruce Richardson 		 */
6013d4e27fdSDavid Marchand 		found = MASK_ALIGN - rte_clz64(cur) - 1;
60299a2dd95SBruce Richardson 
60399a2dd95SBruce Richardson 		return MASK_GET_IDX(idx, found);
60499a2dd95SBruce Richardson 	} while (idx-- != 0); /* decrement after check  to include zero*/
60599a2dd95SBruce Richardson 
60699a2dd95SBruce Richardson 	/* we didn't find anything */
60799a2dd95SBruce Richardson 	rte_errno = used ? ENOENT : ENOSPC;
60899a2dd95SBruce Richardson 	return -1;
60999a2dd95SBruce Richardson }
61099a2dd95SBruce Richardson 
61199a2dd95SBruce Richardson static int
find_rev_contig(const struct rte_fbarray * arr,unsigned int start,bool used)61299a2dd95SBruce Richardson find_rev_contig(const struct rte_fbarray *arr, unsigned int start, bool used)
61399a2dd95SBruce Richardson {
61499a2dd95SBruce Richardson 	const struct used_mask *msk = get_used_mask(arr->data, arr->elt_sz,
61599a2dd95SBruce Richardson 			arr->len);
61699a2dd95SBruce Richardson 	unsigned int idx, first, first_mod;
61799a2dd95SBruce Richardson 	unsigned int need_len, result = 0;
61899a2dd95SBruce Richardson 
61999a2dd95SBruce Richardson 	first = MASK_LEN_TO_IDX(start);
62099a2dd95SBruce Richardson 	first_mod = MASK_LEN_TO_MOD(start);
62199a2dd95SBruce Richardson 
62299a2dd95SBruce Richardson 	/* go backwards, include zero */
62399a2dd95SBruce Richardson 	idx = first;
62499a2dd95SBruce Richardson 	do {
62599a2dd95SBruce Richardson 		uint64_t cur = msk->data[idx];
62699a2dd95SBruce Richardson 		unsigned int run_len;
62799a2dd95SBruce Richardson 
62899a2dd95SBruce Richardson 		need_len = MASK_ALIGN;
62999a2dd95SBruce Richardson 
63099a2dd95SBruce Richardson 		/* if we're looking for free entries, invert mask */
63199a2dd95SBruce Richardson 		if (!used)
63299a2dd95SBruce Richardson 			cur = ~cur;
63399a2dd95SBruce Richardson 
63499a2dd95SBruce Richardson 		/* ignore everything after start on first iteration */
63599a2dd95SBruce Richardson 		if (idx == first) {
63699a2dd95SBruce Richardson 			unsigned int end_len = MASK_ALIGN - first_mod - 1;
63799a2dd95SBruce Richardson 			cur <<= end_len;
63899a2dd95SBruce Richardson 			/* at the start, we don't need the full mask len */
63999a2dd95SBruce Richardson 			need_len -= end_len;
64099a2dd95SBruce Richardson 		}
64199a2dd95SBruce Richardson 
64299a2dd95SBruce Richardson 		/* we will be looking for zeroes, so invert the mask */
64399a2dd95SBruce Richardson 		cur = ~cur;
64499a2dd95SBruce Richardson 
64599a2dd95SBruce Richardson 		/* if mask is zero, we have a complete run */
64699a2dd95SBruce Richardson 		if (cur == 0)
64799a2dd95SBruce Richardson 			goto endloop;
64899a2dd95SBruce Richardson 
64999a2dd95SBruce Richardson 		/*
65099a2dd95SBruce Richardson 		 * see where run ends, starting from the end.
65199a2dd95SBruce Richardson 		 */
6523d4e27fdSDavid Marchand 		run_len = rte_clz64(cur);
65399a2dd95SBruce Richardson 
65499a2dd95SBruce Richardson 		/* add however many zeroes we've had in the last run and quit */
65599a2dd95SBruce Richardson 		if (run_len < need_len) {
65699a2dd95SBruce Richardson 			result += run_len;
65799a2dd95SBruce Richardson 			break;
65899a2dd95SBruce Richardson 		}
65999a2dd95SBruce Richardson endloop:
66099a2dd95SBruce Richardson 		result += need_len;
66199a2dd95SBruce Richardson 	} while (idx-- != 0); /* decrement after check to include zero */
66299a2dd95SBruce Richardson 	return result;
66399a2dd95SBruce Richardson }
66499a2dd95SBruce Richardson 
66599a2dd95SBruce Richardson static int
set_used(struct rte_fbarray * arr,unsigned int idx,bool used)66699a2dd95SBruce Richardson set_used(struct rte_fbarray *arr, unsigned int idx, bool used)
66799a2dd95SBruce Richardson {
66899a2dd95SBruce Richardson 	struct used_mask *msk;
66999a2dd95SBruce Richardson 	uint64_t msk_bit = 1ULL << MASK_LEN_TO_MOD(idx);
67099a2dd95SBruce Richardson 	unsigned int msk_idx = MASK_LEN_TO_IDX(idx);
67199a2dd95SBruce Richardson 	bool already_used;
67299a2dd95SBruce Richardson 	int ret = -1;
67399a2dd95SBruce Richardson 
67499a2dd95SBruce Richardson 	if (arr == NULL || idx >= arr->len) {
67599a2dd95SBruce Richardson 		rte_errno = EINVAL;
67699a2dd95SBruce Richardson 		return -1;
67799a2dd95SBruce Richardson 	}
67899a2dd95SBruce Richardson 	msk = get_used_mask(arr->data, arr->elt_sz, arr->len);
67999a2dd95SBruce Richardson 	ret = 0;
68099a2dd95SBruce Richardson 
68199a2dd95SBruce Richardson 	/* prevent array from changing under us */
68299a2dd95SBruce Richardson 	rte_rwlock_write_lock(&arr->rwlock);
68399a2dd95SBruce Richardson 
68499a2dd95SBruce Richardson 	already_used = (msk->data[msk_idx] & msk_bit) != 0;
68599a2dd95SBruce Richardson 
68699a2dd95SBruce Richardson 	/* nothing to be done */
68799a2dd95SBruce Richardson 	if (used == already_used)
68899a2dd95SBruce Richardson 		goto out;
68999a2dd95SBruce Richardson 
69099a2dd95SBruce Richardson 	if (used) {
69199a2dd95SBruce Richardson 		msk->data[msk_idx] |= msk_bit;
69299a2dd95SBruce Richardson 		arr->count++;
69399a2dd95SBruce Richardson 	} else {
69499a2dd95SBruce Richardson 		msk->data[msk_idx] &= ~msk_bit;
69599a2dd95SBruce Richardson 		arr->count--;
69699a2dd95SBruce Richardson 	}
69799a2dd95SBruce Richardson out:
69899a2dd95SBruce Richardson 	rte_rwlock_write_unlock(&arr->rwlock);
69999a2dd95SBruce Richardson 
70099a2dd95SBruce Richardson 	return ret;
70199a2dd95SBruce Richardson }
70299a2dd95SBruce Richardson 
70399a2dd95SBruce Richardson static int
fully_validate(const char * name,unsigned int elt_sz,unsigned int len)70499a2dd95SBruce Richardson fully_validate(const char *name, unsigned int elt_sz, unsigned int len)
70599a2dd95SBruce Richardson {
70699a2dd95SBruce Richardson 	if (name == NULL || elt_sz == 0 || len == 0 || len > INT_MAX) {
70799a2dd95SBruce Richardson 		rte_errno = EINVAL;
70899a2dd95SBruce Richardson 		return -1;
70999a2dd95SBruce Richardson 	}
71099a2dd95SBruce Richardson 
71199a2dd95SBruce Richardson 	if (strnlen(name, RTE_FBARRAY_NAME_LEN) == RTE_FBARRAY_NAME_LEN) {
71299a2dd95SBruce Richardson 		rte_errno = ENAMETOOLONG;
71399a2dd95SBruce Richardson 		return -1;
71499a2dd95SBruce Richardson 	}
71599a2dd95SBruce Richardson 	return 0;
71699a2dd95SBruce Richardson }
71799a2dd95SBruce Richardson 
71899a2dd95SBruce Richardson int
rte_fbarray_init(struct rte_fbarray * arr,const char * name,unsigned int len,unsigned int elt_sz)71999a2dd95SBruce Richardson rte_fbarray_init(struct rte_fbarray *arr, const char *name, unsigned int len,
72099a2dd95SBruce Richardson 		unsigned int elt_sz)
72199a2dd95SBruce Richardson {
72299a2dd95SBruce Richardson 	size_t page_sz, mmap_len;
72399a2dd95SBruce Richardson 	char path[PATH_MAX];
72499a2dd95SBruce Richardson 	struct used_mask *msk;
72599a2dd95SBruce Richardson 	struct mem_area *ma = NULL;
72699a2dd95SBruce Richardson 	void *data = NULL;
72799a2dd95SBruce Richardson 	int fd = -1;
72899a2dd95SBruce Richardson 	const struct internal_config *internal_conf =
72999a2dd95SBruce Richardson 		eal_get_internal_configuration();
73099a2dd95SBruce Richardson 
73199a2dd95SBruce Richardson 	if (arr == NULL) {
73299a2dd95SBruce Richardson 		rte_errno = EINVAL;
73399a2dd95SBruce Richardson 		return -1;
73499a2dd95SBruce Richardson 	}
73599a2dd95SBruce Richardson 
73699a2dd95SBruce Richardson 	if (fully_validate(name, elt_sz, len))
73799a2dd95SBruce Richardson 		return -1;
73899a2dd95SBruce Richardson 
73999a2dd95SBruce Richardson 	/* allocate mem area before doing anything */
74099a2dd95SBruce Richardson 	ma = malloc(sizeof(*ma));
74199a2dd95SBruce Richardson 	if (ma == NULL) {
74299a2dd95SBruce Richardson 		rte_errno = ENOMEM;
74399a2dd95SBruce Richardson 		return -1;
74499a2dd95SBruce Richardson 	}
74599a2dd95SBruce Richardson 
74699a2dd95SBruce Richardson 	page_sz = rte_mem_page_size();
74799a2dd95SBruce Richardson 	if (page_sz == (size_t)-1) {
74899a2dd95SBruce Richardson 		free(ma);
74999a2dd95SBruce Richardson 		return -1;
75099a2dd95SBruce Richardson 	}
75199a2dd95SBruce Richardson 
75299a2dd95SBruce Richardson 	/* calculate our memory limits */
75399a2dd95SBruce Richardson 	mmap_len = calc_data_size(page_sz, elt_sz, len);
75499a2dd95SBruce Richardson 
75599a2dd95SBruce Richardson 	data = eal_get_virtual_area(NULL, &mmap_len, page_sz, 0, 0);
75699a2dd95SBruce Richardson 	if (data == NULL) {
75799a2dd95SBruce Richardson 		free(ma);
75899a2dd95SBruce Richardson 		return -1;
75999a2dd95SBruce Richardson 	}
76099a2dd95SBruce Richardson 
76199a2dd95SBruce Richardson 	rte_spinlock_lock(&mem_area_lock);
76299a2dd95SBruce Richardson 
76399a2dd95SBruce Richardson 	fd = -1;
76499a2dd95SBruce Richardson 
76599a2dd95SBruce Richardson 	if (internal_conf->no_shconf) {
76699a2dd95SBruce Richardson 		/* remap virtual area as writable */
76799a2dd95SBruce Richardson 		static const int flags = RTE_MAP_FORCE_ADDRESS |
76899a2dd95SBruce Richardson 			RTE_MAP_PRIVATE | RTE_MAP_ANONYMOUS;
76999a2dd95SBruce Richardson 		void *new_data = rte_mem_map(data, mmap_len,
77099a2dd95SBruce Richardson 			RTE_PROT_READ | RTE_PROT_WRITE, flags, fd, 0);
77199a2dd95SBruce Richardson 		if (new_data == NULL) {
772ae67895bSDavid Marchand 			EAL_LOG(DEBUG, "%s(): couldn't remap anonymous memory: %s",
77399a2dd95SBruce Richardson 					__func__, rte_strerror(rte_errno));
77499a2dd95SBruce Richardson 			goto fail;
77599a2dd95SBruce Richardson 		}
77699a2dd95SBruce Richardson 	} else {
77799a2dd95SBruce Richardson 		eal_get_fbarray_path(path, sizeof(path), name);
77899a2dd95SBruce Richardson 
77999a2dd95SBruce Richardson 		/*
78099a2dd95SBruce Richardson 		 * Each fbarray is unique to process namespace, i.e. the
78199a2dd95SBruce Richardson 		 * filename depends on process prefix. Try to take out a lock
78299a2dd95SBruce Richardson 		 * and see if we succeed. If we don't, someone else is using it
78399a2dd95SBruce Richardson 		 * already.
78499a2dd95SBruce Richardson 		 */
78599a2dd95SBruce Richardson 		fd = eal_file_open(path, EAL_OPEN_CREATE | EAL_OPEN_READWRITE);
78699a2dd95SBruce Richardson 		if (fd < 0) {
787ae67895bSDavid Marchand 			EAL_LOG(DEBUG, "%s(): couldn't open %s: %s",
78899a2dd95SBruce Richardson 				__func__, path, rte_strerror(rte_errno));
78999a2dd95SBruce Richardson 			goto fail;
79099a2dd95SBruce Richardson 		} else if (eal_file_lock(
79199a2dd95SBruce Richardson 				fd, EAL_FLOCK_EXCLUSIVE, EAL_FLOCK_RETURN)) {
792ae67895bSDavid Marchand 			EAL_LOG(DEBUG, "%s(): couldn't lock %s: %s",
79399a2dd95SBruce Richardson 				__func__, path, rte_strerror(rte_errno));
79499a2dd95SBruce Richardson 			rte_errno = EBUSY;
79599a2dd95SBruce Richardson 			goto fail;
79699a2dd95SBruce Richardson 		}
79799a2dd95SBruce Richardson 
79899a2dd95SBruce Richardson 		/* take out a non-exclusive lock, so that other processes could
79999a2dd95SBruce Richardson 		 * still attach to it, but no other process could reinitialize
80099a2dd95SBruce Richardson 		 * it.
80199a2dd95SBruce Richardson 		 */
80299a2dd95SBruce Richardson 		if (eal_file_lock(fd, EAL_FLOCK_SHARED, EAL_FLOCK_RETURN))
80399a2dd95SBruce Richardson 			goto fail;
80499a2dd95SBruce Richardson 
80599a2dd95SBruce Richardson 		if (resize_and_map(fd, path, data, mmap_len))
80699a2dd95SBruce Richardson 			goto fail;
80799a2dd95SBruce Richardson 	}
80899a2dd95SBruce Richardson 	ma->addr = data;
80999a2dd95SBruce Richardson 	ma->len = mmap_len;
81099a2dd95SBruce Richardson 	ma->fd = fd;
81199a2dd95SBruce Richardson 
81299a2dd95SBruce Richardson 	/* do not close fd - keep it until detach/destroy */
81399a2dd95SBruce Richardson 	TAILQ_INSERT_TAIL(&mem_area_tailq, ma, next);
81499a2dd95SBruce Richardson 
81599a2dd95SBruce Richardson 	/* initialize the data */
81699a2dd95SBruce Richardson 	memset(data, 0, mmap_len);
81799a2dd95SBruce Richardson 
81899a2dd95SBruce Richardson 	/* populate data structure */
81999a2dd95SBruce Richardson 	strlcpy(arr->name, name, sizeof(arr->name));
82099a2dd95SBruce Richardson 	arr->data = data;
82199a2dd95SBruce Richardson 	arr->len = len;
82299a2dd95SBruce Richardson 	arr->elt_sz = elt_sz;
82399a2dd95SBruce Richardson 	arr->count = 0;
82499a2dd95SBruce Richardson 
82599a2dd95SBruce Richardson 	msk = get_used_mask(data, elt_sz, len);
82699a2dd95SBruce Richardson 	msk->n_masks = MASK_LEN_TO_IDX(RTE_ALIGN_CEIL(len, MASK_ALIGN));
82799a2dd95SBruce Richardson 
82899a2dd95SBruce Richardson 	rte_rwlock_init(&arr->rwlock);
82999a2dd95SBruce Richardson 
83099a2dd95SBruce Richardson 	rte_spinlock_unlock(&mem_area_lock);
83199a2dd95SBruce Richardson 
83299a2dd95SBruce Richardson 	return 0;
83399a2dd95SBruce Richardson fail:
83499a2dd95SBruce Richardson 	if (data)
83599a2dd95SBruce Richardson 		rte_mem_unmap(data, mmap_len);
83699a2dd95SBruce Richardson 	if (fd >= 0)
83799a2dd95SBruce Richardson 		close(fd);
83899a2dd95SBruce Richardson 	free(ma);
83999a2dd95SBruce Richardson 
84099a2dd95SBruce Richardson 	rte_spinlock_unlock(&mem_area_lock);
84199a2dd95SBruce Richardson 	return -1;
84299a2dd95SBruce Richardson }
84399a2dd95SBruce Richardson 
84499a2dd95SBruce Richardson int
rte_fbarray_attach(struct rte_fbarray * arr)84599a2dd95SBruce Richardson rte_fbarray_attach(struct rte_fbarray *arr)
84699a2dd95SBruce Richardson {
84799a2dd95SBruce Richardson 	struct mem_area *ma = NULL, *tmp = NULL;
84899a2dd95SBruce Richardson 	size_t page_sz, mmap_len;
84999a2dd95SBruce Richardson 	char path[PATH_MAX];
85099a2dd95SBruce Richardson 	void *data = NULL;
85199a2dd95SBruce Richardson 	int fd = -1;
85299a2dd95SBruce Richardson 
85399a2dd95SBruce Richardson 	if (arr == NULL) {
85499a2dd95SBruce Richardson 		rte_errno = EINVAL;
85599a2dd95SBruce Richardson 		return -1;
85699a2dd95SBruce Richardson 	}
85799a2dd95SBruce Richardson 
85899a2dd95SBruce Richardson 	/*
85999a2dd95SBruce Richardson 	 * we don't need to synchronize attach as two values we need (element
86099a2dd95SBruce Richardson 	 * size and array length) are constant for the duration of life of
86199a2dd95SBruce Richardson 	 * the array, so the parts we care about will not race.
86299a2dd95SBruce Richardson 	 */
86399a2dd95SBruce Richardson 
86499a2dd95SBruce Richardson 	if (fully_validate(arr->name, arr->elt_sz, arr->len))
86599a2dd95SBruce Richardson 		return -1;
86699a2dd95SBruce Richardson 
86799a2dd95SBruce Richardson 	ma = malloc(sizeof(*ma));
86899a2dd95SBruce Richardson 	if (ma == NULL) {
86999a2dd95SBruce Richardson 		rte_errno = ENOMEM;
87099a2dd95SBruce Richardson 		return -1;
87199a2dd95SBruce Richardson 	}
87299a2dd95SBruce Richardson 
87399a2dd95SBruce Richardson 	page_sz = rte_mem_page_size();
87499a2dd95SBruce Richardson 	if (page_sz == (size_t)-1) {
87599a2dd95SBruce Richardson 		free(ma);
87699a2dd95SBruce Richardson 		return -1;
87799a2dd95SBruce Richardson 	}
87899a2dd95SBruce Richardson 
87999a2dd95SBruce Richardson 	mmap_len = calc_data_size(page_sz, arr->elt_sz, arr->len);
88099a2dd95SBruce Richardson 
88199a2dd95SBruce Richardson 	/* check the tailq - maybe user has already mapped this address space */
88299a2dd95SBruce Richardson 	rte_spinlock_lock(&mem_area_lock);
88399a2dd95SBruce Richardson 
88499a2dd95SBruce Richardson 	TAILQ_FOREACH(tmp, &mem_area_tailq, next) {
88599a2dd95SBruce Richardson 		if (overlap(tmp, arr->data, mmap_len)) {
88699a2dd95SBruce Richardson 			rte_errno = EEXIST;
88799a2dd95SBruce Richardson 			goto fail;
88899a2dd95SBruce Richardson 		}
88999a2dd95SBruce Richardson 	}
89099a2dd95SBruce Richardson 
89199a2dd95SBruce Richardson 	/* we know this memory area is unique, so proceed */
89299a2dd95SBruce Richardson 
89399a2dd95SBruce Richardson 	data = eal_get_virtual_area(arr->data, &mmap_len, page_sz, 0, 0);
89499a2dd95SBruce Richardson 	if (data == NULL)
89599a2dd95SBruce Richardson 		goto fail;
89699a2dd95SBruce Richardson 
89799a2dd95SBruce Richardson 	eal_get_fbarray_path(path, sizeof(path), arr->name);
89899a2dd95SBruce Richardson 
89999a2dd95SBruce Richardson 	fd = eal_file_open(path, EAL_OPEN_READWRITE);
90099a2dd95SBruce Richardson 	if (fd < 0) {
90199a2dd95SBruce Richardson 		goto fail;
90299a2dd95SBruce Richardson 	}
90399a2dd95SBruce Richardson 
90499a2dd95SBruce Richardson 	/* lock the file, to let others know we're using it */
90599a2dd95SBruce Richardson 	if (eal_file_lock(fd, EAL_FLOCK_SHARED, EAL_FLOCK_RETURN))
90699a2dd95SBruce Richardson 		goto fail;
90799a2dd95SBruce Richardson 
90899a2dd95SBruce Richardson 	if (resize_and_map(fd, path, data, mmap_len))
90999a2dd95SBruce Richardson 		goto fail;
91099a2dd95SBruce Richardson 
91199a2dd95SBruce Richardson 	/* store our new memory area */
91299a2dd95SBruce Richardson 	ma->addr = data;
91399a2dd95SBruce Richardson 	ma->fd = fd; /* keep fd until detach/destroy */
91499a2dd95SBruce Richardson 	ma->len = mmap_len;
91599a2dd95SBruce Richardson 
91699a2dd95SBruce Richardson 	TAILQ_INSERT_TAIL(&mem_area_tailq, ma, next);
91799a2dd95SBruce Richardson 
91899a2dd95SBruce Richardson 	/* we're done */
91999a2dd95SBruce Richardson 
92099a2dd95SBruce Richardson 	rte_spinlock_unlock(&mem_area_lock);
92199a2dd95SBruce Richardson 	return 0;
92299a2dd95SBruce Richardson fail:
92399a2dd95SBruce Richardson 	if (data)
92499a2dd95SBruce Richardson 		rte_mem_unmap(data, mmap_len);
92599a2dd95SBruce Richardson 	if (fd >= 0)
92699a2dd95SBruce Richardson 		close(fd);
92799a2dd95SBruce Richardson 	free(ma);
92899a2dd95SBruce Richardson 	rte_spinlock_unlock(&mem_area_lock);
92999a2dd95SBruce Richardson 	return -1;
93099a2dd95SBruce Richardson }
93199a2dd95SBruce Richardson 
93299a2dd95SBruce Richardson int
rte_fbarray_detach(struct rte_fbarray * arr)93399a2dd95SBruce Richardson rte_fbarray_detach(struct rte_fbarray *arr)
93499a2dd95SBruce Richardson {
93599a2dd95SBruce Richardson 	struct mem_area *tmp = NULL;
93699a2dd95SBruce Richardson 	size_t mmap_len;
93799a2dd95SBruce Richardson 	int ret = -1;
93899a2dd95SBruce Richardson 
93999a2dd95SBruce Richardson 	if (arr == NULL) {
94099a2dd95SBruce Richardson 		rte_errno = EINVAL;
94199a2dd95SBruce Richardson 		return -1;
94299a2dd95SBruce Richardson 	}
94399a2dd95SBruce Richardson 
94499a2dd95SBruce Richardson 	/*
94599a2dd95SBruce Richardson 	 * we don't need to synchronize detach as two values we need (element
94699a2dd95SBruce Richardson 	 * size and total capacity) are constant for the duration of life of
94799a2dd95SBruce Richardson 	 * the array, so the parts we care about will not race. if the user is
94899a2dd95SBruce Richardson 	 * detaching while doing something else in the same process, we can't
94999a2dd95SBruce Richardson 	 * really do anything about it, things will blow up either way.
95099a2dd95SBruce Richardson 	 */
95199a2dd95SBruce Richardson 
95299a2dd95SBruce Richardson 	size_t page_sz = rte_mem_page_size();
95399a2dd95SBruce Richardson 	if (page_sz == (size_t)-1)
95499a2dd95SBruce Richardson 		return -1;
95599a2dd95SBruce Richardson 
95699a2dd95SBruce Richardson 	mmap_len = calc_data_size(page_sz, arr->elt_sz, arr->len);
95799a2dd95SBruce Richardson 
95899a2dd95SBruce Richardson 	/* does this area exist? */
95999a2dd95SBruce Richardson 	rte_spinlock_lock(&mem_area_lock);
96099a2dd95SBruce Richardson 
96199a2dd95SBruce Richardson 	TAILQ_FOREACH(tmp, &mem_area_tailq, next) {
96299a2dd95SBruce Richardson 		if (tmp->addr == arr->data && tmp->len == mmap_len)
96399a2dd95SBruce Richardson 			break;
96499a2dd95SBruce Richardson 	}
96599a2dd95SBruce Richardson 	if (tmp == NULL) {
96699a2dd95SBruce Richardson 		rte_errno = ENOENT;
96799a2dd95SBruce Richardson 		ret = -1;
96899a2dd95SBruce Richardson 		goto out;
96999a2dd95SBruce Richardson 	}
97099a2dd95SBruce Richardson 
97199a2dd95SBruce Richardson 	rte_mem_unmap(arr->data, mmap_len);
97299a2dd95SBruce Richardson 
97399a2dd95SBruce Richardson 	/* area is unmapped, close fd and remove the tailq entry */
97499a2dd95SBruce Richardson 	if (tmp->fd >= 0)
97599a2dd95SBruce Richardson 		close(tmp->fd);
97699a2dd95SBruce Richardson 	TAILQ_REMOVE(&mem_area_tailq, tmp, next);
97799a2dd95SBruce Richardson 	free(tmp);
97899a2dd95SBruce Richardson 
97999a2dd95SBruce Richardson 	ret = 0;
98099a2dd95SBruce Richardson out:
98199a2dd95SBruce Richardson 	rte_spinlock_unlock(&mem_area_lock);
98299a2dd95SBruce Richardson 	return ret;
98399a2dd95SBruce Richardson }
98499a2dd95SBruce Richardson 
98599a2dd95SBruce Richardson int
rte_fbarray_destroy(struct rte_fbarray * arr)98699a2dd95SBruce Richardson rte_fbarray_destroy(struct rte_fbarray *arr)
98799a2dd95SBruce Richardson {
98899a2dd95SBruce Richardson 	struct mem_area *tmp = NULL;
98999a2dd95SBruce Richardson 	size_t mmap_len;
99099a2dd95SBruce Richardson 	int fd, ret;
99199a2dd95SBruce Richardson 	char path[PATH_MAX];
99299a2dd95SBruce Richardson 	const struct internal_config *internal_conf =
99399a2dd95SBruce Richardson 		eal_get_internal_configuration();
99499a2dd95SBruce Richardson 
99599a2dd95SBruce Richardson 	if (arr == NULL) {
99699a2dd95SBruce Richardson 		rte_errno = EINVAL;
99799a2dd95SBruce Richardson 		return -1;
99899a2dd95SBruce Richardson 	}
99999a2dd95SBruce Richardson 
100099a2dd95SBruce Richardson 	/*
100199a2dd95SBruce Richardson 	 * we don't need to synchronize detach as two values we need (element
100299a2dd95SBruce Richardson 	 * size and total capacity) are constant for the duration of life of
100399a2dd95SBruce Richardson 	 * the array, so the parts we care about will not race. if the user is
100499a2dd95SBruce Richardson 	 * detaching while doing something else in the same process, we can't
100599a2dd95SBruce Richardson 	 * really do anything about it, things will blow up either way.
100699a2dd95SBruce Richardson 	 */
100799a2dd95SBruce Richardson 
100899a2dd95SBruce Richardson 	size_t page_sz = rte_mem_page_size();
100999a2dd95SBruce Richardson 	if (page_sz == (size_t)-1)
101099a2dd95SBruce Richardson 		return -1;
101199a2dd95SBruce Richardson 
101299a2dd95SBruce Richardson 	mmap_len = calc_data_size(page_sz, arr->elt_sz, arr->len);
101399a2dd95SBruce Richardson 
101499a2dd95SBruce Richardson 	/* does this area exist? */
101599a2dd95SBruce Richardson 	rte_spinlock_lock(&mem_area_lock);
101699a2dd95SBruce Richardson 
101799a2dd95SBruce Richardson 	TAILQ_FOREACH(tmp, &mem_area_tailq, next) {
101899a2dd95SBruce Richardson 		if (tmp->addr == arr->data && tmp->len == mmap_len)
101999a2dd95SBruce Richardson 			break;
102099a2dd95SBruce Richardson 	}
102199a2dd95SBruce Richardson 	if (tmp == NULL) {
102299a2dd95SBruce Richardson 		rte_errno = ENOENT;
102399a2dd95SBruce Richardson 		ret = -1;
102499a2dd95SBruce Richardson 		goto out;
102599a2dd95SBruce Richardson 	}
102699a2dd95SBruce Richardson 	/* with no shconf, there were never any files to begin with */
102799a2dd95SBruce Richardson 	if (!internal_conf->no_shconf) {
102899a2dd95SBruce Richardson 		/*
102999a2dd95SBruce Richardson 		 * attempt to get an exclusive lock on the file, to ensure it
103099a2dd95SBruce Richardson 		 * has been detached by all other processes
103199a2dd95SBruce Richardson 		 */
103299a2dd95SBruce Richardson 		fd = tmp->fd;
103399a2dd95SBruce Richardson 		if (eal_file_lock(fd, EAL_FLOCK_EXCLUSIVE, EAL_FLOCK_RETURN)) {
1034ae67895bSDavid Marchand 			EAL_LOG(DEBUG, "Cannot destroy fbarray - another process is using it");
103599a2dd95SBruce Richardson 			rte_errno = EBUSY;
103699a2dd95SBruce Richardson 			ret = -1;
103799a2dd95SBruce Richardson 			goto out;
103899a2dd95SBruce Richardson 		}
103999a2dd95SBruce Richardson 
104099a2dd95SBruce Richardson 		/* we're OK to destroy the file */
104199a2dd95SBruce Richardson 		eal_get_fbarray_path(path, sizeof(path), arr->name);
104299a2dd95SBruce Richardson 		if (unlink(path)) {
1043ae67895bSDavid Marchand 			EAL_LOG(DEBUG, "Cannot unlink fbarray: %s",
104499a2dd95SBruce Richardson 				strerror(errno));
104599a2dd95SBruce Richardson 			rte_errno = errno;
104699a2dd95SBruce Richardson 			/*
104799a2dd95SBruce Richardson 			 * we're still holding an exclusive lock, so drop it to
104899a2dd95SBruce Richardson 			 * shared.
104999a2dd95SBruce Richardson 			 */
105099a2dd95SBruce Richardson 			eal_file_lock(fd, EAL_FLOCK_SHARED, EAL_FLOCK_RETURN);
105199a2dd95SBruce Richardson 
105299a2dd95SBruce Richardson 			ret = -1;
105399a2dd95SBruce Richardson 			goto out;
105499a2dd95SBruce Richardson 		}
105599a2dd95SBruce Richardson 		close(fd);
105699a2dd95SBruce Richardson 	}
105799a2dd95SBruce Richardson 	rte_mem_unmap(arr->data, mmap_len);
105899a2dd95SBruce Richardson 
105999a2dd95SBruce Richardson 	/* area is unmapped, remove the tailq entry */
106099a2dd95SBruce Richardson 	TAILQ_REMOVE(&mem_area_tailq, tmp, next);
106199a2dd95SBruce Richardson 	free(tmp);
106299a2dd95SBruce Richardson 	ret = 0;
106399a2dd95SBruce Richardson 
106499a2dd95SBruce Richardson 	/* reset the fbarray structure */
106599a2dd95SBruce Richardson 	memset(arr, 0, sizeof(*arr));
106699a2dd95SBruce Richardson out:
106799a2dd95SBruce Richardson 	rte_spinlock_unlock(&mem_area_lock);
106899a2dd95SBruce Richardson 	return ret;
106999a2dd95SBruce Richardson }
107099a2dd95SBruce Richardson 
107199a2dd95SBruce Richardson void *
rte_fbarray_get(const struct rte_fbarray * arr,unsigned int idx)107299a2dd95SBruce Richardson rte_fbarray_get(const struct rte_fbarray *arr, unsigned int idx)
107399a2dd95SBruce Richardson {
107499a2dd95SBruce Richardson 	void *ret = NULL;
107599a2dd95SBruce Richardson 	if (arr == NULL) {
107699a2dd95SBruce Richardson 		rte_errno = EINVAL;
107799a2dd95SBruce Richardson 		return NULL;
107899a2dd95SBruce Richardson 	}
107999a2dd95SBruce Richardson 
108099a2dd95SBruce Richardson 	if (idx >= arr->len) {
108199a2dd95SBruce Richardson 		rte_errno = EINVAL;
108299a2dd95SBruce Richardson 		return NULL;
108399a2dd95SBruce Richardson 	}
108499a2dd95SBruce Richardson 
108599a2dd95SBruce Richardson 	ret = RTE_PTR_ADD(arr->data, idx * arr->elt_sz);
108699a2dd95SBruce Richardson 
108799a2dd95SBruce Richardson 	return ret;
108899a2dd95SBruce Richardson }
108999a2dd95SBruce Richardson 
109099a2dd95SBruce Richardson int
rte_fbarray_set_used(struct rte_fbarray * arr,unsigned int idx)109199a2dd95SBruce Richardson rte_fbarray_set_used(struct rte_fbarray *arr, unsigned int idx)
109299a2dd95SBruce Richardson {
109399a2dd95SBruce Richardson 	return set_used(arr, idx, true);
109499a2dd95SBruce Richardson }
109599a2dd95SBruce Richardson 
109699a2dd95SBruce Richardson int
rte_fbarray_set_free(struct rte_fbarray * arr,unsigned int idx)109799a2dd95SBruce Richardson rte_fbarray_set_free(struct rte_fbarray *arr, unsigned int idx)
109899a2dd95SBruce Richardson {
109999a2dd95SBruce Richardson 	return set_used(arr, idx, false);
110099a2dd95SBruce Richardson }
110199a2dd95SBruce Richardson 
110299a2dd95SBruce Richardson int
rte_fbarray_is_used(struct rte_fbarray * arr,unsigned int idx)110399a2dd95SBruce Richardson rte_fbarray_is_used(struct rte_fbarray *arr, unsigned int idx)
110499a2dd95SBruce Richardson {
110599a2dd95SBruce Richardson 	struct used_mask *msk;
110699a2dd95SBruce Richardson 	int msk_idx;
110799a2dd95SBruce Richardson 	uint64_t msk_bit;
110899a2dd95SBruce Richardson 	int ret = -1;
110999a2dd95SBruce Richardson 
111099a2dd95SBruce Richardson 	if (arr == NULL || idx >= arr->len) {
111199a2dd95SBruce Richardson 		rte_errno = EINVAL;
111299a2dd95SBruce Richardson 		return -1;
111399a2dd95SBruce Richardson 	}
111499a2dd95SBruce Richardson 
111599a2dd95SBruce Richardson 	/* prevent array from changing under us */
111699a2dd95SBruce Richardson 	rte_rwlock_read_lock(&arr->rwlock);
111799a2dd95SBruce Richardson 
111899a2dd95SBruce Richardson 	msk = get_used_mask(arr->data, arr->elt_sz, arr->len);
111999a2dd95SBruce Richardson 	msk_idx = MASK_LEN_TO_IDX(idx);
112099a2dd95SBruce Richardson 	msk_bit = 1ULL << MASK_LEN_TO_MOD(idx);
112199a2dd95SBruce Richardson 
112299a2dd95SBruce Richardson 	ret = (msk->data[msk_idx] & msk_bit) != 0;
112399a2dd95SBruce Richardson 
112499a2dd95SBruce Richardson 	rte_rwlock_read_unlock(&arr->rwlock);
112599a2dd95SBruce Richardson 
112699a2dd95SBruce Richardson 	return ret;
112799a2dd95SBruce Richardson }
112899a2dd95SBruce Richardson 
112999a2dd95SBruce Richardson static int
fbarray_find(struct rte_fbarray * arr,unsigned int start,bool next,bool used)113099a2dd95SBruce Richardson fbarray_find(struct rte_fbarray *arr, unsigned int start, bool next, bool used)
113199a2dd95SBruce Richardson {
113299a2dd95SBruce Richardson 	int ret = -1;
113399a2dd95SBruce Richardson 
113499a2dd95SBruce Richardson 	if (arr == NULL || start >= arr->len) {
113599a2dd95SBruce Richardson 		rte_errno = EINVAL;
113699a2dd95SBruce Richardson 		return -1;
113799a2dd95SBruce Richardson 	}
113899a2dd95SBruce Richardson 
113999a2dd95SBruce Richardson 	/* prevent array from changing under us */
114099a2dd95SBruce Richardson 	rte_rwlock_read_lock(&arr->rwlock);
114199a2dd95SBruce Richardson 
114299a2dd95SBruce Richardson 	/* cheap checks to prevent doing useless work */
114399a2dd95SBruce Richardson 	if (!used) {
114499a2dd95SBruce Richardson 		if (arr->len == arr->count) {
114599a2dd95SBruce Richardson 			rte_errno = ENOSPC;
114699a2dd95SBruce Richardson 			goto out;
114799a2dd95SBruce Richardson 		}
114899a2dd95SBruce Richardson 		if (arr->count == 0) {
114999a2dd95SBruce Richardson 			ret = start;
115099a2dd95SBruce Richardson 			goto out;
115199a2dd95SBruce Richardson 		}
115299a2dd95SBruce Richardson 	} else {
115399a2dd95SBruce Richardson 		if (arr->count == 0) {
115499a2dd95SBruce Richardson 			rte_errno = ENOENT;
115599a2dd95SBruce Richardson 			goto out;
115699a2dd95SBruce Richardson 		}
115799a2dd95SBruce Richardson 		if (arr->len == arr->count) {
115899a2dd95SBruce Richardson 			ret = start;
115999a2dd95SBruce Richardson 			goto out;
116099a2dd95SBruce Richardson 		}
116199a2dd95SBruce Richardson 	}
116299a2dd95SBruce Richardson 	if (next)
116399a2dd95SBruce Richardson 		ret = find_next(arr, start, used);
116499a2dd95SBruce Richardson 	else
116599a2dd95SBruce Richardson 		ret = find_prev(arr, start, used);
116699a2dd95SBruce Richardson out:
116799a2dd95SBruce Richardson 	rte_rwlock_read_unlock(&arr->rwlock);
116899a2dd95SBruce Richardson 	return ret;
116999a2dd95SBruce Richardson }
117099a2dd95SBruce Richardson 
117199a2dd95SBruce Richardson int
rte_fbarray_find_next_free(struct rte_fbarray * arr,unsigned int start)117299a2dd95SBruce Richardson rte_fbarray_find_next_free(struct rte_fbarray *arr, unsigned int start)
117399a2dd95SBruce Richardson {
117499a2dd95SBruce Richardson 	return fbarray_find(arr, start, true, false);
117599a2dd95SBruce Richardson }
117699a2dd95SBruce Richardson 
117799a2dd95SBruce Richardson int
rte_fbarray_find_next_used(struct rte_fbarray * arr,unsigned int start)117899a2dd95SBruce Richardson rte_fbarray_find_next_used(struct rte_fbarray *arr, unsigned int start)
117999a2dd95SBruce Richardson {
118099a2dd95SBruce Richardson 	return fbarray_find(arr, start, true, true);
118199a2dd95SBruce Richardson }
118299a2dd95SBruce Richardson 
118399a2dd95SBruce Richardson int
rte_fbarray_find_prev_free(struct rte_fbarray * arr,unsigned int start)118499a2dd95SBruce Richardson rte_fbarray_find_prev_free(struct rte_fbarray *arr, unsigned int start)
118599a2dd95SBruce Richardson {
118699a2dd95SBruce Richardson 	return fbarray_find(arr, start, false, false);
118799a2dd95SBruce Richardson }
118899a2dd95SBruce Richardson 
118999a2dd95SBruce Richardson int
rte_fbarray_find_prev_used(struct rte_fbarray * arr,unsigned int start)119099a2dd95SBruce Richardson rte_fbarray_find_prev_used(struct rte_fbarray *arr, unsigned int start)
119199a2dd95SBruce Richardson {
119299a2dd95SBruce Richardson 	return fbarray_find(arr, start, false, true);
119399a2dd95SBruce Richardson }
119499a2dd95SBruce Richardson 
119599a2dd95SBruce Richardson static int
fbarray_find_n(struct rte_fbarray * arr,unsigned int start,unsigned int n,bool next,bool used)119699a2dd95SBruce Richardson fbarray_find_n(struct rte_fbarray *arr, unsigned int start, unsigned int n,
119799a2dd95SBruce Richardson 		bool next, bool used)
119899a2dd95SBruce Richardson {
119999a2dd95SBruce Richardson 	int ret = -1;
120099a2dd95SBruce Richardson 
120199a2dd95SBruce Richardson 	if (arr == NULL || start >= arr->len || n > arr->len || n == 0) {
120299a2dd95SBruce Richardson 		rte_errno = EINVAL;
120399a2dd95SBruce Richardson 		return -1;
120499a2dd95SBruce Richardson 	}
120599a2dd95SBruce Richardson 	if (next && (arr->len - start) < n) {
120699a2dd95SBruce Richardson 		rte_errno = used ? ENOENT : ENOSPC;
120799a2dd95SBruce Richardson 		return -1;
120899a2dd95SBruce Richardson 	}
120999a2dd95SBruce Richardson 	if (!next && start < (n - 1)) {
121099a2dd95SBruce Richardson 		rte_errno = used ? ENOENT : ENOSPC;
121199a2dd95SBruce Richardson 		return -1;
121299a2dd95SBruce Richardson 	}
121399a2dd95SBruce Richardson 
121499a2dd95SBruce Richardson 	/* prevent array from changing under us */
121599a2dd95SBruce Richardson 	rte_rwlock_read_lock(&arr->rwlock);
121699a2dd95SBruce Richardson 
121799a2dd95SBruce Richardson 	/* cheap checks to prevent doing useless work */
121899a2dd95SBruce Richardson 	if (!used) {
121999a2dd95SBruce Richardson 		if (arr->len == arr->count || arr->len - arr->count < n) {
122099a2dd95SBruce Richardson 			rte_errno = ENOSPC;
122199a2dd95SBruce Richardson 			goto out;
122299a2dd95SBruce Richardson 		}
122399a2dd95SBruce Richardson 		if (arr->count == 0) {
122499a2dd95SBruce Richardson 			ret = next ? start : start - n + 1;
122599a2dd95SBruce Richardson 			goto out;
122699a2dd95SBruce Richardson 		}
122799a2dd95SBruce Richardson 	} else {
122899a2dd95SBruce Richardson 		if (arr->count < n) {
122999a2dd95SBruce Richardson 			rte_errno = ENOENT;
123099a2dd95SBruce Richardson 			goto out;
123199a2dd95SBruce Richardson 		}
123299a2dd95SBruce Richardson 		if (arr->count == arr->len) {
123399a2dd95SBruce Richardson 			ret = next ? start : start - n + 1;
123499a2dd95SBruce Richardson 			goto out;
123599a2dd95SBruce Richardson 		}
123699a2dd95SBruce Richardson 	}
123799a2dd95SBruce Richardson 
123899a2dd95SBruce Richardson 	if (next)
123999a2dd95SBruce Richardson 		ret = find_next_n(arr, start, n, used);
124099a2dd95SBruce Richardson 	else
124199a2dd95SBruce Richardson 		ret = find_prev_n(arr, start, n, used);
124299a2dd95SBruce Richardson out:
124399a2dd95SBruce Richardson 	rte_rwlock_read_unlock(&arr->rwlock);
124499a2dd95SBruce Richardson 	return ret;
124599a2dd95SBruce Richardson }
124699a2dd95SBruce Richardson 
124799a2dd95SBruce Richardson int
rte_fbarray_find_next_n_free(struct rte_fbarray * arr,unsigned int start,unsigned int n)124899a2dd95SBruce Richardson rte_fbarray_find_next_n_free(struct rte_fbarray *arr, unsigned int start,
124999a2dd95SBruce Richardson 		unsigned int n)
125099a2dd95SBruce Richardson {
125199a2dd95SBruce Richardson 	return fbarray_find_n(arr, start, n, true, false);
125299a2dd95SBruce Richardson }
125399a2dd95SBruce Richardson 
125499a2dd95SBruce Richardson int
rte_fbarray_find_next_n_used(struct rte_fbarray * arr,unsigned int start,unsigned int n)125599a2dd95SBruce Richardson rte_fbarray_find_next_n_used(struct rte_fbarray *arr, unsigned int start,
125699a2dd95SBruce Richardson 		unsigned int n)
125799a2dd95SBruce Richardson {
125899a2dd95SBruce Richardson 	return fbarray_find_n(arr, start, n, true, true);
125999a2dd95SBruce Richardson }
126099a2dd95SBruce Richardson 
126199a2dd95SBruce Richardson int
rte_fbarray_find_prev_n_free(struct rte_fbarray * arr,unsigned int start,unsigned int n)126299a2dd95SBruce Richardson rte_fbarray_find_prev_n_free(struct rte_fbarray *arr, unsigned int start,
126399a2dd95SBruce Richardson 		unsigned int n)
126499a2dd95SBruce Richardson {
126599a2dd95SBruce Richardson 	return fbarray_find_n(arr, start, n, false, false);
126699a2dd95SBruce Richardson }
126799a2dd95SBruce Richardson 
126899a2dd95SBruce Richardson int
rte_fbarray_find_prev_n_used(struct rte_fbarray * arr,unsigned int start,unsigned int n)126999a2dd95SBruce Richardson rte_fbarray_find_prev_n_used(struct rte_fbarray *arr, unsigned int start,
127099a2dd95SBruce Richardson 		unsigned int n)
127199a2dd95SBruce Richardson {
127299a2dd95SBruce Richardson 	return fbarray_find_n(arr, start, n, false, true);
127399a2dd95SBruce Richardson }
127499a2dd95SBruce Richardson 
127599a2dd95SBruce Richardson static int
fbarray_find_contig(struct rte_fbarray * arr,unsigned int start,bool next,bool used)127699a2dd95SBruce Richardson fbarray_find_contig(struct rte_fbarray *arr, unsigned int start, bool next,
127799a2dd95SBruce Richardson 		bool used)
127899a2dd95SBruce Richardson {
127999a2dd95SBruce Richardson 	int ret = -1;
128099a2dd95SBruce Richardson 
128199a2dd95SBruce Richardson 	if (arr == NULL || start >= arr->len) {
128299a2dd95SBruce Richardson 		rte_errno = EINVAL;
128399a2dd95SBruce Richardson 		return -1;
128499a2dd95SBruce Richardson 	}
128599a2dd95SBruce Richardson 
128699a2dd95SBruce Richardson 	/* prevent array from changing under us */
128799a2dd95SBruce Richardson 	rte_rwlock_read_lock(&arr->rwlock);
128899a2dd95SBruce Richardson 
128999a2dd95SBruce Richardson 	/* cheap checks to prevent doing useless work */
129099a2dd95SBruce Richardson 	if (used) {
129199a2dd95SBruce Richardson 		if (arr->count == 0) {
129299a2dd95SBruce Richardson 			ret = 0;
129399a2dd95SBruce Richardson 			goto out;
129499a2dd95SBruce Richardson 		}
129599a2dd95SBruce Richardson 		if (next && arr->count == arr->len) {
129699a2dd95SBruce Richardson 			ret = arr->len - start;
129799a2dd95SBruce Richardson 			goto out;
129899a2dd95SBruce Richardson 		}
129999a2dd95SBruce Richardson 		if (!next && arr->count == arr->len) {
130099a2dd95SBruce Richardson 			ret = start + 1;
130199a2dd95SBruce Richardson 			goto out;
130299a2dd95SBruce Richardson 		}
130399a2dd95SBruce Richardson 	} else {
130499a2dd95SBruce Richardson 		if (arr->len == arr->count) {
130599a2dd95SBruce Richardson 			ret = 0;
130699a2dd95SBruce Richardson 			goto out;
130799a2dd95SBruce Richardson 		}
130899a2dd95SBruce Richardson 		if (next && arr->count == 0) {
130999a2dd95SBruce Richardson 			ret = arr->len - start;
131099a2dd95SBruce Richardson 			goto out;
131199a2dd95SBruce Richardson 		}
131299a2dd95SBruce Richardson 		if (!next && arr->count == 0) {
131399a2dd95SBruce Richardson 			ret = start + 1;
131499a2dd95SBruce Richardson 			goto out;
131599a2dd95SBruce Richardson 		}
131699a2dd95SBruce Richardson 	}
131799a2dd95SBruce Richardson 
131899a2dd95SBruce Richardson 	if (next)
131999a2dd95SBruce Richardson 		ret = find_contig(arr, start, used);
132099a2dd95SBruce Richardson 	else
132199a2dd95SBruce Richardson 		ret = find_rev_contig(arr, start, used);
132299a2dd95SBruce Richardson out:
132399a2dd95SBruce Richardson 	rte_rwlock_read_unlock(&arr->rwlock);
132499a2dd95SBruce Richardson 	return ret;
132599a2dd95SBruce Richardson }
132699a2dd95SBruce Richardson 
132799a2dd95SBruce Richardson static int
fbarray_find_biggest(struct rte_fbarray * arr,unsigned int start,bool used,bool rev)132899a2dd95SBruce Richardson fbarray_find_biggest(struct rte_fbarray *arr, unsigned int start, bool used,
132999a2dd95SBruce Richardson 		bool rev)
133099a2dd95SBruce Richardson {
133199a2dd95SBruce Richardson 	int cur_idx, next_idx, cur_len, biggest_idx, biggest_len;
133299a2dd95SBruce Richardson 	/* don't stack if conditions, use function pointers instead */
133399a2dd95SBruce Richardson 	int (*find_func)(struct rte_fbarray *, unsigned int);
133499a2dd95SBruce Richardson 	int (*find_contig_func)(struct rte_fbarray *, unsigned int);
133599a2dd95SBruce Richardson 
133699a2dd95SBruce Richardson 	if (arr == NULL || start >= arr->len) {
133799a2dd95SBruce Richardson 		rte_errno = EINVAL;
133899a2dd95SBruce Richardson 		return -1;
133999a2dd95SBruce Richardson 	}
134099a2dd95SBruce Richardson 	/* the other API calls already do their fair share of cheap checks, so
134199a2dd95SBruce Richardson 	 * no need to do them here.
134299a2dd95SBruce Richardson 	 */
134399a2dd95SBruce Richardson 
134499a2dd95SBruce Richardson 	/* the API's called are thread-safe, but something may still happen
134599a2dd95SBruce Richardson 	 * between the API calls, so lock the fbarray. all other API's are
134699a2dd95SBruce Richardson 	 * read-locking the fbarray, so read lock here is OK.
134799a2dd95SBruce Richardson 	 */
134899a2dd95SBruce Richardson 	rte_rwlock_read_lock(&arr->rwlock);
134999a2dd95SBruce Richardson 
135099a2dd95SBruce Richardson 	/* pick out appropriate functions */
135199a2dd95SBruce Richardson 	if (used) {
135299a2dd95SBruce Richardson 		if (rev) {
135399a2dd95SBruce Richardson 			find_func = rte_fbarray_find_prev_used;
135499a2dd95SBruce Richardson 			find_contig_func = rte_fbarray_find_rev_contig_used;
135599a2dd95SBruce Richardson 		} else {
135699a2dd95SBruce Richardson 			find_func = rte_fbarray_find_next_used;
135799a2dd95SBruce Richardson 			find_contig_func = rte_fbarray_find_contig_used;
135899a2dd95SBruce Richardson 		}
135999a2dd95SBruce Richardson 	} else {
136099a2dd95SBruce Richardson 		if (rev) {
136199a2dd95SBruce Richardson 			find_func = rte_fbarray_find_prev_free;
136299a2dd95SBruce Richardson 			find_contig_func = rte_fbarray_find_rev_contig_free;
136399a2dd95SBruce Richardson 		} else {
136499a2dd95SBruce Richardson 			find_func = rte_fbarray_find_next_free;
136599a2dd95SBruce Richardson 			find_contig_func = rte_fbarray_find_contig_free;
136699a2dd95SBruce Richardson 		}
136799a2dd95SBruce Richardson 	}
136899a2dd95SBruce Richardson 
136999a2dd95SBruce Richardson 	cur_idx = start;
137099a2dd95SBruce Richardson 	biggest_idx = -1; /* default is error */
137199a2dd95SBruce Richardson 	biggest_len = 0;
137299a2dd95SBruce Richardson 	for (;;) {
137399a2dd95SBruce Richardson 		cur_idx = find_func(arr, cur_idx);
137499a2dd95SBruce Richardson 
137599a2dd95SBruce Richardson 		/* block found, check its length */
137699a2dd95SBruce Richardson 		if (cur_idx >= 0) {
137799a2dd95SBruce Richardson 			cur_len = find_contig_func(arr, cur_idx);
137899a2dd95SBruce Richardson 			/* decide where we go next */
137999a2dd95SBruce Richardson 			next_idx = rev ? cur_idx - cur_len : cur_idx + cur_len;
138099a2dd95SBruce Richardson 			/* move current index to start of chunk */
138199a2dd95SBruce Richardson 			cur_idx = rev ? next_idx + 1 : cur_idx;
138299a2dd95SBruce Richardson 
138399a2dd95SBruce Richardson 			if (cur_len > biggest_len) {
138499a2dd95SBruce Richardson 				biggest_idx = cur_idx;
138599a2dd95SBruce Richardson 				biggest_len = cur_len;
138699a2dd95SBruce Richardson 			}
138799a2dd95SBruce Richardson 			cur_idx = next_idx;
138899a2dd95SBruce Richardson 			/* in reverse mode, next_idx may be -1 if chunk started
138999a2dd95SBruce Richardson 			 * at array beginning. this means there's no more work
139099a2dd95SBruce Richardson 			 * to do.
139199a2dd95SBruce Richardson 			 */
139299a2dd95SBruce Richardson 			if (cur_idx < 0)
139399a2dd95SBruce Richardson 				break;
139499a2dd95SBruce Richardson 		} else {
139599a2dd95SBruce Richardson 			/* nothing more to find, stop. however, a failed API
139699a2dd95SBruce Richardson 			 * call has set rte_errno, which we want to ignore, as
139799a2dd95SBruce Richardson 			 * reaching the end of fbarray is not an error.
139899a2dd95SBruce Richardson 			 */
139999a2dd95SBruce Richardson 			rte_errno = 0;
140099a2dd95SBruce Richardson 			break;
140199a2dd95SBruce Richardson 		}
140299a2dd95SBruce Richardson 	}
140399a2dd95SBruce Richardson 	/* if we didn't find anything at all, set rte_errno */
140499a2dd95SBruce Richardson 	if (biggest_idx < 0)
140599a2dd95SBruce Richardson 		rte_errno = used ? ENOENT : ENOSPC;
140699a2dd95SBruce Richardson 
140799a2dd95SBruce Richardson 	rte_rwlock_read_unlock(&arr->rwlock);
140899a2dd95SBruce Richardson 	return biggest_idx;
140999a2dd95SBruce Richardson }
141099a2dd95SBruce Richardson 
141199a2dd95SBruce Richardson int
rte_fbarray_find_biggest_free(struct rte_fbarray * arr,unsigned int start)141299a2dd95SBruce Richardson rte_fbarray_find_biggest_free(struct rte_fbarray *arr, unsigned int start)
141399a2dd95SBruce Richardson {
141499a2dd95SBruce Richardson 	return fbarray_find_biggest(arr, start, false, false);
141599a2dd95SBruce Richardson }
141699a2dd95SBruce Richardson 
141799a2dd95SBruce Richardson int
rte_fbarray_find_biggest_used(struct rte_fbarray * arr,unsigned int start)141899a2dd95SBruce Richardson rte_fbarray_find_biggest_used(struct rte_fbarray *arr, unsigned int start)
141999a2dd95SBruce Richardson {
142099a2dd95SBruce Richardson 	return fbarray_find_biggest(arr, start, true, false);
142199a2dd95SBruce Richardson }
142299a2dd95SBruce Richardson 
142399a2dd95SBruce Richardson int
rte_fbarray_find_rev_biggest_free(struct rte_fbarray * arr,unsigned int start)142499a2dd95SBruce Richardson rte_fbarray_find_rev_biggest_free(struct rte_fbarray *arr, unsigned int start)
142599a2dd95SBruce Richardson {
142699a2dd95SBruce Richardson 	return fbarray_find_biggest(arr, start, false, true);
142799a2dd95SBruce Richardson }
142899a2dd95SBruce Richardson 
142999a2dd95SBruce Richardson int
rte_fbarray_find_rev_biggest_used(struct rte_fbarray * arr,unsigned int start)143099a2dd95SBruce Richardson rte_fbarray_find_rev_biggest_used(struct rte_fbarray *arr, unsigned int start)
143199a2dd95SBruce Richardson {
143299a2dd95SBruce Richardson 	return fbarray_find_biggest(arr, start, true, true);
143399a2dd95SBruce Richardson }
143499a2dd95SBruce Richardson 
143599a2dd95SBruce Richardson 
143699a2dd95SBruce Richardson int
rte_fbarray_find_contig_free(struct rte_fbarray * arr,unsigned int start)143799a2dd95SBruce Richardson rte_fbarray_find_contig_free(struct rte_fbarray *arr, unsigned int start)
143899a2dd95SBruce Richardson {
143999a2dd95SBruce Richardson 	return fbarray_find_contig(arr, start, true, false);
144099a2dd95SBruce Richardson }
144199a2dd95SBruce Richardson 
144299a2dd95SBruce Richardson int
rte_fbarray_find_contig_used(struct rte_fbarray * arr,unsigned int start)144399a2dd95SBruce Richardson rte_fbarray_find_contig_used(struct rte_fbarray *arr, unsigned int start)
144499a2dd95SBruce Richardson {
144599a2dd95SBruce Richardson 	return fbarray_find_contig(arr, start, true, true);
144699a2dd95SBruce Richardson }
144799a2dd95SBruce Richardson 
144899a2dd95SBruce Richardson int
rte_fbarray_find_rev_contig_free(struct rte_fbarray * arr,unsigned int start)144999a2dd95SBruce Richardson rte_fbarray_find_rev_contig_free(struct rte_fbarray *arr, unsigned int start)
145099a2dd95SBruce Richardson {
145199a2dd95SBruce Richardson 	return fbarray_find_contig(arr, start, false, false);
145299a2dd95SBruce Richardson }
145399a2dd95SBruce Richardson 
145499a2dd95SBruce Richardson int
rte_fbarray_find_rev_contig_used(struct rte_fbarray * arr,unsigned int start)145599a2dd95SBruce Richardson rte_fbarray_find_rev_contig_used(struct rte_fbarray *arr, unsigned int start)
145699a2dd95SBruce Richardson {
145799a2dd95SBruce Richardson 	return fbarray_find_contig(arr, start, false, true);
145899a2dd95SBruce Richardson }
145999a2dd95SBruce Richardson 
146099a2dd95SBruce Richardson int
rte_fbarray_find_idx(const struct rte_fbarray * arr,const void * elt)146199a2dd95SBruce Richardson rte_fbarray_find_idx(const struct rte_fbarray *arr, const void *elt)
146299a2dd95SBruce Richardson {
146399a2dd95SBruce Richardson 	void *end;
146499a2dd95SBruce Richardson 	int ret = -1;
146599a2dd95SBruce Richardson 
146699a2dd95SBruce Richardson 	/*
146799a2dd95SBruce Richardson 	 * no need to synchronize as it doesn't matter if underlying data
146899a2dd95SBruce Richardson 	 * changes - we're doing pointer arithmetic here.
146999a2dd95SBruce Richardson 	 */
147099a2dd95SBruce Richardson 
147199a2dd95SBruce Richardson 	if (arr == NULL || elt == NULL) {
147299a2dd95SBruce Richardson 		rte_errno = EINVAL;
147399a2dd95SBruce Richardson 		return -1;
147499a2dd95SBruce Richardson 	}
147599a2dd95SBruce Richardson 	end = RTE_PTR_ADD(arr->data, arr->elt_sz * arr->len);
147699a2dd95SBruce Richardson 	if (elt < arr->data || elt >= end) {
147799a2dd95SBruce Richardson 		rte_errno = EINVAL;
147899a2dd95SBruce Richardson 		return -1;
147999a2dd95SBruce Richardson 	}
148099a2dd95SBruce Richardson 
148199a2dd95SBruce Richardson 	ret = RTE_PTR_DIFF(elt, arr->data) / arr->elt_sz;
148299a2dd95SBruce Richardson 
148399a2dd95SBruce Richardson 	return ret;
148499a2dd95SBruce Richardson }
148599a2dd95SBruce Richardson 
148699a2dd95SBruce Richardson void
rte_fbarray_dump_metadata(struct rte_fbarray * arr,FILE * f)148799a2dd95SBruce Richardson rte_fbarray_dump_metadata(struct rte_fbarray *arr, FILE *f)
148899a2dd95SBruce Richardson {
148999a2dd95SBruce Richardson 	struct used_mask *msk;
149099a2dd95SBruce Richardson 	unsigned int i;
149199a2dd95SBruce Richardson 
149299a2dd95SBruce Richardson 	if (arr == NULL || f == NULL) {
149399a2dd95SBruce Richardson 		rte_errno = EINVAL;
149499a2dd95SBruce Richardson 		return;
149599a2dd95SBruce Richardson 	}
149699a2dd95SBruce Richardson 
149799a2dd95SBruce Richardson 	if (fully_validate(arr->name, arr->elt_sz, arr->len)) {
149899a2dd95SBruce Richardson 		fprintf(f, "Invalid file-backed array\n");
149970eb4069SDavid Marchand 		return;
150099a2dd95SBruce Richardson 	}
150199a2dd95SBruce Richardson 
150299a2dd95SBruce Richardson 	/* prevent array from changing under us */
150399a2dd95SBruce Richardson 	rte_rwlock_read_lock(&arr->rwlock);
150499a2dd95SBruce Richardson 
150599a2dd95SBruce Richardson 	fprintf(f, "File-backed array: %s\n", arr->name);
150699a2dd95SBruce Richardson 	fprintf(f, "size: %i occupied: %i elt_sz: %i\n",
150799a2dd95SBruce Richardson 			arr->len, arr->count, arr->elt_sz);
150899a2dd95SBruce Richardson 
150999a2dd95SBruce Richardson 	msk = get_used_mask(arr->data, arr->elt_sz, arr->len);
151099a2dd95SBruce Richardson 
151199a2dd95SBruce Richardson 	for (i = 0; i < msk->n_masks; i++)
151299a2dd95SBruce Richardson 		fprintf(f, "msk idx %i: 0x%016" PRIx64 "\n", i, msk->data[i]);
151399a2dd95SBruce Richardson 	rte_rwlock_read_unlock(&arr->rwlock);
151499a2dd95SBruce Richardson }
1515