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 | Optional | Type | Description
----------------------- | -------- | ----------- | ----------- ----------------------- | -------- | ----------- | -----------
name | Required | string | Block device name 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 ### Example

View File

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

View File

@ -2885,24 +2885,73 @@ struct set_qos_limit_ctx {
static void static void
_spdk_bdev_set_qos_limit_done(struct set_qos_limit_ctx *ctx, int status) _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); ctx->cb_fn(ctx->cb_arg, status);
free(ctx); 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 static void
_spdk_bdev_update_qos_limit_iops_msg(void *cb_arg) _spdk_bdev_update_qos_limit_iops_msg(void *cb_arg)
{ {
struct set_qos_limit_ctx *ctx = cb_arg; struct set_qos_limit_ctx *ctx = cb_arg;
struct spdk_bdev *bdev = ctx->bdev; struct spdk_bdev *bdev = ctx->bdev;
/* pthread_mutex_lock(&bdev->mutex);
* 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); spdk_bdev_qos_update_max_ios_per_timeslice(&bdev->qos);
} pthread_mutex_unlock(&bdev->mutex);
_spdk_bdev_set_qos_limit_done(ctx, 0); _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) void (*cb_fn)(void *cb_arg, int status), void *cb_arg)
{ {
struct set_qos_limit_ctx *ctx; 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", 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); ios_per_sec, SPDK_BDEV_QOS_MIN_IOS_PER_SEC);
cb_fn(cb_arg, -EINVAL); 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_fn = cb_fn;
ctx->cb_arg = cb_arg; ctx->cb_arg = cb_arg;
ctx->bdev = bdev;
pthread_mutex_lock(&bdev->mutex); pthread_mutex_lock(&bdev->mutex);
bdev->qos.rate_limit = ios_per_sec; if (bdev->qos.mod_in_progress) {
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);
pthread_mutex_unlock(&bdev->mutex); pthread_mutex_unlock(&bdev->mutex);
free(ctx);
cb_fn(cb_arg, -EAGAIN);
return; return;
} }
bdev->qos.mod_in_progress = true;
bdev->qos.rate_limit = ios_per_sec;
thread = bdev->qos.thread;
pthread_mutex_unlock(&bdev->mutex); pthread_mutex_unlock(&bdev->mutex);
/* Enable QoS on all channels. */ 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_for_each_channel(__bdev_to_io_dev(bdev),
_spdk_bdev_enable_qos_msg, ctx, _spdk_bdev_enable_qos_msg, ctx,
_spdk_bdev_enable_qos_done); _spdk_bdev_enable_qos_done);
}
} }
SPDK_LOG_REGISTER_COMPONENT("bdev", SPDK_LOG_BDEV) SPDK_LOG_REGISTER_COMPONENT("bdev", SPDK_LOG_BDEV)