Spdk/test/unit/lib/bdev/part.c/part_ut.c
Konrad Sztyber 22c0e97884 bdev: accel sequence support for write requests
It is now possible to submit a write request with a sequence of accel
operations that need to be executed before actually writing the data.

Such requests will be directly passed to a bdev module (so that it can
append subsequent operations to an accel sequence) if that bdev supports
accel sequences and the request doesn't need to be split.  If either of
these conditions are not met, bdev layer will execute all the
accumulated accel operations before passing the request to a bdev
module.

The reason for not submitting split IOs with an accel sequence is that
we would need to split that accel sequence too.  Currently, there's no
such functionality in accel, so we treat this case in the same way as if
the underlying bdev module didn't support accel sequences (it's executed
before bdev_io is split).

Signed-off-by: Konrad Sztyber <konrad.sztyber@intel.com>
Change-Id: I66c53b3a1a87a35ea2687292206c899f80aaed4a
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/16974
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
2023-03-13 21:02:27 +00:00

424 lines
10 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright (C) 2018 Intel Corporation.
* All rights reserved.
*/
#include "spdk_cunit.h"
#include "common/lib/ut_multithread.c"
#include "unit/lib/json_mock.c"
#include "spdk/config.h"
/* HACK: disable VTune integration so the unit test doesn't need VTune headers and libs to build */
#undef SPDK_CONFIG_VTUNE
#include "bdev/bdev.c"
#include "bdev/part.c"
struct ut_expected_io {
};
struct bdev_ut_channel {
TAILQ_HEAD(, spdk_bdev_io) outstanding_io;
uint32_t outstanding_io_count;
TAILQ_HEAD(, ut_expected_io) expected_io;
};
static uint32_t g_part_ut_io_device;
static struct bdev_ut_channel *g_bdev_ut_channel;
static int g_accel_io_device;
DEFINE_STUB(spdk_notify_send, uint64_t, (const char *type, const char *ctx), 0);
DEFINE_STUB(spdk_notify_type_register, struct spdk_notify_type *, (const char *type), NULL);
DEFINE_STUB(spdk_memory_domain_get_dma_device_id, const char *, (struct spdk_memory_domain *domain),
"test_domain");
DEFINE_STUB(spdk_memory_domain_get_dma_device_type, enum spdk_dma_device_type,
(struct spdk_memory_domain *domain), 0);
DEFINE_STUB(spdk_accel_sequence_finish, int,
(struct spdk_accel_sequence *seq, spdk_accel_completion_cb cb_fn, void *cb_arg), 0);
DEFINE_STUB_V(spdk_accel_sequence_abort, (struct spdk_accel_sequence *seq));
DEFINE_STUB(spdk_accel_append_copy, int,
(struct spdk_accel_sequence **seq, struct spdk_io_channel *ch, struct iovec *dst_iovs,
uint32_t dst_iovcnt, struct spdk_memory_domain *dst_domain, void *dst_domain_ctx,
struct iovec *src_iovs, uint32_t src_iovcnt, struct spdk_memory_domain *src_domain,
void *src_domain_ctx, int flags, spdk_accel_step_cb cb_fn, void *cb_arg), 0);
DEFINE_STUB(spdk_accel_get_memory_domain, struct spdk_memory_domain *, (void), NULL);
DEFINE_RETURN_MOCK(spdk_memory_domain_pull_data, int);
int
spdk_memory_domain_pull_data(struct spdk_memory_domain *src_domain, void *src_domain_ctx,
struct iovec *src_iov, uint32_t src_iov_cnt, struct iovec *dst_iov, uint32_t dst_iov_cnt,
spdk_memory_domain_data_cpl_cb cpl_cb, void *cpl_cb_arg)
{
HANDLE_RETURN_MOCK(spdk_memory_domain_pull_data);
cpl_cb(cpl_cb_arg, 0);
return 0;
}
DEFINE_RETURN_MOCK(spdk_memory_domain_push_data, int);
int
spdk_memory_domain_push_data(struct spdk_memory_domain *dst_domain, void *dst_domain_ctx,
struct iovec *dst_iov, uint32_t dst_iovcnt, struct iovec *src_iov, uint32_t src_iovcnt,
spdk_memory_domain_data_cpl_cb cpl_cb, void *cpl_cb_arg)
{
HANDLE_RETURN_MOCK(spdk_memory_domain_push_data);
cpl_cb(cpl_cb_arg, 0);
return 0;
}
struct spdk_io_channel *
spdk_accel_get_io_channel(void)
{
return spdk_get_io_channel(&g_accel_io_device);
}
static int
ut_accel_ch_create_cb(void *io_device, void *ctx)
{
return 0;
}
static void
ut_accel_ch_destroy_cb(void *io_device, void *ctx)
{
}
static int
ut_part_setup(void)
{
spdk_io_device_register(&g_accel_io_device, ut_accel_ch_create_cb,
ut_accel_ch_destroy_cb, 0, NULL);
return 0;
}
static int
ut_part_teardown(void)
{
spdk_io_device_unregister(&g_accel_io_device, NULL);
return 0;
}
static void
_part_cleanup(struct spdk_bdev_part *part)
{
spdk_io_device_unregister(part, NULL);
free(part->internal.bdev.name);
free(part->internal.bdev.product_name);
}
static struct spdk_io_channel *
part_ut_get_io_channel(void *ctx)
{
return spdk_get_io_channel(&g_part_ut_io_device);
}
void
spdk_scsi_nvme_translate(const struct spdk_bdev_io *bdev_io,
int *sc, int *sk, int *asc, int *ascq)
{
}
static int
bdev_ut_create_ch(void *io_device, void *ctx_buf)
{
struct bdev_ut_channel *ch = ctx_buf;
CU_ASSERT(g_bdev_ut_channel == NULL);
g_bdev_ut_channel = ch;
g_part_ut_io_device++;
TAILQ_INIT(&ch->outstanding_io);
ch->outstanding_io_count = 0;
TAILQ_INIT(&ch->expected_io);
return 0;
}
static void
bdev_ut_destroy_ch(void *io_device, void *ctx_buf)
{
CU_ASSERT(g_bdev_ut_channel != NULL);
g_bdev_ut_channel = NULL;
g_part_ut_io_device--;
}
struct spdk_bdev_module bdev_ut_if;
static int
bdev_ut_module_init(void)
{
spdk_io_device_register(&g_part_ut_io_device, bdev_ut_create_ch, bdev_ut_destroy_ch,
sizeof(struct bdev_ut_channel), NULL);
spdk_bdev_module_init_done(&bdev_ut_if);
return 0;
}
static void
bdev_ut_module_fini(void)
{
spdk_io_device_unregister(&g_part_ut_io_device, NULL);
}
struct spdk_bdev_module bdev_ut_if = {
.name = "bdev_ut",
.module_init = bdev_ut_module_init,
.module_fini = bdev_ut_module_fini,
.async_init = true,
};
static void vbdev_ut_examine(struct spdk_bdev *bdev);
static int
vbdev_ut_module_init(void)
{
return 0;
}
static void
vbdev_ut_module_fini(void)
{
}
struct spdk_bdev_module vbdev_ut_if = {
.name = "vbdev_ut",
.module_init = vbdev_ut_module_init,
.module_fini = vbdev_ut_module_fini,
.examine_config = vbdev_ut_examine,
};
SPDK_BDEV_MODULE_REGISTER(bdev_ut, &bdev_ut_if)
SPDK_BDEV_MODULE_REGISTER(vbdev_ut, &vbdev_ut_if)
static void
vbdev_ut_examine(struct spdk_bdev *bdev)
{
spdk_bdev_module_examine_done(&vbdev_ut_if);
}
static int
__destruct(void *ctx)
{
return 0;
}
static struct spdk_bdev_fn_table base_fn_table = {
.destruct = __destruct,
.get_io_channel = part_ut_get_io_channel,
};
static struct spdk_bdev_fn_table part_fn_table = {
.destruct = __destruct,
};
static void
bdev_init_cb(void *arg, int rc)
{
CU_ASSERT(rc == 0);
}
static void
bdev_fini_cb(void *arg)
{
}
static void
ut_init_bdev(void)
{
int rc;
rc = spdk_iobuf_initialize();
CU_ASSERT(rc == 0);
spdk_bdev_initialize(bdev_init_cb, NULL);
poll_threads();
}
static void
ut_fini_bdev(void)
{
spdk_bdev_finish(bdev_fini_cb, NULL);
spdk_iobuf_finish(bdev_fini_cb, NULL);
poll_threads();
}
static void
bdev_ut_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx)
{
}
static void
part_test(void)
{
struct spdk_bdev_part_base *base;
struct spdk_bdev_part part1 = {};
struct spdk_bdev_part part2 = {};
struct spdk_bdev_part part3 = {};
struct spdk_bdev bdev_base = {};
SPDK_BDEV_PART_TAILQ tailq = TAILQ_HEAD_INITIALIZER(tailq);
int rc;
bdev_base.name = "base";
bdev_base.fn_table = &base_fn_table;
bdev_base.module = &bdev_ut_if;
rc = spdk_bdev_register(&bdev_base);
CU_ASSERT(rc == 0);
rc = spdk_bdev_part_base_construct_ext("base", NULL, &vbdev_ut_if,
&part_fn_table, &tailq, NULL,
NULL, 0, NULL, NULL, &base);
CU_ASSERT(rc == 0);
SPDK_CU_ASSERT_FATAL(base != NULL);
rc = spdk_bdev_part_construct(&part1, base, "test1", 0, 100, "test");
SPDK_CU_ASSERT_FATAL(rc == 0);
SPDK_CU_ASSERT_FATAL(base->ref == 1);
SPDK_CU_ASSERT_FATAL(base->claimed == true);
rc = spdk_bdev_part_construct(&part2, base, "test2", 100, 100, "test");
SPDK_CU_ASSERT_FATAL(rc == 0);
SPDK_CU_ASSERT_FATAL(base->ref == 2);
SPDK_CU_ASSERT_FATAL(base->claimed == true);
rc = spdk_bdev_part_construct(&part3, base, "test1", 0, 100, "test");
SPDK_CU_ASSERT_FATAL(rc != 0);
SPDK_CU_ASSERT_FATAL(base->ref == 2);
SPDK_CU_ASSERT_FATAL(base->claimed == true);
spdk_bdev_part_base_hotremove(base, &tailq);
spdk_bdev_part_base_free(base);
_part_cleanup(&part1);
_part_cleanup(&part2);
spdk_bdev_unregister(&bdev_base, NULL, NULL);
poll_threads();
}
static void
part_free_test(void)
{
struct spdk_bdev_part_base *base = NULL;
struct spdk_bdev_part *part;
struct spdk_bdev bdev_base = {};
SPDK_BDEV_PART_TAILQ tailq = TAILQ_HEAD_INITIALIZER(tailq);
int rc;
bdev_base.name = "base";
bdev_base.fn_table = &base_fn_table;
bdev_base.module = &bdev_ut_if;
rc = spdk_bdev_register(&bdev_base);
CU_ASSERT(rc == 0);
poll_threads();
rc = spdk_bdev_part_base_construct_ext("base", NULL, &vbdev_ut_if,
&part_fn_table, &tailq, NULL,
NULL, 0, NULL, NULL, &base);
CU_ASSERT(rc == 0);
CU_ASSERT(TAILQ_EMPTY(&tailq));
SPDK_CU_ASSERT_FATAL(base != NULL);
part = calloc(1, sizeof(*part));
SPDK_CU_ASSERT_FATAL(part != NULL);
rc = spdk_bdev_part_construct(part, base, "test", 0, 100, "test");
SPDK_CU_ASSERT_FATAL(rc == 0);
poll_threads();
CU_ASSERT(!TAILQ_EMPTY(&tailq));
spdk_bdev_unregister(&part->internal.bdev, NULL, NULL);
poll_threads();
rc = spdk_bdev_part_free(part);
CU_ASSERT(rc == 1);
poll_threads();
CU_ASSERT(TAILQ_EMPTY(&tailq));
spdk_bdev_unregister(&bdev_base, NULL, NULL);
poll_threads();
}
static void
part_get_io_channel_test(void)
{
struct spdk_bdev_part_base *base = NULL;
struct spdk_bdev_desc *desc = NULL;
struct spdk_io_channel *io_ch;
struct spdk_bdev_part *part;
struct spdk_bdev bdev_base = {};
SPDK_BDEV_PART_TAILQ tailq = TAILQ_HEAD_INITIALIZER(tailq);
int rc;
ut_init_bdev();
bdev_base.name = "base";
bdev_base.blocklen = 512;
bdev_base.blockcnt = 1024;
bdev_base.fn_table = &base_fn_table;
bdev_base.module = &bdev_ut_if;
rc = spdk_bdev_register(&bdev_base);
CU_ASSERT(rc == 0);
rc = spdk_bdev_part_base_construct_ext("base", NULL, &vbdev_ut_if,
&part_fn_table, &tailq, NULL,
NULL, 100, NULL, NULL, &base);
CU_ASSERT(rc == 0);
CU_ASSERT(TAILQ_EMPTY(&tailq));
SPDK_CU_ASSERT_FATAL(base != NULL);
part = calloc(1, sizeof(*part));
SPDK_CU_ASSERT_FATAL(part != NULL);
rc = spdk_bdev_part_construct(part, base, "test", 0, 100, "test");
SPDK_CU_ASSERT_FATAL(rc == 0);
CU_ASSERT(!TAILQ_EMPTY(&tailq));
rc = spdk_bdev_open_ext("test", true, bdev_ut_event_cb, NULL, &desc);
CU_ASSERT(rc == 0);
SPDK_CU_ASSERT_FATAL(desc != NULL);
CU_ASSERT(&part->internal.bdev == spdk_bdev_desc_get_bdev(desc));
io_ch = spdk_bdev_get_io_channel(desc);
CU_ASSERT(io_ch != NULL);
CU_ASSERT(g_part_ut_io_device == 1);
spdk_put_io_channel(io_ch);
spdk_bdev_close(desc);
spdk_bdev_unregister(&part->internal.bdev, NULL, NULL);
poll_threads();
CU_ASSERT(g_part_ut_io_device == 0);
rc = spdk_bdev_part_free(part);
CU_ASSERT(rc == 1);
poll_threads();
CU_ASSERT(TAILQ_EMPTY(&tailq));
spdk_bdev_unregister(&bdev_base, NULL, NULL);
ut_fini_bdev();
}
int
main(int argc, char **argv)
{
CU_pSuite suite = NULL;
unsigned int num_failures;
CU_set_error_action(CUEA_ABORT);
CU_initialize_registry();
suite = CU_add_suite("bdev_part", ut_part_setup, ut_part_teardown);
CU_ADD_TEST(suite, part_test);
CU_ADD_TEST(suite, part_free_test);
CU_ADD_TEST(suite, part_get_io_channel_test);
allocate_cores(1);
allocate_threads(1);
set_thread(0);
CU_basic_set_mode(CU_BRM_VERBOSE);
CU_basic_run_tests();
num_failures = CU_get_number_of_failures();
CU_cleanup_registry();
free_threads();
free_cores();
return num_failures;
}