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 recieves 46 */ 47 #define ENV_ALLOCATOR_NBUFS 32767 48 49 /* Use unique index for env allocators */ 50 static env_atomic g_env_allocator_index = 0; 51 52 void * 53 env_allocator_new(env_allocator *allocator) 54 { 55 void *mem = spdk_mempool_get(allocator->mempool); 56 57 if (spdk_likely(mem)) { 58 memset(mem, 0, allocator->element_size); 59 } 60 61 return mem; 62 } 63 64 env_allocator * 65 env_allocator_create(uint32_t size, const char *name) 66 { 67 env_allocator *allocator; 68 char qualified_name[128] = {0}; 69 70 snprintf(qualified_name, 128, "ocf_env_%d", env_atomic_inc_return(&g_env_allocator_index)); 71 72 allocator = calloc(1, sizeof(*allocator)); 73 if (!allocator) { 74 return NULL; 75 } 76 77 allocator->mempool = spdk_mempool_create(qualified_name, 78 ENV_ALLOCATOR_NBUFS, size, 79 SPDK_MEMPOOL_DEFAULT_CACHE_SIZE, 80 SPDK_ENV_SOCKET_ID_ANY); 81 82 if (!allocator->mempool) { 83 SPDK_ERRLOG("mempool creation failed\n"); 84 free(allocator); 85 return NULL; 86 } 87 88 allocator->element_size = size; 89 90 return allocator; 91 } 92 93 void 94 env_allocator_del(env_allocator *allocator, void *item) 95 { 96 spdk_mempool_put(allocator->mempool, item); 97 } 98 99 void 100 env_allocator_destroy(env_allocator *allocator) 101 { 102 if (allocator) { 103 if (ENV_ALLOCATOR_NBUFS - spdk_mempool_count(allocator->mempool)) { 104 SPDK_ERRLOG("Not all objects deallocated\n"); 105 assert(false); 106 } 107 108 spdk_mempool_free(allocator->mempool); 109 free(allocator); 110 } 111 } 112 /* *** CRC *** */ 113 114 uint32_t 115 env_crc32(uint32_t crc, uint8_t const *message, size_t len) 116 { 117 return spdk_crc32_ieee_update(message, len, crc); 118 } 119 120 /* EXECUTION CONTEXTS */ 121 pthread_mutex_t *exec_context_mutex; 122 123 static void __attribute__((constructor)) init_execution_context(void) 124 { 125 unsigned count = env_get_execution_context_count(); 126 unsigned i; 127 128 ENV_BUG_ON(count == 0); 129 exec_context_mutex = malloc(count * sizeof(exec_context_mutex[0])); 130 ENV_BUG_ON(exec_context_mutex == NULL); 131 for (i = 0; i < count; i++) { 132 ENV_BUG_ON(pthread_mutex_init(&exec_context_mutex[i], NULL)); 133 } 134 } 135 136 static void __attribute__((destructor)) deinit_execution_context(void) 137 { 138 unsigned count = env_get_execution_context_count(); 139 unsigned i; 140 141 ENV_BUG_ON(count == 0); 142 ENV_BUG_ON(exec_context_mutex == NULL); 143 144 for (i = 0; i < count; i++) { 145 ENV_BUG_ON(pthread_mutex_destroy(&exec_context_mutex[i])); 146 } 147 free(exec_context_mutex); 148 } 149 150 /* get_execuction_context must assure that after the call finishes, the caller 151 * will not get preempted from current execution context. For userspace env 152 * we simulate this behavior by acquiring per execution context mutex. As a 153 * result the caller might actually get preempted, but no other thread will 154 * execute in this context by the time the caller puts current execution ctx. */ 155 unsigned env_get_execution_context(void) 156 { 157 unsigned cpu; 158 159 cpu = sched_getcpu(); 160 cpu = (cpu == -1) ? 0 : cpu; 161 162 ENV_BUG_ON(pthread_mutex_lock(&exec_context_mutex[cpu])); 163 164 return cpu; 165 } 166 167 void env_put_execution_context(unsigned ctx) 168 { 169 pthread_mutex_unlock(&exec_context_mutex[ctx]); 170 } 171 172 unsigned env_get_execution_context_count(void) 173 { 174 int num = sysconf(_SC_NPROCESSORS_ONLN); 175 176 return (num == -1) ? 0 : num; 177 } 178