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