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