1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 #include "ocf/ocf_def.h" 34 #include "ocf_env.h" 35 36 #include "spdk/crc32.h" 37 #include "spdk/env.h" 38 #include "spdk/log.h" 39 40 /* Number of buffers for mempool 41 * Need to be power of two - 1 for better memory utilization 42 * It depends on memory usage of OCF which 43 * in itself depends on the workload 44 * It is a big number because OCF uses allocators 45 * for every request it sends and receives 46 */ 47 #define ENV_ALLOCATOR_NBUFS 32767 48 #define GET_ELEMENTS_COUNT(_limit) (_limit < 0 ? ENV_ALLOCATOR_NBUFS : _limit) 49 50 /* Use unique index for env allocators */ 51 static env_atomic g_env_allocator_index = 0; 52 53 void * 54 env_allocator_new(env_allocator *allocator) 55 { 56 void *mem = spdk_mempool_get(allocator->mempool); 57 58 if (spdk_unlikely(!mem)) { 59 return NULL; 60 } 61 62 if (allocator->zero) { 63 memset(mem, 0, allocator->element_size); 64 } 65 66 return mem; 67 } 68 69 env_allocator * 70 env_allocator_create(uint32_t size, const char *name, bool zero) 71 { 72 return env_allocator_create_extended(size, name, -1, zero); 73 } 74 75 env_allocator * 76 env_allocator_create_extended(uint32_t size, const char *name, int limit, bool zero) 77 { 78 env_allocator *allocator; 79 char qualified_name[128] = {0}; 80 81 snprintf(qualified_name, 128, "ocf_env_%d", env_atomic_inc_return(&g_env_allocator_index)); 82 83 allocator = calloc(1, sizeof(*allocator)); 84 if (!allocator) { 85 return NULL; 86 } 87 88 allocator->mempool = spdk_mempool_create(qualified_name, 89 GET_ELEMENTS_COUNT(limit), size, 90 SPDK_MEMPOOL_DEFAULT_CACHE_SIZE, 91 SPDK_ENV_SOCKET_ID_ANY); 92 93 if (!allocator->mempool) { 94 SPDK_ERRLOG("mempool creation failed\n"); 95 free(allocator); 96 return NULL; 97 } 98 99 allocator->element_size = size; 100 allocator->element_count = GET_ELEMENTS_COUNT(limit); 101 allocator->zero = zero; 102 103 return allocator; 104 } 105 106 void 107 env_allocator_del(env_allocator *allocator, void *item) 108 { 109 spdk_mempool_put(allocator->mempool, item); 110 } 111 112 void 113 env_allocator_destroy(env_allocator *allocator) 114 { 115 if (allocator) { 116 if (allocator->element_count - spdk_mempool_count(allocator->mempool)) { 117 SPDK_ERRLOG("Not all objects deallocated\n"); 118 assert(false); 119 } 120 121 spdk_mempool_free(allocator->mempool); 122 free(allocator); 123 } 124 } 125 /* *** CRC *** */ 126 127 uint32_t 128 env_crc32(uint32_t crc, uint8_t const *message, size_t len) 129 { 130 return spdk_crc32_ieee_update(message, len, crc); 131 } 132 133 /* EXECUTION CONTEXTS */ 134 pthread_mutex_t *exec_context_mutex; 135 136 static void __attribute__((constructor)) init_execution_context(void) 137 { 138 unsigned count = env_get_execution_context_count(); 139 unsigned i; 140 141 ENV_BUG_ON(count == 0); 142 exec_context_mutex = malloc(count * sizeof(exec_context_mutex[0])); 143 ENV_BUG_ON(exec_context_mutex == NULL); 144 for (i = 0; i < count; i++) { 145 ENV_BUG_ON(pthread_mutex_init(&exec_context_mutex[i], NULL)); 146 } 147 } 148 149 static void __attribute__((destructor)) deinit_execution_context(void) 150 { 151 unsigned count = env_get_execution_context_count(); 152 unsigned i; 153 154 ENV_BUG_ON(count == 0); 155 ENV_BUG_ON(exec_context_mutex == NULL); 156 157 for (i = 0; i < count; i++) { 158 ENV_BUG_ON(pthread_mutex_destroy(&exec_context_mutex[i])); 159 } 160 free(exec_context_mutex); 161 } 162 163 /* get_execution_context must assure that after the call finishes, the caller 164 * will not get preempted from current execution context. For userspace env 165 * we simulate this behavior by acquiring per execution context mutex. As a 166 * result the caller might actually get preempted, but no other thread will 167 * execute in this context by the time the caller puts current execution ctx. */ 168 unsigned env_get_execution_context(void) 169 { 170 unsigned cpu; 171 172 cpu = sched_getcpu(); 173 cpu = (cpu == -1) ? 0 : cpu; 174 175 ENV_BUG_ON(pthread_mutex_lock(&exec_context_mutex[cpu])); 176 177 return cpu; 178 } 179 180 void env_put_execution_context(unsigned ctx) 181 { 182 pthread_mutex_unlock(&exec_context_mutex[ctx]); 183 } 184 185 unsigned env_get_execution_context_count(void) 186 { 187 int num = sysconf(_SC_NPROCESSORS_ONLN); 188 189 return (num == -1) ? 0 : num; 190 } 191