1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) Intel Corporation. All rights reserved. 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 34 #include "spdk/stdinc.h" 35 36 #include "spdk/env.h" 37 #include "spdk/likely.h" 38 #include "spdk/string.h" 39 #include "spdk/util.h" 40 #include "spdk/memory.h" 41 #include "spdk/barrier.h" 42 #include "spdk/vhost.h" 43 #include "vhost_internal.h" 44 45 static struct spdk_cpuset g_vhost_core_mask; 46 47 static TAILQ_HEAD(, spdk_vhost_dev) g_vhost_devices = TAILQ_HEAD_INITIALIZER( 48 g_vhost_devices); 49 static pthread_mutex_t g_vhost_mutex = PTHREAD_MUTEX_INITIALIZER; 50 51 struct spdk_vhost_dev * 52 spdk_vhost_dev_next(struct spdk_vhost_dev *vdev) 53 { 54 if (vdev == NULL) { 55 return TAILQ_FIRST(&g_vhost_devices); 56 } 57 58 return TAILQ_NEXT(vdev, tailq); 59 } 60 61 struct spdk_vhost_dev * 62 spdk_vhost_dev_find(const char *ctrlr_name) 63 { 64 struct spdk_vhost_dev *vdev; 65 66 TAILQ_FOREACH(vdev, &g_vhost_devices, tailq) { 67 if (strcmp(vdev->name, ctrlr_name) == 0) { 68 return vdev; 69 } 70 } 71 72 return NULL; 73 } 74 75 static int 76 vhost_parse_core_mask(const char *mask, struct spdk_cpuset *cpumask) 77 { 78 int rc; 79 struct spdk_cpuset negative_vhost_mask; 80 81 if (cpumask == NULL) { 82 return -1; 83 } 84 85 if (mask == NULL) { 86 spdk_cpuset_copy(cpumask, &g_vhost_core_mask); 87 return 0; 88 } 89 90 rc = spdk_cpuset_parse(cpumask, mask); 91 if (rc < 0) { 92 SPDK_ERRLOG("invalid cpumask %s\n", mask); 93 return -1; 94 } 95 96 spdk_cpuset_copy(&negative_vhost_mask, &g_vhost_core_mask); 97 spdk_cpuset_negate(&negative_vhost_mask); 98 spdk_cpuset_and(&negative_vhost_mask, cpumask); 99 100 if (spdk_cpuset_count(&negative_vhost_mask) != 0) { 101 SPDK_ERRLOG("one of selected cpu is outside of core mask(=%s)\n", 102 spdk_cpuset_fmt(&g_vhost_core_mask)); 103 return -1; 104 } 105 106 spdk_cpuset_and(cpumask, &g_vhost_core_mask); 107 108 if (spdk_cpuset_count(cpumask) == 0) { 109 SPDK_ERRLOG("no cpu is selected among core mask(=%s)\n", 110 spdk_cpuset_fmt(&g_vhost_core_mask)); 111 return -1; 112 } 113 114 return 0; 115 } 116 117 int 118 vhost_dev_register(struct spdk_vhost_dev *vdev, const char *name, const char *mask_str, 119 const struct spdk_vhost_dev_backend *backend, 120 const struct spdk_vhost_user_dev_backend *user_backend) 121 { 122 struct spdk_cpuset cpumask = {}; 123 int rc; 124 125 assert(vdev); 126 if (name == NULL) { 127 SPDK_ERRLOG("Can't register controller with no name\n"); 128 return -EINVAL; 129 } 130 131 if (vhost_parse_core_mask(mask_str, &cpumask) != 0) { 132 SPDK_ERRLOG("cpumask %s is invalid (core mask is 0x%s)\n", 133 mask_str, spdk_cpuset_fmt(&g_vhost_core_mask)); 134 return -EINVAL; 135 } 136 137 if (spdk_vhost_dev_find(name)) { 138 SPDK_ERRLOG("vhost controller %s already exists.\n", name); 139 return -EEXIST; 140 } 141 142 vdev->name = strdup(name); 143 if (vdev->name == NULL) { 144 return -EIO; 145 } 146 147 vdev->backend = backend; 148 149 rc = vhost_user_dev_register(vdev, name, &cpumask, user_backend); 150 if (rc != 0) { 151 free(vdev->name); 152 return rc; 153 } 154 155 TAILQ_INSERT_TAIL(&g_vhost_devices, vdev, tailq); 156 157 SPDK_INFOLOG(vhost, "Controller %s: new controller added\n", vdev->name); 158 return 0; 159 } 160 161 int 162 vhost_dev_unregister(struct spdk_vhost_dev *vdev) 163 { 164 int rc; 165 166 rc = vhost_user_dev_unregister(vdev); 167 if (rc != 0) { 168 return rc; 169 } 170 171 SPDK_INFOLOG(vhost, "Controller %s: removed\n", vdev->name); 172 173 free(vdev->name); 174 TAILQ_REMOVE(&g_vhost_devices, vdev, tailq); 175 return 0; 176 } 177 178 const char * 179 spdk_vhost_dev_get_name(struct spdk_vhost_dev *vdev) 180 { 181 assert(vdev != NULL); 182 return vdev->name; 183 } 184 185 const struct spdk_cpuset * 186 spdk_vhost_dev_get_cpumask(struct spdk_vhost_dev *vdev) 187 { 188 assert(vdev != NULL); 189 return spdk_thread_get_cpumask(vdev->thread); 190 } 191 192 void 193 vhost_dump_info_json(struct spdk_vhost_dev *vdev, struct spdk_json_write_ctx *w) 194 { 195 assert(vdev->backend->dump_info_json != NULL); 196 vdev->backend->dump_info_json(vdev, w); 197 } 198 199 int 200 spdk_vhost_dev_remove(struct spdk_vhost_dev *vdev) 201 { 202 return vdev->backend->remove_device(vdev); 203 } 204 205 void 206 spdk_vhost_lock(void) 207 { 208 pthread_mutex_lock(&g_vhost_mutex); 209 } 210 211 int 212 spdk_vhost_trylock(void) 213 { 214 return -pthread_mutex_trylock(&g_vhost_mutex); 215 } 216 217 void 218 spdk_vhost_unlock(void) 219 { 220 pthread_mutex_unlock(&g_vhost_mutex); 221 } 222 223 void 224 spdk_vhost_init(spdk_vhost_init_cb init_cb) 225 { 226 uint32_t i; 227 int ret = 0; 228 229 ret = vhost_user_init(); 230 if (ret != 0) { 231 init_cb(ret); 232 return; 233 } 234 235 spdk_cpuset_zero(&g_vhost_core_mask); 236 SPDK_ENV_FOREACH_CORE(i) { 237 spdk_cpuset_set_cpu(&g_vhost_core_mask, i, true); 238 } 239 init_cb(ret); 240 } 241 242 static spdk_vhost_fini_cb g_fini_cb; 243 244 static void 245 vhost_fini(void *arg1) 246 { 247 struct spdk_vhost_dev *vdev, *tmp; 248 249 spdk_vhost_lock(); 250 vdev = spdk_vhost_dev_next(NULL); 251 while (vdev != NULL) { 252 tmp = spdk_vhost_dev_next(vdev); 253 spdk_vhost_dev_remove(vdev); 254 /* don't care if it fails, there's nothing we can do for now */ 255 vdev = tmp; 256 } 257 spdk_vhost_unlock(); 258 259 g_fini_cb(); 260 } 261 262 void 263 spdk_vhost_fini(spdk_vhost_fini_cb fini_cb) 264 { 265 g_fini_cb = fini_cb; 266 267 vhost_user_fini(vhost_fini); 268 } 269 270 static void 271 vhost_user_config_json(struct spdk_vhost_dev *vdev, struct spdk_json_write_ctx *w) 272 { 273 uint32_t delay_base_us; 274 uint32_t iops_threshold; 275 276 vdev->backend->write_config_json(vdev, w); 277 278 spdk_vhost_get_coalescing(vdev, &delay_base_us, &iops_threshold); 279 if (delay_base_us) { 280 spdk_json_write_object_begin(w); 281 spdk_json_write_named_string(w, "method", "vhost_controller_set_coalescing"); 282 283 spdk_json_write_named_object_begin(w, "params"); 284 spdk_json_write_named_string(w, "ctrlr", vdev->name); 285 spdk_json_write_named_uint32(w, "delay_base_us", delay_base_us); 286 spdk_json_write_named_uint32(w, "iops_threshold", iops_threshold); 287 spdk_json_write_object_end(w); 288 289 spdk_json_write_object_end(w); 290 } 291 } 292 293 void 294 spdk_vhost_config_json(struct spdk_json_write_ctx *w) 295 { 296 struct spdk_vhost_dev *vdev; 297 298 spdk_json_write_array_begin(w); 299 300 spdk_vhost_lock(); 301 for (vdev = spdk_vhost_dev_next(NULL); vdev != NULL; 302 vdev = spdk_vhost_dev_next(vdev)) { 303 vhost_user_config_json(vdev, w); 304 } 305 spdk_vhost_unlock(); 306 307 spdk_json_write_array_end(w); 308 } 309 310 SPDK_LOG_REGISTER_COMPONENT(vhost) 311 SPDK_LOG_REGISTER_COMPONENT(vhost_ring) 312