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 "spdk/stdinc.h" 35 36 #include "spdk/blob_bdev.h" 37 #include "spdk/blob.h" 38 #include "spdk/thread.h" 39 #include "spdk/log.h" 40 #include "spdk/endian.h" 41 #define __SPDK_BDEV_MODULE_ONLY 42 #include "spdk/bdev_module.h" 43 44 struct blob_bdev { 45 struct spdk_bs_dev bs_dev; 46 struct spdk_bdev *bdev; 47 struct spdk_bdev_desc *desc; 48 bool claimed; 49 }; 50 51 struct blob_resubmit { 52 struct spdk_bdev_io_wait_entry bdev_io_wait; 53 enum spdk_bdev_io_type io_type; 54 struct spdk_bs_dev *dev; 55 struct spdk_io_channel *channel; 56 void *payload; 57 int iovcnt; 58 uint64_t lba; 59 uint32_t lba_count; 60 struct spdk_bs_dev_cb_args *cb_args; 61 struct spdk_blob_ext_io_opts *ext_io_opts; 62 }; 63 static void bdev_blob_resubmit(void *); 64 65 static inline struct spdk_bdev_desc * 66 __get_desc(struct spdk_bs_dev *dev) 67 { 68 return ((struct blob_bdev *)dev)->desc; 69 } 70 71 static inline struct spdk_bdev * 72 __get_bdev(struct spdk_bs_dev *dev) 73 { 74 return ((struct blob_bdev *)dev)->bdev; 75 } 76 77 static void 78 bdev_blob_io_complete(struct spdk_bdev_io *bdev_io, bool success, void *arg) 79 { 80 struct spdk_bs_dev_cb_args *cb_args = arg; 81 int bserrno; 82 83 if (success) { 84 bserrno = 0; 85 } else { 86 bserrno = -EIO; 87 } 88 cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, bserrno); 89 spdk_bdev_free_io(bdev_io); 90 } 91 92 static void 93 bdev_blob_queue_io(struct spdk_bs_dev *dev, struct spdk_io_channel *channel, void *payload, 94 int iovcnt, uint64_t lba, uint32_t lba_count, enum spdk_bdev_io_type io_type, 95 struct spdk_bs_dev_cb_args *cb_args, struct spdk_blob_ext_io_opts *ext_io_opts) 96 { 97 int rc; 98 struct spdk_bdev *bdev = __get_bdev(dev); 99 struct blob_resubmit *ctx; 100 101 ctx = calloc(1, sizeof(struct blob_resubmit)); 102 103 if (ctx == NULL) { 104 SPDK_ERRLOG("Not enough memory to queue io\n"); 105 cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, -ENOMEM); 106 return; 107 } 108 109 ctx->io_type = io_type; 110 ctx->dev = dev; 111 ctx->channel = channel; 112 ctx->payload = payload; 113 ctx->iovcnt = iovcnt; 114 ctx->lba = lba; 115 ctx->lba_count = lba_count; 116 ctx->cb_args = cb_args; 117 ctx->bdev_io_wait.bdev = bdev; 118 ctx->bdev_io_wait.cb_fn = bdev_blob_resubmit; 119 ctx->bdev_io_wait.cb_arg = ctx; 120 ctx->ext_io_opts = ext_io_opts; 121 122 rc = spdk_bdev_queue_io_wait(bdev, channel, &ctx->bdev_io_wait); 123 if (rc != 0) { 124 SPDK_ERRLOG("Queue io failed, rc=%d\n", rc); 125 cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, rc); 126 free(ctx); 127 assert(false); 128 } 129 } 130 131 static void 132 bdev_blob_read(struct spdk_bs_dev *dev, struct spdk_io_channel *channel, void *payload, 133 uint64_t lba, uint32_t lba_count, struct spdk_bs_dev_cb_args *cb_args) 134 { 135 int rc; 136 137 rc = spdk_bdev_read_blocks(__get_desc(dev), channel, payload, lba, 138 lba_count, bdev_blob_io_complete, cb_args); 139 if (rc == -ENOMEM) { 140 bdev_blob_queue_io(dev, channel, payload, 0, lba, 141 lba_count, SPDK_BDEV_IO_TYPE_READ, cb_args, NULL); 142 } else if (rc != 0) { 143 cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, rc); 144 } 145 } 146 147 static void 148 bdev_blob_write(struct spdk_bs_dev *dev, struct spdk_io_channel *channel, void *payload, 149 uint64_t lba, uint32_t lba_count, struct spdk_bs_dev_cb_args *cb_args) 150 { 151 int rc; 152 153 rc = spdk_bdev_write_blocks(__get_desc(dev), channel, payload, lba, 154 lba_count, bdev_blob_io_complete, cb_args); 155 if (rc == -ENOMEM) { 156 bdev_blob_queue_io(dev, channel, payload, 0, lba, 157 lba_count, SPDK_BDEV_IO_TYPE_WRITE, cb_args, NULL); 158 } else if (rc != 0) { 159 cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, rc); 160 } 161 } 162 163 static void 164 bdev_blob_readv(struct spdk_bs_dev *dev, struct spdk_io_channel *channel, 165 struct iovec *iov, int iovcnt, 166 uint64_t lba, uint32_t lba_count, struct spdk_bs_dev_cb_args *cb_args) 167 { 168 int rc; 169 170 rc = spdk_bdev_readv_blocks(__get_desc(dev), channel, iov, iovcnt, lba, 171 lba_count, bdev_blob_io_complete, cb_args); 172 if (rc == -ENOMEM) { 173 bdev_blob_queue_io(dev, channel, iov, iovcnt, lba, 174 lba_count, SPDK_BDEV_IO_TYPE_READ, cb_args, NULL); 175 } else if (rc != 0) { 176 cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, rc); 177 } 178 } 179 180 static void 181 bdev_blob_writev(struct spdk_bs_dev *dev, struct spdk_io_channel *channel, 182 struct iovec *iov, int iovcnt, 183 uint64_t lba, uint32_t lba_count, struct spdk_bs_dev_cb_args *cb_args) 184 { 185 int rc; 186 187 rc = spdk_bdev_writev_blocks(__get_desc(dev), channel, iov, iovcnt, lba, 188 lba_count, bdev_blob_io_complete, cb_args); 189 if (rc == -ENOMEM) { 190 bdev_blob_queue_io(dev, channel, iov, iovcnt, lba, 191 lba_count, SPDK_BDEV_IO_TYPE_WRITE, cb_args, NULL); 192 } else if (rc != 0) { 193 cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, rc); 194 } 195 } 196 197 static void 198 bdev_blob_readv_ext(struct spdk_bs_dev *dev, struct spdk_io_channel *channel, 199 struct iovec *iov, int iovcnt, 200 uint64_t lba, uint32_t lba_count, struct spdk_bs_dev_cb_args *cb_args, 201 struct spdk_blob_ext_io_opts *io_opts) 202 { 203 struct spdk_bdev_ext_io_opts *bdev_io_opts = NULL; 204 int rc; 205 206 if (io_opts) { 207 /* bdev ext API requires ext_io_opts to be allocated by the user, we don't have enough context to allocate 208 * bdev ext_opts structure here. Also blob and bdev ext_opts are not API/ABI compatible, so we can't use the given 209 * io_opts. Restore ext_opts passed by the user of this bs_dev */ 210 bdev_io_opts = io_opts->user_ctx; 211 assert(bdev_io_opts); 212 } 213 214 rc = spdk_bdev_readv_blocks_ext(__get_desc(dev), channel, iov, iovcnt, lba, lba_count, 215 bdev_blob_io_complete, cb_args, bdev_io_opts); 216 if (rc == -ENOMEM) { 217 bdev_blob_queue_io(dev, channel, iov, iovcnt, lba, lba_count, SPDK_BDEV_IO_TYPE_READ, cb_args, 218 io_opts); 219 } else if (rc != 0) { 220 cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, rc); 221 } 222 } 223 224 static void 225 bdev_blob_writev_ext(struct spdk_bs_dev *dev, struct spdk_io_channel *channel, 226 struct iovec *iov, int iovcnt, 227 uint64_t lba, uint32_t lba_count, struct spdk_bs_dev_cb_args *cb_args, 228 struct spdk_blob_ext_io_opts *io_opts) 229 { 230 struct spdk_bdev_ext_io_opts *bdev_io_opts = NULL; 231 int rc; 232 233 if (io_opts) { 234 /* bdev ext API requires ext_io_opts to be allocated by the user, we don't have enough context to allocate 235 * bdev ext_opts structure here. Also blob and bdev ext_opts are not API/ABI compatible, so we can't use the given 236 * io_opts. Restore ext_opts passed by the user of this bs_dev */ 237 bdev_io_opts = io_opts->user_ctx; 238 assert(bdev_io_opts); 239 } 240 241 rc = spdk_bdev_writev_blocks_ext(__get_desc(dev), channel, iov, iovcnt, lba, lba_count, 242 bdev_blob_io_complete, cb_args, bdev_io_opts); 243 if (rc == -ENOMEM) { 244 bdev_blob_queue_io(dev, channel, iov, iovcnt, lba, lba_count, SPDK_BDEV_IO_TYPE_WRITE, cb_args, 245 io_opts); 246 } else if (rc != 0) { 247 cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, rc); 248 } 249 } 250 251 static void 252 bdev_blob_write_zeroes(struct spdk_bs_dev *dev, struct spdk_io_channel *channel, uint64_t lba, 253 uint64_t lba_count, struct spdk_bs_dev_cb_args *cb_args) 254 { 255 int rc; 256 257 rc = spdk_bdev_write_zeroes_blocks(__get_desc(dev), channel, lba, 258 lba_count, bdev_blob_io_complete, cb_args); 259 if (rc == -ENOMEM) { 260 bdev_blob_queue_io(dev, channel, NULL, 0, lba, 261 lba_count, SPDK_BDEV_IO_TYPE_WRITE_ZEROES, cb_args, NULL); 262 } else if (rc != 0) { 263 cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, rc); 264 } 265 } 266 267 static void 268 bdev_blob_unmap(struct spdk_bs_dev *dev, struct spdk_io_channel *channel, uint64_t lba, 269 uint64_t lba_count, struct spdk_bs_dev_cb_args *cb_args) 270 { 271 struct blob_bdev *blob_bdev = (struct blob_bdev *)dev; 272 int rc; 273 274 if (spdk_bdev_io_type_supported(blob_bdev->bdev, SPDK_BDEV_IO_TYPE_UNMAP)) { 275 rc = spdk_bdev_unmap_blocks(__get_desc(dev), channel, lba, lba_count, 276 bdev_blob_io_complete, cb_args); 277 if (rc == -ENOMEM) { 278 bdev_blob_queue_io(dev, channel, NULL, 0, lba, 279 lba_count, SPDK_BDEV_IO_TYPE_UNMAP, cb_args, NULL); 280 } else if (rc != 0) { 281 cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, rc); 282 } 283 } else { 284 /* 285 * If the device doesn't support unmap, immediately complete 286 * the request. Blobstore does not rely on unmap zeroing 287 * data. 288 */ 289 cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, 0); 290 } 291 } 292 293 static void 294 bdev_blob_resubmit(void *arg) 295 { 296 struct blob_resubmit *ctx = (struct blob_resubmit *) arg; 297 298 switch (ctx->io_type) { 299 case SPDK_BDEV_IO_TYPE_READ: 300 if (ctx->iovcnt > 0) { 301 bdev_blob_readv_ext(ctx->dev, ctx->channel, (struct iovec *) ctx->payload, ctx->iovcnt, 302 ctx->lba, ctx->lba_count, ctx->cb_args, ctx->ext_io_opts); 303 } else { 304 bdev_blob_read(ctx->dev, ctx->channel, ctx->payload, 305 ctx->lba, ctx->lba_count, ctx->cb_args); 306 } 307 break; 308 case SPDK_BDEV_IO_TYPE_WRITE: 309 if (ctx->iovcnt > 0) { 310 bdev_blob_writev_ext(ctx->dev, ctx->channel, (struct iovec *) ctx->payload, ctx->iovcnt, 311 ctx->lba, ctx->lba_count, ctx->cb_args, ctx->ext_io_opts); 312 } else { 313 bdev_blob_write(ctx->dev, ctx->channel, ctx->payload, 314 ctx->lba, ctx->lba_count, ctx->cb_args); 315 } 316 break; 317 case SPDK_BDEV_IO_TYPE_UNMAP: 318 bdev_blob_unmap(ctx->dev, ctx->channel, 319 ctx->lba, ctx->lba_count, ctx->cb_args); 320 break; 321 case SPDK_BDEV_IO_TYPE_WRITE_ZEROES: 322 bdev_blob_write_zeroes(ctx->dev, ctx->channel, 323 ctx->lba, ctx->lba_count, ctx->cb_args); 324 break; 325 default: 326 SPDK_ERRLOG("Unsupported io type %d\n", ctx->io_type); 327 assert(false); 328 break; 329 } 330 free(ctx); 331 } 332 333 int 334 spdk_bs_bdev_claim(struct spdk_bs_dev *bs_dev, struct spdk_bdev_module *module) 335 { 336 struct blob_bdev *blob_bdev = (struct blob_bdev *)bs_dev; 337 int rc; 338 339 rc = spdk_bdev_module_claim_bdev(blob_bdev->bdev, NULL, module); 340 if (rc != 0) { 341 SPDK_ERRLOG("could not claim bs dev\n"); 342 return rc; 343 } 344 345 blob_bdev->claimed = true; 346 347 return rc; 348 } 349 350 static struct spdk_io_channel * 351 bdev_blob_create_channel(struct spdk_bs_dev *dev) 352 { 353 struct blob_bdev *blob_bdev = (struct blob_bdev *)dev; 354 355 return spdk_bdev_get_io_channel(blob_bdev->desc); 356 } 357 358 static void 359 bdev_blob_destroy_channel(struct spdk_bs_dev *dev, struct spdk_io_channel *channel) 360 { 361 spdk_put_io_channel(channel); 362 } 363 364 static void 365 bdev_blob_destroy(struct spdk_bs_dev *bs_dev) 366 { 367 struct spdk_bdev_desc *desc = __get_desc(bs_dev); 368 struct blob_bdev *blob_bdev = (struct blob_bdev *)bs_dev; 369 370 if (blob_bdev->claimed) { 371 spdk_bdev_module_release_bdev(blob_bdev->bdev); 372 } 373 374 spdk_bdev_close(desc); 375 free(bs_dev); 376 } 377 378 static struct spdk_bdev * 379 bdev_blob_get_base_bdev(struct spdk_bs_dev *bs_dev) 380 { 381 return __get_bdev(bs_dev); 382 } 383 384 static void 385 blob_bdev_init(struct blob_bdev *b, struct spdk_bdev_desc *desc) 386 { 387 struct spdk_bdev *bdev; 388 389 bdev = spdk_bdev_desc_get_bdev(desc); 390 assert(bdev != NULL); 391 392 b->bdev = bdev; 393 b->desc = desc; 394 b->bs_dev.blockcnt = spdk_bdev_get_num_blocks(bdev); 395 b->bs_dev.blocklen = spdk_bdev_get_block_size(bdev); 396 b->bs_dev.create_channel = bdev_blob_create_channel; 397 b->bs_dev.destroy_channel = bdev_blob_destroy_channel; 398 b->bs_dev.destroy = bdev_blob_destroy; 399 b->bs_dev.read = bdev_blob_read; 400 b->bs_dev.write = bdev_blob_write; 401 b->bs_dev.readv = bdev_blob_readv; 402 b->bs_dev.writev = bdev_blob_writev; 403 b->bs_dev.readv_ext = bdev_blob_readv_ext; 404 b->bs_dev.writev_ext = bdev_blob_writev_ext; 405 b->bs_dev.write_zeroes = bdev_blob_write_zeroes; 406 b->bs_dev.unmap = bdev_blob_unmap; 407 b->bs_dev.get_base_bdev = bdev_blob_get_base_bdev; 408 } 409 410 int 411 spdk_bdev_create_bs_dev_ext(const char *bdev_name, spdk_bdev_event_cb_t event_cb, 412 void *event_ctx, struct spdk_bs_dev **_bs_dev) 413 { 414 struct blob_bdev *b; 415 struct spdk_bdev_desc *desc; 416 int rc; 417 418 b = calloc(1, sizeof(*b)); 419 420 if (b == NULL) { 421 SPDK_ERRLOG("could not allocate blob_bdev\n"); 422 return -ENOMEM; 423 } 424 425 rc = spdk_bdev_open_ext(bdev_name, true, event_cb, event_ctx, &desc); 426 if (rc != 0) { 427 free(b); 428 return rc; 429 } 430 431 blob_bdev_init(b, desc); 432 433 *_bs_dev = &b->bs_dev; 434 435 return 0; 436 } 437