Spdk/module/bdev/ftl/bdev_ftl_rpc.c
Kozlowski Mateusz 0e33da4974 ftl: fast shutdown
Adds API for fast shutdown - the ability for FTL to skip most
of the metadata persists made during clean shutdown, and relying
on their representation in shared memory instead. This allows for
faster update of SPDK (or just FTL, assuming no metadata changes),
with downtime reduction from 2-5 seconds to 500-1000 ms (for
14TiB+800GiB base and cache drives).

Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com>
Signed-off-by: Kozlowski Mateusz <mateusz.kozlowski@intel.com>
Change-Id: I5999d31698a81512db8d5893eabee7b505c80d06
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/13348
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>
2022-08-30 14:48:50 +00:00

171 lines
4.6 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright (c) 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
},
{
"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);
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)