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.h> 34 #include <execinfo.h> 35 36 #include "spdk/env.h" 37 #include "spdk/log.h" 38 39 #include "ctx.h" 40 #include "ocf_env.h" 41 #include "data.h" 42 43 ocf_ctx_t vbdev_ocf_ctx; 44 45 static ctx_data_t * 46 vbdev_ocf_ctx_data_alloc(uint32_t pages) 47 { 48 struct bdev_ocf_data *data; 49 void *buf; 50 uint32_t sz; 51 52 data = vbdev_ocf_data_alloc(1); 53 54 sz = pages * PAGE_SIZE; 55 buf = spdk_malloc(sz, PAGE_SIZE, NULL, 56 SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA); 57 if (buf == NULL) { 58 return NULL; 59 } 60 61 vbdev_ocf_iovs_add(data, buf, sz); 62 63 data->size = sz; 64 65 return data; 66 } 67 68 static void 69 vbdev_ocf_ctx_data_free(ctx_data_t *ctx_data) 70 { 71 struct bdev_ocf_data *data = ctx_data; 72 int i; 73 74 if (!data) { 75 return; 76 } 77 78 for (i = 0; i < data->iovcnt; i++) { 79 spdk_free(data->iovs[i].iov_base); 80 } 81 82 vbdev_ocf_data_free(data); 83 } 84 85 static int 86 vbdev_ocf_ctx_data_mlock(ctx_data_t *ctx_data) 87 { 88 /* TODO [mlock]: add mlock option */ 89 return 0; 90 } 91 92 static void 93 vbdev_ocf_ctx_data_munlock(ctx_data_t *ctx_data) 94 { 95 /* TODO [mlock]: add mlock option */ 96 } 97 98 static size_t 99 iovec_flatten(struct iovec *iov, size_t iovcnt, void *buf, size_t size, size_t offset) 100 { 101 size_t i, len, done = 0; 102 103 for (i = 0; i < iovcnt; i++) { 104 if (offset >= iov[i].iov_len) { 105 offset -= iov[i].iov_len; 106 continue; 107 } 108 109 if (iov[i].iov_base == NULL) { 110 continue; 111 } 112 113 if (done >= size) { 114 break; 115 } 116 117 len = MIN(size - done, iov[i].iov_len - offset); 118 memcpy(buf, iov[i].iov_base + offset, len); 119 buf += len; 120 done += len; 121 offset = 0; 122 } 123 124 return done; 125 } 126 127 static uint32_t 128 vbdev_ocf_ctx_data_rd(void *dst, ctx_data_t *src, uint32_t size) 129 { 130 struct bdev_ocf_data *s = src; 131 uint32_t size_local; 132 133 size_local = iovec_flatten(s->iovs, s->iovcnt, dst, size, s->seek); 134 s->seek += size_local; 135 136 return size_local; 137 } 138 139 static size_t 140 buf_to_iovec(const void *buf, size_t size, struct iovec *iov, size_t iovcnt, size_t offset) 141 { 142 size_t i, len, done = 0; 143 144 for (i = 0; i < iovcnt; i++) { 145 if (offset >= iov[i].iov_len) { 146 offset -= iov[i].iov_len; 147 continue; 148 } 149 150 if (iov[i].iov_base == NULL) { 151 continue; 152 } 153 154 if (done >= size) { 155 break; 156 } 157 158 len = MIN(size - done, iov[i].iov_len - offset); 159 memcpy(iov[i].iov_base + offset, buf, len); 160 buf += len; 161 done += len; 162 offset = 0; 163 } 164 165 return done; 166 } 167 168 static uint32_t 169 vbdev_ocf_ctx_data_wr(ctx_data_t *dst, const void *src, uint32_t size) 170 { 171 struct bdev_ocf_data *d = dst; 172 uint32_t size_local; 173 174 size_local = buf_to_iovec(src, size, d->iovs, d->iovcnt, d->seek); 175 d->seek += size_local; 176 177 return size_local; 178 } 179 180 static size_t 181 iovset(struct iovec *iov, size_t iovcnt, int byte, size_t size, size_t offset) 182 { 183 size_t i, len, done = 0; 184 185 for (i = 0; i < iovcnt; i++) { 186 if (offset >= iov[i].iov_len) { 187 offset -= iov[i].iov_len; 188 continue; 189 } 190 191 if (iov[i].iov_base == NULL) { 192 continue; 193 } 194 195 if (done >= size) { 196 break; 197 } 198 199 len = MIN(size - done, iov[i].iov_len - offset); 200 memset(iov[i].iov_base + offset, byte, len); 201 done += len; 202 offset = 0; 203 } 204 205 return done; 206 } 207 208 static uint32_t 209 vbdev_ocf_ctx_data_zero(ctx_data_t *dst, uint32_t size) 210 { 211 struct bdev_ocf_data *d = dst; 212 uint32_t size_local; 213 214 size_local = iovset(d->iovs, d->iovcnt, 0, size, d->seek); 215 d->seek += size_local; 216 217 return size_local; 218 } 219 220 static uint32_t 221 vbdev_ocf_ctx_data_seek(ctx_data_t *dst, ctx_data_seek_t seek, uint32_t offset) 222 { 223 struct bdev_ocf_data *d = dst; 224 uint32_t off = 0; 225 226 switch (seek) { 227 case ctx_data_seek_begin: 228 off = MIN(offset, d->size); 229 d->seek = off; 230 break; 231 case ctx_data_seek_current: 232 off = MIN(offset, d->size - d->seek); 233 d->seek += off; 234 break; 235 } 236 237 return off; 238 } 239 240 static uint64_t 241 vbdev_ocf_ctx_data_cpy(ctx_data_t *dst, ctx_data_t *src, uint64_t to, 242 uint64_t from, uint64_t bytes) 243 { 244 struct bdev_ocf_data *s = src; 245 struct bdev_ocf_data *d = dst; 246 uint32_t it_iov = 0; 247 uint32_t it_off = 0; 248 uint32_t n, sz; 249 250 bytes = MIN(bytes, s->size - from); 251 bytes = MIN(bytes, d->size - to); 252 sz = bytes; 253 254 while (from || bytes) { 255 if (s->iovs[it_iov].iov_len == it_off) { 256 it_iov++; 257 it_off = 0; 258 continue; 259 } 260 261 if (from) { 262 n = MIN(from, s->iovs[it_iov].iov_len); 263 from -= n; 264 } else { 265 n = MIN(bytes, s->iovs[it_iov].iov_len); 266 buf_to_iovec(s->iovs[it_iov].iov_base + it_off, n, d->iovs, d->iovcnt, to); 267 bytes -= n; 268 to += n; 269 } 270 271 it_off += n; 272 } 273 274 return sz; 275 } 276 277 static void 278 vbdev_ocf_ctx_data_secure_erase(ctx_data_t *ctx_data) 279 { 280 struct bdev_ocf_data *data = ctx_data; 281 struct iovec *iovs = data->iovs; 282 int i; 283 284 for (i = 0; i < data->iovcnt; i++) { 285 if (env_memset(iovs[i].iov_base, iovs[i].iov_len, 0)) { 286 assert(false); 287 } 288 } 289 } 290 291 int vbdev_ocf_queue_create(ocf_cache_t cache, ocf_queue_t *queue, const struct ocf_queue_ops *ops) 292 { 293 int rc; 294 struct vbdev_ocf_cache_ctx *ctx = ocf_cache_get_priv(cache); 295 296 pthread_mutex_lock(&ctx->lock); 297 rc = ocf_queue_create(cache, queue, ops); 298 pthread_mutex_unlock(&ctx->lock); 299 return rc; 300 } 301 302 void vbdev_ocf_queue_put(ocf_queue_t queue) 303 { 304 ocf_cache_t cache = ocf_queue_get_cache(queue); 305 struct vbdev_ocf_cache_ctx *ctx = ocf_cache_get_priv(cache); 306 307 pthread_mutex_lock(&ctx->lock); 308 ocf_queue_put(queue); 309 pthread_mutex_unlock(&ctx->lock); 310 } 311 312 void vbdev_ocf_cache_ctx_put(struct vbdev_ocf_cache_ctx *ctx) 313 { 314 if (env_atomic_dec_return(&ctx->refcnt) == 0) { 315 pthread_mutex_destroy(&ctx->lock); 316 free(ctx); 317 } 318 } 319 320 void vbdev_ocf_cache_ctx_get(struct vbdev_ocf_cache_ctx *ctx) 321 { 322 env_atomic_inc(&ctx->refcnt); 323 } 324 325 struct cleaner_priv { 326 struct spdk_poller *poller; 327 ocf_queue_t queue; 328 uint64_t next_run; 329 }; 330 331 static int 332 cleaner_poll(void *arg) 333 { 334 ocf_cleaner_t cleaner = arg; 335 struct cleaner_priv *priv = ocf_cleaner_get_priv(cleaner); 336 uint32_t iono = ocf_queue_pending_io(priv->queue); 337 int i, max = spdk_min(32, iono); 338 339 for (i = 0; i < max; i++) { 340 ocf_queue_run_single(priv->queue); 341 } 342 343 if (spdk_get_ticks() >= priv->next_run) { 344 ocf_cleaner_run(cleaner, priv->queue); 345 return SPDK_POLLER_BUSY; 346 } 347 348 if (iono > 0) { 349 return SPDK_POLLER_BUSY; 350 } else { 351 return SPDK_POLLER_IDLE; 352 } 353 } 354 355 static void 356 cleaner_cmpl(ocf_cleaner_t c, uint32_t interval) 357 { 358 struct cleaner_priv *priv = ocf_cleaner_get_priv(c); 359 360 priv->next_run = spdk_get_ticks() + ((interval * spdk_get_ticks_hz()) / 1000); 361 } 362 363 static void 364 cleaner_queue_kick(ocf_queue_t q) 365 { 366 } 367 368 static void 369 cleaner_queue_stop(ocf_queue_t q) 370 { 371 struct cleaner_priv *cpriv = ocf_queue_get_priv(q); 372 373 if (cpriv) { 374 spdk_poller_unregister(&cpriv->poller); 375 free(cpriv); 376 } 377 } 378 379 const struct ocf_queue_ops cleaner_queue_ops = { 380 .kick_sync = cleaner_queue_kick, 381 .kick = cleaner_queue_kick, 382 .stop = cleaner_queue_stop, 383 }; 384 385 static int 386 vbdev_ocf_ctx_cleaner_init(ocf_cleaner_t c) 387 { 388 int rc; 389 struct cleaner_priv *priv = calloc(1, sizeof(*priv)); 390 ocf_cache_t cache = ocf_cleaner_get_cache(c); 391 struct vbdev_ocf_cache_ctx *cctx = ocf_cache_get_priv(cache); 392 393 if (priv == NULL) { 394 return -ENOMEM; 395 } 396 397 rc = vbdev_ocf_queue_create(cache, &priv->queue, &cleaner_queue_ops); 398 if (rc) { 399 free(priv); 400 return rc; 401 } 402 403 ocf_queue_set_priv(priv->queue, priv); 404 405 cctx->cleaner_queue = priv->queue; 406 407 ocf_cleaner_set_cmpl(c, cleaner_cmpl); 408 ocf_cleaner_set_priv(c, priv); 409 410 return 0; 411 } 412 413 static void 414 vbdev_ocf_ctx_cleaner_stop(ocf_cleaner_t c) 415 { 416 struct cleaner_priv *priv = ocf_cleaner_get_priv(c); 417 418 vbdev_ocf_queue_put(priv->queue); 419 } 420 421 static void 422 vbdev_ocf_ctx_cleaner_kick(ocf_cleaner_t cleaner) 423 { 424 struct cleaner_priv *priv = ocf_cleaner_get_priv(cleaner); 425 426 if (priv->poller) { 427 return; 428 } 429 430 /* We start cleaner poller at the same thread where cache was created 431 * TODO: allow user to specify core at which cleaner should run */ 432 priv->poller = SPDK_POLLER_REGISTER(cleaner_poll, cleaner, 0); 433 } 434 435 static void 436 vbdev_ocf_md_kick(void *ctx) 437 { 438 ocf_metadata_updater_t mu = ctx; 439 ocf_cache_t cache = ocf_metadata_updater_get_cache(mu); 440 441 ocf_metadata_updater_run(mu); 442 443 /* Decrease cache ref count after metadata has been updated */ 444 ocf_mngt_cache_put(cache); 445 } 446 447 static int 448 vbdev_ocf_volume_updater_init(ocf_metadata_updater_t mu) 449 { 450 struct spdk_thread *md_thread = spdk_get_thread(); 451 452 ocf_metadata_updater_set_priv(mu, md_thread); 453 454 return 0; 455 } 456 457 static void 458 vbdev_ocf_volume_updater_stop(ocf_metadata_updater_t mu) 459 { 460 461 } 462 463 static void 464 vbdev_ocf_volume_updater_kick(ocf_metadata_updater_t mu) 465 { 466 struct spdk_thread *md_thread = ocf_metadata_updater_get_priv(mu); 467 ocf_cache_t cache = ocf_metadata_updater_get_cache(mu); 468 469 /* Increase cache ref count prior sending a message to a thread 470 * for metadata update */ 471 ocf_mngt_cache_get(cache); 472 473 /* We need to send message to updater thread because 474 * kick can happen from any thread */ 475 spdk_thread_send_msg(md_thread, vbdev_ocf_md_kick, mu); 476 } 477 478 /* This function is main way by which OCF communicates with user 479 * We don't want to use SPDK_LOG here because debugging information that is 480 * associated with every print message is not helpful in callback that only prints info 481 * while the real source is somewhere in OCF code */ 482 static int 483 vbdev_ocf_ctx_log_printf(ocf_logger_t logger, ocf_logger_lvl_t lvl, 484 const char *fmt, va_list args) 485 { 486 int spdk_lvl; 487 488 switch (lvl) { 489 case log_emerg: 490 case log_alert: 491 case log_crit: 492 case log_err: 493 spdk_lvl = SPDK_LOG_ERROR; 494 break; 495 496 case log_warn: 497 spdk_lvl = SPDK_LOG_WARN; 498 break; 499 500 case log_notice: 501 spdk_lvl = SPDK_LOG_NOTICE; 502 break; 503 504 case log_info: 505 case log_debug: 506 default: 507 spdk_lvl = SPDK_LOG_INFO; 508 } 509 510 spdk_vlog(spdk_lvl, NULL, -1, NULL, fmt, args); 511 return 0; 512 } 513 514 static const struct ocf_ctx_config vbdev_ocf_ctx_cfg = { 515 .name = "OCF SPDK", 516 517 .ops = { 518 .data = { 519 .alloc = vbdev_ocf_ctx_data_alloc, 520 .free = vbdev_ocf_ctx_data_free, 521 .mlock = vbdev_ocf_ctx_data_mlock, 522 .munlock = vbdev_ocf_ctx_data_munlock, 523 .read = vbdev_ocf_ctx_data_rd, 524 .write = vbdev_ocf_ctx_data_wr, 525 .zero = vbdev_ocf_ctx_data_zero, 526 .seek = vbdev_ocf_ctx_data_seek, 527 .copy = vbdev_ocf_ctx_data_cpy, 528 .secure_erase = vbdev_ocf_ctx_data_secure_erase, 529 }, 530 531 .metadata_updater = { 532 .init = vbdev_ocf_volume_updater_init, 533 .stop = vbdev_ocf_volume_updater_stop, 534 .kick = vbdev_ocf_volume_updater_kick, 535 }, 536 537 .cleaner = { 538 .init = vbdev_ocf_ctx_cleaner_init, 539 .stop = vbdev_ocf_ctx_cleaner_stop, 540 .kick = vbdev_ocf_ctx_cleaner_kick, 541 }, 542 543 .logger = { 544 .print = vbdev_ocf_ctx_log_printf, 545 .dump_stack = NULL, 546 }, 547 548 }, 549 }; 550 551 int 552 vbdev_ocf_ctx_init(void) 553 { 554 int ret; 555 556 ret = ocf_ctx_create(&vbdev_ocf_ctx, &vbdev_ocf_ctx_cfg); 557 if (ret < 0) { 558 return ret; 559 } 560 561 return 0; 562 } 563 564 void 565 vbdev_ocf_ctx_cleanup(void) 566 { 567 ocf_ctx_put(vbdev_ocf_ctx); 568 vbdev_ocf_ctx = NULL; 569 } 570