xref: /spdk/module/blob/bdev/blob_bdev.c (revision 2dc4a231ac65d10dd2e1a96684094bef1b7ebb95)
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