bdev/null: complete requests asynchronously
To better match bdev modules like nvme, complete requests for the bdev/null driver asynchronously. This will be done by allocating IO channels that register a poller and keep a TAILQ of bdev IO to be completed next time the poller runs. This is actually more efficient as well, since completing I/O in submit_request context defers the completion using an event. A benchmark of bdevperf with split running on top of null module shows this patch increases throughput 20%. Signed-off-by: Jim Harris <james.r.harris@intel.com> Change-Id: I8c664234660c249fd8ec8d9244eed33502d4103e Reviewed-on: https://review.gerrithub.io/392528 Tested-by: SPDK Automated Test System <sys_sgsw@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com> Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
This commit is contained in:
parent
d8b8bc4353
commit
45697d33ff
@ -50,6 +50,11 @@ struct null_bdev {
|
|||||||
TAILQ_ENTRY(null_bdev) tailq;
|
TAILQ_ENTRY(null_bdev) tailq;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct null_io_channel {
|
||||||
|
struct spdk_poller *poller;
|
||||||
|
TAILQ_HEAD(, spdk_bdev_io) io;
|
||||||
|
};
|
||||||
|
|
||||||
static TAILQ_HEAD(, null_bdev) g_null_bdev_head;
|
static TAILQ_HEAD(, null_bdev) g_null_bdev_head;
|
||||||
static void *g_null_read_buf;
|
static void *g_null_read_buf;
|
||||||
|
|
||||||
@ -66,8 +71,10 @@ bdev_null_destruct(void *ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
bdev_null_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
|
bdev_null_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io)
|
||||||
{
|
{
|
||||||
|
struct null_io_channel *ch = spdk_io_channel_get_ctx(_ch);
|
||||||
|
|
||||||
switch (bdev_io->type) {
|
switch (bdev_io->type) {
|
||||||
case SPDK_BDEV_IO_TYPE_READ:
|
case SPDK_BDEV_IO_TYPE_READ:
|
||||||
if (bdev_io->u.bdev.iovs[0].iov_base == NULL) {
|
if (bdev_io->u.bdev.iovs[0].iov_base == NULL) {
|
||||||
@ -75,12 +82,12 @@ bdev_null_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_i
|
|||||||
bdev_io->u.bdev.iovs[0].iov_base = g_null_read_buf;
|
bdev_io->u.bdev.iovs[0].iov_base = g_null_read_buf;
|
||||||
bdev_io->u.bdev.iovs[0].iov_len = bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen;
|
bdev_io->u.bdev.iovs[0].iov_len = bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen;
|
||||||
}
|
}
|
||||||
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
|
TAILQ_INSERT_TAIL(&ch->io, bdev_io, module_link);
|
||||||
break;
|
break;
|
||||||
case SPDK_BDEV_IO_TYPE_WRITE:
|
case SPDK_BDEV_IO_TYPE_WRITE:
|
||||||
case SPDK_BDEV_IO_TYPE_WRITE_ZEROES:
|
case SPDK_BDEV_IO_TYPE_WRITE_ZEROES:
|
||||||
case SPDK_BDEV_IO_TYPE_RESET:
|
case SPDK_BDEV_IO_TYPE_RESET:
|
||||||
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
|
TAILQ_INSERT_TAIL(&ch->io, bdev_io, module_link);
|
||||||
break;
|
break;
|
||||||
case SPDK_BDEV_IO_TYPE_FLUSH:
|
case SPDK_BDEV_IO_TYPE_FLUSH:
|
||||||
case SPDK_BDEV_IO_TYPE_UNMAP:
|
case SPDK_BDEV_IO_TYPE_UNMAP:
|
||||||
@ -168,15 +175,40 @@ create_null_bdev(const char *name, uint64_t num_blocks, uint32_t block_size)
|
|||||||
return &bdev->bdev;
|
return &bdev->bdev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
null_io_poll(void *arg)
|
||||||
|
{
|
||||||
|
struct null_io_channel *ch = arg;
|
||||||
|
TAILQ_HEAD(, spdk_bdev_io) io;
|
||||||
|
struct spdk_bdev_io *bdev_io;
|
||||||
|
|
||||||
|
TAILQ_INIT(&io);
|
||||||
|
TAILQ_SWAP(&ch->io, &io, spdk_bdev_io, module_link);
|
||||||
|
|
||||||
|
while (!TAILQ_EMPTY(&io)) {
|
||||||
|
bdev_io = TAILQ_FIRST(&io);
|
||||||
|
TAILQ_REMOVE(&io, bdev_io, module_link);
|
||||||
|
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
null_bdev_create_cb(void *io_device, void *ctx_buf)
|
null_bdev_create_cb(void *io_device, void *ctx_buf)
|
||||||
{
|
{
|
||||||
|
struct null_io_channel *ch = ctx_buf;
|
||||||
|
|
||||||
|
TAILQ_INIT(&ch->io);
|
||||||
|
ch->poller = spdk_poller_register(null_io_poll, ch, 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
null_bdev_destroy_cb(void *io_device, void *ctx_buf)
|
null_bdev_destroy_cb(void *io_device, void *ctx_buf)
|
||||||
{
|
{
|
||||||
|
struct null_io_channel *ch = ctx_buf;
|
||||||
|
|
||||||
|
spdk_poller_unregister(&ch->poller);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -201,7 +233,8 @@ bdev_null_initialize(void)
|
|||||||
* We need to pick some unique address as our "io device" - so just use the
|
* We need to pick some unique address as our "io device" - so just use the
|
||||||
* address of the global tailq.
|
* address of the global tailq.
|
||||||
*/
|
*/
|
||||||
spdk_io_device_register(&g_null_bdev_head, null_bdev_create_cb, null_bdev_destroy_cb, 0);
|
spdk_io_device_register(&g_null_bdev_head, null_bdev_create_cb, null_bdev_destroy_cb,
|
||||||
|
sizeof(struct null_io_channel));
|
||||||
|
|
||||||
if (sp == NULL) {
|
if (sp == NULL) {
|
||||||
goto end;
|
goto end;
|
||||||
|
Loading…
Reference in New Issue
Block a user