xref: /spdk/module/bdev/ftl/bdev_ftl_rpc.c (revision 307b8c112ffd90a26d53dd15fad67bd9038ef526)
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 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