Commit d8ccf6e7 authored by Mateusz Kozlowski's avatar Mateusz Kozlowski Committed by Tomasz Zawadzki
Browse files

bdev/zone: Read IO handling



Added handling of reads to a zone; blocks outside of a write pointer
are zeroed out.

Signed-off-by: default avatarMateusz Kozlowski <mateusz.kozlowski@intel.com>
Change-Id: Iaf60d6ff74caf9831998862e048446ccd0a0fa3f
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/468038


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarKonrad Sztyber <konrad.sztyber@intel.com>
parent ab1641eb
Loading
Loading
Loading
Loading
+53 −0
Original line number Diff line number Diff line
@@ -395,6 +395,55 @@ write_fail:
	return rc;
}

static void
_zone_block_complete_read(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
{
	struct spdk_bdev_io *orig_io = cb_arg;
	int status = success ? SPDK_BDEV_IO_STATUS_SUCCESS : SPDK_BDEV_IO_STATUS_FAILED;

	/* Complete the original IO and then free the one that we created here
	 * as a result of issuing an IO via submit_reqeust.
	 */
	spdk_bdev_io_complete(orig_io, status);
	spdk_bdev_free_io(bdev_io);
}

static int
zone_block_read(struct bdev_zone_block *bdev_node, struct zone_block_io_channel *ch,
		struct spdk_bdev_io *bdev_io)
{
	struct block_zone *zone;
	uint64_t len = bdev_io->u.bdev.num_blocks;
	uint64_t lba = bdev_io->u.bdev.offset_blocks;
	int rc;

	zone = zone_block_get_zone_containing_lba(bdev_node, lba);
	if (!zone) {
		SPDK_ERRLOG("Trying to read from invalid zone (lba 0x%lx)\n", lba);
		return -EINVAL;
	}

	if ((lba + len) > (zone->zone_info.zone_id + zone->zone_info.capacity)) {
		SPDK_ERRLOG("Read exceeds zone capacity (lba 0x%lx, len 0x%lx)\n", lba, len);
		return -EINVAL;
	}

	if (bdev_io->u.bdev.md_buf == NULL) {
		rc = spdk_bdev_readv_blocks(bdev_node->base_desc, ch->base_ch, bdev_io->u.bdev.iovs,
					    bdev_io->u.bdev.iovcnt, lba,
					    len, _zone_block_complete_read,
					    bdev_io);
	} else {
		rc = spdk_bdev_readv_blocks_with_md(bdev_node->base_desc, ch->base_ch,
						    bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt,
						    bdev_io->u.bdev.md_buf,
						    lba, len,
						    _zone_block_complete_read, bdev_io);
	}

	return rc;
}

static void
zone_block_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
{
@@ -412,6 +461,9 @@ zone_block_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_
	case SPDK_BDEV_IO_TYPE_WRITE:
		rc = zone_block_write(bdev_node, dev_ch, bdev_io);
		break;
	case SPDK_BDEV_IO_TYPE_READ:
		rc = zone_block_read(bdev_node, dev_ch, bdev_io);
		break;
	default:
		SPDK_ERRLOG("vbdev_block: unknown I/O type %u\n", bdev_io->type);
		rc = -ENOTSUP;
@@ -435,6 +487,7 @@ zone_block_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type)
	switch (io_type) {
	case SPDK_BDEV_IO_TYPE_ZONE_MANAGEMENT:
	case SPDK_BDEV_IO_TYPE_WRITE:
	case SPDK_BDEV_IO_TYPE_READ:
		return true;
	default:
		return false;
+114 −2
Original line number Diff line number Diff line
@@ -378,6 +378,38 @@ spdk_bdev_writev_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
					       cb, cb_arg);
}

int
spdk_bdev_readv_blocks_with_md(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
			       struct iovec *iov, int iovcnt, void *md,
			       uint64_t offset_blocks, uint64_t num_blocks,
			       spdk_bdev_io_completion_cb cb, void *cb_arg)
{
	struct io_output *output = &g_io_output[g_io_output_index];
	struct spdk_bdev_io *child_io;

	SPDK_CU_ASSERT_FATAL(g_io_output_index < g_max_io_size);
	set_io_output(output, desc, ch, offset_blocks, num_blocks, cb, cb_arg,
		      SPDK_BDEV_IO_TYPE_READ);
	g_io_output_index++;

	child_io = calloc(1, sizeof(struct spdk_bdev_io));
	SPDK_CU_ASSERT_FATAL(child_io != NULL);
	cb(child_io, true, cb_arg);

	return 0;
}

int
spdk_bdev_readv_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
		       struct iovec *iov, int iovcnt,
		       uint64_t offset_blocks, uint64_t num_blocks,
		       spdk_bdev_io_completion_cb cb, void *cb_arg)
{

	return spdk_bdev_readv_blocks_with_md(desc, ch, iov, iovcnt, NULL, offset_blocks, num_blocks,
					      cb, cb_arg);
}

