per Intel policy to include file commit date using git cmd below. The policy does not apply to non-Intel (C) notices. git log --follow -C90% --format=%ad --date default <file> | tail -1 and then pull just the 4 digit year from the result. Intel copyrights were not added to files where Intel either had no contribution ot the contribution lacked substance (ie license header updates, formatting changes, etc). Contribution date used "--follow -C95%" to get the most accurate date. Note that several files in this patch didn't end the license/(c) block with a blank comment line so these were added as the vast majority of files do have this last blank line. Simply there for consistency. Signed-off-by: paul luse <paul.e.luse@intel.com> Change-Id: Id5b7ce4f658fe87132f14139ead58d6e285c04d4 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15192 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com> Community-CI: Mellanox Build Bot
494 lines
12 KiB
C
494 lines
12 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright (C) 2016 Intel Corporation.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
#include "spdk/stdinc.h"
|
|
|
|
#include "spdk/bit_array.h"
|
|
#include "spdk/bit_pool.h"
|
|
#include "spdk/env.h"
|
|
|
|
#include "spdk/likely.h"
|
|
#include "spdk/util.h"
|
|
|
|
typedef uint64_t spdk_bit_array_word;
|
|
#define SPDK_BIT_ARRAY_WORD_TZCNT(x) (__builtin_ctzll(x))
|
|
#define SPDK_BIT_ARRAY_WORD_POPCNT(x) (__builtin_popcountll(x))
|
|
#define SPDK_BIT_ARRAY_WORD_C(x) ((spdk_bit_array_word)(x))
|
|
#define SPDK_BIT_ARRAY_WORD_BYTES sizeof(spdk_bit_array_word)
|
|
#define SPDK_BIT_ARRAY_WORD_BITS (SPDK_BIT_ARRAY_WORD_BYTES * 8)
|
|
#define SPDK_BIT_ARRAY_WORD_INDEX_SHIFT spdk_u32log2(SPDK_BIT_ARRAY_WORD_BITS)
|
|
#define SPDK_BIT_ARRAY_WORD_INDEX_MASK ((1u << SPDK_BIT_ARRAY_WORD_INDEX_SHIFT) - 1)
|
|
|
|
struct spdk_bit_array {
|
|
uint32_t bit_count;
|
|
spdk_bit_array_word words[];
|
|
};
|
|
|
|
struct spdk_bit_array *
|
|
spdk_bit_array_create(uint32_t num_bits)
|
|
{
|
|
struct spdk_bit_array *ba = NULL;
|
|
|
|
spdk_bit_array_resize(&ba, num_bits);
|
|
|
|
return ba;
|
|
}
|
|
|
|
void
|
|
spdk_bit_array_free(struct spdk_bit_array **bap)
|
|
{
|
|
struct spdk_bit_array *ba;
|
|
|
|
if (!bap) {
|
|
return;
|
|
}
|
|
|
|
ba = *bap;
|
|
*bap = NULL;
|
|
spdk_free(ba);
|
|
}
|
|
|
|
static inline uint32_t
|
|
bit_array_word_count(uint32_t num_bits)
|
|
{
|
|
return (num_bits + SPDK_BIT_ARRAY_WORD_BITS - 1) >> SPDK_BIT_ARRAY_WORD_INDEX_SHIFT;
|
|
}
|
|
|
|
static inline spdk_bit_array_word
|
|
bit_array_word_mask(uint32_t num_bits)
|
|
{
|
|
assert(num_bits < SPDK_BIT_ARRAY_WORD_BITS);
|
|
return (SPDK_BIT_ARRAY_WORD_C(1) << num_bits) - 1;
|
|
}
|
|
|
|
int
|
|
spdk_bit_array_resize(struct spdk_bit_array **bap, uint32_t num_bits)
|
|
{
|
|
struct spdk_bit_array *new_ba;
|
|
uint32_t old_word_count, new_word_count;
|
|
size_t new_size;
|
|
|
|
/*
|
|
* Max number of bits allowed is UINT32_MAX - 1, because we use UINT32_MAX to denote
|
|
* when a set or cleared bit cannot be found.
|
|
*/
|
|
if (!bap || num_bits == UINT32_MAX) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
new_word_count = bit_array_word_count(num_bits);
|
|
new_size = offsetof(struct spdk_bit_array, words) + new_word_count * SPDK_BIT_ARRAY_WORD_BYTES;
|
|
|
|
/*
|
|
* Always keep one extra word with a 0 and a 1 past the actual required size so that the
|
|
* find_first functions can just keep going until they match.
|
|
*/
|
|
new_size += SPDK_BIT_ARRAY_WORD_BYTES;
|
|
|
|
new_ba = (struct spdk_bit_array *)spdk_realloc(*bap, new_size, 64);
|
|
if (!new_ba) {
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/*
|
|
* Set up special extra word (see above comment about find_first_clear).
|
|
*
|
|
* This is set to 0b10 so that find_first_clear will find a 0 at the very first
|
|
* bit past the end of the buffer, and find_first_set will find a 1 at the next bit
|
|
* past that.
|
|
*/
|
|
new_ba->words[new_word_count] = 0x2;
|
|
|
|
if (*bap == NULL) {
|
|
old_word_count = 0;
|
|
new_ba->bit_count = 0;
|
|
} else {
|
|
old_word_count = bit_array_word_count(new_ba->bit_count);
|
|
}
|
|
|
|
if (new_word_count > old_word_count) {
|
|
/* Zero out new entries */
|
|
memset(&new_ba->words[old_word_count], 0,
|
|
(new_word_count - old_word_count) * SPDK_BIT_ARRAY_WORD_BYTES);
|
|
} else if (new_word_count == old_word_count && num_bits < new_ba->bit_count) {
|
|
/* Make sure any existing partial last word is cleared beyond the new num_bits. */
|
|
uint32_t last_word_bits;
|
|
spdk_bit_array_word mask;
|
|
|
|
last_word_bits = num_bits & SPDK_BIT_ARRAY_WORD_INDEX_MASK;
|
|
mask = bit_array_word_mask(last_word_bits);
|
|
new_ba->words[old_word_count - 1] &= mask;
|
|
}
|
|
|
|
new_ba->bit_count = num_bits;
|
|
*bap = new_ba;
|
|
return 0;
|
|
}
|
|
|
|
uint32_t
|
|
spdk_bit_array_capacity(const struct spdk_bit_array *ba)
|
|
{
|
|
return ba->bit_count;
|
|
}
|
|
|
|
static inline int
|
|
bit_array_get_word(const struct spdk_bit_array *ba, uint32_t bit_index,
|
|
uint32_t *word_index, uint32_t *word_bit_index)
|
|
{
|
|
if (spdk_unlikely(bit_index >= ba->bit_count)) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
*word_index = bit_index >> SPDK_BIT_ARRAY_WORD_INDEX_SHIFT;
|
|
*word_bit_index = bit_index & SPDK_BIT_ARRAY_WORD_INDEX_MASK;
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool
|
|
spdk_bit_array_get(const struct spdk_bit_array *ba, uint32_t bit_index)
|
|
{
|
|
uint32_t word_index, word_bit_index;
|
|
|
|
if (bit_array_get_word(ba, bit_index, &word_index, &word_bit_index)) {
|
|
return false;
|
|
}
|
|
|
|
return (ba->words[word_index] >> word_bit_index) & 1U;
|
|
}
|
|
|
|
int
|
|
spdk_bit_array_set(struct spdk_bit_array *ba, uint32_t bit_index)
|
|
{
|
|
uint32_t word_index, word_bit_index;
|
|
|
|
if (bit_array_get_word(ba, bit_index, &word_index, &word_bit_index)) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
ba->words[word_index] |= (SPDK_BIT_ARRAY_WORD_C(1) << word_bit_index);
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
spdk_bit_array_clear(struct spdk_bit_array *ba, uint32_t bit_index)
|
|
{
|
|
uint32_t word_index, word_bit_index;
|
|
|
|
if (bit_array_get_word(ba, bit_index, &word_index, &word_bit_index)) {
|
|
/*
|
|
* Clearing past the end of the bit array is a no-op, since bit past the end
|
|
* are implicitly 0.
|
|
*/
|
|
return;
|
|
}
|
|
|
|
ba->words[word_index] &= ~(SPDK_BIT_ARRAY_WORD_C(1) << word_bit_index);
|
|
}
|
|
|
|
static inline uint32_t
|
|
bit_array_find_first(const struct spdk_bit_array *ba, uint32_t start_bit_index,
|
|
spdk_bit_array_word xor_mask)
|
|
{
|
|
uint32_t word_index, first_word_bit_index;
|
|
spdk_bit_array_word word, first_word_mask;
|
|
const spdk_bit_array_word *words, *cur_word;
|
|
|
|
if (spdk_unlikely(start_bit_index >= ba->bit_count)) {
|
|
return ba->bit_count;
|
|
}
|
|
|
|
word_index = start_bit_index >> SPDK_BIT_ARRAY_WORD_INDEX_SHIFT;
|
|
words = ba->words;
|
|
cur_word = &words[word_index];
|
|
|
|
/*
|
|
* Special case for first word: skip start_bit_index % SPDK_BIT_ARRAY_WORD_BITS bits
|
|
* within the first word.
|
|
*/
|
|
first_word_bit_index = start_bit_index & SPDK_BIT_ARRAY_WORD_INDEX_MASK;
|
|
first_word_mask = bit_array_word_mask(first_word_bit_index);
|
|
|
|
word = (*cur_word ^ xor_mask) & ~first_word_mask;
|
|
|
|
/*
|
|
* spdk_bit_array_resize() guarantees that an extra word with a 1 and a 0 will always be
|
|
* at the end of the words[] array, so just keep going until a word matches.
|
|
*/
|
|
while (word == 0) {
|
|
word = *++cur_word ^ xor_mask;
|
|
}
|
|
|
|
return ((uintptr_t)cur_word - (uintptr_t)words) * 8 + SPDK_BIT_ARRAY_WORD_TZCNT(word);
|
|
}
|
|
|
|
|
|
uint32_t
|
|
spdk_bit_array_find_first_set(const struct spdk_bit_array *ba, uint32_t start_bit_index)
|
|
{
|
|
uint32_t bit_index;
|
|
|
|
bit_index = bit_array_find_first(ba, start_bit_index, 0);
|
|
|
|
/*
|
|
* If we ran off the end of the array and found the 1 bit in the extra word,
|
|
* return UINT32_MAX to indicate no actual 1 bits were found.
|
|
*/
|
|
if (bit_index >= ba->bit_count) {
|
|
bit_index = UINT32_MAX;
|
|
}
|
|
|
|
return bit_index;
|
|
}
|
|
|
|
uint32_t
|
|
spdk_bit_array_find_first_clear(const struct spdk_bit_array *ba, uint32_t start_bit_index)
|
|
{
|
|
uint32_t bit_index;
|
|
|
|
bit_index = bit_array_find_first(ba, start_bit_index, SPDK_BIT_ARRAY_WORD_C(-1));
|
|
|
|
/*
|
|
* If we ran off the end of the array and found the 0 bit in the extra word,
|
|
* return UINT32_MAX to indicate no actual 0 bits were found.
|
|
*/
|
|
if (bit_index >= ba->bit_count) {
|
|
bit_index = UINT32_MAX;
|
|
}
|
|
|
|
return bit_index;
|
|
}
|
|
|
|
uint32_t
|
|
spdk_bit_array_count_set(const struct spdk_bit_array *ba)
|
|
{
|
|
const spdk_bit_array_word *cur_word = ba->words;
|
|
uint32_t word_count = bit_array_word_count(ba->bit_count);
|
|
uint32_t set_count = 0;
|
|
|
|
while (word_count--) {
|
|
/*
|
|
* No special treatment is needed for the last (potentially partial) word, since
|
|
* spdk_bit_array_resize() makes sure the bits past bit_count are cleared.
|
|
*/
|
|
set_count += SPDK_BIT_ARRAY_WORD_POPCNT(*cur_word++);
|
|
}
|
|
|
|
return set_count;
|
|
}
|
|
|
|
uint32_t
|
|
spdk_bit_array_count_clear(const struct spdk_bit_array *ba)
|
|
{
|
|
return ba->bit_count - spdk_bit_array_count_set(ba);
|
|
}
|
|
|
|
void
|
|
spdk_bit_array_store_mask(const struct spdk_bit_array *ba, void *mask)
|
|
{
|
|
uint32_t size, i;
|
|
uint32_t num_bits = spdk_bit_array_capacity(ba);
|
|
|
|
size = num_bits / CHAR_BIT;
|
|
memcpy(mask, ba->words, size);
|
|
|
|
for (i = 0; i < num_bits % CHAR_BIT; i++) {
|
|
if (spdk_bit_array_get(ba, i + size * CHAR_BIT)) {
|
|
((uint8_t *)mask)[size] |= (1U << i);
|
|
} else {
|
|
((uint8_t *)mask)[size] &= ~(1U << i);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
spdk_bit_array_load_mask(struct spdk_bit_array *ba, const void *mask)
|
|
{
|
|
uint32_t size, i;
|
|
uint32_t num_bits = spdk_bit_array_capacity(ba);
|
|
|
|
size = num_bits / CHAR_BIT;
|
|
memcpy(ba->words, mask, size);
|
|
|
|
for (i = 0; i < num_bits % CHAR_BIT; i++) {
|
|
if (((uint8_t *)mask)[size] & (1U << i)) {
|
|
spdk_bit_array_set(ba, i + size * CHAR_BIT);
|
|
} else {
|
|
spdk_bit_array_clear(ba, i + size * CHAR_BIT);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
spdk_bit_array_clear_mask(struct spdk_bit_array *ba)
|
|
{
|
|
uint32_t size, i;
|
|
uint32_t num_bits = spdk_bit_array_capacity(ba);
|
|
|
|
size = num_bits / CHAR_BIT;
|
|
memset(ba->words, 0, size);
|
|
|
|
for (i = 0; i < num_bits % CHAR_BIT; i++) {
|
|
spdk_bit_array_clear(ba, i + size * CHAR_BIT);
|
|
}
|
|
}
|
|
|
|
struct spdk_bit_pool {
|
|
struct spdk_bit_array *array;
|
|
uint32_t lowest_free_bit;
|
|
uint32_t free_count;
|
|
};
|
|
|
|
struct spdk_bit_pool *
|
|
spdk_bit_pool_create(uint32_t num_bits)
|
|
{
|
|
struct spdk_bit_pool *pool = NULL;
|
|
struct spdk_bit_array *array;
|
|
|
|
array = spdk_bit_array_create(num_bits);
|
|
if (array == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
pool = calloc(1, sizeof(*pool));
|
|
if (pool == NULL) {
|
|
spdk_bit_array_free(&array);
|
|
return NULL;
|
|
}
|
|
|
|
pool->array = array;
|
|
pool->lowest_free_bit = 0;
|
|
pool->free_count = num_bits;
|
|
|
|
return pool;
|
|
}
|
|
|
|
struct spdk_bit_pool *
|
|
spdk_bit_pool_create_from_array(struct spdk_bit_array *array)
|
|
{
|
|
struct spdk_bit_pool *pool = NULL;
|
|
|
|
pool = calloc(1, sizeof(*pool));
|
|
if (pool == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
pool->array = array;
|
|
pool->lowest_free_bit = spdk_bit_array_find_first_clear(array, 0);
|
|
pool->free_count = spdk_bit_array_count_clear(array);
|
|
|
|
return pool;
|
|
}
|
|
|
|
void
|
|
spdk_bit_pool_free(struct spdk_bit_pool **ppool)
|
|
{
|
|
struct spdk_bit_pool *pool;
|
|
|
|
if (!ppool) {
|
|
return;
|
|
}
|
|
|
|
pool = *ppool;
|
|
*ppool = NULL;
|
|
if (pool != NULL) {
|
|
spdk_bit_array_free(&pool->array);
|
|
free(pool);
|
|
}
|
|
}
|
|
|
|
int
|
|
spdk_bit_pool_resize(struct spdk_bit_pool **ppool, uint32_t num_bits)
|
|
{
|
|
struct spdk_bit_pool *pool;
|
|
int rc;
|
|
|
|
assert(ppool != NULL);
|
|
|
|
pool = *ppool;
|
|
rc = spdk_bit_array_resize(&pool->array, num_bits);
|
|
if (rc) {
|
|
return rc;
|
|
}
|
|
|
|
pool->lowest_free_bit = spdk_bit_array_find_first_clear(pool->array, 0);
|
|
pool->free_count = spdk_bit_array_count_clear(pool->array);
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint32_t
|
|
spdk_bit_pool_capacity(const struct spdk_bit_pool *pool)
|
|
{
|
|
return spdk_bit_array_capacity(pool->array);
|
|
}
|
|
|
|
bool
|
|
spdk_bit_pool_is_allocated(const struct spdk_bit_pool *pool, uint32_t bit_index)
|
|
{
|
|
return spdk_bit_array_get(pool->array, bit_index);
|
|
}
|
|
|
|
uint32_t
|
|
spdk_bit_pool_allocate_bit(struct spdk_bit_pool *pool)
|
|
{
|
|
uint32_t bit_index = pool->lowest_free_bit;
|
|
|
|
if (bit_index == UINT32_MAX) {
|
|
return UINT32_MAX;
|
|
}
|
|
|
|
spdk_bit_array_set(pool->array, bit_index);
|
|
pool->lowest_free_bit = spdk_bit_array_find_first_clear(pool->array, bit_index);
|
|
pool->free_count--;
|
|
return bit_index;
|
|
}
|
|
|
|
void
|
|
spdk_bit_pool_free_bit(struct spdk_bit_pool *pool, uint32_t bit_index)
|
|
{
|
|
assert(spdk_bit_array_get(pool->array, bit_index) == true);
|
|
|
|
spdk_bit_array_clear(pool->array, bit_index);
|
|
if (pool->lowest_free_bit > bit_index) {
|
|
pool->lowest_free_bit = bit_index;
|
|
}
|
|
pool->free_count++;
|
|
}
|
|
|
|
uint32_t
|
|
spdk_bit_pool_count_allocated(const struct spdk_bit_pool *pool)
|
|
{
|
|
return spdk_bit_array_capacity(pool->array) - pool->free_count;
|
|
}
|
|
|
|
uint32_t
|
|
spdk_bit_pool_count_free(const struct spdk_bit_pool *pool)
|
|
{
|
|
return pool->free_count;
|
|
}
|
|
|
|
void
|
|
spdk_bit_pool_store_mask(const struct spdk_bit_pool *pool, void *mask)
|
|
{
|
|
spdk_bit_array_store_mask(pool->array, mask);
|
|
}
|
|
|
|
void
|
|
spdk_bit_pool_load_mask(struct spdk_bit_pool *pool, const void *mask)
|
|
{
|
|
spdk_bit_array_load_mask(pool->array, mask);
|
|
pool->lowest_free_bit = spdk_bit_array_find_first_clear(pool->array, 0);
|
|
pool->free_count = spdk_bit_array_count_clear(pool->array);
|
|
}
|
|
|
|
void
|
|
spdk_bit_pool_free_all_bits(struct spdk_bit_pool *pool)
|
|
{
|
|
spdk_bit_array_clear_mask(pool->array);
|
|
pool->lowest_free_bit = 0;
|
|
pool->free_count = spdk_bit_array_capacity(pool->array);
|
|
}
|