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