xref: /spdk/module/bdev/split/vbdev_split.c (revision a6dbe3721eb3b5990707fc3e378c95e505dd8ab5)
1  /*   SPDX-License-Identifier: BSD-3-Clause
2   *   Copyright (C) 2016 Intel Corporation.
3   *   All rights reserved.
4   */
5  
6  /*
7   * This is a simple example of a virtual block device that takes a single
8   * bdev and slices it into multiple smaller bdevs.
9   */
10  
11  #include "vbdev_split.h"
12  
13  #include "spdk/rpc.h"
14  #include "spdk/endian.h"
15  #include "spdk/string.h"
16  #include "spdk/thread.h"
17  #include "spdk/util.h"
18  
19  #include "spdk/bdev_module.h"
20  #include "spdk/log.h"
21  
22  struct spdk_vbdev_split_config {
23  	char *base_bdev;
24  	unsigned split_count;
25  	uint64_t split_size_mb;
26  
27  	SPDK_BDEV_PART_TAILQ splits;
28  	struct spdk_bdev_part_base *split_base;
29  
30  	TAILQ_ENTRY(spdk_vbdev_split_config) tailq;
31  };
32  
33  static TAILQ_HEAD(, spdk_vbdev_split_config) g_split_config = TAILQ_HEAD_INITIALIZER(
34  			g_split_config);
35  
36  struct vbdev_split_channel {
37  	struct spdk_bdev_part_channel	part_ch;
38  };
39  
40  struct vbdev_split_bdev_io {
41  	struct spdk_io_channel *ch;
42  	struct spdk_bdev_io *bdev_io;
43  
44  	/* for bdev_io_wait */
45  	struct spdk_bdev_io_wait_entry bdev_io_wait;
46  };
47  
48  static void vbdev_split_del_config(struct spdk_vbdev_split_config *cfg);
49  
50  static int vbdev_split_init(void);
51  static void vbdev_split_fini(void);
52  static void vbdev_split_examine(struct spdk_bdev *bdev);
53  static int vbdev_split_config_json(struct spdk_json_write_ctx *w);
54  static int vbdev_split_get_ctx_size(void);
55  
56  static void _vbdev_split_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io);
57  
58  static struct spdk_bdev_module split_if = {
59  	.name = "split",
60  	.module_init = vbdev_split_init,
61  	.module_fini = vbdev_split_fini,
62  	.get_ctx_size = vbdev_split_get_ctx_size,
63  	.examine_config = vbdev_split_examine,
64  	.config_json = vbdev_split_config_json,
65  };
66  
67  SPDK_BDEV_MODULE_REGISTER(split, &split_if)
68  
69  static void
vbdev_split_base_free(void * ctx)70  vbdev_split_base_free(void *ctx)
71  {
72  	struct spdk_vbdev_split_config *cfg = ctx;
73  
74  	vbdev_split_del_config(cfg);
75  }
76  
77  static int
_vbdev_split_destruct(void * ctx)78  _vbdev_split_destruct(void *ctx)
79  {
80  	struct spdk_bdev_part *part = ctx;
81  
82  	return spdk_bdev_part_free(part);
83  }
84  
85  static void
vbdev_split_base_bdev_hotremove_cb(void * _part_base)86  vbdev_split_base_bdev_hotremove_cb(void *_part_base)
87  {
88  	struct spdk_bdev_part_base *part_base = _part_base;
89  	struct spdk_vbdev_split_config *cfg = spdk_bdev_part_base_get_ctx(part_base);
90  
91  	spdk_bdev_part_base_hotremove(part_base, &cfg->splits);
92  }
93  
94  static void
vbdev_split_resubmit_io(void * arg)95  vbdev_split_resubmit_io(void *arg)
96  {
97  	struct vbdev_split_bdev_io *split_io = (struct vbdev_split_bdev_io *)arg;
98  
99  	_vbdev_split_submit_request(split_io->ch, split_io->bdev_io);
100  }
101  
102  static void
vbdev_split_queue_io(struct vbdev_split_bdev_io * split_io)103  vbdev_split_queue_io(struct vbdev_split_bdev_io *split_io)
104  {
105  	struct vbdev_split_channel *ch = spdk_io_channel_get_ctx(split_io->ch);
106  	int rc;
107  
108  	split_io->bdev_io_wait.bdev = split_io->bdev_io->bdev;
109  	split_io->bdev_io_wait.cb_fn = vbdev_split_resubmit_io;
110  	split_io->bdev_io_wait.cb_arg = split_io;
111  
112  	rc = spdk_bdev_queue_io_wait(split_io->bdev_io->bdev,
113  				     ch->part_ch.base_ch, &split_io->bdev_io_wait);
114  	if (rc != 0) {
115  		SPDK_ERRLOG("Queue io failed in vbdev_split_queue_io, rc=%d\n", rc);
116  		spdk_bdev_io_complete(split_io->bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
117  	}
118  }
119  
120  static void
_vbdev_split_submit_request(struct spdk_io_channel * _ch,struct spdk_bdev_io * bdev_io)121  _vbdev_split_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io)
122  {
123  	struct vbdev_split_channel *ch = spdk_io_channel_get_ctx(_ch);
124  	struct vbdev_split_bdev_io *io_ctx = (struct vbdev_split_bdev_io *)bdev_io->driver_ctx;
125  	int rc;
126  
127  	rc = spdk_bdev_part_submit_request(&ch->part_ch, bdev_io);
128  	if (rc) {
129  		if (rc == -ENOMEM) {
130  			SPDK_DEBUGLOG(vbdev_split, "split: no memory, queue io.\n");
131  			io_ctx->ch = _ch;
132  			io_ctx->bdev_io = bdev_io;
133  			vbdev_split_queue_io(io_ctx);
134  		} else {
135  			SPDK_ERRLOG("split: error on io submission, rc=%d.\n", rc);
136  			spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
137  		}
138  	}
139  }
140  
141  static void
vbdev_split_get_buf_cb(struct spdk_io_channel * ch,struct spdk_bdev_io * bdev_io,bool success)142  vbdev_split_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io, bool success)
143  {
144  	if (!success) {
145  		spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
146  		return;
147  	}
148  
149  	_vbdev_split_submit_request(ch, bdev_io);
150  }
151  
152  static void
vbdev_split_submit_request(struct spdk_io_channel * _ch,struct spdk_bdev_io * bdev_io)153  vbdev_split_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io)
154  {
155  	switch (bdev_io->type) {
156  	case SPDK_BDEV_IO_TYPE_READ:
157  		spdk_bdev_io_get_buf(bdev_io, vbdev_split_get_buf_cb,
158  				     bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
159  		break;
160  	default:
161  		_vbdev_split_submit_request(_ch, bdev_io);
162  		break;
163  	}
164  }
165  
166  static int
vbdev_split_dump_info_json(void * ctx,struct spdk_json_write_ctx * w)167  vbdev_split_dump_info_json(void *ctx, struct spdk_json_write_ctx *w)
168  {
169  	struct spdk_bdev_part *part = ctx;
170  	struct spdk_bdev *split_base_bdev = spdk_bdev_part_get_base_bdev(part);
171  	uint64_t offset_blocks = spdk_bdev_part_get_offset_blocks(part);
172  
173  	spdk_json_write_named_object_begin(w, "split");
174  
175  	spdk_json_write_named_string(w, "base_bdev", spdk_bdev_get_name(split_base_bdev));
176  	spdk_json_write_named_uint64(w, "offset_blocks", offset_blocks);
177  
178  	spdk_json_write_object_end(w);
179  
180  	return 0;
181  }
182  
183  static void
vbdev_split_write_config_json(struct spdk_bdev * bdev,struct spdk_json_write_ctx * w)184  vbdev_split_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w)
185  {
186  	/* No config per bdev needed */
187  }
188  
189  static struct spdk_bdev_fn_table vbdev_split_fn_table = {
190  	.destruct		= _vbdev_split_destruct,
191  	.submit_request		= vbdev_split_submit_request,
192  	.dump_info_json		= vbdev_split_dump_info_json,
193  	.write_config_json	= vbdev_split_write_config_json
194  };
195  
196  static int
vbdev_split_create(struct spdk_vbdev_split_config * cfg)197  vbdev_split_create(struct spdk_vbdev_split_config *cfg)
198  {
199  	uint64_t split_size_blocks, offset_blocks;
200  	uint64_t split_count, max_split_count;
201  	uint64_t mb = 1024 * 1024;
202  	uint64_t i;
203  	int rc;
204  	char *name;
205  	struct spdk_bdev *base_bdev;
206  	struct bdev_part_tailq *split_base_tailq;
207  
208  	assert(cfg->split_count > 0);
209  
210  	TAILQ_INIT(&cfg->splits);
211  	rc = spdk_bdev_part_base_construct_ext(cfg->base_bdev,
212  					       vbdev_split_base_bdev_hotremove_cb,
213  					       &split_if, &vbdev_split_fn_table,
214  					       &cfg->splits, vbdev_split_base_free, cfg,
215  					       sizeof(struct vbdev_split_channel),
216  					       NULL, NULL, &cfg->split_base);
217  	if (rc != 0) {
218  		if (rc != -ENODEV) {
219  			SPDK_ERRLOG("Cannot construct bdev part base\n");
220  		}
221  		return rc;
222  	}
223  
224  	base_bdev = spdk_bdev_part_base_get_bdev(cfg->split_base);
225  
226  	if (cfg->split_size_mb) {
227  		if (((cfg->split_size_mb * mb) % base_bdev->blocklen) != 0) {
228  			SPDK_ERRLOG("Split size %" PRIu64 " MB is not possible with block size "
229  				    "%" PRIu32 "\n",
230  				    cfg->split_size_mb, base_bdev->blocklen);
231  			rc = -EINVAL;
232  			goto err;
233  		}
234  		split_size_blocks = (cfg->split_size_mb * mb) / base_bdev->blocklen;
235  		SPDK_DEBUGLOG(vbdev_split, "Split size %" PRIu64 " MB specified by user\n",
236  			      cfg->split_size_mb);
237  	} else {
238  		split_size_blocks = base_bdev->blockcnt / cfg->split_count;
239  		SPDK_DEBUGLOG(vbdev_split, "Split size not specified by user\n");
240  	}
241  
242  	max_split_count = base_bdev->blockcnt / split_size_blocks;
243  	split_count = cfg->split_count;
244  	if (split_count > max_split_count) {
245  		SPDK_WARNLOG("Split count %" PRIu64 " is greater than maximum possible split count "
246  			     "%" PRIu64 " - clamping\n", split_count, max_split_count);
247  		split_count = max_split_count;
248  	}
249  
250  	SPDK_DEBUGLOG(vbdev_split, "base_bdev: %s split_count: %" PRIu64
251  		      " split_size_blocks: %" PRIu64 "\n",
252  		      cfg->base_bdev, split_count, split_size_blocks);
253  
254  	offset_blocks = 0;
255  	for (i = 0; i < split_count; i++) {
256  		struct spdk_bdev_part *d;
257  
258  		d = calloc(1, sizeof(*d));
259  		if (d == NULL) {
260  			SPDK_ERRLOG("could not allocate bdev part\n");
261  			rc = -ENOMEM;
262  			goto err;
263  		}
264  
265  		name = spdk_sprintf_alloc("%sp%" PRIu64, cfg->base_bdev, i);
266  		if (!name) {
267  			SPDK_ERRLOG("could not allocate name\n");
268  			free(d);
269  			rc = -ENOMEM;
270  			goto err;
271  		}
272  
273  		rc = spdk_bdev_part_construct(d, cfg->split_base, name, offset_blocks, split_size_blocks,
274  					      "Split Disk");
275  		free(name);
276  		if (rc) {
277  			SPDK_ERRLOG("could not construct bdev part\n");
278  			/* spdk_bdev_part_construct will free name if it fails */
279  			free(d);
280  			rc = -ENOMEM;
281  			goto err;
282  		}
283  
284  		offset_blocks += split_size_blocks;
285  	}
286  
287  	return 0;
288  err:
289  	split_base_tailq = spdk_bdev_part_base_get_tailq(cfg->split_base);
290  	spdk_bdev_part_base_hotremove(cfg->split_base, split_base_tailq);
291  	spdk_bdev_part_base_free(cfg->split_base);
292  	return rc;
293  }
294  
295  static void
vbdev_split_del_config(struct spdk_vbdev_split_config * cfg)296  vbdev_split_del_config(struct spdk_vbdev_split_config *cfg)
297  {
298  	TAILQ_REMOVE(&g_split_config, cfg, tailq);
299  	free(cfg->base_bdev);
300  	free(cfg);
301  }
302  
303  static void
vbdev_split_destruct_config(struct spdk_vbdev_split_config * cfg)304  vbdev_split_destruct_config(struct spdk_vbdev_split_config *cfg)
305  {
306  	struct bdev_part_tailq *split_base_tailq;
307  
308  	if (cfg->split_base != NULL) {
309  		split_base_tailq = spdk_bdev_part_base_get_tailq(cfg->split_base);
310  		spdk_bdev_part_base_hotremove(cfg->split_base, split_base_tailq);
311  	} else {
312  		vbdev_split_del_config(cfg);
313  	}
314  }
315  
316  static void
vbdev_split_clear_config(void)317  vbdev_split_clear_config(void)
318  {
319  	struct spdk_vbdev_split_config *cfg, *tmp_cfg;
320  
321  	TAILQ_FOREACH_SAFE(cfg, &g_split_config, tailq, tmp_cfg) {
322  		vbdev_split_destruct_config(cfg);
323  	}
324  }
325  
326  static struct spdk_vbdev_split_config *
vbdev_split_config_find_by_base_name(const char * base_bdev_name)327  vbdev_split_config_find_by_base_name(const char *base_bdev_name)
328  {
329  	struct spdk_vbdev_split_config *cfg;
330  
331  	TAILQ_FOREACH(cfg, &g_split_config, tailq) {
332  		if (strcmp(cfg->base_bdev, base_bdev_name) == 0) {
333  			return cfg;
334  		}
335  	}
336  
337  	return NULL;
338  }
339  
340  static int
vbdev_split_add_config(const char * base_bdev_name,unsigned split_count,uint64_t split_size,struct spdk_vbdev_split_config ** config)341  vbdev_split_add_config(const char *base_bdev_name, unsigned split_count, uint64_t split_size,
342  		       struct spdk_vbdev_split_config **config)
343  {
344  	struct spdk_vbdev_split_config *cfg;
345  	assert(base_bdev_name);
346  
347  	if (base_bdev_name == NULL) {
348  		SPDK_ERRLOG("Split bdev config: no base bdev provided.");
349  		return -EINVAL;
350  	}
351  
352  	if (split_count == 0) {
353  		SPDK_ERRLOG("Split bdev config: split_count can't be 0.");
354  		return -EINVAL;
355  	}
356  
357  	/* Check if we already have 'base_bdev_name' registered in config */
358  	cfg = vbdev_split_config_find_by_base_name(base_bdev_name);
359  	if (cfg) {
360  		SPDK_ERRLOG("Split bdev config for base bdev '%s' already exist.", base_bdev_name);
361  		return -EEXIST;
362  	}
363  
364  	cfg = calloc(1, sizeof(*cfg));
365  	if (!cfg) {
366  		SPDK_ERRLOG("calloc(): Out of memory");
367  		return -ENOMEM;
368  	}
369  
370  	cfg->base_bdev = strdup(base_bdev_name);
371  	if (!cfg->base_bdev) {
372  		SPDK_ERRLOG("strdup(): Out of memory");
373  		free(cfg);
374  		return -ENOMEM;
375  	}
376  
377  	cfg->split_count = split_count;
378  	cfg->split_size_mb = split_size;
379  	TAILQ_INSERT_TAIL(&g_split_config, cfg, tailq);
380  	if (config) {
381  		*config = cfg;
382  	}
383  
384  	return 0;
385  }
386  
387  static int
vbdev_split_init(void)388  vbdev_split_init(void)
389  {
390  	return 0;
391  }
392  
393  static void
vbdev_split_fini(void)394  vbdev_split_fini(void)
395  {
396  	vbdev_split_clear_config();
397  }
398  
399  static void
vbdev_split_examine(struct spdk_bdev * bdev)400  vbdev_split_examine(struct spdk_bdev *bdev)
401  {
402  	struct spdk_vbdev_split_config *cfg = vbdev_split_config_find_by_base_name(bdev->name);
403  
404  	if (cfg != NULL) {
405  		assert(cfg->split_base == NULL);
406  
407  		if (vbdev_split_create(cfg)) {
408  			SPDK_ERRLOG("could not split bdev %s\n", bdev->name);
409  		}
410  	}
411  	spdk_bdev_module_examine_done(&split_if);
412  }
413  
414  static int
vbdev_split_config_json(struct spdk_json_write_ctx * w)415  vbdev_split_config_json(struct spdk_json_write_ctx *w)
416  {
417  	struct spdk_vbdev_split_config *cfg;
418  
419  	TAILQ_FOREACH(cfg, &g_split_config, tailq) {
420  		spdk_json_write_object_begin(w);
421  
422  		spdk_json_write_named_string(w, "method", "bdev_split_create");
423  
424  		spdk_json_write_named_object_begin(w, "params");
425  		spdk_json_write_named_string(w, "base_bdev", cfg->base_bdev);
426  		spdk_json_write_named_uint32(w, "split_count", cfg->split_count);
427  		spdk_json_write_named_uint64(w, "split_size_mb", cfg->split_size_mb);
428  		spdk_json_write_object_end(w);
429  
430  		spdk_json_write_object_end(w);
431  	}
432  
433  	return 0;
434  }
435  
436  int
create_vbdev_split(const char * base_bdev_name,unsigned split_count,uint64_t split_size_mb)437  create_vbdev_split(const char *base_bdev_name, unsigned split_count, uint64_t split_size_mb)
438  {
439  	int rc;
440  	struct spdk_vbdev_split_config *cfg;
441  
442  	rc = vbdev_split_add_config(base_bdev_name, split_count, split_size_mb, &cfg);
443  	if (rc) {
444  		return rc;
445  	}
446  
447  	rc = vbdev_split_create(cfg);
448  	if (rc == -ENODEV) {
449  		/* It is ok if base bdev does not exist yet. */
450  		rc = 0;
451  	}
452  
453  	return rc;
454  }
455  
456  int
vbdev_split_destruct(const char * base_bdev_name)457  vbdev_split_destruct(const char *base_bdev_name)
458  {
459  	struct spdk_vbdev_split_config *cfg = vbdev_split_config_find_by_base_name(base_bdev_name);
460  
461  	if (!cfg) {
462  		SPDK_ERRLOG("Split configuration for '%s' not found\n", base_bdev_name);
463  		return -ENOENT;
464  	}
465  
466  	vbdev_split_destruct_config(cfg);
467  	return 0;
468  }
469  
470  struct spdk_bdev_part_base *
vbdev_split_get_part_base(struct spdk_bdev * bdev)471  vbdev_split_get_part_base(struct spdk_bdev *bdev)
472  {
473  	struct spdk_vbdev_split_config *cfg;
474  
475  	cfg = vbdev_split_config_find_by_base_name(spdk_bdev_get_name(bdev));
476  
477  	if (cfg == NULL) {
478  		return NULL;
479  	}
480  
481  	return cfg->split_base;
482  }
483  
484  /*
485   * During init we'll be asked how much memory we'd like passed to us
486   * in bev_io structures as context. Here's where we specify how
487   * much context we want per IO.
488   */
489  static int
vbdev_split_get_ctx_size(void)490  vbdev_split_get_ctx_size(void)
491  {
492  	return sizeof(struct vbdev_split_bdev_io);
493  }
494  
495  SPDK_LOG_REGISTER_COMPONENT(vbdev_split)
496