diff --git a/module/bdev/zone_block/vbdev_zone_block.c b/module/bdev/zone_block/vbdev_zone_block.c index 46dc47bb0..6b09b2deb 100644 --- a/module/bdev/zone_block/vbdev_zone_block.c +++ b/module/bdev/zone_block/vbdev_zone_block.c @@ -351,6 +351,10 @@ _zone_block_complete_write(struct spdk_bdev_io *bdev_io, bool success, void *cb_ struct spdk_bdev_io *orig_io = cb_arg; int status = success ? SPDK_BDEV_IO_STATUS_SUCCESS : SPDK_BDEV_IO_STATUS_FAILED; + if (success && orig_io->type == SPDK_BDEV_IO_TYPE_ZONE_APPEND) { + orig_io->u.bdev.offset_blocks = bdev_io->u.bdev.offset_blocks; + } + /* Complete the original IO and then free the one that we created here * as a result of issuing an IO via submit_reqeust. */ @@ -367,8 +371,13 @@ zone_block_write(struct bdev_zone_block *bdev_node, struct zone_block_io_channel uint64_t lba = bdev_io->u.bdev.offset_blocks; uint64_t num_blocks_left, wp; int rc = 0; + bool is_append = bdev_io->type == SPDK_BDEV_IO_TYPE_ZONE_APPEND; - zone = zone_block_get_zone_containing_lba(bdev_node, lba); + if (is_append) { + zone = zone_block_get_zone_by_slba(bdev_node, lba); + } else { + zone = zone_block_get_zone_containing_lba(bdev_node, lba); + } if (!zone) { SPDK_ERRLOG("Trying to write to invalid zone (lba 0x%lx)\n", lba); return -EINVAL; @@ -389,11 +398,14 @@ zone_block_write(struct bdev_zone_block *bdev_node, struct zone_block_io_channel } wp = zone->zone_info.write_pointer; - - if (lba != wp) { - SPDK_ERRLOG("Trying to write to zone with invalid address (lba 0x%lx, wp 0x%lx)\n", lba, wp); - rc = -EINVAL; - goto write_fail; + if (is_append) { + lba = wp; + } else { + if (lba != wp) { + SPDK_ERRLOG("Trying to write to zone with invalid address (lba 0x%lx, wp 0x%lx)\n", lba, wp); + rc = -EINVAL; + goto write_fail; + } } num_blocks_left = zone->zone_info.zone_id + zone->zone_info.capacity - wp; @@ -494,6 +506,7 @@ zone_block_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_ rc = zone_block_zone_management(bdev_node, dev_ch, bdev_io); break; case SPDK_BDEV_IO_TYPE_WRITE: + case SPDK_BDEV_IO_TYPE_ZONE_APPEND: rc = zone_block_write(bdev_node, dev_ch, bdev_io); break; case SPDK_BDEV_IO_TYPE_READ: @@ -523,6 +536,7 @@ zone_block_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type) case SPDK_BDEV_IO_TYPE_ZONE_MANAGEMENT: case SPDK_BDEV_IO_TYPE_WRITE: case SPDK_BDEV_IO_TYPE_READ: + case SPDK_BDEV_IO_TYPE_ZONE_APPEND: return true; default: return false; 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 cfbc7b88e..71fdca295 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 @@ -782,7 +782,7 @@ test_supported_io_types(void) bdev = create_and_get_vbdev("zone_dev1", name, num_zones, 1, true); 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_ZONE_APPEND) == true); 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); @@ -1044,6 +1044,28 @@ send_read_zone(struct bdev_zone_block *bdev, struct spdk_io_channel *ch, uint64_ bdev_io_cleanup(bdev_io); } +static void +send_append_zone(struct bdev_zone_block *bdev, struct spdk_io_channel *ch, uint64_t lba, + uint64_t blocks, uint32_t output_index, bool success, uint64_t wp) +{ + 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_ZONE_APPEND); + 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); + if (success) { + CU_ASSERT(bdev_io->u.bdev.offset_blocks == wp); + } + bdev_io_cleanup(bdev_io); +} + static void test_open_zone(void) { @@ -1366,6 +1388,78 @@ test_finish_zone(void) test_cleanup(); } +static void +test_append_zone(void) +{ + struct spdk_io_channel *ch; + struct bdev_zone_block *bdev; + char *name = "Nvme0n1"; + uint32_t num_zones = 20; + uint64_t zone_id, block_len, i; + 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); + + /* Append to full zone */ + zone_id = 0; + send_append_zone(bdev, ch, zone_id, 1, output_index, false, 0); + + /* Append out of device range */ + zone_id = g_block_cnt; + send_append_zone(bdev, ch, zone_id, 1, output_index, false, 0); + + /* Append 1 sector to zone 0 */ + zone_id = 0; + send_reset_zone(bdev, ch, zone_id, output_index, true); + send_append_zone(bdev, ch, zone_id, 1, output_index, true, zone_id); + send_zone_info(bdev, ch, zone_id, 1, SPDK_BDEV_ZONE_STATE_OPEN, output_index, true); + + /* Append to another zone */ + zone_id = bdev->bdev.zone_size; + send_reset_zone(bdev, ch, zone_id, output_index, true); + send_append_zone(bdev, ch, zone_id, 5, output_index, true, zone_id); + send_zone_info(bdev, ch, zone_id, zone_id + 5, SPDK_BDEV_ZONE_STATE_OPEN, output_index, true); + + /* Fill zone 0 and verify zone state change */ + zone_id = 0; + block_len = 15; + send_append_zone(bdev, ch, zone_id, block_len, output_index, true, 1); + block_len++; + for (i = block_len; i < bdev->zone_capacity; i += block_len) { + send_append_zone(bdev, ch, zone_id, block_len, output_index, true, i); + } + send_zone_info(bdev, ch, zone_id, bdev->bdev.zone_size, SPDK_BDEV_ZONE_STATE_FULL, output_index, + true); + + /* Append to two zones at once */ + for (i = 0; i < num_zones; i++) { + zone_id = i * bdev->bdev.zone_size; + send_reset_zone(bdev, ch, zone_id, output_index, true); + send_zone_info(bdev, ch, zone_id, zone_id, SPDK_BDEV_ZONE_STATE_EMPTY, output_index, true); + } + + zone_id = 0; + block_len = 16; + for (i = 0; i < bdev->zone_capacity - block_len; i += block_len) { + send_append_zone(bdev, ch, zone_id, block_len, output_index, true, zone_id + i); + } + send_append_zone(bdev, ch, zone_id, 32, output_index, false, 0); + /* 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; @@ -1391,7 +1485,8 @@ int main(int argc, char **argv) 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_close_zone", test_close_zone) == NULL || - CU_add_test(suite, "test_finish_zone", test_finish_zone) == NULL + CU_add_test(suite, "test_finish_zone", test_finish_zone) == NULL || + CU_add_test(suite, "test_append_zone", test_append_zone) == NULL ) { CU_cleanup_registry(); return CU_get_error();