xref: /spdk/lib/ublk/ublk_rpc.c (revision 8afdeef3becfe9409cc9e7372bd0bc10e8b7d46d)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2022 Intel Corporation.
3  *   All rights reserved.
4  */
5 
6 #include "spdk/string.h"
7 #include "spdk/env.h"
8 #include "spdk/rpc.h"
9 #include "spdk/util.h"
10 #include "spdk/log.h"
11 
12 #include "ublk_internal.h"
13 
14 struct rpc_ublk_create_target {
15 	char		*cpumask;
16 };
17 
18 static const struct spdk_json_object_decoder rpc_ublk_create_target_decoders[] = {
19 	{"cpumask", offsetof(struct rpc_ublk_create_target, cpumask), spdk_json_decode_string, true},
20 };
21 
22 static void
23 free_rpc_ublk_create_target(struct rpc_ublk_create_target *req)
24 {
25 	free(req->cpumask);
26 }
27 
28 static void
29 rpc_ublk_create_target(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params)
30 {
31 	int rc = 0;
32 	struct rpc_ublk_create_target req = {};
33 
34 	if (params != NULL) {
35 		if (spdk_json_decode_object_relaxed(params, rpc_ublk_create_target_decoders,
36 						    SPDK_COUNTOF(rpc_ublk_create_target_decoders),
37 						    &req)) {
38 			SPDK_ERRLOG("spdk_json_decode_object failed\n");
39 			rc = -EINVAL;
40 			goto invalid;
41 		}
42 	}
43 	rc = ublk_create_target(req.cpumask, params);
44 	if (rc != 0) {
45 		goto invalid;
46 	}
47 	spdk_jsonrpc_send_bool_response(request, true);
48 	free_rpc_ublk_create_target(&req);
49 	return;
50 invalid:
51 	SPDK_ERRLOG("Can't create ublk target: %s\n", spdk_strerror(-rc));
52 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, spdk_strerror(-rc));
53 	free_rpc_ublk_create_target(&req);
54 }
55 SPDK_RPC_REGISTER("ublk_create_target", rpc_ublk_create_target, SPDK_RPC_RUNTIME)
56 
57 static void
58 ublk_destroy_target_done(void *arg)
59 {
60 	struct spdk_jsonrpc_request *req = arg;
61 
62 	spdk_jsonrpc_send_bool_response(req, true);
63 	SPDK_NOTICELOG("ublk target has been destroyed\n");
64 }
65 
66 static void
67 rpc_ublk_destroy_target(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params)
68 {
69 	int rc = 0;
70 
71 	rc = ublk_destroy_target(ublk_destroy_target_done, request);
72 	if (rc != 0) {
73 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, spdk_strerror(-rc));
74 		SPDK_ERRLOG("Can't destroy ublk target: %s\n", spdk_strerror(-rc));
75 	}
76 }
77 SPDK_RPC_REGISTER("ublk_destroy_target", rpc_ublk_destroy_target, SPDK_RPC_RUNTIME)
78 
79 struct rpc_ublk_start_disk {
80 	char		*bdev_name;
81 	uint32_t	ublk_id;
82 	uint32_t	num_queues;
83 	uint32_t	queue_depth;
84 	struct spdk_jsonrpc_request *request;
85 };
86 
87 static const struct spdk_json_object_decoder rpc_ublk_start_disk_decoders[] = {
88 	{"bdev_name", offsetof(struct rpc_ublk_start_disk, bdev_name), spdk_json_decode_string},
89 	{"ublk_id", offsetof(struct rpc_ublk_start_disk, ublk_id), spdk_json_decode_uint32},
90 	{"num_queues", offsetof(struct rpc_ublk_start_disk, num_queues), spdk_json_decode_uint32, true},
91 	{"queue_depth", offsetof(struct rpc_ublk_start_disk, queue_depth), spdk_json_decode_uint32, true},
92 };
93 
94 static void
95 free_rpc_ublk_start_disk(struct rpc_ublk_start_disk *req)
96 {
97 	free(req->bdev_name);
98 	free(req);
99 }
100 
101 static void
102 rpc_ublk_start_disk_done(void *cb_arg, int rc)
103 {
104 	struct rpc_ublk_start_disk *req = cb_arg;
105 	struct spdk_json_write_ctx *w;
106 
107 	if (rc == 0) {
108 		w = spdk_jsonrpc_begin_result(req->request);
109 		spdk_json_write_uint32(w, req->ublk_id);
110 		spdk_jsonrpc_end_result(req->request, w);
111 	} else {
112 		spdk_jsonrpc_send_error_response(req->request, rc, spdk_strerror(-rc));
113 	}
114 
115 	free_rpc_ublk_start_disk(req);
116 }
117 
118 static void
119 rpc_ublk_start_disk(struct spdk_jsonrpc_request *request,
120 		    const struct spdk_json_val *params)
121 {
122 	struct rpc_ublk_start_disk *req;
123 	int rc;
124 
125 	req = calloc(1, sizeof(*req));
126 	if (req == NULL) {
127 		SPDK_ERRLOG("could not allocate request.\n");
128 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory");
129 		return;
130 	}
131 	req->request = request;
132 	req->queue_depth = UBLK_DEV_QUEUE_DEPTH;
133 	req->num_queues = UBLK_DEV_NUM_QUEUE;
134 
135 	if (spdk_json_decode_object(params, rpc_ublk_start_disk_decoders,
136 				    SPDK_COUNTOF(rpc_ublk_start_disk_decoders),
137 				    req)) {
138 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
139 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
140 						 "spdk_json_decode_object failed");
141 		goto out;
142 	}
143 
144 	rc = ublk_start_disk(req->bdev_name, req->ublk_id, req->num_queues, req->queue_depth,
145 			     rpc_ublk_start_disk_done, req);
146 	if (rc != 0) {
147 		rpc_ublk_start_disk_done(req, rc);
148 	}
149 
150 	return;
151 
152 out:
153 	free_rpc_ublk_start_disk(req);
154 }
155 
156 SPDK_RPC_REGISTER("ublk_start_disk", rpc_ublk_start_disk, SPDK_RPC_RUNTIME)
157 
158 struct rpc_ublk_stop_disk {
159 	uint32_t ublk_id;
160 	struct spdk_jsonrpc_request *request;
161 };
162 
163 static void
164 free_rpc_ublk_stop_disk(struct rpc_ublk_stop_disk *req)
165 {
166 	free(req);
167 }
168 
169 static const struct spdk_json_object_decoder rpc_ublk_stop_disk_decoders[] = {
170 	{"ublk_id", offsetof(struct rpc_ublk_stop_disk, ublk_id), spdk_json_decode_uint32},
171 };
172 
173 static void
174 rpc_ublk_stop_disk_done(void *cb_arg, int rc)
175 {
176 	struct rpc_ublk_stop_disk *req = cb_arg;
177 
178 	spdk_jsonrpc_send_bool_response(req->request, true);
179 	free_rpc_ublk_stop_disk(req);
180 }
181 
182 static void
183 rpc_ublk_stop_disk(struct spdk_jsonrpc_request *request,
184 		   const struct spdk_json_val *params)
185 {
186 	struct rpc_ublk_stop_disk *req;
187 	int rc;
188 
189 	req = calloc(1, sizeof(*req));
190 	if (req == NULL) {
191 		SPDK_ERRLOG("could not allocate request.\n");
192 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory");
193 		return;
194 	}
195 	req->request = request;
196 
197 	if (spdk_json_decode_object(params, rpc_ublk_stop_disk_decoders,
198 				    SPDK_COUNTOF(rpc_ublk_stop_disk_decoders),
199 				    req)) {
200 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
201 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
202 						 "spdk_json_decode_object failed");
203 		goto invalid;
204 	}
205 
206 	rc = ublk_stop_disk(req->ublk_id, rpc_ublk_stop_disk_done, req);
207 	if (rc) {
208 		spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
209 		goto invalid;
210 	}
211 	return;
212 
213 invalid:
214 	free_rpc_ublk_stop_disk(req);
215 }
216 
217 SPDK_RPC_REGISTER("ublk_stop_disk", rpc_ublk_stop_disk, SPDK_RPC_RUNTIME)
218 
219 static void
220 rpc_dump_ublk_info(struct spdk_json_write_ctx *w,
221 		   struct spdk_ublk_dev *ublk)
222 {
223 	char ublk_path[32];
224 
225 	snprintf(ublk_path, 32, "%s%u", "/dev/ublkb", ublk_dev_get_id(ublk));
226 	spdk_json_write_object_begin(w);
227 
228 	spdk_json_write_named_string(w, "ublk_device", ublk_path);
229 	spdk_json_write_named_uint32(w, "id", ublk_dev_get_id(ublk));
230 	spdk_json_write_named_uint32(w, "queue_depth", ublk_dev_get_queue_depth(ublk));
231 	spdk_json_write_named_uint32(w, "num_queues", ublk_dev_get_num_queues(ublk));
232 	spdk_json_write_named_string(w, "bdev_name", ublk_dev_get_bdev_name(ublk));
233 
234 	spdk_json_write_object_end(w);
235 }
236 
237 struct rpc_ublk_get_disks {
238 	uint32_t ublk_id;
239 };
240 
241 static const struct spdk_json_object_decoder rpc_ublk_get_disks_decoders[] = {
242 	{"ublk_id", offsetof(struct rpc_ublk_get_disks, ublk_id), spdk_json_decode_uint32, true},
243 };
244 
245 static void
246 rpc_ublk_get_disks(struct spdk_jsonrpc_request *request,
247 		   const struct spdk_json_val *params)
248 {
249 	struct rpc_ublk_get_disks req = {};
250 	struct spdk_json_write_ctx *w;
251 	struct spdk_ublk_dev *ublk = NULL;
252 
253 	if (params != NULL) {
254 		if (spdk_json_decode_object(params, rpc_ublk_get_disks_decoders,
255 					    SPDK_COUNTOF(rpc_ublk_get_disks_decoders),
256 					    &req)) {
257 			SPDK_ERRLOG("spdk_json_decode_object failed\n");
258 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
259 							 "spdk_json_decode_object failed");
260 			return;
261 		}
262 
263 		if (req.ublk_id) {
264 			ublk = ublk_dev_find_by_id(req.ublk_id);
265 			if (ublk == NULL) {
266 				SPDK_ERRLOG("ublk device '%d' does not exist\n", req.ublk_id);
267 				spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
268 				return;
269 			}
270 		}
271 	}
272 
273 	w = spdk_jsonrpc_begin_result(request);
274 	spdk_json_write_array_begin(w);
275 
276 	if (ublk != NULL) {
277 		rpc_dump_ublk_info(w, ublk);
278 	} else {
279 		for (ublk = ublk_dev_first(); ublk != NULL; ublk = ublk_dev_next(ublk)) {
280 			rpc_dump_ublk_info(w, ublk);
281 		}
282 	}
283 
284 	spdk_json_write_array_end(w);
285 	spdk_jsonrpc_end_result(request, w);
286 
287 	return;
288 }
289 SPDK_RPC_REGISTER("ublk_get_disks", rpc_ublk_get_disks, SPDK_RPC_RUNTIME)
290 
291 struct rpc_ublk_recover_disk {
292 	char		*bdev_name;
293 	uint32_t	ublk_id;
294 	struct spdk_jsonrpc_request *request;
295 };
296 
297 static const struct spdk_json_object_decoder rpc_ublk_recover_disk_decoders[] = {
298 	{"bdev_name", offsetof(struct rpc_ublk_recover_disk, bdev_name), spdk_json_decode_string},
299 	{"ublk_id", offsetof(struct rpc_ublk_recover_disk, ublk_id), spdk_json_decode_uint32},
300 };
301 
302 static void
303 free_rpc_ublk_recover_disk(struct rpc_ublk_recover_disk *req)
304 {
305 	free(req->bdev_name);
306 	free(req);
307 }
308 
309 static void
310 rpc_ublk_recover_disk_done(void *cb_arg, int rc)
311 {
312 	struct rpc_ublk_recover_disk *req = cb_arg;
313 	struct spdk_json_write_ctx *w;
314 
315 	if (rc == 0) {
316 		w = spdk_jsonrpc_begin_result(req->request);
317 		spdk_json_write_uint32(w, req->ublk_id);
318 		spdk_jsonrpc_end_result(req->request, w);
319 	} else {
320 		spdk_jsonrpc_send_error_response(req->request, rc, spdk_strerror(-rc));
321 	}
322 
323 	free_rpc_ublk_recover_disk(req);
324 }
325 
326 static void
327 rpc_ublk_recover_disk(struct spdk_jsonrpc_request *request,
328 		      const struct spdk_json_val *params)
329 {
330 	struct rpc_ublk_recover_disk *req;
331 	int rc;
332 
333 	req = calloc(1, sizeof(*req));
334 	if (req == NULL) {
335 		SPDK_ERRLOG("could not allocate request.\n");
336 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory");
337 		return;
338 	}
339 	req->request = request;
340 
341 	if (spdk_json_decode_object(params, rpc_ublk_recover_disk_decoders,
342 				    SPDK_COUNTOF(rpc_ublk_recover_disk_decoders),
343 				    req)) {
344 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
345 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
346 						 "spdk_json_decode_object failed");
347 		free(req);
348 		return;
349 	}
350 
351 	rc = ublk_start_disk_recovery(req->bdev_name, req->ublk_id, NULL, NULL);
352 	rpc_ublk_recover_disk_done(req, rc);
353 }
354 
355 SPDK_RPC_REGISTER("ublk_recover_disk", rpc_ublk_recover_disk, SPDK_RPC_RUNTIME)
356