1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * This is a simple example of a virtual block device that takes a single 36 * bdev and slices it into multiple smaller bdevs. 37 */ 38 39 #include "vbdev_split.h" 40 41 #include "spdk/rpc.h" 42 #include "spdk/endian.h" 43 #include "spdk/string.h" 44 #include "spdk/thread.h" 45 #include "spdk/util.h" 46 47 #include "spdk/bdev_module.h" 48 #include "spdk/log.h" 49 50 struct spdk_vbdev_split_config { 51 char *base_bdev; 52 unsigned split_count; 53 uint64_t split_size_mb; 54 55 SPDK_BDEV_PART_TAILQ splits; 56 struct spdk_bdev_part_base *split_base; 57 58 TAILQ_ENTRY(spdk_vbdev_split_config) tailq; 59 }; 60 61 static TAILQ_HEAD(, spdk_vbdev_split_config) g_split_config = TAILQ_HEAD_INITIALIZER( 62 g_split_config); 63 64 struct vbdev_split_channel { 65 struct spdk_bdev_part_channel part_ch; 66 }; 67 68 struct vbdev_split_bdev_io { 69 struct spdk_io_channel *ch; 70 struct spdk_bdev_io *bdev_io; 71 72 /* for bdev_io_wait */ 73 struct spdk_bdev_io_wait_entry bdev_io_wait; 74 }; 75 76 static void vbdev_split_del_config(struct spdk_vbdev_split_config *cfg); 77 78 static int vbdev_split_init(void); 79 static void vbdev_split_fini(void); 80 static void vbdev_split_examine(struct spdk_bdev *bdev); 81 static int vbdev_split_config_json(struct spdk_json_write_ctx *w); 82 static int vbdev_split_get_ctx_size(void); 83 84 static void 85 _vbdev_split_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io); 86 87 static struct spdk_bdev_module split_if = { 88 .name = "split", 89 .module_init = vbdev_split_init, 90 .module_fini = vbdev_split_fini, 91 .get_ctx_size = vbdev_split_get_ctx_size, 92 .examine_config = vbdev_split_examine, 93 .config_json = vbdev_split_config_json, 94 }; 95 96 SPDK_BDEV_MODULE_REGISTER(split, &split_if) 97 98 static void 99 vbdev_split_base_free(void *ctx) 100 { 101 struct spdk_vbdev_split_config *cfg = ctx; 102 103 vbdev_split_del_config(cfg); 104 } 105 106 static int 107 _vbdev_split_destruct(void *ctx) 108 { 109 struct spdk_bdev_part *part = ctx; 110 111 return spdk_bdev_part_free(part); 112 } 113 114 static void 115 vbdev_split_base_bdev_hotremove_cb(void *_part_base) 116 { 117 struct spdk_bdev_part_base *part_base = _part_base; 118 struct spdk_vbdev_split_config *cfg = spdk_bdev_part_base_get_ctx(part_base); 119 120 spdk_bdev_part_base_hotremove(part_base, &cfg->splits); 121 } 122 123 static void 124 vbdev_split_resubmit_io(void *arg) 125 { 126 struct vbdev_split_bdev_io *split_io = (struct vbdev_split_bdev_io *)arg; 127 128 _vbdev_split_submit_request(split_io->ch, split_io->bdev_io); 129 } 130 131 static void 132 vbdev_split_queue_io(struct vbdev_split_bdev_io *split_io) 133 { 134 struct vbdev_split_channel *ch = spdk_io_channel_get_ctx(split_io->ch); 135 int rc; 136 137 split_io->bdev_io_wait.bdev = split_io->bdev_io->bdev; 138 split_io->bdev_io_wait.cb_fn = vbdev_split_resubmit_io; 139 split_io->bdev_io_wait.cb_arg = split_io; 140 141 rc = spdk_bdev_queue_io_wait(split_io->bdev_io->bdev, 142 ch->part_ch.base_ch, &split_io->bdev_io_wait); 143 if (rc != 0) { 144 SPDK_ERRLOG("Queue io failed in vbdev_split_queue_io, rc=%d\n", rc); 145 spdk_bdev_io_complete(split_io->bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 146 } 147 } 148 149 static void 150 _vbdev_split_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io) 151 { 152 struct vbdev_split_channel *ch = spdk_io_channel_get_ctx(_ch); 153 struct vbdev_split_bdev_io *io_ctx = (struct vbdev_split_bdev_io *)bdev_io->driver_ctx; 154 int rc; 155 156 rc = spdk_bdev_part_submit_request(&ch->part_ch, bdev_io); 157 if (rc) { 158 if (rc == -ENOMEM) { 159 SPDK_DEBUGLOG(vbdev_split, "split: no memory, queue io.\n"); 160 io_ctx->ch = _ch; 161 io_ctx->bdev_io = bdev_io; 162 vbdev_split_queue_io(io_ctx); 163 } else { 164 SPDK_ERRLOG("split: error on io submission, rc=%d.\n", rc); 165 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 166 } 167 } 168 } 169 170 static void 171 vbdev_split_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io, bool success) 172 { 173 if (!success) { 174 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 175 return; 176 } 177 178 _vbdev_split_submit_request(ch, bdev_io); 179 } 180 181 static void 182 vbdev_split_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io) 183 { 184 switch (bdev_io->type) { 185 case SPDK_BDEV_IO_TYPE_READ: 186 spdk_bdev_io_get_buf(bdev_io, vbdev_split_get_buf_cb, 187 bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen); 188 break; 189 default: 190 _vbdev_split_submit_request(_ch, bdev_io); 191 break; 192 } 193 } 194 195 static int 196 vbdev_split_dump_info_json(void *ctx, struct spdk_json_write_ctx *w) 197 { 198 struct spdk_bdev_part *part = ctx; 199 struct spdk_bdev *split_base_bdev = spdk_bdev_part_get_base_bdev(part); 200 uint64_t offset_blocks = spdk_bdev_part_get_offset_blocks(part); 201 202 spdk_json_write_named_object_begin(w, "split"); 203 204 spdk_json_write_named_string(w, "base_bdev", spdk_bdev_get_name(split_base_bdev)); 205 spdk_json_write_named_uint64(w, "offset_blocks", offset_blocks); 206 207 spdk_json_write_object_end(w); 208 209 return 0; 210 } 211 212 static void 213 vbdev_split_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w) 214 { 215 /* No config per bdev needed */ 216 } 217 218 static struct spdk_bdev_fn_table vbdev_split_fn_table = { 219 .destruct = _vbdev_split_destruct, 220 .submit_request = vbdev_split_submit_request, 221 .dump_info_json = vbdev_split_dump_info_json, 222 .write_config_json = vbdev_split_write_config_json 223 }; 224 225 static int 226 vbdev_split_create(struct spdk_vbdev_split_config *cfg) 227 { 228 uint64_t split_size_blocks, offset_blocks; 229 uint64_t split_count, max_split_count; 230 uint64_t mb = 1024 * 1024; 231 uint64_t i; 232 int rc; 233 char *name; 234 struct spdk_bdev *base_bdev; 235 struct bdev_part_tailq *split_base_tailq; 236 237 assert(cfg->split_count > 0); 238 239 TAILQ_INIT(&cfg->splits); 240 rc = spdk_bdev_part_base_construct_ext(cfg->base_bdev, 241 vbdev_split_base_bdev_hotremove_cb, 242 &split_if, &vbdev_split_fn_table, 243 &cfg->splits, vbdev_split_base_free, cfg, 244 sizeof(struct vbdev_split_channel), 245 NULL, NULL, &cfg->split_base); 246 if (rc != 0) { 247 if (rc != -ENODEV) { 248 SPDK_ERRLOG("Cannot construct bdev part base\n"); 249 } 250 return rc; 251 } 252 253 base_bdev = spdk_bdev_part_base_get_bdev(cfg->split_base); 254 255 if (cfg->split_size_mb) { 256 if (((cfg->split_size_mb * mb) % base_bdev->blocklen) != 0) { 257 SPDK_ERRLOG("Split size %" PRIu64 " MB is not possible with block size " 258 "%" PRIu32 "\n", 259 cfg->split_size_mb, base_bdev->blocklen); 260 rc = -EINVAL; 261 goto err; 262 } 263 split_size_blocks = (cfg->split_size_mb * mb) / base_bdev->blocklen; 264 SPDK_DEBUGLOG(vbdev_split, "Split size %" PRIu64 " MB specified by user\n", 265 cfg->split_size_mb); 266 } else { 267 split_size_blocks = base_bdev->blockcnt / cfg->split_count; 268 SPDK_DEBUGLOG(vbdev_split, "Split size not specified by user\n"); 269 } 270 271 max_split_count = base_bdev->blockcnt / split_size_blocks; 272 split_count = cfg->split_count; 273 if (split_count > max_split_count) { 274 SPDK_WARNLOG("Split count %" PRIu64 " is greater than maximum possible split count " 275 "%" PRIu64 " - clamping\n", split_count, max_split_count); 276 split_count = max_split_count; 277 } 278 279 SPDK_DEBUGLOG(vbdev_split, "base_bdev: %s split_count: %" PRIu64 280 " split_size_blocks: %" PRIu64 "\n", 281 cfg->base_bdev, split_count, split_size_blocks); 282 283 offset_blocks = 0; 284 for (i = 0; i < split_count; i++) { 285 struct spdk_bdev_part *d; 286 287 d = calloc(1, sizeof(*d)); 288 if (d == NULL) { 289 SPDK_ERRLOG("could not allocate bdev part\n"); 290 rc = -ENOMEM; 291 goto err; 292 } 293 294 name = spdk_sprintf_alloc("%sp%" PRIu64, cfg->base_bdev, i); 295 if (!name) { 296 SPDK_ERRLOG("could not allocate name\n"); 297 free(d); 298 rc = -ENOMEM; 299 goto err; 300 } 301 302 rc = spdk_bdev_part_construct(d, cfg->split_base, name, offset_blocks, split_size_blocks, 303 "Split Disk"); 304 free(name); 305 if (rc) { 306 SPDK_ERRLOG("could not construct bdev part\n"); 307 /* spdk_bdev_part_construct will free name if it fails */ 308 free(d); 309 rc = -ENOMEM; 310 goto err; 311 } 312 313 offset_blocks += split_size_blocks; 314 } 315 316 return 0; 317 err: 318 split_base_tailq = spdk_bdev_part_base_get_tailq(cfg->split_base); 319 spdk_bdev_part_base_hotremove(cfg->split_base, split_base_tailq); 320 spdk_bdev_part_base_free(cfg->split_base); 321 return rc; 322 } 323 324 static void 325 vbdev_split_del_config(struct spdk_vbdev_split_config *cfg) 326 { 327 TAILQ_REMOVE(&g_split_config, cfg, tailq); 328 free(cfg->base_bdev); 329 free(cfg); 330 } 331 332 static void 333 vbdev_split_destruct_config(struct spdk_vbdev_split_config *cfg) 334 { 335 struct bdev_part_tailq *split_base_tailq; 336 337 if (cfg->split_base != NULL) { 338 split_base_tailq = spdk_bdev_part_base_get_tailq(cfg->split_base); 339 spdk_bdev_part_base_hotremove(cfg->split_base, split_base_tailq); 340 } else { 341 vbdev_split_del_config(cfg); 342 } 343 } 344 345 static void 346 vbdev_split_clear_config(void) 347 { 348 struct spdk_vbdev_split_config *cfg, *tmp_cfg; 349 350 TAILQ_FOREACH_SAFE(cfg, &g_split_config, tailq, tmp_cfg) { 351 vbdev_split_destruct_config(cfg); 352 } 353 } 354 355 static struct spdk_vbdev_split_config * 356 vbdev_split_config_find_by_base_name(const char *base_bdev_name) 357 { 358 struct spdk_vbdev_split_config *cfg; 359 360 TAILQ_FOREACH(cfg, &g_split_config, tailq) { 361 if (strcmp(cfg->base_bdev, base_bdev_name) == 0) { 362 return cfg; 363 } 364 } 365 366 return NULL; 367 } 368 369 static int 370 vbdev_split_add_config(const char *base_bdev_name, unsigned split_count, uint64_t split_size, 371 struct spdk_vbdev_split_config **config) 372 { 373 struct spdk_vbdev_split_config *cfg; 374 assert(base_bdev_name); 375 376 if (base_bdev_name == NULL) { 377 SPDK_ERRLOG("Split bdev config: no base bdev provided."); 378 return -EINVAL; 379 } 380 381 if (split_count == 0) { 382 SPDK_ERRLOG("Split bdev config: split_count can't be 0."); 383 return -EINVAL; 384 } 385 386 /* Check if we already have 'base_bdev_name' registered in config */ 387 cfg = vbdev_split_config_find_by_base_name(base_bdev_name); 388 if (cfg) { 389 SPDK_ERRLOG("Split bdev config for base bdev '%s' already exist.", base_bdev_name); 390 return -EEXIST; 391 } 392 393 cfg = calloc(1, sizeof(*cfg)); 394 if (!cfg) { 395 SPDK_ERRLOG("calloc(): Out of memory"); 396 return -ENOMEM; 397 } 398 399 cfg->base_bdev = strdup(base_bdev_name); 400 if (!cfg->base_bdev) { 401 SPDK_ERRLOG("strdup(): Out of memory"); 402 free(cfg); 403 return -ENOMEM; 404 } 405 406 cfg->split_count = split_count; 407 cfg->split_size_mb = split_size; 408 TAILQ_INSERT_TAIL(&g_split_config, cfg, tailq); 409 if (config) { 410 *config = cfg; 411 } 412 413 return 0; 414 } 415 416 static int 417 vbdev_split_init(void) 418 { 419 return 0; 420 } 421 422 static void 423 vbdev_split_fini(void) 424 { 425 vbdev_split_clear_config(); 426 } 427 428 static void 429 vbdev_split_examine(struct spdk_bdev *bdev) 430 { 431 struct spdk_vbdev_split_config *cfg = vbdev_split_config_find_by_base_name(bdev->name); 432 433 if (cfg != NULL) { 434 assert(cfg->split_base == NULL); 435 436 if (vbdev_split_create(cfg)) { 437 SPDK_ERRLOG("could not split bdev %s\n", bdev->name); 438 } 439 } 440 spdk_bdev_module_examine_done(&split_if); 441 } 442 443 static int 444 vbdev_split_config_json(struct spdk_json_write_ctx *w) 445 { 446 struct spdk_vbdev_split_config *cfg; 447 448 TAILQ_FOREACH(cfg, &g_split_config, tailq) { 449 spdk_json_write_object_begin(w); 450 451 spdk_json_write_named_string(w, "method", "bdev_split_create"); 452 453 spdk_json_write_named_object_begin(w, "params"); 454 spdk_json_write_named_string(w, "base_bdev", cfg->base_bdev); 455 spdk_json_write_named_uint32(w, "split_count", cfg->split_count); 456 spdk_json_write_named_uint64(w, "split_size_mb", cfg->split_size_mb); 457 spdk_json_write_object_end(w); 458 459 spdk_json_write_object_end(w); 460 } 461 462 return 0; 463 } 464 465 int 466 create_vbdev_split(const char *base_bdev_name, unsigned split_count, uint64_t split_size_mb) 467 { 468 int rc; 469 struct spdk_vbdev_split_config *cfg; 470 471 rc = vbdev_split_add_config(base_bdev_name, split_count, split_size_mb, &cfg); 472 if (rc) { 473 return rc; 474 } 475 476 rc = vbdev_split_create(cfg); 477 if (rc == -ENODEV) { 478 /* It is ok if base bdev does not exist yet. */ 479 rc = 0; 480 } 481 482 return rc; 483 } 484 485 int 486 vbdev_split_destruct(const char *base_bdev_name) 487 { 488 struct spdk_vbdev_split_config *cfg = vbdev_split_config_find_by_base_name(base_bdev_name); 489 490 if (!cfg) { 491 SPDK_ERRLOG("Split configuration for '%s' not found\n", base_bdev_name); 492 return -ENOENT; 493 } 494 495 vbdev_split_destruct_config(cfg); 496 return 0; 497 } 498 499 struct spdk_bdev_part_base * 500 vbdev_split_get_part_base(struct spdk_bdev *bdev) 501 { 502 struct spdk_vbdev_split_config *cfg; 503 504 cfg = vbdev_split_config_find_by_base_name(spdk_bdev_get_name(bdev)); 505 506 if (cfg == NULL) { 507 return NULL; 508 } 509 510 return cfg->split_base; 511 } 512 513 /* 514 * During init we'll be asked how much memory we'd like passed to us 515 * in bev_io structures as context. Here's where we specify how 516 * much context we want per IO. 517 */ 518 static int 519 vbdev_split_get_ctx_size(void) 520 { 521 return sizeof(struct vbdev_split_bdev_io); 522 } 523 524 SPDK_LOG_REGISTER_COMPONENT(vbdev_split) 525