xref: /spdk/module/bdev/ocf/vbdev_ocf_rpc.c (revision 488570ebd418ba07c9e69e65106dcc964f3bb41b)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (c) Intel Corporation.
3  *   All rights reserved.
4  */
5 
6 #include "vbdev_ocf.h"
7 #include "stats.h"
8 #include "utils.h"
9 #include "spdk/log.h"
10 #include "spdk/rpc.h"
11 #include "spdk/string.h"
12 
13 /* Structure to hold the parameters for this RPC method. */
14 struct rpc_bdev_ocf_create {
15 	char *name;			/* main vbdev */
16 	char *mode;			/* OCF mode (choose one) */
17 	uint64_t cache_line_size;	/* OCF cache line size */
18 	char *cache_bdev_name;		/* sub bdev */
19 	char *core_bdev_name;		/* sub bdev */
20 };
21 
22 static void
23 free_rpc_bdev_ocf_create(struct rpc_bdev_ocf_create *r)
24 {
25 	free(r->name);
26 	free(r->core_bdev_name);
27 	free(r->cache_bdev_name);
28 	free(r->mode);
29 }
30 
31 /* Structure to decode the input parameters for this RPC method. */
32 static const struct spdk_json_object_decoder rpc_bdev_ocf_create_decoders[] = {
33 	{"name", offsetof(struct rpc_bdev_ocf_create, name), spdk_json_decode_string},
34 	{"mode", offsetof(struct rpc_bdev_ocf_create, mode), spdk_json_decode_string},
35 	{"cache_line_size", offsetof(struct rpc_bdev_ocf_create, cache_line_size), spdk_json_decode_uint64, true},
36 	{"cache_bdev_name", offsetof(struct rpc_bdev_ocf_create, cache_bdev_name), spdk_json_decode_string},
37 	{"core_bdev_name", offsetof(struct rpc_bdev_ocf_create, core_bdev_name), spdk_json_decode_string},
38 };
39 
40 static void
41 construct_cb(int status, struct vbdev_ocf *vbdev, void *cb_arg)
42 {
43 	struct spdk_jsonrpc_request *request = cb_arg;
44 	struct spdk_json_write_ctx *w;
45 
46 	if (status) {
47 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
48 						     "Could not create OCF vbdev: %d",
49 						     status);
50 	} else {
51 		w = spdk_jsonrpc_begin_result(request);
52 		spdk_json_write_string(w, vbdev->name);
53 		spdk_jsonrpc_end_result(request, w);
54 	}
55 }
56 
57 static void
58 rpc_bdev_ocf_create(struct spdk_jsonrpc_request *request,
59 		    const struct spdk_json_val *params)
60 {
61 	struct rpc_bdev_ocf_create req = {NULL};
62 	int ret;
63 
64 	ret = spdk_json_decode_object(params, rpc_bdev_ocf_create_decoders,
65 				      SPDK_COUNTOF(rpc_bdev_ocf_create_decoders),
66 				      &req);
67 	if (ret) {
68 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
69 						 "Invalid parameters");
70 		free_rpc_bdev_ocf_create(&req);
71 		return;
72 	}
73 
74 	vbdev_ocf_construct(req.name, req.mode, req.cache_line_size, req.cache_bdev_name,
75 			    req.core_bdev_name, false, construct_cb, request);
76 	free_rpc_bdev_ocf_create(&req);
77 }
78 SPDK_RPC_REGISTER("bdev_ocf_create", rpc_bdev_ocf_create, SPDK_RPC_RUNTIME)
79 
80 /* Structure to hold the parameters for this RPC method. */
81 struct rpc_bdev_ocf_delete {
82 	char *name;             /* main vbdev name */
83 };
84 
85 static void
86 free_rpc_bdev_ocf_delete(struct rpc_bdev_ocf_delete *r)
87 {
88 	free(r->name);
89 }
90 
91 /* Structure to decode the input parameters for this RPC method. */
92 static const struct spdk_json_object_decoder rpc_bdev_ocf_delete_decoders[] = {
93 	{"name", offsetof(struct rpc_bdev_ocf_delete, name), spdk_json_decode_string},
94 };
95 
96 static void
97 delete_cb(void *cb_arg, int status)
98 {
99 	struct spdk_jsonrpc_request *request = cb_arg;
100 
101 	if (status) {
102 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
103 						     "Could not delete OCF vbdev: %d",
104 						     status);
105 	} else {
106 		spdk_jsonrpc_send_bool_response(request, true);
107 	}
108 }
109 
110 static void
111 rpc_bdev_ocf_delete(struct spdk_jsonrpc_request *request,
112 		    const struct spdk_json_val *params)
113 {
114 	struct rpc_bdev_ocf_delete req = {NULL};
115 	struct vbdev_ocf *vbdev;
116 	int status;
117 
118 	status = spdk_json_decode_object(params, rpc_bdev_ocf_delete_decoders,
119 					 SPDK_COUNTOF(rpc_bdev_ocf_delete_decoders),
120 					 &req);
121 	if (status) {
122 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
123 						 "Invalid parameters");
124 		goto end;
125 	}
126 
127 	vbdev = vbdev_ocf_get_by_name(req.name);
128 	if (vbdev == NULL) {
129 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
130 						 spdk_strerror(ENODEV));
131 		goto end;
132 	}
133 
134 	status = vbdev_ocf_delete_clean(vbdev, delete_cb, request);
135 	if (status) {
136 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
137 						     "Could not delete OCF vbdev: %s",
138 						     spdk_strerror(-status));
139 		goto end;
140 	}
141 
142 end:
143 	free_rpc_bdev_ocf_delete(&req);
144 }
145 SPDK_RPC_REGISTER("bdev_ocf_delete", rpc_bdev_ocf_delete, SPDK_RPC_RUNTIME)
146 
147 /* Structure to hold the parameters for this RPC method. */
148 struct rpc_bdev_ocf_get_stats {
149 	char *name;             /* main vbdev name */
150 };
151 
152 static void
153 free_rpc_bdev_ocf_get_stats(struct rpc_bdev_ocf_get_stats *r)
154 {
155 	free(r->name);
156 }
157 
158 /* Structure to decode the input parameters for this RPC method. */
159 static const struct spdk_json_object_decoder rpc_bdev_ocf_get_stats_decoders[] = {
160 	{"name", offsetof(struct rpc_bdev_ocf_get_stats, name), spdk_json_decode_string},
161 };
162 
163 struct get_ocf_stats_ctx {
164 	struct spdk_jsonrpc_request *request;
165 	char *core_name;
166 };
167 
168 static void
169 rpc_bdev_ocf_get_stats_cmpl(ocf_cache_t cache, void *priv, int error)
170 {
171 	struct get_ocf_stats_ctx *ctx = (struct get_ocf_stats_ctx *) priv;
172 	struct spdk_json_write_ctx *w;
173 	struct vbdev_ocf_stats stats;
174 
175 	if (error) {
176 		goto end;
177 	}
178 
179 	error = vbdev_ocf_stats_get(cache, ctx->core_name, &stats);
180 
181 	ocf_mngt_cache_read_unlock(cache);
182 
183 	if (error) {
184 		goto end;
185 	}
186 
187 	w = spdk_jsonrpc_begin_result(ctx->request);
188 	vbdev_ocf_stats_write_json(w, &stats);
189 	spdk_jsonrpc_end_result(ctx->request, w);
190 
191 end:
192 	if (error) {
193 		spdk_jsonrpc_send_error_response_fmt(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
194 						     "Could not get stats: %s",
195 						     spdk_strerror(-error));
196 	}
197 	free(ctx);
198 }
199 
200 static void
201 rpc_bdev_ocf_get_stats(struct spdk_jsonrpc_request *request,
202 		       const struct spdk_json_val *params)
203 {
204 	struct rpc_bdev_ocf_get_stats req = {NULL};
205 	struct vbdev_ocf *vbdev;
206 	struct get_ocf_stats_ctx *ctx;
207 
208 	ctx = calloc(1, sizeof(*ctx));
209 	if (!ctx) {
210 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
211 						 "Not enough memory to process request");
212 		goto end;
213 	}
214 
215 	if (spdk_json_decode_object(params, rpc_bdev_ocf_get_stats_decoders,
216 				    SPDK_COUNTOF(rpc_bdev_ocf_get_stats_decoders),
217 				    &req)) {
218 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
219 						 "Invalid parameters");
220 		free(ctx);
221 		goto end;
222 	}
223 
224 	vbdev = vbdev_ocf_get_by_name(req.name);
225 	if (vbdev == NULL) {
226 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
227 						 spdk_strerror(ENODEV));
228 		free(ctx);
229 		goto end;
230 	}
231 
232 	ctx->core_name = vbdev->core.name;
233 	ctx->request = request;
234 	ocf_mngt_cache_read_lock(vbdev->ocf_cache, rpc_bdev_ocf_get_stats_cmpl, ctx);
235 
236 end:
237 	free_rpc_bdev_ocf_get_stats(&req);
238 }
239 SPDK_RPC_REGISTER("bdev_ocf_get_stats", rpc_bdev_ocf_get_stats, SPDK_RPC_RUNTIME)
240 
241 /* Structure to hold the parameters for this RPC method. */
242 struct rpc_bdev_ocf_get_bdevs {
243 	char *name;
244 };
245 
246 static void
247 free_rpc_bdev_ocf_get_bdevs(struct rpc_bdev_ocf_get_bdevs *r)
248 {
249 	free(r->name);
250 }
251 
252 /* Structure to decode the input parameters for this RPC method. */
253 static const struct spdk_json_object_decoder rpc_bdev_ocf_get_bdevs_decoders[] = {
254 	{"name", offsetof(struct rpc_bdev_ocf_get_bdevs, name), spdk_json_decode_string, true},
255 };
256 
257 struct bdev_get_bdevs_ctx {
258 	char *name;
259 	struct spdk_json_write_ctx *w;
260 };
261 
262 static void
263 bdev_get_bdevs_fn(struct vbdev_ocf *vbdev, void *ctx)
264 {
265 	struct bdev_get_bdevs_ctx *cctx = ctx;
266 	struct spdk_json_write_ctx *w = cctx->w;
267 
268 	if (cctx->name != NULL &&
269 	    strcmp(vbdev->name, cctx->name) &&
270 	    strcmp(vbdev->cache.name, cctx->name) &&
271 	    strcmp(vbdev->core.name, cctx->name)) {
272 		return;
273 	}
274 
275 	spdk_json_write_object_begin(w);
276 	spdk_json_write_named_string(w, "name", vbdev->name);
277 	spdk_json_write_named_bool(w, "started", vbdev->state.started);
278 
279 	spdk_json_write_named_object_begin(w, "cache");
280 	spdk_json_write_named_string(w, "name", vbdev->cache.name);
281 	spdk_json_write_named_bool(w, "attached", vbdev->cache.attached);
282 	spdk_json_write_object_end(w);
283 
284 	spdk_json_write_named_object_begin(w, "core");
285 	spdk_json_write_named_string(w, "name", vbdev->core.name);
286 	spdk_json_write_named_bool(w, "attached", vbdev->core.attached);
287 	spdk_json_write_object_end(w);
288 
289 	spdk_json_write_object_end(w);
290 }
291 
292 static void
293 rpc_bdev_ocf_get_bdevs(struct spdk_jsonrpc_request *request,
294 		       const struct spdk_json_val *params)
295 {
296 	struct spdk_json_write_ctx *w;
297 	struct rpc_bdev_ocf_get_bdevs req = {NULL};
298 	struct bdev_get_bdevs_ctx cctx;
299 
300 	if (params && spdk_json_decode_object(params, rpc_bdev_ocf_get_bdevs_decoders,
301 					      SPDK_COUNTOF(rpc_bdev_ocf_get_bdevs_decoders),
302 					      &req)) {
303 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
304 						 "Invalid parameters");
305 		goto end;
306 	}
307 
308 	if (req.name) {
309 		if (!(vbdev_ocf_get_by_name(req.name) || vbdev_ocf_get_base_by_name(req.name))) {
310 			spdk_jsonrpc_send_error_response(request,
311 							 SPDK_JSONRPC_ERROR_INVALID_PARAMS,
312 							 spdk_strerror(ENODEV));
313 			goto end;
314 		}
315 	}
316 
317 	w = spdk_jsonrpc_begin_result(request);
318 
319 	cctx.name    = req.name;
320 	cctx.w       = w;
321 
322 	spdk_json_write_array_begin(w);
323 	vbdev_ocf_foreach(bdev_get_bdevs_fn, &cctx);
324 	spdk_json_write_array_end(w);
325 	spdk_jsonrpc_end_result(request, w);
326 
327 end:
328 	free_rpc_bdev_ocf_get_bdevs(&req);
329 }
330 SPDK_RPC_REGISTER("bdev_ocf_get_bdevs", rpc_bdev_ocf_get_bdevs, SPDK_RPC_RUNTIME)
331 
332 /* Structure to hold the parameters for this RPC method. */
333 struct rpc_bdev_ocf_set_cache_mode {
334 	char *name;			/* main vbdev name */
335 	char *mode;			/* OCF cache mode to switch to */
336 };
337 
338 static void
339 free_rpc_bdev_ocf_set_cache_mode(struct rpc_bdev_ocf_set_cache_mode *r)
340 {
341 	free(r->name);
342 	free(r->mode);
343 }
344 
345 /* Structure to decode the input parameters for this RPC method. */
346 static const struct spdk_json_object_decoder rpc_bdev_ocf_set_cache_mode_decoders[] = {
347 	{"name", offsetof(struct rpc_bdev_ocf_set_cache_mode, name), spdk_json_decode_string},
348 	{"mode", offsetof(struct rpc_bdev_ocf_set_cache_mode, mode), spdk_json_decode_string},
349 };
350 
351 static void
352 cache_mode_cb(int status, struct vbdev_ocf *vbdev, void *cb_arg)
353 {
354 	struct spdk_jsonrpc_request *request = cb_arg;
355 	struct spdk_json_write_ctx *w;
356 
357 	if (status) {
358 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
359 						     "Could not change OCF vbdev cache mode: %d",
360 						     status);
361 	} else {
362 		w = spdk_jsonrpc_begin_result(request);
363 		spdk_json_write_string(w, ocf_get_cache_modename(
364 					       ocf_cache_get_mode(vbdev->ocf_cache)));
365 		spdk_jsonrpc_end_result(request, w);
366 	}
367 }
368 
369 static void
370 rpc_bdev_ocf_set_cache_mode(struct spdk_jsonrpc_request *request,
371 			    const struct spdk_json_val *params)
372 {
373 	struct rpc_bdev_ocf_set_cache_mode req = {NULL};
374 	struct vbdev_ocf *vbdev;
375 	int status;
376 
377 	status = spdk_json_decode_object(params, rpc_bdev_ocf_set_cache_mode_decoders,
378 					 SPDK_COUNTOF(rpc_bdev_ocf_set_cache_mode_decoders),
379 					 &req);
380 	if (status) {
381 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
382 						 "Invalid parameters");
383 		goto end;
384 	}
385 
386 	vbdev = vbdev_ocf_get_by_name(req.name);
387 	if (vbdev == NULL) {
388 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
389 						 spdk_strerror(ENODEV));
390 		goto end;
391 	}
392 
393 	vbdev_ocf_set_cache_mode(vbdev, req.mode, cache_mode_cb, request);
394 
395 end:
396 	free_rpc_bdev_ocf_set_cache_mode(&req);
397 }
398 SPDK_RPC_REGISTER("bdev_ocf_set_cache_mode", rpc_bdev_ocf_set_cache_mode, SPDK_RPC_RUNTIME)
399 
400 static void
401 seqcutoff_cb(int status, void *cb_arg)
402 {
403 	struct spdk_jsonrpc_request *request = cb_arg;
404 
405 	if (status) {
406 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
407 						     "OCF could not set sequential cutoff parameters: %d", status);
408 	} else {
409 		spdk_jsonrpc_send_bool_response(request, true);
410 	}
411 }
412 
413 /* Structure to hold the parameters for this RPC method. */
414 struct rpc_bdev_ocf_set_seqcutoff {
415 	char *name;		/* main vbdev name */
416 	char *policy;
417 	uint32_t threshold;
418 	uint32_t promotion_count;
419 };
420 
421 static void
422 free_rpc_bdev_ocf_set_seqcutoff(struct rpc_bdev_ocf_set_seqcutoff *r)
423 {
424 	free(r->name);
425 	free(r->policy);
426 }
427 
428 /* Structure to decode the input parameters for this RPC method. */
429 static const struct spdk_json_object_decoder rpc_bdev_ocf_set_seqcutoff_decoders[] = {
430 	{"name", offsetof(struct rpc_bdev_ocf_set_seqcutoff, name), spdk_json_decode_string},
431 	{"policy", offsetof(struct rpc_bdev_ocf_set_seqcutoff, policy), spdk_json_decode_string},
432 	{"threshold", offsetof(struct rpc_bdev_ocf_set_seqcutoff, threshold), spdk_json_decode_uint32, true},
433 	{"promotion_count", offsetof(struct rpc_bdev_ocf_set_seqcutoff, promotion_count), spdk_json_decode_uint32, true},
434 };
435 
436 static void
437 rpc_bdev_ocf_set_seqcutoff(struct spdk_jsonrpc_request *request,
438 			   const struct spdk_json_val *params)
439 {
440 	struct rpc_bdev_ocf_set_seqcutoff req = {NULL};
441 	struct vbdev_ocf *vbdev;
442 	int ret;
443 
444 	ret = spdk_json_decode_object(params, rpc_bdev_ocf_set_seqcutoff_decoders,
445 				      SPDK_COUNTOF(rpc_bdev_ocf_set_seqcutoff_decoders), &req);
446 	if (ret) {
447 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
448 						 "Invalid parameters");
449 		goto end;
450 	}
451 
452 	vbdev = vbdev_ocf_get_by_name(req.name);
453 	if (vbdev == NULL) {
454 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
455 						 spdk_strerror(ENODEV));
456 		goto end;
457 	}
458 
459 	vbdev_ocf_set_seqcutoff(vbdev, req.policy, req.threshold, req.promotion_count, seqcutoff_cb,
460 				request);
461 
462 end:
463 	free_rpc_bdev_ocf_set_seqcutoff(&req);
464 }
465 SPDK_RPC_REGISTER("bdev_ocf_set_seqcutoff", rpc_bdev_ocf_set_seqcutoff, SPDK_RPC_RUNTIME)
466