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