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 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(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 if (cctx == NULL) { 235 return -EFAULT; 236 } 237 238 if (q == cctx->cleaner_queue || q == cctx->mngt_queue) { 239 io_ctx->ch = base->management_channel; 240 return 0; 241 } 242 243 qctx = ocf_queue_get_priv(q); 244 if (qctx == NULL) { 245 return -EFAULT; 246 } 247 248 if (base->is_cache) { 249 io_ctx->ch = qctx->cache_ch; 250 } else { 251 io_ctx->ch = qctx->core_ch; 252 } 253 254 return rc; 255 } 256 257 static void 258 vbdev_ocf_volume_submit_flush(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 int status; 265 266 status = prepare_submit(io); 267 if (status) { 268 SPDK_ERRLOG("Preparing io failed with status=%d\n", status); 269 vbdev_ocf_volume_submit_io_cb(NULL, false, io); 270 return; 271 } 272 273 status = spdk_bdev_flush( 274 base->desc, io_ctx->ch, 275 io->addr, io->bytes, 276 vbdev_ocf_volume_submit_io_cb, io); 277 if (status) { 278 /* Since callback is not called, we need to do it manually to free io structures */ 279 SPDK_ERRLOG("Submission failed with status=%d\n", status); 280 vbdev_ocf_volume_submit_io_cb(NULL, false, io); 281 } 282 } 283 284 static void 285 vbdev_ocf_volume_submit_io(struct ocf_io *io) 286 { 287 struct vbdev_ocf_base *base = 288 *((struct vbdev_ocf_base **) 289 ocf_volume_get_priv(ocf_io_get_volume(io))); 290 struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io); 291 struct iovec *iovs; 292 int iovcnt, status = 0, i, offset; 293 uint64_t addr, len; 294 295 if (io->flags == OCF_WRITE_FLUSH) { 296 vbdev_ocf_volume_submit_flush(io); 297 return; 298 } 299 300 status = prepare_submit(io); 301 if (status) { 302 SPDK_ERRLOG("Preparing io failed with status=%d\n", status); 303 vbdev_ocf_volume_submit_io_cb(NULL, false, io); 304 return; 305 } 306 307 /* IO fields */ 308 addr = io->addr; 309 len = io->bytes; 310 offset = io_ctx->offset; 311 312 if (len < io_ctx->data->size) { 313 if (io_ctx->data->iovcnt == 1) { 314 if (io->dir == OCF_READ) { 315 status = spdk_bdev_read(base->desc, io_ctx->ch, 316 io_ctx->data->iovs[0].iov_base + offset, addr, len, 317 vbdev_ocf_volume_submit_io_cb, io); 318 } else if (io->dir == OCF_WRITE) { 319 status = spdk_bdev_write(base->desc, io_ctx->ch, 320 io_ctx->data->iovs[0].iov_base + offset, addr, len, 321 vbdev_ocf_volume_submit_io_cb, io); 322 } 323 goto end; 324 } else { 325 i = get_starting_vec(io_ctx->data->iovs, io_ctx->data->iovcnt, &offset); 326 327 if (i < 0) { 328 SPDK_ERRLOG("offset bigger than data size\n"); 329 vbdev_ocf_volume_submit_io_cb(NULL, false, io); 330 return; 331 } 332 333 iovcnt = io_ctx->data->iovcnt - i; 334 335 io_ctx->iovs_allocated = true; 336 iovs = env_malloc(sizeof(*iovs) * iovcnt, ENV_MEM_NOIO); 337 338 if (!iovs) { 339 SPDK_ERRLOG("allocation failed\n"); 340 vbdev_ocf_volume_submit_io_cb(NULL, false, io); 341 return; 342 } 343 344 initialize_cpy_vector(iovs, io_ctx->data->iovcnt, &io_ctx->data->iovs[i], 345 iovcnt, offset, len); 346 } 347 } else { 348 iovs = io_ctx->data->iovs; 349 iovcnt = io_ctx->data->iovcnt; 350 } 351 352 if (io->dir == OCF_READ) { 353 status = spdk_bdev_readv(base->desc, io_ctx->ch, 354 iovs, iovcnt, addr, len, vbdev_ocf_volume_submit_io_cb, io); 355 } else if (io->dir == OCF_WRITE) { 356 status = spdk_bdev_writev(base->desc, io_ctx->ch, 357 iovs, iovcnt, addr, len, vbdev_ocf_volume_submit_io_cb, io); 358 } 359 360 end: 361 if (status) { 362 /* TODO [ENOMEM]: implement ENOMEM handling when submitting IO to base device */ 363 364 /* Since callback is not called, we need to do it manually to free io structures */ 365 SPDK_ERRLOG("submission failed with status=%d\n", status); 366 vbdev_ocf_volume_submit_io_cb(NULL, false, io); 367 } 368 } 369 370 static void 371 vbdev_ocf_volume_submit_discard(struct ocf_io *io) 372 { 373 struct vbdev_ocf_base *base = 374 *((struct vbdev_ocf_base **) 375 ocf_volume_get_priv(ocf_io_get_volume(io))); 376 struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io); 377 int status = 0; 378 379 status = prepare_submit(io); 380 if (status) { 381 SPDK_ERRLOG("Preparing io failed with status=%d\n", status); 382 vbdev_ocf_volume_submit_io_cb(NULL, false, io); 383 return; 384 } 385 386 status = spdk_bdev_unmap( 387 base->desc, io_ctx->ch, 388 io->addr, io->bytes, 389 vbdev_ocf_volume_submit_io_cb, io); 390 if (status) { 391 /* Since callback is not called, we need to do it manually to free io structures */ 392 SPDK_ERRLOG("Submission failed with status=%d\n", status); 393 vbdev_ocf_volume_submit_io_cb(NULL, false, io); 394 } 395 } 396 397 static void 398 vbdev_ocf_volume_submit_metadata(struct ocf_io *io) 399 { 400 /* Implement with persistent metadata support */ 401 } 402 403 static unsigned int 404 vbdev_ocf_volume_get_max_io_size(ocf_volume_t volume) 405 { 406 return 131072; 407 } 408 409 static struct ocf_volume_properties vbdev_volume_props = { 410 .name = "SPDK block device", 411 .io_priv_size = sizeof(struct ocf_io_ctx), 412 .volume_priv_size = sizeof(struct vbdev_ocf_base *), 413 .caps = { 414 .atomic_writes = 0 /* to enable need to have ops->submit_metadata */ 415 }, 416 .ops = { 417 .open = vbdev_ocf_volume_open, 418 .close = vbdev_ocf_volume_close, 419 .get_length = vbdev_ocf_volume_get_length, 420 .submit_io = vbdev_ocf_volume_submit_io, 421 .submit_discard = vbdev_ocf_volume_submit_discard, 422 .submit_flush = vbdev_ocf_volume_submit_flush, 423 .get_max_io_size = vbdev_ocf_volume_get_max_io_size, 424 .submit_metadata = vbdev_ocf_volume_submit_metadata, 425 }, 426 .io_ops = { 427 .set_data = vbdev_ocf_volume_io_set_data, 428 .get_data = vbdev_ocf_volume_io_get_data, 429 }, 430 }; 431 432 int 433 vbdev_ocf_volume_init(void) 434 { 435 return ocf_ctx_register_volume_type(vbdev_ocf_ctx, SPDK_OBJECT, &vbdev_volume_props); 436 } 437 438 void 439 vbdev_ocf_volume_cleanup(void) 440 { 441 ocf_ctx_unregister_volume_type(vbdev_ocf_ctx, SPDK_OBJECT); 442 } 443 444 SPDK_LOG_REGISTER_COMPONENT(vbdev_ocf_volume) 445