1488570ebSJim Harris /* SPDX-License-Identifier: BSD-3-Clause 2a6dbe372Spaul luse * Copyright (C) 2017 Intel Corporation. 37392cdefSSeth Howell * All rights reserved. 4f246b2d5SMike Gerdts * Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 57392cdefSSeth Howell */ 67392cdefSSeth Howell 77392cdefSSeth Howell #include "spdk/stdinc.h" 87392cdefSSeth Howell 97392cdefSSeth Howell #include "spdk/blob_bdev.h" 107392cdefSSeth Howell #include "spdk/blob.h" 117392cdefSSeth Howell #include "spdk/thread.h" 127392cdefSSeth Howell #include "spdk/log.h" 137392cdefSSeth Howell #include "spdk/endian.h" 14eef51593SJim Harris #define __SPDK_BDEV_MODULE_ONLY 157392cdefSSeth Howell #include "spdk/bdev_module.h" 167392cdefSSeth Howell 177392cdefSSeth Howell struct blob_bdev { 187392cdefSSeth Howell struct spdk_bs_dev bs_dev; 197392cdefSSeth Howell struct spdk_bdev *bdev; 207392cdefSSeth Howell struct spdk_bdev_desc *desc; 21ab2eff07SMike Gerdts bool write; 22421fb110SMike Gerdts int32_t refs; 23421fb110SMike Gerdts struct spdk_spinlock lock; 247392cdefSSeth Howell }; 257392cdefSSeth Howell 267392cdefSSeth Howell struct blob_resubmit { 277392cdefSSeth Howell struct spdk_bdev_io_wait_entry bdev_io_wait; 287392cdefSSeth Howell enum spdk_bdev_io_type io_type; 297392cdefSSeth Howell struct spdk_bs_dev *dev; 307392cdefSSeth Howell struct spdk_io_channel *channel; 317392cdefSSeth Howell void *payload; 327392cdefSSeth Howell int iovcnt; 337392cdefSSeth Howell uint64_t lba; 34b7bfa504SEvgeniy Kochetov uint64_t src_lba; 357392cdefSSeth Howell uint32_t lba_count; 367392cdefSSeth Howell struct spdk_bs_dev_cb_args *cb_args; 37c3a40396SAlexey Marchuk struct spdk_blob_ext_io_opts *ext_io_opts; 387392cdefSSeth Howell }; 397392cdefSSeth Howell static void bdev_blob_resubmit(void *); 407392cdefSSeth Howell 417392cdefSSeth Howell static inline struct spdk_bdev_desc * 427392cdefSSeth Howell __get_desc(struct spdk_bs_dev *dev) 437392cdefSSeth Howell { 447392cdefSSeth Howell return ((struct blob_bdev *)dev)->desc; 457392cdefSSeth Howell } 467392cdefSSeth Howell 477392cdefSSeth Howell static inline struct spdk_bdev * 487392cdefSSeth Howell __get_bdev(struct spdk_bs_dev *dev) 497392cdefSSeth Howell { 507392cdefSSeth Howell return ((struct blob_bdev *)dev)->bdev; 517392cdefSSeth Howell } 527392cdefSSeth Howell 537392cdefSSeth Howell static void 547392cdefSSeth Howell bdev_blob_io_complete(struct spdk_bdev_io *bdev_io, bool success, void *arg) 557392cdefSSeth Howell { 567392cdefSSeth Howell struct spdk_bs_dev_cb_args *cb_args = arg; 577392cdefSSeth Howell int bserrno; 587392cdefSSeth Howell 597392cdefSSeth Howell if (success) { 607392cdefSSeth Howell bserrno = 0; 617392cdefSSeth Howell } else { 627392cdefSSeth Howell bserrno = -EIO; 637392cdefSSeth Howell } 647392cdefSSeth Howell cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, bserrno); 657392cdefSSeth Howell spdk_bdev_free_io(bdev_io); 667392cdefSSeth Howell } 677392cdefSSeth Howell 687392cdefSSeth Howell static void 697392cdefSSeth Howell bdev_blob_queue_io(struct spdk_bs_dev *dev, struct spdk_io_channel *channel, void *payload, 70b7bfa504SEvgeniy Kochetov int iovcnt, uint64_t lba, uint64_t src_lba, uint32_t lba_count, 71b7bfa504SEvgeniy Kochetov enum spdk_bdev_io_type io_type, struct spdk_bs_dev_cb_args *cb_args, 72b7bfa504SEvgeniy Kochetov struct spdk_blob_ext_io_opts *ext_io_opts) 737392cdefSSeth Howell { 747392cdefSSeth Howell int rc; 757392cdefSSeth Howell struct spdk_bdev *bdev = __get_bdev(dev); 767392cdefSSeth Howell struct blob_resubmit *ctx; 777392cdefSSeth Howell 787392cdefSSeth Howell ctx = calloc(1, sizeof(struct blob_resubmit)); 797392cdefSSeth Howell 807392cdefSSeth Howell if (ctx == NULL) { 817392cdefSSeth Howell SPDK_ERRLOG("Not enough memory to queue io\n"); 827392cdefSSeth Howell cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, -ENOMEM); 837392cdefSSeth Howell return; 847392cdefSSeth Howell } 857392cdefSSeth Howell 867392cdefSSeth Howell ctx->io_type = io_type; 877392cdefSSeth Howell ctx->dev = dev; 887392cdefSSeth Howell ctx->channel = channel; 897392cdefSSeth Howell ctx->payload = payload; 907392cdefSSeth Howell ctx->iovcnt = iovcnt; 917392cdefSSeth Howell ctx->lba = lba; 92b7bfa504SEvgeniy Kochetov ctx->src_lba = src_lba; 937392cdefSSeth Howell ctx->lba_count = lba_count; 947392cdefSSeth Howell ctx->cb_args = cb_args; 957392cdefSSeth Howell ctx->bdev_io_wait.bdev = bdev; 967392cdefSSeth Howell ctx->bdev_io_wait.cb_fn = bdev_blob_resubmit; 977392cdefSSeth Howell ctx->bdev_io_wait.cb_arg = ctx; 98c3a40396SAlexey Marchuk ctx->ext_io_opts = ext_io_opts; 997392cdefSSeth Howell 1007392cdefSSeth Howell rc = spdk_bdev_queue_io_wait(bdev, channel, &ctx->bdev_io_wait); 1017392cdefSSeth Howell if (rc != 0) { 1027392cdefSSeth Howell SPDK_ERRLOG("Queue io failed, rc=%d\n", rc); 1037392cdefSSeth Howell cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, rc); 1047392cdefSSeth Howell free(ctx); 1057392cdefSSeth Howell assert(false); 1067392cdefSSeth Howell } 1077392cdefSSeth Howell } 1087392cdefSSeth Howell 1097392cdefSSeth Howell static void 1107392cdefSSeth Howell bdev_blob_read(struct spdk_bs_dev *dev, struct spdk_io_channel *channel, void *payload, 1117392cdefSSeth Howell uint64_t lba, uint32_t lba_count, struct spdk_bs_dev_cb_args *cb_args) 1127392cdefSSeth Howell { 1137392cdefSSeth Howell int rc; 1147392cdefSSeth Howell 1157392cdefSSeth Howell rc = spdk_bdev_read_blocks(__get_desc(dev), channel, payload, lba, 1167392cdefSSeth Howell lba_count, bdev_blob_io_complete, cb_args); 1177392cdefSSeth Howell if (rc == -ENOMEM) { 118b7bfa504SEvgeniy Kochetov bdev_blob_queue_io(dev, channel, payload, 0, lba, 0, 119c3a40396SAlexey Marchuk lba_count, SPDK_BDEV_IO_TYPE_READ, cb_args, NULL); 1207392cdefSSeth Howell } else if (rc != 0) { 1217392cdefSSeth Howell cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, rc); 1227392cdefSSeth Howell } 1237392cdefSSeth Howell } 1247392cdefSSeth Howell 1257392cdefSSeth Howell static void 1267392cdefSSeth Howell bdev_blob_write(struct spdk_bs_dev *dev, struct spdk_io_channel *channel, void *payload, 1277392cdefSSeth Howell uint64_t lba, uint32_t lba_count, struct spdk_bs_dev_cb_args *cb_args) 1287392cdefSSeth Howell { 1297392cdefSSeth Howell int rc; 1307392cdefSSeth Howell 1317392cdefSSeth Howell rc = spdk_bdev_write_blocks(__get_desc(dev), channel, payload, lba, 1327392cdefSSeth Howell lba_count, bdev_blob_io_complete, cb_args); 1337392cdefSSeth Howell if (rc == -ENOMEM) { 134b7bfa504SEvgeniy Kochetov bdev_blob_queue_io(dev, channel, payload, 0, lba, 0, 135c3a40396SAlexey Marchuk lba_count, SPDK_BDEV_IO_TYPE_WRITE, cb_args, NULL); 1367392cdefSSeth Howell } else if (rc != 0) { 1377392cdefSSeth Howell cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, rc); 1387392cdefSSeth Howell } 1397392cdefSSeth Howell } 1407392cdefSSeth Howell 1417392cdefSSeth Howell static void 1427392cdefSSeth Howell bdev_blob_readv(struct spdk_bs_dev *dev, struct spdk_io_channel *channel, 1437392cdefSSeth Howell struct iovec *iov, int iovcnt, 1447392cdefSSeth Howell uint64_t lba, uint32_t lba_count, struct spdk_bs_dev_cb_args *cb_args) 1457392cdefSSeth Howell { 1467392cdefSSeth Howell int rc; 1477392cdefSSeth Howell 1487392cdefSSeth Howell rc = spdk_bdev_readv_blocks(__get_desc(dev), channel, iov, iovcnt, lba, 1497392cdefSSeth Howell lba_count, bdev_blob_io_complete, cb_args); 1507392cdefSSeth Howell if (rc == -ENOMEM) { 151b7bfa504SEvgeniy Kochetov bdev_blob_queue_io(dev, channel, iov, iovcnt, lba, 0, 152c3a40396SAlexey Marchuk lba_count, SPDK_BDEV_IO_TYPE_READ, cb_args, NULL); 1537392cdefSSeth Howell } else if (rc != 0) { 1547392cdefSSeth Howell cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, rc); 1557392cdefSSeth Howell } 1567392cdefSSeth Howell } 1577392cdefSSeth Howell 1587392cdefSSeth Howell static void 1597392cdefSSeth Howell bdev_blob_writev(struct spdk_bs_dev *dev, struct spdk_io_channel *channel, 1607392cdefSSeth Howell struct iovec *iov, int iovcnt, 1617392cdefSSeth Howell uint64_t lba, uint32_t lba_count, struct spdk_bs_dev_cb_args *cb_args) 1627392cdefSSeth Howell { 1637392cdefSSeth Howell int rc; 1647392cdefSSeth Howell 1657392cdefSSeth Howell rc = spdk_bdev_writev_blocks(__get_desc(dev), channel, iov, iovcnt, lba, 1667392cdefSSeth Howell lba_count, bdev_blob_io_complete, cb_args); 1677392cdefSSeth Howell if (rc == -ENOMEM) { 168b7bfa504SEvgeniy Kochetov bdev_blob_queue_io(dev, channel, iov, iovcnt, lba, 0, 169c3a40396SAlexey Marchuk lba_count, SPDK_BDEV_IO_TYPE_WRITE, cb_args, NULL); 1707392cdefSSeth Howell } else if (rc != 0) { 1717392cdefSSeth Howell cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, rc); 1727392cdefSSeth Howell } 1737392cdefSSeth Howell } 1747392cdefSSeth Howell 17555f94793SKonrad Sztyber static inline void 17655f94793SKonrad Sztyber blob_ext_io_opts_to_bdev_opts(struct spdk_bdev_ext_io_opts *dst, struct spdk_blob_ext_io_opts *src) 17755f94793SKonrad Sztyber { 17855f94793SKonrad Sztyber memset(dst, 0, sizeof(*dst)); 17955f94793SKonrad Sztyber dst->size = sizeof(*dst); 18055f94793SKonrad Sztyber dst->memory_domain = src->memory_domain; 18155f94793SKonrad Sztyber dst->memory_domain_ctx = src->memory_domain_ctx; 18255f94793SKonrad Sztyber } 18355f94793SKonrad Sztyber 1847392cdefSSeth Howell static void 185ba8f1a9eSAlexey Marchuk bdev_blob_readv_ext(struct spdk_bs_dev *dev, struct spdk_io_channel *channel, 186ba8f1a9eSAlexey Marchuk struct iovec *iov, int iovcnt, 187ba8f1a9eSAlexey Marchuk uint64_t lba, uint32_t lba_count, struct spdk_bs_dev_cb_args *cb_args, 188ba8f1a9eSAlexey Marchuk struct spdk_blob_ext_io_opts *io_opts) 189ba8f1a9eSAlexey Marchuk { 19055f94793SKonrad Sztyber struct spdk_bdev_ext_io_opts bdev_io_opts; 191c3a40396SAlexey Marchuk int rc; 192c3a40396SAlexey Marchuk 19355f94793SKonrad Sztyber blob_ext_io_opts_to_bdev_opts(&bdev_io_opts, io_opts); 194c3a40396SAlexey Marchuk rc = spdk_bdev_readv_blocks_ext(__get_desc(dev), channel, iov, iovcnt, lba, lba_count, 19555f94793SKonrad Sztyber bdev_blob_io_complete, cb_args, &bdev_io_opts); 196c3a40396SAlexey Marchuk if (rc == -ENOMEM) { 197b7bfa504SEvgeniy Kochetov bdev_blob_queue_io(dev, channel, iov, iovcnt, lba, 0, lba_count, SPDK_BDEV_IO_TYPE_READ, cb_args, 198c3a40396SAlexey Marchuk io_opts); 199c3a40396SAlexey Marchuk } else if (rc != 0) { 200c3a40396SAlexey Marchuk cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, rc); 201c3a40396SAlexey Marchuk } 202ba8f1a9eSAlexey Marchuk } 203ba8f1a9eSAlexey Marchuk 204ba8f1a9eSAlexey Marchuk static void 205ba8f1a9eSAlexey Marchuk bdev_blob_writev_ext(struct spdk_bs_dev *dev, struct spdk_io_channel *channel, 206ba8f1a9eSAlexey Marchuk struct iovec *iov, int iovcnt, 207ba8f1a9eSAlexey Marchuk uint64_t lba, uint32_t lba_count, struct spdk_bs_dev_cb_args *cb_args, 208ba8f1a9eSAlexey Marchuk struct spdk_blob_ext_io_opts *io_opts) 209ba8f1a9eSAlexey Marchuk { 21055f94793SKonrad Sztyber struct spdk_bdev_ext_io_opts bdev_io_opts; 211c3a40396SAlexey Marchuk int rc; 212c3a40396SAlexey Marchuk 21355f94793SKonrad Sztyber blob_ext_io_opts_to_bdev_opts(&bdev_io_opts, io_opts); 214c3a40396SAlexey Marchuk rc = spdk_bdev_writev_blocks_ext(__get_desc(dev), channel, iov, iovcnt, lba, lba_count, 21555f94793SKonrad Sztyber bdev_blob_io_complete, cb_args, &bdev_io_opts); 216c3a40396SAlexey Marchuk if (rc == -ENOMEM) { 217b7bfa504SEvgeniy Kochetov bdev_blob_queue_io(dev, channel, iov, iovcnt, lba, 0, lba_count, SPDK_BDEV_IO_TYPE_WRITE, cb_args, 218c3a40396SAlexey Marchuk io_opts); 219c3a40396SAlexey Marchuk } else if (rc != 0) { 220c3a40396SAlexey Marchuk cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, rc); 221c3a40396SAlexey Marchuk } 222ba8f1a9eSAlexey Marchuk } 223ba8f1a9eSAlexey Marchuk 224ba8f1a9eSAlexey Marchuk static void 2257392cdefSSeth Howell bdev_blob_write_zeroes(struct spdk_bs_dev *dev, struct spdk_io_channel *channel, uint64_t lba, 226f01146aeSJim Harris uint64_t lba_count, struct spdk_bs_dev_cb_args *cb_args) 2277392cdefSSeth Howell { 2287392cdefSSeth Howell int rc; 2297392cdefSSeth Howell 2307392cdefSSeth Howell rc = spdk_bdev_write_zeroes_blocks(__get_desc(dev), channel, lba, 2317392cdefSSeth Howell lba_count, bdev_blob_io_complete, cb_args); 2327392cdefSSeth Howell if (rc == -ENOMEM) { 233b7bfa504SEvgeniy Kochetov bdev_blob_queue_io(dev, channel, NULL, 0, lba, 0, 234c3a40396SAlexey Marchuk lba_count, SPDK_BDEV_IO_TYPE_WRITE_ZEROES, cb_args, NULL); 2357392cdefSSeth Howell } else if (rc != 0) { 2367392cdefSSeth Howell cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, rc); 2377392cdefSSeth Howell } 2387392cdefSSeth Howell } 2397392cdefSSeth Howell 2407392cdefSSeth Howell static void 2417392cdefSSeth Howell bdev_blob_unmap(struct spdk_bs_dev *dev, struct spdk_io_channel *channel, uint64_t lba, 242f01146aeSJim Harris uint64_t lba_count, struct spdk_bs_dev_cb_args *cb_args) 2437392cdefSSeth Howell { 2447392cdefSSeth Howell struct blob_bdev *blob_bdev = (struct blob_bdev *)dev; 2457392cdefSSeth Howell int rc; 2467392cdefSSeth Howell 2477392cdefSSeth Howell if (spdk_bdev_io_type_supported(blob_bdev->bdev, SPDK_BDEV_IO_TYPE_UNMAP)) { 2487392cdefSSeth Howell rc = spdk_bdev_unmap_blocks(__get_desc(dev), channel, lba, lba_count, 2497392cdefSSeth Howell bdev_blob_io_complete, cb_args); 2507392cdefSSeth Howell if (rc == -ENOMEM) { 251b7bfa504SEvgeniy Kochetov bdev_blob_queue_io(dev, channel, NULL, 0, lba, 0, 252c3a40396SAlexey Marchuk lba_count, SPDK_BDEV_IO_TYPE_UNMAP, cb_args, NULL); 2537392cdefSSeth Howell } else if (rc != 0) { 2547392cdefSSeth Howell cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, rc); 2557392cdefSSeth Howell } 2567392cdefSSeth Howell } else { 2577392cdefSSeth Howell /* 2587392cdefSSeth Howell * If the device doesn't support unmap, immediately complete 2597392cdefSSeth Howell * the request. Blobstore does not rely on unmap zeroing 2607392cdefSSeth Howell * data. 2617392cdefSSeth Howell */ 2627392cdefSSeth Howell cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, 0); 2637392cdefSSeth Howell } 2647392cdefSSeth Howell } 2657392cdefSSeth Howell 2667392cdefSSeth Howell static void 267b7bfa504SEvgeniy Kochetov bdev_blob_copy(struct spdk_bs_dev *dev, struct spdk_io_channel *channel, 268b7bfa504SEvgeniy Kochetov uint64_t dst_lba, uint64_t src_lba, uint64_t lba_count, 269b7bfa504SEvgeniy Kochetov struct spdk_bs_dev_cb_args *cb_args) 270b7bfa504SEvgeniy Kochetov { 271b7bfa504SEvgeniy Kochetov int rc; 272b7bfa504SEvgeniy Kochetov 273b7bfa504SEvgeniy Kochetov rc = spdk_bdev_copy_blocks(__get_desc(dev), channel, 274b7bfa504SEvgeniy Kochetov dst_lba, src_lba, lba_count, 275b7bfa504SEvgeniy Kochetov bdev_blob_io_complete, cb_args); 276b7bfa504SEvgeniy Kochetov if (rc == -ENOMEM) { 277b7bfa504SEvgeniy Kochetov bdev_blob_queue_io(dev, channel, NULL, 0, dst_lba, src_lba, 278b7bfa504SEvgeniy Kochetov lba_count, SPDK_BDEV_IO_TYPE_COPY, cb_args, NULL); 279b7bfa504SEvgeniy Kochetov } else if (rc != 0) { 280b7bfa504SEvgeniy Kochetov cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, rc); 281b7bfa504SEvgeniy Kochetov } 282b7bfa504SEvgeniy Kochetov } 283b7bfa504SEvgeniy Kochetov 284b7bfa504SEvgeniy Kochetov static void 2857392cdefSSeth Howell bdev_blob_resubmit(void *arg) 2867392cdefSSeth Howell { 2877392cdefSSeth Howell struct blob_resubmit *ctx = (struct blob_resubmit *) arg; 2887392cdefSSeth Howell 2897392cdefSSeth Howell switch (ctx->io_type) { 2907392cdefSSeth Howell case SPDK_BDEV_IO_TYPE_READ: 2917392cdefSSeth Howell if (ctx->iovcnt > 0) { 2923f0a3930SJinlong Chen if (ctx->ext_io_opts) { 293c3a40396SAlexey Marchuk bdev_blob_readv_ext(ctx->dev, ctx->channel, (struct iovec *) ctx->payload, ctx->iovcnt, 294c3a40396SAlexey Marchuk ctx->lba, ctx->lba_count, ctx->cb_args, ctx->ext_io_opts); 2957392cdefSSeth Howell } else { 2963f0a3930SJinlong Chen bdev_blob_readv(ctx->dev, ctx->channel, (struct iovec *) ctx->payload, ctx->iovcnt, 2973f0a3930SJinlong Chen ctx->lba, ctx->lba_count, ctx->cb_args); 2983f0a3930SJinlong Chen } 2993f0a3930SJinlong Chen } else { 3007392cdefSSeth Howell bdev_blob_read(ctx->dev, ctx->channel, ctx->payload, 3017392cdefSSeth Howell ctx->lba, ctx->lba_count, ctx->cb_args); 3027392cdefSSeth Howell } 3037392cdefSSeth Howell break; 3047392cdefSSeth Howell case SPDK_BDEV_IO_TYPE_WRITE: 3057392cdefSSeth Howell if (ctx->iovcnt > 0) { 3063f0a3930SJinlong Chen if (ctx->ext_io_opts) { 307c3a40396SAlexey Marchuk bdev_blob_writev_ext(ctx->dev, ctx->channel, (struct iovec *) ctx->payload, ctx->iovcnt, 308c3a40396SAlexey Marchuk ctx->lba, ctx->lba_count, ctx->cb_args, ctx->ext_io_opts); 3097392cdefSSeth Howell } else { 3103f0a3930SJinlong Chen bdev_blob_writev(ctx->dev, ctx->channel, (struct iovec *) ctx->payload, ctx->iovcnt, 3113f0a3930SJinlong Chen ctx->lba, ctx->lba_count, ctx->cb_args); 3123f0a3930SJinlong Chen } 3133f0a3930SJinlong Chen } else { 3147392cdefSSeth Howell bdev_blob_write(ctx->dev, ctx->channel, ctx->payload, 3157392cdefSSeth Howell ctx->lba, ctx->lba_count, ctx->cb_args); 3167392cdefSSeth Howell } 3177392cdefSSeth Howell break; 3187392cdefSSeth Howell case SPDK_BDEV_IO_TYPE_UNMAP: 3197392cdefSSeth Howell bdev_blob_unmap(ctx->dev, ctx->channel, 3207392cdefSSeth Howell ctx->lba, ctx->lba_count, ctx->cb_args); 3217392cdefSSeth Howell break; 3227392cdefSSeth Howell case SPDK_BDEV_IO_TYPE_WRITE_ZEROES: 3237392cdefSSeth Howell bdev_blob_write_zeroes(ctx->dev, ctx->channel, 3247392cdefSSeth Howell ctx->lba, ctx->lba_count, ctx->cb_args); 3257392cdefSSeth Howell break; 326b7bfa504SEvgeniy Kochetov case SPDK_BDEV_IO_TYPE_COPY: 327b7bfa504SEvgeniy Kochetov bdev_blob_copy(ctx->dev, ctx->channel, 328b7bfa504SEvgeniy Kochetov ctx->lba, ctx->src_lba, ctx->lba_count, ctx->cb_args); 329b7bfa504SEvgeniy Kochetov break; 3307392cdefSSeth Howell default: 3317392cdefSSeth Howell SPDK_ERRLOG("Unsupported io type %d\n", ctx->io_type); 3327392cdefSSeth Howell assert(false); 3337392cdefSSeth Howell break; 3347392cdefSSeth Howell } 3357392cdefSSeth Howell free(ctx); 3367392cdefSSeth Howell } 3377392cdefSSeth Howell 3387392cdefSSeth Howell int 3397392cdefSSeth Howell spdk_bs_bdev_claim(struct spdk_bs_dev *bs_dev, struct spdk_bdev_module *module) 3407392cdefSSeth Howell { 341ab2eff07SMike Gerdts struct blob_bdev *blob_bdev = (struct blob_bdev *)bs_dev; 342ab2eff07SMike Gerdts struct spdk_bdev_desc *desc = blob_bdev->desc; 343ab2eff07SMike Gerdts enum spdk_bdev_claim_type claim_type; 3447392cdefSSeth Howell int rc; 3457392cdefSSeth Howell 346ab2eff07SMike Gerdts claim_type = blob_bdev->write ? SPDK_BDEV_CLAIM_READ_MANY_WRITE_ONE : 347ab2eff07SMike Gerdts SPDK_BDEV_CLAIM_READ_MANY_WRITE_NONE; 348ab2eff07SMike Gerdts rc = spdk_bdev_module_claim_bdev_desc(desc, claim_type, NULL, module); 3497392cdefSSeth Howell if (rc != 0) { 3507392cdefSSeth Howell SPDK_ERRLOG("could not claim bs dev\n"); 3517392cdefSSeth Howell return rc; 3527392cdefSSeth Howell } 3537392cdefSSeth Howell 3547392cdefSSeth Howell return rc; 3557392cdefSSeth Howell } 3567392cdefSSeth Howell 3577392cdefSSeth Howell static struct spdk_io_channel * 3587392cdefSSeth Howell bdev_blob_create_channel(struct spdk_bs_dev *dev) 3597392cdefSSeth Howell { 3607392cdefSSeth Howell struct blob_bdev *blob_bdev = (struct blob_bdev *)dev; 361421fb110SMike Gerdts struct spdk_io_channel *ch; 3627392cdefSSeth Howell 363421fb110SMike Gerdts ch = spdk_bdev_get_io_channel(blob_bdev->desc); 364421fb110SMike Gerdts if (ch != NULL) { 365421fb110SMike Gerdts spdk_spin_lock(&blob_bdev->lock); 366421fb110SMike Gerdts blob_bdev->refs++; 367421fb110SMike Gerdts spdk_spin_unlock(&blob_bdev->lock); 368421fb110SMike Gerdts } 369421fb110SMike Gerdts 370421fb110SMike Gerdts return ch; 371421fb110SMike Gerdts } 372421fb110SMike Gerdts 373421fb110SMike Gerdts static void 374421fb110SMike Gerdts bdev_blob_free(struct blob_bdev *blob_bdev) 375421fb110SMike Gerdts { 376421fb110SMike Gerdts assert(blob_bdev->refs == 0); 377421fb110SMike Gerdts 378421fb110SMike Gerdts spdk_spin_destroy(&blob_bdev->lock); 379421fb110SMike Gerdts free(blob_bdev); 3807392cdefSSeth Howell } 3817392cdefSSeth Howell 3827392cdefSSeth Howell static void 3837392cdefSSeth Howell bdev_blob_destroy_channel(struct spdk_bs_dev *dev, struct spdk_io_channel *channel) 3847392cdefSSeth Howell { 385421fb110SMike Gerdts struct blob_bdev *blob_bdev = (struct blob_bdev *)dev; 386421fb110SMike Gerdts int32_t refs; 387421fb110SMike Gerdts 388421fb110SMike Gerdts spdk_spin_lock(&blob_bdev->lock); 389421fb110SMike Gerdts 390421fb110SMike Gerdts assert(blob_bdev->refs > 0); 391421fb110SMike Gerdts blob_bdev->refs--; 392421fb110SMike Gerdts refs = blob_bdev->refs; 393421fb110SMike Gerdts 394421fb110SMike Gerdts spdk_spin_unlock(&blob_bdev->lock); 395421fb110SMike Gerdts 3967392cdefSSeth Howell spdk_put_io_channel(channel); 397421fb110SMike Gerdts 398421fb110SMike Gerdts /* 399421fb110SMike Gerdts * If the value of blob_bdev->refs taken while holding blob_bdev->refs is zero, the blob and 400421fb110SMike Gerdts * this channel have been destroyed. This means that dev->destroy() has been called and it 401421fb110SMike Gerdts * would be an error (akin to use after free) if dev is dereferenced after destroying it. 402421fb110SMike Gerdts * Thus, there should be no race with bdev_blob_create_channel(). 403421fb110SMike Gerdts * 404421fb110SMike Gerdts * Because the value of blob_bdev->refs was taken while holding the lock here and the same 405421fb110SMike Gerdts * is done in bdev_blob_destroy(), there is no race with bdev_blob_destroy(). 406421fb110SMike Gerdts */ 407421fb110SMike Gerdts if (refs == 0) { 408421fb110SMike Gerdts bdev_blob_free(blob_bdev); 409421fb110SMike Gerdts } 4107392cdefSSeth Howell } 4117392cdefSSeth Howell 4127392cdefSSeth Howell static void 4137392cdefSSeth Howell bdev_blob_destroy(struct spdk_bs_dev *bs_dev) 4147392cdefSSeth Howell { 415421fb110SMike Gerdts struct blob_bdev *blob_bdev = (struct blob_bdev *)bs_dev; 416421fb110SMike Gerdts struct spdk_bdev_desc *desc; 417421fb110SMike Gerdts int32_t refs; 418421fb110SMike Gerdts 419421fb110SMike Gerdts spdk_spin_lock(&blob_bdev->lock); 420421fb110SMike Gerdts 421421fb110SMike Gerdts desc = blob_bdev->desc; 422421fb110SMike Gerdts blob_bdev->desc = NULL; 423421fb110SMike Gerdts blob_bdev->refs--; 424421fb110SMike Gerdts refs = blob_bdev->refs; 425421fb110SMike Gerdts 426421fb110SMike Gerdts spdk_spin_unlock(&blob_bdev->lock); 4277392cdefSSeth Howell 4287392cdefSSeth Howell spdk_bdev_close(desc); 429421fb110SMike Gerdts 430421fb110SMike Gerdts /* 431421fb110SMike Gerdts * If the value of blob_bdev->refs taken while holding blob_bdev->refs is zero, 432421fb110SMike Gerdts * bs_dev->destroy() has been called and all the channels have been destroyed. It would be 433421fb110SMike Gerdts * an error (akin to use after free) if bs_dev is dereferenced after destroying it. Thus, 434421fb110SMike Gerdts * there should be no race with bdev_blob_create_channel(). 435421fb110SMike Gerdts * 436421fb110SMike Gerdts * Because the value of blob_bdev->refs was taken while holding the lock here and the same 437421fb110SMike Gerdts * is done in bdev_blob_destroy_channel(), there is no race with 438421fb110SMike Gerdts * bdev_blob_destroy_channel(). 439421fb110SMike Gerdts */ 440421fb110SMike Gerdts if (refs == 0) { 441421fb110SMike Gerdts bdev_blob_free(blob_bdev); 442421fb110SMike Gerdts } 4437392cdefSSeth Howell } 4447392cdefSSeth Howell 4453ea2bffbSShuhei Matsumoto static struct spdk_bdev * 4463ea2bffbSShuhei Matsumoto bdev_blob_get_base_bdev(struct spdk_bs_dev *bs_dev) 4473ea2bffbSShuhei Matsumoto { 4483ea2bffbSShuhei Matsumoto return __get_bdev(bs_dev); 4493ea2bffbSShuhei Matsumoto } 4503ea2bffbSShuhei Matsumoto 4512e7a7fe5SEvgeniy Kochetov static bool 4522e7a7fe5SEvgeniy Kochetov bdev_blob_is_zeroes(struct spdk_bs_dev *dev, uint64_t lba, uint64_t lba_count) 4532e7a7fe5SEvgeniy Kochetov { 4542e7a7fe5SEvgeniy Kochetov return false; 4552e7a7fe5SEvgeniy Kochetov } 4562e7a7fe5SEvgeniy Kochetov 4579e843fdbSEvgeniy Kochetov static bool 45800311abcSDiwakar Sharma bdev_blob_is_range_valid(struct spdk_bs_dev *dev, uint64_t lba, uint64_t lba_count) 45900311abcSDiwakar Sharma { 46000311abcSDiwakar Sharma struct spdk_bdev *bdev = __get_bdev(dev); 46100311abcSDiwakar Sharma 46200311abcSDiwakar Sharma /* The lba requested should be within the bounds of this bs_dev. */ 46300311abcSDiwakar Sharma if (lba >= spdk_bdev_get_num_blocks(bdev)) { 46400311abcSDiwakar Sharma return false; 46500311abcSDiwakar Sharma } else if (lba + lba_count > spdk_bdev_get_num_blocks(bdev)) { 46600311abcSDiwakar Sharma /* bdevs used for esnaps must currently be an exact multiple of the 46700311abcSDiwakar Sharma * blobstore cluster size (see spdk_lvol_create_esnap_clone()), but if that 46800311abcSDiwakar Sharma * ever changes this code here needs to be updated to account for it. */ 46900311abcSDiwakar Sharma SPDK_ERRLOG("Entire range must be within the bs_dev bounds for CoW.\n" 47000311abcSDiwakar Sharma "lba(lba_count): %lu(%lu), num_blks: %lu\n", lba, lba_count, spdk_bdev_get_num_blocks(bdev)); 47100311abcSDiwakar Sharma assert(false); 47200311abcSDiwakar Sharma return false; 47300311abcSDiwakar Sharma } 47400311abcSDiwakar Sharma 47500311abcSDiwakar Sharma return true; 47600311abcSDiwakar Sharma } 47700311abcSDiwakar Sharma 47800311abcSDiwakar Sharma static bool 4799e843fdbSEvgeniy Kochetov bdev_blob_translate_lba(struct spdk_bs_dev *dev, uint64_t lba, uint64_t *base_lba) 4809e843fdbSEvgeniy Kochetov { 4819e843fdbSEvgeniy Kochetov *base_lba = lba; 4829e843fdbSEvgeniy Kochetov return true; 4839e843fdbSEvgeniy Kochetov } 4849e843fdbSEvgeniy Kochetov 485778e21aaSShuhei Matsumoto static void 486778e21aaSShuhei Matsumoto blob_bdev_init(struct blob_bdev *b, struct spdk_bdev_desc *desc) 487778e21aaSShuhei Matsumoto { 488778e21aaSShuhei Matsumoto struct spdk_bdev *bdev; 489778e21aaSShuhei Matsumoto 490778e21aaSShuhei Matsumoto bdev = spdk_bdev_desc_get_bdev(desc); 491778e21aaSShuhei Matsumoto assert(bdev != NULL); 492778e21aaSShuhei Matsumoto 493778e21aaSShuhei Matsumoto b->bdev = bdev; 494778e21aaSShuhei Matsumoto b->desc = desc; 495778e21aaSShuhei Matsumoto b->bs_dev.blockcnt = spdk_bdev_get_num_blocks(bdev); 496778e21aaSShuhei Matsumoto b->bs_dev.blocklen = spdk_bdev_get_block_size(bdev); 497*2dc4a231SAtul Malakar b->bs_dev.phys_blocklen = spdk_bdev_get_physical_block_size(bdev); 498778e21aaSShuhei Matsumoto b->bs_dev.create_channel = bdev_blob_create_channel; 499778e21aaSShuhei Matsumoto b->bs_dev.destroy_channel = bdev_blob_destroy_channel; 500778e21aaSShuhei Matsumoto b->bs_dev.destroy = bdev_blob_destroy; 501778e21aaSShuhei Matsumoto b->bs_dev.read = bdev_blob_read; 502778e21aaSShuhei Matsumoto b->bs_dev.write = bdev_blob_write; 503778e21aaSShuhei Matsumoto b->bs_dev.readv = bdev_blob_readv; 504778e21aaSShuhei Matsumoto b->bs_dev.writev = bdev_blob_writev; 505ba8f1a9eSAlexey Marchuk b->bs_dev.readv_ext = bdev_blob_readv_ext; 506ba8f1a9eSAlexey Marchuk b->bs_dev.writev_ext = bdev_blob_writev_ext; 507778e21aaSShuhei Matsumoto b->bs_dev.write_zeroes = bdev_blob_write_zeroes; 508778e21aaSShuhei Matsumoto b->bs_dev.unmap = bdev_blob_unmap; 509b7bfa504SEvgeniy Kochetov if (spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_COPY)) { 510b7bfa504SEvgeniy Kochetov b->bs_dev.copy = bdev_blob_copy; 511b7bfa504SEvgeniy Kochetov } 5123ea2bffbSShuhei Matsumoto b->bs_dev.get_base_bdev = bdev_blob_get_base_bdev; 5132e7a7fe5SEvgeniy Kochetov b->bs_dev.is_zeroes = bdev_blob_is_zeroes; 51400311abcSDiwakar Sharma b->bs_dev.is_range_valid = bdev_blob_is_range_valid; 5159e843fdbSEvgeniy Kochetov b->bs_dev.translate_lba = bdev_blob_translate_lba; 516778e21aaSShuhei Matsumoto } 517778e21aaSShuhei Matsumoto 51891c0a9d2STomasz Zawadzki void 51991c0a9d2STomasz Zawadzki spdk_bdev_update_bs_blockcnt(struct spdk_bs_dev *bs_dev) 52091c0a9d2STomasz Zawadzki { 52191c0a9d2STomasz Zawadzki struct blob_bdev *blob_bdev = (struct blob_bdev *)bs_dev; 52291c0a9d2STomasz Zawadzki 52391c0a9d2STomasz Zawadzki assert(bs_dev->blocklen == spdk_bdev_get_block_size(blob_bdev->bdev)); 52491c0a9d2STomasz Zawadzki bs_dev->blockcnt = spdk_bdev_get_num_blocks(blob_bdev->bdev); 52591c0a9d2STomasz Zawadzki } 52691c0a9d2STomasz Zawadzki 5276a72c19eSShuhei Matsumoto int 528bd5a7847SMike Gerdts spdk_bdev_create_bs_dev(const char *bdev_name, bool write, 529bd5a7847SMike Gerdts struct spdk_bdev_bs_dev_opts *opts, size_t opts_size, 530bd5a7847SMike Gerdts spdk_bdev_event_cb_t event_cb, void *event_ctx, 531bd5a7847SMike Gerdts struct spdk_bs_dev **bs_dev) 5326a72c19eSShuhei Matsumoto { 5336a72c19eSShuhei Matsumoto struct blob_bdev *b; 5346a72c19eSShuhei Matsumoto struct spdk_bdev_desc *desc; 5356a72c19eSShuhei Matsumoto int rc; 5366a72c19eSShuhei Matsumoto 537421fb110SMike Gerdts assert(spdk_get_thread() != NULL); 538421fb110SMike Gerdts 539bd5a7847SMike Gerdts if (opts != NULL && opts_size != sizeof(*opts)) { 540bd5a7847SMike Gerdts SPDK_ERRLOG("bdev name '%s': unsupported options\n", bdev_name); 541bd5a7847SMike Gerdts return -EINVAL; 542bd5a7847SMike Gerdts } 543bd5a7847SMike Gerdts 5446a72c19eSShuhei Matsumoto b = calloc(1, sizeof(*b)); 5456a72c19eSShuhei Matsumoto 5466a72c19eSShuhei Matsumoto if (b == NULL) { 5476a72c19eSShuhei Matsumoto SPDK_ERRLOG("could not allocate blob_bdev\n"); 5486a72c19eSShuhei Matsumoto return -ENOMEM; 5496a72c19eSShuhei Matsumoto } 5506a72c19eSShuhei Matsumoto 551bd5a7847SMike Gerdts rc = spdk_bdev_open_ext(bdev_name, write, event_cb, event_ctx, &desc); 5526a72c19eSShuhei Matsumoto if (rc != 0) { 5536a72c19eSShuhei Matsumoto free(b); 5546a72c19eSShuhei Matsumoto return rc; 5556a72c19eSShuhei Matsumoto } 5566a72c19eSShuhei Matsumoto 5576a72c19eSShuhei Matsumoto blob_bdev_init(b, desc); 5586a72c19eSShuhei Matsumoto 559bd5a7847SMike Gerdts *bs_dev = &b->bs_dev; 560ab2eff07SMike Gerdts b->write = write; 561421fb110SMike Gerdts b->refs = 1; 562421fb110SMike Gerdts spdk_spin_init(&b->lock); 5636a72c19eSShuhei Matsumoto 5646a72c19eSShuhei Matsumoto return 0; 5656a72c19eSShuhei Matsumoto } 566bd5a7847SMike Gerdts 567bd5a7847SMike Gerdts int 568bd5a7847SMike Gerdts spdk_bdev_create_bs_dev_ext(const char *bdev_name, spdk_bdev_event_cb_t event_cb, 569bd5a7847SMike Gerdts void *event_ctx, struct spdk_bs_dev **bs_dev) 570bd5a7847SMike Gerdts { 571bd5a7847SMike Gerdts return spdk_bdev_create_bs_dev(bdev_name, true, NULL, 0, event_cb, event_ctx, bs_dev); 572bd5a7847SMike Gerdts } 573