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