1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2020 Intel Corporation. 3 * Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 4 * All rights reserved. 5 */ 6 7 #include "spdk/rpc.h" 8 #include "spdk/util.h" 9 #include "spdk/bdev_module.h" 10 #include "spdk/string.h" 11 #include "spdk/log.h" 12 13 #include "bdev_ftl.h" 14 15 static int 16 rpc_bdev_ftl_decode_uuid(const struct spdk_json_val *val, void *out) 17 { 18 char *uuid_str; 19 int ret; 20 21 uuid_str = spdk_json_strdup(val); 22 if (!uuid_str) { 23 return -ENOMEM; 24 } 25 26 ret = spdk_uuid_parse(out, uuid_str); 27 28 free(uuid_str); 29 return ret; 30 } 31 32 static const struct spdk_json_object_decoder rpc_bdev_ftl_create_decoders[] = { 33 {"name", offsetof(struct spdk_ftl_conf, name), spdk_json_decode_string}, 34 {"base_bdev", offsetof(struct spdk_ftl_conf, base_bdev), spdk_json_decode_string}, 35 {"uuid", offsetof(struct spdk_ftl_conf, uuid), rpc_bdev_ftl_decode_uuid, true}, 36 {"cache", offsetof(struct spdk_ftl_conf, cache_bdev), spdk_json_decode_string}, 37 { 38 "overprovisioning", offsetof(struct spdk_ftl_conf, overprovisioning), 39 spdk_json_decode_uint64, true 40 }, 41 { 42 "l2p_dram_limit", offsetof(struct spdk_ftl_conf, l2p_dram_limit), 43 spdk_json_decode_uint64, true 44 }, 45 { 46 "core_mask", offsetof(struct spdk_ftl_conf, core_mask), 47 spdk_json_decode_string, true 48 }, 49 { 50 "fast_shutdown", offsetof(struct spdk_ftl_conf, fast_shutdown), 51 spdk_json_decode_bool, true 52 }, 53 }; 54 55 static void 56 rpc_bdev_ftl_create_cb(const struct ftl_bdev_info *bdev_info, void *ctx, int status) 57 { 58 struct spdk_jsonrpc_request *request = ctx; 59 char bdev_uuid[SPDK_UUID_STRING_LEN]; 60 struct spdk_json_write_ctx *w; 61 62 if (status) { 63 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 64 "Failed to create FTL bdev: %s", 65 spdk_strerror(-status)); 66 return; 67 } 68 69 w = spdk_jsonrpc_begin_result(request); 70 spdk_uuid_fmt_lower(bdev_uuid, sizeof(bdev_uuid), &bdev_info->uuid); 71 spdk_json_write_object_begin(w); 72 spdk_json_write_named_string(w, "name", bdev_info->name); 73 spdk_json_write_named_string(w, "uuid", bdev_uuid); 74 spdk_json_write_object_end(w); 75 spdk_jsonrpc_end_result(request, w); 76 } 77 78 static void 79 rpc_bdev_ftl_create(struct spdk_jsonrpc_request *request, 80 const struct spdk_json_val *params) 81 { 82 struct spdk_ftl_conf conf = {}; 83 struct spdk_json_write_ctx *w; 84 int rc; 85 86 spdk_ftl_get_default_conf(&conf, sizeof(conf)); 87 88 if (spdk_json_decode_object(params, rpc_bdev_ftl_create_decoders, 89 SPDK_COUNTOF(rpc_bdev_ftl_create_decoders), 90 &conf)) { 91 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 92 "Invalid parameters"); 93 goto out; 94 } 95 96 if (spdk_uuid_is_null(&conf.uuid)) { 97 conf.mode |= SPDK_FTL_MODE_CREATE; 98 } 99 100 rc = bdev_ftl_create_bdev(&conf, rpc_bdev_ftl_create_cb, request); 101 if (rc == -ENODEV) { 102 rc = bdev_ftl_defer_init(&conf); 103 if (rc == 0) { 104 w = spdk_jsonrpc_begin_result(request); 105 spdk_json_write_string_fmt(w, "FTL bdev: %s creation deferred", conf.name); 106 spdk_jsonrpc_end_result(request, w); 107 } 108 } 109 110 if (rc) { 111 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 112 "Failed to create FTL bdev: %s", 113 spdk_strerror(-rc)); 114 } 115 out: 116 spdk_ftl_conf_deinit(&conf); 117 } 118 SPDK_RPC_REGISTER("bdev_ftl_create", rpc_bdev_ftl_create, SPDK_RPC_RUNTIME) 119 120 static void 121 rpc_bdev_ftl_load(struct spdk_jsonrpc_request *request, 122 const struct spdk_json_val *params) 123 { 124 rpc_bdev_ftl_create(request, params); 125 } 126 SPDK_RPC_REGISTER("bdev_ftl_load", rpc_bdev_ftl_load, SPDK_RPC_RUNTIME) 127 128 struct rpc_delete_ftl { 129 char *name; 130 bool fast_shutdown; 131 }; 132 133 static const struct spdk_json_object_decoder rpc_delete_ftl_decoders[] = { 134 {"name", offsetof(struct rpc_delete_ftl, name), spdk_json_decode_string}, 135 { 136 "fast_shutdown", offsetof(struct rpc_delete_ftl, fast_shutdown), 137 spdk_json_decode_bool, true 138 }, 139 }; 140 141 static void 142 rpc_bdev_ftl_delete_cb(void *cb_arg, int bdeverrno) 143 { 144 struct spdk_jsonrpc_request *request = cb_arg; 145 146 if (bdeverrno == 0) { 147 spdk_jsonrpc_send_bool_response(request, true); 148 } else { 149 spdk_jsonrpc_send_error_response(request, bdeverrno, spdk_strerror(-bdeverrno)); 150 } 151 } 152 153 static void 154 rpc_bdev_ftl_delete(struct spdk_jsonrpc_request *request, 155 const struct spdk_json_val *params) 156 { 157 struct rpc_delete_ftl attrs = {}; 158 159 if (spdk_json_decode_object(params, rpc_delete_ftl_decoders, 160 SPDK_COUNTOF(rpc_delete_ftl_decoders), 161 &attrs)) { 162 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 163 "Invalid parameters"); 164 goto invalid; 165 } 166 167 bdev_ftl_delete_bdev(attrs.name, attrs.fast_shutdown, rpc_bdev_ftl_delete_cb, request); 168 invalid: 169 free(attrs.name); 170 } 171 SPDK_RPC_REGISTER("bdev_ftl_delete", rpc_bdev_ftl_delete, SPDK_RPC_RUNTIME) 172 173 static void 174 rpc_bdev_ftl_unload(struct spdk_jsonrpc_request *request, 175 const struct spdk_json_val *params) 176 { 177 rpc_bdev_ftl_delete(request, params); 178 } 179 SPDK_RPC_REGISTER("bdev_ftl_unload", rpc_bdev_ftl_unload, SPDK_RPC_RUNTIME) 180 181 struct rpc_ftl_unmap { 182 char *name; 183 uint64_t lba; 184 uint64_t num_blocks; 185 }; 186 187 static const struct spdk_json_object_decoder rpc_ftl_unmap_decoders[] = { 188 {"name", offsetof(struct rpc_delete_ftl, name), spdk_json_decode_string}, 189 {"lba", offsetof(struct rpc_ftl_unmap, lba), spdk_json_decode_uint64, true}, 190 {"num_blocks", offsetof(struct rpc_ftl_unmap, num_blocks), spdk_json_decode_uint64, true}, 191 }; 192 193 static void 194 rpc_bdev_ftl_unmap_cb(void *cb_arg, int bdeverrno) 195 { 196 struct spdk_jsonrpc_request *request = cb_arg; 197 198 if (bdeverrno == 0) { 199 spdk_jsonrpc_send_bool_response(request, true); 200 } else { 201 spdk_jsonrpc_send_error_response(request, bdeverrno, spdk_strerror(-bdeverrno)); 202 } 203 } 204 205 static void 206 rpc_bdev_ftl_unmap(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params) 207 { 208 struct rpc_ftl_unmap attrs = {}; 209 210 if (spdk_json_decode_object(params, rpc_ftl_unmap_decoders, SPDK_COUNTOF(rpc_ftl_unmap_decoders), 211 &attrs)) { 212 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 213 goto invalid; 214 } 215 216 bdev_ftl_unmap(attrs.name, attrs.lba, attrs.num_blocks, rpc_bdev_ftl_unmap_cb, request); 217 invalid: 218 free(attrs.name); 219 } 220 221 SPDK_RPC_REGISTER("bdev_ftl_unmap", rpc_bdev_ftl_unmap, SPDK_RPC_RUNTIME) 222 223 struct rpc_ftl_stats { 224 char *name; 225 }; 226 227 static const struct spdk_json_object_decoder rpc_ftl_stats_decoders[] = { 228 {"name", offsetof(struct rpc_ftl_stats, name), spdk_json_decode_string}, 229 }; 230 231 static void 232 _rpc_bdev_ftl_get_stats(void *cntx) 233 { 234 struct rpc_ftl_stats_ctx *ftl_stats = cntx; 235 struct spdk_jsonrpc_request *request = ftl_stats->request; 236 struct ftl_stats *stats = ftl_stats->ftl_stats; 237 struct spdk_json_write_ctx *w = spdk_jsonrpc_begin_result(request); 238 239 spdk_json_write_object_begin(w); 240 spdk_json_write_named_string(w, "name", spdk_bdev_desc_get_bdev(ftl_stats->ftl_bdev_desc)->name); 241 242 /* TODO: Instead of named objects, store them in an array with the name being an attribute */ 243 for (uint64_t i = 0; i < FTL_STATS_TYPE_MAX; i++) { 244 switch (i) { 245 case FTL_STATS_TYPE_USER: 246 spdk_json_write_named_object_begin(w, "user"); 247 break; 248 case FTL_STATS_TYPE_CMP: 249 spdk_json_write_named_object_begin(w, "cmp"); 250 break; 251 case FTL_STATS_TYPE_GC: 252 spdk_json_write_named_object_begin(w, "gc"); 253 break; 254 case FTL_STATS_TYPE_MD_BASE: 255 spdk_json_write_named_object_begin(w, "md_base"); 256 break; 257 case FTL_STATS_TYPE_MD_NV_CACHE: 258 spdk_json_write_named_object_begin(w, "md_nv_cache"); 259 break; 260 case FTL_STATS_TYPE_L2P: 261 spdk_json_write_named_object_begin(w, "l2p"); 262 break; 263 default: 264 assert(false); 265 continue; 266 } 267 268 spdk_json_write_named_object_begin(w, "read"); 269 spdk_json_write_named_uint64(w, "ios", stats->entries[i].read.ios); 270 spdk_json_write_named_uint64(w, "blocks", stats->entries[i].read.blocks); 271 spdk_json_write_named_object_begin(w, "errors"); 272 spdk_json_write_named_uint64(w, "media", stats->entries[i].read.errors.media); 273 spdk_json_write_named_uint64(w, "crc", stats->entries[i].read.errors.crc); 274 spdk_json_write_named_uint64(w, "other", stats->entries[i].read.errors.other); 275 spdk_json_write_object_end(w); 276 spdk_json_write_object_end(w); 277 278 spdk_json_write_named_object_begin(w, "write"); 279 spdk_json_write_named_uint64(w, "ios", stats->entries[i].write.ios); 280 spdk_json_write_named_uint64(w, "blocks", stats->entries[i].write.blocks); 281 spdk_json_write_named_object_begin(w, "errors"); 282 spdk_json_write_named_uint64(w, "media", stats->entries[i].write.errors.media); 283 spdk_json_write_named_uint64(w, "other", stats->entries[i].write.errors.other); 284 spdk_json_write_object_end(w); 285 spdk_json_write_object_end(w); 286 287 spdk_json_write_object_end(w); 288 } 289 290 spdk_json_write_object_end(w); 291 spdk_jsonrpc_end_result(request, w); 292 293 free(stats); 294 } 295 296 static void 297 rpc_bdev_ftl_get_stats(struct spdk_jsonrpc_request *request, 298 const struct spdk_json_val *params) 299 { 300 struct ftl_stats *stats; 301 struct rpc_ftl_stats attrs = {}; 302 int rc; 303 304 if (spdk_json_decode_object(params, rpc_ftl_stats_decoders, SPDK_COUNTOF(rpc_ftl_stats_decoders), 305 &attrs)) { 306 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 307 goto invalid; 308 } 309 310 stats = calloc(1, sizeof(struct ftl_stats)); 311 if (!stats) { 312 spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM)); 313 goto invalid; 314 } 315 316 rc = bdev_ftl_get_stats(attrs.name, _rpc_bdev_ftl_get_stats, request, stats); 317 if (rc) { 318 free(stats); 319 spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc)); 320 goto invalid; 321 } 322 323 invalid: 324 free(attrs.name); 325 } 326 327 SPDK_RPC_REGISTER("bdev_ftl_get_stats", rpc_bdev_ftl_get_stats, SPDK_RPC_RUNTIME) 328