From be90ea6e7bfbcf8a5704410fc5ebe25b11dd0d54 Mon Sep 17 00:00:00 2001 From: Artur Paszkiewicz Date: Fri, 15 Jul 2022 19:48:17 -0700 Subject: [PATCH] FTL: Add bdev_ftl_create and delete rpc definitions Signed-off-by: Kozlowski Mateusz Signed-off-by: Artur Paszkiewicz Change-Id: I0837028fbe349e8df7f05fb3c9db1f4682f04679 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/13301 Community-CI: Mellanox Build Bot Tested-by: SPDK CI Jenkins Reviewed-by: Jim Harris Reviewed-by: Ben Walker --- doc/jsonrpc.md | 116 +++++++++++++++++++++--- mk/spdk.lib_deps.mk | 2 +- module/bdev/ftl/Makefile | 2 +- module/bdev/ftl/bdev_ftl_rpc.c | 161 +++++++++++++++++++++++++++++++++ python/spdk/rpc/bdev.py | 28 ++++++ scripts/rpc.py | 72 +++++++-------- 6 files changed, 332 insertions(+), 49 deletions(-) create mode 100644 module/bdev/ftl/bdev_ftl_rpc.c diff --git a/doc/jsonrpc.md b/doc/jsonrpc.md index be5281b05..cbf161b2d 100644 --- a/doc/jsonrpc.md +++ b/doc/jsonrpc.md @@ -465,7 +465,9 @@ Example response: "bdev_malloc_delete", "bdev_malloc_create", "bdev_ftl_delete", + "bdev_ftl_unload", "bdev_ftl_create", + "bdev_ftl_load", "bdev_lvol_get_lvstores", "bdev_lvol_delete", "bdev_lvol_resize", @@ -4564,11 +4566,11 @@ This RPC is subject to change. Name | Optional | Type | Description ----------------------- | -------- | ----------- | ----------- name | Required | string | Bdev name -trtype | Required | string | Transport type -traddr | Required | string | NVMe target address -punits | Required | string | Parallel unit range in the form of start-end e.g 4-8 +base_bdev | Required | string | Name of the base device +cache | Required | string | Name of the cache device uuid | Optional | string | UUID of restored bdev (not applicable when creating new instance) -cache | Optional | string | Name of the bdev to be used as a write buffer cache +core_mask | Optional | string | CPU core(s) possible for placement of the ftl core thread, application main thread by default +overprovisioning | Optional | int | Percentage of base device used for relocation, 20% by default #### Result @@ -4581,11 +4583,12 @@ Example request: ~~~json { "params": { - "name": "nvme0" - "trtype" "pcie" - "traddr": "0000:00:04.0" - "punits": "0-3" - "uuid": "4a7481ce-786f-41a0-9b86-8f7465c8f4d3" + "name": "ftl0", + "base_bdev": "nvme0n1", + "cache": "nvme1n1", + "uuid": "4a7481ce-786f-41a0-9b86-8f7465c8f4d3", + "core_mask": "[0]", + "overprovisioning": 10 }, "jsonrpc": "2.0", "method": "bdev_ftl_create", @@ -4600,7 +4603,61 @@ Example response: "jsonrpc": "2.0", "id": 1, "result": { - "name" : "nvme0" + "name" : "ftl0" + "uuid" : "4a7481ce-786f-41a0-9b86-8f7465c8f4d3" + } +} +~~~ + +### bdev_ftl_load {#rpc_bdev_ftl_load} + +Loads FTL bdev. + +This RPC is subject to change. + +#### Parameters + +Name | Optional | Type | Description +----------------------- | -------- | ----------- | ----------- +name | Required | string | Bdev name +base_bdev | Required | string | Name of the base device +cache | Required | string | Name of the cache device +uuid | Required | string | UUID of restored bdev +core_mask | Optional | string | CPU core(s) possible for placement of the ftl core thread, application main thread by default +overprovisioning | Optional | int | Percentage of base device used for relocation, 20% by default + +#### Result + +Name of loaded bdev. + +#### Example + +Example request: + +~~~json +{ + "params": { + "name": "ftl0", + "base_bdev": "nvme0n1", + "cache": "nvme1n1", + "uuid": "4a7481ce-786f-41a0-9b86-8f7465c8f4d3", + "core_mask": "[0]", + "overprovisioning": 10 + }, + "jsonrpc": "2.0", + "method": "bdev_ftl_load", + "id": 1 +} +~~~ + +Example response: + +~~~json +{ + "jsonrpc": "2.0", + "id": 1, + "result": { + "name" : "ftl0" "uuid" : "4a7481ce-786f-41a0-9b86-8f7465c8f4d3" } } @@ -4625,7 +4682,7 @@ Example request: ~~~json { "params": { - "name": "nvme0" + "name": "ftl0" }, "jsonrpc": "2.0", "method": "bdev_ftl_delete", @@ -4643,6 +4700,43 @@ Example response: } ~~~ +### bdev_ftl_unload {#rpc_bdev_ftl_unload} + +Unloads FTL bdev. + +This RPC is subject to change. + +#### Parameters + +Name | Optional | Type | Description +----------------------- | -------- | ----------- | ----------- +name | Required | string | Bdev name + +#### Example + +Example request: + +~~~json +{ + "params": { + "name": "ftl0" + }, + "jsonrpc": "2.0", + "method": "bdev_ftl_unload", + "id": 1 +} +~~~ + +Example response: + +~~~json +{ + "jsonrpc": "2.0", + "id": 1, + "result": true +} +~~~ + ### bdev_pmem_create_pool {#rpc_bdev_pmem_create_pool} Create a @ref bdev_config_pmem blk pool file. It is equivalent of following `pmempool create` command: diff --git a/mk/spdk.lib_deps.mk b/mk/spdk.lib_deps.mk index 8c7f09f6e..1cd59c726 100644 --- a/mk/spdk.lib_deps.mk +++ b/mk/spdk.lib_deps.mk @@ -110,7 +110,7 @@ endif # module/bdev ifeq ($(OS),Linux) -DEPDIRS-bdev_ftl := bdev json log util ftl +DEPDIRS-bdev_ftl := $(BDEV_DEPS) ftl endif DEPDIRS-bdev_gpt := bdev json log thread util diff --git a/module/bdev/ftl/Makefile b/module/bdev/ftl/Makefile index 1d8e004f3..3b53425b4 100644 --- a/module/bdev/ftl/Makefile +++ b/module/bdev/ftl/Makefile @@ -15,7 +15,7 @@ ifdef SPDK_FTL_VSS_EMU CFLAGS += -DSPDK_FTL_VSS_EMU endif -C_SRCS += bdev_ftl.c +C_SRCS += bdev_ftl.c bdev_ftl_rpc.c LIBNAME = bdev_ftl SPDK_MAP_FILE = $(SPDK_ROOT_DIR)/mk/spdk_blank.map diff --git a/module/bdev/ftl/bdev_ftl_rpc.c b/module/bdev/ftl/bdev_ftl_rpc.c new file mode 100644 index 000000000..4929630df --- /dev/null +++ b/module/bdev/ftl/bdev_ftl_rpc.c @@ -0,0 +1,161 @@ +/* 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 + }, +}; + +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; +}; + +static const struct spdk_json_object_decoder rpc_delete_ftl_decoders[] = { + {"name", offsetof(struct rpc_delete_ftl, name), spdk_json_decode_string}, +}; + +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, 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) diff --git a/python/spdk/rpc/bdev.py b/python/spdk/rpc/bdev.py index ff1f4e3d2..2b5e81c65 100644 --- a/python/spdk/rpc/bdev.py +++ b/python/spdk/rpc/bdev.py @@ -1347,6 +1347,34 @@ def bdev_ftl_create(client, name, base_bdev, **kwargs): return client.call('bdev_ftl_create', params) +def bdev_ftl_load(client, name, base_bdev, **kwargs): + """Load FTL bdev + + Args: + name: name of the bdev + base_bdev: name of the base bdev + kwargs: optional parameters + """ + params = {'name': name, + 'base_bdev': base_bdev} + for key, value in kwargs.items(): + if value is not None: + params[key] = value + + return client.call('bdev_ftl_load', params) + + +def bdev_ftl_unload(client, name): + """Unload FTL bdev + + Args: + name: name of the bdev + """ + params = {'name': name} + + return client.call('bdev_ftl_unload', params) + + def bdev_ftl_delete(client, name): """Delete FTL bdev diff --git a/scripts/rpc.py b/scripts/rpc.py index d94e20f26..f1b96cac7 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -1993,58 +1993,58 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse p.set_defaults(func=bdev_split_delete) # ftl - ftl_valid_limits = ('crit', 'high', 'low', 'start') - def bdev_ftl_create(args): - def parse_limits(limits, arg_dict, key_suffix=''): - for limit in limits.split(','): - key, value = limit.split(':', 1) - if key in ftl_valid_limits: - arg_dict['limit_' + key + key_suffix] = int(value) - else: - raise ValueError('Limit {} is not supported'.format(key)) - - arg_limits = {} - if args.limit_threshold: - parse_limits(args.limit_threshold, arg_limits, '_threshold') - - if args.limit: - parse_limits(args.limit, arg_limits) - print_dict(rpc.bdev.bdev_ftl_create(args.client, name=args.name, base_bdev=args.base_bdev, uuid=args.uuid, cache=args.cache, - allow_open_bands=args.allow_open_bands, overprovisioning=args.overprovisioning, - l2p_path=args.l2p_path, - use_append=args.use_append, - **arg_limits)) + core_mask=args.core_mask)) p = subparsers.add_parser('bdev_ftl_create', help='Add FTL bdev') p.add_argument('-b', '--name', help="Name of the bdev", required=True) - p.add_argument('-d', '--base-bdev', help='Name of zoned bdev used as underlying device', + p.add_argument('-d', '--base-bdev', help='Name of bdev used as underlying device', required=True) p.add_argument('-u', '--uuid', help='UUID of restored bdev (not applicable when creating new ' 'instance): e.g. b286d19a-0059-4709-abcd-9f7732b1567d (optional)') - p.add_argument('-c', '--cache', help='Name of the bdev to be used as a write buffer cache (optional)') - p.add_argument('-o', '--allow-open-bands', help='Restoring after dirty shutdown without cache will' - ' result in partial data recovery, instead of error', action='store_true') + p.add_argument('-c', '--cache', help='Name of the bdev to be used as a write buffer cache', + required=True) p.add_argument('--overprovisioning', help='Percentage of device used for relocation, not exposed' - ' to user (optional)', type=int) - p.add_argument('--l2p-path', help='Path to persistent memory file or device to store l2p onto, ' - 'by default l2p is kept in DRAM and is volatile (optional)') - p.add_argument('--use-append', help='Use appends instead of writes', action='store_true') - - limits = p.add_argument_group('Defrag limits', 'Configures defrag limits and thresholds for' - ' levels ' + str(ftl_valid_limits)[1:-1]) - limits.add_argument('--limit', help='Percentage of allowed user versus internal writes at given' - ' levels, e.g. crit:0,high:20,low:80') - limits.add_argument('--limit-threshold', help='Number of free bands triggering a given level of' - ' write limiting e.g. crit:1,high:2,low:3,start:4') + ' to user (optional); default 20', type=int) + p.add_argument('--core-mask', help='CPU core mask - which cores will be used for ftl core thread, ' + 'by default core thread will be set to the main application core (optional)') p.set_defaults(func=bdev_ftl_create) + def bdev_ftl_load(args): + print_dict(rpc.bdev.bdev_ftl_load(args.client, + name=args.name, + base_bdev=args.base_bdev, + uuid=args.uuid, + cache=args.cache, + overprovisioning=args.overprovisioning, + core_mask=args.core_mask)) + + p = subparsers.add_parser('bdev_ftl_load', help='Load FTL bdev') + p.add_argument('-b', '--name', help="Name of the bdev", required=True) + p.add_argument('-d', '--base-bdev', help='Name of bdev used as underlying device', + required=True) + p.add_argument('-u', '--uuid', help='UUID of restored bdev', required=True) + p.add_argument('-c', '--cache', help='Name of the bdev to be used as a write buffer cache', + required=True) + p.add_argument('--overprovisioning', help='Percentage of device used for relocation, not exposed' + ' to user (optional); default 20', type=int) + p.add_argument('--core-mask', help='CPU core mask - which cores will be used for ftl core thread, ' + 'by default core thread will be set to the main application core (optional)') + p.set_defaults(func=bdev_ftl_load) + + def bdev_ftl_unload(args): + print_dict(rpc.bdev.bdev_ftl_unload(args.client, name=args.name)) + + p = subparsers.add_parser('bdev_ftl_unload', help='Unload FTL bdev') + p.add_argument('-b', '--name', help="Name of the bdev", required=True) + p.set_defaults(func=bdev_ftl_unload) + def bdev_ftl_delete(args): print_dict(rpc.bdev.bdev_ftl_delete(args.client, name=args.name))