Spdk/test/unit/lib/ftl/ftl_io.c/ftl_io_ut.c
paul luse a6dbe3721e update Intel copyright notices
per Intel policy to include file commit date using git cmd
below.  The policy does not apply to non-Intel (C) notices.

git log --follow -C90% --format=%ad --date default <file> | tail -1

and then pull just the 4 digit year from the result.

Intel copyrights were not added to files where Intel either had
no contribution ot the contribution lacked substance (ie license
header updates, formatting changes, etc).  Contribution date used
"--follow -C95%" to get the most accurate date.

Note that several files in this patch didn't end the license/(c)
block with a blank comment line so these were added as the vast
majority of files do have this last blank line.  Simply there for
consistency.

Signed-off-by: paul luse <paul.e.luse@intel.com>
Change-Id: Id5b7ce4f658fe87132f14139ead58d6e285c04d4
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15192
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Community-CI: Mellanox Build Bot
2022-11-10 08:28:53 +00:00

307 lines
11 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright (C) 2019 Intel Corporation.
* All rights reserved.
*/
#include "spdk/stdinc.h"
#include "spdk_cunit.h"
#include "common/lib/ut_multithread.c"
#include "ftl/ftl_io.c"
#include "ftl/utils/ftl_conf.c"
DEFINE_STUB(spdk_bdev_io_get_append_location, uint64_t, (struct spdk_bdev_io *bdev_io), 0);
DEFINE_STUB_V(spdk_bdev_close, (struct spdk_bdev_desc *desc));
DEFINE_STUB(spdk_bdev_desc_get_bdev, struct spdk_bdev *, (struct spdk_bdev_desc *desc), NULL);
DEFINE_STUB(spdk_bdev_get_optimal_open_zones, uint32_t, (const struct spdk_bdev *b), 1);
DEFINE_STUB(spdk_bdev_get_by_name, struct spdk_bdev *, (const char *bdev_name), NULL);
DEFINE_STUB(spdk_bdev_is_md_separate, bool, (const struct spdk_bdev *bdev), false);
DEFINE_STUB(spdk_bdev_is_zoned, bool, (const struct spdk_bdev *bdev), false);
DEFINE_STUB(spdk_bdev_zone_appendv, int, (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
struct iovec *iov, int iovcnt, uint64_t zone_id, uint64_t num_blocks,
spdk_bdev_io_completion_cb cb, void *cb_arg), 0);
DEFINE_STUB(spdk_bdev_get_zone_size, uint64_t, (const struct spdk_bdev *b), 1024);
DEFINE_STUB_V(spdk_bdev_free_io, (struct spdk_bdev_io *bdev_io));
DEFINE_STUB(spdk_bdev_get_buf_align, size_t, (const struct spdk_bdev *bdev), 64);
DEFINE_STUB(spdk_bdev_get_dif_type, enum spdk_dif_type,
(const struct spdk_bdev *bdev), 0);
DEFINE_STUB(spdk_bdev_get_name, const char *, (const struct spdk_bdev *bdev), "test");
DEFINE_STUB(spdk_bdev_get_write_unit_size, uint32_t,
(const struct spdk_bdev *bdev), 0);
DEFINE_STUB(spdk_bdev_io_type_supported, bool, (struct spdk_bdev *bdev,
enum spdk_bdev_io_type io_type), true);
DEFINE_STUB(spdk_bdev_open_ext, int,
(const char *bdev_name, bool write, spdk_bdev_event_cb_t event_cb,
void *event_ctx, struct spdk_bdev_desc **desc), 0);
DEFINE_STUB(spdk_bdev_read_blocks, int, (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
void *buf, uint64_t offset_blocks, uint64_t num_blocks,
spdk_bdev_io_completion_cb cb, void *cb_arg), 0);
DEFINE_STUB(spdk_bdev_write_blocks, int, (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
void *buf, uint64_t offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb,
void *cb_arg), 0);
DEFINE_STUB(spdk_bdev_write_blocks_with_md, int, (struct spdk_bdev_desc *desc,
struct spdk_io_channel *ch, void *buf, void *md, uint64_t offset_blocks,
uint64_t num_blocks, spdk_bdev_io_completion_cb cb, void *cb_arg), 0);
DEFINE_STUB(spdk_bdev_writev_blocks, int, (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), 0);
DEFINE_STUB(spdk_bdev_get_num_blocks, uint64_t, (const struct spdk_bdev *bdev), 1024);
DEFINE_STUB(spdk_bdev_get_md_size, uint32_t, (const struct spdk_bdev *bdev), 0);
DEFINE_STUB(spdk_bdev_get_block_size, uint32_t, (const struct spdk_bdev *bdev), 4096);
DEFINE_STUB_V(spdk_bdev_module_release_bdev, (struct spdk_bdev *bdev));
DEFINE_STUB(spdk_bdev_write_zeroes_blocks, int,
(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
uint64_t offset_blocks, uint64_t num_blocks,
spdk_bdev_io_completion_cb cb, void *cb_arg), 0);
DEFINE_STUB(spdk_mempool_create_ctor, struct spdk_mempool *,
(const char *name, size_t count, size_t ele_size, size_t cache_size,
int socket_id, spdk_mempool_obj_cb_t *obj_init, void *obj_init_arg), NULL);
DEFINE_STUB(spdk_mempool_obj_iter, uint32_t,
(struct spdk_mempool *mp, spdk_mempool_obj_cb_t obj_cb, void *obj_cb_arg), 0);
DEFINE_STUB_V(ftl_reloc, (struct ftl_reloc *reloc));
DEFINE_STUB_V(ftl_reloc_add, (struct ftl_reloc *reloc, struct ftl_band *band, size_t offset,
size_t num_blocks, int prio, bool defrag));
DEFINE_STUB_V(ftl_reloc_free, (struct ftl_reloc *reloc));
DEFINE_STUB_V(ftl_reloc_halt, (struct ftl_reloc *reloc));
DEFINE_STUB(ftl_reloc_init, struct ftl_reloc *, (struct spdk_ftl_dev *dev), NULL);
DEFINE_STUB(ftl_reloc_is_defrag_active, bool, (const struct ftl_reloc *reloc), false);
DEFINE_STUB(ftl_reloc_is_halted, bool, (const struct ftl_reloc *reloc), false);
DEFINE_STUB_V(ftl_reloc_resume, (struct ftl_reloc *reloc));
DEFINE_STUB_V(ftl_l2p_unpin, (struct spdk_ftl_dev *dev, uint64_t lba, uint64_t count));
DEFINE_STUB(ftl_p2l_ckpt_acquire, struct ftl_p2l_ckpt *, (struct spdk_ftl_dev *dev), NULL);
DEFINE_STUB_V(ftl_p2l_ckpt_release, (struct spdk_ftl_dev *dev, struct ftl_p2l_ckpt *ckpt));
DEFINE_STUB(ftl_l2p_get, ftl_addr, (struct spdk_ftl_dev *dev, uint64_t lba), 0);
DEFINE_STUB_V(ftl_mempool_put, (struct ftl_mempool *mpool, void *element));
#if defined(DEBUG)
DEFINE_STUB_V(ftl_trace_defrag_band, (struct spdk_ftl_dev *dev, const struct ftl_band *band));
DEFINE_STUB_V(ftl_trace_submission, (struct spdk_ftl_dev *dev, const struct ftl_io *io,
ftl_addr addr, size_t addr_cnt));
DEFINE_STUB_V(ftl_trace_lba_io_init, (struct spdk_ftl_dev *dev, const struct ftl_io *io));
DEFINE_STUB_V(ftl_trace_limits, (struct spdk_ftl_dev *dev, int limit, size_t num_free));
DEFINE_STUB(ftl_trace_alloc_id, uint64_t, (struct spdk_ftl_dev *dev), 0);
DEFINE_STUB_V(ftl_trace_completion, (struct spdk_ftl_dev *dev, const struct ftl_io *io,
enum ftl_trace_completion type));
DEFINE_STUB_V(ftl_trace_wbuf_fill, (struct spdk_ftl_dev *dev, const struct ftl_io *io));
DEFINE_STUB_V(ftl_trace_wbuf_pop, (struct spdk_ftl_dev *dev, const struct ftl_wbuf_entry *entry));
DEFINE_STUB_V(ftl_trace_write_band, (struct spdk_ftl_dev *dev, const struct ftl_band *band));
#endif
#if defined(FTL_DUMP_STATS)
DEFINE_STUB_V(ftl_dev_dump_stats, (const struct spdk_ftl_dev *dev));
#endif
struct ftl_io_channel_ctx {
struct ftl_io_channel *ioch;
};
struct ftl_io_channel *
ftl_io_channel_get_ctx(struct spdk_io_channel *ioch)
{
struct ftl_io_channel_ctx *ctx = spdk_io_channel_get_ctx(ioch);
return ctx->ioch;
}
struct spdk_io_channel *
spdk_bdev_get_io_channel(struct spdk_bdev_desc *bdev_desc)
{
return spdk_get_io_channel(bdev_desc);
}
static int
channel_create_cb(void *io_device, void *ctx)
{
return 0;
}
static void
channel_destroy_cb(void *io_device, void *ctx)
{
}
static struct spdk_ftl_dev *
setup_device(uint32_t num_threads, uint32_t xfer_size)
{
struct spdk_ftl_dev *dev;
struct ftl_io_channel *ioch;
struct ftl_io_channel_ctx *ctx;
allocate_threads(num_threads);
set_thread(0);
dev = calloc(1, sizeof(*dev));
SPDK_CU_ASSERT_FATAL(dev != NULL);
dev->core_thread = spdk_get_thread();
dev->ioch = calloc(1, SPDK_IO_CHANNEL_STRUCT_SIZE + sizeof(struct ftl_io_channel_ctx));
SPDK_CU_ASSERT_FATAL(dev->ioch != NULL);
ctx = spdk_io_channel_get_ctx(dev->ioch);
ctx->ioch = calloc(1, sizeof(*ctx->ioch));
ioch = ftl_io_channel_get_ctx(dev->ioch);
SPDK_CU_ASSERT_FATAL(ioch != NULL);
ioch->cq = spdk_ring_create(0, 1024, 0);
dev->conf = g_default_conf;
dev->xfer_size = xfer_size;
dev->base_bdev_desc = (struct spdk_bdev_desc *)0xdeadbeef;
dev->nv_cache.bdev_desc = (struct spdk_bdev_desc *)0xdead1234;
spdk_io_device_register(dev, channel_create_cb, channel_destroy_cb, 0, NULL);
spdk_io_device_register(dev->base_bdev_desc, channel_create_cb, channel_destroy_cb, 0, NULL);
spdk_io_device_register(dev->nv_cache.bdev_desc, channel_create_cb, channel_destroy_cb, 0, NULL);
TAILQ_INIT(&dev->ioch_queue);
return dev;
}
static void
free_device(struct spdk_ftl_dev *dev)
{
struct ftl_io_channel *ioch;
ioch = ftl_io_channel_get_ctx(dev->ioch);
spdk_ring_free(ioch->cq);
free(ioch);
spdk_io_device_unregister(dev, NULL);
spdk_io_device_unregister(dev->base_bdev_desc, NULL);
spdk_io_device_unregister(dev->nv_cache.bdev_desc, NULL);
while (!TAILQ_EMPTY(&dev->ioch_queue)) {
TAILQ_REMOVE(&dev->ioch_queue, TAILQ_FIRST(&dev->ioch_queue), entry);
}
free_threads();
free(dev->ioch);
free(dev->sb);
free(dev);
}
static void
setup_io(struct ftl_io *io, struct spdk_ftl_dev *dev, spdk_ftl_fn cb, void *ctx)
{
io->dev = dev;
io->user_fn = cb;
io->cb_ctx = ctx;
io->flags = 0;
io->ioch = dev->ioch;
}
static void
io_complete_cb(void *ctx, int status)
{
*(int *)ctx = status;
}
static void
test_completion(void)
{
struct spdk_ftl_dev *dev;
struct ftl_io_channel *ioch;
struct ftl_io io = { 0 }, *io_ring;
int req, status = 0;
dev = setup_device(1, FTL_NUM_LBA_IN_BLOCK);
ioch = ftl_io_channel_get_ctx(dev->ioch);
/* Setup IO and 'send' NUM_REQUESTS subrequests */
setup_io(&io, dev, io_complete_cb, &status);
io.status = -EIO;
#define NUM_REQUESTS 16
for (req = 0; req < NUM_REQUESTS; ++req) {
ftl_io_inc_req(&io);
CU_ASSERT_FALSE(ftl_io_done(&io));
}
CU_ASSERT_EQUAL(io.req_cnt, NUM_REQUESTS);
/* Complete all but one subrequest, make sure io still not marked as done */
for (req = 0; req < (NUM_REQUESTS - 1); ++req) {
ftl_io_dec_req(&io);
CU_ASSERT_FALSE(ftl_io_done(&io));
}
CU_ASSERT_EQUAL(io.req_cnt, 1);
/* Complete last subrequest, make sure it appears on the completion queue */
ftl_io_dec_req(&io);
CU_ASSERT_TRUE(ftl_io_done(&io));
ftl_io_complete(&io);
CU_ASSERT_EQUAL(spdk_ring_count(ioch->cq), 1);
/* Dequeue and check if the completion callback changes the status, this is usually done via poller */
spdk_ring_dequeue(ioch->cq, (void **)&io_ring, 1);
io_ring->user_fn(io_ring->cb_ctx, io_ring->status);
CU_ASSERT_EQUAL(status, -EIO);
free_device(dev);
}
static void
test_multiple_ios(void)
{
struct spdk_ftl_dev *dev;
struct ftl_io_channel *ioch;
struct ftl_io io[2] = { 0 }, *io_ring[2];
int status = -1;
dev = setup_device(1, FTL_NUM_LBA_IN_BLOCK);
ioch = ftl_io_channel_get_ctx(dev->ioch);
/* Send t2o IOs and check if both are in the completion queue */
setup_io(&io[0], dev, io_complete_cb, &status);
CU_ASSERT_EQUAL(spdk_ring_count(ioch->cq), 0);
ftl_io_complete(io);
CU_ASSERT_EQUAL(spdk_ring_count(ioch->cq), 1);
setup_io(&io[1], dev, io_complete_cb, &status);
ftl_io_complete(&io[1]);
CU_ASSERT_EQUAL(spdk_ring_count(ioch->cq), 2);
/* Dequeue and check if the completion callback changes the status, this is usually done via poller */
spdk_ring_dequeue(ioch->cq, (void **)io_ring, 2);
status = -1;
io_ring[0]->user_fn(io_ring[0]->cb_ctx, io_ring[0]->status);
CU_ASSERT_EQUAL(status, 0);
status = -1;
io_ring[1]->user_fn(io_ring[1]->cb_ctx, io_ring[1]->status);
CU_ASSERT_EQUAL(status, 0);
free_device(dev);
}
int
main(int argc, char **argv)
{
CU_pSuite suite;
unsigned int num_failures;
CU_set_error_action(CUEA_ABORT);
CU_initialize_registry();
suite = CU_add_suite("ftl_io_suite", NULL, NULL);
CU_ADD_TEST(suite, test_completion);
CU_ADD_TEST(suite, test_multiple_ios);
CU_basic_set_mode(CU_BRM_VERBOSE);
CU_basic_run_tests();
num_failures = CU_get_number_of_failures();
CU_cleanup_registry();
return num_failures;
}