1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) Intel Corporation. 3 * All rights reserved. 4 */ 5 6 #include "spdk/rpc.h" 7 #include "spdk/util.h" 8 #include "spdk/bdev_module.h" 9 #include "spdk/string.h" 10 #include "spdk/log.h" 11 12 #include "bdev_ftl.h" 13 14 struct rpc_bdev_ftl_create { 15 char *name; 16 char *base_bdev; 17 char *uuid; 18 char *cache_bdev; 19 struct spdk_ftl_conf ftl_conf; 20 }; 21 22 static void 23 free_rpc_bdev_ftl_create(struct rpc_bdev_ftl_create *req) 24 { 25 free(req->name); 26 free(req->base_bdev); 27 free(req->uuid); 28 free(req->cache_bdev); 29 free((char *)req->ftl_conf.l2p_path); 30 } 31 32 static const struct spdk_json_object_decoder rpc_bdev_ftl_create_decoders[] = { 33 {"name", offsetof(struct rpc_bdev_ftl_create, name), spdk_json_decode_string}, 34 {"base_bdev", offsetof(struct rpc_bdev_ftl_create, base_bdev), spdk_json_decode_string}, 35 {"uuid", offsetof(struct rpc_bdev_ftl_create, uuid), spdk_json_decode_string, true}, 36 {"cache", offsetof(struct rpc_bdev_ftl_create, cache_bdev), spdk_json_decode_string, true}, 37 { 38 "allow_open_bands", offsetof(struct rpc_bdev_ftl_create, ftl_conf) + 39 offsetof(struct spdk_ftl_conf, allow_open_bands), spdk_json_decode_bool, true 40 }, 41 { 42 "overprovisioning", offsetof(struct rpc_bdev_ftl_create, ftl_conf) + 43 offsetof(struct spdk_ftl_conf, lba_rsvd), spdk_json_decode_uint64, true 44 }, 45 { 46 "use_append", offsetof(struct rpc_bdev_ftl_create, ftl_conf) + 47 offsetof(struct spdk_ftl_conf, use_append), spdk_json_decode_bool, true 48 }, 49 { 50 "l2p_path", offsetof(struct rpc_bdev_ftl_create, ftl_conf) + 51 offsetof(struct spdk_ftl_conf, l2p_path), 52 spdk_json_decode_string, true 53 }, 54 { 55 "limit_crit", offsetof(struct rpc_bdev_ftl_create, ftl_conf) + 56 offsetof(struct spdk_ftl_conf, limits[SPDK_FTL_LIMIT_CRIT]) + 57 offsetof(struct spdk_ftl_limit, limit), 58 spdk_json_decode_uint64, true 59 }, 60 { 61 "limit_crit_threshold", offsetof(struct rpc_bdev_ftl_create, ftl_conf) + 62 offsetof(struct spdk_ftl_conf, limits[SPDK_FTL_LIMIT_CRIT]) + 63 offsetof(struct spdk_ftl_limit, thld), 64 spdk_json_decode_uint64, true 65 }, 66 { 67 "limit_high", offsetof(struct rpc_bdev_ftl_create, ftl_conf) + 68 offsetof(struct spdk_ftl_conf, limits[SPDK_FTL_LIMIT_HIGH]) + 69 offsetof(struct spdk_ftl_limit, limit), 70 spdk_json_decode_uint64, true 71 }, 72 { 73 "limit_high_threshold", offsetof(struct rpc_bdev_ftl_create, ftl_conf) + 74 offsetof(struct spdk_ftl_conf, limits[SPDK_FTL_LIMIT_HIGH]) + 75 offsetof(struct spdk_ftl_limit, thld), 76 spdk_json_decode_uint64, true 77 }, 78 { 79 "limit_low", offsetof(struct rpc_bdev_ftl_create, ftl_conf) + 80 offsetof(struct spdk_ftl_conf, limits[SPDK_FTL_LIMIT_LOW]) + 81 offsetof(struct spdk_ftl_limit, limit), 82 spdk_json_decode_uint64, true 83 }, 84 { 85 "limit_low_threshold", offsetof(struct rpc_bdev_ftl_create, ftl_conf) + 86 offsetof(struct spdk_ftl_conf, limits[SPDK_FTL_LIMIT_LOW]) + 87 offsetof(struct spdk_ftl_limit, thld), 88 spdk_json_decode_uint64, true 89 }, 90 { 91 "limit_start", offsetof(struct rpc_bdev_ftl_create, ftl_conf) + 92 offsetof(struct spdk_ftl_conf, limits[SPDK_FTL_LIMIT_START]) + 93 offsetof(struct spdk_ftl_limit, limit), 94 spdk_json_decode_uint64, true 95 }, 96 { 97 "limit_start_threshold", offsetof(struct rpc_bdev_ftl_create, ftl_conf) + 98 offsetof(struct spdk_ftl_conf, limits[SPDK_FTL_LIMIT_START]) + 99 offsetof(struct spdk_ftl_limit, thld), 100 spdk_json_decode_uint64, true 101 }, 102 }; 103 104 static void 105 rpc_bdev_ftl_create_cb(const struct ftl_bdev_info *bdev_info, void *ctx, int status) 106 { 107 struct spdk_jsonrpc_request *request = ctx; 108 char bdev_uuid[SPDK_UUID_STRING_LEN]; 109 struct spdk_json_write_ctx *w; 110 111 if (status) { 112 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 113 "Failed to create FTL bdev: %s", 114 spdk_strerror(-status)); 115 return; 116 } 117 118 w = spdk_jsonrpc_begin_result(request); 119 spdk_uuid_fmt_lower(bdev_uuid, sizeof(bdev_uuid), &bdev_info->uuid); 120 spdk_json_write_object_begin(w); 121 spdk_json_write_named_string(w, "name", bdev_info->name); 122 spdk_json_write_named_string(w, "uuid", bdev_uuid); 123 spdk_json_write_object_end(w); 124 spdk_jsonrpc_end_result(request, w); 125 } 126 127 static void 128 rpc_bdev_ftl_create(struct spdk_jsonrpc_request *request, 129 const struct spdk_json_val *params) 130 { 131 struct rpc_bdev_ftl_create req = {}; 132 struct ftl_bdev_init_opts opts = {}; 133 struct spdk_json_write_ctx *w; 134 int rc; 135 136 spdk_ftl_conf_init_defaults(&req.ftl_conf); 137 138 if (spdk_json_decode_object(params, rpc_bdev_ftl_create_decoders, 139 SPDK_COUNTOF(rpc_bdev_ftl_create_decoders), 140 &req)) { 141 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 142 "Invalid parameters"); 143 goto invalid; 144 } 145 146 if (req.cache_bdev && !spdk_bdev_get_by_name(req.cache_bdev)) { 147 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 148 "No such bdev: %s", req.cache_bdev); 149 goto invalid; 150 } 151 152 opts.name = req.name; 153 opts.mode = SPDK_FTL_MODE_CREATE; 154 opts.base_bdev = req.base_bdev; 155 opts.cache_bdev = req.cache_bdev; 156 opts.ftl_conf = req.ftl_conf; 157 158 if (req.uuid) { 159 if (spdk_uuid_parse(&opts.uuid, req.uuid) < 0) { 160 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 161 "Failed to parse uuid: %s", 162 req.uuid); 163 goto invalid; 164 } 165 166 if (!spdk_mem_all_zero(&opts.uuid, sizeof(opts.uuid))) { 167 opts.mode &= ~SPDK_FTL_MODE_CREATE; 168 } 169 } 170 171 rc = bdev_ftl_create_bdev(&opts, rpc_bdev_ftl_create_cb, request); 172 if (rc) { 173 if (rc == -ENODEV) { 174 w = spdk_jsonrpc_begin_result(request); 175 spdk_json_write_string_fmt(w, "FTL bdev: %s creation deferred", req.name); 176 spdk_jsonrpc_end_result(request, w); 177 } else { 178 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 179 "Failed to create FTL bdev: %s", 180 spdk_strerror(-rc)); 181 } 182 goto invalid; 183 } 184 185 invalid: 186 free_rpc_bdev_ftl_create(&req); 187 } 188 189 SPDK_RPC_REGISTER("bdev_ftl_create", rpc_bdev_ftl_create, SPDK_RPC_RUNTIME) 190 191 struct rpc_delete_ftl { 192 char *name; 193 }; 194 195 static const struct spdk_json_object_decoder rpc_delete_ftl_decoders[] = { 196 {"name", offsetof(struct rpc_bdev_ftl_create, name), spdk_json_decode_string}, 197 }; 198 199 static void 200 rpc_bdev_ftl_delete_cb(void *cb_arg, int bdeverrno) 201 { 202 struct spdk_jsonrpc_request *request = cb_arg; 203 204 if (bdeverrno == 0) { 205 spdk_jsonrpc_send_bool_response(request, true); 206 } else { 207 spdk_jsonrpc_send_error_response(request, bdeverrno, spdk_strerror(-bdeverrno)); 208 } 209 } 210 211 static void 212 rpc_bdev_ftl_delete(struct spdk_jsonrpc_request *request, 213 const struct spdk_json_val *params) 214 { 215 struct rpc_delete_ftl attrs = {}; 216 217 if (spdk_json_decode_object(params, rpc_delete_ftl_decoders, 218 SPDK_COUNTOF(rpc_delete_ftl_decoders), 219 &attrs)) { 220 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 221 "Invalid parameters"); 222 goto invalid; 223 } 224 225 bdev_ftl_delete_bdev(attrs.name, rpc_bdev_ftl_delete_cb, request); 226 invalid: 227 free(attrs.name); 228 } 229 230 SPDK_RPC_REGISTER("bdev_ftl_delete", rpc_bdev_ftl_delete, SPDK_RPC_RUNTIME) 231