1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. All rights reserved. 5 * Copyright (c) 2019 Mellanox Technologies LTD. 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 #include "spdk/stdinc.h" 35 36 #include "spdk/bdev.h" 37 #include "spdk/conf.h" 38 #include "spdk/env.h" 39 #include "spdk/thread.h" 40 #include "spdk/json.h" 41 #include "spdk/string.h" 42 #include "spdk/likely.h" 43 44 #include "spdk/bdev_module.h" 45 #include "spdk_internal/log.h" 46 47 #include "bdev_null.h" 48 49 struct null_bdev { 50 struct spdk_bdev bdev; 51 TAILQ_ENTRY(null_bdev) tailq; 52 }; 53 54 struct null_io_channel { 55 struct spdk_poller *poller; 56 TAILQ_HEAD(, spdk_bdev_io) io; 57 }; 58 59 static TAILQ_HEAD(, null_bdev) g_null_bdev_head; 60 static void *g_null_read_buf; 61 62 static int bdev_null_initialize(void); 63 static void bdev_null_finish(void); 64 static void bdev_null_get_spdk_running_config(FILE *fp); 65 66 static struct spdk_bdev_module null_if = { 67 .name = "null", 68 .module_init = bdev_null_initialize, 69 .module_fini = bdev_null_finish, 70 .config_text = bdev_null_get_spdk_running_config, 71 .async_fini = true, 72 }; 73 74 SPDK_BDEV_MODULE_REGISTER(null, &null_if) 75 76 static int 77 bdev_null_destruct(void *ctx) 78 { 79 struct null_bdev *bdev = ctx; 80 81 TAILQ_REMOVE(&g_null_bdev_head, bdev, tailq); 82 free(bdev->bdev.name); 83 free(bdev); 84 85 return 0; 86 } 87 88 static bool 89 bdev_null_abort_io(struct null_io_channel *ch, struct spdk_bdev_io *bio_to_abort) 90 { 91 struct spdk_bdev_io *bdev_io; 92 93 TAILQ_FOREACH(bdev_io, &ch->io, module_link) { 94 if (bdev_io == bio_to_abort) { 95 TAILQ_REMOVE(&ch->io, bio_to_abort, module_link); 96 spdk_bdev_io_complete(bio_to_abort, SPDK_BDEV_IO_STATUS_ABORTED); 97 return true; 98 } 99 } 100 101 return false; 102 } 103 104 static void 105 bdev_null_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io) 106 { 107 struct null_io_channel *ch = spdk_io_channel_get_ctx(_ch); 108 struct spdk_bdev *bdev = bdev_io->bdev; 109 struct spdk_dif_ctx dif_ctx; 110 struct spdk_dif_error err_blk; 111 int rc; 112 113 if (SPDK_DIF_DISABLE != bdev->dif_type && 114 (SPDK_BDEV_IO_TYPE_READ == bdev_io->type || 115 SPDK_BDEV_IO_TYPE_WRITE == bdev_io->type)) { 116 rc = spdk_dif_ctx_init(&dif_ctx, 117 bdev->blocklen, 118 bdev->md_len, 119 bdev->md_interleave, 120 bdev->dif_is_head_of_md, 121 bdev->dif_type, 122 bdev->dif_check_flags, 123 bdev_io->u.bdev.offset_blocks & 0xFFFFFFFF, 124 0xFFFF, 0, 0, 0); 125 if (0 != rc) { 126 SPDK_ERRLOG("Failed to initialize DIF context, error %d\n", rc); 127 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 128 return; 129 } 130 } 131 132 switch (bdev_io->type) { 133 case SPDK_BDEV_IO_TYPE_READ: 134 if (bdev_io->u.bdev.iovs[0].iov_base == NULL) { 135 assert(bdev_io->u.bdev.iovcnt == 1); 136 if (spdk_likely(bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen <= 137 SPDK_BDEV_LARGE_BUF_MAX_SIZE)) { 138 bdev_io->u.bdev.iovs[0].iov_base = g_null_read_buf; 139 bdev_io->u.bdev.iovs[0].iov_len = bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen; 140 } else { 141 SPDK_ERRLOG("Overflow occurred. Read I/O size %" PRIu64 " was larger than permitted %d\n", 142 bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen, 143 SPDK_BDEV_LARGE_BUF_MAX_SIZE); 144 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 145 return; 146 } 147 } 148 if (SPDK_DIF_DISABLE != bdev->dif_type) { 149 rc = spdk_dif_generate(bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt, 150 bdev_io->u.bdev.num_blocks, &dif_ctx); 151 if (0 != rc) { 152 SPDK_ERRLOG("IO DIF generation failed: lba %lu, num_block %lu\n", 153 bdev_io->u.bdev.offset_blocks, 154 bdev_io->u.bdev.num_blocks); 155 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 156 return; 157 } 158 } 159 TAILQ_INSERT_TAIL(&ch->io, bdev_io, module_link); 160 break; 161 case SPDK_BDEV_IO_TYPE_WRITE: 162 if (SPDK_DIF_DISABLE != bdev->dif_type) { 163 rc = spdk_dif_verify(bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt, 164 bdev_io->u.bdev.num_blocks, &dif_ctx, &err_blk); 165 if (0 != rc) { 166 SPDK_ERRLOG("IO DIF verification failed: lba %lu, num_blocks %lu, " 167 "err_type %u, expected %u, actual %u, err_offset %u\n", 168 bdev_io->u.bdev.offset_blocks, 169 bdev_io->u.bdev.num_blocks, 170 err_blk.err_type, 171 err_blk.expected, 172 err_blk.actual, 173 err_blk.err_offset); 174 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 175 return; 176 } 177 } 178 TAILQ_INSERT_TAIL(&ch->io, bdev_io, module_link); 179 break; 180 case SPDK_BDEV_IO_TYPE_WRITE_ZEROES: 181 case SPDK_BDEV_IO_TYPE_RESET: 182 TAILQ_INSERT_TAIL(&ch->io, bdev_io, module_link); 183 break; 184 case SPDK_BDEV_IO_TYPE_ABORT: 185 if (bdev_null_abort_io(ch, bdev_io->u.abort.bio_to_abort)) { 186 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS); 187 } else { 188 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 189 } 190 break; 191 case SPDK_BDEV_IO_TYPE_FLUSH: 192 case SPDK_BDEV_IO_TYPE_UNMAP: 193 default: 194 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 195 break; 196 } 197 } 198 199 static bool 200 bdev_null_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type) 201 { 202 switch (io_type) { 203 case SPDK_BDEV_IO_TYPE_READ: 204 case SPDK_BDEV_IO_TYPE_WRITE: 205 case SPDK_BDEV_IO_TYPE_WRITE_ZEROES: 206 case SPDK_BDEV_IO_TYPE_RESET: 207 case SPDK_BDEV_IO_TYPE_ABORT: 208 return true; 209 case SPDK_BDEV_IO_TYPE_FLUSH: 210 case SPDK_BDEV_IO_TYPE_UNMAP: 211 default: 212 return false; 213 } 214 } 215 216 static struct spdk_io_channel * 217 bdev_null_get_io_channel(void *ctx) 218 { 219 return spdk_get_io_channel(&g_null_bdev_head); 220 } 221 222 static void 223 bdev_null_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w) 224 { 225 char uuid_str[SPDK_UUID_STRING_LEN]; 226 227 spdk_json_write_object_begin(w); 228 229 spdk_json_write_named_string(w, "method", "bdev_null_create"); 230 231 spdk_json_write_named_object_begin(w, "params"); 232 spdk_json_write_named_string(w, "name", bdev->name); 233 spdk_json_write_named_uint64(w, "num_blocks", bdev->blockcnt); 234 spdk_json_write_named_uint32(w, "block_size", bdev->blocklen); 235 spdk_json_write_named_uint32(w, "md_size", bdev->md_len); 236 spdk_json_write_named_uint32(w, "dif_type", bdev->dif_type); 237 spdk_json_write_named_bool(w, "dif_is_head_of_md", bdev->dif_is_head_of_md); 238 spdk_uuid_fmt_lower(uuid_str, sizeof(uuid_str), &bdev->uuid); 239 spdk_json_write_named_string(w, "uuid", uuid_str); 240 spdk_json_write_object_end(w); 241 242 spdk_json_write_object_end(w); 243 } 244 245 static const struct spdk_bdev_fn_table null_fn_table = { 246 .destruct = bdev_null_destruct, 247 .submit_request = bdev_null_submit_request, 248 .io_type_supported = bdev_null_io_type_supported, 249 .get_io_channel = bdev_null_get_io_channel, 250 .write_config_json = bdev_null_write_config_json, 251 }; 252 253 int 254 bdev_null_create(struct spdk_bdev **bdev, const struct spdk_null_bdev_opts *opts) 255 { 256 struct null_bdev *null_disk; 257 uint32_t data_block_size; 258 int rc; 259 260 if (!opts) { 261 SPDK_ERRLOG("No options provided for Null bdev.\n"); 262 return -EINVAL; 263 } 264 265 if (opts->md_interleave) { 266 if (opts->block_size < opts->md_size) { 267 SPDK_ERRLOG("Interleaved metadata size can not be greater than block size.\n"); 268 return -EINVAL; 269 } 270 data_block_size = opts->block_size - opts->md_size; 271 } else { 272 if (opts->md_size != 0) { 273 SPDK_ERRLOG("Metadata in separate buffer is not supported\n"); 274 return -ENOTSUP; 275 } 276 data_block_size = opts->block_size; 277 } 278 279 if (data_block_size % 512 != 0) { 280 SPDK_ERRLOG("Data block size %u is not a multiple of 512.\n", opts->block_size); 281 return -EINVAL; 282 } 283 284 if (opts->num_blocks == 0) { 285 SPDK_ERRLOG("Disk must be more than 0 blocks\n"); 286 return -EINVAL; 287 } 288 289 null_disk = calloc(1, sizeof(*null_disk)); 290 if (!null_disk) { 291 SPDK_ERRLOG("could not allocate null_bdev\n"); 292 return -ENOMEM; 293 } 294 295 null_disk->bdev.name = strdup(opts->name); 296 if (!null_disk->bdev.name) { 297 free(null_disk); 298 return -ENOMEM; 299 } 300 null_disk->bdev.product_name = "Null disk"; 301 302 null_disk->bdev.write_cache = 0; 303 null_disk->bdev.blocklen = opts->block_size; 304 null_disk->bdev.blockcnt = opts->num_blocks; 305 null_disk->bdev.md_len = opts->md_size; 306 null_disk->bdev.md_interleave = opts->md_interleave; 307 null_disk->bdev.dif_type = opts->dif_type; 308 null_disk->bdev.dif_is_head_of_md = opts->dif_is_head_of_md; 309 /* Current block device layer API does not propagate 310 * any DIF related information from user. So, we can 311 * not generate or verify Application Tag. 312 */ 313 switch (opts->dif_type) { 314 case SPDK_DIF_TYPE1: 315 case SPDK_DIF_TYPE2: 316 null_disk->bdev.dif_check_flags = SPDK_DIF_FLAGS_GUARD_CHECK | 317 SPDK_DIF_FLAGS_REFTAG_CHECK; 318 break; 319 case SPDK_DIF_TYPE3: 320 null_disk->bdev.dif_check_flags = SPDK_DIF_FLAGS_GUARD_CHECK; 321 break; 322 case SPDK_DIF_DISABLE: 323 break; 324 } 325 if (opts->uuid) { 326 null_disk->bdev.uuid = *opts->uuid; 327 } else { 328 spdk_uuid_generate(&null_disk->bdev.uuid); 329 } 330 331 null_disk->bdev.ctxt = null_disk; 332 null_disk->bdev.fn_table = &null_fn_table; 333 null_disk->bdev.module = &null_if; 334 335 rc = spdk_bdev_register(&null_disk->bdev); 336 if (rc) { 337 free(null_disk->bdev.name); 338 free(null_disk); 339 return rc; 340 } 341 342 *bdev = &(null_disk->bdev); 343 344 TAILQ_INSERT_TAIL(&g_null_bdev_head, null_disk, tailq); 345 346 return rc; 347 } 348 349 void 350 bdev_null_delete(struct spdk_bdev *bdev, spdk_delete_null_complete cb_fn, void *cb_arg) 351 { 352 if (!bdev || bdev->module != &null_if) { 353 cb_fn(cb_arg, -ENODEV); 354 return; 355 } 356 357 spdk_bdev_unregister(bdev, cb_fn, cb_arg); 358 } 359 360 static int 361 null_io_poll(void *arg) 362 { 363 struct null_io_channel *ch = arg; 364 TAILQ_HEAD(, spdk_bdev_io) io; 365 struct spdk_bdev_io *bdev_io; 366 367 TAILQ_INIT(&io); 368 TAILQ_SWAP(&ch->io, &io, spdk_bdev_io, module_link); 369 370 if (TAILQ_EMPTY(&io)) { 371 return 0; 372 } 373 374 while (!TAILQ_EMPTY(&io)) { 375 bdev_io = TAILQ_FIRST(&io); 376 TAILQ_REMOVE(&io, bdev_io, module_link); 377 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS); 378 } 379 380 return 1; 381 } 382 383 static int 384 null_bdev_create_cb(void *io_device, void *ctx_buf) 385 { 386 struct null_io_channel *ch = ctx_buf; 387 388 TAILQ_INIT(&ch->io); 389 ch->poller = SPDK_POLLER_REGISTER(null_io_poll, ch, 0); 390 391 return 0; 392 } 393 394 static void 395 null_bdev_destroy_cb(void *io_device, void *ctx_buf) 396 { 397 struct null_io_channel *ch = ctx_buf; 398 399 spdk_poller_unregister(&ch->poller); 400 } 401 402 static void 403 _bdev_null_cleanup_cb(void *arg) 404 { 405 spdk_free(g_null_read_buf); 406 } 407 408 static int 409 bdev_null_initialize(void) 410 { 411 struct spdk_conf_section *sp = spdk_conf_find_section(NULL, "Null"); 412 uint64_t size_in_mb, num_blocks; 413 int block_size, i, rc = 0; 414 int md_size, dif_type; 415 struct spdk_bdev *bdev; 416 const char *name, *val; 417 struct spdk_null_bdev_opts opts = {}; 418 419 TAILQ_INIT(&g_null_bdev_head); 420 421 /* 422 * This will be used if upper layer expects us to allocate the read buffer. 423 * Instead of using a real rbuf from the bdev pool, just always point to 424 * this same zeroed buffer. 425 */ 426 g_null_read_buf = spdk_zmalloc(SPDK_BDEV_LARGE_BUF_MAX_SIZE, 0, NULL, 427 SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA); 428 429 /* 430 * We need to pick some unique address as our "io device" - so just use the 431 * address of the global tailq. 432 */ 433 spdk_io_device_register(&g_null_bdev_head, null_bdev_create_cb, null_bdev_destroy_cb, 434 sizeof(struct null_io_channel), 435 "null_bdev"); 436 437 if (sp == NULL) { 438 goto end; 439 } 440 441 for (i = 0; ; ++i) { 442 val = spdk_conf_section_get_nval(sp, "Dev", i); 443 if (val == NULL) { 444 break; 445 } 446 447 name = spdk_conf_section_get_nmval(sp, "Dev", i, 0); 448 if (name == NULL) { 449 SPDK_ERRLOG("Null entry %d: Name must be provided\n", i); 450 continue; 451 } 452 453 val = spdk_conf_section_get_nmval(sp, "Dev", i, 1); 454 if (val == NULL) { 455 SPDK_ERRLOG("Null entry %d: Size in MB must be provided\n", i); 456 continue; 457 } 458 459 errno = 0; 460 size_in_mb = strtoull(val, NULL, 10); 461 if (errno) { 462 SPDK_ERRLOG("Null entry %d: Invalid size in MB %s\n", i, val); 463 continue; 464 } 465 466 val = spdk_conf_section_get_nmval(sp, "Dev", i, 2); 467 if (val == NULL) { 468 block_size = 512; 469 } else { 470 block_size = (int)spdk_strtol(val, 10); 471 if (block_size <= 0) { 472 SPDK_ERRLOG("Null entry %d: Invalid block size %s\n", i, val); 473 continue; 474 } 475 } 476 477 val = spdk_conf_section_get_nmval(sp, "Dev", i, 3); 478 if (val == NULL) { 479 md_size = 0; 480 } else { 481 md_size = (int)spdk_strtol(val, 10); 482 if (md_size < 0) { 483 SPDK_ERRLOG("Null entry %d: Invalid metadata size %s\n", i, val); 484 continue; 485 } 486 } 487 488 val = spdk_conf_section_get_nmval(sp, "Dev", i, 4); 489 if (val == NULL) { 490 dif_type = SPDK_DIF_DISABLE; 491 } else { 492 dif_type = (int)spdk_strtol(val, 10); 493 if (dif_type < SPDK_DIF_DISABLE || dif_type > SPDK_DIF_TYPE3) { 494 SPDK_ERRLOG("Null entry %d: Invalid data protection type %s\n", i, val); 495 continue; 496 } 497 } 498 num_blocks = size_in_mb * (1024 * 1024) / block_size; 499 500 opts.name = name; 501 opts.num_blocks = num_blocks; 502 opts.block_size = block_size; 503 opts.md_size = md_size; 504 opts.md_interleave = true; 505 opts.dif_type = dif_type; 506 opts.dif_is_head_of_md = false; 507 rc = bdev_null_create(&bdev, &opts); 508 if (rc) { 509 SPDK_ERRLOG("Could not create null bdev\n"); 510 goto end; 511 } 512 } 513 end: 514 if (rc) { 515 spdk_io_device_unregister(&g_null_bdev_head, _bdev_null_cleanup_cb); 516 } 517 return rc; 518 } 519 520 static void 521 _bdev_null_finish_cb(void *arg) 522 { 523 spdk_free(g_null_read_buf); 524 spdk_bdev_module_finish_done(); 525 } 526 527 static void 528 bdev_null_finish(void) 529 { 530 spdk_io_device_unregister(&g_null_bdev_head, _bdev_null_finish_cb); 531 } 532 533 static void 534 bdev_null_get_spdk_running_config(FILE *fp) 535 { 536 struct null_bdev *bdev; 537 uint64_t null_bdev_size; 538 539 fprintf(fp, "\n[Null]\n"); 540 541 TAILQ_FOREACH(bdev, &g_null_bdev_head, tailq) { 542 null_bdev_size = bdev->bdev.blocklen * bdev->bdev.blockcnt; 543 null_bdev_size /= (1024 * 1024); 544 fprintf(fp, " Dev %s %" PRIu64 " %d %d %d\n", 545 bdev->bdev.name, null_bdev_size, bdev->bdev.blocklen, bdev->bdev.md_len, 546 bdev->bdev.dif_type); 547 } 548 } 549 550 SPDK_LOG_REGISTER_COMPONENT("bdev_null", SPDK_LOG_BDEV_NULL) 551