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 return rc; 321 } 322 323 static void 324 vbdev_split_del_config(struct spdk_vbdev_split_config *cfg) 325 { 326 TAILQ_REMOVE(&g_split_config, cfg, tailq); 327 free(cfg->base_bdev); 328 free(cfg); 329 } 330 331 static void 332 vbdev_split_destruct_config(struct spdk_vbdev_split_config *cfg) 333 { 334 struct bdev_part_tailq *split_base_tailq; 335 336 if (cfg->split_base != NULL) { 337 split_base_tailq = spdk_bdev_part_base_get_tailq(cfg->split_base); 338 spdk_bdev_part_base_hotremove(cfg->split_base, split_base_tailq); 339 } else { 340 vbdev_split_del_config(cfg); 341 } 342 } 343 344 static void 345 vbdev_split_clear_config(void) 346 { 347 struct spdk_vbdev_split_config *cfg, *tmp_cfg; 348 349 TAILQ_FOREACH_SAFE(cfg, &g_split_config, tailq, tmp_cfg) { 350 vbdev_split_destruct_config(cfg); 351 } 352 } 353 354 static struct spdk_vbdev_split_config * 355 vbdev_split_config_find_by_base_name(const char *base_bdev_name) 356 { 357 struct spdk_vbdev_split_config *cfg; 358 359 TAILQ_FOREACH(cfg, &g_split_config, tailq) { 360 if (strcmp(cfg->base_bdev, base_bdev_name) == 0) { 361 return cfg; 362 } 363 } 364 365 return NULL; 366 } 367 368 static int 369 vbdev_split_add_config(const char *base_bdev_name, unsigned split_count, uint64_t split_size, 370 struct spdk_vbdev_split_config **config) 371 { 372 struct spdk_vbdev_split_config *cfg; 373 assert(base_bdev_name); 374 375 if (base_bdev_name == NULL) { 376 SPDK_ERRLOG("Split bdev config: no base bdev provided."); 377 return -EINVAL; 378 } 379 380 if (split_count == 0) { 381 SPDK_ERRLOG("Split bdev config: split_count can't be 0."); 382 return -EINVAL; 383 } 384 385 /* Check if we already have 'base_bdev_name' registered in config */ 386 cfg = vbdev_split_config_find_by_base_name(base_bdev_name); 387 if (cfg) { 388 SPDK_ERRLOG("Split bdev config for base bdev '%s' already exist.", base_bdev_name); 389 return -EEXIST; 390 } 391 392 cfg = calloc(1, sizeof(*cfg)); 393 if (!cfg) { 394 SPDK_ERRLOG("calloc(): Out of memory"); 395 return -ENOMEM; 396 } 397 398 cfg->base_bdev = strdup(base_bdev_name); 399 if (!cfg->base_bdev) { 400 SPDK_ERRLOG("strdup(): Out of memory"); 401 free(cfg); 402 return -ENOMEM; 403 } 404 405 cfg->split_count = split_count; 406 cfg->split_size_mb = split_size; 407 TAILQ_INSERT_TAIL(&g_split_config, cfg, tailq); 408 if (config) { 409 *config = cfg; 410 } 411 412 return 0; 413 } 414 415 static int 416 vbdev_split_init(void) 417 { 418 return 0; 419 } 420 421 static void 422 vbdev_split_fini(void) 423 { 424 vbdev_split_clear_config(); 425 } 426 427 static void 428 vbdev_split_examine(struct spdk_bdev *bdev) 429 { 430 struct spdk_vbdev_split_config *cfg = vbdev_split_config_find_by_base_name(bdev->name); 431 432 if (cfg != NULL) { 433 assert(cfg->split_base == NULL); 434 435 if (vbdev_split_create(cfg)) { 436 SPDK_ERRLOG("could not split bdev %s\n", bdev->name); 437 } 438 } 439 spdk_bdev_module_examine_done(&split_if); 440 } 441 442 static int 443 vbdev_split_config_json(struct spdk_json_write_ctx *w) 444 { 445 struct spdk_vbdev_split_config *cfg; 446 447 TAILQ_FOREACH(cfg, &g_split_config, tailq) { 448 spdk_json_write_object_begin(w); 449 450 spdk_json_write_named_string(w, "method", "bdev_split_create"); 451 452 spdk_json_write_named_object_begin(w, "params"); 453 spdk_json_write_named_string(w, "base_bdev", cfg->base_bdev); 454 spdk_json_write_named_uint32(w, "split_count", cfg->split_count); 455 spdk_json_write_named_uint64(w, "split_size_mb", cfg->split_size_mb); 456 spdk_json_write_object_end(w); 457 458 spdk_json_write_object_end(w); 459 } 460 461 return 0; 462 } 463 464 int 465 create_vbdev_split(const char *base_bdev_name, unsigned split_count, uint64_t split_size_mb) 466 { 467 int rc; 468 struct spdk_vbdev_split_config *cfg; 469 470 rc = vbdev_split_add_config(base_bdev_name, split_count, split_size_mb, &cfg); 471 if (rc) { 472 return rc; 473 } 474 475 rc = vbdev_split_create(cfg); 476 if (rc == -ENODEV) { 477 /* It is ok if base bdev does not exist yet. */ 478 rc = 0; 479 } 480 481 return rc; 482 } 483 484 int 485 vbdev_split_destruct(const char *base_bdev_name) 486 { 487 struct spdk_vbdev_split_config *cfg = vbdev_split_config_find_by_base_name(base_bdev_name); 488 489 if (!cfg) { 490 SPDK_ERRLOG("Split configuration for '%s' not found\n", base_bdev_name); 491 return -ENOENT; 492 } 493 494 vbdev_split_destruct_config(cfg); 495 return 0; 496 } 497 498 struct spdk_bdev_part_base * 499 vbdev_split_get_part_base(struct spdk_bdev *bdev) 500 { 501 struct spdk_vbdev_split_config *cfg; 502 503 cfg = vbdev_split_config_find_by_base_name(spdk_bdev_get_name(bdev)); 504 505 if (cfg == NULL) { 506 return NULL; 507 } 508 509 return cfg->split_base; 510 } 511 512 /* 513 * During init we'll be asked how much memory we'd like passed to us 514 * in bev_io structures as context. Here's where we specify how 515 * much context we want per IO. 516 */ 517 static int 518 vbdev_split_get_ctx_size(void) 519 { 520 return sizeof(struct vbdev_split_bdev_io); 521 } 522 523 SPDK_LOG_REGISTER_COMPONENT(vbdev_split) 524