Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2016 Intel Corporation. All rights reserved.
3 : : * Copyright (c) 2018-2021 Mellanox Technologies LTD. All rights reserved.
4 : : * Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
5 : : */
6 : :
7 : : #include "spdk/bdev.h"
8 : : #include "spdk/log.h"
9 : : #include "spdk/rpc.h"
10 : : #include "spdk/env.h"
11 : : #include "spdk/nvme.h"
12 : : #include "spdk/nvmf.h"
13 : : #include "spdk/string.h"
14 : : #include "spdk/util.h"
15 : : #include "spdk/bit_array.h"
16 : :
17 : : #include "spdk_internal/assert.h"
18 : :
19 : : #include "nvmf_internal.h"
20 : :
21 : : static bool g_logged_deprecated_nvmf_get_subsystems = false;
22 : :
23 : : static int rpc_ana_state_parse(const char *str, enum spdk_nvme_ana_state *ana_state);
24 : :
25 : : static int
26 : 690 : json_write_hex_str(struct spdk_json_write_ctx *w, const void *data, size_t size)
27 : : {
28 : : static const char hex_char[16] = "0123456789ABCDEF";
29 : 690 : const uint8_t *buf = data;
30 : : char *str, *out;
31 : : int rc;
32 : :
33 : 690 : str = malloc(size * 2 + 1);
34 [ - + ]: 690 : if (str == NULL) {
35 : 0 : return -1;
36 : : }
37 : :
38 : 690 : out = str;
39 [ + + ]: 11698 : while (size--) {
40 : 11008 : unsigned byte = *buf++;
41 : :
42 : 11008 : out[0] = hex_char[(byte >> 4) & 0xF];
43 : 11008 : out[1] = hex_char[byte & 0xF];
44 : :
45 : 11008 : out += 2;
46 : : }
47 : 690 : *out = '\0';
48 : :
49 : 690 : rc = spdk_json_write_string(w, str);
50 : 690 : free(str);
51 : :
52 : 690 : return rc;
53 : : }
54 : :
55 : : static int
56 : 1280 : hex_nybble_to_num(char c)
57 : : {
58 [ + - + + ]: 1280 : if (c >= '0' && c <= '9') {
59 : 839 : return c - '0';
60 : : }
61 : :
62 [ + + + - ]: 441 : if (c >= 'a' && c <= 'f') {
63 : 232 : return c - 'a' + 0xA;
64 : : }
65 : :
66 [ + - + - ]: 209 : if (c >= 'A' && c <= 'F') {
67 : 209 : return c - 'A' + 0xA;
68 : : }
69 : :
70 : 0 : return -1;
71 : : }
72 : :
73 : : static int
74 : 640 : hex_byte_to_num(const char *str)
75 : : {
76 : : int hi, lo;
77 : :
78 : 640 : hi = hex_nybble_to_num(str[0]);
79 [ - + ]: 640 : if (hi < 0) {
80 : 0 : return hi;
81 : : }
82 : :
83 : 640 : lo = hex_nybble_to_num(str[1]);
84 [ - + ]: 640 : if (lo < 0) {
85 : 0 : return lo;
86 : : }
87 : :
88 : 640 : return hi * 16 + lo;
89 : : }
90 : :
91 : : static int
92 : 42 : decode_hex_string_be(const char *str, uint8_t *out, size_t size)
93 : : {
94 : : size_t i;
95 : :
96 : : /* Decode a string in "ABCDEF012345" format to its binary representation */
97 [ + + ]: 682 : for (i = 0; i < size; i++) {
98 : 640 : int num = hex_byte_to_num(str);
99 : :
100 [ - + ]: 640 : if (num < 0) {
101 : : /* Invalid hex byte or end of string */
102 : 0 : return -1;
103 : : }
104 : :
105 : 640 : out[i] = (uint8_t)num;
106 : 640 : str += 2;
107 : : }
108 : :
109 [ + - - + ]: 42 : if (i != size || *str != '\0') {
110 : : /* Length mismatch */
111 : 0 : return -1;
112 : : }
113 : :
114 : 42 : return 0;
115 : : }
116 : :
117 : : static int
118 : 38 : decode_ns_nguid(const struct spdk_json_val *val, void *out)
119 : : {
120 : 38 : char *str = NULL;
121 : : int rc;
122 : :
123 : 38 : rc = spdk_json_decode_string(val, &str);
124 [ + - ]: 38 : if (rc == 0) {
125 : : /* 16-byte NGUID */
126 : 38 : rc = decode_hex_string_be(str, out, 16);
127 : : }
128 : :
129 : 38 : free(str);
130 : 38 : return rc;
131 : : }
132 : :
133 : : static int
134 : 4 : decode_ns_eui64(const struct spdk_json_val *val, void *out)
135 : : {
136 : 4 : char *str = NULL;
137 : : int rc;
138 : :
139 : 4 : rc = spdk_json_decode_string(val, &str);
140 [ + - ]: 4 : if (rc == 0) {
141 : : /* 8-byte EUI-64 */
142 : 4 : rc = decode_hex_string_be(str, out, 8);
143 : : }
144 : :
145 : 4 : free(str);
146 : 4 : return rc;
147 : : }
148 : :
149 : : struct rpc_get_subsystem {
150 : : char *nqn;
151 : : char *tgt_name;
152 : : };
153 : :
154 : : static const struct spdk_json_object_decoder rpc_get_subsystem_decoders[] = {
155 : : {"nqn", offsetof(struct rpc_get_subsystem, nqn), spdk_json_decode_string, true},
156 : : {"tgt_name", offsetof(struct rpc_get_subsystem, tgt_name), spdk_json_decode_string, true},
157 : : };
158 : :
159 : : static void
160 : 947 : dump_nvmf_subsystem(struct spdk_json_write_ctx *w, struct spdk_nvmf_subsystem *subsystem)
161 : : {
162 : : struct spdk_nvmf_host *host;
163 : : struct spdk_nvmf_subsystem_listener *listener;
164 : :
165 : 947 : spdk_json_write_object_begin(w);
166 : :
167 : 947 : spdk_json_write_named_string(w, "nqn", spdk_nvmf_subsystem_get_nqn(subsystem));
168 : 947 : spdk_json_write_name(w, "subtype");
169 [ + + ]: 947 : if (spdk_nvmf_subsystem_get_type(subsystem) == SPDK_NVMF_SUBTYPE_NVME) {
170 : 631 : spdk_json_write_string(w, "NVMe");
171 : : } else {
172 : 316 : spdk_json_write_string(w, "Discovery");
173 : : }
174 : :
175 : 947 : spdk_json_write_named_array_begin(w, "listen_addresses");
176 : :
177 [ + + ]: 1762 : for (listener = spdk_nvmf_subsystem_get_first_listener(subsystem); listener != NULL;
178 : 815 : listener = spdk_nvmf_subsystem_get_next_listener(subsystem, listener)) {
179 : : const struct spdk_nvme_transport_id *trid;
180 : :
181 : 815 : trid = spdk_nvmf_subsystem_listener_get_trid(listener);
182 : :
183 : 815 : spdk_json_write_object_begin(w);
184 : :
185 : : /* NOTE: "transport" is kept for compatibility; new code should use "trtype". */
186 : : /* TODO: Remove after SPDK v23.09 release. */
187 : 815 : spdk_json_write_named_string(w, "transport", trid->trstring);
188 : 815 : nvmf_transport_listen_dump_trid(trid, w);
189 : 815 : spdk_json_write_object_end(w);
190 : : }
191 : 947 : spdk_json_write_array_end(w);
192 : :
193 : 947 : spdk_json_write_named_bool(w, "allow_any_host",
194 : 947 : spdk_nvmf_subsystem_get_allow_any_host(subsystem));
195 : :
196 : 947 : spdk_json_write_named_array_begin(w, "hosts");
197 : :
198 [ + + ]: 1142 : for (host = spdk_nvmf_subsystem_get_first_host(subsystem); host != NULL;
199 : 195 : host = spdk_nvmf_subsystem_get_next_host(subsystem, host)) {
200 : 195 : spdk_json_write_object_begin(w);
201 : 195 : spdk_json_write_named_string(w, "nqn", spdk_nvmf_host_get_nqn(host));
202 : 195 : spdk_json_write_object_end(w);
203 : : }
204 : 947 : spdk_json_write_array_end(w);
205 : :
206 [ + + ]: 947 : if (spdk_nvmf_subsystem_get_type(subsystem) == SPDK_NVMF_SUBTYPE_NVME) {
207 : : struct spdk_nvmf_ns *ns;
208 : 158 : struct spdk_nvmf_ns_opts ns_opts;
209 : : uint32_t max_namespaces;
210 : :
211 : 631 : spdk_json_write_named_string(w, "serial_number", spdk_nvmf_subsystem_get_sn(subsystem));
212 : :
213 : 631 : spdk_json_write_named_string(w, "model_number", spdk_nvmf_subsystem_get_mn(subsystem));
214 : :
215 : 631 : max_namespaces = spdk_nvmf_subsystem_get_max_namespaces(subsystem);
216 [ + - ]: 631 : if (max_namespaces != 0) {
217 : 631 : spdk_json_write_named_uint32(w, "max_namespaces", max_namespaces);
218 : : }
219 : :
220 : 631 : spdk_json_write_named_uint32(w, "min_cntlid", spdk_nvmf_subsystem_get_min_cntlid(subsystem));
221 : 631 : spdk_json_write_named_uint32(w, "max_cntlid", spdk_nvmf_subsystem_get_max_cntlid(subsystem));
222 : :
223 : 631 : spdk_json_write_named_array_begin(w, "namespaces");
224 [ + + ]: 1317 : for (ns = spdk_nvmf_subsystem_get_first_ns(subsystem); ns != NULL;
225 : 686 : ns = spdk_nvmf_subsystem_get_next_ns(subsystem, ns)) {
226 : 686 : spdk_nvmf_ns_get_opts(ns, &ns_opts, sizeof(ns_opts));
227 : 686 : spdk_json_write_object_begin(w);
228 : 686 : spdk_json_write_named_int32(w, "nsid", spdk_nvmf_ns_get_id(ns));
229 : 686 : spdk_json_write_named_string(w, "bdev_name",
230 : 686 : spdk_bdev_get_name(spdk_nvmf_ns_get_bdev(ns)));
231 : : /* NOTE: "name" is kept for compatibility only - new code should use bdev_name. */
232 : 686 : spdk_json_write_named_string(w, "name",
233 : 686 : spdk_bdev_get_name(spdk_nvmf_ns_get_bdev(ns)));
234 : :
235 [ + - ]: 686 : if (!spdk_mem_all_zero(ns_opts.nguid, sizeof(ns_opts.nguid))) {
236 : 686 : spdk_json_write_name(w, "nguid");
237 : 686 : json_write_hex_str(w, ns_opts.nguid, sizeof(ns_opts.nguid));
238 : : }
239 : :
240 [ + + ]: 686 : if (!spdk_mem_all_zero(ns_opts.eui64, sizeof(ns_opts.eui64))) {
241 : 4 : spdk_json_write_name(w, "eui64");
242 : 4 : json_write_hex_str(w, ns_opts.eui64, sizeof(ns_opts.eui64));
243 : : }
244 : :
245 [ + - ]: 686 : if (!spdk_uuid_is_null(&ns_opts.uuid)) {
246 : 686 : spdk_json_write_named_uuid(w, "uuid", &ns_opts.uuid);
247 : : }
248 : :
249 [ - + ]: 686 : if (spdk_nvmf_subsystem_get_ana_reporting(subsystem)) {
250 : 0 : spdk_json_write_named_uint32(w, "anagrpid", ns_opts.anagrpid);
251 : : }
252 : :
253 : 686 : spdk_json_write_object_end(w);
254 : : }
255 : 631 : spdk_json_write_array_end(w);
256 : : }
257 : 947 : spdk_json_write_object_end(w);
258 : 947 : }
259 : :
260 [ - + ]: 741 : SPDK_LOG_DEPRECATION_REGISTER(rpc_nvmf_get_subsystems,
261 : : "listener.transport is deprecated in favor of trtype",
262 : : "v24.05", 0);
263 : :
264 : : static void
265 : 459 : rpc_nvmf_get_subsystems(struct spdk_jsonrpc_request *request,
266 : : const struct spdk_json_val *params)
267 : : {
268 : 459 : struct rpc_get_subsystem req = { 0 };
269 : : struct spdk_json_write_ctx *w;
270 : 459 : struct spdk_nvmf_subsystem *subsystem = NULL;
271 : : struct spdk_nvmf_tgt *tgt;
272 : :
273 : : /* Log only once */
274 [ - + + + ]: 459 : if (!g_logged_deprecated_nvmf_get_subsystems) {
275 : 26 : SPDK_LOG_DEPRECATED(rpc_nvmf_get_subsystems);
276 : 26 : g_logged_deprecated_nvmf_get_subsystems = true;
277 : : }
278 : :
279 [ + + ]: 459 : if (params) {
280 [ - + ]: 119 : if (spdk_json_decode_object(params, rpc_get_subsystem_decoders,
281 : : SPDK_COUNTOF(rpc_get_subsystem_decoders),
282 : : &req)) {
283 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
284 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
285 : 0 : return;
286 : : }
287 : : }
288 : :
289 : 459 : tgt = spdk_nvmf_get_tgt(req.tgt_name);
290 [ - + ]: 459 : if (!tgt) {
291 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
292 : : "Unable to find a target.");
293 : 0 : free(req.tgt_name);
294 : 0 : free(req.nqn);
295 : 0 : return;
296 : : }
297 : :
298 [ + + ]: 459 : if (req.nqn) {
299 : 119 : subsystem = spdk_nvmf_tgt_find_subsystem(tgt, req.nqn);
300 [ + + ]: 119 : if (!subsystem) {
301 : 16 : SPDK_ERRLOG("subsystem '%s' does not exist\n", req.nqn);
302 : 16 : spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
303 : 16 : free(req.tgt_name);
304 : 16 : free(req.nqn);
305 : 16 : return;
306 : : }
307 : : }
308 : :
309 : 443 : w = spdk_jsonrpc_begin_result(request);
310 : 443 : spdk_json_write_array_begin(w);
311 : :
312 [ + + ]: 443 : if (subsystem) {
313 : 103 : dump_nvmf_subsystem(w, subsystem);
314 : : } else {
315 [ + + ]: 1184 : for (subsystem = spdk_nvmf_subsystem_get_first(tgt); subsystem != NULL;
316 : 844 : subsystem = spdk_nvmf_subsystem_get_next(subsystem)) {
317 : 844 : dump_nvmf_subsystem(w, subsystem);
318 : : }
319 : : }
320 : :
321 : 443 : spdk_json_write_array_end(w);
322 : 443 : spdk_jsonrpc_end_result(request, w);
323 : 443 : free(req.tgt_name);
324 : 443 : free(req.nqn);
325 : : }
326 : 741 : SPDK_RPC_REGISTER("nvmf_get_subsystems", rpc_nvmf_get_subsystems, SPDK_RPC_RUNTIME)
327 : :
328 : : struct rpc_subsystem_create {
329 : : char *nqn;
330 : : char *serial_number;
331 : : char *model_number;
332 : : char *tgt_name;
333 : : uint32_t max_namespaces;
334 : : bool allow_any_host;
335 : : bool ana_reporting;
336 : : uint16_t min_cntlid;
337 : : uint16_t max_cntlid;
338 : : uint64_t max_discard_size_kib;
339 : : uint64_t max_write_zeroes_size_kib;
340 : : };
341 : :
342 : : static const struct spdk_json_object_decoder rpc_subsystem_create_decoders[] = {
343 : : {"nqn", offsetof(struct rpc_subsystem_create, nqn), spdk_json_decode_string},
344 : : {"serial_number", offsetof(struct rpc_subsystem_create, serial_number), spdk_json_decode_string, true},
345 : : {"model_number", offsetof(struct rpc_subsystem_create, model_number), spdk_json_decode_string, true},
346 : : {"tgt_name", offsetof(struct rpc_subsystem_create, tgt_name), spdk_json_decode_string, true},
347 : : {"max_namespaces", offsetof(struct rpc_subsystem_create, max_namespaces), spdk_json_decode_uint32, true},
348 : : {"allow_any_host", offsetof(struct rpc_subsystem_create, allow_any_host), spdk_json_decode_bool, true},
349 : : {"ana_reporting", offsetof(struct rpc_subsystem_create, ana_reporting), spdk_json_decode_bool, true},
350 : : {"min_cntlid", offsetof(struct rpc_subsystem_create, min_cntlid), spdk_json_decode_uint16, true},
351 : : {"max_cntlid", offsetof(struct rpc_subsystem_create, max_cntlid), spdk_json_decode_uint16, true},
352 : : {"max_discard_size_kib", offsetof(struct rpc_subsystem_create, max_discard_size_kib), spdk_json_decode_uint64, true},
353 : : {"max_write_zeroes_size_kib", offsetof(struct rpc_subsystem_create, max_write_zeroes_size_kib), spdk_json_decode_uint64, true},
354 : : };
355 : :
356 : : static void
357 : 404 : rpc_nvmf_subsystem_started(struct spdk_nvmf_subsystem *subsystem,
358 : : void *cb_arg, int status)
359 : : {
360 : 404 : struct spdk_jsonrpc_request *request = cb_arg;
361 : :
362 [ + - ]: 404 : if (!status) {
363 : 404 : spdk_jsonrpc_send_bool_response(request, true);
364 : : } else {
365 : 0 : spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
366 : : "Subsystem %s start failed",
367 : 0 : subsystem->subnqn);
368 : 0 : spdk_nvmf_subsystem_destroy(subsystem, NULL, NULL);
369 : : }
370 : 404 : }
371 : :
372 : : static void
373 : 434 : rpc_nvmf_create_subsystem(struct spdk_jsonrpc_request *request,
374 : : const struct spdk_json_val *params)
375 : : {
376 : : struct rpc_subsystem_create *req;
377 : 434 : struct spdk_nvmf_subsystem *subsystem = NULL;
378 : : struct spdk_nvmf_tgt *tgt;
379 : 434 : int rc = -1;
380 : :
381 : 434 : req = calloc(1, sizeof(*req));
382 [ - + ]: 434 : if (!req) {
383 : 0 : SPDK_ERRLOG("Memory allocation failed\n");
384 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
385 : : "Memory allocation failed");
386 : 0 : return;
387 : : }
388 : 434 : req->min_cntlid = NVMF_MIN_CNTLID;
389 : 434 : req->max_cntlid = NVMF_MAX_CNTLID;
390 : :
391 [ - + ]: 434 : if (spdk_json_decode_object(params, rpc_subsystem_create_decoders,
392 : : SPDK_COUNTOF(rpc_subsystem_create_decoders),
393 : : req)) {
394 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
395 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
396 : 0 : goto cleanup;
397 : : }
398 : :
399 : 434 : tgt = spdk_nvmf_get_tgt(req->tgt_name);
400 [ + + ]: 434 : if (!tgt) {
401 : 3 : SPDK_ERRLOG("Unable to find target %s\n", req->tgt_name);
402 : 3 : spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
403 : : "Unable to find target %s", req->tgt_name);
404 : 3 : goto cleanup;
405 : : }
406 : :
407 : 431 : subsystem = spdk_nvmf_subsystem_create(tgt, req->nqn, SPDK_NVMF_SUBTYPE_NVME,
408 : : req->max_namespaces);
409 [ - + ]: 431 : if (!subsystem) {
410 : 0 : SPDK_ERRLOG("Unable to create subsystem %s\n", req->nqn);
411 : 0 : spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
412 : : "Unable to create subsystem %s", req->nqn);
413 : 0 : goto cleanup;
414 : : }
415 : :
416 [ + + ]: 431 : if (req->serial_number) {
417 [ + + ]: 371 : if (spdk_nvmf_subsystem_set_sn(subsystem, req->serial_number)) {
418 : 6 : SPDK_ERRLOG("Subsystem %s: invalid serial number '%s'\n", req->nqn, req->serial_number);
419 : 6 : spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
420 : : "Invalid SN %s", req->serial_number);
421 : 6 : goto cleanup;
422 : : }
423 : : }
424 : :
425 [ + + ]: 425 : if (req->model_number) {
426 [ + + ]: 27 : if (spdk_nvmf_subsystem_set_mn(subsystem, req->model_number)) {
427 : 6 : SPDK_ERRLOG("Subsystem %s: invalid model number '%s'\n", req->nqn, req->model_number);
428 : 6 : spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
429 : : "Invalid MN %s", req->model_number);
430 : 6 : goto cleanup;
431 : : }
432 : : }
433 : :
434 [ - + ]: 419 : spdk_nvmf_subsystem_set_allow_any_host(subsystem, req->allow_any_host);
435 : :
436 [ - + ]: 419 : spdk_nvmf_subsystem_set_ana_reporting(subsystem, req->ana_reporting);
437 : :
438 [ + + ]: 419 : if (nvmf_subsystem_set_cntlid_range(subsystem, req->min_cntlid, req->max_cntlid)) {
439 : 15 : SPDK_ERRLOG("Subsystem %s: invalid cntlid range [%u-%u]\n", req->nqn, req->min_cntlid,
440 : : req->max_cntlid);
441 : 30 : spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
442 : 15 : "Invalid cntlid range [%u-%u]", req->min_cntlid, req->max_cntlid);
443 : 15 : goto cleanup;
444 : : }
445 : :
446 : 404 : subsystem->max_discard_size_kib = req->max_discard_size_kib;
447 : :
448 : : /* max_write_zeroes_size_kib must be aligned to 4 and power of 2 */
449 [ - + - - : 404 : if (req->max_write_zeroes_size_kib == 0 || (req->max_write_zeroes_size_kib > 2 &&
- - ]
450 : 0 : spdk_u64_is_pow2(req->max_write_zeroes_size_kib))) {
451 : 404 : subsystem->max_write_zeroes_size_kib = req->max_write_zeroes_size_kib;
452 : : } else {
453 : 0 : SPDK_ERRLOG("Subsystem %s: invalid max_write_zeroes_size_kib %"PRIu64"\n", req->nqn,
454 : : req->max_write_zeroes_size_kib);
455 : 0 : spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
456 : : "Invalid max_write_zeroes_size_kib %"PRIu64"\n", req->max_write_zeroes_size_kib);
457 : 0 : goto cleanup;
458 : : }
459 : :
460 : 404 : rc = spdk_nvmf_subsystem_start(subsystem,
461 : : rpc_nvmf_subsystem_started,
462 : : request);
463 [ + - ]: 404 : if (rc) {
464 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
465 : : "Failed to start subsystem");
466 : : }
467 : :
468 : 404 : cleanup:
469 : 434 : free(req->nqn);
470 : 434 : free(req->tgt_name);
471 : 434 : free(req->serial_number);
472 : 434 : free(req->model_number);
473 : 434 : free(req);
474 : :
475 [ + + + + ]: 434 : if (rc && subsystem) {
476 : 27 : spdk_nvmf_subsystem_destroy(subsystem, NULL, NULL);
477 : : }
478 : : }
479 : 741 : SPDK_RPC_REGISTER("nvmf_create_subsystem", rpc_nvmf_create_subsystem, SPDK_RPC_RUNTIME)
480 : :
481 : : struct rpc_delete_subsystem {
482 : : char *nqn;
483 : : char *tgt_name;
484 : : };
485 : :
486 : : static void
487 : 243 : free_rpc_delete_subsystem(struct rpc_delete_subsystem *r)
488 : : {
489 : 243 : free(r->nqn);
490 : 243 : free(r->tgt_name);
491 : 243 : }
492 : :
493 : : static void
494 : 3 : rpc_nvmf_subsystem_destroy_complete_cb(void *cb_arg)
495 : : {
496 : 3 : struct spdk_jsonrpc_request *request = cb_arg;
497 : :
498 : 3 : spdk_jsonrpc_send_bool_response(request, true);
499 : 3 : }
500 : :
501 : : static void
502 : 243 : rpc_nvmf_subsystem_stopped(struct spdk_nvmf_subsystem *subsystem,
503 : : void *cb_arg, int status)
504 : : {
505 : 243 : struct spdk_jsonrpc_request *request = cb_arg;
506 : : int rc;
507 : :
508 : 243 : nvmf_subsystem_remove_all_listeners(subsystem, true);
509 : 243 : rc = spdk_nvmf_subsystem_destroy(subsystem, rpc_nvmf_subsystem_destroy_complete_cb, request);
510 [ + + ]: 243 : if (rc) {
511 [ + - ]: 3 : if (rc == -EINPROGRESS) {
512 : : /* response will be sent in completion callback */
513 : 3 : return;
514 : : } else {
515 : 0 : SPDK_ERRLOG("Subsystem destruction failed, rc %d\n", rc);
516 : 0 : spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
517 : : "Subsystem destruction failed, rc %d", rc);
518 : 0 : return;
519 : : }
520 : : }
521 : 240 : spdk_jsonrpc_send_bool_response(request, true);
522 : : }
523 : :
524 : : static const struct spdk_json_object_decoder rpc_delete_subsystem_decoders[] = {
525 : : {"nqn", offsetof(struct rpc_delete_subsystem, nqn), spdk_json_decode_string},
526 : : {"tgt_name", offsetof(struct rpc_delete_subsystem, tgt_name), spdk_json_decode_string, true},
527 : : };
528 : :
529 : : static void
530 : 243 : rpc_nvmf_delete_subsystem(struct spdk_jsonrpc_request *request,
531 : : const struct spdk_json_val *params)
532 : : {
533 : 243 : struct rpc_delete_subsystem req = { 0 };
534 : : struct spdk_nvmf_subsystem *subsystem;
535 : : struct spdk_nvmf_tgt *tgt;
536 : : int rc;
537 : :
538 [ - + ]: 243 : if (spdk_json_decode_object(params, rpc_delete_subsystem_decoders,
539 : : SPDK_COUNTOF(rpc_delete_subsystem_decoders),
540 : : &req)) {
541 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
542 : 0 : goto invalid;
543 : : }
544 : :
545 [ - + ]: 243 : if (req.nqn == NULL) {
546 : 0 : SPDK_ERRLOG("missing name param\n");
547 : 0 : goto invalid;
548 : : }
549 : :
550 : 243 : tgt = spdk_nvmf_get_tgt(req.tgt_name);
551 [ - + ]: 243 : if (!tgt) {
552 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
553 : : "Unable to find a target.");
554 : 0 : goto invalid_custom_response;
555 : : }
556 : :
557 : 243 : subsystem = spdk_nvmf_tgt_find_subsystem(tgt, req.nqn);
558 [ - + ]: 243 : if (!subsystem) {
559 : 0 : goto invalid;
560 : : }
561 : :
562 : 243 : free_rpc_delete_subsystem(&req);
563 : :
564 : 243 : rc = spdk_nvmf_subsystem_stop(subsystem,
565 : : rpc_nvmf_subsystem_stopped,
566 : : request);
567 [ - + ]: 243 : if (rc == -EBUSY) {
568 : 0 : SPDK_ERRLOG("Subsystem currently in another state change try again later.\n");
569 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
570 : : "Subsystem currently in another state change try again later.");
571 [ - + ]: 243 : } else if (rc != 0) {
572 : 0 : SPDK_ERRLOG("Unable to change state on subsystem. rc=%d\n", rc);
573 : 0 : spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
574 : : "Unable to change state on subsystem. rc=%d", rc);
575 : : }
576 : :
577 : 243 : return;
578 : :
579 : 0 : invalid:
580 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
581 : 0 : invalid_custom_response:
582 : 0 : free_rpc_delete_subsystem(&req);
583 : : }
584 : 741 : SPDK_RPC_REGISTER("nvmf_delete_subsystem", rpc_nvmf_delete_subsystem, SPDK_RPC_RUNTIME)
585 : :
586 : : struct rpc_listen_address {
587 : : char *transport;
588 : : char *adrfam;
589 : : char *traddr;
590 : : char *trsvcid;
591 : : };
592 : :
593 : : static const struct spdk_json_object_decoder rpc_listen_address_decoders[] = {
594 : : /* NOTE: "transport" is kept for compatibility; new code should use "trtype" */
595 : : {"transport", offsetof(struct rpc_listen_address, transport), spdk_json_decode_string, true},
596 : : {"trtype", offsetof(struct rpc_listen_address, transport), spdk_json_decode_string, true},
597 : : {"adrfam", offsetof(struct rpc_listen_address, adrfam), spdk_json_decode_string, true},
598 : : {"traddr", offsetof(struct rpc_listen_address, traddr), spdk_json_decode_string},
599 : : {"trsvcid", offsetof(struct rpc_listen_address, trsvcid), spdk_json_decode_string, true},
600 : : };
601 : :
602 : : static int
603 : 634 : decode_rpc_listen_address(const struct spdk_json_val *val, void *out)
604 : : {
605 : 634 : struct rpc_listen_address *req = (struct rpc_listen_address *)out;
606 [ - + ]: 634 : if (spdk_json_decode_object(val, rpc_listen_address_decoders,
607 : : SPDK_COUNTOF(rpc_listen_address_decoders),
608 : : req)) {
609 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
610 : 0 : return -1;
611 : : }
612 : 634 : return 0;
613 : : }
614 : :
615 : : static void
616 : 634 : free_rpc_listen_address(struct rpc_listen_address *r)
617 : : {
618 : 634 : free(r->transport);
619 : 634 : free(r->adrfam);
620 : 634 : free(r->traddr);
621 : 634 : free(r->trsvcid);
622 : 634 : }
623 : :
624 : : enum nvmf_rpc_listen_op {
625 : : NVMF_RPC_LISTEN_ADD,
626 : : NVMF_RPC_LISTEN_REMOVE,
627 : : NVMF_RPC_LISTEN_SET_ANA_STATE,
628 : : };
629 : :
630 : : struct nvmf_rpc_listener_ctx {
631 : : char *nqn;
632 : : char *tgt_name;
633 : : struct spdk_nvmf_tgt *tgt;
634 : : struct spdk_nvmf_transport *transport;
635 : : struct spdk_nvmf_subsystem *subsystem;
636 : : struct rpc_listen_address address;
637 : : char *ana_state_str;
638 : : enum spdk_nvme_ana_state ana_state;
639 : : uint32_t anagrpid;
640 : :
641 : : struct spdk_jsonrpc_request *request;
642 : : struct spdk_nvme_transport_id trid;
643 : : enum nvmf_rpc_listen_op op;
644 : : bool response_sent;
645 : : struct spdk_nvmf_listen_opts opts;
646 : :
647 : : /* Additional options for listener creation. */
648 : : struct spdk_nvmf_listener_opts listener_opts;
649 : : };
650 : :
651 : : static const struct spdk_json_object_decoder nvmf_rpc_listener_decoder[] = {
652 : : {"nqn", offsetof(struct nvmf_rpc_listener_ctx, nqn), spdk_json_decode_string},
653 : : {"listen_address", offsetof(struct nvmf_rpc_listener_ctx, address), decode_rpc_listen_address},
654 : : {"tgt_name", offsetof(struct nvmf_rpc_listener_ctx, tgt_name), spdk_json_decode_string, true},
655 : : {"secure_channel", offsetof(struct nvmf_rpc_listener_ctx, listener_opts.secure_channel), spdk_json_decode_bool, true},
656 : : {"ana_state", offsetof(struct nvmf_rpc_listener_ctx, ana_state_str), spdk_json_decode_string, true},
657 : : };
658 : :
659 : : static void
660 : 595 : nvmf_rpc_listener_ctx_free(struct nvmf_rpc_listener_ctx *ctx)
661 : : {
662 : 595 : free(ctx->nqn);
663 : 595 : free(ctx->tgt_name);
664 : 595 : free_rpc_listen_address(&ctx->address);
665 : 595 : free(ctx->ana_state_str);
666 : 595 : free(ctx);
667 : 595 : }
668 : :
669 : : static void
670 : 595 : nvmf_rpc_listen_resumed(struct spdk_nvmf_subsystem *subsystem,
671 : : void *cb_arg, int status)
672 : : {
673 : 595 : struct nvmf_rpc_listener_ctx *ctx = cb_arg;
674 : : struct spdk_jsonrpc_request *request;
675 : :
676 : 595 : request = ctx->request;
677 [ - + + + ]: 595 : if (ctx->response_sent) {
678 : : /* If an error occurred, the response has already been sent. */
679 : 3 : nvmf_rpc_listener_ctx_free(ctx);
680 : 3 : return;
681 : : }
682 : :
683 : 592 : nvmf_rpc_listener_ctx_free(ctx);
684 : :
685 : 592 : spdk_jsonrpc_send_bool_response(request, true);
686 : : }
687 : :
688 : : static void
689 : 508 : nvmf_rpc_subsystem_listen(void *cb_arg, int status)
690 : : {
691 : 508 : struct nvmf_rpc_listener_ctx *ctx = cb_arg;
692 : :
693 [ - + ]: 508 : if (status) {
694 : : /* Destroy the listener that we just created. Ignore the error code because
695 : : * the RPC is failing already anyway. */
696 : 0 : spdk_nvmf_tgt_stop_listen(ctx->tgt, &ctx->trid);
697 : :
698 : 0 : spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
699 : : "Invalid parameters");
700 : 0 : ctx->response_sent = true;
701 : : }
702 : :
703 [ - + ]: 508 : if (spdk_nvmf_subsystem_resume(ctx->subsystem, nvmf_rpc_listen_resumed, ctx)) {
704 [ # # # # ]: 0 : if (!ctx->response_sent) {
705 : 0 : spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
706 : : "Internal error");
707 : : }
708 : 0 : nvmf_rpc_listener_ctx_free(ctx);
709 : : /* Can't really do anything to recover here - subsystem will remain paused. */
710 : : }
711 : 508 : }
712 : : static void
713 : 40 : nvmf_rpc_stop_listen_async_done(void *cb_arg, int status)
714 : : {
715 : 40 : struct nvmf_rpc_listener_ctx *ctx = cb_arg;
716 : :
717 [ - + ]: 40 : if (status) {
718 : 0 : SPDK_ERRLOG("Unable to stop listener.\n");
719 : 0 : spdk_jsonrpc_send_error_response_fmt(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
720 : : "error stopping listener: %d", status);
721 : 0 : ctx->response_sent = true;
722 : : }
723 : :
724 [ - + ]: 40 : if (spdk_nvmf_subsystem_resume(ctx->subsystem, nvmf_rpc_listen_resumed, ctx)) {
725 [ # # # # ]: 0 : if (!ctx->response_sent) {
726 : 0 : spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
727 : : "Internal error");
728 : : }
729 : 0 : nvmf_rpc_listener_ctx_free(ctx);
730 : : /* Can't really do anything to recover here - subsystem will remain paused. */
731 : : }
732 : 40 : }
733 : :
734 : : static void
735 : 42 : nvmf_rpc_set_ana_state_done(void *cb_arg, int status)
736 : : {
737 : 42 : struct nvmf_rpc_listener_ctx *ctx = cb_arg;
738 : :
739 [ - + ]: 42 : if (status) {
740 : 0 : SPDK_ERRLOG("Unable to set ANA state.\n");
741 : 0 : spdk_jsonrpc_send_error_response_fmt(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
742 : : "error setting ANA state: %d", status);
743 : 0 : ctx->response_sent = true;
744 : : }
745 : :
746 [ - + ]: 42 : if (spdk_nvmf_subsystem_resume(ctx->subsystem, nvmf_rpc_listen_resumed, ctx)) {
747 [ # # # # ]: 0 : if (!ctx->response_sent) {
748 : 0 : spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
749 : : "Internal error");
750 : : }
751 : 0 : nvmf_rpc_listener_ctx_free(ctx);
752 : : /* Can't really do anything to recover here - subsystem will remain paused. */
753 : : }
754 : 42 : }
755 : :
756 : : static void
757 : 595 : nvmf_rpc_listen_paused(struct spdk_nvmf_subsystem *subsystem,
758 : : void *cb_arg, int status)
759 : : {
760 : 595 : struct nvmf_rpc_listener_ctx *ctx = cb_arg;
761 : : int rc;
762 : :
763 [ + + ]: 595 : if (ctx->op == NVMF_RPC_LISTEN_ADD) {
764 [ + + ]: 510 : if (!nvmf_subsystem_find_listener(subsystem, &ctx->trid)) {
765 : 508 : rc = spdk_nvmf_tgt_listen_ext(ctx->tgt, &ctx->trid, &ctx->opts);
766 [ + - ]: 508 : if (rc == 0) {
767 : 508 : spdk_nvmf_subsystem_add_listener_ext(ctx->subsystem, &ctx->trid, nvmf_rpc_subsystem_listen, ctx,
768 : : &ctx->listener_opts);
769 : 508 : return;
770 : : }
771 : :
772 : 0 : spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
773 : : "Invalid parameters");
774 : 0 : ctx->response_sent = true;
775 : : }
776 [ + + ]: 85 : } else if (ctx->op == NVMF_RPC_LISTEN_REMOVE) {
777 : 43 : rc = spdk_nvmf_subsystem_remove_listener(subsystem, &ctx->trid);
778 [ + + ]: 43 : if (rc == 0) {
779 : 40 : spdk_nvmf_transport_stop_listen_async(ctx->transport, &ctx->trid, subsystem,
780 : : nvmf_rpc_stop_listen_async_done, ctx);
781 : 40 : return;
782 : : }
783 : 3 : SPDK_ERRLOG("Unable to remove listener, rc %d\n", rc);
784 : 3 : spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
785 : : "Invalid parameters");
786 : 3 : ctx->response_sent = true;
787 [ + - ]: 42 : } else if (ctx->op == NVMF_RPC_LISTEN_SET_ANA_STATE) {
788 : 42 : spdk_nvmf_subsystem_set_ana_state(subsystem, &ctx->trid, ctx->ana_state, ctx->anagrpid,
789 : : nvmf_rpc_set_ana_state_done, ctx);
790 : 42 : return;
791 : : } else {
792 : 0 : SPDK_UNREACHABLE();
793 : : }
794 : :
795 [ - + ]: 5 : if (spdk_nvmf_subsystem_resume(subsystem, nvmf_rpc_listen_resumed, ctx)) {
796 [ # # # # ]: 0 : if (!ctx->response_sent) {
797 : 0 : spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
798 : : "Internal error");
799 : : }
800 : 0 : nvmf_rpc_listener_ctx_free(ctx);
801 : : /* Can't really do anything to recover here - subsystem will remain paused. */
802 : : }
803 : : }
804 : :
805 : : static int
806 : 634 : rpc_listen_address_to_trid(const struct rpc_listen_address *address,
807 : : struct spdk_nvme_transport_id *trid)
808 : : {
809 : : size_t len;
810 : :
811 [ - + ]: 634 : memset(trid, 0, sizeof(*trid));
812 : :
813 [ - + ]: 634 : if (spdk_nvme_transport_id_populate_trstring(trid, address->transport)) {
814 : 0 : SPDK_ERRLOG("Invalid transport string: %s\n", address->transport);
815 : 0 : return -EINVAL;
816 : : }
817 : :
818 [ - + ]: 634 : if (spdk_nvme_transport_id_parse_trtype(&trid->trtype, address->transport)) {
819 : 0 : SPDK_ERRLOG("Invalid transport type: %s\n", address->transport);
820 : 0 : return -EINVAL;
821 : : }
822 : :
823 [ + + ]: 634 : if (address->adrfam) {
824 [ - + ]: 48 : if (spdk_nvme_transport_id_parse_adrfam(&trid->adrfam, address->adrfam)) {
825 : 0 : SPDK_ERRLOG("Invalid adrfam: %s\n", address->adrfam);
826 : 0 : return -EINVAL;
827 : : }
828 : : } else {
829 : 586 : trid->adrfam = SPDK_NVMF_ADRFAM_IPV4;
830 : : }
831 : :
832 [ - + ]: 634 : len = strlen(address->traddr);
833 [ - + ]: 634 : if (len > sizeof(trid->traddr) - 1) {
834 : 0 : SPDK_ERRLOG("Transport address longer than %zu characters: %s\n",
835 : : sizeof(trid->traddr) - 1, address->traddr);
836 : 0 : return -EINVAL;
837 : : }
838 [ - + - + ]: 634 : memcpy(trid->traddr, address->traddr, len + 1);
839 : :
840 : 634 : trid->trsvcid[0] = '\0';
841 [ + + ]: 634 : if (address->trsvcid) {
842 [ - + ]: 625 : len = strlen(address->trsvcid);
843 [ - + ]: 625 : if (len > sizeof(trid->trsvcid) - 1) {
844 : 0 : SPDK_ERRLOG("Transport service id longer than %zu characters: %s\n",
845 : : sizeof(trid->trsvcid) - 1, address->trsvcid);
846 : 0 : return -EINVAL;
847 : : }
848 [ - + - + ]: 625 : memcpy(trid->trsvcid, address->trsvcid, len + 1);
849 : : }
850 : :
851 : 634 : return 0;
852 : : }
853 : :
854 : : static void
855 : 510 : rpc_nvmf_subsystem_add_listener(struct spdk_jsonrpc_request *request,
856 : : const struct spdk_json_val *params)
857 : : {
858 : : struct nvmf_rpc_listener_ctx *ctx;
859 : : struct spdk_nvmf_subsystem *subsystem;
860 : : struct spdk_nvmf_tgt *tgt;
861 : : int rc;
862 : :
863 : 510 : ctx = calloc(1, sizeof(*ctx));
864 [ - + ]: 510 : if (!ctx) {
865 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory");
866 : 0 : return;
867 : : }
868 : :
869 : 510 : ctx->request = request;
870 : :
871 : 510 : spdk_nvmf_subsystem_listener_opts_init(&ctx->listener_opts, sizeof(ctx->listener_opts));
872 : :
873 [ - + ]: 510 : if (spdk_json_decode_object_relaxed(params, nvmf_rpc_listener_decoder,
874 : : SPDK_COUNTOF(nvmf_rpc_listener_decoder),
875 : : ctx)) {
876 : 0 : SPDK_ERRLOG("spdk_json_decode_object_relaxed failed\n");
877 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
878 : 0 : nvmf_rpc_listener_ctx_free(ctx);
879 : 0 : return;
880 : : }
881 : :
882 : 510 : tgt = spdk_nvmf_get_tgt(ctx->tgt_name);
883 [ - + ]: 510 : if (!tgt) {
884 : 0 : SPDK_ERRLOG("Unable to find a target object.\n");
885 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
886 : : "Unable to find a target.");
887 : 0 : nvmf_rpc_listener_ctx_free(ctx);
888 : 0 : return;
889 : : }
890 : 510 : ctx->tgt = tgt;
891 : :
892 : 510 : subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx->nqn);
893 [ - + ]: 510 : if (!subsystem) {
894 : 0 : SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn);
895 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
896 : 0 : nvmf_rpc_listener_ctx_free(ctx);
897 : 0 : return;
898 : : }
899 : :
900 : 510 : ctx->subsystem = subsystem;
901 : :
902 [ - + ]: 510 : if (rpc_listen_address_to_trid(&ctx->address, &ctx->trid)) {
903 : 0 : spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
904 : : "Invalid parameters");
905 : 0 : nvmf_rpc_listener_ctx_free(ctx);
906 : 0 : return;
907 : : }
908 : :
909 : 510 : ctx->op = NVMF_RPC_LISTEN_ADD;
910 : 510 : spdk_nvmf_listen_opts_init(&ctx->opts, sizeof(ctx->opts));
911 : 510 : ctx->opts.transport_specific = params;
912 [ + + - + : 510 : if (subsystem->flags.allow_any_host == 1 && ctx->listener_opts.secure_channel == true) {
- + ]
913 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
914 : : "Cannot establish secure channel, when 'allow_any_host' is set");
915 : 0 : nvmf_rpc_listener_ctx_free(ctx);
916 : 0 : return;
917 : : }
918 [ - + ]: 510 : ctx->opts.secure_channel = ctx->listener_opts.secure_channel;
919 : :
920 [ - + ]: 510 : if (ctx->ana_state_str) {
921 [ # # ]: 0 : if (rpc_ana_state_parse(ctx->ana_state_str, &ctx->ana_state)) {
922 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
923 : : "Invalid parameters");
924 : 0 : nvmf_rpc_listener_ctx_free(ctx);
925 : 0 : return;
926 : : }
927 : 0 : ctx->listener_opts.ana_state = ctx->ana_state;
928 : : }
929 : :
930 : 510 : rc = spdk_nvmf_subsystem_pause(subsystem, 0, nvmf_rpc_listen_paused, ctx);
931 [ - + ]: 510 : if (rc != 0) {
932 [ # # ]: 0 : if (rc == -EBUSY) {
933 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
934 : : "subsystem busy, retry later.\n");
935 : : } else {
936 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
937 : : }
938 : 0 : nvmf_rpc_listener_ctx_free(ctx);
939 : : }
940 : : }
941 : 741 : SPDK_RPC_REGISTER("nvmf_subsystem_add_listener", rpc_nvmf_subsystem_add_listener,
942 : : SPDK_RPC_RUNTIME);
943 : :
944 : : static void
945 : 43 : rpc_nvmf_subsystem_remove_listener(struct spdk_jsonrpc_request *request,
946 : : const struct spdk_json_val *params)
947 : : {
948 : : struct nvmf_rpc_listener_ctx *ctx;
949 : : struct spdk_nvmf_subsystem *subsystem;
950 : : struct spdk_nvmf_tgt *tgt;
951 : : int rc;
952 : :
953 : 43 : ctx = calloc(1, sizeof(*ctx));
954 [ - + ]: 43 : if (!ctx) {
955 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory");
956 : 0 : return;
957 : : }
958 : :
959 : 43 : ctx->request = request;
960 : :
961 [ - + ]: 43 : if (spdk_json_decode_object(params, nvmf_rpc_listener_decoder,
962 : : SPDK_COUNTOF(nvmf_rpc_listener_decoder),
963 : : ctx)) {
964 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
965 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
966 : 0 : nvmf_rpc_listener_ctx_free(ctx);
967 : 0 : return;
968 : : }
969 : :
970 : 43 : tgt = spdk_nvmf_get_tgt(ctx->tgt_name);
971 [ - + ]: 43 : if (!tgt) {
972 : 0 : SPDK_ERRLOG("Unable to find a target object.\n");
973 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
974 : : "Unable to find a target.");
975 : 0 : nvmf_rpc_listener_ctx_free(ctx);
976 : 0 : return;
977 : : }
978 : 43 : ctx->tgt = tgt;
979 : :
980 : 43 : subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx->nqn);
981 [ - + ]: 43 : if (!subsystem) {
982 : 0 : SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn);
983 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
984 : 0 : nvmf_rpc_listener_ctx_free(ctx);
985 : 0 : return;
986 : : }
987 : :
988 : 43 : ctx->subsystem = subsystem;
989 : :
990 [ - + ]: 43 : if (rpc_listen_address_to_trid(&ctx->address, &ctx->trid)) {
991 : 0 : spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
992 : : "Invalid parameters");
993 : 0 : nvmf_rpc_listener_ctx_free(ctx);
994 : 0 : return;
995 : : }
996 : :
997 : 43 : ctx->transport = spdk_nvmf_tgt_get_transport(tgt, ctx->trid.trstring);
998 [ - + ]: 43 : if (!ctx->transport) {
999 : 0 : SPDK_ERRLOG("Unable to find %s transport. The transport must be created first also make sure it is properly registered.\n",
1000 : : ctx->trid.trstring);
1001 : 0 : spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1002 : : "Invalid parameters");
1003 : 0 : nvmf_rpc_listener_ctx_free(ctx);
1004 : 0 : return;
1005 : : }
1006 : :
1007 : 43 : ctx->op = NVMF_RPC_LISTEN_REMOVE;
1008 : :
1009 : 43 : rc = spdk_nvmf_subsystem_pause(subsystem, 0, nvmf_rpc_listen_paused, ctx);
1010 [ - + ]: 43 : if (rc != 0) {
1011 [ # # ]: 0 : if (rc == -EBUSY) {
1012 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1013 : : "subsystem busy, retry later.\n");
1014 : : } else {
1015 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
1016 : : }
1017 : 0 : nvmf_rpc_listener_ctx_free(ctx);
1018 : : }
1019 : : }
1020 : 741 : SPDK_RPC_REGISTER("nvmf_subsystem_remove_listener", rpc_nvmf_subsystem_remove_listener,
1021 : : SPDK_RPC_RUNTIME);
1022 : :
1023 : : struct nvmf_rpc_referral_ctx {
1024 : : char *tgt_name;
1025 : : struct rpc_listen_address address;
1026 : : bool secure_channel;
1027 : : char *subnqn;
1028 : : };
1029 : :
1030 : : static const struct spdk_json_object_decoder nvmf_rpc_referral_decoder[] = {
1031 : : {"address", offsetof(struct nvmf_rpc_referral_ctx, address), decode_rpc_listen_address},
1032 : : {"tgt_name", offsetof(struct nvmf_rpc_referral_ctx, tgt_name), spdk_json_decode_string, true},
1033 : : {"secure_channel", offsetof(struct nvmf_rpc_referral_ctx, secure_channel), spdk_json_decode_bool, true},
1034 : : {"subnqn", offsetof(struct nvmf_rpc_referral_ctx, subnqn), spdk_json_decode_string, true},
1035 : : };
1036 : :
1037 : : static void
1038 : 39 : nvmf_rpc_referral_ctx_free(struct nvmf_rpc_referral_ctx *ctx)
1039 : : {
1040 : 39 : free(ctx->tgt_name);
1041 : 39 : free(ctx->subnqn);
1042 : 39 : free_rpc_listen_address(&ctx->address);
1043 : 39 : }
1044 : :
1045 : : static void
1046 : 21 : rpc_nvmf_add_referral(struct spdk_jsonrpc_request *request,
1047 : : const struct spdk_json_val *params)
1048 : : {
1049 : 21 : struct nvmf_rpc_referral_ctx ctx = {};
1050 : 21 : struct spdk_nvme_transport_id trid = {};
1051 : : struct spdk_nvmf_tgt *tgt;
1052 : 21 : struct spdk_nvmf_referral_opts opts = {};
1053 : : int rc;
1054 : :
1055 [ - + ]: 21 : if (spdk_json_decode_object_relaxed(params, nvmf_rpc_referral_decoder,
1056 : : SPDK_COUNTOF(nvmf_rpc_referral_decoder),
1057 : : &ctx)) {
1058 : 0 : SPDK_ERRLOG("spdk_json_decode_object_relaxed failed\n");
1059 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
1060 : 0 : nvmf_rpc_referral_ctx_free(&ctx);
1061 : 0 : return;
1062 : : }
1063 : :
1064 : 21 : tgt = spdk_nvmf_get_tgt(ctx.tgt_name);
1065 [ - + ]: 21 : if (!tgt) {
1066 : 0 : SPDK_ERRLOG("Unable to find a target object.\n");
1067 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1068 : : "Unable to find a target.");
1069 : 0 : nvmf_rpc_referral_ctx_free(&ctx);
1070 : 0 : return;
1071 : : }
1072 : :
1073 [ - + ]: 21 : if (rpc_listen_address_to_trid(&ctx.address, &trid)) {
1074 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1075 : : "Invalid parameters");
1076 : 0 : nvmf_rpc_referral_ctx_free(&ctx);
1077 : 0 : return;
1078 : : }
1079 : :
1080 [ + + ]: 21 : if (ctx.subnqn != NULL) {
1081 [ - + ]: 6 : rc = snprintf(trid.subnqn, sizeof(trid.subnqn), "%s", ctx.subnqn);
1082 [ + - - + ]: 6 : if (rc < 0 || (size_t)rc >= sizeof(trid.subnqn)) {
1083 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1084 : : "Invalid subsystem NQN");
1085 : 0 : nvmf_rpc_referral_ctx_free(&ctx);
1086 : 0 : return;
1087 : : }
1088 : : }
1089 : :
1090 [ + + ]: 21 : if ((trid.trtype == SPDK_NVME_TRANSPORT_TCP ||
1091 [ + - ]: 6 : trid.trtype == SPDK_NVME_TRANSPORT_RDMA) &&
1092 [ - + ]: 21 : !strlen(trid.trsvcid)) {
1093 : 0 : SPDK_ERRLOG("Service ID is required.\n");
1094 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1095 : : "Service ID is required.");
1096 : 0 : nvmf_rpc_referral_ctx_free(&ctx);
1097 : 0 : return;
1098 : : }
1099 : :
1100 : 21 : opts.size = SPDK_SIZEOF(&opts, secure_channel);
1101 : 21 : opts.trid = trid;
1102 [ - + ]: 21 : opts.secure_channel = ctx.secure_channel;
1103 : :
1104 : 21 : rc = spdk_nvmf_tgt_add_referral(tgt, &opts);
1105 [ - + ]: 21 : if (rc != 0) {
1106 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1107 : : "Internal error");
1108 : 0 : nvmf_rpc_referral_ctx_free(&ctx);
1109 : 0 : return;
1110 : : }
1111 : :
1112 : 21 : nvmf_rpc_referral_ctx_free(&ctx);
1113 : :
1114 : 21 : spdk_jsonrpc_send_bool_response(request, true);
1115 : : }
1116 : :
1117 : 741 : SPDK_RPC_REGISTER("nvmf_discovery_add_referral", rpc_nvmf_add_referral,
1118 : : SPDK_RPC_RUNTIME);
1119 : :
1120 : : static void
1121 : 18 : rpc_nvmf_remove_referral(struct spdk_jsonrpc_request *request,
1122 : : const struct spdk_json_val *params)
1123 : : {
1124 : 18 : struct nvmf_rpc_referral_ctx ctx = {};
1125 : 18 : struct spdk_nvme_transport_id trid = {};
1126 : 18 : struct spdk_nvmf_referral_opts opts = {};
1127 : : struct spdk_nvmf_tgt *tgt;
1128 : : int rc;
1129 : :
1130 [ - + ]: 18 : if (spdk_json_decode_object(params, nvmf_rpc_referral_decoder,
1131 : : SPDK_COUNTOF(nvmf_rpc_referral_decoder),
1132 : : &ctx)) {
1133 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
1134 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
1135 : 0 : nvmf_rpc_referral_ctx_free(&ctx);
1136 : 0 : return;
1137 : : }
1138 : :
1139 : 18 : tgt = spdk_nvmf_get_tgt(ctx.tgt_name);
1140 [ - + ]: 18 : if (!tgt) {
1141 : 0 : SPDK_ERRLOG("Unable to find a target object.\n");
1142 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1143 : : "Unable to find a target.");
1144 : 0 : nvmf_rpc_referral_ctx_free(&ctx);
1145 : 0 : return;
1146 : : }
1147 : :
1148 [ - + ]: 18 : if (rpc_listen_address_to_trid(&ctx.address, &trid)) {
1149 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1150 : : "Invalid parameters");
1151 : 0 : nvmf_rpc_referral_ctx_free(&ctx);
1152 : 0 : return;
1153 : : }
1154 : :
1155 [ + + ]: 18 : if (ctx.subnqn != NULL) {
1156 [ - + ]: 6 : rc = snprintf(trid.subnqn, sizeof(trid.subnqn), "%s", ctx.subnqn);
1157 [ + - - + ]: 6 : if (rc < 0 || (size_t)rc >= sizeof(trid.subnqn)) {
1158 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1159 : : "Invalid subsystem NQN");
1160 : 0 : nvmf_rpc_referral_ctx_free(&ctx);
1161 : 0 : return;
1162 : : }
1163 : : }
1164 : :
1165 : 18 : opts.size = SPDK_SIZEOF(&opts, secure_channel);
1166 : 18 : opts.trid = trid;
1167 : :
1168 [ - + ]: 18 : if (spdk_nvmf_tgt_remove_referral(tgt, &opts)) {
1169 : 0 : SPDK_ERRLOG("Failed to remove referral.\n");
1170 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1171 : : "Unable to remove a referral.");
1172 : 0 : nvmf_rpc_referral_ctx_free(&ctx);
1173 : 0 : return;
1174 : : }
1175 : :
1176 : 18 : nvmf_rpc_referral_ctx_free(&ctx);
1177 : :
1178 : 18 : spdk_jsonrpc_send_bool_response(request, true);
1179 : : }
1180 : :
1181 : 741 : SPDK_RPC_REGISTER("nvmf_discovery_remove_referral", rpc_nvmf_remove_referral,
1182 : : SPDK_RPC_RUNTIME);
1183 : :
1184 : : static void
1185 : 81 : dump_nvmf_referral(struct spdk_json_write_ctx *w,
1186 : : struct spdk_nvmf_referral *referral)
1187 : : {
1188 : 81 : spdk_json_write_object_begin(w);
1189 : :
1190 : 81 : spdk_json_write_named_object_begin(w, "address");
1191 : 81 : nvmf_transport_listen_dump_trid(&referral->trid, w);
1192 : 81 : spdk_json_write_object_end(w);
1193 : 81 : spdk_json_write_named_bool(w, "secure_channel",
1194 : 81 : referral->entry.treq.secure_channel == SPDK_NVMF_TREQ_SECURE_CHANNEL_REQUIRED);
1195 : 81 : spdk_json_write_named_string(w, "subnqn", referral->trid.subnqn);
1196 : :
1197 : 81 : spdk_json_write_object_end(w);
1198 : 81 : }
1199 : :
1200 : : struct rpc_get_referrals_ctx {
1201 : : char *tgt_name;
1202 : : };
1203 : :
1204 : : static const struct spdk_json_object_decoder rpc_get_referrals_decoders[] = {
1205 : : {"tgt_name", offsetof(struct rpc_get_referrals_ctx, tgt_name), spdk_json_decode_string, true},
1206 : : };
1207 : :
1208 : : static void
1209 : 200 : free_rpc_get_referrals_ctx(struct rpc_get_referrals_ctx *ctx)
1210 : : {
1211 : 200 : free(ctx->tgt_name);
1212 : 200 : free(ctx);
1213 : 200 : }
1214 : :
1215 : : static void
1216 : 200 : rpc_nvmf_get_referrals(struct spdk_jsonrpc_request *request,
1217 : : const struct spdk_json_val *params)
1218 : : {
1219 : : struct rpc_get_referrals_ctx *ctx;
1220 : : struct spdk_nvmf_tgt *tgt;
1221 : : struct spdk_json_write_ctx *w;
1222 : : struct spdk_nvmf_referral *referral;
1223 : :
1224 : 200 : ctx = calloc(1, sizeof(*ctx));
1225 [ - + ]: 200 : if (!ctx) {
1226 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1227 : : "Out of memory");
1228 : 0 : return;
1229 : : }
1230 : :
1231 [ - + ]: 200 : if (params) {
1232 [ # # ]: 0 : if (spdk_json_decode_object(params, rpc_get_referrals_decoders,
1233 : : SPDK_COUNTOF(rpc_get_referrals_decoders),
1234 : : ctx)) {
1235 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
1236 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1237 : : "Invalid parameters");
1238 : 0 : free_rpc_get_referrals_ctx(ctx);
1239 : 0 : return;
1240 : : }
1241 : : }
1242 : :
1243 : 200 : tgt = spdk_nvmf_get_tgt(ctx->tgt_name);
1244 [ - + ]: 200 : if (!tgt) {
1245 : 0 : SPDK_ERRLOG("Unable to find a target object.\n");
1246 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1247 : : "Unable to find a target");
1248 : 0 : free_rpc_get_referrals_ctx(ctx);
1249 : 0 : return;
1250 : : }
1251 : :
1252 : 200 : w = spdk_jsonrpc_begin_result(request);
1253 : :
1254 : 200 : spdk_json_write_array_begin(w);
1255 : :
1256 [ + + ]: 281 : TAILQ_FOREACH(referral, &tgt->referrals, link) {
1257 : 81 : dump_nvmf_referral(w, referral);
1258 : : }
1259 : :
1260 : 200 : spdk_json_write_array_end(w);
1261 : :
1262 : 200 : spdk_jsonrpc_end_result(request, w);
1263 : :
1264 : 200 : free_rpc_get_referrals_ctx(ctx);
1265 : : }
1266 : 741 : SPDK_RPC_REGISTER("nvmf_discovery_get_referrals", rpc_nvmf_get_referrals,
1267 : : SPDK_RPC_RUNTIME);
1268 : :
1269 : : static const struct spdk_json_object_decoder nvmf_rpc_set_ana_state_decoder[] = {
1270 : : {"nqn", offsetof(struct nvmf_rpc_listener_ctx, nqn), spdk_json_decode_string},
1271 : : {"listen_address", offsetof(struct nvmf_rpc_listener_ctx, address), decode_rpc_listen_address},
1272 : : {"ana_state", offsetof(struct nvmf_rpc_listener_ctx, ana_state_str), spdk_json_decode_string},
1273 : : {"tgt_name", offsetof(struct nvmf_rpc_listener_ctx, tgt_name), spdk_json_decode_string, true},
1274 : : {"anagrpid", offsetof(struct nvmf_rpc_listener_ctx, anagrpid), spdk_json_decode_uint32, true},
1275 : : };
1276 : :
1277 : : static int
1278 : 42 : rpc_ana_state_parse(const char *str, enum spdk_nvme_ana_state *ana_state)
1279 : : {
1280 [ + - - + ]: 42 : if (ana_state == NULL || str == NULL) {
1281 : 0 : return -EINVAL;
1282 : : }
1283 : :
1284 [ - + + + ]: 42 : if (strcasecmp(str, "optimized") == 0) {
1285 : 12 : *ana_state = SPDK_NVME_ANA_OPTIMIZED_STATE;
1286 [ - + + + ]: 30 : } else if (strcasecmp(str, "non_optimized") == 0) {
1287 : 14 : *ana_state = SPDK_NVME_ANA_NON_OPTIMIZED_STATE;
1288 [ - + + - ]: 16 : } else if (strcasecmp(str, "inaccessible") == 0) {
1289 : 16 : *ana_state = SPDK_NVME_ANA_INACCESSIBLE_STATE;
1290 : : } else {
1291 : 0 : return -ENOENT;
1292 : : }
1293 : :
1294 : 42 : return 0;
1295 : : }
1296 : :
1297 : : static void
1298 : 42 : rpc_nvmf_subsystem_listener_set_ana_state(struct spdk_jsonrpc_request *request,
1299 : : const struct spdk_json_val *params)
1300 : : {
1301 : : struct nvmf_rpc_listener_ctx *ctx;
1302 : : struct spdk_nvmf_subsystem *subsystem;
1303 : : struct spdk_nvmf_tgt *tgt;
1304 : :
1305 : 42 : ctx = calloc(1, sizeof(*ctx));
1306 [ - + ]: 42 : if (!ctx) {
1307 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1308 : : "Out of memory");
1309 : 0 : return;
1310 : : }
1311 : :
1312 : 42 : ctx->request = request;
1313 : :
1314 [ - + ]: 42 : if (spdk_json_decode_object(params, nvmf_rpc_set_ana_state_decoder,
1315 : : SPDK_COUNTOF(nvmf_rpc_set_ana_state_decoder),
1316 : : ctx)) {
1317 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
1318 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1319 : : "Invalid parameters");
1320 : 0 : nvmf_rpc_listener_ctx_free(ctx);
1321 : 0 : return;
1322 : : }
1323 : :
1324 : 42 : tgt = spdk_nvmf_get_tgt(ctx->tgt_name);
1325 [ - + ]: 42 : if (!tgt) {
1326 : 0 : SPDK_ERRLOG("Unable to find a target object.\n");
1327 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1328 : : "Unable to find a target.\n");
1329 : 0 : nvmf_rpc_listener_ctx_free(ctx);
1330 : 0 : return;
1331 : : }
1332 : :
1333 : 42 : ctx->tgt = tgt;
1334 : :
1335 : 42 : subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx->nqn);
1336 [ - + ]: 42 : if (!subsystem) {
1337 : 0 : SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn);
1338 : 0 : spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1339 : : "Unable to find subsystem with NQN %s",
1340 : : ctx->nqn);
1341 : 0 : nvmf_rpc_listener_ctx_free(ctx);
1342 : 0 : return;
1343 : : }
1344 : :
1345 : 42 : ctx->subsystem = subsystem;
1346 : :
1347 [ - + ]: 42 : if (rpc_listen_address_to_trid(&ctx->address, &ctx->trid)) {
1348 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1349 : : "Invalid parameters");
1350 : 0 : nvmf_rpc_listener_ctx_free(ctx);
1351 : 0 : return;
1352 : : }
1353 : :
1354 [ - + ]: 42 : if (rpc_ana_state_parse(ctx->ana_state_str, &ctx->ana_state)) {
1355 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1356 : : "Invalid parameters");
1357 : 0 : nvmf_rpc_listener_ctx_free(ctx);
1358 : 0 : return;
1359 : : }
1360 : :
1361 : 42 : ctx->op = NVMF_RPC_LISTEN_SET_ANA_STATE;
1362 : :
1363 [ - + ]: 42 : if (spdk_nvmf_subsystem_pause(subsystem, 0, nvmf_rpc_listen_paused, ctx)) {
1364 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1365 : : "Internal error");
1366 : 0 : nvmf_rpc_listener_ctx_free(ctx);
1367 : : }
1368 : : }
1369 : 741 : SPDK_RPC_REGISTER("nvmf_subsystem_listener_set_ana_state",
1370 : : rpc_nvmf_subsystem_listener_set_ana_state, SPDK_RPC_RUNTIME);
1371 : :
1372 : : struct spdk_nvmf_ns_params {
1373 : : char *bdev_name;
1374 : : char *ptpl_file;
1375 : : uint32_t nsid;
1376 : : char nguid[16];
1377 : : char eui64[8];
1378 : : struct spdk_uuid uuid;
1379 : : uint32_t anagrpid;
1380 : : };
1381 : :
1382 : : static const struct spdk_json_object_decoder rpc_ns_params_decoders[] = {
1383 : : {"nsid", offsetof(struct spdk_nvmf_ns_params, nsid), spdk_json_decode_uint32, true},
1384 : : {"bdev_name", offsetof(struct spdk_nvmf_ns_params, bdev_name), spdk_json_decode_string},
1385 : : {"ptpl_file", offsetof(struct spdk_nvmf_ns_params, ptpl_file), spdk_json_decode_string, true},
1386 : : {"nguid", offsetof(struct spdk_nvmf_ns_params, nguid), decode_ns_nguid, true},
1387 : : {"eui64", offsetof(struct spdk_nvmf_ns_params, eui64), decode_ns_eui64, true},
1388 : : {"uuid", offsetof(struct spdk_nvmf_ns_params, uuid), spdk_json_decode_uuid, true},
1389 : : {"anagrpid", offsetof(struct spdk_nvmf_ns_params, anagrpid), spdk_json_decode_uint32, true},
1390 : : };
1391 : :
1392 : : static int
1393 : 4133 : decode_rpc_ns_params(const struct spdk_json_val *val, void *out)
1394 : : {
1395 : 4133 : struct spdk_nvmf_ns_params *ns_params = out;
1396 : :
1397 : 4133 : return spdk_json_decode_object(val, rpc_ns_params_decoders,
1398 : : SPDK_COUNTOF(rpc_ns_params_decoders),
1399 : : ns_params);
1400 : : }
1401 : :
1402 : : struct nvmf_rpc_ns_ctx {
1403 : : char *nqn;
1404 : : char *tgt_name;
1405 : : struct spdk_nvmf_ns_params ns_params;
1406 : :
1407 : : struct spdk_jsonrpc_request *request;
1408 : : bool response_sent;
1409 : : };
1410 : :
1411 : : static const struct spdk_json_object_decoder nvmf_rpc_subsystem_ns_decoder[] = {
1412 : : {"nqn", offsetof(struct nvmf_rpc_ns_ctx, nqn), spdk_json_decode_string},
1413 : : {"namespace", offsetof(struct nvmf_rpc_ns_ctx, ns_params), decode_rpc_ns_params},
1414 : : {"tgt_name", offsetof(struct nvmf_rpc_ns_ctx, tgt_name), spdk_json_decode_string, true},
1415 : : };
1416 : :
1417 : : static void
1418 : 4133 : nvmf_rpc_ns_ctx_free(struct nvmf_rpc_ns_ctx *ctx)
1419 : : {
1420 : 4133 : free(ctx->nqn);
1421 : 4133 : free(ctx->tgt_name);
1422 : 4133 : free(ctx->ns_params.bdev_name);
1423 : 4133 : free(ctx->ns_params.ptpl_file);
1424 : 4133 : free(ctx);
1425 : 4133 : }
1426 : :
1427 : : static void
1428 : 0 : nvmf_rpc_ns_failback_resumed(struct spdk_nvmf_subsystem *subsystem,
1429 : : void *cb_arg, int status)
1430 : : {
1431 : 0 : struct nvmf_rpc_ns_ctx *ctx = cb_arg;
1432 : 0 : struct spdk_jsonrpc_request *request = ctx->request;
1433 : :
1434 [ # # ]: 0 : if (status) {
1435 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1436 : : "Unable to add ns, subsystem in invalid state");
1437 : : } else {
1438 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1439 : : "Unable to add ns, subsystem in active state");
1440 : : }
1441 : :
1442 : 0 : nvmf_rpc_ns_ctx_free(ctx);
1443 : 0 : }
1444 : :
1445 : : static void
1446 : 4133 : nvmf_rpc_ns_resumed(struct spdk_nvmf_subsystem *subsystem,
1447 : : void *cb_arg, int status)
1448 : : {
1449 : 4133 : struct nvmf_rpc_ns_ctx *ctx = cb_arg;
1450 : 4133 : struct spdk_jsonrpc_request *request = ctx->request;
1451 : 4133 : uint32_t nsid = ctx->ns_params.nsid;
1452 [ - + ]: 4133 : bool response_sent = ctx->response_sent;
1453 : : struct spdk_json_write_ctx *w;
1454 : : int rc;
1455 : :
1456 : : /* The case where the call to add the namespace was successful, but the subsystem couldn't be resumed. */
1457 [ - + - - : 4133 : if (status && !ctx->response_sent) {
- - ]
1458 : 0 : rc = spdk_nvmf_subsystem_remove_ns(subsystem, nsid);
1459 [ # # ]: 0 : if (rc != 0) {
1460 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1461 : : "Unable to add ns, subsystem in invalid state");
1462 : 0 : nvmf_rpc_ns_ctx_free(ctx);
1463 : 0 : return;
1464 : : }
1465 : :
1466 : 0 : rc = spdk_nvmf_subsystem_resume(subsystem, nvmf_rpc_ns_failback_resumed, ctx);
1467 [ # # ]: 0 : if (rc != 0) {
1468 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
1469 : 0 : nvmf_rpc_ns_ctx_free(ctx);
1470 : 0 : return;
1471 : : }
1472 : :
1473 : 0 : return;
1474 : : }
1475 : :
1476 : 4133 : nvmf_rpc_ns_ctx_free(ctx);
1477 : :
1478 [ + + ]: 4133 : if (response_sent) {
1479 : 1433 : return;
1480 : : }
1481 : :
1482 : 2700 : w = spdk_jsonrpc_begin_result(request);
1483 : 2700 : spdk_json_write_uint32(w, nsid);
1484 : 2700 : spdk_jsonrpc_end_result(request, w);
1485 : : }
1486 : :
1487 : : static void
1488 : 4133 : nvmf_rpc_ns_paused(struct spdk_nvmf_subsystem *subsystem,
1489 : : void *cb_arg, int status)
1490 : : {
1491 : 4133 : struct nvmf_rpc_ns_ctx *ctx = cb_arg;
1492 : 34 : struct spdk_nvmf_ns_opts ns_opts;
1493 : :
1494 : 4133 : spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts));
1495 : 4133 : ns_opts.nsid = ctx->ns_params.nsid;
1496 : :
1497 : : SPDK_STATIC_ASSERT(sizeof(ns_opts.nguid) == sizeof(ctx->ns_params.nguid), "size mismatch");
1498 : 4133 : memcpy(ns_opts.nguid, ctx->ns_params.nguid, sizeof(ns_opts.nguid));
1499 : :
1500 : : SPDK_STATIC_ASSERT(sizeof(ns_opts.eui64) == sizeof(ctx->ns_params.eui64), "size mismatch");
1501 : 4133 : memcpy(ns_opts.eui64, ctx->ns_params.eui64, sizeof(ns_opts.eui64));
1502 : :
1503 [ + + ]: 4133 : if (!spdk_uuid_is_null(&ctx->ns_params.uuid)) {
1504 : 31 : ns_opts.uuid = ctx->ns_params.uuid;
1505 : : }
1506 : :
1507 : 4133 : ns_opts.anagrpid = ctx->ns_params.anagrpid;
1508 : :
1509 : 4133 : ctx->ns_params.nsid = spdk_nvmf_subsystem_add_ns_ext(subsystem, ctx->ns_params.bdev_name,
1510 : : &ns_opts, sizeof(ns_opts),
1511 : 4133 : ctx->ns_params.ptpl_file);
1512 [ + + ]: 4133 : if (ctx->ns_params.nsid == 0) {
1513 : 1433 : SPDK_ERRLOG("Unable to add namespace\n");
1514 : 1433 : spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1515 : : "Invalid parameters");
1516 : 1433 : ctx->response_sent = true;
1517 : 1433 : goto resume;
1518 : : }
1519 : :
1520 : 2700 : resume:
1521 [ - + ]: 4133 : if (spdk_nvmf_subsystem_resume(subsystem, nvmf_rpc_ns_resumed, ctx)) {
1522 : 0 : spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
1523 : 0 : nvmf_rpc_ns_ctx_free(ctx);
1524 : : }
1525 : 4133 : }
1526 : :
1527 : : static void
1528 : 4133 : rpc_nvmf_subsystem_add_ns(struct spdk_jsonrpc_request *request,
1529 : : const struct spdk_json_val *params)
1530 : : {
1531 : : struct nvmf_rpc_ns_ctx *ctx;
1532 : : struct spdk_nvmf_subsystem *subsystem;
1533 : : struct spdk_nvmf_tgt *tgt;
1534 : : int rc;
1535 : :
1536 : 4133 : ctx = calloc(1, sizeof(*ctx));
1537 [ - + ]: 4133 : if (!ctx) {
1538 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory");
1539 : 0 : return;
1540 : : }
1541 : :
1542 [ - + ]: 4133 : if (spdk_json_decode_object(params, nvmf_rpc_subsystem_ns_decoder,
1543 : : SPDK_COUNTOF(nvmf_rpc_subsystem_ns_decoder),
1544 : : ctx)) {
1545 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
1546 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
1547 : 0 : nvmf_rpc_ns_ctx_free(ctx);
1548 : 0 : return;
1549 : : }
1550 : :
1551 : 4133 : ctx->request = request;
1552 : 4133 : ctx->response_sent = false;
1553 : :
1554 : 4133 : tgt = spdk_nvmf_get_tgt(ctx->tgt_name);
1555 [ - + ]: 4133 : if (!tgt) {
1556 : 0 : SPDK_ERRLOG("Unable to find a target object.\n");
1557 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1558 : : "Unable to find a target.");
1559 : 0 : nvmf_rpc_ns_ctx_free(ctx);
1560 : 0 : return;
1561 : : }
1562 : :
1563 : 4133 : subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx->nqn);
1564 [ - + ]: 4133 : if (!subsystem) {
1565 : 0 : SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn);
1566 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
1567 : 0 : nvmf_rpc_ns_ctx_free(ctx);
1568 : 0 : return;
1569 : : }
1570 : :
1571 : 4133 : rc = spdk_nvmf_subsystem_pause(subsystem, ctx->ns_params.nsid, nvmf_rpc_ns_paused, ctx);
1572 [ - + ]: 4133 : if (rc != 0) {
1573 [ # # ]: 0 : if (rc == -EBUSY) {
1574 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1575 : : "subsystem busy, retry later.\n");
1576 : : } else {
1577 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
1578 : : }
1579 : 0 : nvmf_rpc_ns_ctx_free(ctx);
1580 : : }
1581 : : }
1582 : 741 : SPDK_RPC_REGISTER("nvmf_subsystem_add_ns", rpc_nvmf_subsystem_add_ns, SPDK_RPC_RUNTIME)
1583 : :
1584 : : struct nvmf_rpc_remove_ns_ctx {
1585 : : char *nqn;
1586 : : char *tgt_name;
1587 : : uint32_t nsid;
1588 : :
1589 : : struct spdk_jsonrpc_request *request;
1590 : : bool response_sent;
1591 : : };
1592 : :
1593 : : static const struct spdk_json_object_decoder nvmf_rpc_subsystem_remove_ns_decoder[] = {
1594 : : {"nqn", offsetof(struct nvmf_rpc_remove_ns_ctx, nqn), spdk_json_decode_string},
1595 : : {"nsid", offsetof(struct nvmf_rpc_remove_ns_ctx, nsid), spdk_json_decode_uint32},
1596 : : {"tgt_name", offsetof(struct nvmf_rpc_remove_ns_ctx, tgt_name), spdk_json_decode_string, true},
1597 : : };
1598 : :
1599 : : static void
1600 : 2319 : nvmf_rpc_remove_ns_ctx_free(struct nvmf_rpc_remove_ns_ctx *ctx)
1601 : : {
1602 : 2319 : free(ctx->nqn);
1603 : 2319 : free(ctx->tgt_name);
1604 : 2319 : free(ctx);
1605 : 2319 : }
1606 : :
1607 : : static void
1608 : 2319 : nvmf_rpc_remove_ns_resumed(struct spdk_nvmf_subsystem *subsystem,
1609 : : void *cb_arg, int status)
1610 : : {
1611 : 2319 : struct nvmf_rpc_remove_ns_ctx *ctx = cb_arg;
1612 : 2319 : struct spdk_jsonrpc_request *request = ctx->request;
1613 [ - + ]: 2319 : bool response_sent = ctx->response_sent;
1614 : :
1615 : 2319 : nvmf_rpc_remove_ns_ctx_free(ctx);
1616 : :
1617 [ - + ]: 2319 : if (response_sent) {
1618 : 0 : return;
1619 : : }
1620 : :
1621 : 2319 : spdk_jsonrpc_send_bool_response(request, true);
1622 : : }
1623 : :
1624 : : static void
1625 : 2319 : nvmf_rpc_remove_ns_paused(struct spdk_nvmf_subsystem *subsystem,
1626 : : void *cb_arg, int status)
1627 : : {
1628 : 2319 : struct nvmf_rpc_remove_ns_ctx *ctx = cb_arg;
1629 : : int ret;
1630 : :
1631 : 2319 : ret = spdk_nvmf_subsystem_remove_ns(subsystem, ctx->nsid);
1632 [ - + ]: 2319 : if (ret < 0) {
1633 : 0 : SPDK_ERRLOG("Unable to remove namespace ID %u\n", ctx->nsid);
1634 : 0 : spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1635 : : "Invalid parameters");
1636 : 0 : ctx->response_sent = true;
1637 : : }
1638 : :
1639 [ - + ]: 2319 : if (spdk_nvmf_subsystem_resume(subsystem, nvmf_rpc_remove_ns_resumed, ctx)) {
1640 [ # # # # ]: 0 : if (!ctx->response_sent) {
1641 : 0 : spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
1642 : : }
1643 : 0 : nvmf_rpc_remove_ns_ctx_free(ctx);
1644 : : }
1645 : 2319 : }
1646 : :
1647 : : static void
1648 : 2319 : rpc_nvmf_subsystem_remove_ns(struct spdk_jsonrpc_request *request,
1649 : : const struct spdk_json_val *params)
1650 : : {
1651 : : struct nvmf_rpc_remove_ns_ctx *ctx;
1652 : : struct spdk_nvmf_subsystem *subsystem;
1653 : : struct spdk_nvmf_tgt *tgt;
1654 : : int rc;
1655 : :
1656 : 2319 : ctx = calloc(1, sizeof(*ctx));
1657 [ - + ]: 2319 : if (!ctx) {
1658 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory");
1659 : 0 : return;
1660 : : }
1661 : :
1662 [ - + ]: 2319 : if (spdk_json_decode_object(params, nvmf_rpc_subsystem_remove_ns_decoder,
1663 : : SPDK_COUNTOF(nvmf_rpc_subsystem_remove_ns_decoder),
1664 : : ctx)) {
1665 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
1666 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
1667 : 0 : nvmf_rpc_remove_ns_ctx_free(ctx);
1668 : 0 : return;
1669 : : }
1670 : :
1671 : 2319 : tgt = spdk_nvmf_get_tgt(ctx->tgt_name);
1672 [ - + ]: 2319 : if (!tgt) {
1673 : 0 : SPDK_ERRLOG("Unable to find a target object.\n");
1674 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1675 : : "Unable to find a target.");
1676 : 0 : nvmf_rpc_remove_ns_ctx_free(ctx);
1677 : 0 : return;
1678 : : }
1679 : :
1680 : 2319 : ctx->request = request;
1681 : 2319 : ctx->response_sent = false;
1682 : :
1683 : 2319 : subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx->nqn);
1684 [ - + ]: 2319 : if (!subsystem) {
1685 : 0 : SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn);
1686 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
1687 : 0 : nvmf_rpc_remove_ns_ctx_free(ctx);
1688 : 0 : return;
1689 : : }
1690 : :
1691 : 2319 : rc = spdk_nvmf_subsystem_pause(subsystem, ctx->nsid, nvmf_rpc_remove_ns_paused, ctx);
1692 [ - + ]: 2319 : if (rc != 0) {
1693 [ # # ]: 0 : if (rc == -EBUSY) {
1694 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1695 : : "subsystem busy, retry later.\n");
1696 : : } else {
1697 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
1698 : : }
1699 : 0 : nvmf_rpc_remove_ns_ctx_free(ctx);
1700 : : }
1701 : : }
1702 : 741 : SPDK_RPC_REGISTER("nvmf_subsystem_remove_ns", rpc_nvmf_subsystem_remove_ns, SPDK_RPC_RUNTIME)
1703 : :
1704 : : struct nvmf_rpc_host_ctx {
1705 : : struct spdk_jsonrpc_request *request;
1706 : : char *nqn;
1707 : : char *host;
1708 : : char *tgt_name;
1709 : : bool allow_any_host;
1710 : : };
1711 : :
1712 : : static const struct spdk_json_object_decoder nvmf_rpc_subsystem_host_decoder[] = {
1713 : : {"nqn", offsetof(struct nvmf_rpc_host_ctx, nqn), spdk_json_decode_string},
1714 : : {"host", offsetof(struct nvmf_rpc_host_ctx, host), spdk_json_decode_string},
1715 : : {"tgt_name", offsetof(struct nvmf_rpc_host_ctx, tgt_name), spdk_json_decode_string, true},
1716 : : };
1717 : :
1718 : : static void
1719 : 112 : nvmf_rpc_host_ctx_free(struct nvmf_rpc_host_ctx *ctx)
1720 : : {
1721 : 112 : free(ctx->nqn);
1722 : 112 : free(ctx->host);
1723 : 112 : free(ctx->tgt_name);
1724 : 112 : }
1725 : :
1726 : : static void
1727 : 51 : rpc_nvmf_subsystem_add_host(struct spdk_jsonrpc_request *request,
1728 : : const struct spdk_json_val *params)
1729 : : {
1730 : 51 : struct nvmf_rpc_host_ctx ctx = {};
1731 : : struct spdk_nvmf_subsystem *subsystem;
1732 : : struct spdk_nvmf_tgt *tgt;
1733 : : int rc;
1734 : :
1735 [ - + ]: 51 : if (spdk_json_decode_object_relaxed(params, nvmf_rpc_subsystem_host_decoder,
1736 : : SPDK_COUNTOF(nvmf_rpc_subsystem_host_decoder),
1737 : : &ctx)) {
1738 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
1739 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
1740 : 0 : nvmf_rpc_host_ctx_free(&ctx);
1741 : 3 : return;
1742 : : }
1743 : :
1744 : 51 : tgt = spdk_nvmf_get_tgt(ctx.tgt_name);
1745 [ - + ]: 51 : if (!tgt) {
1746 : 0 : SPDK_ERRLOG("Unable to find a target object.\n");
1747 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1748 : : "Unable to find a target.");
1749 : 0 : nvmf_rpc_host_ctx_free(&ctx);
1750 : 0 : return;
1751 : : }
1752 : :
1753 : 51 : subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx.nqn);
1754 [ - + ]: 51 : if (!subsystem) {
1755 : 0 : SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx.nqn);
1756 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
1757 : 0 : nvmf_rpc_host_ctx_free(&ctx);
1758 : 0 : return;
1759 : : }
1760 : :
1761 : 51 : rc = spdk_nvmf_subsystem_add_host(subsystem, ctx.host, params);
1762 [ + + ]: 51 : if (rc != 0) {
1763 : 3 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
1764 : 3 : nvmf_rpc_host_ctx_free(&ctx);
1765 : 3 : return;
1766 : : }
1767 : :
1768 : 48 : spdk_jsonrpc_send_bool_response(request, true);
1769 : 48 : nvmf_rpc_host_ctx_free(&ctx);
1770 : : }
1771 : 741 : SPDK_RPC_REGISTER("nvmf_subsystem_add_host", rpc_nvmf_subsystem_add_host, SPDK_RPC_RUNTIME)
1772 : :
1773 : : static void
1774 : 16 : rpc_nvmf_subsystem_remove_host_done(void *_ctx, int status)
1775 : : {
1776 : 16 : struct nvmf_rpc_host_ctx *ctx = _ctx;
1777 : :
1778 : 16 : spdk_jsonrpc_send_bool_response(ctx->request, true);
1779 : 16 : nvmf_rpc_host_ctx_free(ctx);
1780 : 16 : free(ctx);
1781 : 16 : }
1782 : :
1783 : : static void
1784 : 16 : rpc_nvmf_subsystem_remove_host(struct spdk_jsonrpc_request *request,
1785 : : const struct spdk_json_val *params)
1786 : : {
1787 : : struct nvmf_rpc_host_ctx *ctx;
1788 : : struct spdk_nvmf_subsystem *subsystem;
1789 : : struct spdk_nvmf_tgt *tgt;
1790 : : int rc;
1791 : :
1792 : 16 : ctx = calloc(1, sizeof(*ctx));
1793 [ - + ]: 16 : if (ctx == NULL) {
1794 : 0 : SPDK_ERRLOG("Unable to allocate context to perform RPC\n");
1795 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory");
1796 : 0 : return;
1797 : : }
1798 : :
1799 : 16 : ctx->request = request;
1800 : :
1801 [ - + ]: 16 : if (spdk_json_decode_object(params, nvmf_rpc_subsystem_host_decoder,
1802 : : SPDK_COUNTOF(nvmf_rpc_subsystem_host_decoder),
1803 : : ctx)) {
1804 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
1805 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
1806 : 0 : nvmf_rpc_host_ctx_free(ctx);
1807 : 0 : free(ctx);
1808 : 0 : return;
1809 : : }
1810 : :
1811 : 16 : tgt = spdk_nvmf_get_tgt(ctx->tgt_name);
1812 [ - + ]: 16 : if (!tgt) {
1813 : 0 : SPDK_ERRLOG("Unable to find a target object.\n");
1814 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1815 : : "Unable to find a target.");
1816 : 0 : nvmf_rpc_host_ctx_free(ctx);
1817 : 0 : free(ctx);
1818 : 0 : return;
1819 : : }
1820 : :
1821 : 16 : subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx->nqn);
1822 [ - + ]: 16 : if (!subsystem) {
1823 : 0 : SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn);
1824 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
1825 : 0 : nvmf_rpc_host_ctx_free(ctx);
1826 : 0 : free(ctx);
1827 : 0 : return;
1828 : : }
1829 : :
1830 : 16 : rc = spdk_nvmf_subsystem_remove_host(subsystem, ctx->host);
1831 [ - + ]: 16 : if (rc != 0) {
1832 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
1833 : 0 : nvmf_rpc_host_ctx_free(ctx);
1834 : 0 : free(ctx);
1835 : 0 : return;
1836 : : }
1837 : :
1838 : 16 : rc = spdk_nvmf_subsystem_disconnect_host(subsystem, ctx->host,
1839 : : rpc_nvmf_subsystem_remove_host_done,
1840 : : ctx);
1841 [ - + ]: 16 : if (rc != 0) {
1842 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
1843 : 0 : nvmf_rpc_host_ctx_free(ctx);
1844 : 0 : free(ctx);
1845 : 0 : return;
1846 : : }
1847 : : }
1848 : 741 : SPDK_RPC_REGISTER("nvmf_subsystem_remove_host", rpc_nvmf_subsystem_remove_host,
1849 : : SPDK_RPC_RUNTIME)
1850 : :
1851 : :
1852 : : static const struct spdk_json_object_decoder nvmf_rpc_subsystem_any_host_decoder[] = {
1853 : : {"nqn", offsetof(struct nvmf_rpc_host_ctx, nqn), spdk_json_decode_string},
1854 : : {"allow_any_host", offsetof(struct nvmf_rpc_host_ctx, allow_any_host), spdk_json_decode_bool},
1855 : : {"tgt_name", offsetof(struct nvmf_rpc_host_ctx, tgt_name), spdk_json_decode_string, true},
1856 : : };
1857 : :
1858 : : static void
1859 : 45 : rpc_nvmf_subsystem_allow_any_host(struct spdk_jsonrpc_request *request,
1860 : : const struct spdk_json_val *params)
1861 : : {
1862 : 45 : struct nvmf_rpc_host_ctx ctx = {};
1863 : : struct spdk_nvmf_subsystem *subsystem;
1864 : : struct spdk_nvmf_tgt *tgt;
1865 : : int rc;
1866 : :
1867 [ - + ]: 45 : if (spdk_json_decode_object(params, nvmf_rpc_subsystem_any_host_decoder,
1868 : : SPDK_COUNTOF(nvmf_rpc_subsystem_any_host_decoder),
1869 : : &ctx)) {
1870 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
1871 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
1872 : 0 : nvmf_rpc_host_ctx_free(&ctx);
1873 : 0 : return;
1874 : : }
1875 : :
1876 : 45 : tgt = spdk_nvmf_get_tgt(ctx.tgt_name);
1877 [ - + ]: 45 : if (!tgt) {
1878 : 0 : SPDK_ERRLOG("Unable to find a target object.\n");
1879 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1880 : : "Unable to find a target.");
1881 : 0 : nvmf_rpc_host_ctx_free(&ctx);
1882 : 0 : return;
1883 : : }
1884 : :
1885 : 45 : subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx.nqn);
1886 [ - + ]: 45 : if (!subsystem) {
1887 : 0 : SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx.nqn);
1888 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
1889 : 0 : nvmf_rpc_host_ctx_free(&ctx);
1890 : 0 : return;
1891 : : }
1892 : :
1893 [ - + ]: 45 : rc = spdk_nvmf_subsystem_set_allow_any_host(subsystem, ctx.allow_any_host);
1894 [ - + ]: 45 : if (rc != 0) {
1895 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
1896 : 0 : nvmf_rpc_host_ctx_free(&ctx);
1897 : 0 : return;
1898 : : }
1899 : :
1900 : 45 : spdk_jsonrpc_send_bool_response(request, true);
1901 : 45 : nvmf_rpc_host_ctx_free(&ctx);
1902 : : }
1903 : 741 : SPDK_RPC_REGISTER("nvmf_subsystem_allow_any_host", rpc_nvmf_subsystem_allow_any_host,
1904 : : SPDK_RPC_RUNTIME)
1905 : :
1906 : : struct nvmf_rpc_target_ctx {
1907 : : char *name;
1908 : : uint32_t max_subsystems;
1909 : : char *discovery_filter;
1910 : : };
1911 : :
1912 : : static int
1913 : 6 : decode_discovery_filter(const struct spdk_json_val *val, void *out)
1914 : : {
1915 : 6 : enum spdk_nvmf_tgt_discovery_filter *_filter = (enum spdk_nvmf_tgt_discovery_filter *)out;
1916 : 6 : enum spdk_nvmf_tgt_discovery_filter filter = SPDK_NVMF_TGT_DISCOVERY_MATCH_ANY;
1917 : 6 : char *tokens = spdk_json_strdup(val);
1918 : : char *tok;
1919 : 6 : int rc = -EINVAL;
1920 : 6 : bool all_specified = false;
1921 : :
1922 [ - + ]: 6 : if (!tokens) {
1923 : 0 : return -ENOMEM;
1924 : : }
1925 : :
1926 : 6 : tok = strtok(tokens, ",");
1927 [ + + ]: 12 : while (tok) {
1928 [ - + + - ]: 6 : if (strncmp(tok, "match_any", 9) == 0) {
1929 [ - + ]: 6 : if (filter != SPDK_NVMF_TGT_DISCOVERY_MATCH_ANY) {
1930 : 0 : goto out;
1931 : : }
1932 : 6 : filter = SPDK_NVMF_TGT_DISCOVERY_MATCH_ANY;
1933 : 6 : all_specified = true;
1934 : : } else {
1935 [ # # ]: 0 : if (all_specified) {
1936 : 0 : goto out;
1937 : : }
1938 [ # # # # ]: 0 : if (strncmp(tok, "transport", 9) == 0) {
1939 : 0 : filter |= SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_TYPE;
1940 [ # # # # ]: 0 : } else if (strncmp(tok, "address", 7) == 0) {
1941 : 0 : filter |= SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_ADDRESS;
1942 [ # # # # ]: 0 : } else if (strncmp(tok, "svcid", 5) == 0) {
1943 : 0 : filter |= SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_SVCID;
1944 : : } else {
1945 : 0 : SPDK_ERRLOG("Invalid value %s\n", tok);
1946 : 0 : goto out;
1947 : : }
1948 : : }
1949 : :
1950 : 6 : tok = strtok(NULL, ",");
1951 : : }
1952 : :
1953 : 6 : rc = 0;
1954 : 6 : *_filter = filter;
1955 : :
1956 : 6 : out:
1957 : 6 : free(tokens);
1958 : :
1959 : 6 : return rc;
1960 : : }
1961 : :
1962 : : static const struct spdk_json_object_decoder nvmf_rpc_create_target_decoder[] = {
1963 : : {"name", offsetof(struct nvmf_rpc_target_ctx, name), spdk_json_decode_string},
1964 : : {"max_subsystems", offsetof(struct nvmf_rpc_target_ctx, max_subsystems), spdk_json_decode_uint32, true},
1965 : : {"discovery_filter", offsetof(struct nvmf_rpc_target_ctx, discovery_filter), decode_discovery_filter, true}
1966 : : };
1967 : :
1968 : : static void
1969 : 6 : rpc_nvmf_create_target(struct spdk_jsonrpc_request *request,
1970 : : const struct spdk_json_val *params)
1971 : : {
1972 : 0 : struct spdk_nvmf_target_opts opts;
1973 : 6 : struct nvmf_rpc_target_ctx ctx = {0};
1974 : : struct spdk_nvmf_tgt *tgt;
1975 : : struct spdk_json_write_ctx *w;
1976 : :
1977 : : /* Decode parameters the first time to get the transport type */
1978 [ - + ]: 6 : if (spdk_json_decode_object(params, nvmf_rpc_create_target_decoder,
1979 : : SPDK_COUNTOF(nvmf_rpc_create_target_decoder),
1980 : : &ctx)) {
1981 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
1982 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
1983 : 0 : goto out;
1984 : : }
1985 : :
1986 [ - + ]: 6 : snprintf(opts.name, NVMF_TGT_NAME_MAX_LENGTH, "%s", ctx.name);
1987 : 6 : opts.max_subsystems = ctx.max_subsystems;
1988 : :
1989 [ - + ]: 6 : if (spdk_nvmf_get_tgt(opts.name) != NULL) {
1990 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1991 : : "Target already exists.");
1992 : 0 : goto out;
1993 : : }
1994 : :
1995 : 6 : tgt = spdk_nvmf_tgt_create(&opts);
1996 : :
1997 [ - + ]: 6 : if (tgt == NULL) {
1998 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1999 : : "Unable to create the requested target.");
2000 : 0 : goto out;
2001 : : }
2002 : :
2003 : 6 : w = spdk_jsonrpc_begin_result(request);
2004 : 6 : spdk_json_write_string(w, spdk_nvmf_tgt_get_name(tgt));
2005 : 6 : spdk_jsonrpc_end_result(request, w);
2006 : 6 : out:
2007 : 6 : free(ctx.name);
2008 : 6 : free(ctx.discovery_filter);
2009 : 6 : }
2010 : 741 : /* private */ SPDK_RPC_REGISTER("nvmf_create_target", rpc_nvmf_create_target, SPDK_RPC_RUNTIME);
2011 : :
2012 : : static const struct spdk_json_object_decoder nvmf_rpc_destroy_target_decoder[] = {
2013 : : {"name", offsetof(struct nvmf_rpc_target_ctx, name), spdk_json_decode_string},
2014 : : };
2015 : :
2016 : : static void
2017 : 6 : nvmf_rpc_destroy_target_done(void *ctx, int status)
2018 : : {
2019 : 6 : struct spdk_jsonrpc_request *request = ctx;
2020 : :
2021 : 6 : spdk_jsonrpc_send_bool_response(request, true);
2022 : 6 : }
2023 : :
2024 : : static void
2025 : 9 : rpc_nvmf_delete_target(struct spdk_jsonrpc_request *request,
2026 : : const struct spdk_json_val *params)
2027 : : {
2028 : 9 : struct nvmf_rpc_target_ctx ctx = {0};
2029 : : struct spdk_nvmf_tgt *tgt;
2030 : :
2031 : : /* Decode parameters the first time to get the transport type */
2032 [ - + ]: 9 : if (spdk_json_decode_object(params, nvmf_rpc_destroy_target_decoder,
2033 : : SPDK_COUNTOF(nvmf_rpc_destroy_target_decoder),
2034 : : &ctx)) {
2035 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
2036 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
2037 : 0 : free(ctx.name);
2038 : 3 : return;
2039 : : }
2040 : :
2041 : 9 : tgt = spdk_nvmf_get_tgt(ctx.name);
2042 : :
2043 [ + + ]: 9 : if (tgt == NULL) {
2044 : 3 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
2045 : : "The specified target doesn't exist, cannot delete it.");
2046 : 3 : free(ctx.name);
2047 : 3 : return;
2048 : : }
2049 : :
2050 : 6 : spdk_nvmf_tgt_destroy(tgt, nvmf_rpc_destroy_target_done, request);
2051 : 6 : free(ctx.name);
2052 : : }
2053 : 741 : /* private */ SPDK_RPC_REGISTER("nvmf_delete_target", rpc_nvmf_delete_target, SPDK_RPC_RUNTIME);
2054 : :
2055 : : static void
2056 : 9 : rpc_nvmf_get_targets(struct spdk_jsonrpc_request *request,
2057 : : const struct spdk_json_val *params)
2058 : : {
2059 : : struct spdk_json_write_ctx *w;
2060 : : struct spdk_nvmf_tgt *tgt;
2061 : : const char *name;
2062 : :
2063 [ - + ]: 9 : if (params != NULL) {
2064 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
2065 : : "nvmf_get_targets has no parameters.");
2066 : 0 : return;
2067 : : }
2068 : :
2069 : 9 : w = spdk_jsonrpc_begin_result(request);
2070 : 9 : spdk_json_write_array_begin(w);
2071 : :
2072 : 9 : tgt = spdk_nvmf_get_first_tgt();
2073 : :
2074 [ + + ]: 24 : while (tgt != NULL) {
2075 : 15 : name = spdk_nvmf_tgt_get_name(tgt);
2076 : 15 : spdk_json_write_string(w, name);
2077 : 15 : tgt = spdk_nvmf_get_next_tgt(tgt);
2078 : : }
2079 : :
2080 : 9 : spdk_json_write_array_end(w);
2081 : 9 : spdk_jsonrpc_end_result(request, w);
2082 : : }
2083 : 741 : /* private */ SPDK_RPC_REGISTER("nvmf_get_targets", rpc_nvmf_get_targets, SPDK_RPC_RUNTIME);
2084 : :
2085 : : struct nvmf_rpc_create_transport_ctx {
2086 : : char *trtype;
2087 : : char *tgt_name;
2088 : : struct spdk_nvmf_transport_opts opts;
2089 : : struct spdk_jsonrpc_request *request;
2090 : : struct spdk_nvmf_transport *transport;
2091 : : int status;
2092 : : };
2093 : :
2094 : : /**
2095 : : * `max_qpairs_per_ctrlr` represents both admin and IO qpairs, that confuses
2096 : : * users when they configure a transport using RPC. So it was decided to
2097 : : * deprecate `max_qpairs_per_ctrlr` RPC parameter and use `max_io_qpairs_per_ctrlr`
2098 : : * But internal logic remains unchanged and SPDK expects that
2099 : : * spdk_nvmf_transport_opts::max_qpairs_per_ctrlr includes an admin qpair.
2100 : : * This function parses the number of IO qpairs and adds +1 for admin qpair.
2101 : : */
2102 : : static int
2103 : 22 : nvmf_rpc_decode_max_io_qpairs(const struct spdk_json_val *val, void *out)
2104 : : {
2105 : 22 : uint16_t *i = out;
2106 : : int rc;
2107 : :
2108 : 22 : rc = spdk_json_number_to_uint16(val, i);
2109 [ + - ]: 22 : if (rc == 0) {
2110 : 22 : (*i)++;
2111 : : }
2112 : :
2113 : 22 : return rc;
2114 : : }
2115 : :
2116 : : static const struct spdk_json_object_decoder nvmf_rpc_create_transport_decoder[] = {
2117 : : { "trtype", offsetof(struct nvmf_rpc_create_transport_ctx, trtype), spdk_json_decode_string},
2118 : : {
2119 : : "max_queue_depth", offsetof(struct nvmf_rpc_create_transport_ctx, opts.max_queue_depth),
2120 : : spdk_json_decode_uint16, true
2121 : : },
2122 : : {
2123 : : "max_io_qpairs_per_ctrlr", offsetof(struct nvmf_rpc_create_transport_ctx, opts.max_qpairs_per_ctrlr),
2124 : : nvmf_rpc_decode_max_io_qpairs, true
2125 : : },
2126 : : {
2127 : : "in_capsule_data_size", offsetof(struct nvmf_rpc_create_transport_ctx, opts.in_capsule_data_size),
2128 : : spdk_json_decode_uint32, true
2129 : : },
2130 : : {
2131 : : "max_io_size", offsetof(struct nvmf_rpc_create_transport_ctx, opts.max_io_size),
2132 : : spdk_json_decode_uint32, true
2133 : : },
2134 : : {
2135 : : "io_unit_size", offsetof(struct nvmf_rpc_create_transport_ctx, opts.io_unit_size),
2136 : : spdk_json_decode_uint32, true
2137 : : },
2138 : : {
2139 : : "max_aq_depth", offsetof(struct nvmf_rpc_create_transport_ctx, opts.max_aq_depth),
2140 : : spdk_json_decode_uint32, true
2141 : : },
2142 : : {
2143 : : "num_shared_buffers", offsetof(struct nvmf_rpc_create_transport_ctx, opts.num_shared_buffers),
2144 : : spdk_json_decode_uint32, true
2145 : : },
2146 : : {
2147 : : "buf_cache_size", offsetof(struct nvmf_rpc_create_transport_ctx, opts.buf_cache_size),
2148 : : spdk_json_decode_uint32, true
2149 : : },
2150 : : {
2151 : : "dif_insert_or_strip", offsetof(struct nvmf_rpc_create_transport_ctx, opts.dif_insert_or_strip),
2152 : : spdk_json_decode_bool, true
2153 : : },
2154 : : {
2155 : : "abort_timeout_sec", offsetof(struct nvmf_rpc_create_transport_ctx, opts.abort_timeout_sec),
2156 : : spdk_json_decode_uint32, true
2157 : : },
2158 : : {
2159 : : "zcopy", offsetof(struct nvmf_rpc_create_transport_ctx, opts.zcopy),
2160 : : spdk_json_decode_bool, true
2161 : : },
2162 : : {
2163 : : "tgt_name", offsetof(struct nvmf_rpc_create_transport_ctx, tgt_name),
2164 : : spdk_json_decode_string, true
2165 : : },
2166 : : {
2167 : : "acceptor_poll_rate", offsetof(struct nvmf_rpc_create_transport_ctx, opts.acceptor_poll_rate),
2168 : : spdk_json_decode_uint32, true
2169 : : },
2170 : : };
2171 : :
2172 : : static void
2173 : 202 : nvmf_rpc_create_transport_ctx_free(struct nvmf_rpc_create_transport_ctx *ctx)
2174 : : {
2175 : 202 : free(ctx->trtype);
2176 : 202 : free(ctx->tgt_name);
2177 : 202 : free(ctx);
2178 : 202 : }
2179 : :
2180 : : static void
2181 : 0 : nvmf_rpc_transport_destroy_done_cb(void *cb_arg)
2182 : : {
2183 : 0 : struct nvmf_rpc_create_transport_ctx *ctx = cb_arg;
2184 : :
2185 : 0 : spdk_jsonrpc_send_error_response_fmt(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
2186 : : "Failed to add transport to tgt.(%d)", ctx->status);
2187 : 0 : nvmf_rpc_create_transport_ctx_free(ctx);
2188 : 0 : }
2189 : :
2190 : : static void
2191 : 202 : nvmf_rpc_tgt_add_transport_done(void *cb_arg, int status)
2192 : : {
2193 : 202 : struct nvmf_rpc_create_transport_ctx *ctx = cb_arg;
2194 : :
2195 [ - + ]: 202 : if (status) {
2196 : 0 : SPDK_ERRLOG("Failed to add transport to tgt.(%d)\n", status);
2197 : 0 : ctx->status = status;
2198 : 0 : spdk_nvmf_transport_destroy(ctx->transport, nvmf_rpc_transport_destroy_done_cb, ctx);
2199 : 0 : return;
2200 : : }
2201 : :
2202 : 202 : spdk_jsonrpc_send_bool_response(ctx->request, true);
2203 : 202 : nvmf_rpc_create_transport_ctx_free(ctx);
2204 : : }
2205 : :
2206 : : static void
2207 : 202 : nvmf_rpc_create_transport_done(void *cb_arg, struct spdk_nvmf_transport *transport)
2208 : : {
2209 : 202 : struct nvmf_rpc_create_transport_ctx *ctx = cb_arg;
2210 : :
2211 [ - + ]: 202 : if (!transport) {
2212 : 0 : SPDK_ERRLOG("Failed to create transport.\n");
2213 : 0 : spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
2214 : : "Failed to create transport.");
2215 : 0 : nvmf_rpc_create_transport_ctx_free(ctx);
2216 : 0 : return;
2217 : : }
2218 : :
2219 : 202 : ctx->transport = transport;
2220 : :
2221 : 202 : spdk_nvmf_tgt_add_transport(spdk_nvmf_get_tgt(ctx->tgt_name), transport,
2222 : : nvmf_rpc_tgt_add_transport_done, ctx);
2223 : : }
2224 : :
2225 : : static void
2226 : 202 : rpc_nvmf_create_transport(struct spdk_jsonrpc_request *request,
2227 : : const struct spdk_json_val *params)
2228 : : {
2229 : : struct nvmf_rpc_create_transport_ctx *ctx;
2230 : : struct spdk_nvmf_tgt *tgt;
2231 : : int rc;
2232 : :
2233 : 202 : ctx = calloc(1, sizeof(*ctx));
2234 [ - + ]: 202 : if (!ctx) {
2235 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory");
2236 : 0 : return;
2237 : : }
2238 : :
2239 : : /* Decode parameters the first time to get the transport type */
2240 [ - + ]: 202 : if (spdk_json_decode_object_relaxed(params, nvmf_rpc_create_transport_decoder,
2241 : : SPDK_COUNTOF(nvmf_rpc_create_transport_decoder),
2242 : : ctx)) {
2243 : 0 : SPDK_ERRLOG("spdk_json_decode_object_relaxed failed\n");
2244 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
2245 : 0 : nvmf_rpc_create_transport_ctx_free(ctx);
2246 : 0 : return;
2247 : : }
2248 : :
2249 : 202 : tgt = spdk_nvmf_get_tgt(ctx->tgt_name);
2250 [ - + ]: 202 : if (!tgt) {
2251 : 0 : SPDK_ERRLOG("Unable to find a target object.\n");
2252 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
2253 : : "Unable to find a target.");
2254 : 0 : nvmf_rpc_create_transport_ctx_free(ctx);
2255 : 0 : return;
2256 : : }
2257 : :
2258 : : /* Initialize all the transport options (based on transport type) and decode the
2259 : : * parameters again to update any options passed in rpc create transport call.
2260 : : */
2261 [ - + ]: 202 : if (!spdk_nvmf_transport_opts_init(ctx->trtype, &ctx->opts, sizeof(ctx->opts))) {
2262 : : /* This can happen if user specifies PCIE transport type which isn't valid for
2263 : : * NVMe-oF.
2264 : : */
2265 : 0 : SPDK_ERRLOG("Invalid transport type '%s'\n", ctx->trtype);
2266 : 0 : spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
2267 : : "Invalid transport type '%s'", ctx->trtype);
2268 : 0 : nvmf_rpc_create_transport_ctx_free(ctx);
2269 : 0 : return;
2270 : : }
2271 : :
2272 [ - + ]: 202 : if (spdk_json_decode_object_relaxed(params, nvmf_rpc_create_transport_decoder,
2273 : : SPDK_COUNTOF(nvmf_rpc_create_transport_decoder),
2274 : : ctx)) {
2275 : 0 : SPDK_ERRLOG("spdk_json_decode_object_relaxed failed\n");
2276 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
2277 : 0 : nvmf_rpc_create_transport_ctx_free(ctx);
2278 : 0 : return;
2279 : : }
2280 : :
2281 [ - + ]: 202 : if (spdk_nvmf_tgt_get_transport(tgt, ctx->trtype)) {
2282 : 0 : SPDK_ERRLOG("Transport type '%s' already exists\n", ctx->trtype);
2283 : 0 : spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
2284 : : "Transport type '%s' already exists", ctx->trtype);
2285 : 0 : nvmf_rpc_create_transport_ctx_free(ctx);
2286 : 0 : return;
2287 : : }
2288 : :
2289 : : /* Transport can parse additional params themselves */
2290 : 202 : ctx->opts.transport_specific = params;
2291 : 202 : ctx->request = request;
2292 : :
2293 : 202 : rc = spdk_nvmf_transport_create_async(ctx->trtype, &ctx->opts, nvmf_rpc_create_transport_done, ctx);
2294 [ - + ]: 202 : if (rc) {
2295 : 0 : SPDK_ERRLOG("Transport type '%s' create failed\n", ctx->trtype);
2296 : 0 : spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
2297 : : "Transport type '%s' create failed", ctx->trtype);
2298 : 0 : nvmf_rpc_create_transport_ctx_free(ctx);
2299 : : }
2300 : : }
2301 : 741 : SPDK_RPC_REGISTER("nvmf_create_transport", rpc_nvmf_create_transport, SPDK_RPC_RUNTIME)
2302 : :
2303 : : struct rpc_get_transport {
2304 : : char *trtype;
2305 : : char *tgt_name;
2306 : : };
2307 : :
2308 : : static const struct spdk_json_object_decoder rpc_get_transport_decoders[] = {
2309 : : {"trtype", offsetof(struct rpc_get_transport, trtype), spdk_json_decode_string, true},
2310 : : {"tgt_name", offsetof(struct rpc_get_transport, tgt_name), spdk_json_decode_string, true},
2311 : : };
2312 : :
2313 : : static void
2314 : 190 : rpc_nvmf_get_transports(struct spdk_jsonrpc_request *request,
2315 : : const struct spdk_json_val *params)
2316 : : {
2317 : 190 : struct rpc_get_transport req = { 0 };
2318 : : struct spdk_json_write_ctx *w;
2319 : 190 : struct spdk_nvmf_transport *transport = NULL;
2320 : : struct spdk_nvmf_tgt *tgt;
2321 : :
2322 [ + + ]: 190 : if (params) {
2323 [ - + ]: 2 : if (spdk_json_decode_object(params, rpc_get_transport_decoders,
2324 : : SPDK_COUNTOF(rpc_get_transport_decoders),
2325 : : &req)) {
2326 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
2327 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
2328 : 0 : return;
2329 : : }
2330 : : }
2331 : :
2332 : 190 : tgt = spdk_nvmf_get_tgt(req.tgt_name);
2333 [ - + ]: 190 : if (!tgt) {
2334 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
2335 : : "Unable to find a target.");
2336 : 0 : free(req.trtype);
2337 : 0 : free(req.tgt_name);
2338 : 0 : return;
2339 : : }
2340 : :
2341 [ + + ]: 190 : if (req.trtype) {
2342 : 2 : transport = spdk_nvmf_tgt_get_transport(tgt, req.trtype);
2343 [ - + ]: 2 : if (transport == NULL) {
2344 : 0 : SPDK_ERRLOG("transport '%s' does not exist\n", req.trtype);
2345 : 0 : spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
2346 : 0 : free(req.trtype);
2347 : 0 : free(req.tgt_name);
2348 : 0 : return;
2349 : : }
2350 : : }
2351 : :
2352 : 190 : w = spdk_jsonrpc_begin_result(request);
2353 : 190 : spdk_json_write_array_begin(w);
2354 : :
2355 [ + + ]: 190 : if (transport) {
2356 : 2 : nvmf_transport_dump_opts(transport, w, false);
2357 : : } else {
2358 [ + + ]: 306 : for (transport = spdk_nvmf_transport_get_first(tgt); transport != NULL;
2359 : 118 : transport = spdk_nvmf_transport_get_next(transport)) {
2360 : 118 : nvmf_transport_dump_opts(transport, w, false);
2361 : : }
2362 : : }
2363 : :
2364 : 190 : spdk_json_write_array_end(w);
2365 : 190 : spdk_jsonrpc_end_result(request, w);
2366 : 190 : free(req.trtype);
2367 : 190 : free(req.tgt_name);
2368 : : }
2369 : 741 : SPDK_RPC_REGISTER("nvmf_get_transports", rpc_nvmf_get_transports, SPDK_RPC_RUNTIME)
2370 : :
2371 : : struct rpc_nvmf_get_stats_ctx {
2372 : : char *tgt_name;
2373 : : struct spdk_nvmf_tgt *tgt;
2374 : : struct spdk_jsonrpc_request *request;
2375 : : struct spdk_json_write_ctx *w;
2376 : : };
2377 : :
2378 : : static const struct spdk_json_object_decoder rpc_get_stats_decoders[] = {
2379 : : {"tgt_name", offsetof(struct rpc_nvmf_get_stats_ctx, tgt_name), spdk_json_decode_string, true},
2380 : : };
2381 : :
2382 : : static void
2383 : 11 : free_get_stats_ctx(struct rpc_nvmf_get_stats_ctx *ctx)
2384 : : {
2385 : 11 : free(ctx->tgt_name);
2386 : 11 : free(ctx);
2387 : 11 : }
2388 : :
2389 : : static void
2390 : 11 : rpc_nvmf_get_stats_done(struct spdk_io_channel_iter *i, int status)
2391 : : {
2392 : 11 : struct rpc_nvmf_get_stats_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
2393 : :
2394 : 11 : spdk_json_write_array_end(ctx->w);
2395 : 11 : spdk_json_write_object_end(ctx->w);
2396 : 11 : spdk_jsonrpc_end_result(ctx->request, ctx->w);
2397 : 11 : free_get_stats_ctx(ctx);
2398 : 11 : }
2399 : :
2400 : : static void
2401 : 44 : _rpc_nvmf_get_stats(struct spdk_io_channel_iter *i)
2402 : : {
2403 : 44 : struct rpc_nvmf_get_stats_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
2404 : : struct spdk_io_channel *ch;
2405 : : struct spdk_nvmf_poll_group *group;
2406 : :
2407 : 44 : ch = spdk_get_io_channel(ctx->tgt);
2408 : 44 : group = spdk_io_channel_get_ctx(ch);
2409 : :
2410 : 44 : spdk_nvmf_poll_group_dump_stat(group, ctx->w);
2411 : :
2412 : 44 : spdk_put_io_channel(ch);
2413 : 44 : spdk_for_each_channel_continue(i, 0);
2414 : 44 : }
2415 : :
2416 : :
2417 : : static void
2418 : 11 : rpc_nvmf_get_stats(struct spdk_jsonrpc_request *request,
2419 : : const struct spdk_json_val *params)
2420 : : {
2421 : : struct rpc_nvmf_get_stats_ctx *ctx;
2422 : :
2423 : 11 : ctx = calloc(1, sizeof(*ctx));
2424 [ - + ]: 11 : if (!ctx) {
2425 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
2426 : : "Memory allocation error");
2427 : 0 : return;
2428 : : }
2429 : 11 : ctx->request = request;
2430 : :
2431 [ - + ]: 11 : if (params) {
2432 [ # # ]: 0 : if (spdk_json_decode_object(params, rpc_get_stats_decoders,
2433 : : SPDK_COUNTOF(rpc_get_stats_decoders),
2434 : : ctx)) {
2435 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
2436 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
2437 : 0 : free_get_stats_ctx(ctx);
2438 : 0 : return;
2439 : : }
2440 : : }
2441 : :
2442 : 11 : ctx->tgt = spdk_nvmf_get_tgt(ctx->tgt_name);
2443 [ - + ]: 11 : if (!ctx->tgt) {
2444 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
2445 : : "Unable to find a target.");
2446 : 0 : free_get_stats_ctx(ctx);
2447 : 0 : return;
2448 : : }
2449 : :
2450 : 11 : ctx->w = spdk_jsonrpc_begin_result(ctx->request);
2451 : 11 : spdk_json_write_object_begin(ctx->w);
2452 : 11 : spdk_json_write_named_uint64(ctx->w, "tick_rate", spdk_get_ticks_hz());
2453 : 11 : spdk_json_write_named_array_begin(ctx->w, "poll_groups");
2454 : :
2455 : 11 : spdk_for_each_channel(ctx->tgt,
2456 : : _rpc_nvmf_get_stats,
2457 : : ctx,
2458 : : rpc_nvmf_get_stats_done);
2459 : : }
2460 : :
2461 : 741 : SPDK_RPC_REGISTER("nvmf_get_stats", rpc_nvmf_get_stats, SPDK_RPC_RUNTIME)
2462 : :
2463 : : static void
2464 : 0 : dump_nvmf_ctrlr(struct spdk_json_write_ctx *w, struct spdk_nvmf_ctrlr *ctrlr)
2465 : : {
2466 : : uint32_t count;
2467 : :
2468 : 0 : spdk_json_write_object_begin(w);
2469 : :
2470 : 0 : spdk_json_write_named_uint32(w, "cntlid", ctrlr->cntlid);
2471 : 0 : spdk_json_write_named_string(w, "hostnqn", ctrlr->hostnqn);
2472 : 0 : spdk_json_write_named_uuid(w, "hostid", &ctrlr->hostid);
2473 : :
2474 : 0 : count = spdk_bit_array_count_set(ctrlr->qpair_mask);
2475 : 0 : spdk_json_write_named_uint32(w, "num_io_qpairs", count);
2476 : :
2477 : 0 : spdk_json_write_object_end(w);
2478 : 0 : }
2479 : :
2480 : : static const char *
2481 : 0 : nvmf_qpair_state_str(enum spdk_nvmf_qpair_state state)
2482 : : {
2483 [ # # # # : 0 : switch (state) {
# ]
2484 : 0 : case SPDK_NVMF_QPAIR_UNINITIALIZED:
2485 : 0 : return "uninitialized";
2486 : 0 : case SPDK_NVMF_QPAIR_ACTIVE:
2487 : 0 : return "active";
2488 : 0 : case SPDK_NVMF_QPAIR_DEACTIVATING:
2489 : 0 : return "deactivating";
2490 : 0 : case SPDK_NVMF_QPAIR_ERROR:
2491 : 0 : return "error";
2492 : 0 : default:
2493 : 0 : return NULL;
2494 : : }
2495 : : }
2496 : :
2497 : : static void
2498 : 0 : dump_nvmf_qpair(struct spdk_json_write_ctx *w, struct spdk_nvmf_qpair *qpair)
2499 : : {
2500 : 0 : struct spdk_nvme_transport_id listen_trid = {};
2501 : :
2502 : 0 : spdk_json_write_object_begin(w);
2503 : :
2504 : 0 : spdk_json_write_named_uint32(w, "cntlid", qpair->ctrlr->cntlid);
2505 : 0 : spdk_json_write_named_uint32(w, "qid", qpair->qid);
2506 : 0 : spdk_json_write_named_string(w, "state", nvmf_qpair_state_str(qpair->state));
2507 : :
2508 [ # # ]: 0 : if (spdk_nvmf_qpair_get_listen_trid(qpair, &listen_trid) == 0) {
2509 : 0 : spdk_json_write_named_object_begin(w, "listen_address");
2510 : 0 : nvmf_transport_listen_dump_trid(&listen_trid, w);
2511 : 0 : spdk_json_write_object_end(w);
2512 [ # # ]: 0 : if (qpair->transport->ops->listen_dump_opts) {
2513 : 0 : qpair->transport->ops->listen_dump_opts(qpair->transport, &listen_trid, w);
2514 : : }
2515 : : }
2516 : :
2517 : 0 : spdk_json_write_object_end(w);
2518 : 0 : }
2519 : :
2520 : : static const char *
2521 : 52 : nvme_ana_state_str(enum spdk_nvme_ana_state ana_state)
2522 : : {
2523 [ + + + - : 52 : switch (ana_state) {
- - ]
2524 : 16 : case SPDK_NVME_ANA_OPTIMIZED_STATE:
2525 : 16 : return "optimized";
2526 : 20 : case SPDK_NVME_ANA_NON_OPTIMIZED_STATE:
2527 : 20 : return "non_optimized";
2528 : 16 : case SPDK_NVME_ANA_INACCESSIBLE_STATE:
2529 : 16 : return "inaccessible";
2530 : 0 : case SPDK_NVME_ANA_PERSISTENT_LOSS_STATE:
2531 : 0 : return "persistent_loss";
2532 : 0 : case SPDK_NVME_ANA_CHANGE_STATE:
2533 : 0 : return "change";
2534 : 0 : default:
2535 : 0 : return NULL;
2536 : : }
2537 : : }
2538 : :
2539 : : static void
2540 : 26 : dump_nvmf_subsystem_listener(struct spdk_json_write_ctx *w,
2541 : : struct spdk_nvmf_subsystem_listener *listener)
2542 : : {
2543 : 26 : const struct spdk_nvme_transport_id *trid = listener->trid;
2544 : : uint32_t i;
2545 : :
2546 : 26 : spdk_json_write_object_begin(w);
2547 : :
2548 : 26 : spdk_json_write_named_object_begin(w, "address");
2549 : 26 : nvmf_transport_listen_dump_trid(trid, w);
2550 : 26 : spdk_json_write_object_end(w);
2551 : :
2552 [ + - ]: 26 : if (spdk_nvmf_subsystem_get_ana_reporting(listener->subsystem)) {
2553 : 26 : spdk_json_write_named_array_begin(w, "ana_states");
2554 [ + + ]: 78 : for (i = 0; i < listener->subsystem->max_nsid; i++) {
2555 : 52 : spdk_json_write_object_begin(w);
2556 : 52 : spdk_json_write_named_uint32(w, "ana_group", i + 1);
2557 : 52 : spdk_json_write_named_string(w, "ana_state",
2558 : 52 : nvme_ana_state_str(listener->ana_state[i]));
2559 : 52 : spdk_json_write_object_end(w);
2560 : : }
2561 : 26 : spdk_json_write_array_end(w);
2562 : : }
2563 : :
2564 : 26 : spdk_json_write_object_end(w);
2565 : 26 : }
2566 : :
2567 : : struct rpc_subsystem_query_ctx {
2568 : : char *nqn;
2569 : : char *tgt_name;
2570 : : struct spdk_nvmf_subsystem *subsystem;
2571 : : struct spdk_jsonrpc_request *request;
2572 : : struct spdk_json_write_ctx *w;
2573 : : };
2574 : :
2575 : : static const struct spdk_json_object_decoder rpc_subsystem_query_decoders[] = {
2576 : : {"nqn", offsetof(struct rpc_subsystem_query_ctx, nqn), spdk_json_decode_string},
2577 : : {"tgt_name", offsetof(struct rpc_subsystem_query_ctx, tgt_name), spdk_json_decode_string, true},
2578 : : };
2579 : :
2580 : : static void
2581 : 14 : free_rpc_subsystem_query_ctx(struct rpc_subsystem_query_ctx *ctx)
2582 : : {
2583 : 14 : free(ctx->nqn);
2584 : 14 : free(ctx->tgt_name);
2585 : 14 : free(ctx);
2586 : 14 : }
2587 : :
2588 : : static void
2589 : 0 : rpc_nvmf_get_controllers_paused(struct spdk_nvmf_subsystem *subsystem,
2590 : : void *cb_arg, int status)
2591 : : {
2592 : 0 : struct rpc_subsystem_query_ctx *ctx = cb_arg;
2593 : : struct spdk_json_write_ctx *w;
2594 : : struct spdk_nvmf_ctrlr *ctrlr;
2595 : :
2596 : 0 : w = spdk_jsonrpc_begin_result(ctx->request);
2597 : :
2598 : 0 : spdk_json_write_array_begin(w);
2599 [ # # ]: 0 : TAILQ_FOREACH(ctrlr, &ctx->subsystem->ctrlrs, link) {
2600 : 0 : dump_nvmf_ctrlr(w, ctrlr);
2601 : : }
2602 : 0 : spdk_json_write_array_end(w);
2603 : :
2604 : 0 : spdk_jsonrpc_end_result(ctx->request, w);
2605 : :
2606 [ # # ]: 0 : if (spdk_nvmf_subsystem_resume(ctx->subsystem, NULL, NULL)) {
2607 : 0 : SPDK_ERRLOG("Resuming subsystem with NQN %s failed\n", ctx->nqn);
2608 : : /* FIXME: RPC should fail if resuming the subsystem failed. */
2609 : : }
2610 : :
2611 : 0 : free_rpc_subsystem_query_ctx(ctx);
2612 : 0 : }
2613 : :
2614 : : static void
2615 : 0 : rpc_nvmf_get_qpairs_done(struct spdk_io_channel_iter *i, int status)
2616 : : {
2617 : 0 : struct rpc_subsystem_query_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
2618 : :
2619 : 0 : spdk_json_write_array_end(ctx->w);
2620 : 0 : spdk_jsonrpc_end_result(ctx->request, ctx->w);
2621 : :
2622 [ # # ]: 0 : if (spdk_nvmf_subsystem_resume(ctx->subsystem, NULL, NULL)) {
2623 : 0 : SPDK_ERRLOG("Resuming subsystem with NQN %s failed\n", ctx->nqn);
2624 : : /* FIXME: RPC should fail if resuming the subsystem failed. */
2625 : : }
2626 : :
2627 : 0 : free_rpc_subsystem_query_ctx(ctx);
2628 : 0 : }
2629 : :
2630 : : static void
2631 : 0 : rpc_nvmf_get_qpairs(struct spdk_io_channel_iter *i)
2632 : : {
2633 : 0 : struct rpc_subsystem_query_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
2634 : : struct spdk_io_channel *ch;
2635 : : struct spdk_nvmf_poll_group *group;
2636 : : struct spdk_nvmf_qpair *qpair;
2637 : :
2638 : 0 : ch = spdk_io_channel_iter_get_channel(i);
2639 : 0 : group = spdk_io_channel_get_ctx(ch);
2640 : :
2641 [ # # ]: 0 : TAILQ_FOREACH(qpair, &group->qpairs, link) {
2642 [ # # ]: 0 : if (qpair->ctrlr->subsys == ctx->subsystem) {
2643 : 0 : dump_nvmf_qpair(ctx->w, qpair);
2644 : : }
2645 : : }
2646 : :
2647 : 0 : spdk_for_each_channel_continue(i, 0);
2648 : 0 : }
2649 : :
2650 : : static void
2651 : 0 : rpc_nvmf_get_qpairs_paused(struct spdk_nvmf_subsystem *subsystem,
2652 : : void *cb_arg, int status)
2653 : : {
2654 : 0 : struct rpc_subsystem_query_ctx *ctx = cb_arg;
2655 : :
2656 : 0 : ctx->w = spdk_jsonrpc_begin_result(ctx->request);
2657 : :
2658 : 0 : spdk_json_write_array_begin(ctx->w);
2659 : :
2660 : 0 : spdk_for_each_channel(ctx->subsystem->tgt,
2661 : : rpc_nvmf_get_qpairs,
2662 : : ctx,
2663 : : rpc_nvmf_get_qpairs_done);
2664 : 0 : }
2665 : :
2666 : : static void
2667 : 14 : rpc_nvmf_get_listeners_paused(struct spdk_nvmf_subsystem *subsystem,
2668 : : void *cb_arg, int status)
2669 : : {
2670 : 14 : struct rpc_subsystem_query_ctx *ctx = cb_arg;
2671 : : struct spdk_json_write_ctx *w;
2672 : : struct spdk_nvmf_subsystem_listener *listener;
2673 : :
2674 : 14 : w = spdk_jsonrpc_begin_result(ctx->request);
2675 : :
2676 : 14 : spdk_json_write_array_begin(w);
2677 : :
2678 [ # # ]: 14 : for (listener = spdk_nvmf_subsystem_get_first_listener(ctx->subsystem);
2679 [ + + ]: 40 : listener != NULL;
2680 : 26 : listener = spdk_nvmf_subsystem_get_next_listener(ctx->subsystem, listener)) {
2681 : 26 : dump_nvmf_subsystem_listener(w, listener);
2682 : : }
2683 : 14 : spdk_json_write_array_end(w);
2684 : :
2685 : 14 : spdk_jsonrpc_end_result(ctx->request, w);
2686 : :
2687 [ - + ]: 14 : if (spdk_nvmf_subsystem_resume(ctx->subsystem, NULL, NULL)) {
2688 : 0 : SPDK_ERRLOG("Resuming subsystem with NQN %s failed\n", ctx->nqn);
2689 : : /* FIXME: RPC should fail if resuming the subsystem failed. */
2690 : : }
2691 : :
2692 : 14 : free_rpc_subsystem_query_ctx(ctx);
2693 : 14 : }
2694 : :
2695 : : static void
2696 : 14 : _rpc_nvmf_subsystem_query(struct spdk_jsonrpc_request *request,
2697 : : const struct spdk_json_val *params,
2698 : : spdk_nvmf_subsystem_state_change_done cb_fn)
2699 : : {
2700 : : struct rpc_subsystem_query_ctx *ctx;
2701 : : struct spdk_nvmf_subsystem *subsystem;
2702 : : struct spdk_nvmf_tgt *tgt;
2703 : :
2704 : 14 : ctx = calloc(1, sizeof(*ctx));
2705 [ - + ]: 14 : if (!ctx) {
2706 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
2707 : : "Out of memory");
2708 : 0 : return;
2709 : : }
2710 : :
2711 : 14 : ctx->request = request;
2712 : :
2713 [ - + ]: 14 : if (spdk_json_decode_object(params, rpc_subsystem_query_decoders,
2714 : : SPDK_COUNTOF(rpc_subsystem_query_decoders),
2715 : : ctx)) {
2716 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
2717 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
2718 : : "Invalid parameters");
2719 : 0 : free_rpc_subsystem_query_ctx(ctx);
2720 : 0 : return;
2721 : : }
2722 : :
2723 : 14 : tgt = spdk_nvmf_get_tgt(ctx->tgt_name);
2724 [ - + ]: 14 : if (!tgt) {
2725 : 0 : SPDK_ERRLOG("Unable to find a target object.\n");
2726 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
2727 : : "Unable to find a target");
2728 : 0 : free_rpc_subsystem_query_ctx(ctx);
2729 : 0 : return;
2730 : : }
2731 : :
2732 : 14 : subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx->nqn);
2733 [ - + ]: 14 : if (!subsystem) {
2734 : 0 : SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn);
2735 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
2736 : : "Invalid parameters");
2737 : 0 : free_rpc_subsystem_query_ctx(ctx);
2738 : 0 : return;
2739 : : }
2740 : :
2741 : 14 : ctx->subsystem = subsystem;
2742 : :
2743 [ - + ]: 14 : if (spdk_nvmf_subsystem_pause(subsystem, 0, cb_fn, ctx)) {
2744 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
2745 : : "Internal error");
2746 : 0 : free_rpc_subsystem_query_ctx(ctx);
2747 : 0 : return;
2748 : : }
2749 : : }
2750 : :
2751 : : static void
2752 : 0 : rpc_nvmf_subsystem_get_controllers(struct spdk_jsonrpc_request *request,
2753 : : const struct spdk_json_val *params)
2754 : : {
2755 : 0 : _rpc_nvmf_subsystem_query(request, params, rpc_nvmf_get_controllers_paused);
2756 : 0 : }
2757 : 741 : SPDK_RPC_REGISTER("nvmf_subsystem_get_controllers", rpc_nvmf_subsystem_get_controllers,
2758 : : SPDK_RPC_RUNTIME);
2759 : :
2760 : : static void
2761 : 0 : rpc_nvmf_subsystem_get_qpairs(struct spdk_jsonrpc_request *request,
2762 : : const struct spdk_json_val *params)
2763 : : {
2764 : 0 : _rpc_nvmf_subsystem_query(request, params, rpc_nvmf_get_qpairs_paused);
2765 : 0 : }
2766 : 741 : SPDK_RPC_REGISTER("nvmf_subsystem_get_qpairs", rpc_nvmf_subsystem_get_qpairs, SPDK_RPC_RUNTIME);
2767 : :
2768 : : static void
2769 : 14 : rpc_nvmf_subsystem_get_listeners(struct spdk_jsonrpc_request *request,
2770 : : const struct spdk_json_val *params)
2771 : : {
2772 : 14 : _rpc_nvmf_subsystem_query(request, params, rpc_nvmf_get_listeners_paused);
2773 : 14 : }
2774 : 741 : SPDK_RPC_REGISTER("nvmf_subsystem_get_listeners", rpc_nvmf_subsystem_get_listeners,
2775 : : SPDK_RPC_RUNTIME);
|