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 273 return ocf_queue_create(cache, queue, ops); 274 } 275 276 int 277 vbdev_ocf_queue_create_mngt(ocf_cache_t cache, ocf_queue_t *queue, const struct ocf_queue_ops *ops) 278 { 279 return ocf_queue_create_mngt(cache, queue, ops); 280 } 281 282 void 283 vbdev_ocf_queue_put(ocf_queue_t queue) 284 { 285 ocf_queue_put(queue); 286 } 287 288 void 289 vbdev_ocf_cache_ctx_put(struct vbdev_ocf_cache_ctx *ctx) 290 { 291 if (env_atomic_dec_return(&ctx->refcnt) == 0) { 292 free(ctx); 293 } 294 } 295 296 void 297 vbdev_ocf_cache_ctx_get(struct vbdev_ocf_cache_ctx *ctx) 298 { 299 env_atomic_inc(&ctx->refcnt); 300 } 301 302 struct cleaner_priv { 303 struct spdk_poller *poller; 304 ocf_queue_t mngt_queue; 305 uint64_t next_run; 306 }; 307 308 static int 309 cleaner_poll(void *arg) 310 { 311 ocf_cleaner_t cleaner = arg; 312 struct cleaner_priv *priv = ocf_cleaner_get_priv(cleaner); 313 314 if (spdk_get_ticks() >= priv->next_run) { 315 ocf_cleaner_run(cleaner, priv->mngt_queue); 316 return SPDK_POLLER_BUSY; 317 } 318 319 return SPDK_POLLER_IDLE; 320 } 321 322 static void 323 cleaner_cmpl(ocf_cleaner_t c, uint32_t interval) 324 { 325 struct cleaner_priv *priv = ocf_cleaner_get_priv(c); 326 327 priv->next_run = spdk_get_ticks() + ((interval * spdk_get_ticks_hz()) / 1000); 328 } 329 330 static int 331 vbdev_ocf_ctx_cleaner_init(ocf_cleaner_t c) 332 { 333 struct cleaner_priv *priv = calloc(1, sizeof(*priv)); 334 ocf_cache_t cache = ocf_cleaner_get_cache(c); 335 struct vbdev_ocf_cache_ctx *cctx = ocf_cache_get_priv(cache); 336 337 if (priv == NULL) { 338 return -ENOMEM; 339 } 340 341 priv->mngt_queue = cctx->mngt_queue; 342 343 ocf_cleaner_set_cmpl(c, cleaner_cmpl); 344 ocf_cleaner_set_priv(c, priv); 345 346 return 0; 347 } 348 349 static void 350 vbdev_ocf_ctx_cleaner_stop(ocf_cleaner_t c) 351 { 352 struct cleaner_priv *priv = ocf_cleaner_get_priv(c); 353 354 if (priv) { 355 spdk_poller_unregister(&priv->poller); 356 free(priv); 357 } 358 } 359 360 static void 361 vbdev_ocf_ctx_cleaner_kick(ocf_cleaner_t cleaner) 362 { 363 struct cleaner_priv *priv = ocf_cleaner_get_priv(cleaner); 364 365 if (priv->poller) { 366 return; 367 } 368 369 /* We start cleaner poller at the same thread where cache was created 370 * TODO: allow user to specify core at which cleaner should run */ 371 priv->poller = SPDK_POLLER_REGISTER(cleaner_poll, cleaner, 0); 372 } 373 374 /* This function is main way by which OCF communicates with user 375 * We don't want to use SPDK_LOG here because debugging information that is 376 * associated with every print message is not helpful in callback that only prints info 377 * while the real source is somewhere in OCF code */ 378 static int 379 vbdev_ocf_ctx_log_printf(ocf_logger_t logger, ocf_logger_lvl_t lvl, 380 const char *fmt, va_list args) 381 { 382 int spdk_lvl; 383 384 switch (lvl) { 385 case log_emerg: 386 case log_alert: 387 case log_crit: 388 case log_err: 389 spdk_lvl = SPDK_LOG_ERROR; 390 break; 391 392 case log_warn: 393 spdk_lvl = SPDK_LOG_WARN; 394 break; 395 396 case log_notice: 397 spdk_lvl = SPDK_LOG_NOTICE; 398 break; 399 400 case log_info: 401 case log_debug: 402 default: 403 spdk_lvl = SPDK_LOG_INFO; 404 } 405 406 spdk_vlog(spdk_lvl, NULL, -1, NULL, fmt, args); 407 return 0; 408 } 409 410 static const struct ocf_ctx_config vbdev_ocf_ctx_cfg = { 411 .name = "OCF SPDK", 412 413 .ops = { 414 .data = { 415 .alloc = vbdev_ocf_ctx_data_alloc, 416 .free = vbdev_ocf_ctx_data_free, 417 .mlock = vbdev_ocf_ctx_data_mlock, 418 .munlock = vbdev_ocf_ctx_data_munlock, 419 .read = vbdev_ocf_ctx_data_rd, 420 .write = vbdev_ocf_ctx_data_wr, 421 .zero = vbdev_ocf_ctx_data_zero, 422 .seek = vbdev_ocf_ctx_data_seek, 423 .copy = vbdev_ocf_ctx_data_cpy, 424 .secure_erase = vbdev_ocf_ctx_data_secure_erase, 425 }, 426 427 .cleaner = { 428 .init = vbdev_ocf_ctx_cleaner_init, 429 .stop = vbdev_ocf_ctx_cleaner_stop, 430 .kick = vbdev_ocf_ctx_cleaner_kick, 431 }, 432 433 .logger = { 434 .print = vbdev_ocf_ctx_log_printf, 435 .dump_stack = NULL, 436 }, 437 438 }, 439 }; 440 441 int 442 vbdev_ocf_ctx_init(void) 443 { 444 int ret; 445 446 ret = ocf_ctx_create(&vbdev_ocf_ctx, &vbdev_ocf_ctx_cfg); 447 if (ret < 0) { 448 return ret; 449 } 450 451 return 0; 452 } 453 454 void 455 vbdev_ocf_ctx_cleanup(void) 456 { 457 ocf_ctx_put(vbdev_ocf_ctx); 458 vbdev_ocf_ctx = NULL; 459 } 460