To support DIF, bdev will need to expose the following information: - Metadata format - Block size - Metadata size - Metadata setting (interleave or separate) - DIF settings - DIF type 1, 2, or 3 - DIF location - DIF check types - Guard check - Reference tag check - Application tag check This patch is for the metadata format. Subsequent patches will do for the DIF setting and DIF check types. Add fields, md_len and md_interleave, to struct spdk_bdev and add APIs, spdk_bdev_get_md_size and spdk_bdev_is_md_interleaved, to bdev APIs. The fields, md_len and md_interleave, are added to the bdev JSON infomation dump. DIF will be used only in the NVMe bdev module and the upcoming virtual DIF bdev module first. But additional required storage by md_len and md_interleave will be very small and they are simple. Hence add them to struct spdk_bdev simply. Change-Id: I4109f6a63e6f0576efe424feb0305a9a17b9b2e8 Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com> Reviewed-on: https://review.gerrithub.io/c/443183 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com>
768 lines
21 KiB
C
768 lines
21 KiB
C
/*-
|
|
* BSD LICENSE
|
|
*
|
|
* Copyright (c) Intel Corporation.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
* * Neither the name of Intel Corporation nor the names of its
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "spdk/env.h"
|
|
#include "spdk/log.h"
|
|
#include "spdk/rpc.h"
|
|
#include "spdk/string.h"
|
|
#include "spdk/util.h"
|
|
#include "spdk/histogram_data.h"
|
|
#include "spdk/base64.h"
|
|
|
|
#include "spdk/bdev_module.h"
|
|
|
|
struct rpc_get_bdevs_iostat_ctx {
|
|
int bdev_count;
|
|
struct spdk_jsonrpc_request *request;
|
|
struct spdk_json_write_ctx *w;
|
|
};
|
|
|
|
static void
|
|
spdk_rpc_get_bdevs_iostat_cb(struct spdk_bdev *bdev,
|
|
struct spdk_bdev_io_stat *stat, void *cb_arg, int rc)
|
|
{
|
|
struct rpc_get_bdevs_iostat_ctx *ctx = cb_arg;
|
|
struct spdk_json_write_ctx *w = ctx->w;
|
|
const char *bdev_name;
|
|
|
|
if (rc != 0) {
|
|
goto done;
|
|
}
|
|
|
|
bdev_name = spdk_bdev_get_name(bdev);
|
|
if (bdev_name != NULL) {
|
|
spdk_json_write_object_begin(w);
|
|
|
|
spdk_json_write_named_string(w, "name", bdev_name);
|
|
|
|
spdk_json_write_named_uint64(w, "bytes_read", stat->bytes_read);
|
|
|
|
spdk_json_write_named_uint64(w, "num_read_ops", stat->num_read_ops);
|
|
|
|
spdk_json_write_named_uint64(w, "bytes_written", stat->bytes_written);
|
|
|
|
spdk_json_write_named_uint64(w, "num_write_ops", stat->num_write_ops);
|
|
|
|
spdk_json_write_named_uint64(w, "bytes_unmapped", stat->bytes_unmapped);
|
|
|
|
spdk_json_write_named_uint64(w, "num_unmap_ops", stat->num_unmap_ops);
|
|
|
|
spdk_json_write_named_uint64(w, "read_latency_ticks", stat->read_latency_ticks);
|
|
|
|
spdk_json_write_named_uint64(w, "write_latency_ticks", stat->write_latency_ticks);
|
|
|
|
spdk_json_write_named_uint64(w, "unmap_latency_ticks", stat->unmap_latency_ticks);
|
|
|
|
if (spdk_bdev_get_qd_sampling_period(bdev)) {
|
|
spdk_json_write_named_uint64(w, "queue_depth_polling_period",
|
|
spdk_bdev_get_qd_sampling_period(bdev));
|
|
|
|
spdk_json_write_named_uint64(w, "queue_depth", spdk_bdev_get_qd(bdev));
|
|
|
|
spdk_json_write_named_uint64(w, "io_time", spdk_bdev_get_io_time(bdev));
|
|
|
|
spdk_json_write_named_uint64(w, "weighted_io_time",
|
|
spdk_bdev_get_weighted_io_time(bdev));
|
|
}
|
|
|
|
spdk_json_write_object_end(w);
|
|
}
|
|
|
|
done:
|
|
free(stat);
|
|
if (--ctx->bdev_count == 0) {
|
|
spdk_json_write_array_end(ctx->w);
|
|
spdk_jsonrpc_end_result(ctx->request, ctx->w);
|
|
free(ctx);
|
|
}
|
|
}
|
|
|
|
struct rpc_get_bdevs_iostat {
|
|
char *name;
|
|
};
|
|
|
|
static void
|
|
free_rpc_get_bdevs_iostat(struct rpc_get_bdevs_iostat *r)
|
|
{
|
|
free(r->name);
|
|
}
|
|
|
|
static const struct spdk_json_object_decoder rpc_get_bdevs_iostat_decoders[] = {
|
|
{"name", offsetof(struct rpc_get_bdevs_iostat, name), spdk_json_decode_string, true},
|
|
};
|
|
|
|
static void
|
|
spdk_rpc_get_bdevs_iostat(struct spdk_jsonrpc_request *request,
|
|
const struct spdk_json_val *params)
|
|
{
|
|
struct rpc_get_bdevs_iostat req = {};
|
|
struct spdk_bdev *bdev = NULL;
|
|
struct spdk_json_write_ctx *w;
|
|
struct spdk_bdev_io_stat *stat;
|
|
struct rpc_get_bdevs_iostat_ctx *ctx;
|
|
|
|
if (params != NULL) {
|
|
if (spdk_json_decode_object(params, rpc_get_bdevs_iostat_decoders,
|
|
SPDK_COUNTOF(rpc_get_bdevs_iostat_decoders),
|
|
&req)) {
|
|
SPDK_ERRLOG("spdk_json_decode_object failed\n");
|
|
goto invalid;
|
|
}
|
|
|
|
if (req.name) {
|
|
bdev = spdk_bdev_get_by_name(req.name);
|
|
if (bdev == NULL) {
|
|
SPDK_ERRLOG("bdev '%s' does not exist\n", req.name);
|
|
goto invalid;
|
|
}
|
|
}
|
|
}
|
|
|
|
free_rpc_get_bdevs_iostat(&req);
|
|
|
|
ctx = calloc(1, sizeof(struct rpc_get_bdevs_iostat_ctx));
|
|
if (ctx == NULL) {
|
|
SPDK_ERRLOG("Failed to allocate rpc_get_bdevs_iostat_ctx struct\n");
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "No memory left");
|
|
return;
|
|
}
|
|
|
|
w = spdk_jsonrpc_begin_result(request);
|
|
if (w == NULL) {
|
|
free(ctx);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Increment initial bdev_count so that it will never reach 0 in the middle
|
|
* of iterating.
|
|
*/
|
|
ctx->bdev_count++;
|
|
ctx->request = request;
|
|
ctx->w = w;
|
|
|
|
spdk_json_write_array_begin(w);
|
|
|
|
spdk_json_write_object_begin(w);
|
|
spdk_json_write_named_uint64(w, "tick_rate", spdk_get_ticks_hz());
|
|
spdk_json_write_object_end(w);
|
|
|
|
if (bdev != NULL) {
|
|
stat = calloc(1, sizeof(struct spdk_bdev_io_stat));
|
|
if (stat == NULL) {
|
|
SPDK_ERRLOG("Failed to allocate rpc_get_bdevs_iostat_ctx struct\n");
|
|
} else {
|
|
ctx->bdev_count++;
|
|
spdk_bdev_get_device_stat(bdev, stat, spdk_rpc_get_bdevs_iostat_cb, ctx);
|
|
}
|
|
} else {
|
|
for (bdev = spdk_bdev_first(); bdev != NULL; bdev = spdk_bdev_next(bdev)) {
|
|
stat = calloc(1, sizeof(struct spdk_bdev_io_stat));
|
|
if (stat == NULL) {
|
|
SPDK_ERRLOG("Failed to allocate spdk_bdev_io_stat struct\n");
|
|
break;
|
|
}
|
|
ctx->bdev_count++;
|
|
spdk_bdev_get_device_stat(bdev, stat, spdk_rpc_get_bdevs_iostat_cb, ctx);
|
|
}
|
|
}
|
|
|
|
if (--ctx->bdev_count == 0) {
|
|
spdk_json_write_array_end(w);
|
|
spdk_jsonrpc_end_result(request, w);
|
|
free(ctx);
|
|
}
|
|
|
|
return;
|
|
|
|
invalid:
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
|
|
|
|
free_rpc_get_bdevs_iostat(&req);
|
|
}
|
|
SPDK_RPC_REGISTER("get_bdevs_iostat", spdk_rpc_get_bdevs_iostat, SPDK_RPC_RUNTIME)
|
|
|
|
static void
|
|
spdk_rpc_dump_bdev_info(struct spdk_json_write_ctx *w,
|
|
struct spdk_bdev *bdev)
|
|
{
|
|
struct spdk_bdev_alias *tmp;
|
|
uint64_t qos_limits[SPDK_BDEV_QOS_NUM_RATE_LIMIT_TYPES];
|
|
int i;
|
|
|
|
spdk_json_write_object_begin(w);
|
|
|
|
spdk_json_write_named_string(w, "name", spdk_bdev_get_name(bdev));
|
|
|
|
spdk_json_write_named_array_begin(w, "aliases");
|
|
|
|
TAILQ_FOREACH(tmp, spdk_bdev_get_aliases(bdev), tailq) {
|
|
spdk_json_write_string(w, tmp->alias);
|
|
}
|
|
|
|
spdk_json_write_array_end(w);
|
|
|
|
spdk_json_write_named_string(w, "product_name", spdk_bdev_get_product_name(bdev));
|
|
|
|
spdk_json_write_named_uint32(w, "block_size", spdk_bdev_get_block_size(bdev));
|
|
|
|
spdk_json_write_named_uint64(w, "num_blocks", spdk_bdev_get_num_blocks(bdev));
|
|
|
|
if (!spdk_mem_all_zero(&bdev->uuid, sizeof(bdev->uuid))) {
|
|
char uuid_str[SPDK_UUID_STRING_LEN];
|
|
|
|
spdk_uuid_fmt_lower(uuid_str, sizeof(uuid_str), &bdev->uuid);
|
|
spdk_json_write_named_string(w, "uuid", uuid_str);
|
|
}
|
|
|
|
if (spdk_bdev_get_md_size(bdev) != 0) {
|
|
spdk_json_write_named_uint32(w, "md_size", spdk_bdev_get_md_size(bdev));
|
|
spdk_json_write_named_bool(w, "md_interleave", spdk_bdev_is_md_interleaved(bdev));
|
|
}
|
|
|
|
spdk_json_write_named_object_begin(w, "assigned_rate_limits");
|
|
spdk_bdev_get_qos_rate_limits(bdev, qos_limits);
|
|
for (i = 0; i < SPDK_BDEV_QOS_NUM_RATE_LIMIT_TYPES; i++) {
|
|
spdk_json_write_named_uint64(w, spdk_bdev_get_qos_rpc_type(i), qos_limits[i]);
|
|
}
|
|
spdk_json_write_object_end(w);
|
|
|
|
spdk_json_write_named_bool(w, "claimed", (bdev->internal.claim_module != NULL));
|
|
|
|
spdk_json_write_named_object_begin(w, "supported_io_types");
|
|
spdk_json_write_named_bool(w, "read",
|
|
spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_READ));
|
|
spdk_json_write_named_bool(w, "write",
|
|
spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_WRITE));
|
|
spdk_json_write_named_bool(w, "unmap",
|
|
spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_UNMAP));
|
|
spdk_json_write_named_bool(w, "write_zeroes",
|
|
spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_WRITE_ZEROES));
|
|
spdk_json_write_named_bool(w, "flush",
|
|
spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_FLUSH));
|
|
spdk_json_write_named_bool(w, "reset",
|
|
spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_RESET));
|
|
spdk_json_write_named_bool(w, "nvme_admin",
|
|
spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_NVME_ADMIN));
|
|
spdk_json_write_named_bool(w, "nvme_io",
|
|
spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_NVME_IO));
|
|
spdk_json_write_object_end(w);
|
|
|
|
spdk_json_write_named_object_begin(w, "driver_specific");
|
|
spdk_bdev_dump_info_json(bdev, w);
|
|
spdk_json_write_object_end(w);
|
|
|
|
spdk_json_write_object_end(w);
|
|
}
|
|
|
|
struct rpc_get_bdevs {
|
|
char *name;
|
|
};
|
|
|
|
static void
|
|
free_rpc_get_bdevs(struct rpc_get_bdevs *r)
|
|
{
|
|
free(r->name);
|
|
}
|
|
|
|
static const struct spdk_json_object_decoder rpc_get_bdevs_decoders[] = {
|
|
{"name", offsetof(struct rpc_get_bdevs, name), spdk_json_decode_string, true},
|
|
};
|
|
|
|
static void
|
|
spdk_rpc_get_bdevs(struct spdk_jsonrpc_request *request,
|
|
const struct spdk_json_val *params)
|
|
{
|
|
struct rpc_get_bdevs req = {};
|
|
struct spdk_json_write_ctx *w;
|
|
struct spdk_bdev *bdev = NULL;
|
|
|
|
if (params && spdk_json_decode_object(params, rpc_get_bdevs_decoders,
|
|
SPDK_COUNTOF(rpc_get_bdevs_decoders),
|
|
&req)) {
|
|
SPDK_ERRLOG("spdk_json_decode_object failed\n");
|
|
goto invalid;
|
|
}
|
|
|
|
if (req.name) {
|
|
bdev = spdk_bdev_get_by_name(req.name);
|
|
if (bdev == NULL) {
|
|
SPDK_ERRLOG("bdev '%s' does not exist\n", req.name);
|
|
goto invalid;
|
|
}
|
|
}
|
|
|
|
free_rpc_get_bdevs(&req);
|
|
w = spdk_jsonrpc_begin_result(request);
|
|
if (w == NULL) {
|
|
return;
|
|
}
|
|
|
|
spdk_json_write_array_begin(w);
|
|
|
|
if (bdev != NULL) {
|
|
spdk_rpc_dump_bdev_info(w, bdev);
|
|
} else {
|
|
for (bdev = spdk_bdev_first(); bdev != NULL; bdev = spdk_bdev_next(bdev)) {
|
|
spdk_rpc_dump_bdev_info(w, bdev);
|
|
}
|
|
}
|
|
|
|
spdk_json_write_array_end(w);
|
|
|
|
spdk_jsonrpc_end_result(request, w);
|
|
|
|
return;
|
|
|
|
invalid:
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
|
|
|
|
free_rpc_get_bdevs(&req);
|
|
}
|
|
SPDK_RPC_REGISTER("get_bdevs", spdk_rpc_get_bdevs, SPDK_RPC_RUNTIME)
|
|
|
|
struct rpc_delete_bdev {
|
|
char *name;
|
|
};
|
|
|
|
static void
|
|
free_rpc_delete_bdev(struct rpc_delete_bdev *r)
|
|
{
|
|
free(r->name);
|
|
}
|
|
|
|
static const struct spdk_json_object_decoder rpc_delete_bdev_decoders[] = {
|
|
{"name", offsetof(struct rpc_delete_bdev, name), spdk_json_decode_string},
|
|
};
|
|
|
|
static void
|
|
_spdk_rpc_delete_bdev_cb(void *cb_arg, int bdeverrno)
|
|
{
|
|
struct spdk_jsonrpc_request *request = cb_arg;
|
|
struct spdk_json_write_ctx *w;
|
|
|
|
w = spdk_jsonrpc_begin_result(request);
|
|
if (w == NULL) {
|
|
return;
|
|
}
|
|
|
|
spdk_json_write_bool(w, bdeverrno == 0);
|
|
spdk_jsonrpc_end_result(request, w);
|
|
}
|
|
|
|
static void
|
|
spdk_rpc_delete_bdev(struct spdk_jsonrpc_request *request,
|
|
const struct spdk_json_val *params)
|
|
{
|
|
struct rpc_delete_bdev req = {};
|
|
struct spdk_bdev *bdev;
|
|
|
|
SPDK_ERRLOG("The delete_bdev RPC is deprecated. Please use the RPC specific\n");
|
|
SPDK_ERRLOG("to the bdev type being deleted.\n");
|
|
|
|
if (spdk_json_decode_object(params, rpc_delete_bdev_decoders,
|
|
SPDK_COUNTOF(rpc_delete_bdev_decoders),
|
|
&req)) {
|
|
SPDK_ERRLOG("spdk_json_decode_object failed\n");
|
|
goto invalid;
|
|
}
|
|
|
|
if (req.name == NULL) {
|
|
SPDK_ERRLOG("missing name param\n");
|
|
goto invalid;
|
|
}
|
|
|
|
bdev = spdk_bdev_get_by_name(req.name);
|
|
if (bdev == NULL) {
|
|
SPDK_ERRLOG("bdev '%s' does not exist\n", req.name);
|
|
goto invalid;
|
|
}
|
|
|
|
spdk_bdev_unregister(bdev, _spdk_rpc_delete_bdev_cb, request);
|
|
|
|
free_rpc_delete_bdev(&req);
|
|
|
|
return;
|
|
|
|
invalid:
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
|
|
free_rpc_delete_bdev(&req);
|
|
}
|
|
SPDK_RPC_REGISTER("delete_bdev", spdk_rpc_delete_bdev, SPDK_RPC_RUNTIME)
|
|
|
|
struct rpc_set_bdev_qd_sampling_period {
|
|
char *name;
|
|
uint64_t period;
|
|
};
|
|
|
|
static void
|
|
free_rpc_set_bdev_qd_sampling_period(struct rpc_set_bdev_qd_sampling_period *r)
|
|
{
|
|
free(r->name);
|
|
}
|
|
|
|
static const struct spdk_json_object_decoder
|
|
rpc_set_bdev_qd_sampling_period_decoders[] = {
|
|
{"name", offsetof(struct rpc_set_bdev_qd_sampling_period, name), spdk_json_decode_string},
|
|
{"period", offsetof(struct rpc_set_bdev_qd_sampling_period, period), spdk_json_decode_uint64},
|
|
};
|
|
|
|
static void
|
|
spdk_rpc_set_bdev_qd_sampling_period(struct spdk_jsonrpc_request *request,
|
|
const struct spdk_json_val *params)
|
|
{
|
|
struct rpc_set_bdev_qd_sampling_period req = {0};
|
|
struct spdk_bdev *bdev;
|
|
struct spdk_json_write_ctx *w;
|
|
|
|
req.period = UINT64_MAX;
|
|
|
|
if (spdk_json_decode_object(params, rpc_set_bdev_qd_sampling_period_decoders,
|
|
SPDK_COUNTOF(rpc_set_bdev_qd_sampling_period_decoders),
|
|
&req)) {
|
|
SPDK_ERRLOG("spdk_json_decode_object failed\n");
|
|
goto invalid;
|
|
}
|
|
|
|
if (req.name) {
|
|
bdev = spdk_bdev_get_by_name(req.name);
|
|
if (bdev == NULL) {
|
|
SPDK_ERRLOG("bdev '%s' does not exist\n", req.name);
|
|
goto invalid;
|
|
}
|
|
} else {
|
|
SPDK_ERRLOG("Missing name param\n");
|
|
goto invalid;
|
|
}
|
|
|
|
if (req.period == UINT64_MAX) {
|
|
SPDK_ERRLOG("Missing period param");
|
|
}
|
|
|
|
w = spdk_jsonrpc_begin_result(request);
|
|
spdk_bdev_set_qd_sampling_period(bdev, req.period);
|
|
|
|
spdk_json_write_bool(w, true);
|
|
spdk_jsonrpc_end_result(request, w);
|
|
free_rpc_set_bdev_qd_sampling_period(&req);
|
|
return;
|
|
|
|
invalid:
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
|
|
free_rpc_set_bdev_qd_sampling_period(&req);
|
|
return;
|
|
}
|
|
SPDK_RPC_REGISTER("set_bdev_qd_sampling_period",
|
|
spdk_rpc_set_bdev_qd_sampling_period,
|
|
SPDK_RPC_RUNTIME)
|
|
|
|
struct rpc_set_bdev_qos_limit {
|
|
char *name;
|
|
uint64_t limits[SPDK_BDEV_QOS_NUM_RATE_LIMIT_TYPES];
|
|
};
|
|
|
|
static void
|
|
free_rpc_set_bdev_qos_limit(struct rpc_set_bdev_qos_limit *r)
|
|
{
|
|
free(r->name);
|
|
}
|
|
|
|
static const struct spdk_json_object_decoder rpc_set_bdev_qos_limit_decoders[] = {
|
|
{"name", offsetof(struct rpc_set_bdev_qos_limit, name), spdk_json_decode_string},
|
|
{
|
|
"rw_ios_per_sec", offsetof(struct rpc_set_bdev_qos_limit,
|
|
limits[SPDK_BDEV_QOS_RW_IOPS_RATE_LIMIT]),
|
|
spdk_json_decode_uint64, true
|
|
},
|
|
{
|
|
"rw_mbytes_per_sec", offsetof(struct rpc_set_bdev_qos_limit,
|
|
limits[SPDK_BDEV_QOS_RW_BPS_RATE_LIMIT]),
|
|
spdk_json_decode_uint64, true
|
|
},
|
|
{
|
|
"r_mbytes_per_sec", offsetof(struct rpc_set_bdev_qos_limit,
|
|
limits[SPDK_BDEV_QOS_R_BPS_RATE_LIMIT]),
|
|
spdk_json_decode_uint64, true
|
|
},
|
|
{
|
|
"w_mbytes_per_sec", offsetof(struct rpc_set_bdev_qos_limit,
|
|
limits[SPDK_BDEV_QOS_W_BPS_RATE_LIMIT]),
|
|
spdk_json_decode_uint64, true
|
|
},
|
|
};
|
|
|
|
static void
|
|
spdk_rpc_set_bdev_qos_limit_complete(void *cb_arg, int status)
|
|
{
|
|
struct spdk_jsonrpc_request *request = cb_arg;
|
|
struct spdk_json_write_ctx *w;
|
|
|
|
if (status != 0) {
|
|
spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
|
|
"Failed to configure rate limit: %s",
|
|
spdk_strerror(-status));
|
|
return;
|
|
}
|
|
|
|
w = spdk_jsonrpc_begin_result(request);
|
|
if (w == NULL) {
|
|
return;
|
|
}
|
|
|
|
spdk_json_write_bool(w, true);
|
|
spdk_jsonrpc_end_result(request, w);
|
|
}
|
|
|
|
static void
|
|
spdk_rpc_set_bdev_qos_limit(struct spdk_jsonrpc_request *request,
|
|
const struct spdk_json_val *params)
|
|
{
|
|
struct rpc_set_bdev_qos_limit req = {NULL, {UINT64_MAX, UINT64_MAX, UINT64_MAX, UINT64_MAX}};
|
|
struct spdk_bdev *bdev;
|
|
int i;
|
|
|
|
if (spdk_json_decode_object(params, rpc_set_bdev_qos_limit_decoders,
|
|
SPDK_COUNTOF(rpc_set_bdev_qos_limit_decoders),
|
|
&req)) {
|
|
SPDK_ERRLOG("spdk_json_decode_object failed\n");
|
|
goto invalid;
|
|
}
|
|
|
|
bdev = spdk_bdev_get_by_name(req.name);
|
|
if (bdev == NULL) {
|
|
SPDK_ERRLOG("bdev '%s' does not exist\n", req.name);
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
|
|
"Bdev does not exist");
|
|
goto exit;
|
|
}
|
|
|
|
for (i = 0; i < SPDK_BDEV_QOS_NUM_RATE_LIMIT_TYPES; i++) {
|
|
if (req.limits[i] != UINT64_MAX) {
|
|
break;
|
|
}
|
|
}
|
|
if (i == SPDK_BDEV_QOS_NUM_RATE_LIMIT_TYPES) {
|
|
SPDK_ERRLOG("no rate limits specified\n");
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
|
|
"No rate limits specified");
|
|
goto exit;
|
|
}
|
|
|
|
free_rpc_set_bdev_qos_limit(&req);
|
|
spdk_bdev_set_qos_rate_limits(bdev, req.limits, spdk_rpc_set_bdev_qos_limit_complete, request);
|
|
return;
|
|
|
|
invalid:
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
|
|
exit:
|
|
free_rpc_set_bdev_qos_limit(&req);
|
|
}
|
|
|
|
SPDK_RPC_REGISTER("set_bdev_qos_limit", spdk_rpc_set_bdev_qos_limit, SPDK_RPC_RUNTIME)
|
|
|
|
/* SPDK_RPC_ENABLE_BDEV_HISTOGRAM */
|
|
|
|
struct rpc_enable_bdev_histogram_request {
|
|
char *name;
|
|
bool enable;
|
|
};
|
|
|
|
static void
|
|
free_rpc_enable_bdev_histogram_request(struct rpc_enable_bdev_histogram_request *r)
|
|
{
|
|
free(r->name);
|
|
}
|
|
|
|
static const struct spdk_json_object_decoder rpc_enable_bdev_histogram_request_decoders[] = {
|
|
{"name", offsetof(struct rpc_enable_bdev_histogram_request, name), spdk_json_decode_string},
|
|
{"enable", offsetof(struct rpc_enable_bdev_histogram_request, enable), spdk_json_decode_bool},
|
|
};
|
|
|
|
static void
|
|
_spdk_bdev_histogram_status_cb(void *cb_arg, int status)
|
|
{
|
|
struct spdk_jsonrpc_request *request = cb_arg;
|
|
struct spdk_json_write_ctx *w;
|
|
|
|
w = spdk_jsonrpc_begin_result(request);
|
|
if (w == NULL) {
|
|
return;
|
|
}
|
|
|
|
spdk_json_write_bool(w, status == 0);
|
|
spdk_jsonrpc_end_result(request, w);
|
|
}
|
|
|
|
static void
|
|
spdk_rpc_enable_bdev_histogram(struct spdk_jsonrpc_request *request,
|
|
const struct spdk_json_val *params)
|
|
{
|
|
struct rpc_enable_bdev_histogram_request req = {NULL};
|
|
struct spdk_bdev *bdev;
|
|
int rc;
|
|
|
|
if (spdk_json_decode_object(params, rpc_enable_bdev_histogram_request_decoders,
|
|
SPDK_COUNTOF(rpc_enable_bdev_histogram_request_decoders),
|
|
&req)) {
|
|
SPDK_ERRLOG("spdk_json_decode_object failed\n");
|
|
rc = -EINVAL;
|
|
goto invalid;
|
|
}
|
|
|
|
bdev = spdk_bdev_get_by_name(req.name);
|
|
if (bdev == NULL) {
|
|
rc = -ENODEV;
|
|
goto invalid;
|
|
}
|
|
|
|
spdk_bdev_histogram_enable(bdev, _spdk_bdev_histogram_status_cb, request, req.enable);
|
|
|
|
free_rpc_enable_bdev_histogram_request(&req);
|
|
|
|
return;
|
|
|
|
invalid:
|
|
free_rpc_enable_bdev_histogram_request(&req);
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, spdk_strerror(-rc));
|
|
}
|
|
|
|
SPDK_RPC_REGISTER("enable_bdev_histogram", spdk_rpc_enable_bdev_histogram, SPDK_RPC_RUNTIME)
|
|
|
|
/* SPDK_RPC_GET_BDEV_HISTOGRAM */
|
|
|
|
struct rpc_get_bdev_histogram_request {
|
|
char *name;
|
|
};
|
|
|
|
static const struct spdk_json_object_decoder rpc_get_bdev_histogram_request_decoders[] = {
|
|
{"name", offsetof(struct rpc_get_bdev_histogram_request, name), spdk_json_decode_string}
|
|
};
|
|
|
|
static void
|
|
free_rpc_get_bdev_histogram_request(struct rpc_get_bdev_histogram_request *r)
|
|
{
|
|
free(r->name);
|
|
}
|
|
|
|
static void
|
|
_spdk_rpc_bdev_histogram_data_cb(void *cb_arg, int status, struct spdk_histogram_data *histogram)
|
|
{
|
|
struct spdk_jsonrpc_request *request = cb_arg;
|
|
struct spdk_json_write_ctx *w;
|
|
int rc;
|
|
char *encoded_histogram;
|
|
size_t src_len, dst_len;
|
|
|
|
|
|
if (status != 0) {
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
|
|
spdk_strerror(-status));
|
|
goto invalid;
|
|
}
|
|
|
|
src_len = SPDK_HISTOGRAM_NUM_BUCKETS(histogram) * sizeof(uint64_t);
|
|
dst_len = spdk_base64_get_encoded_strlen(src_len) + 1;
|
|
|
|
encoded_histogram = malloc(dst_len);
|
|
if (encoded_histogram == NULL) {
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
|
|
spdk_strerror(ENOMEM));
|
|
goto invalid;
|
|
}
|
|
|
|
rc = spdk_base64_encode(encoded_histogram, histogram->bucket, src_len);
|
|
if (rc != 0) {
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
|
|
spdk_strerror(-rc));
|
|
goto free_encoded_histogram;
|
|
}
|
|
|
|
w = spdk_jsonrpc_begin_result(request);
|
|
if (w == NULL) {
|
|
goto free_encoded_histogram;
|
|
}
|
|
|
|
spdk_json_write_object_begin(w);
|
|
spdk_json_write_named_string(w, "histogram", encoded_histogram);
|
|
spdk_json_write_named_int64(w, "bucket_shift", histogram->bucket_shift);
|
|
spdk_json_write_named_int64(w, "tsc_rate", spdk_get_ticks_hz());
|
|
spdk_json_write_object_end(w);
|
|
spdk_jsonrpc_end_result(request, w);
|
|
|
|
free_encoded_histogram:
|
|
free(encoded_histogram);
|
|
invalid:
|
|
spdk_histogram_data_free(histogram);
|
|
}
|
|
|
|
static void
|
|
spdk_rpc_get_bdev_histogram(struct spdk_jsonrpc_request *request,
|
|
const struct spdk_json_val *params)
|
|
{
|
|
struct rpc_get_bdev_histogram_request req = {NULL};
|
|
struct spdk_histogram_data *histogram;
|
|
struct spdk_bdev *bdev;
|
|
int rc;
|
|
|
|
if (spdk_json_decode_object(params, rpc_get_bdev_histogram_request_decoders,
|
|
SPDK_COUNTOF(rpc_get_bdev_histogram_request_decoders),
|
|
&req)) {
|
|
SPDK_ERRLOG("spdk_json_decode_object failed\n");
|
|
rc = -EINVAL;
|
|
goto invalid;
|
|
}
|
|
|
|
bdev = spdk_bdev_get_by_name(req.name);
|
|
if (bdev == NULL) {
|
|
rc = -ENODEV;
|
|
goto invalid;
|
|
}
|
|
|
|
histogram = spdk_histogram_data_alloc();
|
|
if (histogram == NULL) {
|
|
rc = -ENOMEM;
|
|
goto invalid;
|
|
}
|
|
|
|
spdk_bdev_histogram_get(bdev, histogram, _spdk_rpc_bdev_histogram_data_cb, request);
|
|
|
|
free_rpc_get_bdev_histogram_request(&req);
|
|
return;
|
|
|
|
invalid:
|
|
free_rpc_get_bdev_histogram_request(&req);
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, spdk_strerror(-rc));
|
|
}
|
|
|
|
SPDK_RPC_REGISTER("get_bdev_histogram", spdk_rpc_get_bdev_histogram, SPDK_RPC_RUNTIME)
|