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