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