From 3ba5dd2852235c13a22c3866db131b753d7a46f0 Mon Sep 17 00:00:00 2001 From: Kozlowski Mateusz Date: Tue, 7 Jan 2020 07:06:48 -0500 Subject: [PATCH] bdev/zone: Per zone information Added zone specific information during initialization (starting LBA, capacity etc.) Signed-off-by: Kozlowski Mateusz Change-Id: If0599960f0f872117691c801dce497649da20da6 Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/468034 Tested-by: SPDK CI Jenkins Community-CI: Broadcom SPDK FC-NVMe CI Community-CI: SPDK CI Jenkins Reviewed-by: Ben Walker Reviewed-by: Konrad Sztyber Reviewed-by: Jim Harris Reviewed-by: Shuhei Matsumoto --- module/bdev/zone_block/vbdev_zone_block.c | 63 ++++++++++++++++--- .../vbdev_zone_block.c/vbdev_zone_block_ut.c | 28 ++++++--- 2 files changed, 77 insertions(+), 14 deletions(-) diff --git a/module/bdev/zone_block/vbdev_zone_block.c b/module/bdev/zone_block/vbdev_zone_block.c index e56d1f957..da04eec9b 100644 --- a/module/bdev/zone_block/vbdev_zone_block.c +++ b/module/bdev/zone_block/vbdev_zone_block.c @@ -37,6 +37,7 @@ #include "spdk/config.h" #include "spdk/nvme.h" +#include "spdk/bdev_zone.h" #include "spdk_internal/log.h" @@ -70,10 +71,16 @@ struct bdev_zone_block_config { }; static TAILQ_HEAD(, bdev_zone_block_config) g_bdev_configs = TAILQ_HEAD_INITIALIZER(g_bdev_configs); +struct block_zone { + struct spdk_bdev_zone_info zone_info; +}; + /* List of block vbdevs and associated info for each. */ struct bdev_zone_block { struct spdk_bdev bdev; /* the block zoned bdev */ struct spdk_bdev_desc *base_desc; /* its descriptor we get from open */ + struct block_zone *zones; /* array of zones */ + uint64_t num_zones; /* number of zones */ uint64_t zone_capacity; /* zone capacity */ TAILQ_ENTRY(bdev_zone_block) link; }; @@ -148,6 +155,7 @@ _device_unregister_cb(void *io_device) struct bdev_zone_block *bdev_node = io_device; free(bdev_node->bdev.name); + free(bdev_node->zones); free(bdev_node); } @@ -297,11 +305,27 @@ zone_block_insert_name(const char *bdev_name, const char *vbdev_name, uint64_t z return 0; } +static void +zone_block_init_zone_info(struct bdev_zone_block *bdev_node) +{ + size_t i; + struct block_zone *zone; + + for (i = 0; i < bdev_node->num_zones; i++) { + zone = &bdev_node->zones[i]; + zone->zone_info.zone_id = bdev_node->bdev.zone_size * i; + zone->zone_info.capacity = bdev_node->zone_capacity; + zone->zone_info.write_pointer = zone->zone_info.zone_id + zone->zone_info.capacity; + zone->zone_info.state = SPDK_BDEV_ZONE_STATE_FULL; + } +} + static int zone_block_register(struct spdk_bdev *base_bdev) { struct bdev_zone_block_config *name, *tmp; struct bdev_zone_block *bdev_node; + uint64_t zone_size; int rc = 0; /* Check our list of names from config versus this bdev and if @@ -332,14 +356,40 @@ zone_block_register(struct spdk_bdev *base_bdev) SPDK_ERRLOG("could not allocate bdev_node name\n"); goto strdup_failed; } + + zone_size = spdk_align64pow2(name->zone_capacity); + if (zone_size == 0) { + rc = -EINVAL; + SPDK_ERRLOG("invalid zone size\n"); + goto roundup_failed; + } + bdev_node->num_zones = base_bdev->blockcnt / zone_size; + + /* Align num_zones to optimal_open_zones */ + bdev_node->num_zones -= bdev_node->num_zones % name->optimal_open_zones; + bdev_node->zones = calloc(bdev_node->num_zones, sizeof(struct block_zone)); + if (!bdev_node->zones) { + rc = -ENOMEM; + SPDK_ERRLOG("could not allocate zones\n"); + goto calloc_failed; + } + bdev_node->bdev.product_name = "zone_block"; /* Copy some properties from the underlying base bdev. */ bdev_node->bdev.write_cache = base_bdev->write_cache; bdev_node->bdev.required_alignment = base_bdev->required_alignment; bdev_node->bdev.optimal_io_boundary = base_bdev->optimal_io_boundary; + bdev_node->bdev.blocklen = base_bdev->blocklen; - bdev_node->bdev.blockcnt = base_bdev->blockcnt; + bdev_node->bdev.blockcnt = bdev_node->num_zones * zone_size; + + if (bdev_node->num_zones * name->zone_capacity != base_bdev->blockcnt) { + SPDK_DEBUGLOG(SPDK_LOG_VBDEV_ZONE_BLOCK, + "Lost %lu blocks due to zone capacity and base bdev size misalignment\n", + base_bdev->blockcnt - bdev_node->num_zones * name->zone_capacity); + } + bdev_node->bdev.write_unit_size = base_bdev->write_unit_size; bdev_node->bdev.md_interleave = base_bdev->md_interleave; @@ -354,16 +404,13 @@ zone_block_register(struct spdk_bdev *base_bdev) bdev_node->bdev.module = &bdev_zoned_if; /* bdev specific info */ - bdev_node->bdev.zone_size = spdk_align64pow2(name->zone_capacity); - if (bdev_node->bdev.zone_size == 0) { - rc = -EINVAL; - SPDK_ERRLOG("invalid zone size\n"); - goto roundup_failed; - } + bdev_node->bdev.zone_size = zone_size; bdev_node->zone_capacity = name->zone_capacity; bdev_node->bdev.optimal_open_zones = name->optimal_open_zones; bdev_node->bdev.max_open_zones = 0; + zone_block_init_zone_info(bdev_node); + TAILQ_INSERT_TAIL(&g_bdev_nodes, bdev_node, link); spdk_io_device_register(bdev_node, _zone_block_ch_create_cb, _zone_block_ch_destroy_cb, @@ -399,6 +446,8 @@ claim_failed: open_failed: TAILQ_REMOVE(&g_bdev_nodes, bdev_node, link); spdk_io_device_unregister(bdev_node, NULL); + free(bdev_node->zones); +calloc_failed: roundup_failed: free(bdev_node->bdev.name); strdup_failed: diff --git a/test/unit/lib/bdev/vbdev_zone_block.c/vbdev_zone_block_ut.c b/test/unit/lib/bdev/vbdev_zone_block.c/vbdev_zone_block_ut.c index ebd1b96f2..681e2e1db 100644 --- a/test/unit/lib/bdev/vbdev_zone_block.c/vbdev_zone_block_ut.c +++ b/test/unit/lib/bdev/vbdev_zone_block.c/vbdev_zone_block_ut.c @@ -374,7 +374,7 @@ verify_zone_config(bool presence) } CU_ASSERT(strcmp(r->base_bdev, cfg->bdev_name) == 0); CU_ASSERT(r->zone_capacity == cfg->zone_capacity); - CU_ASSERT(r->optimal_open_zones == cfg->optimal_open_zones); + CU_ASSERT(spdk_max(r->optimal_open_zones, 1) == cfg->optimal_open_zones); break; } } @@ -390,8 +390,12 @@ static void verify_zone_bdev(bool presence) { struct rpc_construct_zone_block *r = g_rpc_req; + struct block_zone *zone; struct bdev_zone_block *bdev; bool bdev_found = false; + uint32_t i; + uint64_t expected_num_zones; + uint64_t expected_optimal_open_zones; TAILQ_FOREACH(bdev, &g_bdev_nodes, link) { if (strcmp(bdev->bdev.name, r->name) == 0) { @@ -400,17 +404,27 @@ verify_zone_bdev(bool presence) break; } + expected_optimal_open_zones = spdk_max(r->optimal_open_zones, 1); + expected_num_zones = BLOCK_CNT / spdk_align64pow2(r->zone_capacity) / expected_optimal_open_zones; + expected_num_zones *= expected_optimal_open_zones; + + CU_ASSERT(bdev->num_zones == expected_num_zones); CU_ASSERT(bdev->bdev.zoned == true); - CU_ASSERT(bdev->bdev.blockcnt == BLOCK_CNT); + CU_ASSERT(bdev->bdev.blockcnt == expected_num_zones * spdk_align64pow2(r->zone_capacity)); CU_ASSERT(bdev->bdev.blocklen == BLOCK_SIZE); CU_ASSERT(bdev->bdev.ctxt == bdev); CU_ASSERT(bdev->bdev.fn_table == &zone_block_fn_table); CU_ASSERT(bdev->bdev.module == &bdev_zoned_if); CU_ASSERT(bdev->bdev.write_unit_size == 1); CU_ASSERT(bdev->bdev.zone_size == spdk_align64pow2(r->zone_capacity)); - CU_ASSERT(bdev->bdev.optimal_open_zones == r->optimal_open_zones); + CU_ASSERT(bdev->bdev.optimal_open_zones == expected_optimal_open_zones); CU_ASSERT(bdev->bdev.max_open_zones == 0); + for (i = 0; i < bdev->num_zones; i++) { + zone = &bdev->zones[i]; + CU_ASSERT(zone->zone_info.state == SPDK_BDEV_ZONE_STATE_FULL); + CU_ASSERT(zone->zone_info.capacity == r->zone_capacity); + } break; } } @@ -458,7 +472,7 @@ test_zone_block_create(void) { struct spdk_bdev *bdev; char *name = "Nvme0n1"; - size_t num_zones = 20; + size_t num_zones = 16; size_t zone_capacity = BLOCK_CNT / num_zones; CU_ASSERT(zone_block_init() == 0); @@ -492,7 +506,7 @@ static void test_zone_block_create_invalid(void) { char *name = "Nvme0n1"; - size_t num_zones = 10; + size_t num_zones = 8; size_t zone_capacity = BLOCK_CNT / num_zones; CU_ASSERT(zone_block_init() == 0); @@ -512,10 +526,10 @@ test_zone_block_create_invalid(void) send_delete_vbdev("zone_dev1", true); /* Try to create zoned virtual device with 0 zone size */ - send_create_vbdev("zone_dev2", name, 0, 1, false, false); + send_create_vbdev("zone_dev1", name, 0, 1, false, false); /* Try to create zoned virtual device with 0 optimal number of zones */ - send_create_vbdev("zone_dev2", name, zone_capacity, 0, false, false); + send_create_vbdev("zone_dev1", name, zone_capacity, 0, false, false); while (spdk_thread_poll(g_thread, 0, 0) > 0) {} test_cleanup();