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 get_starting_vec(struct iovec *iovs, int iovcnt, uint64_t *offset) 56 { 57 int i; 58 size_t off; 59 60 off = *offset; 61 62 for (i = 0; i < iovcnt; i++) { 63 if (off < iovs[i].iov_len) { 64 *offset = off; 65 return i; 66 } 67 off -= iovs[i].iov_len; 68 } 69 70 return -1; 71 } 72 73 static void 74 initialize_cpy_vector(struct iovec *cpy_vec, int cpy_vec_len, struct iovec *orig_vec, 75 int orig_vec_len, 76 size_t offset, size_t bytes) 77 { 78 void *curr_base; 79 int len, i; 80 81 i = 0; 82 83 while (bytes > 0) { 84 curr_base = orig_vec[i].iov_base + offset; 85 len = MIN(bytes, orig_vec[i].iov_len - offset); 86 87 cpy_vec[i].iov_base = curr_base; 88 cpy_vec[i].iov_len = len; 89 90 bytes -= len; 91 offset = 0; 92 i++; 93 } 94 } 95 96 static unsigned int 97 vbdev_ocf_volume_get_max_io_size(ocf_volume_t volume) 98 { 99 return 131072; 100 } 101 102 static void 103 vbdev_forward_io_cb(struct spdk_bdev_io *bdev_io, bool success, void *opaque) 104 { 105 ocf_forward_token_t token = (ocf_forward_token_t) opaque; 106 107 assert(token); 108 109 spdk_bdev_free_io(bdev_io); 110 111 ocf_forward_end(token, success ? 0 : -OCF_ERR_IO); 112 } 113 114 static void 115 vbdev_forward_io_free_iovs_cb(struct spdk_bdev_io *bdev_io, bool success, void *opaque) 116 { 117 env_free(bdev_io->u.bdev.iovs); 118 vbdev_forward_io_cb(bdev_io, success, opaque); 119 } 120 121 static struct spdk_io_channel * 122 vbdev_forward_get_channel(ocf_volume_t volume, ocf_forward_token_t token) 123 { 124 struct vbdev_ocf_base *base = 125 *((struct vbdev_ocf_base **) 126 ocf_volume_get_priv(volume)); 127 ocf_queue_t queue = ocf_forward_get_io_queue(token); 128 struct vbdev_ocf_qctx *qctx; 129 130 if (unlikely(ocf_queue_is_mngt(queue))) { 131 return base->management_channel; 132 } 133 134 qctx = ocf_queue_get_priv(queue); 135 if (unlikely(qctx == NULL)) { 136 return NULL; 137 } 138 139 return (base->is_cache) ? qctx->cache_ch : qctx->core_ch; 140 } 141 142 static void 143 vbdev_forward_io(ocf_volume_t volume, ocf_forward_token_t token, 144 int dir, uint64_t addr, uint64_t bytes, 145 uint64_t offset) 146 { 147 struct vbdev_ocf_base *base = 148 *((struct vbdev_ocf_base **) 149 ocf_volume_get_priv(volume)); 150 struct bdev_ocf_data *data = ocf_forward_get_data(token); 151 struct spdk_io_channel *ch; 152 spdk_bdev_io_completion_cb cb = vbdev_forward_io_cb; 153 bool iovs_allocated = false; 154 int iovcnt, skip, status = -1; 155 struct iovec *iovs; 156 157 ch = vbdev_forward_get_channel(volume, token); 158 if (unlikely(ch == NULL)) { 159 ocf_forward_end(token, -EFAULT); 160 return; 161 } 162 163 if (bytes == data->size) { 164 iovs = data->iovs; 165 iovcnt = data->iovcnt; 166 } else { 167 skip = get_starting_vec(data->iovs, data->iovcnt, &offset); 168 if (skip < 0) { 169 SPDK_ERRLOG("Offset bigger than data size\n"); 170 ocf_forward_end(token, -OCF_ERR_IO); 171 return; 172 } 173 174 iovcnt = data->iovcnt - skip; 175 176 iovs_allocated = true; 177 cb = vbdev_forward_io_free_iovs_cb; 178 iovs = env_malloc(sizeof(*iovs) * iovcnt, ENV_MEM_NOIO); 179 180 if (!iovs) { 181 SPDK_ERRLOG("Allocation failed\n"); 182 ocf_forward_end(token, -OCF_ERR_NO_MEM); 183 return; 184 } 185 186 initialize_cpy_vector(iovs, data->iovcnt, &data->iovs[skip], 187 iovcnt, offset, bytes); 188 } 189 190 if (dir == OCF_READ) { 191 status = spdk_bdev_readv(base->desc, ch, iovs, iovcnt, 192 addr, bytes, cb, (void *) token); 193 } else if (dir == OCF_WRITE) { 194 status = spdk_bdev_writev(base->desc, ch, iovs, iovcnt, 195 addr, bytes, cb, (void *) token); 196 } 197 198 if (unlikely(status)) { 199 SPDK_ERRLOG("Submission failed with status=%d\n", status); 200 /* Since callback is not called, we need to do it manually to free iovs */ 201 if (iovs_allocated) { 202 env_free(iovs); 203 } 204 ocf_forward_end(token, (status == -ENOMEM) ? -OCF_ERR_NO_MEM : -OCF_ERR_IO); 205 } 206 } 207 208 static void 209 vbdev_forward_flush(ocf_volume_t volume, ocf_forward_token_t token) 210 { 211 struct vbdev_ocf_base *base = 212 *((struct vbdev_ocf_base **) 213 ocf_volume_get_priv(volume)); 214 struct spdk_io_channel *ch; 215 uint64_t bytes = base->bdev->blockcnt * base->bdev->blocklen; 216 int status; 217 218 ch = vbdev_forward_get_channel(volume, token); 219 if (unlikely(ch == NULL)) { 220 ocf_forward_end(token, -EFAULT); 221 return; 222 } 223 224 status = spdk_bdev_flush( 225 base->desc, ch, 0, bytes, 226 vbdev_forward_io_cb, (void *)token); 227 if (unlikely(status)) { 228 SPDK_ERRLOG("Submission failed with status=%d\n", status); 229 ocf_forward_end(token, (status == -ENOMEM) ? -OCF_ERR_NO_MEM : -OCF_ERR_IO); 230 } 231 } 232 233 static void 234 vbdev_forward_discard(ocf_volume_t volume, ocf_forward_token_t token, 235 uint64_t addr, uint64_t bytes) 236 { 237 struct vbdev_ocf_base *base = 238 *((struct vbdev_ocf_base **) 239 ocf_volume_get_priv(volume)); 240 struct spdk_io_channel *ch; 241 int status = 0; 242 243 ch = vbdev_forward_get_channel(volume, token); 244 if (unlikely(ch == NULL)) { 245 ocf_forward_end(token, -EFAULT); 246 return; 247 } 248 249 status = spdk_bdev_unmap( 250 base->desc, ch, addr, bytes, 251 vbdev_forward_io_cb, (void *)token); 252 if (unlikely(status)) { 253 SPDK_ERRLOG("Submission failed with status=%d\n", status); 254 ocf_forward_end(token, (status == -ENOMEM) ? -OCF_ERR_NO_MEM : -OCF_ERR_IO); 255 } 256 } 257 258 struct vbdev_forward_io_simple_ctx { 259 ocf_forward_token_t token; 260 struct spdk_io_channel *ch; 261 }; 262 263 static void 264 vbdev_forward_io_simple_cb(struct spdk_bdev_io *bdev_io, bool success, void *opaque) 265 { 266 struct vbdev_forward_io_simple_ctx *ctx = opaque; 267 ocf_forward_token_t token = ctx->token; 268 269 assert(token); 270 271 spdk_bdev_free_io(bdev_io); 272 spdk_put_io_channel(ctx->ch); 273 env_free(ctx); 274 275 ocf_forward_end(token, success ? 0 : -OCF_ERR_IO); 276 } 277 278 static void 279 vbdev_forward_io_simple(ocf_volume_t volume, ocf_forward_token_t token, 280 int dir, uint64_t addr, uint64_t bytes) 281 { 282 struct vbdev_ocf_base *base = 283 *((struct vbdev_ocf_base **) 284 ocf_volume_get_priv(volume)); 285 struct bdev_ocf_data *data = ocf_forward_get_data(token); 286 struct vbdev_forward_io_simple_ctx *ctx; 287 int status = -1; 288 289 ctx = env_malloc(sizeof(*ctx), ENV_MEM_NOIO); 290 if (unlikely(!ctx)) { 291 ocf_forward_end(token, -OCF_ERR_NO_MEM); 292 return; 293 } 294 295 /* Forward IO simple is used in context where queue is not available 296 * so we have to get io channel ourselves */ 297 ctx->ch = spdk_bdev_get_io_channel(base->desc); 298 if (unlikely(ctx->ch == NULL)) { 299 env_free(ctx); 300 ocf_forward_end(token, -EFAULT); 301 return; 302 } 303 304 ctx->token = token; 305 306 if (dir == OCF_READ) { 307 status = spdk_bdev_readv(base->desc, ctx->ch, data->iovs, 308 data->iovcnt, addr, bytes, 309 vbdev_forward_io_simple_cb, ctx); 310 } else if (dir == OCF_WRITE) { 311 status = spdk_bdev_writev(base->desc, ctx->ch, data->iovs, 312 data->iovcnt, addr, bytes, 313 vbdev_forward_io_simple_cb, ctx); 314 } 315 316 if (unlikely(status)) { 317 SPDK_ERRLOG("Submission failed with status=%d\n", status); 318 spdk_put_io_channel(ctx->ch); 319 env_free(ctx); 320 ocf_forward_end(token, (status == -ENOMEM) ? -OCF_ERR_NO_MEM : -OCF_ERR_IO); 321 } 322 } 323 324 static struct ocf_volume_properties vbdev_volume_props = { 325 .name = "SPDK_block_device", 326 .volume_priv_size = sizeof(struct vbdev_ocf_base *), 327 .caps = { 328 .atomic_writes = 0 /* to enable need to have ops->submit_metadata */ 329 }, 330 .ops = { 331 .open = vbdev_ocf_volume_open, 332 .close = vbdev_ocf_volume_close, 333 .get_length = vbdev_ocf_volume_get_length, 334 .get_max_io_size = vbdev_ocf_volume_get_max_io_size, 335 .forward_io = vbdev_forward_io, 336 .forward_flush = vbdev_forward_flush, 337 .forward_discard = vbdev_forward_discard, 338 .forward_io_simple = vbdev_forward_io_simple, 339 }, 340 }; 341 342 int 343 vbdev_ocf_volume_init(void) 344 { 345 return ocf_ctx_register_volume_type(vbdev_ocf_ctx, SPDK_OBJECT, &vbdev_volume_props); 346 } 347 348 void 349 vbdev_ocf_volume_cleanup(void) 350 { 351 ocf_ctx_unregister_volume_type(vbdev_ocf_ctx, SPDK_OBJECT); 352 } 353 354 SPDK_LOG_REGISTER_COMPONENT(vbdev_ocf_volume) 355