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