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