xref: /spdk/module/bdev/null/bdev_null.c (revision 186b109dd3a723612e3df79bb3d97699173d39e3)
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