static void
verify_config_present(const char *name, bool presence)
{
@@ -751,7 +783,7 @@ test_supported_io_types(void)

	CU_ASSERT(zone_block_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_ZONE_MANAGEMENT) == true);
	CU_ASSERT(zone_block_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_ZONE_APPEND) == false);
	CU_ASSERT(zone_block_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_READ) == false);
	CU_ASSERT(zone_block_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_READ) == true);
	CU_ASSERT(zone_block_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_WRITE) == true);

	CU_ASSERT(zone_block_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_NVME_ADMIN) == false);
@@ -979,6 +1011,25 @@ send_write_zone(struct bdev_zone_block *bdev, struct spdk_io_channel *ch, uint64
	bdev_io_cleanup(bdev_io);
}

static void
send_read_zone(struct bdev_zone_block *bdev, struct spdk_io_channel *ch, uint64_t lba,
	       uint64_t blocks, uint32_t output_index, bool success)
{
	struct spdk_bdev_io *bdev_io;

	bdev_io = calloc(1, sizeof(struct spdk_bdev_io) + sizeof(struct zone_block_io));
	SPDK_CU_ASSERT_FATAL(bdev_io != NULL);
	bdev_io_initialize(bdev_io, &bdev->bdev, lba, blocks, SPDK_BDEV_IO_TYPE_READ);
	memset(g_io_output, 0, (g_max_io_size * sizeof(struct io_output)));
	g_io_output_index = output_index;

	g_io_comp_status = !success;
	zone_block_submit_request(ch, bdev_io);

	CU_ASSERT(g_io_comp_status == success);
	bdev_io_cleanup(bdev_io);
}

static void
test_open_zone(void)
{
@@ -1122,6 +1173,66 @@ test_zone_write(void)
	test_cleanup();
}

static void
test_zone_read(void)
{
	struct spdk_io_channel *ch;
	struct bdev_zone_block *bdev;
	char *name = "Nvme0n1";
	uint32_t num_zones = 20;
	uint64_t lba, block_len;
	uint32_t output_index = 0;

	init_test_globals(20 * 1024ul);
	CU_ASSERT(zone_block_init() == 0);

	/* Create zone dev */
	bdev = create_and_get_vbdev("zone_dev1", name, num_zones, 1, true);

	ch = calloc(1, sizeof(struct spdk_io_channel) + sizeof(struct zone_block_io_channel));
	SPDK_CU_ASSERT_FATAL(ch != NULL);

	/* Read out of device range */
	block_len = 16;
	lba = g_block_cnt - block_len / 2;
	send_read_zone(bdev, ch, lba, block_len, output_index, false);

	block_len = 1;
	lba = g_block_cnt;
	send_read_zone(bdev, ch, lba, block_len, output_index, false);

	/* Read from full zone */
	lba = 0;
	send_read_zone(bdev, ch, lba, 1, output_index, true);

	/* Read from empty zone */
	send_reset_zone(bdev, ch, lba, output_index, true);
	send_read_zone(bdev, ch, lba, 1, output_index, true);

	/* Read written sectors from open zone */
	send_write_zone(bdev, ch, lba, 1, output_index, true);
	send_read_zone(bdev, ch, lba, 1, output_index, true);

	/* Read partially written sectors from open zone */
	send_read_zone(bdev, ch, lba, 2, output_index, true);

	/* Read unwritten sectors from open zone */
	lba = 2;
	send_read_zone(bdev, ch, lba, 1, output_index, true);

	/* Read from two zones at once */
	block_len = 16;
	lba = bdev->bdev.zone_size - block_len / 2;
	send_read_zone(bdev, ch, lba, block_len, output_index, false);

	/* Delete zone dev */
	send_delete_vbdev("zone_dev1", true);

	while (spdk_thread_poll(g_thread, 0, 0) > 0) {}
	free(ch);
	test_cleanup();
}

int main(int argc, char **argv)
{
	CU_pSuite       suite = NULL;
@@ -1144,7 +1255,8 @@ int main(int argc, char **argv)
		CU_add_test(suite, "test_supported_io_types", test_supported_io_types) == NULL ||
		CU_add_test(suite, "test_reset_zone", test_reset_zone) == NULL ||
		CU_add_test(suite, "test_open_zone", test_open_zone) == NULL ||
		CU_add_test(suite, "test_zone_write", test_zone_write) == NULL
		CU_add_test(suite, "test_zone_write", test_zone_write) == NULL ||
		CU_add_test(suite, "test_zone_read", test_zone_read) == NULL
	) {
		CU_cleanup_registry();
		return CU_get_error();