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