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