Branch data Line data Source code
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 : 2146 : SPDK_BDEV_MODULE_REGISTER(split, &split_if)
68 : :
69 : : static void
70 : 121 : vbdev_split_base_free(void *ctx)
71 : : {
72 : 121 : struct spdk_vbdev_split_config *cfg = ctx;
73 : :
74 : 121 : vbdev_split_del_config(cfg);
75 : 121 : }
76 : :
77 : : static int
78 : 492 : _vbdev_split_destruct(void *ctx)
79 : : {
80 : 492 : struct spdk_bdev_part *part = ctx;
81 : :
82 : 492 : return spdk_bdev_part_free(part);
83 : : }
84 : :
85 : : static void
86 : 1 : vbdev_split_base_bdev_hotremove_cb(void *_part_base)
87 : : {
88 : 1 : struct spdk_bdev_part_base *part_base = _part_base;
89 : 1 : struct spdk_vbdev_split_config *cfg = spdk_bdev_part_base_get_ctx(part_base);
90 : :
91 : 1 : spdk_bdev_part_base_hotremove(part_base, &cfg->splits);
92 : 1 : }
93 : :
94 : : static void
95 : 0 : vbdev_split_resubmit_io(void *arg)
96 : : {
97 : 0 : struct vbdev_split_bdev_io *split_io = (struct vbdev_split_bdev_io *)arg;
98 : :
99 : 0 : _vbdev_split_submit_request(split_io->ch, split_io->bdev_io);
100 : 0 : }
101 : :
102 : : static void
103 : 0 : vbdev_split_queue_io(struct vbdev_split_bdev_io *split_io)
104 : : {
105 : 0 : struct vbdev_split_channel *ch = spdk_io_channel_get_ctx(split_io->ch);
106 : : int rc;
107 : :
108 : 0 : split_io->bdev_io_wait.bdev = split_io->bdev_io->bdev;
109 : 0 : split_io->bdev_io_wait.cb_fn = vbdev_split_resubmit_io;
110 : 0 : split_io->bdev_io_wait.cb_arg = split_io;
111 : :
112 : 0 : rc = spdk_bdev_queue_io_wait(split_io->bdev_io->bdev,
113 : : ch->part_ch.base_ch, &split_io->bdev_io_wait);
114 [ # # ]: 0 : if (rc != 0) {
115 : 0 : SPDK_ERRLOG("Queue io failed in vbdev_split_queue_io, rc=%d\n", rc);
116 : 0 : spdk_bdev_io_complete(split_io->bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
117 : : }
118 : 0 : }
119 : :
120 : : static void
121 : 20127279 : _vbdev_split_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io)
122 : : {
123 : 20127279 : struct vbdev_split_channel *ch = spdk_io_channel_get_ctx(_ch);
124 : 20127279 : struct vbdev_split_bdev_io *io_ctx = (struct vbdev_split_bdev_io *)bdev_io->driver_ctx;
125 : : int rc;
126 : :
127 : 20127279 : rc = spdk_bdev_part_submit_request(&ch->part_ch, bdev_io);
128 [ - + ]: 20127279 : if (rc) {
129 [ # # ]: 0 : if (rc == -ENOMEM) {
130 [ # # # # ]: 0 : SPDK_DEBUGLOG(vbdev_split, "split: no memory, queue io.\n");
131 : 0 : io_ctx->ch = _ch;
132 : 0 : io_ctx->bdev_io = bdev_io;
133 : 0 : vbdev_split_queue_io(io_ctx);
134 : : } else {
135 : 0 : SPDK_ERRLOG("split: error on io submission, rc=%d.\n", rc);
136 : 0 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
137 : : }
138 : : }
139 : 20127279 : }
140 : :
141 : : static void
142 : 4119557 : vbdev_split_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io, bool success)
143 : : {
144 [ - + ]: 4119557 : if (!success) {
145 : 0 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
146 : 0 : return;
147 : : }
148 : :
149 : 4119557 : _vbdev_split_submit_request(ch, bdev_io);
150 : : }
151 : :
152 : : static void
153 : 20127279 : vbdev_split_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io)
154 : : {
155 [ + + ]: 20127279 : switch (bdev_io->type) {
156 : 4119557 : case SPDK_BDEV_IO_TYPE_READ:
157 : 4119557 : spdk_bdev_io_get_buf(bdev_io, vbdev_split_get_buf_cb,
158 : 4119557 : bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
159 : 4119557 : break;
160 : 16007716 : default:
161 : 16007716 : _vbdev_split_submit_request(_ch, bdev_io);
162 : 16007716 : break;
163 : : }
164 : 20127279 : }
165 : :
166 : : static int
167 : 2464 : vbdev_split_dump_info_json(void *ctx, struct spdk_json_write_ctx *w)
168 : : {
169 : 2464 : struct spdk_bdev_part *part = ctx;
170 : 2464 : struct spdk_bdev *split_base_bdev = spdk_bdev_part_get_base_bdev(part);
171 : 2464 : uint64_t offset_blocks = spdk_bdev_part_get_offset_blocks(part);
172 : :
173 : 2464 : spdk_json_write_named_object_begin(w, "split");
174 : :
175 : 2464 : spdk_json_write_named_string(w, "base_bdev", spdk_bdev_get_name(split_base_bdev));
176 : 2464 : spdk_json_write_named_uint64(w, "offset_blocks", offset_blocks);
177 : :
178 : 2464 : spdk_json_write_object_end(w);
179 : :
180 : 2464 : return 0;
181 : : }
182 : :
183 : : static void
184 : 204 : vbdev_split_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w)
185 : : {
186 : : /* No config per bdev needed */
187 : 204 : }
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
197 : 226 : 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 : 226 : 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 [ - + ]: 226 : assert(cfg->split_count > 0);
209 : :
210 : 226 : TAILQ_INIT(&cfg->splits);
211 : 409 : 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 : 226 : &cfg->splits, vbdev_split_base_free, cfg,
215 : : sizeof(struct vbdev_split_channel),
216 : : NULL, NULL, &cfg->split_base);
217 [ + + ]: 226 : if (rc != 0) {
218 [ - + ]: 105 : if (rc != -ENODEV) {
219 : 0 : SPDK_ERRLOG("Cannot construct bdev part base\n");
220 : : }
221 : 105 : return rc;
222 : : }
223 : :
224 : 121 : base_bdev = spdk_bdev_part_base_get_bdev(cfg->split_base);
225 : :
226 [ + + ]: 121 : if (cfg->split_size_mb) {
227 [ - + - + ]: 59 : if (((cfg->split_size_mb * mb) % base_bdev->blocklen) != 0) {
228 : 0 : SPDK_ERRLOG("Split size %" PRIu64 " MB is not possible with block size "
229 : : "%" PRIu32 "\n",
230 : : cfg->split_size_mb, base_bdev->blocklen);
231 : 0 : rc = -EINVAL;
232 : 0 : goto err;
233 : : }
234 [ - + ]: 59 : split_size_blocks = (cfg->split_size_mb * mb) / base_bdev->blocklen;
235 [ - + - + ]: 59 : SPDK_DEBUGLOG(vbdev_split, "Split size %" PRIu64 " MB specified by user\n",
236 : : cfg->split_size_mb);
237 : : } else {
238 [ - + ]: 62 : split_size_blocks = base_bdev->blockcnt / cfg->split_count;
239 [ - + - + ]: 62 : SPDK_DEBUGLOG(vbdev_split, "Split size not specified by user\n");
240 : : }
241 : :
242 [ - + ]: 121 : max_split_count = base_bdev->blockcnt / split_size_blocks;
243 : 121 : split_count = cfg->split_count;
244 [ - + ]: 121 : if (split_count > max_split_count) {
245 : 0 : SPDK_WARNLOG("Split count %" PRIu64 " is greater than maximum possible split count "
246 : : "%" PRIu64 " - clamping\n", split_count, max_split_count);
247 : 0 : split_count = max_split_count;
248 : : }
249 : :
250 [ - + - + ]: 121 : 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 : 121 : offset_blocks = 0;
255 [ + + ]: 613 : for (i = 0; i < split_count; i++) {
256 : : struct spdk_bdev_part *d;
257 : :
258 : 492 : d = calloc(1, sizeof(*d));
259 [ - + ]: 492 : if (d == NULL) {
260 : 0 : SPDK_ERRLOG("could not allocate bdev part\n");
261 : 0 : rc = -ENOMEM;
262 : 0 : goto err;
263 : : }
264 : :
265 : 492 : name = spdk_sprintf_alloc("%sp%" PRIu64, cfg->base_bdev, i);
266 [ - + ]: 492 : if (!name) {
267 : 0 : SPDK_ERRLOG("could not allocate name\n");
268 : 0 : free(d);
269 : 0 : rc = -ENOMEM;
270 : 0 : goto err;
271 : : }
272 : :
273 : 492 : rc = spdk_bdev_part_construct(d, cfg->split_base, name, offset_blocks, split_size_blocks,
274 : : "Split Disk");
275 : 492 : free(name);
276 [ - + ]: 492 : if (rc) {
277 : 0 : SPDK_ERRLOG("could not construct bdev part\n");
278 : : /* spdk_bdev_part_construct will free name if it fails */
279 : 0 : free(d);
280 : 0 : rc = -ENOMEM;
281 : 0 : goto err;
282 : : }
283 : :
284 : 492 : offset_blocks += split_size_blocks;
285 : : }
286 : :
287 : 121 : return 0;
288 : 0 : err:
289 : 0 : split_base_tailq = spdk_bdev_part_base_get_tailq(cfg->split_base);
290 : 0 : spdk_bdev_part_base_hotremove(cfg->split_base, split_base_tailq);
291 : 0 : spdk_bdev_part_base_free(cfg->split_base);
292 : 0 : return rc;
293 : : }
294 : :
295 : : static void
296 : 121 : vbdev_split_del_config(struct spdk_vbdev_split_config *cfg)
297 : : {
298 [ + + ]: 121 : TAILQ_REMOVE(&g_split_config, cfg, tailq);
299 : 121 : free(cfg->base_bdev);
300 : 121 : free(cfg);
301 : 121 : }
302 : :
303 : : static void
304 : 13 : vbdev_split_destruct_config(struct spdk_vbdev_split_config *cfg)
305 : : {
306 : : struct bdev_part_tailq *split_base_tailq;
307 : :
308 [ + - ]: 13 : if (cfg->split_base != NULL) {
309 : 13 : split_base_tailq = spdk_bdev_part_base_get_tailq(cfg->split_base);
310 : 13 : spdk_bdev_part_base_hotremove(cfg->split_base, split_base_tailq);
311 : : } else {
312 : 0 : vbdev_split_del_config(cfg);
313 : : }
314 : 13 : }
315 : :
316 : : static void
317 : 1972 : vbdev_split_clear_config(void)
318 : : {
319 : : struct spdk_vbdev_split_config *cfg, *tmp_cfg;
320 : :
321 [ - + ]: 1972 : TAILQ_FOREACH_SAFE(cfg, &g_split_config, tailq, tmp_cfg) {
322 : 0 : vbdev_split_destruct_config(cfg);
323 : : }
324 : 1972 : }
325 : :
326 : : static struct spdk_vbdev_split_config *
327 : 7225 : vbdev_split_config_find_by_base_name(const char *base_bdev_name)
328 : : {
329 : : struct spdk_vbdev_split_config *cfg;
330 : :
331 [ + + ]: 9428 : TAILQ_FOREACH(cfg, &g_split_config, tailq) {
332 [ + + - + : 2337 : if (strcmp(cfg->base_bdev, base_bdev_name) == 0) {
+ + ]
333 : 134 : return cfg;
334 : : }
335 : : }
336 : :
337 : 7091 : return NULL;
338 : : }
339 : :
340 : : static int
341 : 121 : 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 [ - + ]: 121 : assert(base_bdev_name);
346 : :
347 [ - + ]: 121 : if (base_bdev_name == NULL) {
348 : 0 : SPDK_ERRLOG("Split bdev config: no base bdev provided.");
349 : 0 : return -EINVAL;
350 : : }
351 : :
352 [ - + ]: 121 : if (split_count == 0) {
353 : 0 : SPDK_ERRLOG("Split bdev config: split_count can't be 0.");
354 : 0 : return -EINVAL;
355 : : }
356 : :
357 : : /* Check if we already have 'base_bdev_name' registered in config */
358 : 121 : cfg = vbdev_split_config_find_by_base_name(base_bdev_name);
359 [ - + ]: 121 : if (cfg) {
360 : 0 : SPDK_ERRLOG("Split bdev config for base bdev '%s' already exist.", base_bdev_name);
361 : 0 : return -EEXIST;
362 : : }
363 : :
364 : 121 : cfg = calloc(1, sizeof(*cfg));
365 [ - + ]: 121 : if (!cfg) {
366 : 0 : SPDK_ERRLOG("calloc(): Out of memory");
367 : 0 : return -ENOMEM;
368 : : }
369 : :
370 [ - + ]: 121 : cfg->base_bdev = strdup(base_bdev_name);
371 [ - + ]: 121 : if (!cfg->base_bdev) {
372 : 0 : SPDK_ERRLOG("strdup(): Out of memory");
373 : 0 : free(cfg);
374 : 0 : return -ENOMEM;
375 : : }
376 : :
377 : 121 : cfg->split_count = split_count;
378 : 121 : cfg->split_size_mb = split_size;
379 : 121 : TAILQ_INSERT_TAIL(&g_split_config, cfg, tailq);
380 [ + - ]: 121 : if (config) {
381 : 121 : *config = cfg;
382 : : }
383 : :
384 : 121 : return 0;
385 : : }
386 : :
387 : : static int
388 : 1972 : vbdev_split_init(void)
389 : : {
390 : 1972 : return 0;
391 : : }
392 : :
393 : : static void
394 : 1972 : vbdev_split_fini(void)
395 : : {
396 : 1972 : vbdev_split_clear_config();
397 : 1972 : }
398 : :
399 : : static void
400 : 7075 : vbdev_split_examine(struct spdk_bdev *bdev)
401 : : {
402 : 7075 : struct spdk_vbdev_split_config *cfg = vbdev_split_config_find_by_base_name(bdev->name);
403 : :
404 [ + + ]: 7075 : if (cfg != NULL) {
405 [ - + ]: 105 : assert(cfg->split_base == NULL);
406 : :
407 [ - + ]: 105 : if (vbdev_split_create(cfg)) {
408 : 0 : SPDK_ERRLOG("could not split bdev %s\n", bdev->name);
409 : : }
410 : : }
411 : 7075 : spdk_bdev_module_examine_done(&split_if);
412 : 7075 : }
413 : :
414 : : static int
415 : 162 : vbdev_split_config_json(struct spdk_json_write_ctx *w)
416 : : {
417 : : struct spdk_vbdev_split_config *cfg;
418 : :
419 [ + + ]: 218 : TAILQ_FOREACH(cfg, &g_split_config, tailq) {
420 : 56 : spdk_json_write_object_begin(w);
421 : :
422 : 56 : spdk_json_write_named_string(w, "method", "bdev_split_create");
423 : :
424 : 56 : spdk_json_write_named_object_begin(w, "params");
425 : 56 : spdk_json_write_named_string(w, "base_bdev", cfg->base_bdev);
426 : 56 : spdk_json_write_named_uint32(w, "split_count", cfg->split_count);
427 : 56 : spdk_json_write_named_uint64(w, "split_size_mb", cfg->split_size_mb);
428 : 56 : spdk_json_write_object_end(w);
429 : :
430 : 56 : spdk_json_write_object_end(w);
431 : : }
432 : :
433 : 162 : return 0;
434 : : }
435 : :
436 : : int
437 : 121 : create_vbdev_split(const char *base_bdev_name, unsigned split_count, uint64_t split_size_mb)
438 : : {
439 : : int rc;
440 : 95 : struct spdk_vbdev_split_config *cfg;
441 : :
442 : 121 : rc = vbdev_split_add_config(base_bdev_name, split_count, split_size_mb, &cfg);
443 [ - + ]: 121 : if (rc) {
444 : 0 : return rc;
445 : : }
446 : :
447 : 121 : rc = vbdev_split_create(cfg);
448 [ + + ]: 121 : if (rc == -ENODEV) {
449 : : /* It is ok if base bdev does not exist yet. */
450 : 105 : rc = 0;
451 : : }
452 : :
453 : 121 : return rc;
454 : : }
455 : :
456 : : int
457 : 13 : vbdev_split_destruct(const char *base_bdev_name)
458 : : {
459 : 13 : struct spdk_vbdev_split_config *cfg = vbdev_split_config_find_by_base_name(base_bdev_name);
460 : :
461 [ - + ]: 13 : if (!cfg) {
462 : 0 : SPDK_ERRLOG("Split configuration for '%s' not found\n", base_bdev_name);
463 : 0 : return -ENOENT;
464 : : }
465 : :
466 : 13 : vbdev_split_destruct_config(cfg);
467 : 13 : return 0;
468 : : }
469 : :
470 : : struct spdk_bdev_part_base *
471 : 16 : vbdev_split_get_part_base(struct spdk_bdev *bdev)
472 : : {
473 : : struct spdk_vbdev_split_config *cfg;
474 : :
475 : 16 : cfg = vbdev_split_config_find_by_base_name(spdk_bdev_get_name(bdev));
476 : :
477 [ - + ]: 16 : if (cfg == NULL) {
478 : 0 : return NULL;
479 : : }
480 : :
481 : 16 : 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
490 : 1972 : vbdev_split_get_ctx_size(void)
491 : : {
492 : 1972 : return sizeof(struct vbdev_split_bdev_io);
493 : : }
494 : :
495 : 2146 : SPDK_LOG_REGISTER_COMPONENT(vbdev_split)
|