1488570ebSJim Harris /* SPDX-License-Identifier: BSD-3-Clause 2a6dbe372Spaul luse * Copyright (C) 2017 Intel Corporation. All rights reserved. 307fe6a43SSeth Howell * Copyright (c) 2019 Mellanox Technologies LTD. All rights reserved. 407fe6a43SSeth Howell */ 507fe6a43SSeth Howell 607fe6a43SSeth Howell #include "spdk/stdinc.h" 707fe6a43SSeth Howell 807fe6a43SSeth Howell #include "spdk/bdev.h" 907fe6a43SSeth Howell #include "spdk/env.h" 1007fe6a43SSeth Howell #include "spdk/thread.h" 1107fe6a43SSeth Howell #include "spdk/json.h" 1207fe6a43SSeth Howell #include "spdk/string.h" 1307fe6a43SSeth Howell #include "spdk/likely.h" 1407fe6a43SSeth Howell 1507fe6a43SSeth Howell #include "spdk/bdev_module.h" 164e8e97c8STomasz Zawadzki #include "spdk/log.h" 1707fe6a43SSeth Howell 1807fe6a43SSeth Howell #include "bdev_null.h" 1907fe6a43SSeth Howell 205fa0d850SBen Walker struct null_bdev_io { 215fa0d850SBen Walker TAILQ_ENTRY(null_bdev_io) link; 225fa0d850SBen Walker }; 235fa0d850SBen Walker 2407fe6a43SSeth Howell struct null_bdev { 2507fe6a43SSeth Howell struct spdk_bdev bdev; 2607fe6a43SSeth Howell TAILQ_ENTRY(null_bdev) tailq; 2707fe6a43SSeth Howell }; 2807fe6a43SSeth Howell 2907fe6a43SSeth Howell struct null_io_channel { 3007fe6a43SSeth Howell struct spdk_poller *poller; 315fa0d850SBen Walker TAILQ_HEAD(, null_bdev_io) io; 3207fe6a43SSeth Howell }; 3307fe6a43SSeth Howell 34232bfc75Syidong0635 static TAILQ_HEAD(, null_bdev) g_null_bdev_head = TAILQ_HEAD_INITIALIZER(g_null_bdev_head); 3507fe6a43SSeth Howell static void *g_null_read_buf; 3607fe6a43SSeth Howell 3707fe6a43SSeth Howell static int bdev_null_initialize(void); 3807fe6a43SSeth Howell static void bdev_null_finish(void); 3907fe6a43SSeth Howell 405fa0d850SBen Walker static int 415fa0d850SBen Walker bdev_null_get_ctx_size(void) 425fa0d850SBen Walker { 435fa0d850SBen Walker return sizeof(struct null_bdev_io); 445fa0d850SBen Walker } 455fa0d850SBen Walker 4607fe6a43SSeth Howell static struct spdk_bdev_module null_if = { 4707fe6a43SSeth Howell .name = "null", 4807fe6a43SSeth Howell .module_init = bdev_null_initialize, 4907fe6a43SSeth Howell .module_fini = bdev_null_finish, 5007fe6a43SSeth Howell .async_fini = true, 515fa0d850SBen Walker .get_ctx_size = bdev_null_get_ctx_size, 5207fe6a43SSeth Howell }; 5307fe6a43SSeth Howell 5407fe6a43SSeth Howell SPDK_BDEV_MODULE_REGISTER(null, &null_if) 5507fe6a43SSeth Howell 5607fe6a43SSeth Howell static int 5707fe6a43SSeth Howell bdev_null_destruct(void *ctx) 5807fe6a43SSeth Howell { 5907fe6a43SSeth Howell struct null_bdev *bdev = ctx; 6007fe6a43SSeth Howell 6107fe6a43SSeth Howell TAILQ_REMOVE(&g_null_bdev_head, bdev, tailq); 6207fe6a43SSeth Howell free(bdev->bdev.name); 6307fe6a43SSeth Howell free(bdev); 6407fe6a43SSeth Howell 6507fe6a43SSeth Howell return 0; 6607fe6a43SSeth Howell } 6707fe6a43SSeth Howell 68269f4a3cSShuhei Matsumoto static bool 69269f4a3cSShuhei Matsumoto bdev_null_abort_io(struct null_io_channel *ch, struct spdk_bdev_io *bio_to_abort) 70269f4a3cSShuhei Matsumoto { 715fa0d850SBen Walker struct null_bdev_io *null_io; 72269f4a3cSShuhei Matsumoto struct spdk_bdev_io *bdev_io; 73269f4a3cSShuhei Matsumoto 745fa0d850SBen Walker TAILQ_FOREACH(null_io, &ch->io, link) { 755fa0d850SBen Walker bdev_io = spdk_bdev_io_from_ctx(null_io); 765fa0d850SBen Walker 77269f4a3cSShuhei Matsumoto if (bdev_io == bio_to_abort) { 785fa0d850SBen Walker TAILQ_REMOVE(&ch->io, null_io, link); 79269f4a3cSShuhei Matsumoto spdk_bdev_io_complete(bio_to_abort, SPDK_BDEV_IO_STATUS_ABORTED); 80269f4a3cSShuhei Matsumoto return true; 81269f4a3cSShuhei Matsumoto } 82269f4a3cSShuhei Matsumoto } 83269f4a3cSShuhei Matsumoto 84269f4a3cSShuhei Matsumoto return false; 85269f4a3cSShuhei Matsumoto } 86269f4a3cSShuhei Matsumoto 8707fe6a43SSeth Howell static void 8807fe6a43SSeth Howell bdev_null_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io) 8907fe6a43SSeth Howell { 905fa0d850SBen Walker struct null_bdev_io *null_io = (struct null_bdev_io *)bdev_io->driver_ctx; 9107fe6a43SSeth Howell struct null_io_channel *ch = spdk_io_channel_get_ctx(_ch); 9265848d0cSEvgeniy Kochetov struct spdk_bdev *bdev = bdev_io->bdev; 9365848d0cSEvgeniy Kochetov struct spdk_dif_ctx dif_ctx; 9465848d0cSEvgeniy Kochetov struct spdk_dif_error err_blk; 9565848d0cSEvgeniy Kochetov int rc; 96a711d629SSlawomir Ptak struct spdk_dif_ctx_init_ext_opts dif_opts; 9765848d0cSEvgeniy Kochetov 9865848d0cSEvgeniy Kochetov if (SPDK_DIF_DISABLE != bdev->dif_type && 9965848d0cSEvgeniy Kochetov (SPDK_BDEV_IO_TYPE_READ == bdev_io->type || 10065848d0cSEvgeniy Kochetov SPDK_BDEV_IO_TYPE_WRITE == bdev_io->type)) { 1015681a8a6SKonrad Sztyber dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format); 102fcf59a6fSShuhei Matsumoto dif_opts.dif_pi_format = bdev->dif_pi_format; 10365848d0cSEvgeniy Kochetov rc = spdk_dif_ctx_init(&dif_ctx, 10465848d0cSEvgeniy Kochetov bdev->blocklen, 10565848d0cSEvgeniy Kochetov bdev->md_len, 10665848d0cSEvgeniy Kochetov bdev->md_interleave, 10765848d0cSEvgeniy Kochetov bdev->dif_is_head_of_md, 10865848d0cSEvgeniy Kochetov bdev->dif_type, 109f751b712SSlawomir Ptak bdev_io->u.bdev.dif_check_flags, 11065848d0cSEvgeniy Kochetov bdev_io->u.bdev.offset_blocks & 0xFFFFFFFF, 111a711d629SSlawomir Ptak 0xFFFF, 0, 0, 0, &dif_opts); 11265848d0cSEvgeniy Kochetov if (0 != rc) { 11365848d0cSEvgeniy Kochetov SPDK_ERRLOG("Failed to initialize DIF context, error %d\n", rc); 11465848d0cSEvgeniy Kochetov spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 11565848d0cSEvgeniy Kochetov return; 11665848d0cSEvgeniy Kochetov } 11765848d0cSEvgeniy Kochetov } 11807fe6a43SSeth Howell 11907fe6a43SSeth Howell switch (bdev_io->type) { 12007fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_READ: 12107fe6a43SSeth Howell if (bdev_io->u.bdev.iovs[0].iov_base == NULL) { 12207fe6a43SSeth Howell assert(bdev_io->u.bdev.iovcnt == 1); 12307fe6a43SSeth Howell if (spdk_likely(bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen <= 12407fe6a43SSeth Howell SPDK_BDEV_LARGE_BUF_MAX_SIZE)) { 12507fe6a43SSeth Howell bdev_io->u.bdev.iovs[0].iov_base = g_null_read_buf; 12607fe6a43SSeth Howell bdev_io->u.bdev.iovs[0].iov_len = bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen; 12707fe6a43SSeth Howell } else { 12807fe6a43SSeth Howell SPDK_ERRLOG("Overflow occurred. Read I/O size %" PRIu64 " was larger than permitted %d\n", 12907fe6a43SSeth Howell bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen, 13007fe6a43SSeth Howell SPDK_BDEV_LARGE_BUF_MAX_SIZE); 13107fe6a43SSeth Howell spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 13207fe6a43SSeth Howell return; 13307fe6a43SSeth Howell } 13407fe6a43SSeth Howell } 13565848d0cSEvgeniy Kochetov if (SPDK_DIF_DISABLE != bdev->dif_type) { 13665848d0cSEvgeniy Kochetov rc = spdk_dif_generate(bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt, 13765848d0cSEvgeniy Kochetov bdev_io->u.bdev.num_blocks, &dif_ctx); 13865848d0cSEvgeniy Kochetov if (0 != rc) { 139024179d8SNick Connolly SPDK_ERRLOG("IO DIF generation failed: lba %" PRIu64 ", num_block %" PRIu64 "\n", 14065848d0cSEvgeniy Kochetov bdev_io->u.bdev.offset_blocks, 14165848d0cSEvgeniy Kochetov bdev_io->u.bdev.num_blocks); 14265848d0cSEvgeniy Kochetov spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 14365848d0cSEvgeniy Kochetov return; 14465848d0cSEvgeniy Kochetov } 14565848d0cSEvgeniy Kochetov } 1465fa0d850SBen Walker TAILQ_INSERT_TAIL(&ch->io, null_io, link); 14707fe6a43SSeth Howell break; 14807fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_WRITE: 14965848d0cSEvgeniy Kochetov if (SPDK_DIF_DISABLE != bdev->dif_type) { 15065848d0cSEvgeniy Kochetov rc = spdk_dif_verify(bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt, 15165848d0cSEvgeniy Kochetov bdev_io->u.bdev.num_blocks, &dif_ctx, &err_blk); 15265848d0cSEvgeniy Kochetov if (0 != rc) { 153024179d8SNick Connolly SPDK_ERRLOG("IO DIF verification failed: lba %" PRIu64 ", num_blocks %" PRIu64 ", " 15407d28d02SSlawomir Ptak "err_type %u, expected %lu, actual %lu, err_offset %u\n", 15565848d0cSEvgeniy Kochetov bdev_io->u.bdev.offset_blocks, 15665848d0cSEvgeniy Kochetov bdev_io->u.bdev.num_blocks, 15765848d0cSEvgeniy Kochetov err_blk.err_type, 15865848d0cSEvgeniy Kochetov err_blk.expected, 15965848d0cSEvgeniy Kochetov err_blk.actual, 16065848d0cSEvgeniy Kochetov err_blk.err_offset); 16165848d0cSEvgeniy Kochetov spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 16265848d0cSEvgeniy Kochetov return; 16365848d0cSEvgeniy Kochetov } 16465848d0cSEvgeniy Kochetov } 1655fa0d850SBen Walker TAILQ_INSERT_TAIL(&ch->io, null_io, link); 16665848d0cSEvgeniy Kochetov break; 16707fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_WRITE_ZEROES: 16807fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_RESET: 1695fa0d850SBen Walker TAILQ_INSERT_TAIL(&ch->io, null_io, link); 17007fe6a43SSeth Howell break; 171269f4a3cSShuhei Matsumoto case SPDK_BDEV_IO_TYPE_ABORT: 172269f4a3cSShuhei Matsumoto if (bdev_null_abort_io(ch, bdev_io->u.abort.bio_to_abort)) { 173269f4a3cSShuhei Matsumoto spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS); 174269f4a3cSShuhei Matsumoto } else { 175269f4a3cSShuhei Matsumoto spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 176269f4a3cSShuhei Matsumoto } 177269f4a3cSShuhei Matsumoto break; 17807fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_FLUSH: 17907fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_UNMAP: 18007fe6a43SSeth Howell default: 18107fe6a43SSeth Howell spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 18207fe6a43SSeth Howell break; 18307fe6a43SSeth Howell } 18407fe6a43SSeth Howell } 18507fe6a43SSeth Howell 18607fe6a43SSeth Howell static bool 18707fe6a43SSeth Howell bdev_null_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type) 18807fe6a43SSeth Howell { 18907fe6a43SSeth Howell switch (io_type) { 19007fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_READ: 19107fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_WRITE: 19207fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_WRITE_ZEROES: 19307fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_RESET: 194269f4a3cSShuhei Matsumoto case SPDK_BDEV_IO_TYPE_ABORT: 19507fe6a43SSeth Howell return true; 19607fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_FLUSH: 19707fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_UNMAP: 19807fe6a43SSeth Howell default: 19907fe6a43SSeth Howell return false; 20007fe6a43SSeth Howell } 20107fe6a43SSeth Howell } 20207fe6a43SSeth Howell 20307fe6a43SSeth Howell static struct spdk_io_channel * 20407fe6a43SSeth Howell bdev_null_get_io_channel(void *ctx) 20507fe6a43SSeth Howell { 20607fe6a43SSeth Howell return spdk_get_io_channel(&g_null_bdev_head); 20707fe6a43SSeth Howell } 20807fe6a43SSeth Howell 20907fe6a43SSeth Howell static void 21007fe6a43SSeth Howell bdev_null_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w) 21107fe6a43SSeth Howell { 21207fe6a43SSeth Howell spdk_json_write_object_begin(w); 21307fe6a43SSeth Howell 21460563dfeSPawel Kaminski spdk_json_write_named_string(w, "method", "bdev_null_create"); 21507fe6a43SSeth Howell 21607fe6a43SSeth Howell spdk_json_write_named_object_begin(w, "params"); 21707fe6a43SSeth Howell spdk_json_write_named_string(w, "name", bdev->name); 21807fe6a43SSeth Howell spdk_json_write_named_uint64(w, "num_blocks", bdev->blockcnt); 21907fe6a43SSeth Howell spdk_json_write_named_uint32(w, "block_size", bdev->blocklen); 2207f50da15SPanfil, Wojciech spdk_json_write_named_uint32(w, "physical_block_size", bdev->phys_blocklen); 2218031dfe2SEvgeniy Kochetov spdk_json_write_named_uint32(w, "md_size", bdev->md_len); 22220aeec56SEvgeniy Kochetov spdk_json_write_named_uint32(w, "dif_type", bdev->dif_type); 22320aeec56SEvgeniy Kochetov spdk_json_write_named_bool(w, "dif_is_head_of_md", bdev->dif_is_head_of_md); 2241521bf3bSShuhei Matsumoto spdk_json_write_named_uint32(w, "dif_pi_format", bdev->dif_pi_format); 22569f9c9acSJim Harris spdk_json_write_named_uuid(w, "uuid", &bdev->uuid); 22607fe6a43SSeth Howell spdk_json_write_object_end(w); 22707fe6a43SSeth Howell 22807fe6a43SSeth Howell spdk_json_write_object_end(w); 22907fe6a43SSeth Howell } 23007fe6a43SSeth Howell 23107fe6a43SSeth Howell static const struct spdk_bdev_fn_table null_fn_table = { 23207fe6a43SSeth Howell .destruct = bdev_null_destruct, 23307fe6a43SSeth Howell .submit_request = bdev_null_submit_request, 23407fe6a43SSeth Howell .io_type_supported = bdev_null_io_type_supported, 23507fe6a43SSeth Howell .get_io_channel = bdev_null_get_io_channel, 23607fe6a43SSeth Howell .write_config_json = bdev_null_write_config_json, 23707fe6a43SSeth Howell }; 23807fe6a43SSeth Howell 239d2407f06SShuhei Matsumoto /* Use a dummy DIF context to validate DIF configuration of the 240d2407f06SShuhei Matsumoto * craeted bdev. 241d2407f06SShuhei Matsumoto */ 242d2407f06SShuhei Matsumoto static int 243d2407f06SShuhei Matsumoto _bdev_validate_dif_config(struct spdk_bdev *bdev) 244d2407f06SShuhei Matsumoto { 245d2407f06SShuhei Matsumoto struct spdk_dif_ctx dif_ctx; 246d2407f06SShuhei Matsumoto struct spdk_dif_ctx_init_ext_opts dif_opts; 247d2407f06SShuhei Matsumoto 248d2407f06SShuhei Matsumoto dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format); 249d2407f06SShuhei Matsumoto dif_opts.dif_pi_format = bdev->dif_pi_format; 250d2407f06SShuhei Matsumoto 251d2407f06SShuhei Matsumoto return spdk_dif_ctx_init(&dif_ctx, 252d2407f06SShuhei Matsumoto bdev->blocklen, 253d2407f06SShuhei Matsumoto bdev->md_len, 254d2407f06SShuhei Matsumoto true, 255d2407f06SShuhei Matsumoto bdev->dif_is_head_of_md, 256d2407f06SShuhei Matsumoto bdev->dif_type, 257d2407f06SShuhei Matsumoto bdev->dif_check_flags, 258d2407f06SShuhei Matsumoto SPDK_DIF_REFTAG_IGNORE, 259d2407f06SShuhei Matsumoto 0xFFFF, SPDK_DIF_APPTAG_IGNORE, 260d2407f06SShuhei Matsumoto 0, 0, &dif_opts); 261d2407f06SShuhei Matsumoto } 262d2407f06SShuhei Matsumoto 26307fe6a43SSeth Howell int 26436943038SShuhei Matsumoto bdev_null_create(struct spdk_bdev **bdev, const struct null_bdev_opts *opts) 26507fe6a43SSeth Howell { 26607fe6a43SSeth Howell struct null_bdev *null_disk; 26736943038SShuhei Matsumoto uint32_t block_size; 26807fe6a43SSeth Howell int rc; 26907fe6a43SSeth Howell 27007fe6a43SSeth Howell if (!opts) { 27107fe6a43SSeth Howell SPDK_ERRLOG("No options provided for Null bdev.\n"); 27207fe6a43SSeth Howell return -EINVAL; 27307fe6a43SSeth Howell } 27407fe6a43SSeth Howell 275a9837c70SChangpeng Liu switch (opts->md_size) { 276a9837c70SChangpeng Liu case 0: 277a9837c70SChangpeng Liu case 8: 278a9837c70SChangpeng Liu case 16: 279a9837c70SChangpeng Liu case 32: 280a9837c70SChangpeng Liu case 64: 281a9837c70SChangpeng Liu case 128: 282a9837c70SChangpeng Liu break; 283a9837c70SChangpeng Liu default: 284a9837c70SChangpeng Liu SPDK_ERRLOG("metadata size %u is not supported\n", opts->md_size); 285a9837c70SChangpeng Liu return -EINVAL; 286a9837c70SChangpeng Liu } 287a9837c70SChangpeng Liu 28836943038SShuhei Matsumoto if (opts->block_size % 512 != 0) { 289f1209426SEvgeniy Kochetov SPDK_ERRLOG("Data block size %u is not a multiple of 512.\n", opts->block_size); 29007fe6a43SSeth Howell return -EINVAL; 29107fe6a43SSeth Howell } 29207fe6a43SSeth Howell 293d2407f06SShuhei Matsumoto if (opts->physical_block_size % 512 != 0) { 294d2407f06SShuhei Matsumoto SPDK_ERRLOG("Physical block must be 512 bytes aligned\n"); 295d2407f06SShuhei Matsumoto return -EINVAL; 296d2407f06SShuhei Matsumoto } 297d2407f06SShuhei Matsumoto 29836943038SShuhei Matsumoto block_size = opts->block_size + opts->md_size; 29936943038SShuhei Matsumoto 30007fe6a43SSeth Howell if (opts->num_blocks == 0) { 30107fe6a43SSeth Howell SPDK_ERRLOG("Disk must be more than 0 blocks\n"); 30207fe6a43SSeth Howell return -EINVAL; 30307fe6a43SSeth Howell } 30407fe6a43SSeth Howell 30507fe6a43SSeth Howell null_disk = calloc(1, sizeof(*null_disk)); 30607fe6a43SSeth Howell if (!null_disk) { 30707fe6a43SSeth Howell SPDK_ERRLOG("could not allocate null_bdev\n"); 30807fe6a43SSeth Howell return -ENOMEM; 30907fe6a43SSeth Howell } 31007fe6a43SSeth Howell 31107fe6a43SSeth Howell null_disk->bdev.name = strdup(opts->name); 31207fe6a43SSeth Howell if (!null_disk->bdev.name) { 31307fe6a43SSeth Howell free(null_disk); 31407fe6a43SSeth Howell return -ENOMEM; 31507fe6a43SSeth Howell } 31607fe6a43SSeth Howell null_disk->bdev.product_name = "Null disk"; 31707fe6a43SSeth Howell 31807fe6a43SSeth Howell null_disk->bdev.write_cache = 0; 31936943038SShuhei Matsumoto null_disk->bdev.blocklen = block_size; 3207f50da15SPanfil, Wojciech null_disk->bdev.phys_blocklen = opts->physical_block_size; 32107fe6a43SSeth Howell null_disk->bdev.blockcnt = opts->num_blocks; 322f1209426SEvgeniy Kochetov null_disk->bdev.md_len = opts->md_size; 323ccc88995SShuhei Matsumoto null_disk->bdev.md_interleave = true; 32465848d0cSEvgeniy Kochetov null_disk->bdev.dif_type = opts->dif_type; 32565848d0cSEvgeniy Kochetov null_disk->bdev.dif_is_head_of_md = opts->dif_is_head_of_md; 32665848d0cSEvgeniy Kochetov /* Current block device layer API does not propagate 32765848d0cSEvgeniy Kochetov * any DIF related information from user. So, we can 32865848d0cSEvgeniy Kochetov * not generate or verify Application Tag. 32965848d0cSEvgeniy Kochetov */ 33065848d0cSEvgeniy Kochetov switch (opts->dif_type) { 33165848d0cSEvgeniy Kochetov case SPDK_DIF_TYPE1: 33265848d0cSEvgeniy Kochetov case SPDK_DIF_TYPE2: 33365848d0cSEvgeniy Kochetov null_disk->bdev.dif_check_flags = SPDK_DIF_FLAGS_GUARD_CHECK | 33465848d0cSEvgeniy Kochetov SPDK_DIF_FLAGS_REFTAG_CHECK; 33565848d0cSEvgeniy Kochetov break; 33665848d0cSEvgeniy Kochetov case SPDK_DIF_TYPE3: 33765848d0cSEvgeniy Kochetov null_disk->bdev.dif_check_flags = SPDK_DIF_FLAGS_GUARD_CHECK; 33865848d0cSEvgeniy Kochetov break; 33965848d0cSEvgeniy Kochetov case SPDK_DIF_DISABLE: 34065848d0cSEvgeniy Kochetov break; 34165848d0cSEvgeniy Kochetov } 3421521bf3bSShuhei Matsumoto null_disk->bdev.dif_pi_format = opts->dif_pi_format; 34307fe6a43SSeth Howell 344d2407f06SShuhei Matsumoto if (opts->dif_type != SPDK_DIF_DISABLE) { 345d2407f06SShuhei Matsumoto rc = _bdev_validate_dif_config(&null_disk->bdev); 346d2407f06SShuhei Matsumoto if (rc != 0) { 347d2407f06SShuhei Matsumoto SPDK_ERRLOG("DIF configuration was wrong\n"); 348d2407f06SShuhei Matsumoto free(null_disk); 349d2407f06SShuhei Matsumoto return -EINVAL; 350d2407f06SShuhei Matsumoto } 351d2407f06SShuhei Matsumoto } 352d2407f06SShuhei Matsumoto 35336943038SShuhei Matsumoto if (!spdk_uuid_is_null(&opts->uuid)) { 35436943038SShuhei Matsumoto spdk_uuid_copy(&null_disk->bdev.uuid, &opts->uuid); 35536943038SShuhei Matsumoto } 35636943038SShuhei Matsumoto 35707fe6a43SSeth Howell null_disk->bdev.ctxt = null_disk; 35807fe6a43SSeth Howell null_disk->bdev.fn_table = &null_fn_table; 35907fe6a43SSeth Howell null_disk->bdev.module = &null_if; 36007fe6a43SSeth Howell 36107fe6a43SSeth Howell rc = spdk_bdev_register(&null_disk->bdev); 36207fe6a43SSeth Howell if (rc) { 36307fe6a43SSeth Howell free(null_disk->bdev.name); 36407fe6a43SSeth Howell free(null_disk); 36507fe6a43SSeth Howell return rc; 36607fe6a43SSeth Howell } 36707fe6a43SSeth Howell 36807fe6a43SSeth Howell *bdev = &(null_disk->bdev); 36907fe6a43SSeth Howell 37007fe6a43SSeth Howell TAILQ_INSERT_TAIL(&g_null_bdev_head, null_disk, tailq); 37107fe6a43SSeth Howell 37207fe6a43SSeth Howell return rc; 37307fe6a43SSeth Howell } 37407fe6a43SSeth Howell 37507fe6a43SSeth Howell void 3764573e4ccSShuhei Matsumoto bdev_null_delete(const char *bdev_name, spdk_delete_null_complete cb_fn, void *cb_arg) 37707fe6a43SSeth Howell { 3784573e4ccSShuhei Matsumoto int rc; 37907fe6a43SSeth Howell 3804573e4ccSShuhei Matsumoto rc = spdk_bdev_unregister_by_name(bdev_name, &null_if, cb_fn, cb_arg); 3814573e4ccSShuhei Matsumoto if (rc != 0) { 3824573e4ccSShuhei Matsumoto cb_fn(cb_arg, rc); 3834573e4ccSShuhei Matsumoto } 38407fe6a43SSeth Howell } 38507fe6a43SSeth Howell 38607fe6a43SSeth Howell static int 38707fe6a43SSeth Howell null_io_poll(void *arg) 38807fe6a43SSeth Howell { 38907fe6a43SSeth Howell struct null_io_channel *ch = arg; 3905fa0d850SBen Walker TAILQ_HEAD(, null_bdev_io) io; 3915fa0d850SBen Walker struct null_bdev_io *null_io; 39207fe6a43SSeth Howell 39307fe6a43SSeth Howell TAILQ_INIT(&io); 3945fa0d850SBen Walker TAILQ_SWAP(&ch->io, &io, null_bdev_io, link); 39507fe6a43SSeth Howell 39607fe6a43SSeth Howell if (TAILQ_EMPTY(&io)) { 397eb05cbd6SMaciej Szwed return SPDK_POLLER_IDLE; 39807fe6a43SSeth Howell } 39907fe6a43SSeth Howell 40007fe6a43SSeth Howell while (!TAILQ_EMPTY(&io)) { 4015fa0d850SBen Walker null_io = TAILQ_FIRST(&io); 4025fa0d850SBen Walker TAILQ_REMOVE(&io, null_io, link); 4035fa0d850SBen Walker spdk_bdev_io_complete(spdk_bdev_io_from_ctx(null_io), SPDK_BDEV_IO_STATUS_SUCCESS); 40407fe6a43SSeth Howell } 40507fe6a43SSeth Howell 406eb05cbd6SMaciej Szwed return SPDK_POLLER_BUSY; 40707fe6a43SSeth Howell } 40807fe6a43SSeth Howell 40907fe6a43SSeth Howell static int 41007fe6a43SSeth Howell null_bdev_create_cb(void *io_device, void *ctx_buf) 41107fe6a43SSeth Howell { 41207fe6a43SSeth Howell struct null_io_channel *ch = ctx_buf; 41307fe6a43SSeth Howell 41407fe6a43SSeth Howell TAILQ_INIT(&ch->io); 415ab0bc5c2SShuhei Matsumoto ch->poller = SPDK_POLLER_REGISTER(null_io_poll, ch, 0); 41607fe6a43SSeth Howell 41707fe6a43SSeth Howell return 0; 41807fe6a43SSeth Howell } 41907fe6a43SSeth Howell 42007fe6a43SSeth Howell static void 42107fe6a43SSeth Howell null_bdev_destroy_cb(void *io_device, void *ctx_buf) 42207fe6a43SSeth Howell { 42307fe6a43SSeth Howell struct null_io_channel *ch = ctx_buf; 42407fe6a43SSeth Howell 42507fe6a43SSeth Howell spdk_poller_unregister(&ch->poller); 42607fe6a43SSeth Howell } 42707fe6a43SSeth Howell 42807fe6a43SSeth Howell static int 42907fe6a43SSeth Howell bdev_null_initialize(void) 43007fe6a43SSeth Howell { 43107fe6a43SSeth Howell /* 43207fe6a43SSeth Howell * This will be used if upper layer expects us to allocate the read buffer. 43307fe6a43SSeth Howell * Instead of using a real rbuf from the bdev pool, just always point to 43407fe6a43SSeth Howell * this same zeroed buffer. 43507fe6a43SSeth Howell */ 43607fe6a43SSeth Howell g_null_read_buf = spdk_zmalloc(SPDK_BDEV_LARGE_BUF_MAX_SIZE, 0, NULL, 437*186b109dSJim Harris SPDK_ENV_NUMA_ID_ANY, SPDK_MALLOC_DMA); 4382eda3fa0STomasz Zawadzki if (g_null_read_buf == NULL) { 4392eda3fa0STomasz Zawadzki return -1; 4402eda3fa0STomasz Zawadzki } 44107fe6a43SSeth Howell 44207fe6a43SSeth Howell /* 44307fe6a43SSeth Howell * We need to pick some unique address as our "io device" - so just use the 44407fe6a43SSeth Howell * address of the global tailq. 44507fe6a43SSeth Howell */ 44607fe6a43SSeth Howell spdk_io_device_register(&g_null_bdev_head, null_bdev_create_cb, null_bdev_destroy_cb, 4472eda3fa0STomasz Zawadzki sizeof(struct null_io_channel), "null_bdev"); 44807fe6a43SSeth Howell 4492eda3fa0STomasz Zawadzki return 0; 45007fe6a43SSeth Howell } 45107fe6a43SSeth Howell 45202e3c62cSShuhei Matsumoto static void 45302e3c62cSShuhei Matsumoto dummy_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *ctx) 454d0657f32SJin Yu { 45502e3c62cSShuhei Matsumoto } 45602e3c62cSShuhei Matsumoto 45702e3c62cSShuhei Matsumoto int 45802e3c62cSShuhei Matsumoto bdev_null_resize(const char *bdev_name, const uint64_t new_size_in_mb) 45902e3c62cSShuhei Matsumoto { 46002e3c62cSShuhei Matsumoto struct spdk_bdev_desc *desc; 46102e3c62cSShuhei Matsumoto struct spdk_bdev *bdev; 462d0657f32SJin Yu uint64_t current_size_in_mb; 463d0657f32SJin Yu uint64_t new_size_in_byte; 46402e3c62cSShuhei Matsumoto int rc = 0; 46502e3c62cSShuhei Matsumoto 46602e3c62cSShuhei Matsumoto rc = spdk_bdev_open_ext(bdev_name, false, dummy_bdev_event_cb, NULL, &desc); 46702e3c62cSShuhei Matsumoto if (rc != 0) { 46802e3c62cSShuhei Matsumoto SPDK_ERRLOG("failed to open bdev; %s.\n", bdev_name); 46902e3c62cSShuhei Matsumoto return rc; 47002e3c62cSShuhei Matsumoto } 47102e3c62cSShuhei Matsumoto 47202e3c62cSShuhei Matsumoto bdev = spdk_bdev_desc_get_bdev(desc); 473d0657f32SJin Yu 474d0657f32SJin Yu if (bdev->module != &null_if) { 47502e3c62cSShuhei Matsumoto rc = -EINVAL; 47602e3c62cSShuhei Matsumoto goto exit; 477d0657f32SJin Yu } 478d0657f32SJin Yu 479d0657f32SJin Yu current_size_in_mb = bdev->blocklen * bdev->blockcnt / (1024 * 1024); 480d0657f32SJin Yu if (new_size_in_mb < current_size_in_mb) { 481d0657f32SJin Yu SPDK_ERRLOG("The new bdev size must not be smaller than current bdev size.\n"); 48202e3c62cSShuhei Matsumoto rc = -EINVAL; 48302e3c62cSShuhei Matsumoto goto exit; 484d0657f32SJin Yu } 485d0657f32SJin Yu 486d0657f32SJin Yu new_size_in_byte = new_size_in_mb * 1024 * 1024; 487d0657f32SJin Yu 488d0657f32SJin Yu rc = spdk_bdev_notify_blockcnt_change(bdev, new_size_in_byte / bdev->blocklen); 489d0657f32SJin Yu if (rc != 0) { 490d0657f32SJin Yu SPDK_ERRLOG("failed to notify block cnt change.\n"); 491d0657f32SJin Yu } 492d0657f32SJin Yu 49302e3c62cSShuhei Matsumoto exit: 49402e3c62cSShuhei Matsumoto spdk_bdev_close(desc); 49502e3c62cSShuhei Matsumoto return rc; 496d0657f32SJin Yu } 497d0657f32SJin Yu 49807fe6a43SSeth Howell static void 49907fe6a43SSeth Howell _bdev_null_finish_cb(void *arg) 50007fe6a43SSeth Howell { 50107fe6a43SSeth Howell spdk_free(g_null_read_buf); 502511fe155STomasz Zawadzki spdk_bdev_module_fini_done(); 50307fe6a43SSeth Howell } 50407fe6a43SSeth Howell 50507fe6a43SSeth Howell static void 50607fe6a43SSeth Howell bdev_null_finish(void) 50707fe6a43SSeth Howell { 508a7d174e2SKefu Chai if (g_null_read_buf == NULL) { 509a7d174e2SKefu Chai spdk_bdev_module_fini_done(); 510a7d174e2SKefu Chai return; 511a7d174e2SKefu Chai } 51207fe6a43SSeth Howell spdk_io_device_unregister(&g_null_bdev_head, _bdev_null_finish_cb); 51307fe6a43SSeth Howell } 51407fe6a43SSeth Howell 5152172c432STomasz Zawadzki SPDK_LOG_REGISTER_COMPONENT(bdev_null) 516