bdevio: refactor to use event framework and I/O channels

Signed-off-by: Jim Harris <james.r.harris@intel.com>
Change-Id: Icea93b065b186ec998fb64bc0fc420a57060f3f9
This commit is contained in:
Jim Harris 2016-10-11 09:02:37 -07:00
parent 81b3d6c9fc
commit f7830911e2
3 changed files with 147 additions and 147 deletions

View File

@ -34,10 +34,7 @@
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../..) SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../..)
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
DIRS-y = bdevperf DIRS-y = bdevio bdevperf
# Disable bdevio build for now - it needs to be rewritten to be
# event based.
#DIRS-y = bdevio
.PHONY: all clean $(DIRS-y) .PHONY: all clean $(DIRS-y)

View File

@ -44,6 +44,7 @@
#include "spdk/copy_engine.h" #include "spdk/copy_engine.h"
#include "spdk/env.h" #include "spdk/env.h"
#include "spdk/log.h" #include "spdk/log.h"
#include "spdk/io_channel.h"
#include "CUnit/Basic.h" #include "CUnit/Basic.h"
@ -52,13 +53,33 @@
#include "../common.c" #include "../common.c"
pthread_mutex_t g_test_mutex;
pthread_cond_t g_test_cond;
struct io_target { struct io_target {
struct spdk_bdev *bdev; struct spdk_bdev *bdev;
struct spdk_io_channel *ch;
struct io_target *next; struct io_target *next;
}; };
struct bdevio_request {
char *buf;
int data_len;
uint64_t offset;
struct iovec iov;
struct io_target *target;
};
struct io_target *g_io_targets = NULL; struct io_target *g_io_targets = NULL;
static void
wake_ut_thread(void)
{
pthread_mutex_lock(&g_test_mutex);
pthread_cond_signal(&g_test_cond);
pthread_mutex_unlock(&g_test_mutex);
}
static int static int
bdevio_construct_targets(void) bdevio_construct_targets(void)
{ {
@ -87,8 +108,7 @@ bdevio_construct_targets(void)
return 0; return 0;
} }
static int complete; static enum spdk_bdev_io_status g_completion_status;
static enum spdk_bdev_io_status completion_status_per_io;
static void static void
initialize_buffer(char **buf, int pattern, int size) initialize_buffer(char **buf, int pattern, int size)
@ -100,72 +120,93 @@ initialize_buffer(char **buf, int pattern, int size)
static void static void
quick_test_complete(spdk_event_t event) quick_test_complete(spdk_event_t event)
{ {
struct bdevio_request *req = spdk_event_get_arg1(event);
struct spdk_bdev_io *bdev_io = spdk_event_get_arg2(event); struct spdk_bdev_io *bdev_io = spdk_event_get_arg2(event);
completion_status_per_io = bdev_io->status; spdk_put_io_channel(req->target->ch);
complete = 1; g_completion_status = bdev_io->status;
spdk_bdev_free_io(bdev_io); spdk_bdev_free_io(bdev_io);
wake_ut_thread();
} }
static int static void
check_io_completion(void) __blockdev_write(spdk_event_t event)
{ {
int rc; struct bdevio_request *req = spdk_event_get_arg1(event);
struct spdk_bdev *bdev; struct io_target *target = req->target;
struct spdk_bdev_io *bdev_io;
rc = 0; req->iov.iov_base = req->buf;
while (!complete) { req->iov.iov_len = req->data_len;
bdev = spdk_bdev_first(); target->ch = spdk_bdev_get_io_channel(target->bdev, SPDK_IO_PRIORITY_DEFAULT);
while (bdev != NULL) { bdev_io = spdk_bdev_writev(target->bdev, target->ch, &req->iov, 1, req->offset,
spdk_bdev_do_work(bdev); req->data_len, quick_test_complete, req);
bdev = spdk_bdev_next(bdev); if (!bdev_io) {
} spdk_put_io_channel(target->ch);
spdk_event_queue_run_all(rte_lcore_id()); g_completion_status = SPDK_BDEV_IO_STATUS_FAILED;
wake_ut_thread();
} }
return rc;
} }
struct iovec iov; static void
blockdev_write(struct io_target *target, char *tx_buf,
static int
blockdev_write(struct io_target *target, void *bdev_task_ctx, char *tx_buf,
uint64_t offset, int data_len) uint64_t offset, int data_len)
{ {
struct spdk_bdev_io *bdev_io; struct bdevio_request req;
spdk_event_t event;
complete = 0; req.target = target;
completion_status_per_io = SPDK_BDEV_IO_STATUS_FAILED; req.buf = tx_buf;
req.data_len = data_len;
req.offset = offset;
req.iov.iov_base = tx_buf;
req.iov.iov_len = data_len;
iov.iov_base = tx_buf; g_completion_status = SPDK_BDEV_IO_STATUS_FAILED;
iov.iov_len = data_len;
bdev_io = spdk_bdev_writev(target->bdev, &iov, 1, (uint64_t)offset,
iov.iov_len, quick_test_complete,
bdev_task_ctx);
if (!bdev_io) {
return -1;
}
return data_len; event = spdk_event_allocate(1, __blockdev_write, &req, NULL, NULL);
pthread_mutex_lock(&g_test_mutex);
spdk_event_call(event);
pthread_cond_wait(&g_test_cond, &g_test_mutex);
pthread_mutex_unlock(&g_test_mutex);
} }
static int static void
blockdev_read(struct io_target *target, void *bdev_task_ctx, char *rx_buf, __blockdev_read(spdk_event_t event)
uint64_t offset, int data_len)
{ {
struct bdevio_request *req = spdk_event_get_arg1(event);
struct io_target *target = req->target;
struct spdk_bdev_io *bdev_io; struct spdk_bdev_io *bdev_io;
complete = 0; target->ch = spdk_bdev_get_io_channel(target->bdev, SPDK_IO_PRIORITY_DEFAULT);
completion_status_per_io = SPDK_BDEV_IO_STATUS_FAILED; bdev_io = spdk_bdev_read(target->bdev, target->ch, req->buf, req->offset,
req->data_len, quick_test_complete, req);
bdev_io = spdk_bdev_read(target->bdev, rx_buf, offset, data_len,
quick_test_complete, bdev_task_ctx);
if (!bdev_io) { if (!bdev_io) {
return -1; spdk_put_io_channel(target->ch);
g_completion_status = SPDK_BDEV_IO_STATUS_FAILED;
wake_ut_thread();
} }
}
return data_len; static void
blockdev_read(struct io_target *target, char *rx_buf,
uint64_t offset, int data_len)
{
struct bdevio_request req;
spdk_event_t event;
req.target = target;
req.buf = rx_buf;
req.data_len = data_len;
req.offset = offset;
g_completion_status = SPDK_BDEV_IO_STATUS_FAILED;
event = spdk_event_allocate(1, __blockdev_read, &req, NULL, NULL);
pthread_mutex_lock(&g_test_mutex);
spdk_event_call(event);
pthread_cond_wait(&g_test_cond, &g_test_mutex);
pthread_mutex_unlock(&g_test_mutex);
} }
static int static int
@ -185,7 +226,6 @@ blockdev_write_read(uint32_t data_length, int pattern, uint64_t offset,
int expected_rc) int expected_rc)
{ {
struct io_target *target; struct io_target *target;
char bdev_task_ctx[BDEV_TASK_ARRAY_SIZE];
char *tx_buf = NULL; char *tx_buf = NULL;
char *rx_buf = NULL; char *rx_buf = NULL;
int rc; int rc;
@ -200,37 +240,23 @@ blockdev_write_read(uint32_t data_length, int pattern, uint64_t offset,
initialize_buffer(&tx_buf, pattern, data_length); initialize_buffer(&tx_buf, pattern, data_length);
initialize_buffer(&rx_buf, 0, data_length); initialize_buffer(&rx_buf, 0, data_length);
rc = blockdev_write(target, (void *)bdev_task_ctx, tx_buf, blockdev_write(target, tx_buf, offset, data_length);
offset, data_length);
/* Assert the rc of the respective blockdev */ if (expected_rc == 0) {
CU_ASSERT_EQUAL(rc, expected_rc); CU_ASSERT_EQUAL(g_completion_status, SPDK_BDEV_IO_STATUS_SUCCESS);
/* If the write was successful, the function returns the data_length
* and the completion_status_per_io is 0 */
if (rc < (int)data_length) {
CU_ASSERT_EQUAL(completion_status_per_io, SPDK_BDEV_IO_STATUS_FAILED);
} else { } else {
check_io_completion(); CU_ASSERT_EQUAL(g_completion_status, SPDK_BDEV_IO_STATUS_FAILED);
CU_ASSERT_EQUAL(completion_status_per_io, SPDK_BDEV_IO_STATUS_SUCCESS);
} }
rc = blockdev_read(target, (void *)bdev_task_ctx, rx_buf, blockdev_read(target, rx_buf, offset, data_length);
offset, data_length);
/* Assert the rc of the respective blockdev */ if (expected_rc == 0) {
CU_ASSERT_EQUAL(rc, expected_rc); CU_ASSERT_EQUAL(g_completion_status, SPDK_BDEV_IO_STATUS_SUCCESS);
/* If the read was successful, the function returns the data_length
* and the completion_status_per_io is 0 */
if (rc < (int)data_length) {
CU_ASSERT_EQUAL(completion_status_per_io, SPDK_BDEV_IO_STATUS_FAILED);
} else { } else {
check_io_completion(); CU_ASSERT_EQUAL(g_completion_status, SPDK_BDEV_IO_STATUS_FAILED);
CU_ASSERT_EQUAL(completion_status_per_io, SPDK_BDEV_IO_STATUS_SUCCESS);
} }
if (completion_status_per_io == SPDK_BDEV_IO_STATUS_SUCCESS) { if (g_completion_status == SPDK_BDEV_IO_STATUS_SUCCESS) {
rc = blockdev_write_read_data_match(rx_buf, tx_buf, data_length); rc = blockdev_write_read_data_match(rx_buf, tx_buf, data_length);
/* Assert the write by comparing it with values read /* Assert the write by comparing it with values read
* from each blockdev */ * from each blockdev */
@ -255,8 +281,8 @@ blockdev_write_read_4k(void)
offset = 0; offset = 0;
pattern = 0xA3; pattern = 0xA3;
/* Params are valid, hence the expected return value /* Params are valid, hence the expected return value
* of write and read for all blockdevs is the data_length */ * of write and read for all blockdevs is 0. */
expected_rc = data_length; expected_rc = 0;
blockdev_write_read(data_length, pattern, offset, expected_rc); blockdev_write_read(data_length, pattern, offset, expected_rc);
} }
@ -275,8 +301,8 @@ blockdev_write_read_512Bytes(void)
offset = 2048; offset = 2048;
pattern = 0xA3; pattern = 0xA3;
/* Params are valid, hence the expected return value /* Params are valid, hence the expected return value
* of write and read for all blockdevs is the data_length */ * of write and read for all blockdevs is 0. */
expected_rc = data_length; expected_rc = 0;
blockdev_write_read(data_length, pattern, offset, expected_rc); blockdev_write_read(data_length, pattern, offset, expected_rc);
} }
@ -295,8 +321,8 @@ blockdev_write_read_size_gt_128k(void)
offset = 2048; offset = 2048;
pattern = 0xA3; pattern = 0xA3;
/* Params are valid, hence the expected return value /* Params are valid, hence the expected return value
* of write and read for all blockdevs is the data_length */ * of write and read for all blockdevs is 0. */
expected_rc = data_length; expected_rc = 0;
blockdev_write_read(data_length, pattern, offset, expected_rc); blockdev_write_read(data_length, pattern, offset, expected_rc);
} }
@ -326,7 +352,6 @@ blockdev_write_read_offset_plus_nbytes_equals_bdev_size(void)
{ {
struct io_target *target; struct io_target *target;
struct spdk_bdev *bdev; struct spdk_bdev *bdev;
char bdev_task_ctx[BDEV_TASK_ARRAY_SIZE];
char *tx_buf = NULL; char *tx_buf = NULL;
char *rx_buf = NULL; char *rx_buf = NULL;
uint64_t offset; uint64_t offset;
@ -344,27 +369,11 @@ blockdev_write_read_offset_plus_nbytes_equals_bdev_size(void)
initialize_buffer(&tx_buf, 0xA3, bdev->blocklen); initialize_buffer(&tx_buf, 0xA3, bdev->blocklen);
initialize_buffer(&rx_buf, 0, bdev->blocklen); initialize_buffer(&rx_buf, 0, bdev->blocklen);
rc = blockdev_write(target, (void *)bdev_task_ctx, tx_buf, blockdev_write(target, tx_buf, offset, bdev->blocklen);
offset, bdev->blocklen); CU_ASSERT_EQUAL(g_completion_status, SPDK_BDEV_IO_STATUS_SUCCESS);
/* Assert the rc of the respective blockdev */ blockdev_read(target, rx_buf, offset, bdev->blocklen);
CU_ASSERT_EQUAL(rc, (int)bdev->blocklen); CU_ASSERT_EQUAL(g_completion_status, SPDK_BDEV_IO_STATUS_SUCCESS);
/* If the write was successful, the function returns the data_length
* and the completion_status_per_io is 0 */
check_io_completion();
CU_ASSERT_EQUAL(completion_status_per_io, SPDK_BDEV_IO_STATUS_SUCCESS);
rc = blockdev_read(target, (void *)bdev_task_ctx, rx_buf,
offset, bdev->blocklen);
/* Assert the rc of the respective blockdev */
CU_ASSERT_EQUAL(rc, (int)bdev->blocklen);
/* If the read was successful, the function returns the data_length
* and the completion_status_per_io is 0 */
check_io_completion();
CU_ASSERT_EQUAL(completion_status_per_io, SPDK_BDEV_IO_STATUS_SUCCESS);
rc = blockdev_write_read_data_match(rx_buf, tx_buf, bdev->blocklen); rc = blockdev_write_read_data_match(rx_buf, tx_buf, bdev->blocklen);
/* Assert the write by comparing it with values read /* Assert the write by comparing it with values read
@ -380,22 +389,16 @@ blockdev_write_read_offset_plus_nbytes_gt_bdev_size(void)
{ {
struct io_target *target; struct io_target *target;
struct spdk_bdev *bdev; struct spdk_bdev *bdev;
char bdev_task_ctx[BDEV_TASK_ARRAY_SIZE];
char *tx_buf = NULL; char *tx_buf = NULL;
char *rx_buf = NULL; char *rx_buf = NULL;
int data_length; int data_length;
uint64_t offset; uint64_t offset;
int pattern; int pattern;
int expected_rc;
int rc;
/* Tests the overflow condition of the blockdevs. */ /* Tests the overflow condition of the blockdevs. */
data_length = 4096; data_length = 4096;
CU_ASSERT_TRUE(data_length < BUFFER_SIZE); CU_ASSERT_TRUE(data_length < BUFFER_SIZE);
pattern = 0xA3; pattern = 0xA3;
/* Params are invalid, hence the expected return value
* of write and read is < 0.*/
expected_rc = -1;
target = g_io_targets; target = g_io_targets;
while (target != NULL) { while (target != NULL) {
@ -409,25 +412,11 @@ blockdev_write_read_offset_plus_nbytes_gt_bdev_size(void)
initialize_buffer(&tx_buf, pattern, data_length); initialize_buffer(&tx_buf, pattern, data_length);
initialize_buffer(&rx_buf, 0, data_length); initialize_buffer(&rx_buf, 0, data_length);
rc = blockdev_write(target, (void *)bdev_task_ctx, tx_buf, blockdev_write(target, tx_buf, offset, data_length);
offset, data_length); CU_ASSERT_EQUAL(g_completion_status, SPDK_BDEV_IO_STATUS_FAILED);
/* Assert the rc of the respective blockdev */ blockdev_read(target, rx_buf, offset, data_length);
CU_ASSERT_EQUAL(rc, expected_rc); CU_ASSERT_EQUAL(g_completion_status, SPDK_BDEV_IO_STATUS_FAILED);
/* If the write failed, the function returns rc<data_length
* and the completion_status_per_io is SPDK_BDEV_IO_STATUS_FAILED */
CU_ASSERT_EQUAL(completion_status_per_io, SPDK_BDEV_IO_STATUS_FAILED);
rc = blockdev_read(target, (void *)bdev_task_ctx, rx_buf,
offset, data_length);
/* Assert the rc of the respective blockdev */
CU_ASSERT_EQUAL(rc, expected_rc);
/* If the read failed, the function returns rc<data_length
* and the completion_status_per_io is SPDK_BDEV_IO_STATUS_FAILED */
CU_ASSERT_EQUAL(completion_status_per_io, SPDK_BDEV_IO_STATUS_FAILED);
target = target->next; target = target->next;
} }
@ -468,8 +457,8 @@ blockdev_overlapped_write_read_8k(void)
offset = 0; offset = 0;
pattern = 0xA3; pattern = 0xA3;
/* Params are valid, hence the expected return value /* Params are valid, hence the expected return value
* of write and read for all blockdevs is the data_length */ * of write and read for all blockdevs is 0. */
expected_rc = data_length; expected_rc = 0;
/* Assert the write by comparing it with values read /* Assert the write by comparing it with values read
* from the same offset for each blockdev */ * from the same offset for each blockdev */
blockdev_write_read(data_length, pattern, offset, expected_rc); blockdev_write_read(data_length, pattern, offset, expected_rc);
@ -487,33 +476,27 @@ blockdev_overlapped_write_read_8k(void)
} }
int static void
main(int argc, char **argv) test_main(spdk_event_t event)
{ {
CU_pSuite suite = NULL; CU_pSuite suite = NULL;
const char *config_file;
unsigned int num_failures; unsigned int num_failures;
if (argc == 1) {
config_file = "/usr/local/etc/spdk/iscsi.conf";
} else {
config_file = argv[1];
}
bdevtest_init(config_file, "0x1");
if (bdevio_construct_targets() < 0) { if (bdevio_construct_targets() < 0) {
return 1; spdk_app_stop(-1);
return;
} }
if (CU_initialize_registry() != CUE_SUCCESS) { if (CU_initialize_registry() != CUE_SUCCESS) {
return CU_get_error(); spdk_app_stop(CU_get_error());
return;
} }
suite = CU_add_suite("components_suite", NULL, NULL); suite = CU_add_suite("components_suite", NULL, NULL);
if (suite == NULL) { if (suite == NULL) {
CU_cleanup_registry(); CU_cleanup_registry();
return CU_get_error(); spdk_app_stop(CU_get_error());
return;
} }
if ( if (
@ -534,12 +517,34 @@ main(int argc, char **argv)
blockdev_overlapped_write_read_8k) == NULL blockdev_overlapped_write_read_8k) == NULL
) { ) {
CU_cleanup_registry(); CU_cleanup_registry();
return CU_get_error(); spdk_app_stop(CU_get_error());
return;
} }
pthread_mutex_init(&g_test_mutex, NULL);
pthread_cond_init(&g_test_cond, NULL);
CU_basic_set_mode(CU_BRM_VERBOSE); CU_basic_set_mode(CU_BRM_VERBOSE);
CU_basic_run_tests(); CU_basic_run_tests();
num_failures = CU_get_number_of_failures(); num_failures = CU_get_number_of_failures();
CU_cleanup_registry(); CU_cleanup_registry();
spdk_app_stop(num_failures);
}
int
main(int argc, char **argv)
{
const char *config_file;
int num_failures;
if (argc == 1) {
config_file = "/usr/local/etc/spdk/iscsi.conf";
} else {
config_file = argv[1];
}
bdevtest_init(config_file, "0x3");
num_failures = spdk_app_start(test_main, NULL, NULL);
spdk_app_fini();
return num_failures; return num_failures;
} }

View File

@ -10,12 +10,10 @@ testdir=$(readlink -f $(dirname $0))
timing_enter blockdev timing_enter blockdev
# bdevio is disconnected from the build currently - it needs to be rewritten timing_enter bounds
# as an event-based test program. $testdir/bdevio/bdevio $testdir/bdev.conf
#timing_enter bounds process_core
#$testdir/bdevio/bdevio $testdir/bdev.conf timing_exit bounds
#process_core
#timing_exit bounds
timing_enter verify timing_enter verify
$testdir/bdevperf/bdevperf -c $testdir/bdev.conf -q 32 -s 4096 -w verify -t 5 $testdir/bdevperf/bdevperf -c $testdir/bdev.conf -q 32 -s 4096 -w verify -t 5