bdev/qos: update the RPC method to make 0 iops mean unlimited

Unlimited I/O per second is equivalent to disabling QoS.

Change-Id: I03a489dd18b5d1a9a42f7853248911e97b7a211e
Signed-off-by: GangCao <gang.cao@intel.com>
Reviewed-on: https://review.gerrithub.io/408291
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
This commit is contained in:
GangCao 2018-04-20 13:55:51 -07:00 committed by Daniel Verkamp
parent 0587e970e5
commit 9c7d842cc4
3 changed files with 86 additions and 21 deletions

View File

@ -181,7 +181,7 @@ Set an IOPS-based quality of service rate limit on a bdev.
Name | Optional | Type | Description
----------------------- | -------- | ----------- | -----------
name | Required | string | Block device name
ios_per_sec | Required | number | Number of I/Os per second to allow
ios_per_sec | Required | number | Number of I/Os per second to allow. 0 means unlimited.
### Example

View File

@ -254,6 +254,9 @@ struct spdk_bdev {
/** True if QoS is enabled */
bool enabled;
/** True if the state of the QoS is being modified */
bool mod_in_progress;
/** Rate limit, in I/O per second */
uint64_t rate_limit;

View File

@ -2885,24 +2885,73 @@ struct set_qos_limit_ctx {
static void
_spdk_bdev_set_qos_limit_done(struct set_qos_limit_ctx *ctx, int status)
{
pthread_mutex_lock(&ctx->bdev->mutex);
ctx->bdev->qos.mod_in_progress = false;
pthread_mutex_unlock(&ctx->bdev->mutex);
ctx->cb_fn(ctx->cb_arg, status);
free(ctx);
}
static void
_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_qos *qos;
pthread_mutex_lock(&bdev->mutex);
qos = &bdev->qos;
qos->enabled = false;
_spdk_bdev_abort_queued_io(&qos->queued, qos->ch);
_spdk_bdev_channel_destroy(qos->ch);
qos->thread = NULL;
qos->max_ios_per_timeslice = 0;
qos->io_submitted_this_timeslice = 0;
spdk_poller_unregister(&qos->poller);
pthread_mutex_unlock(&bdev->mutex);
_spdk_bdev_set_qos_limit_done(ctx, 0);
}
static void
_spdk_bdev_disable_qos_msg_done(struct spdk_io_channel_iter *i, int status)
{
void *io_device = spdk_io_channel_iter_get_io_device(i);
struct spdk_bdev *bdev = __bdev_from_io_dev(io_device);
struct set_qos_limit_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
struct spdk_thread *thread;
pthread_mutex_lock(&bdev->mutex);
thread = bdev->qos.thread;
pthread_mutex_unlock(&bdev->mutex);
if (thread) {
spdk_thread_send_msg(thread, _spdk_bdev_disable_qos_done, ctx);
}
}
static void
_spdk_bdev_disable_qos_msg(struct spdk_io_channel_iter *i)
{
struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i);
struct spdk_bdev_channel *bdev_ch = spdk_io_channel_get_ctx(ch);
bdev_ch->flags &= ~BDEV_CH_QOS_ENABLED;
spdk_for_each_channel_continue(i, 0);
}
static void
_spdk_bdev_update_qos_limit_iops_msg(void *cb_arg)
{
struct set_qos_limit_ctx *ctx = cb_arg;
struct spdk_bdev *bdev = ctx->bdev;
/*
* There is possibility that the QoS channel has been destroyed
* when processing this message. Have a check here as the QoS
* channel is protected through the critical section.
*/
if (bdev->qos.ch) {
spdk_bdev_qos_update_max_ios_per_timeslice(&bdev->qos);
}
pthread_mutex_lock(&bdev->mutex);
spdk_bdev_qos_update_max_ios_per_timeslice(&bdev->qos);
pthread_mutex_unlock(&bdev->mutex);
_spdk_bdev_set_qos_limit_done(ctx, 0);
}
@ -2936,8 +2985,9 @@ spdk_bdev_set_qos_limit_iops(struct spdk_bdev *bdev, uint64_t ios_per_sec,
void (*cb_fn)(void *cb_arg, int status), void *cb_arg)
{
struct set_qos_limit_ctx *ctx;
struct spdk_thread *thread;
if (ios_per_sec == 0 || ios_per_sec % SPDK_BDEV_QOS_MIN_IOS_PER_SEC) {
if (ios_per_sec > 0 && ios_per_sec % SPDK_BDEV_QOS_MIN_IOS_PER_SEC) {
SPDK_ERRLOG("Requested ios_per_sec limit %" PRIu64 " is not a multiple of %u\n",
ios_per_sec, SPDK_BDEV_QOS_MIN_IOS_PER_SEC);
cb_fn(cb_arg, -EINVAL);
@ -2952,24 +3002,36 @@ spdk_bdev_set_qos_limit_iops(struct spdk_bdev *bdev, uint64_t ios_per_sec,
ctx->cb_fn = cb_fn;
ctx->cb_arg = cb_arg;
ctx->bdev = bdev;
pthread_mutex_lock(&bdev->mutex);
bdev->qos.rate_limit = ios_per_sec;
if (bdev->qos.thread) {
/*
* QoS is already enabled, so just update the limit information on the QoS thread.
*/
ctx->bdev = bdev;
spdk_thread_send_msg(bdev->qos.thread, _spdk_bdev_update_qos_limit_iops_msg, ctx);
if (bdev->qos.mod_in_progress) {
pthread_mutex_unlock(&bdev->mutex);
free(ctx);
cb_fn(cb_arg, -EAGAIN);
return;
}
bdev->qos.mod_in_progress = true;
bdev->qos.rate_limit = ios_per_sec;
thread = bdev->qos.thread;
pthread_mutex_unlock(&bdev->mutex);
/* Enable QoS on all channels. */
spdk_for_each_channel(__bdev_to_io_dev(bdev),
_spdk_bdev_enable_qos_msg, ctx,
_spdk_bdev_enable_qos_done);
if (thread) {
if (ios_per_sec == 0) {
/* Disabling */
spdk_for_each_channel(__bdev_to_io_dev(bdev),
_spdk_bdev_disable_qos_msg, ctx,
_spdk_bdev_disable_qos_msg_done);
} else {
/* Updating */
spdk_thread_send_msg(thread, _spdk_bdev_update_qos_limit_iops_msg, ctx);
}
} else {
/* Enabling */
spdk_for_each_channel(__bdev_to_io_dev(bdev),
_spdk_bdev_enable_qos_msg, ctx,
_spdk_bdev_enable_qos_done);
}
}
SPDK_LOG_REGISTER_COMPONENT("bdev", SPDK_LOG_BDEV)