1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2019 Intel Corporation. 3 * All rights reserved. 4 */ 5 6 #include <ocf/ocf.h> 7 8 #include "spdk/bdev_module.h" 9 #include "spdk/env.h" 10 #include "spdk/thread.h" 11 #include "spdk/log.h" 12 13 #include "data.h" 14 #include "volume.h" 15 #include "ctx.h" 16 #include "vbdev_ocf.h" 17 18 static int 19 vbdev_ocf_volume_open(ocf_volume_t volume, void *opts) 20 { 21 struct vbdev_ocf_base **priv = ocf_volume_get_priv(volume); 22 struct vbdev_ocf_base *base; 23 24 if (opts) { 25 base = opts; 26 } else { 27 base = vbdev_ocf_get_base_by_name(ocf_volume_get_uuid(volume)->data); 28 if (base == NULL) { 29 return -ENODEV; 30 } 31 } 32 33 *priv = base; 34 35 return 0; 36 } 37 38 static void 39 vbdev_ocf_volume_close(ocf_volume_t volume) 40 { 41 } 42 43 static uint64_t 44 vbdev_ocf_volume_get_length(ocf_volume_t volume) 45 { 46 struct vbdev_ocf_base *base = *((struct vbdev_ocf_base **)ocf_volume_get_priv(volume)); 47 uint64_t len; 48 49 len = base->bdev->blocklen * base->bdev->blockcnt; 50 51 return len; 52 } 53 54 static int 55 vbdev_ocf_volume_io_set_data(struct ocf_io *io, ctx_data_t *data, 56 uint32_t offset) 57 { 58 struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io); 59 60 io_ctx->offset = offset; 61 io_ctx->data = data; 62 63 assert(io_ctx->data != NULL); 64 if (io_ctx->data->iovs && offset >= io_ctx->data->size) { 65 return -ENOBUFS; 66 } 67 68 return 0; 69 } 70 71 static ctx_data_t * 72 vbdev_ocf_volume_io_get_data(struct ocf_io *io) 73 { 74 return ocf_get_io_ctx(io)->data; 75 } 76 77 static void 78 vbdev_ocf_volume_io_get(struct ocf_io *io) 79 { 80 struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io); 81 82 io_ctx->ref++; 83 } 84 85 static void 86 vbdev_ocf_volume_io_put(struct ocf_io *io) 87 { 88 struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io); 89 90 if (--io_ctx->ref) { 91 return; 92 } 93 } 94 95 static int 96 get_starting_vec(struct iovec *iovs, int iovcnt, int *offset) 97 { 98 int i; 99 size_t off; 100 101 off = *offset; 102 103 for (i = 0; i < iovcnt; i++) { 104 if (off < iovs[i].iov_len) { 105 *offset = off; 106 return i; 107 } 108 off -= iovs[i].iov_len; 109 } 110 111 return -1; 112 } 113 114 static void 115 initialize_cpy_vector(struct iovec *cpy_vec, int cpy_vec_len, struct iovec *orig_vec, 116 int orig_vec_len, 117 size_t offset, size_t bytes) 118 { 119 void *curr_base; 120 int len, i; 121 122 i = 0; 123 124 while (bytes > 0) { 125 curr_base = orig_vec[i].iov_base + offset; 126 len = MIN(bytes, orig_vec[i].iov_len - offset); 127 128 cpy_vec[i].iov_base = curr_base; 129 cpy_vec[i].iov_len = len; 130 131 bytes -= len; 132 offset = 0; 133 i++; 134 } 135 } 136 137 static void 138 vbdev_ocf_volume_submit_io_cb(struct spdk_bdev_io *bdev_io, bool success, void *opaque) 139 { 140 struct ocf_io *io; 141 struct ocf_io_ctx *io_ctx; 142 143 assert(opaque); 144 145 io = opaque; 146 io_ctx = ocf_get_io_ctx(io); 147 assert(io_ctx != NULL); 148 149 if (!success) { 150 io_ctx->error = io_ctx->error ? : -OCF_ERR_IO; 151 } 152 153 if (io_ctx->iovs_allocated && bdev_io != NULL) { 154 env_free(bdev_io->u.bdev.iovs); 155 } 156 157 if (io_ctx->error) { 158 SPDK_DEBUGLOG(vbdev_ocf_volume, 159 "base returned error on io submission: %d\n", io_ctx->error); 160 } 161 162 if (io->io_queue == NULL && io_ctx->ch != NULL) { 163 spdk_put_io_channel(io_ctx->ch); 164 } 165 166 vbdev_ocf_volume_io_put(io); 167 if (bdev_io) { 168 spdk_bdev_free_io(bdev_io); 169 } 170 171 if (--io_ctx->rq_cnt == 0) { 172 io->end(io, io_ctx->error); 173 } 174 } 175 176 static int 177 prepare_submit(struct ocf_io *io) 178 { 179 struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io); 180 struct vbdev_ocf_qctx *qctx; 181 struct vbdev_ocf_base *base; 182 ocf_queue_t q = io->io_queue; 183 ocf_cache_t cache; 184 struct vbdev_ocf_cache_ctx *cctx; 185 int rc = 0; 186 187 io_ctx->rq_cnt++; 188 if (io_ctx->rq_cnt != 1) { 189 return 0; 190 } 191 192 vbdev_ocf_volume_io_get(io); 193 base = *((struct vbdev_ocf_base **)ocf_volume_get_priv(ocf_io_get_volume(io))); 194 195 if (io->io_queue == NULL) { 196 /* In case IO is initiated by OCF, queue is unknown 197 * so we have to get io channel ourselves */ 198 io_ctx->ch = spdk_bdev_get_io_channel(base->desc); 199 if (io_ctx->ch == NULL) { 200 return -EPERM; 201 } 202 return 0; 203 } 204 205 cache = ocf_queue_get_cache(q); 206 cctx = ocf_cache_get_priv(cache); 207 if (cctx == NULL) { 208 return -EFAULT; 209 } 210 211 if (q == cctx->mngt_queue) { 212 io_ctx->ch = base->management_channel; 213 return 0; 214 } 215 216 qctx = ocf_queue_get_priv(q); 217 if (qctx == NULL) { 218 return -EFAULT; 219 } 220 221 if (base->is_cache) { 222 io_ctx->ch = qctx->cache_ch; 223 } else { 224 io_ctx->ch = qctx->core_ch; 225 } 226 227 return rc; 228 } 229 230 static void 231 vbdev_ocf_volume_submit_flush(struct ocf_io *io) 232 { 233 struct vbdev_ocf_base *base = 234 *((struct vbdev_ocf_base **) 235 ocf_volume_get_priv(ocf_io_get_volume(io))); 236 struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io); 237 int status; 238 239 status = prepare_submit(io); 240 if (status) { 241 SPDK_ERRLOG("Preparing io failed with status=%d\n", status); 242 vbdev_ocf_volume_submit_io_cb(NULL, false, io); 243 return; 244 } 245 246 status = spdk_bdev_flush( 247 base->desc, io_ctx->ch, 248 io->addr, io->bytes, 249 vbdev_ocf_volume_submit_io_cb, io); 250 if (status) { 251 /* Since callback is not called, we need to do it manually to free io structures */ 252 SPDK_ERRLOG("Submission failed with status=%d\n", status); 253 vbdev_ocf_volume_submit_io_cb(NULL, false, io); 254 } 255 } 256 257 static void 258 vbdev_ocf_volume_submit_io(struct ocf_io *io) 259 { 260 struct vbdev_ocf_base *base = 261 *((struct vbdev_ocf_base **) 262 ocf_volume_get_priv(ocf_io_get_volume(io))); 263 struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io); 264 struct iovec *iovs; 265 int iovcnt, status = 0, i, offset; 266 uint64_t addr, len; 267 268 if (io->flags == OCF_WRITE_FLUSH) { 269 vbdev_ocf_volume_submit_flush(io); 270 return; 271 } 272 273 status = prepare_submit(io); 274 if (status) { 275 SPDK_ERRLOG("Preparing io failed with status=%d\n", status); 276 vbdev_ocf_volume_submit_io_cb(NULL, false, io); 277 return; 278 } 279 280 /* IO fields */ 281 addr = io->addr; 282 len = io->bytes; 283 offset = io_ctx->offset; 284 285 if (len < io_ctx->data->size) { 286 if (io_ctx->data->iovcnt == 1) { 287 if (io->dir == OCF_READ) { 288 status = spdk_bdev_read(base->desc, io_ctx->ch, 289 io_ctx->data->iovs[0].iov_base + offset, addr, len, 290 vbdev_ocf_volume_submit_io_cb, io); 291 } else if (io->dir == OCF_WRITE) { 292 status = spdk_bdev_write(base->desc, io_ctx->ch, 293 io_ctx->data->iovs[0].iov_base + offset, addr, len, 294 vbdev_ocf_volume_submit_io_cb, io); 295 } 296 goto end; 297 } else { 298 i = get_starting_vec(io_ctx->data->iovs, io_ctx->data->iovcnt, &offset); 299 300 if (i < 0) { 301 SPDK_ERRLOG("offset bigger than data size\n"); 302 vbdev_ocf_volume_submit_io_cb(NULL, false, io); 303 return; 304 } 305 306 iovcnt = io_ctx->data->iovcnt - i; 307 308 io_ctx->iovs_allocated = true; 309 iovs = env_malloc(sizeof(*iovs) * iovcnt, ENV_MEM_NOIO); 310 311 if (!iovs) { 312 SPDK_ERRLOG("allocation failed\n"); 313 vbdev_ocf_volume_submit_io_cb(NULL, false, io); 314 return; 315 } 316 317 initialize_cpy_vector(iovs, io_ctx->data->iovcnt, &io_ctx->data->iovs[i], 318 iovcnt, offset, len); 319 } 320 } else { 321 iovs = io_ctx->data->iovs; 322 iovcnt = io_ctx->data->iovcnt; 323 } 324 325 if (io->dir == OCF_READ) { 326 status = spdk_bdev_readv(base->desc, io_ctx->ch, 327 iovs, iovcnt, addr, len, vbdev_ocf_volume_submit_io_cb, io); 328 } else if (io->dir == OCF_WRITE) { 329 status = spdk_bdev_writev(base->desc, io_ctx->ch, 330 iovs, iovcnt, addr, len, vbdev_ocf_volume_submit_io_cb, io); 331 } 332 333 end: 334 if (status) { 335 if (status == -ENOMEM) { 336 io_ctx->error = -OCF_ERR_NO_MEM; 337 } else { 338 SPDK_ERRLOG("submission failed with status=%d\n", status); 339 } 340 341 /* Since callback is not called, we need to do it manually to free io structures */ 342 vbdev_ocf_volume_submit_io_cb(NULL, false, io); 343 } 344 } 345 346 static void 347 vbdev_ocf_volume_submit_discard(struct ocf_io *io) 348 { 349 struct vbdev_ocf_base *base = 350 *((struct vbdev_ocf_base **) 351 ocf_volume_get_priv(ocf_io_get_volume(io))); 352 struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io); 353 int status = 0; 354 355 status = prepare_submit(io); 356 if (status) { 357 SPDK_ERRLOG("Preparing io failed with status=%d\n", status); 358 vbdev_ocf_volume_submit_io_cb(NULL, false, io); 359 return; 360 } 361 362 status = spdk_bdev_unmap( 363 base->desc, io_ctx->ch, 364 io->addr, io->bytes, 365 vbdev_ocf_volume_submit_io_cb, io); 366 if (status) { 367 /* Since callback is not called, we need to do it manually to free io structures */ 368 SPDK_ERRLOG("Submission failed with status=%d\n", status); 369 vbdev_ocf_volume_submit_io_cb(NULL, false, io); 370 } 371 } 372 373 static void 374 vbdev_ocf_volume_submit_metadata(struct ocf_io *io) 375 { 376 /* Implement with persistent metadata support */ 377 } 378 379 static unsigned int 380 vbdev_ocf_volume_get_max_io_size(ocf_volume_t volume) 381 { 382 return 131072; 383 } 384 385 static struct ocf_volume_properties vbdev_volume_props = { 386 .name = "SPDK_block_device", 387 .io_priv_size = sizeof(struct ocf_io_ctx), 388 .volume_priv_size = sizeof(struct vbdev_ocf_base *), 389 .caps = { 390 .atomic_writes = 0 /* to enable need to have ops->submit_metadata */ 391 }, 392 .ops = { 393 .open = vbdev_ocf_volume_open, 394 .close = vbdev_ocf_volume_close, 395 .get_length = vbdev_ocf_volume_get_length, 396 .submit_io = vbdev_ocf_volume_submit_io, 397 .submit_discard = vbdev_ocf_volume_submit_discard, 398 .submit_flush = vbdev_ocf_volume_submit_flush, 399 .get_max_io_size = vbdev_ocf_volume_get_max_io_size, 400 .submit_metadata = vbdev_ocf_volume_submit_metadata, 401 }, 402 .io_ops = { 403 .set_data = vbdev_ocf_volume_io_set_data, 404 .get_data = vbdev_ocf_volume_io_get_data, 405 }, 406 }; 407 408 int 409 vbdev_ocf_volume_init(void) 410 { 411 return ocf_ctx_register_volume_type(vbdev_ocf_ctx, SPDK_OBJECT, &vbdev_volume_props); 412 } 413 414 void 415 vbdev_ocf_volume_cleanup(void) 416 { 417 ocf_ctx_unregister_volume_type(vbdev_ocf_ctx, SPDK_OBJECT); 418 } 419 420 SPDK_LOG_REGISTER_COMPONENT(vbdev_ocf_volume) 421