diff options
Diffstat (limited to '')
-rw-r--r-- | src/spdk/lib/util/Makefile | 41 | ||||
-rw-r--r-- | src/spdk/lib/util/base64.c | 228 | ||||
-rw-r--r-- | src/spdk/lib/util/bit_array.c | 313 | ||||
-rw-r--r-- | src/spdk/lib/util/cpuset.c | 320 | ||||
-rw-r--r-- | src/spdk/lib/util/crc16.c | 53 | ||||
-rw-r--r-- | src/spdk/lib/util/crc32.c | 66 | ||||
-rw-r--r-- | src/spdk/lib/util/crc32_ieee.c | 48 | ||||
-rw-r--r-- | src/spdk/lib/util/crc32c.c | 89 | ||||
-rw-r--r-- | src/spdk/lib/util/fd.c | 103 | ||||
-rw-r--r-- | src/spdk/lib/util/strerror_tls.c | 43 | ||||
-rw-r--r-- | src/spdk/lib/util/string.c | 405 | ||||
-rw-r--r-- | src/spdk/lib/util/uuid.c | 67 |
12 files changed, 1776 insertions, 0 deletions
diff --git a/src/spdk/lib/util/Makefile b/src/spdk/lib/util/Makefile new file mode 100644 index 00000000..c31a506b --- /dev/null +++ b/src/spdk/lib/util/Makefile @@ -0,0 +1,41 @@ +# +# BSD LICENSE +# +# Copyright (c) Intel Corporation. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..) +include $(SPDK_ROOT_DIR)/mk/spdk.common.mk + +C_SRCS = base64.c bit_array.c cpuset.c crc16.c crc32.c crc32c.c crc32_ieee.c fd.c strerror_tls.c string.c uuid.c +LIBNAME = util +LOCAL_SYS_LIBS = -luuid + +include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk diff --git a/src/spdk/lib/util/base64.c b/src/spdk/lib/util/base64.c new file mode 100644 index 00000000..81361263 --- /dev/null +++ b/src/spdk/lib/util/base64.c @@ -0,0 +1,228 @@ +/*- + * BSD LICENSE + * + * Copyright(c) Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/stdinc.h" +#include "spdk/endian.h" +#include "spdk/base64.h" + +#define BASE64_ENC_BITMASK 0x3FUL +#define BASE64_PADDING_CHAR '=' + +static const char base64_enc_table[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + +static const char base64_urfsafe_enc_table[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789-_"; + +static const uint8_t +base64_dec_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255, + 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, + 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +}; + +static const uint8_t +base64_urlsafe_dec_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255, + 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 63, + 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +}; + +static int +_spdk_base64_encode(char *dst, const char *enc_table, const void *src, size_t src_len) +{ + uint32_t raw_u32; + + if (!dst || !src || src_len <= 0) { + return -EINVAL; + } + + while (src_len >= 4) { + raw_u32 = from_be32(src); + + *dst++ = enc_table[(raw_u32 >> 26) & BASE64_ENC_BITMASK]; + *dst++ = enc_table[(raw_u32 >> 20) & BASE64_ENC_BITMASK]; + *dst++ = enc_table[(raw_u32 >> 14) & BASE64_ENC_BITMASK]; + *dst++ = enc_table[(raw_u32 >> 8) & BASE64_ENC_BITMASK]; + + src_len -= 3; + src += 3; + } + + if (src_len == 0) { + goto out; + } + + raw_u32 = 0; + memcpy(&raw_u32, src, src_len); + raw_u32 = from_be32(&raw_u32); + + *dst++ = enc_table[(raw_u32 >> 26) & BASE64_ENC_BITMASK]; + *dst++ = enc_table[(raw_u32 >> 20) & BASE64_ENC_BITMASK]; + *dst++ = (src_len >= 2) ? enc_table[(raw_u32 >> 14) & BASE64_ENC_BITMASK] : BASE64_PADDING_CHAR; + *dst++ = (src_len == 3) ? enc_table[(raw_u32 >> 8) & BASE64_ENC_BITMASK] : BASE64_PADDING_CHAR; + +out: + *dst = '\0'; + + return 0; +} + +int +spdk_base64_encode(char *dst, const void *src, size_t src_len) +{ + return _spdk_base64_encode(dst, base64_enc_table, src, src_len); +} + +int +spdk_base64_urlsafe_encode(char *dst, const void *src, size_t src_len) +{ + return _spdk_base64_encode(dst, base64_urfsafe_enc_table, src, src_len); +} + +static int +_spdk_base64_decode(void *dst, size_t *_dst_len, const uint8_t *dec_table, const char *src) +{ + size_t src_strlen, dst_len; + size_t tail_len = 0; + const uint8_t *src_in; + uint32_t tmp[4]; + int i; + + if (!dst || !src) { + return -EINVAL; + } + + src_strlen = strlen(src); + + /* strlen of src should be 4n */ + if (src_strlen == 0 || src_strlen % 4 != 0) { + return -EINVAL; + } + + /* Consider Base64 padding, it at most has 2 padding characters. */ + for (i = 0; i < 2; i++) { + if (src[src_strlen - 1] != BASE64_PADDING_CHAR) { + break; + } + src_strlen--; + } + + /* strlen of src without padding shouldn't be 4n+1 */ + if (src_strlen == 0 || src_strlen % 4 == 1) { + return -EINVAL; + } + + dst_len = spdk_base64_get_decoded_len(src_strlen); + src_in = (const uint8_t *) src; + + /* space of dst can be used by to_be32 */ + while (src_strlen > 4) { + tmp[0] = dec_table[*src_in++]; + tmp[1] = dec_table[*src_in++]; + tmp[2] = dec_table[*src_in++]; + tmp[3] = dec_table[*src_in++]; + + if (tmp[0] == 255 || tmp[1] == 255 || tmp[2] == 255 || tmp[3] == 255) { + return -EINVAL; + } + + to_be32(dst, tmp[3] << 8 | tmp[2] << 14 | tmp[1] << 20 | tmp[0] << 26); + + dst += 3; + src_strlen -= 4; + } + + /* space of dst is not enough to be used by to_be32 */ + tmp[0] = dec_table[src_in[0]]; + tmp[1] = dec_table[src_in[1]]; + tmp[2] = (src_strlen >= 3) ? dec_table[src_in[2]] : 0; + tmp[3] = (src_strlen == 4) ? dec_table[src_in[3]] : 0; + tail_len = src_strlen - 1; + + if (tmp[0] == 255 || tmp[1] == 255 || tmp[2] == 255 || tmp[3] == 255) { + return -EINVAL; + } + + to_be32(&tmp[3], tmp[3] << 8 | tmp[2] << 14 | tmp[1] << 20 | tmp[0] << 26); + memcpy(dst, (uint8_t *)&tmp[3], tail_len); + + /* Assign pointers */ + if (_dst_len) { + *_dst_len = dst_len; + } + + return 0; +} + +int +spdk_base64_decode(void *dst, size_t *dst_len, const char *src) +{ + return _spdk_base64_decode(dst, dst_len, base64_dec_table, src); +} + +int +spdk_base64_urlsafe_decode(void *dst, size_t *dst_len, const char *src) +{ + return _spdk_base64_decode(dst, dst_len, base64_urlsafe_dec_table, src); +} diff --git a/src/spdk/lib/util/bit_array.c b/src/spdk/lib/util/bit_array.c new file mode 100644 index 00000000..d6c112f7 --- /dev/null +++ b/src/spdk/lib/util/bit_array.c @@ -0,0 +1,313 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/stdinc.h" + +#include "spdk/bit_array.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_dma_free(ba); +} + +static inline uint32_t +spdk_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 +spdk_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 = spdk_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_dma_realloc(*bap, new_size, 64, NULL); + 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 = spdk_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 = spdk_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 +_spdk_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 (_spdk_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 (_spdk_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 (_spdk_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 +_spdk_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 = spdk_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 = _spdk_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 = _spdk_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 = spdk_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); +} diff --git a/src/spdk/lib/util/cpuset.c b/src/spdk/lib/util/cpuset.c new file mode 100644 index 00000000..1a02e59f --- /dev/null +++ b/src/spdk/lib/util/cpuset.c @@ -0,0 +1,320 @@ +/*- + * BSD LICENSE + * + * Copyright(c) Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/cpuset.h" +#include "spdk/log.h" + +struct spdk_cpuset { + char str[SPDK_CPUSET_SIZE / 4]; + uint8_t cpus[SPDK_CPUSET_SIZE / 8]; +}; + +struct spdk_cpuset * +spdk_cpuset_alloc(void) +{ + return (struct spdk_cpuset *)calloc(sizeof(struct spdk_cpuset), 1); +} + +void +spdk_cpuset_free(struct spdk_cpuset *set) +{ + free(set); +} + +bool +spdk_cpuset_equal(const struct spdk_cpuset *set1, const struct spdk_cpuset *set2) +{ + assert(set1 != NULL); + assert(set2 != NULL); + return memcmp(set1->cpus, set2->cpus, sizeof(set2->cpus)) == 0; +} + +void +spdk_cpuset_copy(struct spdk_cpuset *set1, const struct spdk_cpuset *set2) +{ + assert(set1 != NULL); + assert(set2 != NULL); + memcpy(&set1->cpus, &set2->cpus, sizeof(set2->cpus)); +} + +void +spdk_cpuset_and(struct spdk_cpuset *set1, const struct spdk_cpuset *set2) +{ + unsigned int i; + assert(set1 != NULL); + assert(set2 != NULL); + for (i = 0; i < sizeof(set2->cpus); i++) { + set1->cpus[i] &= set2->cpus[i]; + } +} + +void +spdk_cpuset_or(struct spdk_cpuset *set1, const struct spdk_cpuset *set2) +{ + unsigned int i; + assert(set1 != NULL); + assert(set2 != NULL); + for (i = 0; i < sizeof(set2->cpus); i++) { + set1->cpus[i] |= set2->cpus[i]; + } +} + +void +spdk_cpuset_zero(struct spdk_cpuset *set) +{ + assert(set != NULL); + memset(set->cpus, 0, sizeof(set->cpus)); +} + +void +spdk_cpuset_set_cpu(struct spdk_cpuset *set, uint32_t cpu, bool state) +{ + assert(set != NULL); + assert(cpu < sizeof(set->cpus) * 8); + if (state) { + set->cpus[cpu / 8] |= (1U << (cpu % 8)); + } else { + set->cpus[cpu / 8] &= ~(1U << (cpu % 8)); + } +} + +bool +spdk_cpuset_get_cpu(const struct spdk_cpuset *set, uint32_t cpu) +{ + assert(set != NULL); + assert(cpu < sizeof(set->cpus) * 8); + return (set->cpus[cpu / 8] >> (cpu % 8)) & 1U; +} + +uint32_t +spdk_cpuset_count(const struct spdk_cpuset *set) +{ + uint32_t count = 0; + uint8_t n; + unsigned int i; + for (i = 0; i < sizeof(set->cpus); i++) { + n = set->cpus[i]; + while (n) { + n &= (n - 1); + count++; + } + } + return count; +} + +const char * +spdk_cpuset_fmt(struct spdk_cpuset *set) +{ + uint32_t lcore, lcore_max = 0; + int val, i, n; + char *ptr; + static const char *hex = "0123456789abcdef"; + + assert(set != NULL); + + for (lcore = 0; lcore < sizeof(set->cpus) * 8; lcore++) { + if (spdk_cpuset_get_cpu(set, lcore)) { + lcore_max = lcore; + } + } + + ptr = set->str; + n = lcore_max / 8; + val = set->cpus[n]; + + /* Store first number only if it is not leading zero */ + if ((val & 0xf0) != 0) { + *(ptr++) = hex[(val & 0xf0) >> 4]; + } + *(ptr++) = hex[val & 0x0f]; + + for (i = n - 1; i >= 0; i--) { + val = set->cpus[i]; + *(ptr++) = hex[(val & 0xf0) >> 4]; + *(ptr++) = hex[val & 0x0f]; + } + *ptr = '\0'; + + return set->str; +} + +static int +hex_value(uint8_t c) +{ +#define V(x, y) [x] = y + 1 + static const int8_t val[256] = { + V('0', 0), V('1', 1), V('2', 2), V('3', 3), V('4', 4), + V('5', 5), V('6', 6), V('7', 7), V('8', 8), V('9', 9), + V('A', 0xA), V('B', 0xB), V('C', 0xC), V('D', 0xD), V('E', 0xE), V('F', 0xF), + V('a', 0xA), V('b', 0xB), V('c', 0xC), V('d', 0xD), V('e', 0xE), V('f', 0xF), + }; +#undef V + + return val[c] - 1; +} + +static int +parse_list(const char *mask, struct spdk_cpuset *set) +{ + char *end; + const char *ptr = mask; + uint32_t lcore; + uint32_t lcore_min, lcore_max; + + spdk_cpuset_zero(set); + lcore_min = UINT32_MAX; + + ptr++; + end = (char *)ptr; + do { + while (isblank(*ptr)) { + ptr++; + } + if (*ptr == '\0' || *ptr == ']' || *ptr == '-' || *ptr == ',') { + goto invalid_character; + } + + errno = 0; + lcore = strtoul(ptr, &end, 10); + if (errno) { + SPDK_ERRLOG("Conversion of core mask in '%s' failed\n", mask); + return -1; + } + + if (lcore >= sizeof(set->cpus) * 8) { + SPDK_ERRLOG("Core number %" PRIu32 " is out of range in '%s'\n", lcore, mask); + return -1; + } + + while (isblank(*end)) { + end++; + } + + if (*end == '-') { + lcore_min = lcore; + } else if (*end == ',' || *end == ']') { + lcore_max = lcore; + if (lcore_min == UINT32_MAX) { + lcore_min = lcore; + } + if (lcore_min > lcore_max) { + SPDK_ERRLOG("Invalid range of CPUs (%" PRIu32 " > %" PRIu32 ")\n", + lcore_min, lcore_max); + return -1; + } + for (lcore = lcore_min; lcore <= lcore_max; lcore++) { + spdk_cpuset_set_cpu(set, lcore, true); + } + lcore_min = UINT32_MAX; + } else { + goto invalid_character; + } + + ptr = end + 1; + + } while (*end != ']'); + + return 0; + +invalid_character: + if (*end == '\0') { + SPDK_ERRLOG("Unexpected end of core list '%s'\n", mask); + } else { + SPDK_ERRLOG("Parsing of core list '%s' failed on character '%c'\n", mask, *end); + } + return -1; +} + +static int +parse_mask(const char *mask, struct spdk_cpuset *set, size_t len) +{ + int i, j; + char c; + int val; + uint32_t lcore = 0; + + if (mask[0] == '0' && (mask[1] == 'x' || mask[1] == 'X')) { + mask += 2; + len -= 2; + } + + spdk_cpuset_zero(set); + for (i = len - 1; i >= 0; i--) { + c = mask[i]; + val = hex_value(c); + if (val < 0) { + /* Invalid character */ + SPDK_ERRLOG("Invalid character in core mask '%s' (%c)\n", mask, c); + return -1; + } + for (j = 0; j < 4 && lcore < sizeof(set->cpus); j++, lcore++) { + if ((1 << j) & val) { + spdk_cpuset_set_cpu(set, lcore, true); + } + } + } + + return 0; +} + +int +spdk_cpuset_parse(struct spdk_cpuset *set, const char *mask) +{ + int ret; + size_t len; + + if (mask == NULL || set == NULL) { + return -1; + } + + while (isblank(*mask)) { + mask++; + } + + len = strlen(mask); + while (len > 0 && isblank(mask[len - 1])) { + len--; + } + + if (len == 0) { + return -1; + } + + if (mask[0] == '[') { + ret = parse_list(mask, set); + } else { + ret = parse_mask(mask, set, len); + } + + return ret; +} diff --git a/src/spdk/lib/util/crc16.c b/src/spdk/lib/util/crc16.c new file mode 100644 index 00000000..491c9058 --- /dev/null +++ b/src/spdk/lib/util/crc16.c @@ -0,0 +1,53 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/crc16.h" + +uint16_t +spdk_crc16_t10dif(const void *buf, size_t len) +{ + uint32_t j, rem = 0; + const uint8_t *data = (const uint8_t *)buf; + size_t i; + + uint16_t poly = SPDK_T10DIF_CRC16_POLYNOMIAL; + + for (i = 0; i < len; i++) { + rem = rem ^ (data[i] << 8); + for (j = 0; j < 8; j++) { + rem = rem << 1; + rem = (rem & 0x10000) ? rem ^ poly : rem; + } + } + return (uint16_t)rem; +} diff --git a/src/spdk/lib/util/crc32.c b/src/spdk/lib/util/crc32.c new file mode 100644 index 00000000..dfef9c54 --- /dev/null +++ b/src/spdk/lib/util/crc32.c @@ -0,0 +1,66 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/crc32.h" + +void +spdk_crc32_table_init(struct spdk_crc32_table *table, uint32_t polynomial_reflect) +{ + int i, j; + uint32_t val; + + for (i = 0; i < 256; i++) { + val = i; + for (j = 0; j < 8; j++) { + if (val & 1) { + val = (val >> 1) ^ polynomial_reflect; + } else { + val = (val >> 1); + } + } + table->table[i] = val; + } +} + +uint32_t +spdk_crc32_update(const struct spdk_crc32_table *table, const void *buf, size_t len, uint32_t crc) +{ + const uint8_t *buf_u8 = buf; + size_t i; + + for (i = 0; i < len; i++) { + crc = (crc >> 8) ^ table->table[(crc ^ buf_u8[i]) & 0xff]; + } + + return crc; +} diff --git a/src/spdk/lib/util/crc32_ieee.c b/src/spdk/lib/util/crc32_ieee.c new file mode 100644 index 00000000..2956e3fc --- /dev/null +++ b/src/spdk/lib/util/crc32_ieee.c @@ -0,0 +1,48 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/crc32.h" + +static struct spdk_crc32_table g_crc32_ieee_table; + +__attribute__((constructor)) static void +spdk_crc32_ieee_init(void) +{ + spdk_crc32_table_init(&g_crc32_ieee_table, SPDK_CRC32_POLYNOMIAL_REFLECT); +} + +uint32_t +spdk_crc32_ieee_update(const void *buf, size_t len, uint32_t crc) +{ + return spdk_crc32_update(&g_crc32_ieee_table, buf, len, crc); +} diff --git a/src/spdk/lib/util/crc32c.c b/src/spdk/lib/util/crc32c.c new file mode 100644 index 00000000..e95283b3 --- /dev/null +++ b/src/spdk/lib/util/crc32c.c @@ -0,0 +1,89 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/crc32.h" + +#if defined(__x86_64__) && defined(__SSE4_2__) +#include <x86intrin.h> + +uint32_t +spdk_crc32c_update(const void *buf, size_t len, uint32_t crc) +{ + uint64_t crc_tmp64; + size_t count; + + /* _mm_crc32_u64() needs a 64-bit intermediate value */ + crc_tmp64 = crc; + + /* Process as much of the buffer as possible in 64-bit blocks. */ + count = len / 8; + while (count--) { + uint64_t block; + + /* + * Use memcpy() to avoid unaligned loads, which are undefined behavior in C. + * The compiler will optimize out the memcpy() in release builds. + */ + memcpy(&block, buf, sizeof(block)); + crc_tmp64 = _mm_crc32_u64(crc_tmp64, block); + buf += sizeof(block); + } + crc = (uint32_t)crc_tmp64; + + /* Handle any trailing bytes. */ + count = len & 7; + while (count--) { + crc = _mm_crc32_u8(crc, *(const uint8_t *)buf); + buf++; + } + + return crc; +} + +#else /* SSE 4.2 (CRC32 instruction) not available */ + +static struct spdk_crc32_table g_crc32c_table; + +__attribute__((constructor)) static void +spdk_crc32c_init(void) +{ + spdk_crc32_table_init(&g_crc32c_table, SPDK_CRC32C_POLYNOMIAL_REFLECT); +} + +uint32_t +spdk_crc32c_update(const void *buf, size_t len, uint32_t crc) +{ + return spdk_crc32_update(&g_crc32c_table, buf, len, crc); +} + +#endif diff --git a/src/spdk/lib/util/fd.c b/src/spdk/lib/util/fd.c new file mode 100644 index 00000000..6b0d0d55 --- /dev/null +++ b/src/spdk/lib/util/fd.c @@ -0,0 +1,103 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/stdinc.h" + +#include "spdk/fd.h" + +#ifdef __linux__ +#include <linux/fs.h> +#endif + +static uint64_t +dev_get_size(int fd) +{ +#if defined(DIOCGMEDIASIZE) /* FreeBSD */ + off_t size; + + if (ioctl(fd, DIOCGMEDIASIZE, &size) == 0) { + return size; + } +#elif defined(__linux__) && defined(BLKGETSIZE64) + uint64_t size; + + if (ioctl(fd, BLKGETSIZE64, &size) == 0) { + return size; + } +#endif + + return 0; +} + +uint32_t +spdk_fd_get_blocklen(int fd) +{ +#if defined(DKIOCGETBLOCKSIZE) /* FreeBSD */ + uint32_t blocklen; + + if (ioctl(fd, DKIOCGETBLOCKSIZE, &blocklen) == 0) { + return blocklen; + } +#elif defined(__linux__) && defined(BLKSSZGET) + uint32_t blocklen; + + if (ioctl(fd, BLKSSZGET, &blocklen) == 0) { + return blocklen; + } +#endif + + return 0; +} + +uint64_t +spdk_fd_get_size(int fd) +{ + struct stat st; + + if (fstat(fd, &st) != 0) { + return 0; + } + + if (S_ISLNK(st.st_mode)) { + return 0; + } + + if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)) { + return dev_get_size(fd); + } else if (S_ISREG(st.st_mode)) { + return st.st_size; + } + + /* Not REG, CHR or BLK */ + return 0; +} diff --git a/src/spdk/lib/util/strerror_tls.c b/src/spdk/lib/util/strerror_tls.c new file mode 100644 index 00000000..c9dc8f13 --- /dev/null +++ b/src/spdk/lib/util/strerror_tls.c @@ -0,0 +1,43 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/string.h" + +static __thread char strerror_message[64]; + +const char * +spdk_strerror(int errnum) +{ + spdk_strerror_r(errnum, strerror_message, sizeof(strerror_message)); + return strerror_message; +} diff --git a/src/spdk/lib/util/string.c b/src/spdk/lib/util/string.c new file mode 100644 index 00000000..455aa20f --- /dev/null +++ b/src/spdk/lib/util/string.c @@ -0,0 +1,405 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/stdinc.h" + +#include "spdk/string.h" + +char * +spdk_vsprintf_alloc(const char *format, va_list args) +{ + va_list args_copy; + char *buf; + size_t bufsize; + int rc; + + /* Try with a small buffer first. */ + bufsize = 32; + + /* Limit maximum buffer size to something reasonable so we don't loop forever. */ + while (bufsize <= 1024 * 1024) { + buf = malloc(bufsize); + if (buf == NULL) { + return NULL; + } + + va_copy(args_copy, args); + rc = vsnprintf(buf, bufsize, format, args_copy); + va_end(args_copy); + + /* + * If vsnprintf() returned a count within our current buffer size, we are done. + * The count does not include the \0 terminator, so rc == bufsize is not OK. + */ + if (rc >= 0 && (size_t)rc < bufsize) { + return buf; + } + + /* + * vsnprintf() should return the required space, but some libc versions do not + * implement this correctly, so just double the buffer size and try again. + * + * We don't need the data in buf, so rather than realloc(), use free() and malloc() + * again to avoid a copy. + */ + free(buf); + bufsize *= 2; + } + + return NULL; +} + +char * +spdk_sprintf_alloc(const char *format, ...) +{ + va_list args; + char *ret; + + va_start(args, format); + ret = spdk_vsprintf_alloc(format, args); + va_end(args); + + return ret; +} + +char * +spdk_strlwr(char *s) +{ + char *p; + + if (s == NULL) { + return NULL; + } + + p = s; + while (*p != '\0') { + *p = tolower(*p); + p++; + } + + return s; +} + +char * +spdk_strsepq(char **stringp, const char *delim) +{ + char *p, *q, *r; + int quoted = 0, bslash = 0; + + p = *stringp; + if (p == NULL) { + return NULL; + } + + r = q = p; + while (*q != '\0' && *q != '\n') { + /* eat quoted characters */ + if (bslash) { + bslash = 0; + *r++ = *q++; + continue; + } else if (quoted) { + if (quoted == '"' && *q == '\\') { + bslash = 1; + q++; + continue; + } else if (*q == quoted) { + quoted = 0; + q++; + continue; + } + *r++ = *q++; + continue; + } else if (*q == '\\') { + bslash = 1; + q++; + continue; + } else if (*q == '"' || *q == '\'') { + quoted = *q; + q++; + continue; + } + + /* separator? */ + if (strchr(delim, *q) == NULL) { + *r++ = *q++; + continue; + } + + /* new string */ + q++; + break; + } + *r = '\0'; + + /* skip tailer */ + while (*q != '\0' && strchr(delim, *q) != NULL) { + q++; + } + if (*q != '\0') { + *stringp = q; + } else { + *stringp = NULL; + } + + return p; +} + +char * +spdk_str_trim(char *s) +{ + char *p, *q; + + if (s == NULL) { + return NULL; + } + + /* remove header */ + p = s; + while (*p != '\0' && isspace(*p)) { + p++; + } + + /* remove tailer */ + q = p + strlen(p); + while (q - 1 >= p && isspace(*(q - 1))) { + q--; + *q = '\0'; + } + + /* if remove header, move */ + if (p != s) { + q = s; + while (*p != '\0') { + *q++ = *p++; + } + *q = '\0'; + } + + return s; +} + +void +spdk_strcpy_pad(void *dst, const char *src, size_t size, int pad) +{ + size_t len; + + len = strlen(src); + if (len < size) { + memcpy(dst, src, len); + memset((char *)dst + len, pad, size - len); + } else { + memcpy(dst, src, size); + } +} + +size_t +spdk_strlen_pad(const void *str, size_t size, int pad) +{ + const uint8_t *start; + const uint8_t *iter; + uint8_t pad_byte; + + pad_byte = (uint8_t)pad; + start = (const uint8_t *)str; + + if (size == 0) { + return 0; + } + + iter = start + size - 1; + while (1) { + if (*iter != pad_byte) { + return iter - start + 1; + } + + if (iter == start) { + /* Hit the start of the string finding only pad_byte. */ + return 0; + } + iter--; + } +} + +int +spdk_parse_ip_addr(char *ip, char **host, char **port) +{ + char *p; + + if (ip == NULL) { + return -EINVAL; + } + + *host = NULL; + *port = NULL; + + if (ip[0] == '[') { + /* IPv6 */ + p = strchr(ip, ']'); + if (p == NULL) { + return -EINVAL; + } + *host = &ip[1]; + *p = '\0'; + + p++; + if (*p == '\0') { + return 0; + } else if (*p != ':') { + return -EINVAL; + } + + p++; + if (*p == '\0') { + return 0; + } + + *port = p; + } else { + /* IPv4 */ + p = strchr(ip, ':'); + if (p == NULL) { + *host = ip; + return 0; + } + + *host = ip; + *p = '\0'; + + p++; + if (*p == '\0') { + return 0; + } + + *port = p; + } + + return 0; +} + +size_t +spdk_str_chomp(char *s) +{ + size_t len = strlen(s); + size_t removed = 0; + + while (len > 0) { + if (s[len - 1] != '\r' && s[len - 1] != '\n') { + break; + } + + s[len - 1] = '\0'; + len--; + removed++; + } + + return removed; +} + +void +spdk_strerror_r(int errnum, char *buf, size_t buflen) +{ + int rc; + +#if defined(__USE_GNU) + char *new_buffer; + new_buffer = strerror_r(errnum, buf, buflen); + if (new_buffer != NULL) { + snprintf(buf, buflen, "%s", new_buffer); + rc = 0; + } else { + rc = 1; + } +#else + rc = strerror_r(errnum, buf, buflen); +#endif + + if (rc != 0) { + snprintf(buf, buflen, "Unknown error %d", errnum); + } +} + +int +spdk_parse_capacity(const char *cap_str, uint64_t *cap, bool *has_prefix) +{ + int rc; + char bin_prefix; + + rc = sscanf(cap_str, "%"SCNu64"%c", cap, &bin_prefix); + if (rc == 1) { + *has_prefix = false; + return 0; + } else if (rc == 0) { + if (errno == 0) { + /* No scanf matches - the string does not start with a digit */ + return -EINVAL; + } else { + /* Parsing error */ + return -errno; + } + } + + *has_prefix = true; + switch (bin_prefix) { + case 'k': + case 'K': + *cap *= 1024; + break; + case 'm': + case 'M': + *cap *= 1024 * 1024; + break; + case 'g': + case 'G': + *cap *= 1024 * 1024 * 1024; + break; + default: + return -EINVAL; + } + + return 0; +} + +bool +spdk_mem_all_zero(const void *data, size_t size) +{ + const uint8_t *buf = data; + + while (size--) { + if (*buf++ != 0) { + return false; + } + } + + return true; +} diff --git a/src/spdk/lib/util/uuid.c b/src/spdk/lib/util/uuid.c new file mode 100644 index 00000000..1af7368f --- /dev/null +++ b/src/spdk/lib/util/uuid.c @@ -0,0 +1,67 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/uuid.h" + +#include <uuid/uuid.h> + +SPDK_STATIC_ASSERT(sizeof(struct spdk_uuid) == sizeof(uuid_t), "Size mismatch"); + +int +spdk_uuid_parse(struct spdk_uuid *uuid, const char *uuid_str) +{ + return uuid_parse(uuid_str, (void *)uuid) == 0 ? 0 : -EINVAL; +} + +int +spdk_uuid_fmt_lower(char *uuid_str, size_t uuid_str_size, const struct spdk_uuid *uuid) +{ + if (uuid_str_size < SPDK_UUID_STRING_LEN) { + return -EINVAL; + } + + uuid_unparse_lower((void *)uuid, uuid_str); + return 0; +} + +int +spdk_uuid_compare(const struct spdk_uuid *u1, const struct spdk_uuid *u2) +{ + return uuid_compare((void *)u1, (void *)u2); +} + +void +spdk_uuid_generate(struct spdk_uuid *uuid) +{ + uuid_generate((void *)uuid); +} |