xref: /spdk/lib/vhost/vhost_rpc.c (revision 877573897ad52be4fa8989f7617bd655b87e05c4)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2017 Intel Corporation. All rights reserved.
3  *   All rights reserved.
4  */
5 
6 #include "spdk/stdinc.h"
7 
8 #include "spdk/log.h"
9 #include "spdk/rpc.h"
10 #include "spdk/util.h"
11 #include "spdk/string.h"
12 #include "spdk/env.h"
13 
14 #include "spdk/scsi.h"
15 #include "spdk/vhost.h"
16 #include "vhost_internal.h"
17 #include "spdk/bdev.h"
18 
19 struct rpc_vhost_scsi_ctrlr {
20 	char *ctrlr;
21 	char *cpumask;
22 };
23 
24 static void
25 free_rpc_vhost_scsi_ctrlr(struct rpc_vhost_scsi_ctrlr *req)
26 {
27 	free(req->ctrlr);
28 	free(req->cpumask);
29 }
30 
31 static const struct spdk_json_object_decoder rpc_vhost_create_scsi_ctrlr[] = {
32 	{"ctrlr", offsetof(struct rpc_vhost_scsi_ctrlr, ctrlr), spdk_json_decode_string },
33 	{"cpumask", offsetof(struct rpc_vhost_scsi_ctrlr, cpumask), spdk_json_decode_string, true},
34 };
35 
36 static void
37 rpc_vhost_create_scsi_controller(struct spdk_jsonrpc_request *request,
38 				 const struct spdk_json_val *params)
39 {
40 	struct rpc_vhost_scsi_ctrlr req = {0};
41 	int rc;
42 
43 	if (spdk_json_decode_object(params, rpc_vhost_create_scsi_ctrlr,
44 				    SPDK_COUNTOF(rpc_vhost_create_scsi_ctrlr),
45 				    &req)) {
46 		SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n");
47 		rc = -EINVAL;
48 		goto invalid;
49 	}
50 
51 	rc = spdk_vhost_scsi_dev_construct(req.ctrlr, req.cpumask);
52 	if (rc < 0) {
53 		goto invalid;
54 	}
55 
56 	free_rpc_vhost_scsi_ctrlr(&req);
57 
58 	spdk_jsonrpc_send_bool_response(request, true);
59 	return;
60 
61 invalid:
62 	free_rpc_vhost_scsi_ctrlr(&req);
63 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
64 					 spdk_strerror(-rc));
65 }
66 SPDK_RPC_REGISTER("vhost_create_scsi_controller", rpc_vhost_create_scsi_controller,
67 		  SPDK_RPC_RUNTIME)
68 
69 struct rpc_vhost_scsi_ctrlr_add_target {
70 	char *ctrlr;
71 	int32_t scsi_target_num;
72 	char *bdev_name;
73 };
74 
75 static void
76 free_rpc_vhost_scsi_ctrlr_add_target(struct rpc_vhost_scsi_ctrlr_add_target *req)
77 {
78 	free(req->ctrlr);
79 	free(req->bdev_name);
80 }
81 
82 static const struct spdk_json_object_decoder rpc_vhost_scsi_ctrlr_add_target[] = {
83 	{"ctrlr", offsetof(struct rpc_vhost_scsi_ctrlr_add_target, ctrlr), spdk_json_decode_string },
84 	{"scsi_target_num", offsetof(struct rpc_vhost_scsi_ctrlr_add_target, scsi_target_num), spdk_json_decode_int32},
85 	{"bdev_name", offsetof(struct rpc_vhost_scsi_ctrlr_add_target, bdev_name), spdk_json_decode_string },
86 };
87 
88 static void
89 rpc_vhost_scsi_controller_add_target(struct spdk_jsonrpc_request *request,
90 				     const struct spdk_json_val *params)
91 {
92 	struct rpc_vhost_scsi_ctrlr_add_target req = {0};
93 	struct spdk_json_write_ctx *w;
94 	struct spdk_vhost_dev *vdev;
95 	int rc;
96 
97 	if (spdk_json_decode_object(params, rpc_vhost_scsi_ctrlr_add_target,
98 				    SPDK_COUNTOF(rpc_vhost_scsi_ctrlr_add_target),
99 				    &req)) {
100 		SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n");
101 		rc = -EINVAL;
102 		goto invalid;
103 	}
104 
105 	spdk_vhost_lock();
106 	vdev = spdk_vhost_dev_find(req.ctrlr);
107 	if (vdev == NULL) {
108 		spdk_vhost_unlock();
109 		rc = -ENODEV;
110 		goto invalid;
111 	}
112 
113 	rc = spdk_vhost_scsi_dev_add_tgt(vdev, req.scsi_target_num, req.bdev_name);
114 	spdk_vhost_unlock();
115 	if (rc < 0) {
116 		goto invalid;
117 	}
118 
119 	free_rpc_vhost_scsi_ctrlr_add_target(&req);
120 
121 	w = spdk_jsonrpc_begin_result(request);
122 	spdk_json_write_int32(w, rc);
123 	spdk_jsonrpc_end_result(request, w);
124 	return;
125 
126 invalid:
127 	free_rpc_vhost_scsi_ctrlr_add_target(&req);
128 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
129 					 spdk_strerror(-rc));
130 }
131 SPDK_RPC_REGISTER("vhost_scsi_controller_add_target", rpc_vhost_scsi_controller_add_target,
132 		  SPDK_RPC_RUNTIME)
133 
134 struct rpc_remove_vhost_scsi_ctrlr_target {
135 	char *ctrlr;
136 	uint32_t scsi_target_num;
137 };
138 
139 static void
140 free_rpc_remove_vhost_scsi_ctrlr_target(struct rpc_remove_vhost_scsi_ctrlr_target *req)
141 {
142 	free(req->ctrlr);
143 }
144 
145 static const struct spdk_json_object_decoder rpc_vhost_remove_target[] = {
146 	{"ctrlr", offsetof(struct rpc_remove_vhost_scsi_ctrlr_target, ctrlr), spdk_json_decode_string },
147 	{"scsi_target_num", offsetof(struct rpc_remove_vhost_scsi_ctrlr_target, scsi_target_num), spdk_json_decode_uint32},
148 };
149 
150 static int
151 rpc_vhost_scsi_controller_remove_target_finish_cb(struct spdk_vhost_dev *vdev, void *arg)
152 {
153 	struct spdk_jsonrpc_request *request = arg;
154 
155 	spdk_jsonrpc_send_bool_response(request, true);
156 	return 0;
157 }
158 
159 static void
160 rpc_vhost_scsi_controller_remove_target(struct spdk_jsonrpc_request *request,
161 					const struct spdk_json_val *params)
162 {
163 	struct rpc_remove_vhost_scsi_ctrlr_target req = {0};
164 	struct spdk_vhost_dev *vdev;
165 	int rc;
166 
167 	if (spdk_json_decode_object(params, rpc_vhost_remove_target,
168 				    SPDK_COUNTOF(rpc_vhost_remove_target),
169 				    &req)) {
170 		SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n");
171 		rc = -EINVAL;
172 		goto invalid;
173 	}
174 
175 	spdk_vhost_lock();
176 	vdev = spdk_vhost_dev_find(req.ctrlr);
177 	if (vdev == NULL) {
178 		spdk_vhost_unlock();
179 		rc = -ENODEV;
180 		goto invalid;
181 	}
182 
183 	rc = spdk_vhost_scsi_dev_remove_tgt(vdev, req.scsi_target_num,
184 					    rpc_vhost_scsi_controller_remove_target_finish_cb,
185 					    request);
186 	spdk_vhost_unlock();
187 	if (rc < 0) {
188 		goto invalid;
189 	}
190 
191 	free_rpc_remove_vhost_scsi_ctrlr_target(&req);
192 	return;
193 
194 invalid:
195 	free_rpc_remove_vhost_scsi_ctrlr_target(&req);
196 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
197 					 spdk_strerror(-rc));
198 }
199 
200 SPDK_RPC_REGISTER("vhost_scsi_controller_remove_target",
201 		  rpc_vhost_scsi_controller_remove_target, SPDK_RPC_RUNTIME)
202 
203 struct rpc_vhost_blk_ctrlr {
204 	char *ctrlr;
205 	char *dev_name;
206 	char *cpumask;
207 	char *transport;
208 };
209 
210 static const struct spdk_json_object_decoder rpc_construct_vhost_blk_ctrlr[] = {
211 	{"ctrlr", offsetof(struct rpc_vhost_blk_ctrlr, ctrlr), spdk_json_decode_string },
212 	{"dev_name", offsetof(struct rpc_vhost_blk_ctrlr, dev_name), spdk_json_decode_string },
213 	{"cpumask", offsetof(struct rpc_vhost_blk_ctrlr, cpumask), spdk_json_decode_string, true},
214 	{"transport", offsetof(struct rpc_vhost_blk_ctrlr, transport), spdk_json_decode_string, true},
215 };
216 
217 static void
218 free_rpc_vhost_blk_ctrlr(struct rpc_vhost_blk_ctrlr *req)
219 {
220 	free(req->ctrlr);
221 	free(req->dev_name);
222 	free(req->cpumask);
223 	free(req->transport);
224 }
225 
226 static void
227 rpc_vhost_create_blk_controller(struct spdk_jsonrpc_request *request,
228 				const struct spdk_json_val *params)
229 {
230 	struct rpc_vhost_blk_ctrlr req = {0};
231 	int rc;
232 
233 	if (spdk_json_decode_object_relaxed(params, rpc_construct_vhost_blk_ctrlr,
234 					    SPDK_COUNTOF(rpc_construct_vhost_blk_ctrlr),
235 					    &req)) {
236 		SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n");
237 		rc = -EINVAL;
238 		goto invalid;
239 	}
240 
241 	rc = spdk_vhost_blk_construct(req.ctrlr, req.cpumask, req.dev_name, req.transport, params);
242 	if (rc < 0) {
243 		goto invalid;
244 	}
245 
246 	free_rpc_vhost_blk_ctrlr(&req);
247 
248 	spdk_jsonrpc_send_bool_response(request, true);
249 	return;
250 
251 invalid:
252 	free_rpc_vhost_blk_ctrlr(&req);
253 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
254 					 spdk_strerror(-rc));
255 
256 }
257 SPDK_RPC_REGISTER("vhost_create_blk_controller", rpc_vhost_create_blk_controller,
258 		  SPDK_RPC_RUNTIME)
259 
260 struct rpc_delete_vhost_ctrlr {
261 	char *ctrlr;
262 };
263 
264 static const struct spdk_json_object_decoder rpc_delete_vhost_ctrlr_decoder[] = {
265 	{"ctrlr", offsetof(struct rpc_delete_vhost_ctrlr, ctrlr), spdk_json_decode_string },
266 };
267 
268 static void
269 free_rpc_delete_vhost_ctrlr(struct rpc_delete_vhost_ctrlr *req)
270 {
271 	free(req->ctrlr);
272 }
273 
274 static void
275 rpc_vhost_delete_controller(struct spdk_jsonrpc_request *request,
276 			    const struct spdk_json_val *params)
277 {
278 	struct rpc_delete_vhost_ctrlr req = {0};
279 	struct spdk_vhost_dev *vdev;
280 	int rc;
281 
282 	if (spdk_json_decode_object(params, rpc_delete_vhost_ctrlr_decoder,
283 				    SPDK_COUNTOF(rpc_delete_vhost_ctrlr_decoder), &req)) {
284 		SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n");
285 		rc = -EINVAL;
286 		goto invalid;
287 	}
288 
289 	spdk_vhost_lock();
290 	vdev = spdk_vhost_dev_find(req.ctrlr);
291 	if (vdev == NULL) {
292 		spdk_vhost_unlock();
293 		rc = -ENODEV;
294 		goto invalid;
295 	}
296 
297 	rc = spdk_vhost_dev_remove(vdev);
298 	spdk_vhost_unlock();
299 	if (rc < 0) {
300 		goto invalid;
301 	}
302 
303 	free_rpc_delete_vhost_ctrlr(&req);
304 
305 	spdk_jsonrpc_send_bool_response(request, true);
306 	return;
307 
308 invalid:
309 	free_rpc_delete_vhost_ctrlr(&req);
310 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
311 					 spdk_strerror(-rc));
312 
313 }
314 SPDK_RPC_REGISTER("vhost_delete_controller", rpc_vhost_delete_controller, SPDK_RPC_RUNTIME)
315 
316 struct rpc_get_vhost_ctrlrs {
317 	char *name;
318 };
319 
320 static void
321 _rpc_get_vhost_controller(struct spdk_json_write_ctx *w, struct spdk_vhost_dev *vdev)
322 {
323 	uint32_t delay_base_us, iops_threshold;
324 
325 	spdk_vhost_get_coalescing(vdev, &delay_base_us, &iops_threshold);
326 
327 	spdk_json_write_object_begin(w);
328 
329 	spdk_json_write_named_string(w, "ctrlr", spdk_vhost_dev_get_name(vdev));
330 	spdk_json_write_named_string_fmt(w, "cpumask", "0x%s",
331 					 spdk_cpuset_fmt(spdk_thread_get_cpumask(vdev->thread)));
332 	spdk_json_write_named_uint32(w, "delay_base_us", delay_base_us);
333 	spdk_json_write_named_uint32(w, "iops_threshold", iops_threshold);
334 	spdk_json_write_named_string(w, "socket", vdev->path);
335 
336 	spdk_json_write_named_object_begin(w, "backend_specific");
337 	vhost_dump_info_json(vdev, w);
338 	spdk_json_write_object_end(w);
339 
340 	spdk_json_write_object_end(w);
341 }
342 
343 static const struct spdk_json_object_decoder rpc_get_vhost_ctrlrs_decoders[] = {
344 	{"name", offsetof(struct rpc_get_vhost_ctrlrs, name), spdk_json_decode_string, true},
345 };
346 
347 static void
348 free_rpc_get_vhost_ctrlrs(struct rpc_get_vhost_ctrlrs *req)
349 {
350 	free(req->name);
351 }
352 
353 static void
354 rpc_vhost_get_controllers(struct spdk_jsonrpc_request *request,
355 			  const struct spdk_json_val *params)
356 {
357 	struct rpc_get_vhost_ctrlrs req = {0};
358 	struct spdk_json_write_ctx *w;
359 	struct spdk_vhost_dev *vdev;
360 	int rc;
361 
362 	if (params && spdk_json_decode_object(params, rpc_get_vhost_ctrlrs_decoders,
363 					      SPDK_COUNTOF(rpc_get_vhost_ctrlrs_decoders), &req)) {
364 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
365 		rc = -EINVAL;
366 		goto invalid;
367 	}
368 
369 	spdk_vhost_lock();
370 	if (req.name != NULL) {
371 		vdev = spdk_vhost_dev_find(req.name);
372 		if (vdev == NULL) {
373 			spdk_vhost_unlock();
374 			rc = -ENODEV;
375 			goto invalid;
376 		}
377 
378 		free_rpc_get_vhost_ctrlrs(&req);
379 
380 		w = spdk_jsonrpc_begin_result(request);
381 		spdk_json_write_array_begin(w);
382 
383 		_rpc_get_vhost_controller(w, vdev);
384 		spdk_vhost_unlock();
385 
386 		spdk_json_write_array_end(w);
387 		spdk_jsonrpc_end_result(request, w);
388 		return;
389 	}
390 
391 	free_rpc_get_vhost_ctrlrs(&req);
392 
393 	w = spdk_jsonrpc_begin_result(request);
394 	spdk_json_write_array_begin(w);
395 
396 	vdev = spdk_vhost_dev_next(NULL);
397 	while (vdev != NULL) {
398 		_rpc_get_vhost_controller(w, vdev);
399 		vdev = spdk_vhost_dev_next(vdev);
400 	}
401 	spdk_vhost_unlock();
402 
403 	spdk_json_write_array_end(w);
404 	spdk_jsonrpc_end_result(request, w);
405 	return;
406 
407 invalid:
408 	free_rpc_get_vhost_ctrlrs(&req);
409 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
410 					 spdk_strerror(-rc));
411 }
412 SPDK_RPC_REGISTER("vhost_get_controllers", rpc_vhost_get_controllers, SPDK_RPC_RUNTIME)
413 
414 
415 struct rpc_vhost_ctrlr_coalescing {
416 	char *ctrlr;
417 	uint32_t delay_base_us;
418 	uint32_t iops_threshold;
419 };
420 
421 static const struct spdk_json_object_decoder rpc_set_vhost_ctrlr_coalescing[] = {
422 	{"ctrlr", offsetof(struct rpc_vhost_ctrlr_coalescing, ctrlr), spdk_json_decode_string },
423 	{"delay_base_us", offsetof(struct rpc_vhost_ctrlr_coalescing, delay_base_us), spdk_json_decode_uint32},
424 	{"iops_threshold", offsetof(struct rpc_vhost_ctrlr_coalescing, iops_threshold), spdk_json_decode_uint32},
425 };
426 
427 static void
428 free_rpc_set_vhost_controllers_event_coalescing(struct rpc_vhost_ctrlr_coalescing *req)
429 {
430 	free(req->ctrlr);
431 }
432 
433 static void
434 rpc_vhost_controller_set_coalescing(struct spdk_jsonrpc_request *request,
435 				    const struct spdk_json_val *params)
436 {
437 	struct rpc_vhost_ctrlr_coalescing req = {0};
438 	struct spdk_vhost_dev *vdev;
439 	int rc;
440 
441 	if (spdk_json_decode_object(params, rpc_set_vhost_ctrlr_coalescing,
442 				    SPDK_COUNTOF(rpc_set_vhost_ctrlr_coalescing), &req)) {
443 		SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n");
444 		rc = -EINVAL;
445 		goto invalid;
446 	}
447 
448 	spdk_vhost_lock();
449 	vdev = spdk_vhost_dev_find(req.ctrlr);
450 	if (vdev == NULL) {
451 		spdk_vhost_unlock();
452 		rc = -ENODEV;
453 		goto invalid;
454 	}
455 
456 	rc = spdk_vhost_set_coalescing(vdev, req.delay_base_us, req.iops_threshold);
457 	spdk_vhost_unlock();
458 	if (rc) {
459 		goto invalid;
460 	}
461 
462 	free_rpc_set_vhost_controllers_event_coalescing(&req);
463 
464 	spdk_jsonrpc_send_bool_response(request, true);
465 	return;
466 
467 invalid:
468 	free_rpc_set_vhost_controllers_event_coalescing(&req);
469 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
470 					 spdk_strerror(-rc));
471 }
472 SPDK_RPC_REGISTER("vhost_controller_set_coalescing", rpc_vhost_controller_set_coalescing,
473 		  SPDK_RPC_RUNTIME)
474 
475 struct rpc_virtio_blk_create_transport {
476 	char *name;
477 };
478 
479 static const struct spdk_json_object_decoder rpc_create_virtio_blk_transport[] = {
480 	{"name", offsetof(struct rpc_virtio_blk_create_transport, name), spdk_json_decode_string},
481 };
482 
483 static void
484 free_rpc_virtio_blk_create_transport(struct rpc_virtio_blk_create_transport *req)
485 {
486 	free(req->name);
487 }
488 
489 static void
490 rpc_virtio_blk_create_transport(struct spdk_jsonrpc_request *request,
491 				const struct spdk_json_val *params)
492 {
493 	struct rpc_virtio_blk_create_transport req = {0};
494 	int rc;
495 
496 	if (spdk_json_decode_object_relaxed(params, rpc_create_virtio_blk_transport,
497 					    SPDK_COUNTOF(rpc_create_virtio_blk_transport), &req)) {
498 		SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n");
499 		rc = -EINVAL;
500 		goto invalid;
501 	}
502 
503 	spdk_vhost_lock();
504 	rc = virtio_blk_transport_create(req.name, params);
505 	spdk_vhost_unlock();
506 	if (rc != 0) {
507 		goto invalid;
508 	}
509 
510 	free_rpc_virtio_blk_create_transport(&req);
511 	spdk_jsonrpc_send_bool_response(request, true);
512 	return;
513 
514 invalid:
515 	free_rpc_virtio_blk_create_transport(&req);
516 	spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
517 }
518 SPDK_RPC_REGISTER("virtio_blk_create_transport", rpc_virtio_blk_create_transport,
519 		  SPDK_RPC_RUNTIME)
520 
521 SPDK_LOG_REGISTER_COMPONENT(vhost_rpc)
522