diff --git a/module/bdev/zone_block/vbdev_zone_block.c b/module/bdev/zone_block/vbdev_zone_block.c index 4b66eeafb..51f628f36 100644 --- a/module/bdev/zone_block/vbdev_zone_block.c +++ b/module/bdev/zone_block/vbdev_zone_block.c @@ -289,6 +289,24 @@ zone_block_reset_zone(struct bdev_zone_block *bdev_node, struct zone_block_io_ch } } +static int +zone_block_close_zone(struct block_zone *zone, struct spdk_bdev_io *bdev_io) +{ + pthread_spin_lock(&zone->lock); + + switch (zone->zone_info.state) { + case SPDK_BDEV_ZONE_STATE_OPEN: + case SPDK_BDEV_ZONE_STATE_CLOSED: + zone->zone_info.state = SPDK_BDEV_ZONE_STATE_CLOSED; + pthread_spin_unlock(&zone->lock); + spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS); + return 0; + default: + pthread_spin_unlock(&zone->lock); + return -EINVAL; + } +} + static int zone_block_zone_management(struct bdev_zone_block *bdev_node, struct zone_block_io_channel *ch, struct spdk_bdev_io *bdev_io) @@ -305,6 +323,8 @@ zone_block_zone_management(struct bdev_zone_block *bdev_node, struct zone_block_ return zone_block_reset_zone(bdev_node, ch, zone, bdev_io); case SPDK_BDEV_ZONE_OPEN: return zone_block_open_zone(zone, bdev_io); + case SPDK_BDEV_ZONE_CLOSE: + return zone_block_close_zone(zone, bdev_io); default: return -EINVAL; } 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 1c8ce54de..373b3ab39 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 @@ -941,6 +941,13 @@ send_open_zone(struct bdev_zone_block *bdev, struct spdk_io_channel *ch, uint64_ send_zone_management(bdev, ch, zone_id, output_index, SPDK_BDEV_ZONE_OPEN, success); } +static void +send_close_zone(struct bdev_zone_block *bdev, struct spdk_io_channel *ch, uint64_t zone_id, + uint32_t output_index, bool success) +{ + send_zone_management(bdev, ch, zone_id, output_index, SPDK_BDEV_ZONE_CLOSE, success); +} + static void test_reset_zone(void) { @@ -1233,6 +1240,65 @@ test_zone_read(void) test_cleanup(); } +static void +test_close_zone(void) +{ + struct spdk_io_channel *ch; + struct bdev_zone_block *bdev; + char *name = "Nvme0n1"; + uint32_t num_zones = 20; + uint64_t zone_id; + 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); + + /* Try to close a full zone */ + zone_id = 0; + send_close_zone(bdev, ch, zone_id, output_index, false); + + /* Try to close an empty zone */ + send_reset_zone(bdev, ch, zone_id, output_index, true); + send_close_zone(bdev, ch, zone_id, output_index, false); + + /* Close an open zone */ + send_open_zone(bdev, ch, zone_id, output_index, true); + send_close_zone(bdev, ch, zone_id, output_index, true); + send_zone_info(bdev, ch, zone_id, zone_id, SPDK_BDEV_ZONE_STATE_CLOSED, output_index, true); + + /* Close a closed zone */ + send_close_zone(bdev, ch, zone_id, output_index, true); + send_zone_info(bdev, ch, zone_id, zone_id, SPDK_BDEV_ZONE_STATE_CLOSED, output_index, true); + + /* Send close to last zone */ + zone_id = (num_zones - 1) * bdev->bdev.zone_size; + send_reset_zone(bdev, ch, zone_id, output_index, true); + send_open_zone(bdev, ch, zone_id, output_index, true); + send_close_zone(bdev, ch, zone_id, output_index, true); + send_zone_info(bdev, ch, zone_id, zone_id, SPDK_BDEV_ZONE_STATE_CLOSED, output_index, true); + + /* Send close with misaligned LBA */ + zone_id = 1; + send_close_zone(bdev, ch, zone_id, output_index, false); + + /* Send close to non-existing zone */ + zone_id = num_zones * bdev->bdev.zone_size; + send_close_zone(bdev, ch, zone_id, 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; @@ -1256,7 +1322,8 @@ int main(int argc, char **argv) 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_read", test_zone_read) == NULL + CU_add_test(suite, "test_zone_read", test_zone_read) == NULL || + CU_add_test(suite, "test_close_zone", test_close_zone) == NULL ) { CU_cleanup_registry(); return CU_get_error();