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