1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2018 Intel Corporation. 3 * All rights reserved. 4 */ 5 6 #include <ocf/ocf.h> 7 #ifdef SPDK_HAVE_EXECINFO_H 8 #include <execinfo.h> 9 #endif 10 11 #include "spdk/env.h" 12 #include "spdk/log.h" 13 14 #include "ctx.h" 15 #include "data.h" 16 17 ocf_ctx_t vbdev_ocf_ctx; 18 19 static ctx_data_t * 20 vbdev_ocf_ctx_data_alloc(uint32_t pages) 21 { 22 struct bdev_ocf_data *data; 23 void *buf; 24 uint32_t sz; 25 26 data = vbdev_ocf_data_alloc(1); 27 if (data == NULL) { 28 return NULL; 29 } 30 31 sz = pages * PAGE_SIZE; 32 buf = spdk_malloc(sz, PAGE_SIZE, NULL, 33 SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA); 34 if (buf == NULL) { 35 vbdev_ocf_data_free(data); 36 return NULL; 37 } 38 39 vbdev_ocf_iovs_add(data, buf, sz); 40 41 data->size = sz; 42 43 return data; 44 } 45 46 static void 47 vbdev_ocf_ctx_data_free(ctx_data_t *ctx_data) 48 { 49 struct bdev_ocf_data *data = ctx_data; 50 int i; 51 52 if (!data) { 53 return; 54 } 55 56 for (i = 0; i < data->iovcnt; i++) { 57 spdk_free(data->iovs[i].iov_base); 58 } 59 60 vbdev_ocf_data_free(data); 61 } 62 63 static int 64 vbdev_ocf_ctx_data_mlock(ctx_data_t *ctx_data) 65 { 66 /* TODO [mlock]: add mlock option */ 67 return 0; 68 } 69 70 static void 71 vbdev_ocf_ctx_data_munlock(ctx_data_t *ctx_data) 72 { 73 /* TODO [mlock]: add mlock option */ 74 } 75 76 static size_t 77 iovec_flatten(struct iovec *iov, size_t iovcnt, void *buf, size_t size, size_t offset) 78 { 79 size_t i, len, done = 0; 80 81 for (i = 0; i < iovcnt; i++) { 82 if (offset >= iov[i].iov_len) { 83 offset -= iov[i].iov_len; 84 continue; 85 } 86 87 if (iov[i].iov_base == NULL) { 88 continue; 89 } 90 91 if (done >= size) { 92 break; 93 } 94 95 len = MIN(size - done, iov[i].iov_len - offset); 96 memcpy(buf, iov[i].iov_base + offset, len); 97 buf += len; 98 done += len; 99 offset = 0; 100 } 101 102 return done; 103 } 104 105 static uint32_t 106 vbdev_ocf_ctx_data_rd(void *dst, ctx_data_t *src, uint32_t size) 107 { 108 struct bdev_ocf_data *s = src; 109 uint32_t size_local; 110 111 size_local = iovec_flatten(s->iovs, s->iovcnt, dst, size, s->seek); 112 s->seek += size_local; 113 114 return size_local; 115 } 116 117 static size_t 118 buf_to_iovec(const void *buf, size_t size, struct iovec *iov, size_t iovcnt, size_t offset) 119 { 120 size_t i, len, done = 0; 121 122 for (i = 0; i < iovcnt; i++) { 123 if (offset >= iov[i].iov_len) { 124 offset -= iov[i].iov_len; 125 continue; 126 } 127 128 if (iov[i].iov_base == NULL) { 129 continue; 130 } 131 132 if (done >= size) { 133 break; 134 } 135 136 len = MIN(size - done, iov[i].iov_len - offset); 137 memcpy(iov[i].iov_base + offset, buf, len); 138 buf += len; 139 done += len; 140 offset = 0; 141 } 142 143 return done; 144 } 145 146 static uint32_t 147 vbdev_ocf_ctx_data_wr(ctx_data_t *dst, const void *src, uint32_t size) 148 { 149 struct bdev_ocf_data *d = dst; 150 uint32_t size_local; 151 152 size_local = buf_to_iovec(src, size, d->iovs, d->iovcnt, d->seek); 153 d->seek += size_local; 154 155 return size_local; 156 } 157 158 static size_t 159 iovset(struct iovec *iov, size_t iovcnt, int byte, size_t size, size_t offset) 160 { 161 size_t i, len, done = 0; 162 163 for (i = 0; i < iovcnt; i++) { 164 if (offset >= iov[i].iov_len) { 165 offset -= iov[i].iov_len; 166 continue; 167 } 168 169 if (iov[i].iov_base == NULL) { 170 continue; 171 } 172 173 if (done >= size) { 174 break; 175 } 176 177 len = MIN(size - done, iov[i].iov_len - offset); 178 memset(iov[i].iov_base + offset, byte, len); 179 done += len; 180 offset = 0; 181 } 182 183 return done; 184 } 185 186 static uint32_t 187 vbdev_ocf_ctx_data_zero(ctx_data_t *dst, uint32_t size) 188 { 189 struct bdev_ocf_data *d = dst; 190 uint32_t size_local; 191 192 size_local = iovset(d->iovs, d->iovcnt, 0, size, d->seek); 193 d->seek += size_local; 194 195 return size_local; 196 } 197 198 static uint32_t 199 vbdev_ocf_ctx_data_seek(ctx_data_t *dst, ctx_data_seek_t seek, uint32_t offset) 200 { 201 struct bdev_ocf_data *d = dst; 202 uint32_t off = 0; 203 204 switch (seek) { 205 case ctx_data_seek_begin: 206 off = MIN(offset, d->size); 207 d->seek = off; 208 break; 209 case ctx_data_seek_current: 210 off = MIN(offset, d->size - d->seek); 211 d->seek += off; 212 break; 213 } 214 215 return off; 216 } 217 218 static uint64_t 219 vbdev_ocf_ctx_data_cpy(ctx_data_t *dst, ctx_data_t *src, uint64_t to, 220 uint64_t from, uint64_t bytes) 221 { 222 struct bdev_ocf_data *s = src; 223 struct bdev_ocf_data *d = dst; 224 uint32_t it_iov = 0; 225 uint32_t it_off = 0; 226 uint32_t n, sz; 227 228 bytes = MIN(bytes, s->size - from); 229 bytes = MIN(bytes, d->size - to); 230 sz = bytes; 231 232 while (from || bytes) { 233 if (s->iovs[it_iov].iov_len == it_off) { 234 it_iov++; 235 it_off = 0; 236 continue; 237 } 238 239 if (from) { 240 n = MIN(from, s->iovs[it_iov].iov_len); 241 from -= n; 242 } else { 243 n = MIN(bytes, s->iovs[it_iov].iov_len); 244 buf_to_iovec(s->iovs[it_iov].iov_base + it_off, n, d->iovs, d->iovcnt, to); 245 bytes -= n; 246 to += n; 247 } 248 249 it_off += n; 250 } 251 252 return sz; 253 } 254 255 static void 256 vbdev_ocf_ctx_data_secure_erase(ctx_data_t *ctx_data) 257 { 258 struct bdev_ocf_data *data = ctx_data; 259 struct iovec *iovs = data->iovs; 260 int i; 261 262 for (i = 0; i < data->iovcnt; i++) { 263 if (env_memset(iovs[i].iov_base, iovs[i].iov_len, 0)) { 264 assert(false); 265 } 266 } 267 } 268 269 int 270 vbdev_ocf_queue_create(ocf_cache_t cache, ocf_queue_t *queue, const struct ocf_queue_ops *ops) 271 { 272 int rc; 273 struct vbdev_ocf_cache_ctx *ctx = ocf_cache_get_priv(cache); 274 275 pthread_mutex_lock(&ctx->lock); 276 rc = ocf_queue_create(cache, queue, ops); 277 pthread_mutex_unlock(&ctx->lock); 278 return rc; 279 } 280 281 void 282 vbdev_ocf_queue_put(ocf_queue_t queue) 283 { 284 ocf_cache_t cache = ocf_queue_get_cache(queue); 285 struct vbdev_ocf_cache_ctx *ctx = ocf_cache_get_priv(cache); 286 287 pthread_mutex_lock(&ctx->lock); 288 ocf_queue_put(queue); 289 pthread_mutex_unlock(&ctx->lock); 290 } 291 292 void 293 vbdev_ocf_cache_ctx_put(struct vbdev_ocf_cache_ctx *ctx) 294 { 295 if (env_atomic_dec_return(&ctx->refcnt) == 0) { 296 pthread_mutex_destroy(&ctx->lock); 297 free(ctx); 298 } 299 } 300 301 void 302 vbdev_ocf_cache_ctx_get(struct vbdev_ocf_cache_ctx *ctx) 303 { 304 env_atomic_inc(&ctx->refcnt); 305 } 306 307 struct cleaner_priv { 308 struct spdk_poller *poller; 309 ocf_queue_t mngt_queue; 310 uint64_t next_run; 311 }; 312 313 static int 314 cleaner_poll(void *arg) 315 { 316 ocf_cleaner_t cleaner = arg; 317 struct cleaner_priv *priv = ocf_cleaner_get_priv(cleaner); 318 319 if (spdk_get_ticks() >= priv->next_run) { 320 ocf_cleaner_run(cleaner, priv->mngt_queue); 321 return SPDK_POLLER_BUSY; 322 } 323 324 return SPDK_POLLER_IDLE; 325 } 326 327 static void 328 cleaner_cmpl(ocf_cleaner_t c, uint32_t interval) 329 { 330 struct cleaner_priv *priv = ocf_cleaner_get_priv(c); 331 332 priv->next_run = spdk_get_ticks() + ((interval * spdk_get_ticks_hz()) / 1000); 333 } 334 335 static int 336 vbdev_ocf_ctx_cleaner_init(ocf_cleaner_t c) 337 { 338 struct cleaner_priv *priv = calloc(1, sizeof(*priv)); 339 ocf_cache_t cache = ocf_cleaner_get_cache(c); 340 struct vbdev_ocf_cache_ctx *cctx = ocf_cache_get_priv(cache); 341 342 if (priv == NULL) { 343 return -ENOMEM; 344 } 345 346 priv->mngt_queue = cctx->mngt_queue; 347 348 ocf_cleaner_set_cmpl(c, cleaner_cmpl); 349 ocf_cleaner_set_priv(c, priv); 350 351 return 0; 352 } 353 354 static void 355 vbdev_ocf_ctx_cleaner_stop(ocf_cleaner_t c) 356 { 357 struct cleaner_priv *priv = ocf_cleaner_get_priv(c); 358 359 if (priv) { 360 spdk_poller_unregister(&priv->poller); 361 free(priv); 362 } 363 } 364 365 static void 366 vbdev_ocf_ctx_cleaner_kick(ocf_cleaner_t cleaner) 367 { 368 struct cleaner_priv *priv = ocf_cleaner_get_priv(cleaner); 369 370 if (priv->poller) { 371 return; 372 } 373 374 /* We start cleaner poller at the same thread where cache was created 375 * TODO: allow user to specify core at which cleaner should run */ 376 priv->poller = SPDK_POLLER_REGISTER(cleaner_poll, cleaner, 0); 377 } 378 379 /* This function is main way by which OCF communicates with user 380 * We don't want to use SPDK_LOG here because debugging information that is 381 * associated with every print message is not helpful in callback that only prints info 382 * while the real source is somewhere in OCF code */ 383 static int 384 vbdev_ocf_ctx_log_printf(ocf_logger_t logger, ocf_logger_lvl_t lvl, 385 const char *fmt, va_list args) 386 { 387 int spdk_lvl; 388 389 switch (lvl) { 390 case log_emerg: 391 case log_alert: 392 case log_crit: 393 case log_err: 394 spdk_lvl = SPDK_LOG_ERROR; 395 break; 396 397 case log_warn: 398 spdk_lvl = SPDK_LOG_WARN; 399 break; 400 401 case log_notice: 402 spdk_lvl = SPDK_LOG_NOTICE; 403 break; 404 405 case log_info: 406 case log_debug: 407 default: 408 spdk_lvl = SPDK_LOG_INFO; 409 } 410 411 spdk_vlog(spdk_lvl, NULL, -1, NULL, fmt, args); 412 return 0; 413 } 414 415 static const struct ocf_ctx_config vbdev_ocf_ctx_cfg = { 416 .name = "OCF SPDK", 417 418 .ops = { 419 .data = { 420 .alloc = vbdev_ocf_ctx_data_alloc, 421 .free = vbdev_ocf_ctx_data_free, 422 .mlock = vbdev_ocf_ctx_data_mlock, 423 .munlock = vbdev_ocf_ctx_data_munlock, 424 .read = vbdev_ocf_ctx_data_rd, 425 .write = vbdev_ocf_ctx_data_wr, 426 .zero = vbdev_ocf_ctx_data_zero, 427 .seek = vbdev_ocf_ctx_data_seek, 428 .copy = vbdev_ocf_ctx_data_cpy, 429 .secure_erase = vbdev_ocf_ctx_data_secure_erase, 430 }, 431 432 .cleaner = { 433 .init = vbdev_ocf_ctx_cleaner_init, 434 .stop = vbdev_ocf_ctx_cleaner_stop, 435 .kick = vbdev_ocf_ctx_cleaner_kick, 436 }, 437 438 .logger = { 439 .print = vbdev_ocf_ctx_log_printf, 440 .dump_stack = NULL, 441 }, 442 443 }, 444 }; 445 446 int 447 vbdev_ocf_ctx_init(void) 448 { 449 int ret; 450 451 ret = ocf_ctx_create(&vbdev_ocf_ctx, &vbdev_ocf_ctx_cfg); 452 if (ret < 0) { 453 return ret; 454 } 455 456 return 0; 457 } 458 459 void 460 vbdev_ocf_ctx_cleanup(void) 461 { 462 ocf_ctx_put(vbdev_ocf_ctx); 463 vbdev_ocf_ctx = NULL; 464 } 465