bdev: submit queued IO after disabling QoS

There's no reason to abort IO that have been queued
due to QoS limits, when QoS is switched from enabled
to disabled.  Submit them to the bdev instead.

Fixes issue #357.

Signed-off-by: Jim Harris <james.r.harris@intel.com>
Change-Id: If5eafc53418ac686120e1d6a1da884b42cef845e

Reviewed-on: https://review.gerrithub.io/418128
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Seth Howell <seth.howell5141@gmail.com>
Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
Jim Harris 2018-07-05 08:57:33 -07:00
parent 436c0c189b
commit 140eaaa084
2 changed files with 69 additions and 2 deletions

View File

@ -3238,6 +3238,7 @@ _spdk_bdev_disable_qos_done(void *cb_arg)
{
struct set_qos_limit_ctx *ctx = cb_arg;
struct spdk_bdev *bdev = ctx->bdev;
struct spdk_bdev_io *bdev_io;
struct spdk_bdev_qos *qos;
pthread_mutex_lock(&bdev->internal.mutex);
@ -3245,7 +3246,24 @@ _spdk_bdev_disable_qos_done(void *cb_arg)
bdev->internal.qos = NULL;
pthread_mutex_unlock(&bdev->internal.mutex);
_spdk_bdev_abort_queued_io(&qos->queued, qos->ch);
while (!TAILQ_EMPTY(&qos->queued)) {
/* Send queued I/O back to their original thread for resubmission. */
bdev_io = TAILQ_FIRST(&qos->queued);
TAILQ_REMOVE(&qos->queued, bdev_io, internal.link);
if (bdev_io->internal.io_submit_ch) {
/*
* Channel was changed when sending it to the QoS thread - change it back
* before sending it back to the original thread.
*/
bdev_io->internal.ch = bdev_io->internal.io_submit_ch;
bdev_io->internal.io_submit_ch = NULL;
}
spdk_thread_send_msg(spdk_io_channel_get_thread(bdev_io->internal.ch->channel),
_spdk_bdev_io_submit, bdev_io);
}
spdk_put_io_channel(spdk_io_channel_from_ctx(qos->ch));
spdk_poller_unregister(&qos->poller);

View File

@ -1061,7 +1061,8 @@ qos_dynamic_enable(void)
struct spdk_io_channel *io_ch[2];
struct spdk_bdev_channel *bdev_ch[2];
struct spdk_bdev *bdev;
int status, second_status;
enum spdk_bdev_io_status bdev_io_status[2];
int status, second_status, rc, i;
setup_test();
reset_time();
@ -1091,6 +1092,38 @@ qos_dynamic_enable(void)
CU_ASSERT((bdev_ch[0]->flags & BDEV_CH_QOS_ENABLED) != 0);
CU_ASSERT((bdev_ch[1]->flags & BDEV_CH_QOS_ENABLED) != 0);
/*
* Submit and complete 10 I/O to fill the QoS allotment for this timeslice.
* Additional I/O will then be queued.
*/
set_thread(0);
for (i = 0; i < 10; i++) {
bdev_io_status[0] = SPDK_BDEV_IO_STATUS_PENDING;
rc = spdk_bdev_read_blocks(g_desc, io_ch[0], NULL, 0, 1, io_during_io_done, &bdev_io_status[0]);
CU_ASSERT(rc == 0);
CU_ASSERT(bdev_io_status[0] == SPDK_BDEV_IO_STATUS_PENDING);
poll_thread(0);
stub_complete_io(g_bdev.io_target, 0);
CU_ASSERT(bdev_io_status[0] == SPDK_BDEV_IO_STATUS_SUCCESS);
}
/*
* Send two more I/O. These I/O will be queued since the current timeslice allotment has been
* filled already. We want to test that when QoS is disabled that these two I/O:
* 1) are not aborted
* 2) are sent back to their original thread for resubmission
*/
bdev_io_status[0] = SPDK_BDEV_IO_STATUS_PENDING;
rc = spdk_bdev_read_blocks(g_desc, io_ch[0], NULL, 0, 1, io_during_io_done, &bdev_io_status[0]);
CU_ASSERT(rc == 0);
CU_ASSERT(bdev_io_status[0] == SPDK_BDEV_IO_STATUS_PENDING);
set_thread(1);
bdev_io_status[1] = SPDK_BDEV_IO_STATUS_PENDING;
rc = spdk_bdev_read_blocks(g_desc, io_ch[1], NULL, 0, 1, io_during_io_done, &bdev_io_status[1]);
CU_ASSERT(rc == 0);
CU_ASSERT(bdev_io_status[1] == SPDK_BDEV_IO_STATUS_PENDING);
poll_threads();
/* Disable QoS */
status = -1;
spdk_bdev_set_qos_limit_iops(bdev, 0, qos_dynamic_enable_done, &status);
@ -1099,6 +1132,22 @@ qos_dynamic_enable(void)
CU_ASSERT((bdev_ch[0]->flags & BDEV_CH_QOS_ENABLED) == 0);
CU_ASSERT((bdev_ch[1]->flags & BDEV_CH_QOS_ENABLED) == 0);
/*
* All I/O should have been resubmitted back on their original thread. Complete
* all I/O on thread 0, and ensure that only the thread 0 I/O was completed.
*/
set_thread(0);
stub_complete_io(g_bdev.io_target, 0);
poll_threads();
CU_ASSERT(bdev_io_status[0] == SPDK_BDEV_IO_STATUS_SUCCESS);
CU_ASSERT(bdev_io_status[1] == SPDK_BDEV_IO_STATUS_PENDING);
/* Now complete all I/O on thread 1 and ensure the thread 1 I/O was completed. */
set_thread(1);
stub_complete_io(g_bdev.io_target, 0);
poll_threads();
CU_ASSERT(bdev_io_status[1] == SPDK_BDEV_IO_STATUS_SUCCESS);
/* Disable QoS again */
status = -1;
spdk_bdev_set_qos_limit_iops(bdev, 0, qos_dynamic_enable_done, &status);