xref: /spdk/lib/vhost/vhost_rpc.c (revision 053d5733e62a33b8b734f33ac5fc357fcc0513de)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "spdk/stdinc.h"
35 
36 #include "spdk_internal/log.h"
37 #include "spdk/rpc.h"
38 #include "spdk/util.h"
39 #include "spdk/string.h"
40 
41 #include "spdk/scsi.h"
42 #include "spdk/vhost.h"
43 #include "vhost_internal.h"
44 #include "spdk/bdev.h"
45 
46 struct rpc_vhost_scsi_ctrlr {
47 	char *ctrlr;
48 	char *cpumask;
49 };
50 
51 static void
52 free_rpc_vhost_scsi_ctrlr(struct rpc_vhost_scsi_ctrlr *req)
53 {
54 	free(req->ctrlr);
55 	free(req->cpumask);
56 }
57 
58 static const struct spdk_json_object_decoder rpc_construct_vhost_ctrlr[] = {
59 	{"ctrlr", offsetof(struct rpc_vhost_scsi_ctrlr, ctrlr), spdk_json_decode_string },
60 	{"cpumask", offsetof(struct rpc_vhost_scsi_ctrlr, cpumask), spdk_json_decode_string, true},
61 };
62 
63 static void
64 spdk_rpc_construct_vhost_scsi_controller(struct spdk_jsonrpc_request *request,
65 		const struct spdk_json_val *params)
66 {
67 	struct rpc_vhost_scsi_ctrlr req = {0};
68 	struct spdk_json_write_ctx *w;
69 	int rc;
70 	char buf[64];
71 	uint64_t cpumask;
72 
73 	if (spdk_json_decode_object(params, rpc_construct_vhost_ctrlr,
74 				    SPDK_COUNTOF(rpc_construct_vhost_ctrlr),
75 				    &req)) {
76 		SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n");
77 		rc = -EINVAL;
78 		goto invalid;
79 	}
80 
81 	cpumask = spdk_app_get_core_mask();
82 	if (req.cpumask != NULL && spdk_vhost_parse_core_mask(req.cpumask, &cpumask)) {
83 		rc = -EINVAL;
84 		goto invalid;
85 	}
86 
87 	rc = spdk_vhost_scsi_dev_construct(req.ctrlr, cpumask);
88 	if (rc < 0) {
89 		goto invalid;
90 	}
91 
92 	free_rpc_vhost_scsi_ctrlr(&req);
93 
94 	w = spdk_jsonrpc_begin_result(request);
95 	if (w == NULL) {
96 		return;
97 	}
98 
99 	spdk_json_write_bool(w, true);
100 	spdk_jsonrpc_end_result(request, w);
101 	return;
102 
103 invalid:
104 	spdk_strerror_r(-rc, buf, sizeof(buf));
105 	free_rpc_vhost_scsi_ctrlr(&req);
106 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf);
107 }
108 SPDK_RPC_REGISTER("construct_vhost_scsi_controller", spdk_rpc_construct_vhost_scsi_controller)
109 
110 struct rpc_remove_vhost_scsi_ctrlr {
111 	char *ctrlr;
112 };
113 
114 static void
115 free_rpc_remove_vhost_scsi_ctrlr(struct rpc_remove_vhost_scsi_ctrlr *req)
116 {
117 	free(req->ctrlr);
118 }
119 
120 static const struct spdk_json_object_decoder rpc_remove_vhost_ctrlr[] = {
121 	{"ctrlr", offsetof(struct rpc_remove_vhost_scsi_ctrlr, ctrlr), spdk_json_decode_string },
122 };
123 
124 static void
125 spdk_rpc_remove_vhost_scsi_controller(struct spdk_jsonrpc_request *request,
126 				      const struct spdk_json_val *params)
127 {
128 	struct rpc_remove_vhost_scsi_ctrlr req = {NULL};
129 	struct spdk_json_write_ctx *w;
130 	struct spdk_vhost_dev *vdev;
131 	int rc;
132 	char buf[64];
133 
134 	if (spdk_json_decode_object(params, rpc_remove_vhost_ctrlr,
135 				    SPDK_COUNTOF(rpc_remove_vhost_ctrlr),
136 				    &req)) {
137 		SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n");
138 		rc = -EINVAL;
139 		goto invalid;
140 	}
141 
142 	if (!(vdev = spdk_vhost_dev_find(req.ctrlr))) {
143 		rc = -ENODEV;
144 		goto invalid;
145 	}
146 
147 	rc = spdk_vhost_scsi_dev_remove(vdev);
148 	if (rc < 0) {
149 		goto invalid;
150 	}
151 
152 	free_rpc_remove_vhost_scsi_ctrlr(&req);
153 
154 	w = spdk_jsonrpc_begin_result(request);
155 	if (w == NULL) {
156 		return;
157 	}
158 
159 	spdk_json_write_bool(w, true);
160 	spdk_jsonrpc_end_result(request, w);
161 	return;
162 
163 invalid:
164 	spdk_strerror_r(-rc, buf, sizeof(buf));
165 	free_rpc_remove_vhost_scsi_ctrlr(&req);
166 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf);
167 }
168 SPDK_RPC_REGISTER("remove_vhost_scsi_controller", spdk_rpc_remove_vhost_scsi_controller)
169 
170 
171 struct rpc_add_vhost_scsi_ctrlr_lun {
172 	char *ctrlr;
173 	uint32_t scsi_dev_num;
174 	char *lun_name;
175 };
176 
177 static void
178 free_rpc_add_vhost_scsi_ctrlr_lun(struct rpc_add_vhost_scsi_ctrlr_lun *req)
179 {
180 	free(req->ctrlr);
181 	free(req->lun_name);
182 }
183 
184 static const struct spdk_json_object_decoder rpc_vhost_add_lun[] = {
185 	{"ctrlr", offsetof(struct rpc_add_vhost_scsi_ctrlr_lun, ctrlr), spdk_json_decode_string },
186 	{"scsi_dev_num", offsetof(struct rpc_add_vhost_scsi_ctrlr_lun, scsi_dev_num), spdk_json_decode_uint32},
187 	{"lun_name", offsetof(struct rpc_add_vhost_scsi_ctrlr_lun, lun_name), spdk_json_decode_string },
188 };
189 
190 static void
191 spdk_rpc_add_vhost_scsi_lun(struct spdk_jsonrpc_request *request,
192 			    const struct spdk_json_val *params)
193 {
194 	struct rpc_add_vhost_scsi_ctrlr_lun req = {0};
195 	struct spdk_json_write_ctx *w;
196 	int rc;
197 	char buf[64];
198 
199 	if (spdk_json_decode_object(params, rpc_vhost_add_lun,
200 				    SPDK_COUNTOF(rpc_vhost_add_lun),
201 				    &req)) {
202 		SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n");
203 		rc = -EINVAL;
204 		goto invalid;
205 	}
206 
207 	rc = spdk_vhost_scsi_dev_add_dev(req.ctrlr, req.scsi_dev_num, req.lun_name);
208 	if (rc < 0) {
209 		goto invalid;
210 	}
211 
212 	free_rpc_add_vhost_scsi_ctrlr_lun(&req);
213 
214 	w = spdk_jsonrpc_begin_result(request);
215 	if (w == NULL) {
216 		return;
217 	}
218 
219 	spdk_json_write_bool(w, true);
220 	spdk_jsonrpc_end_result(request, w);
221 	return;
222 
223 invalid:
224 	spdk_strerror_r(-rc, buf, sizeof(buf));
225 	free_rpc_add_vhost_scsi_ctrlr_lun(&req);
226 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf);
227 }
228 SPDK_RPC_REGISTER("add_vhost_scsi_lun", spdk_rpc_add_vhost_scsi_lun)
229 
230 struct rpc_remove_vhost_scsi_ctrlr_dev {
231 	char *ctrlr;
232 	uint32_t scsi_dev_num;
233 };
234 
235 static void
236 free_rpc_remove_vhost_scsi_ctrlr_dev(struct rpc_remove_vhost_scsi_ctrlr_dev *req)
237 {
238 	free(req->ctrlr);
239 }
240 
241 static const struct spdk_json_object_decoder rpc_vhost_remove_dev[] = {
242 	{"ctrlr", offsetof(struct rpc_remove_vhost_scsi_ctrlr_dev, ctrlr), spdk_json_decode_string },
243 	{"scsi_dev_num", offsetof(struct rpc_remove_vhost_scsi_ctrlr_dev, scsi_dev_num), spdk_json_decode_uint32},
244 };
245 
246 static void
247 spdk_rpc_remove_vhost_scsi_dev(struct spdk_jsonrpc_request *request,
248 			       const struct spdk_json_val *params)
249 {
250 	struct rpc_remove_vhost_scsi_ctrlr_dev req = {0};
251 	struct spdk_json_write_ctx *w;
252 	struct spdk_vhost_dev *vdev;
253 	int rc;
254 	char buf[64];
255 
256 	if (spdk_json_decode_object(params, rpc_vhost_remove_dev,
257 				    SPDK_COUNTOF(rpc_vhost_remove_dev),
258 				    &req)) {
259 		SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n");
260 		rc = -EINVAL;
261 		goto invalid;
262 	}
263 
264 	if (!(vdev = spdk_vhost_dev_find(req.ctrlr))) {
265 		rc = -ENODEV;
266 		goto invalid;
267 	}
268 
269 	rc = spdk_vhost_scsi_dev_remove_dev(vdev, req.scsi_dev_num);
270 	if (rc < 0) {
271 		goto invalid;
272 	}
273 
274 	free_rpc_remove_vhost_scsi_ctrlr_dev(&req);
275 
276 	w = spdk_jsonrpc_begin_result(request);
277 	if (w == NULL) {
278 		return;
279 	}
280 
281 	spdk_json_write_bool(w, true);
282 	spdk_jsonrpc_end_result(request, w);
283 	return;
284 
285 invalid:
286 	spdk_strerror_r(-rc, buf, sizeof(buf));
287 	free_rpc_remove_vhost_scsi_ctrlr_dev(&req);
288 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf);
289 }
290 SPDK_RPC_REGISTER("remove_vhost_scsi_dev", spdk_rpc_remove_vhost_scsi_dev)
291 
292 struct rpc_vhost_blk_ctrlr {
293 	char *ctrlr;
294 	char *dev_name;
295 	char *cpumask;
296 	bool readonly;
297 };
298 
299 static const struct spdk_json_object_decoder rpc_construct_vhost_blk_ctrlr[] = {
300 	{"ctrlr", offsetof(struct rpc_vhost_blk_ctrlr, ctrlr), spdk_json_decode_string },
301 	{"dev_name", offsetof(struct rpc_vhost_blk_ctrlr, dev_name), spdk_json_decode_string },
302 	{"cpumask", offsetof(struct rpc_vhost_blk_ctrlr, cpumask), spdk_json_decode_string, true},
303 	{"readonly", offsetof(struct rpc_vhost_blk_ctrlr, readonly), spdk_json_decode_bool, true},
304 };
305 
306 static void
307 free_rpc_vhost_blk_ctrlr(struct rpc_vhost_blk_ctrlr *req)
308 {
309 	free(req->ctrlr);
310 	free(req->dev_name);
311 	free(req->cpumask);
312 }
313 
314 static void
315 spdk_rpc_construct_vhost_blk_controller(struct spdk_jsonrpc_request *request,
316 					const struct spdk_json_val *params)
317 {
318 	struct rpc_vhost_blk_ctrlr req = {0};
319 	struct spdk_json_write_ctx *w;
320 	int rc;
321 	char buf[64];
322 	uint64_t cpumask;
323 
324 	if (spdk_json_decode_object(params, rpc_construct_vhost_blk_ctrlr,
325 				    SPDK_COUNTOF(rpc_construct_vhost_blk_ctrlr),
326 				    &req)) {
327 		SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n");
328 		rc = -EINVAL;
329 		goto invalid;
330 	}
331 
332 	cpumask = spdk_app_get_core_mask();
333 	if (req.cpumask != NULL && spdk_vhost_parse_core_mask(req.cpumask, &cpumask)) {
334 		rc = -EINVAL;
335 		goto invalid;
336 	}
337 
338 	rc = spdk_vhost_blk_construct(req.ctrlr, cpumask, req.dev_name, req.readonly);
339 	if (rc < 0) {
340 		goto invalid;
341 	}
342 
343 	free_rpc_vhost_blk_ctrlr(&req);
344 
345 	w = spdk_jsonrpc_begin_result(request);
346 	if (w == NULL) {
347 		return;
348 	}
349 
350 	spdk_json_write_bool(w, true);
351 	spdk_jsonrpc_end_result(request, w);
352 	return;
353 
354 invalid:
355 	spdk_strerror_r(-rc, buf, sizeof(buf));
356 	free_rpc_vhost_blk_ctrlr(&req);
357 	spdk_jsonrpc_send_error_response(request,
358 					 SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf);
359 
360 }
361 SPDK_RPC_REGISTER("construct_vhost_blk_controller", spdk_rpc_construct_vhost_blk_controller)
362 
363 struct rpc_remove_vhost_blk_ctrlr {
364 	char *ctrlr;
365 };
366 
367 static const struct spdk_json_object_decoder rpc_remove_vhost_blk_ctrlr[] = {
368 	{"ctrlr", offsetof(struct rpc_remove_vhost_blk_ctrlr, ctrlr), spdk_json_decode_string },
369 };
370 
371 static void
372 free_rpc_remove_vhost_blk_ctrlr(struct rpc_remove_vhost_blk_ctrlr *req)
373 {
374 	free(req->ctrlr);
375 }
376 
377 static void
378 spdk_rpc_remove_vhost_blk_controller(struct spdk_jsonrpc_request *request,
379 				     const struct spdk_json_val *params)
380 {
381 	struct rpc_remove_vhost_blk_ctrlr req = {NULL};
382 	struct spdk_json_write_ctx *w;
383 	struct spdk_vhost_dev *vdev;
384 	int rc;
385 	char buf[64];
386 
387 	if (spdk_json_decode_object(params, rpc_remove_vhost_blk_ctrlr,
388 				    SPDK_COUNTOF(rpc_remove_vhost_blk_ctrlr), &req)) {
389 		SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n");
390 		rc = -EINVAL;
391 		goto invalid;
392 	}
393 
394 	if (!(vdev = spdk_vhost_dev_find(req.ctrlr))) {
395 		rc = -ENODEV;
396 		goto invalid;
397 	}
398 
399 	rc = spdk_vhost_blk_destroy(vdev);
400 	if (rc < 0) {
401 		goto invalid;
402 	}
403 
404 	free_rpc_remove_vhost_blk_ctrlr(&req);
405 
406 	w = spdk_jsonrpc_begin_result(request);
407 	if (w == NULL) {
408 		return;
409 	}
410 
411 	spdk_json_write_bool(w, true);
412 	spdk_jsonrpc_end_result(request, w);
413 	return;
414 
415 invalid:
416 	spdk_strerror_r(-rc, buf, sizeof(buf));
417 	free_rpc_remove_vhost_blk_ctrlr(&req);
418 	spdk_jsonrpc_send_error_response(request,
419 					 SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf);
420 
421 }
422 SPDK_RPC_REGISTER("remove_vhost_blk_controller", spdk_rpc_remove_vhost_blk_controller)
423 
424 static void
425 spdk_rpc_get_vhost_controllers(struct spdk_jsonrpc_request *request,
426 			       const struct spdk_json_val *params)
427 {
428 	struct spdk_json_write_ctx *w;
429 	struct spdk_vhost_dev *vdev = NULL;
430 
431 	if (params != NULL) {
432 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
433 						 "get_vhost_controllers requires no parameters");
434 		return;
435 	}
436 
437 	w = spdk_jsonrpc_begin_result(request);
438 	if (w == NULL) {
439 		return;
440 	}
441 
442 	spdk_json_write_array_begin(w);
443 	while ((vdev = spdk_vhost_dev_next(vdev)) != NULL) {
444 		spdk_json_write_object_begin(w);
445 
446 		spdk_json_write_name(w, "ctrlr");
447 		spdk_json_write_string(w, spdk_vhost_dev_get_name(vdev));
448 
449 		spdk_json_write_name(w, "cpumask");
450 		spdk_json_write_string_fmt(w, "%#" PRIx64, spdk_vhost_dev_get_cpumask(vdev));
451 
452 		spdk_json_write_name(w, "backend_specific");
453 
454 		spdk_json_write_object_begin(w);
455 		spdk_vhost_dump_config_json(vdev, w);
456 		spdk_json_write_object_end(w);
457 
458 		spdk_json_write_object_end(w);
459 	}
460 
461 	spdk_json_write_array_end(w);
462 	spdk_jsonrpc_end_result(request, w);
463 }
464 SPDK_RPC_REGISTER("get_vhost_controllers", spdk_rpc_get_vhost_controllers)
465