per Intel policy to include file commit date using git cmd below. The policy does not apply to non-Intel (C) notices. git log --follow -C90% --format=%ad --date default <file> | tail -1 and then pull just the 4 digit year from the result. Intel copyrights were not added to files where Intel either had no contribution ot the contribution lacked substance (ie license header updates, formatting changes, etc). Contribution date used "--follow -C95%" to get the most accurate date. Note that several files in this patch didn't end the license/(c) block with a blank comment line so these were added as the vast majority of files do have this last blank line. Simply there for consistency. Signed-off-by: paul luse <paul.e.luse@intel.com> Change-Id: Id5b7ce4f658fe87132f14139ead58d6e285c04d4 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15192 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com> Community-CI: Mellanox Build Bot
319 lines
9.1 KiB
C
319 lines
9.1 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright (C) 2020 Intel Corporation.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
#include "spdk/rpc.h"
|
|
#include "spdk/util.h"
|
|
#include "spdk/bdev_module.h"
|
|
#include "spdk/string.h"
|
|
#include "spdk/log.h"
|
|
|
|
#include "bdev_ftl.h"
|
|
|
|
static int
|
|
rpc_bdev_ftl_decode_uuid(const struct spdk_json_val *val, void *out)
|
|
{
|
|
char *uuid_str;
|
|
int ret;
|
|
|
|
uuid_str = spdk_json_strdup(val);
|
|
if (!uuid_str) {
|
|
return -ENOMEM;
|
|
}
|
|
|
|
ret = spdk_uuid_parse(out, uuid_str);
|
|
|
|
free(uuid_str);
|
|
return ret;
|
|
}
|
|
|
|
static const struct spdk_json_object_decoder rpc_bdev_ftl_create_decoders[] = {
|
|
{"name", offsetof(struct spdk_ftl_conf, name), spdk_json_decode_string},
|
|
{"base_bdev", offsetof(struct spdk_ftl_conf, base_bdev), spdk_json_decode_string},
|
|
{"uuid", offsetof(struct spdk_ftl_conf, uuid), rpc_bdev_ftl_decode_uuid, true},
|
|
{"cache", offsetof(struct spdk_ftl_conf, cache_bdev), spdk_json_decode_string},
|
|
{
|
|
"overprovisioning", offsetof(struct spdk_ftl_conf, overprovisioning),
|
|
spdk_json_decode_uint64, true
|
|
},
|
|
{
|
|
"l2p_dram_limit", offsetof(struct spdk_ftl_conf, l2p_dram_limit),
|
|
spdk_json_decode_uint64, true
|
|
},
|
|
{
|
|
"core_mask", offsetof(struct spdk_ftl_conf, core_mask),
|
|
spdk_json_decode_string, true
|
|
},
|
|
{
|
|
"fast_shutdown", offsetof(struct spdk_ftl_conf, fast_shutdown),
|
|
spdk_json_decode_bool, true
|
|
},
|
|
};
|
|
|
|
static void
|
|
rpc_bdev_ftl_create_cb(const struct ftl_bdev_info *bdev_info, void *ctx, int status)
|
|
{
|
|
struct spdk_jsonrpc_request *request = ctx;
|
|
char bdev_uuid[SPDK_UUID_STRING_LEN];
|
|
struct spdk_json_write_ctx *w;
|
|
|
|
if (status) {
|
|
spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
|
|
"Failed to create FTL bdev: %s",
|
|
spdk_strerror(-status));
|
|
return;
|
|
}
|
|
|
|
w = spdk_jsonrpc_begin_result(request);
|
|
spdk_uuid_fmt_lower(bdev_uuid, sizeof(bdev_uuid), &bdev_info->uuid);
|
|
spdk_json_write_object_begin(w);
|
|
spdk_json_write_named_string(w, "name", bdev_info->name);
|
|
spdk_json_write_named_string(w, "uuid", bdev_uuid);
|
|
spdk_json_write_object_end(w);
|
|
spdk_jsonrpc_end_result(request, w);
|
|
}
|
|
|
|
static void
|
|
rpc_bdev_ftl_create(struct spdk_jsonrpc_request *request,
|
|
const struct spdk_json_val *params)
|
|
{
|
|
struct spdk_ftl_conf conf = {};
|
|
struct spdk_json_write_ctx *w;
|
|
int rc;
|
|
|
|
spdk_ftl_get_default_conf(&conf, sizeof(conf));
|
|
|
|
if (spdk_json_decode_object(params, rpc_bdev_ftl_create_decoders,
|
|
SPDK_COUNTOF(rpc_bdev_ftl_create_decoders),
|
|
&conf)) {
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
|
|
"Invalid parameters");
|
|
goto out;
|
|
}
|
|
|
|
if (spdk_mem_all_zero(&conf.uuid, sizeof(conf.uuid))) {
|
|
conf.mode |= SPDK_FTL_MODE_CREATE;
|
|
}
|
|
|
|
rc = bdev_ftl_create_bdev(&conf, rpc_bdev_ftl_create_cb, request);
|
|
if (rc == -ENODEV) {
|
|
rc = bdev_ftl_defer_init(&conf);
|
|
if (rc == 0) {
|
|
w = spdk_jsonrpc_begin_result(request);
|
|
spdk_json_write_string_fmt(w, "FTL bdev: %s creation deferred", conf.name);
|
|
spdk_jsonrpc_end_result(request, w);
|
|
}
|
|
}
|
|
|
|
if (rc) {
|
|
spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
|
|
"Failed to create FTL bdev: %s",
|
|
spdk_strerror(-rc));
|
|
}
|
|
out:
|
|
spdk_ftl_conf_deinit(&conf);
|
|
}
|
|
SPDK_RPC_REGISTER("bdev_ftl_create", rpc_bdev_ftl_create, SPDK_RPC_RUNTIME)
|
|
|
|
static void
|
|
rpc_bdev_ftl_load(struct spdk_jsonrpc_request *request,
|
|
const struct spdk_json_val *params)
|
|
{
|
|
rpc_bdev_ftl_create(request, params);
|
|
}
|
|
SPDK_RPC_REGISTER("bdev_ftl_load", rpc_bdev_ftl_load, SPDK_RPC_RUNTIME)
|
|
|
|
struct rpc_delete_ftl {
|
|
char *name;
|
|
bool fast_shutdown;
|
|
};
|
|
|
|
static const struct spdk_json_object_decoder rpc_delete_ftl_decoders[] = {
|
|
{"name", offsetof(struct rpc_delete_ftl, name), spdk_json_decode_string},
|
|
{
|
|
"fast_shutdown", offsetof(struct rpc_delete_ftl, fast_shutdown),
|
|
spdk_json_decode_bool, true
|
|
},
|
|
};
|
|
|
|
static void
|
|
rpc_bdev_ftl_delete_cb(void *cb_arg, int bdeverrno)
|
|
{
|
|
struct spdk_jsonrpc_request *request = cb_arg;
|
|
|
|
spdk_jsonrpc_send_bool_response(request, bdeverrno == 0);
|
|
}
|
|
|
|
static void
|
|
rpc_bdev_ftl_delete(struct spdk_jsonrpc_request *request,
|
|
const struct spdk_json_val *params)
|
|
{
|
|
struct rpc_delete_ftl attrs = {};
|
|
|
|
if (spdk_json_decode_object(params, rpc_delete_ftl_decoders,
|
|
SPDK_COUNTOF(rpc_delete_ftl_decoders),
|
|
&attrs)) {
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
|
|
"Invalid parameters");
|
|
goto invalid;
|
|
}
|
|
|
|
bdev_ftl_delete_bdev(attrs.name, attrs.fast_shutdown, rpc_bdev_ftl_delete_cb, request);
|
|
invalid:
|
|
free(attrs.name);
|
|
}
|
|
SPDK_RPC_REGISTER("bdev_ftl_delete", rpc_bdev_ftl_delete, SPDK_RPC_RUNTIME)
|
|
|
|
static void
|
|
rpc_bdev_ftl_unload(struct spdk_jsonrpc_request *request,
|
|
const struct spdk_json_val *params)
|
|
{
|
|
rpc_bdev_ftl_delete(request, params);
|
|
}
|
|
SPDK_RPC_REGISTER("bdev_ftl_unload", rpc_bdev_ftl_unload, SPDK_RPC_RUNTIME)
|
|
|
|
struct rpc_ftl_unmap {
|
|
char *name;
|
|
uint64_t lba;
|
|
uint64_t num_blocks;
|
|
};
|
|
|
|
static const struct spdk_json_object_decoder rpc_ftl_unmap_decoders[] = {
|
|
{"name", offsetof(struct rpc_delete_ftl, name), spdk_json_decode_string},
|
|
{"lba", offsetof(struct rpc_ftl_unmap, lba), spdk_json_decode_uint64, true},
|
|
{"num_blocks", offsetof(struct rpc_ftl_unmap, num_blocks), spdk_json_decode_uint64, true},
|
|
};
|
|
|
|
static void
|
|
rpc_bdev_ftl_unmap_cb(void *cb_arg, int bdeverrno)
|
|
{
|
|
struct spdk_jsonrpc_request *request = cb_arg;
|
|
|
|
spdk_jsonrpc_send_bool_response(request, bdeverrno == 0);
|
|
}
|
|
|
|
static void
|
|
rpc_bdev_ftl_unmap(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params)
|
|
{
|
|
struct rpc_ftl_unmap attrs = {};
|
|
|
|
if (spdk_json_decode_object(params, rpc_ftl_unmap_decoders, SPDK_COUNTOF(rpc_ftl_unmap_decoders),
|
|
&attrs)) {
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
|
|
goto invalid;
|
|
}
|
|
|
|
bdev_ftl_unmap(attrs.name, attrs.lba, attrs.num_blocks, rpc_bdev_ftl_unmap_cb, request);
|
|
invalid:
|
|
free(attrs.name);
|
|
}
|
|
|
|
SPDK_RPC_REGISTER("bdev_ftl_unmap", rpc_bdev_ftl_unmap, SPDK_RPC_RUNTIME)
|
|
|
|
struct rpc_ftl_stats {
|
|
char *name;
|
|
};
|
|
|
|
static const struct spdk_json_object_decoder rpc_ftl_stats_decoders[] = {
|
|
{"name", offsetof(struct rpc_ftl_stats, name), spdk_json_decode_string},
|
|
};
|
|
|
|
static void
|
|
_rpc_bdev_ftl_get_stats(void *cntx)
|
|
{
|
|
struct rpc_ftl_stats_ctx *ftl_stats = cntx;
|
|
struct spdk_jsonrpc_request *request = ftl_stats->request;
|
|
struct ftl_stats *stats = ftl_stats->ftl_stats;
|
|
struct spdk_json_write_ctx *w = spdk_jsonrpc_begin_result(request);
|
|
|
|
spdk_json_write_object_begin(w);
|
|
spdk_json_write_named_string(w, "name", spdk_bdev_desc_get_bdev(ftl_stats->ftl_bdev_desc)->name);
|
|
|
|
/* TODO: Instead of named objects, store them in an array with the name being an attribute */
|
|
for (uint64_t i = 0; i < FTL_STATS_TYPE_MAX; i++) {
|
|
switch (i) {
|
|
case FTL_STATS_TYPE_USER:
|
|
spdk_json_write_named_object_begin(w, "user");
|
|
break;
|
|
case FTL_STATS_TYPE_CMP:
|
|
spdk_json_write_named_object_begin(w, "cmp");
|
|
break;
|
|
case FTL_STATS_TYPE_GC:
|
|
spdk_json_write_named_object_begin(w, "gc");
|
|
break;
|
|
case FTL_STATS_TYPE_MD_BASE:
|
|
spdk_json_write_named_object_begin(w, "md_base");
|
|
break;
|
|
case FTL_STATS_TYPE_MD_NV_CACHE:
|
|
spdk_json_write_named_object_begin(w, "md_nv_cache");
|
|
break;
|
|
case FTL_STATS_TYPE_L2P:
|
|
spdk_json_write_named_object_begin(w, "l2p");
|
|
break;
|
|
default:
|
|
assert(false);
|
|
continue;
|
|
}
|
|
|
|
spdk_json_write_named_object_begin(w, "read");
|
|
spdk_json_write_named_uint64(w, "ios", stats->entries[i].read.ios);
|
|
spdk_json_write_named_uint64(w, "blocks", stats->entries[i].read.blocks);
|
|
spdk_json_write_named_object_begin(w, "errors");
|
|
spdk_json_write_named_uint64(w, "media", stats->entries[i].read.errors.media);
|
|
spdk_json_write_named_uint64(w, "crc", stats->entries[i].read.errors.crc);
|
|
spdk_json_write_named_uint64(w, "other", stats->entries[i].read.errors.other);
|
|
spdk_json_write_object_end(w);
|
|
spdk_json_write_object_end(w);
|
|
|
|
spdk_json_write_named_object_begin(w, "write");
|
|
spdk_json_write_named_uint64(w, "ios", stats->entries[i].write.ios);
|
|
spdk_json_write_named_uint64(w, "blocks", stats->entries[i].write.blocks);
|
|
spdk_json_write_named_object_begin(w, "errors");
|
|
spdk_json_write_named_uint64(w, "media", stats->entries[i].write.errors.media);
|
|
spdk_json_write_named_uint64(w, "other", stats->entries[i].write.errors.other);
|
|
spdk_json_write_object_end(w);
|
|
spdk_json_write_object_end(w);
|
|
|
|
spdk_json_write_object_end(w);
|
|
}
|
|
|
|
spdk_json_write_object_end(w);
|
|
spdk_jsonrpc_end_result(request, w);
|
|
|
|
free(stats);
|
|
}
|
|
|
|
static void
|
|
rpc_bdev_ftl_get_stats(struct spdk_jsonrpc_request *request,
|
|
const struct spdk_json_val *params)
|
|
{
|
|
struct ftl_stats *stats;
|
|
struct rpc_ftl_stats attrs = {};
|
|
int rc;
|
|
|
|
if (spdk_json_decode_object(params, rpc_ftl_stats_decoders, SPDK_COUNTOF(rpc_ftl_stats_decoders),
|
|
&attrs)) {
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
|
|
goto invalid;
|
|
}
|
|
|
|
stats = calloc(1, sizeof(struct ftl_stats));
|
|
if (!stats) {
|
|
spdk_jsonrpc_send_bool_response(request, false);
|
|
goto invalid;
|
|
}
|
|
|
|
rc = bdev_ftl_get_stats(attrs.name, _rpc_bdev_ftl_get_stats, request, stats);
|
|
if (rc) {
|
|
free(stats);
|
|
spdk_jsonrpc_send_bool_response(request, false);
|
|
goto invalid;
|
|
}
|
|
|
|
invalid:
|
|
free(attrs.name);
|
|
}
|
|
|
|
SPDK_RPC_REGISTER("bdev_ftl_get_stats", rpc_bdev_ftl_get_stats, SPDK_RPC_RUNTIME)
|