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 0 : SPDK_BDEV_MODULE_REGISTER(split, &split_if)
68 :
69 : static void
70 0 : vbdev_split_base_free(void *ctx)
71 : {
72 0 : struct spdk_vbdev_split_config *cfg = ctx;
73 :
74 0 : vbdev_split_del_config(cfg);
75 0 : }
76 :
77 : static int
78 0 : _vbdev_split_destruct(void *ctx)
79 : {
80 0 : struct spdk_bdev_part *part = ctx;
81 :
82 0 : return spdk_bdev_part_free(part);
83 0 : }
84 :
85 : static void
86 0 : vbdev_split_base_bdev_hotremove_cb(void *_part_base)
87 : {
88 0 : struct spdk_bdev_part_base *part_base = _part_base;
89 0 : struct spdk_vbdev_split_config *cfg = spdk_bdev_part_base_get_ctx(part_base);
90 :
91 0 : spdk_bdev_part_base_hotremove(part_base, &cfg->splits);
92 0 : }
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 0 : 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 0 : 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 0 : }
118 0 : }
119 :
120 : static void
121 0 : _vbdev_split_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io)
122 : {
123 0 : struct vbdev_split_channel *ch = spdk_io_channel_get_ctx(_ch);
124 0 : struct vbdev_split_bdev_io *io_ctx = (struct vbdev_split_bdev_io *)bdev_io->driver_ctx;
125 0 : int rc;
126 :
127 0 : rc = spdk_bdev_part_submit_request(&ch->part_ch, bdev_io);
128 0 : 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 0 : } 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 0 : }
139 0 : }
140 :
141 : static void
142 0 : vbdev_split_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io, bool success)
143 : {
144 0 : if (!success) {
145 0 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
146 0 : return;
147 : }
148 :
149 0 : _vbdev_split_submit_request(ch, bdev_io);
150 0 : }
151 :
152 : static void
153 0 : vbdev_split_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io)
154 : {
155 0 : switch (bdev_io->type) {
156 : case SPDK_BDEV_IO_TYPE_READ:
157 0 : spdk_bdev_io_get_buf(bdev_io, vbdev_split_get_buf_cb,
158 0 : bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
159 0 : break;
160 : default:
161 0 : _vbdev_split_submit_request(_ch, bdev_io);
162 0 : break;
163 : }
164 0 : }
165 :
166 : static int
167 0 : vbdev_split_dump_info_json(void *ctx, struct spdk_json_write_ctx *w)
168 : {
169 0 : struct spdk_bdev_part *part = ctx;
170 0 : struct spdk_bdev *split_base_bdev = spdk_bdev_part_get_base_bdev(part);
171 0 : uint64_t offset_blocks = spdk_bdev_part_get_offset_blocks(part);
172 :
173 0 : spdk_json_write_named_object_begin(w, "split");
174 :
175 0 : spdk_json_write_named_string(w, "base_bdev", spdk_bdev_get_name(split_base_bdev));
176 0 : spdk_json_write_named_uint64(w, "offset_blocks", offset_blocks);
177 :
178 0 : spdk_json_write_object_end(w);
179 :
180 0 : return 0;
181 0 : }
182 :
183 : static void
184 0 : vbdev_split_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w)
185 : {
186 : /* No config per bdev needed */
187 0 : }
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 0 : vbdev_split_create(struct spdk_vbdev_split_config *cfg)
198 : {
199 0 : uint64_t split_size_blocks, offset_blocks;
200 0 : uint64_t split_count, max_split_count;
201 0 : uint64_t mb = 1024 * 1024;
202 0 : uint64_t i;
203 0 : int rc;
204 0 : char *name;
205 0 : struct spdk_bdev *base_bdev;
206 0 : struct bdev_part_tailq *split_base_tailq;
207 :
208 0 : assert(cfg->split_count > 0);
209 :
210 0 : TAILQ_INIT(&cfg->splits);
211 0 : 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 0 : &cfg->splits, vbdev_split_base_free, cfg,
215 : sizeof(struct vbdev_split_channel),
216 0 : NULL, NULL, &cfg->split_base);
217 0 : if (rc != 0) {
218 0 : if (rc != -ENODEV) {
219 0 : SPDK_ERRLOG("Cannot construct bdev part base\n");
220 0 : }
221 0 : return rc;
222 : }
223 :
224 0 : base_bdev = spdk_bdev_part_base_get_bdev(cfg->split_base);
225 :
226 0 : if (cfg->split_size_mb) {
227 0 : 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 0 : split_size_blocks = (cfg->split_size_mb * mb) / base_bdev->blocklen;
235 0 : SPDK_DEBUGLOG(vbdev_split, "Split size %" PRIu64 " MB specified by user\n",
236 : cfg->split_size_mb);
237 0 : } else {
238 0 : split_size_blocks = base_bdev->blockcnt / cfg->split_count;
239 0 : SPDK_DEBUGLOG(vbdev_split, "Split size not specified by user\n");
240 : }
241 :
242 0 : max_split_count = base_bdev->blockcnt / split_size_blocks;
243 0 : split_count = cfg->split_count;
244 0 : 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 0 : }
249 :
250 0 : 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 0 : offset_blocks = 0;
255 0 : for (i = 0; i < split_count; i++) {
256 0 : struct spdk_bdev_part *d;
257 :
258 0 : d = calloc(1, sizeof(*d));
259 0 : if (d == NULL) {
260 0 : SPDK_ERRLOG("could not allocate bdev part\n");
261 0 : rc = -ENOMEM;
262 0 : goto err;
263 : }
264 :
265 0 : name = spdk_sprintf_alloc("%sp%" PRIu64, cfg->base_bdev, i);
266 0 : 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 0 : rc = spdk_bdev_part_construct(d, cfg->split_base, name, offset_blocks, split_size_blocks,
274 : "Split Disk");
275 0 : free(name);
276 0 : 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 0 : offset_blocks += split_size_blocks;
285 0 : }
286 :
287 0 : return 0;
288 : 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 0 : }
294 :
295 : static void
296 0 : vbdev_split_del_config(struct spdk_vbdev_split_config *cfg)
297 : {
298 0 : TAILQ_REMOVE(&g_split_config, cfg, tailq);
299 0 : free(cfg->base_bdev);
300 0 : free(cfg);
301 0 : }
302 :
303 : static void
304 0 : vbdev_split_destruct_config(struct spdk_vbdev_split_config *cfg)
305 : {
306 0 : struct bdev_part_tailq *split_base_tailq;
307 :
308 0 : if (cfg->split_base != NULL) {
309 0 : split_base_tailq = spdk_bdev_part_base_get_tailq(cfg->split_base);
310 0 : spdk_bdev_part_base_hotremove(cfg->split_base, split_base_tailq);
311 0 : } else {
312 0 : vbdev_split_del_config(cfg);
313 : }
314 0 : }
315 :
316 : static void
317 0 : vbdev_split_clear_config(void)
318 : {
319 0 : struct spdk_vbdev_split_config *cfg, *tmp_cfg;
320 :
321 0 : TAILQ_FOREACH_SAFE(cfg, &g_split_config, tailq, tmp_cfg) {
322 0 : vbdev_split_destruct_config(cfg);
323 0 : }
324 0 : }
325 :
326 : static struct spdk_vbdev_split_config *
327 0 : vbdev_split_config_find_by_base_name(const char *base_bdev_name)
328 : {
329 0 : struct spdk_vbdev_split_config *cfg;
330 :
331 0 : TAILQ_FOREACH(cfg, &g_split_config, tailq) {
332 0 : if (strcmp(cfg->base_bdev, base_bdev_name) == 0) {
333 0 : return cfg;
334 : }
335 0 : }
336 :
337 0 : return NULL;
338 0 : }
339 :
340 : static int
341 0 : 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 0 : struct spdk_vbdev_split_config *cfg;
345 0 : assert(base_bdev_name);
346 :
347 0 : if (base_bdev_name == NULL) {
348 0 : SPDK_ERRLOG("Split bdev config: no base bdev provided.");
349 0 : return -EINVAL;
350 : }
351 :
352 0 : 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 0 : cfg = vbdev_split_config_find_by_base_name(base_bdev_name);
359 0 : 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 0 : cfg = calloc(1, sizeof(*cfg));
365 0 : if (!cfg) {
366 0 : SPDK_ERRLOG("calloc(): Out of memory");
367 0 : return -ENOMEM;
368 : }
369 :
370 0 : cfg->base_bdev = strdup(base_bdev_name);
371 0 : if (!cfg->base_bdev) {
372 0 : SPDK_ERRLOG("strdup(): Out of memory");
373 0 : free(cfg);
374 0 : return -ENOMEM;
375 : }
376 :
377 0 : cfg->split_count = split_count;
378 0 : cfg->split_size_mb = split_size;
379 0 : TAILQ_INSERT_TAIL(&g_split_config, cfg, tailq);
380 0 : if (config) {
381 0 : *config = cfg;
382 0 : }
383 :
384 0 : return 0;
385 0 : }
386 :
387 : static int
388 0 : vbdev_split_init(void)
389 : {
390 0 : return 0;
391 : }
392 :
393 : static void
394 0 : vbdev_split_fini(void)
395 : {
396 0 : vbdev_split_clear_config();
397 0 : }
398 :
399 : static void
400 0 : vbdev_split_examine(struct spdk_bdev *bdev)
401 : {
402 0 : struct spdk_vbdev_split_config *cfg = vbdev_split_config_find_by_base_name(bdev->name);
403 :
404 0 : if (cfg != NULL) {
405 0 : assert(cfg->split_base == NULL);
406 :
407 0 : if (vbdev_split_create(cfg)) {
408 0 : SPDK_ERRLOG("could not split bdev %s\n", bdev->name);
409 0 : }
410 0 : }
411 0 : spdk_bdev_module_examine_done(&split_if);
412 0 : }
413 :
414 : static int
415 0 : vbdev_split_config_json(struct spdk_json_write_ctx *w)
416 : {
417 0 : struct spdk_vbdev_split_config *cfg;
418 :
419 0 : TAILQ_FOREACH(cfg, &g_split_config, tailq) {
420 0 : spdk_json_write_object_begin(w);
421 :
422 0 : spdk_json_write_named_string(w, "method", "bdev_split_create");
423 :
424 0 : spdk_json_write_named_object_begin(w, "params");
425 0 : spdk_json_write_named_string(w, "base_bdev", cfg->base_bdev);
426 0 : spdk_json_write_named_uint32(w, "split_count", cfg->split_count);
427 0 : spdk_json_write_named_uint64(w, "split_size_mb", cfg->split_size_mb);
428 0 : spdk_json_write_object_end(w);
429 :
430 0 : spdk_json_write_object_end(w);
431 0 : }
432 :
433 0 : return 0;
434 0 : }
435 :
436 : int
437 0 : create_vbdev_split(const char *base_bdev_name, unsigned split_count, uint64_t split_size_mb)
438 : {
439 0 : int rc;
440 0 : struct spdk_vbdev_split_config *cfg;
441 :
442 0 : rc = vbdev_split_add_config(base_bdev_name, split_count, split_size_mb, &cfg);
443 0 : if (rc) {
444 0 : return rc;
445 : }
446 :
447 0 : rc = vbdev_split_create(cfg);
448 0 : if (rc == -ENODEV) {
449 : /* It is ok if base bdev does not exist yet. */
450 0 : rc = 0;
451 0 : }
452 :
453 0 : return rc;
454 0 : }
455 :
456 : int
457 0 : vbdev_split_destruct(const char *base_bdev_name)
458 : {
459 0 : struct spdk_vbdev_split_config *cfg = vbdev_split_config_find_by_base_name(base_bdev_name);
460 :
461 0 : if (!cfg) {
462 0 : SPDK_ERRLOG("Split configuration for '%s' not found\n", base_bdev_name);
463 0 : return -ENOENT;
464 : }
465 :
466 0 : vbdev_split_destruct_config(cfg);
467 0 : return 0;
468 0 : }
469 :
470 : struct spdk_bdev_part_base *
471 0 : vbdev_split_get_part_base(struct spdk_bdev *bdev)
472 : {
473 0 : struct spdk_vbdev_split_config *cfg;
474 :
475 0 : cfg = vbdev_split_config_find_by_base_name(spdk_bdev_get_name(bdev));
476 :
477 0 : if (cfg == NULL) {
478 0 : return NULL;
479 : }
480 :
481 0 : return cfg->split_base;
482 0 : }
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 0 : vbdev_split_get_ctx_size(void)
491 : {
492 0 : return sizeof(struct vbdev_split_bdev_io);
493 : }
494 :
495 0 : SPDK_LOG_REGISTER_COMPONENT(vbdev_split)
|