xref: /spdk/lib/nbd/nbd_rpc.c (revision a6dbe3721eb3b5990707fc3e378c95e505dd8ab5)
1488570ebSJim Harris /*   SPDX-License-Identifier: BSD-3-Clause
2*a6dbe372Spaul luse  *   Copyright (C) 2017 Intel Corporation.
3b93d767fSXiaodong Liu  *   All rights reserved.
4b93d767fSXiaodong Liu  */
5b93d767fSXiaodong Liu 
63a6ff827SXiaodong Liu #include "spdk/string.h"
73a6ff827SXiaodong Liu #include "spdk/env.h"
8b93d767fSXiaodong Liu #include "spdk/rpc.h"
9b93d767fSXiaodong Liu #include "spdk/util.h"
10b93d767fSXiaodong Liu 
11b93d767fSXiaodong Liu #include <linux/nbd.h>
12b93d767fSXiaodong Liu 
13b93d767fSXiaodong Liu #include "nbd_internal.h"
144e8e97c8STomasz Zawadzki #include "spdk/log.h"
15b93d767fSXiaodong Liu 
160a993323SPawel Kaminski struct rpc_nbd_start_disk {
17deddb8d8SXiaodong Liu 	char *bdev_name;
18deddb8d8SXiaodong Liu 	char *nbd_device;
19efdd6edbSXiaodong Liu 	/* Used to search one available nbd device */
20efdd6edbSXiaodong Liu 	int nbd_idx;
21efdd6edbSXiaodong Liu 	bool nbd_idx_specified;
22efdd6edbSXiaodong Liu 	struct spdk_jsonrpc_request *request;
23deddb8d8SXiaodong Liu };
24deddb8d8SXiaodong Liu 
25deddb8d8SXiaodong Liu static void
free_rpc_nbd_start_disk(struct rpc_nbd_start_disk * req)260a993323SPawel Kaminski free_rpc_nbd_start_disk(struct rpc_nbd_start_disk *req)
27deddb8d8SXiaodong Liu {
28deddb8d8SXiaodong Liu 	free(req->bdev_name);
29deddb8d8SXiaodong Liu 	free(req->nbd_device);
30efdd6edbSXiaodong Liu 	free(req);
31deddb8d8SXiaodong Liu }
32deddb8d8SXiaodong Liu 
330a993323SPawel Kaminski static const struct spdk_json_object_decoder rpc_nbd_start_disk_decoders[] = {
340a993323SPawel Kaminski 	{"bdev_name", offsetof(struct rpc_nbd_start_disk, bdev_name), spdk_json_decode_string},
350a993323SPawel Kaminski 	{"nbd_device", offsetof(struct rpc_nbd_start_disk, nbd_device), spdk_json_decode_string, true},
36deddb8d8SXiaodong Liu };
37deddb8d8SXiaodong Liu 
38efdd6edbSXiaodong Liu /* Return 0 to indicate the nbd_device might be available,
39cbd8036eSpaul luse  * or non-zero to indicate the nbd_device is invalid or in use.
40efdd6edbSXiaodong Liu  */
41efdd6edbSXiaodong Liu static int
check_available_nbd_disk(char * nbd_device)42efdd6edbSXiaodong Liu check_available_nbd_disk(char *nbd_device)
43efdd6edbSXiaodong Liu {
44efdd6edbSXiaodong Liu 	char nbd_block_path[256];
45efdd6edbSXiaodong Liu 	char tail[2];
46efdd6edbSXiaodong Liu 	int rc;
47efdd6edbSXiaodong Liu 	unsigned int nbd_idx;
48efdd6edbSXiaodong Liu 	struct spdk_nbd_disk *nbd;
49efdd6edbSXiaodong Liu 
50efdd6edbSXiaodong Liu 	/* nbd device path must be in format of /dev/nbd<num>, with no tail. */
51efdd6edbSXiaodong Liu 	rc = sscanf(nbd_device, "/dev/nbd%u%1s", &nbd_idx, tail);
52efdd6edbSXiaodong Liu 	if (rc != 1) {
536fdd36e1SPawel Kaminski 		return -errno;
54efdd6edbSXiaodong Liu 	}
55efdd6edbSXiaodong Liu 
56efdd6edbSXiaodong Liu 	/* make sure nbd_device is not registered inside SPDK */
5717b53caaSSeth Howell 	nbd = nbd_disk_find_by_nbd_path(nbd_device);
58efdd6edbSXiaodong Liu 	if (nbd) {
59cbd8036eSpaul luse 		/* nbd_device is in use */
606fdd36e1SPawel Kaminski 		return -EBUSY;
61efdd6edbSXiaodong Liu 	}
62efdd6edbSXiaodong Liu 
63cbd8036eSpaul luse 	/* A valid pid file in /sys/block indicates the device is in use */
64efdd6edbSXiaodong Liu 	snprintf(nbd_block_path, 256, "/sys/block/nbd%u/pid", nbd_idx);
65efdd6edbSXiaodong Liu 
66efdd6edbSXiaodong Liu 	rc = open(nbd_block_path, O_RDONLY);
67efdd6edbSXiaodong Liu 	if (rc < 0) {
68efdd6edbSXiaodong Liu 		if (errno == ENOENT) {
69efdd6edbSXiaodong Liu 			/* nbd_device might be available */
70efdd6edbSXiaodong Liu 			return 0;
71efdd6edbSXiaodong Liu 		} else {
72efdd6edbSXiaodong Liu 			SPDK_ERRLOG("Failed to check PID file %s: %s\n", nbd_block_path, spdk_strerror(errno));
736fdd36e1SPawel Kaminski 			return -errno;
74efdd6edbSXiaodong Liu 		}
75efdd6edbSXiaodong Liu 	}
76efdd6edbSXiaodong Liu 
77efdd6edbSXiaodong Liu 	close(rc);
78efdd6edbSXiaodong Liu 
79cbd8036eSpaul luse 	/* nbd_device is in use */
806fdd36e1SPawel Kaminski 	return -EBUSY;
81efdd6edbSXiaodong Liu }
82efdd6edbSXiaodong Liu 
83efdd6edbSXiaodong Liu static char *
find_available_nbd_disk(int nbd_idx,int * next_nbd_idx)84efdd6edbSXiaodong Liu find_available_nbd_disk(int nbd_idx, int *next_nbd_idx)
85efdd6edbSXiaodong Liu {
86efdd6edbSXiaodong Liu 	int i, rc;
87efdd6edbSXiaodong Liu 	char nbd_device[20];
88efdd6edbSXiaodong Liu 
89efdd6edbSXiaodong Liu 	for (i = nbd_idx; ; i++) {
90efdd6edbSXiaodong Liu 		snprintf(nbd_device, 20, "/dev/nbd%d", i);
91efdd6edbSXiaodong Liu 		/* Check whether an nbd device exists in order to reach the last one nbd device */
92efdd6edbSXiaodong Liu 		rc = access(nbd_device, F_OK);
93efdd6edbSXiaodong Liu 		if (rc != 0) {
94efdd6edbSXiaodong Liu 			break;
95efdd6edbSXiaodong Liu 		}
96efdd6edbSXiaodong Liu 
97efdd6edbSXiaodong Liu 		rc = check_available_nbd_disk(nbd_device);
98efdd6edbSXiaodong Liu 		if (rc == 0) {
99efdd6edbSXiaodong Liu 			if (next_nbd_idx != NULL) {
100efdd6edbSXiaodong Liu 				*next_nbd_idx = i + 1;
101efdd6edbSXiaodong Liu 			}
102efdd6edbSXiaodong Liu 
103efdd6edbSXiaodong Liu 			return strdup(nbd_device);
104efdd6edbSXiaodong Liu 		}
105efdd6edbSXiaodong Liu 	}
106efdd6edbSXiaodong Liu 
107efdd6edbSXiaodong Liu 	return NULL;
108efdd6edbSXiaodong Liu }
109efdd6edbSXiaodong Liu 
110deddb8d8SXiaodong Liu static void
rpc_start_nbd_done(void * cb_arg,struct spdk_nbd_disk * nbd,int rc)1110be5557cSSeth Howell rpc_start_nbd_done(void *cb_arg, struct spdk_nbd_disk *nbd, int rc)
1122fe6d1d5SBen Walker {
1130a993323SPawel Kaminski 	struct rpc_nbd_start_disk *req = cb_arg;
114efdd6edbSXiaodong Liu 	struct spdk_jsonrpc_request *request = req->request;
1152fe6d1d5SBen Walker 	struct spdk_json_write_ctx *w;
1162fe6d1d5SBen Walker 
117efdd6edbSXiaodong Liu 	/* Check whether it's automatic nbd-device assignment */
118efdd6edbSXiaodong Liu 	if (rc == -EBUSY && req->nbd_idx_specified == false) {
119efdd6edbSXiaodong Liu 		free(req->nbd_device);
120efdd6edbSXiaodong Liu 
121efdd6edbSXiaodong Liu 		req->nbd_device = find_available_nbd_disk(req->nbd_idx, &req->nbd_idx);
122efdd6edbSXiaodong Liu 		if (req->nbd_device != NULL) {
123efdd6edbSXiaodong Liu 			spdk_nbd_start(req->bdev_name, req->nbd_device,
1240be5557cSSeth Howell 				       rpc_start_nbd_done, req);
125efdd6edbSXiaodong Liu 			return;
126efdd6edbSXiaodong Liu 		}
127efdd6edbSXiaodong Liu 
1282172c432STomasz Zawadzki 		SPDK_INFOLOG(nbd, "There is no available nbd device.\n");
129efdd6edbSXiaodong Liu 	}
130efdd6edbSXiaodong Liu 
1312fe6d1d5SBen Walker 	if (rc) {
1326fdd36e1SPawel Kaminski 		spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
1330dc567ebSyidong0635 		free_rpc_nbd_start_disk(req);
1342fe6d1d5SBen Walker 		return;
1352fe6d1d5SBen Walker 	}
1362fe6d1d5SBen Walker 
1372fe6d1d5SBen Walker 	w = spdk_jsonrpc_begin_result(request);
1382fe6d1d5SBen Walker 	spdk_json_write_string(w, spdk_nbd_get_path(nbd));
1392fe6d1d5SBen Walker 	spdk_jsonrpc_end_result(request, w);
140efdd6edbSXiaodong Liu 
1410a993323SPawel Kaminski 	free_rpc_nbd_start_disk(req);
1422fe6d1d5SBen Walker }
1432fe6d1d5SBen Walker 
1442fe6d1d5SBen Walker static void
rpc_nbd_start_disk(struct spdk_jsonrpc_request * request,const struct spdk_json_val * params)1450be5557cSSeth Howell rpc_nbd_start_disk(struct spdk_jsonrpc_request *request,
146deddb8d8SXiaodong Liu 		   const struct spdk_json_val *params)
147deddb8d8SXiaodong Liu {
1480a993323SPawel Kaminski 	struct rpc_nbd_start_disk *req;
149efdd6edbSXiaodong Liu 	int rc;
150efdd6edbSXiaodong Liu 
151efdd6edbSXiaodong Liu 	req = calloc(1, sizeof(*req));
152efdd6edbSXiaodong Liu 	if (req == NULL) {
1530a993323SPawel Kaminski 		SPDK_ERRLOG("could not allocate nbd_start_disk request.\n");
154efdd6edbSXiaodong Liu 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory");
155efdd6edbSXiaodong Liu 		return;
156efdd6edbSXiaodong Liu 	}
157deddb8d8SXiaodong Liu 
1580a993323SPawel Kaminski 	if (spdk_json_decode_object(params, rpc_nbd_start_disk_decoders,
1590a993323SPawel Kaminski 				    SPDK_COUNTOF(rpc_nbd_start_disk_decoders),
160efdd6edbSXiaodong Liu 				    req)) {
161deddb8d8SXiaodong Liu 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1626fdd36e1SPawel Kaminski 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1636fdd36e1SPawel Kaminski 						 "spdk_json_decode_object failed");
164deddb8d8SXiaodong Liu 		goto invalid;
165deddb8d8SXiaodong Liu 	}
166deddb8d8SXiaodong Liu 
167efdd6edbSXiaodong Liu 	if (req->bdev_name == NULL) {
168deddb8d8SXiaodong Liu 		goto invalid;
169deddb8d8SXiaodong Liu 	}
170deddb8d8SXiaodong Liu 
171efdd6edbSXiaodong Liu 	if (req->nbd_device != NULL) {
172efdd6edbSXiaodong Liu 		req->nbd_idx_specified = true;
173efdd6edbSXiaodong Liu 		rc = check_available_nbd_disk(req->nbd_device);
1746fdd36e1SPawel Kaminski 		if (rc == -EBUSY) {
175cbd8036eSpaul luse 			SPDK_DEBUGLOG(nbd, "NBD device %s is in use.\n", req->nbd_device);
1766fdd36e1SPawel Kaminski 			spdk_jsonrpc_send_error_response(request, -EBUSY, spdk_strerror(-rc));
177deddb8d8SXiaodong Liu 			goto invalid;
178deddb8d8SXiaodong Liu 		}
179deddb8d8SXiaodong Liu 
180efdd6edbSXiaodong Liu 		if (rc != 0) {
1812172c432STomasz Zawadzki 			SPDK_DEBUGLOG(nbd, "Illegal nbd_device %s.\n", req->nbd_device);
1826fdd36e1SPawel Kaminski 			spdk_jsonrpc_send_error_response_fmt(request, -ENODEV,
1836fdd36e1SPawel Kaminski 							     "illegal nbd device %s", req->nbd_device);
184efdd6edbSXiaodong Liu 			goto invalid;
185efdd6edbSXiaodong Liu 		}
186efdd6edbSXiaodong Liu 	} else {
187efdd6edbSXiaodong Liu 		req->nbd_idx = 0;
188efdd6edbSXiaodong Liu 		req->nbd_device = find_available_nbd_disk(req->nbd_idx, &req->nbd_idx);
189efdd6edbSXiaodong Liu 		if (req->nbd_device == NULL) {
1902172c432STomasz Zawadzki 			SPDK_INFOLOG(nbd, "There is no available nbd device.\n");
1916fdd36e1SPawel Kaminski 			spdk_jsonrpc_send_error_response(request, -ENODEV,
1926fdd36e1SPawel Kaminski 							 "nbd device not found");
193efdd6edbSXiaodong Liu 			goto invalid;
194efdd6edbSXiaodong Liu 		}
195efdd6edbSXiaodong Liu 	}
196deddb8d8SXiaodong Liu 
197efdd6edbSXiaodong Liu 	req->request = request;
198efdd6edbSXiaodong Liu 	spdk_nbd_start(req->bdev_name, req->nbd_device,
1990be5557cSSeth Howell 		       rpc_start_nbd_done, req);
200efdd6edbSXiaodong Liu 
201deddb8d8SXiaodong Liu 	return;
202deddb8d8SXiaodong Liu 
203deddb8d8SXiaodong Liu invalid:
2040a993323SPawel Kaminski 	free_rpc_nbd_start_disk(req);
205deddb8d8SXiaodong Liu }
206deddb8d8SXiaodong Liu 
2070be5557cSSeth Howell SPDK_RPC_REGISTER("nbd_start_disk", rpc_nbd_start_disk, SPDK_RPC_RUNTIME)
208deddb8d8SXiaodong Liu 
209d242f5a0SPawel Kaminski struct rpc_nbd_stop_disk {
210b93d767fSXiaodong Liu 	char *nbd_device;
211b93d767fSXiaodong Liu };
212b93d767fSXiaodong Liu 
213b93d767fSXiaodong Liu static void
free_rpc_nbd_stop_disk(struct rpc_nbd_stop_disk * req)214d242f5a0SPawel Kaminski free_rpc_nbd_stop_disk(struct rpc_nbd_stop_disk *req)
215b93d767fSXiaodong Liu {
216b93d767fSXiaodong Liu 	free(req->nbd_device);
217b93d767fSXiaodong Liu }
218b93d767fSXiaodong Liu 
219d242f5a0SPawel Kaminski static const struct spdk_json_object_decoder rpc_nbd_stop_disk_decoders[] = {
220d242f5a0SPawel Kaminski 	{"nbd_device", offsetof(struct rpc_nbd_stop_disk, nbd_device), spdk_json_decode_string},
221b93d767fSXiaodong Liu };
222b93d767fSXiaodong Liu 
2233a6ff827SXiaodong Liu struct nbd_disconnect_arg {
2243a6ff827SXiaodong Liu 	struct spdk_jsonrpc_request *request;
2253a6ff827SXiaodong Liu 	struct spdk_nbd_disk *nbd;
2263a6ff827SXiaodong Liu };
2273a6ff827SXiaodong Liu 
2283a6ff827SXiaodong Liu static void *
nbd_disconnect_thread(void * arg)2293a6ff827SXiaodong Liu nbd_disconnect_thread(void *arg)
2303a6ff827SXiaodong Liu {
2313a6ff827SXiaodong Liu 	struct nbd_disconnect_arg *thd_arg = arg;
2323a6ff827SXiaodong Liu 
2333a6ff827SXiaodong Liu 	spdk_unaffinitize_thread();
2343a6ff827SXiaodong Liu 
2353a6ff827SXiaodong Liu 	nbd_disconnect(thd_arg->nbd);
2363a6ff827SXiaodong Liu 
237d73077b8Syidong0635 	spdk_jsonrpc_send_bool_response(thd_arg->request, true);
2383a6ff827SXiaodong Liu 
2393a6ff827SXiaodong Liu 	free(thd_arg);
2403a6ff827SXiaodong Liu 	pthread_exit(NULL);
2413a6ff827SXiaodong Liu }
2423a6ff827SXiaodong Liu 
243b93d767fSXiaodong Liu static void
rpc_nbd_stop_disk(struct spdk_jsonrpc_request * request,const struct spdk_json_val * params)2440be5557cSSeth Howell rpc_nbd_stop_disk(struct spdk_jsonrpc_request *request,
245b93d767fSXiaodong Liu 		  const struct spdk_json_val *params)
246b93d767fSXiaodong Liu {
247d242f5a0SPawel Kaminski 	struct rpc_nbd_stop_disk req = {};
248b93d767fSXiaodong Liu 	struct spdk_nbd_disk *nbd;
2493a6ff827SXiaodong Liu 	pthread_t tid;
2503a6ff827SXiaodong Liu 	struct nbd_disconnect_arg *thd_arg = NULL;
2513a6ff827SXiaodong Liu 	int rc;
252b93d767fSXiaodong Liu 
253d242f5a0SPawel Kaminski 	if (spdk_json_decode_object(params, rpc_nbd_stop_disk_decoders,
254d242f5a0SPawel Kaminski 				    SPDK_COUNTOF(rpc_nbd_stop_disk_decoders),
255b93d767fSXiaodong Liu 				    &req)) {
256b93d767fSXiaodong Liu 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
2576fdd36e1SPawel Kaminski 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
2586fdd36e1SPawel Kaminski 						 "spdk_json_decode_object failed");
2593a6ff827SXiaodong Liu 		goto out;
260b93d767fSXiaodong Liu 	}
261b93d767fSXiaodong Liu 
262b93d767fSXiaodong Liu 	if (req.nbd_device == NULL) {
2636fdd36e1SPawel Kaminski 		spdk_jsonrpc_send_error_response(request, -ENODEV, "invalid nbd device");
2643a6ff827SXiaodong Liu 		goto out;
265b93d767fSXiaodong Liu 	}
266b93d767fSXiaodong Liu 
267b93d767fSXiaodong Liu 	/* make sure nbd_device is registered */
26817b53caaSSeth Howell 	nbd = nbd_disk_find_by_nbd_path(req.nbd_device);
269b93d767fSXiaodong Liu 	if (!nbd) {
2706fdd36e1SPawel Kaminski 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
2713a6ff827SXiaodong Liu 		goto out;
272b93d767fSXiaodong Liu 	}
273b93d767fSXiaodong Liu 
2743a6ff827SXiaodong Liu 	/*
2753a6ff827SXiaodong Liu 	 * thd_arg should be freed by created thread
2763a6ff827SXiaodong Liu 	 * if thread is created successfully.
2773a6ff827SXiaodong Liu 	 */
2783a6ff827SXiaodong Liu 	thd_arg = malloc(sizeof(*thd_arg));
2793a6ff827SXiaodong Liu 	if (!thd_arg) {
280891c12a6SPawel Wodkowski 		SPDK_ERRLOG("could not allocate nbd disconnect thread arg\n");
281891c12a6SPawel Wodkowski 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory");
2823a6ff827SXiaodong Liu 		goto out;
283b93d767fSXiaodong Liu 	}
284b93d767fSXiaodong Liu 
2853a6ff827SXiaodong Liu 	thd_arg->request = request;
2863a6ff827SXiaodong Liu 	thd_arg->nbd = nbd;
287b93d767fSXiaodong Liu 
2883a6ff827SXiaodong Liu 	/*
2893a6ff827SXiaodong Liu 	 * NBD ioctl of disconnect will block until data are flushed.
2903a6ff827SXiaodong Liu 	 * Create separate thread to execute it.
2913a6ff827SXiaodong Liu 	 */
2923a6ff827SXiaodong Liu 	rc = pthread_create(&tid, NULL, nbd_disconnect_thread, (void *)thd_arg);
2933a6ff827SXiaodong Liu 	if (rc != 0) {
294891c12a6SPawel Wodkowski 		SPDK_ERRLOG("could not create nbd disconnect thread: %s\n", spdk_strerror(rc));
295891c12a6SPawel Wodkowski 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, spdk_strerror(rc));
2963a6ff827SXiaodong Liu 		free(thd_arg);
2973a6ff827SXiaodong Liu 		goto out;
2983a6ff827SXiaodong Liu 	}
2993a6ff827SXiaodong Liu 
3003a6ff827SXiaodong Liu 	rc = pthread_detach(tid);
3013a6ff827SXiaodong Liu 	if (rc != 0) {
302891c12a6SPawel Wodkowski 		SPDK_ERRLOG("could not detach nbd disconnect thread: %s\n", spdk_strerror(rc));
3033a6ff827SXiaodong Liu 		goto out;
3043a6ff827SXiaodong Liu 	}
3053a6ff827SXiaodong Liu 
3063a6ff827SXiaodong Liu out:
307d242f5a0SPawel Kaminski 	free_rpc_nbd_stop_disk(&req);
308b93d767fSXiaodong Liu }
309b93d767fSXiaodong Liu 
3100be5557cSSeth Howell SPDK_RPC_REGISTER("nbd_stop_disk", rpc_nbd_stop_disk, SPDK_RPC_RUNTIME)
3111170628eSXiaodong Liu 
3121170628eSXiaodong Liu static void
rpc_dump_nbd_info(struct spdk_json_write_ctx * w,struct spdk_nbd_disk * nbd)3130be5557cSSeth Howell rpc_dump_nbd_info(struct spdk_json_write_ctx *w,
3141170628eSXiaodong Liu 		  struct spdk_nbd_disk *nbd)
3151170628eSXiaodong Liu {
3161170628eSXiaodong Liu 	spdk_json_write_object_begin(w);
3171170628eSXiaodong Liu 
31817b53caaSSeth Howell 	spdk_json_write_named_string(w, "nbd_device", nbd_disk_get_nbd_path(nbd));
3191170628eSXiaodong Liu 
32017b53caaSSeth Howell 	spdk_json_write_named_string(w, "bdev_name", nbd_disk_get_bdev_name(nbd));
3211170628eSXiaodong Liu 
3221170628eSXiaodong Liu 	spdk_json_write_object_end(w);
3231170628eSXiaodong Liu }
3241170628eSXiaodong Liu 
3255456a430SPawel Kaminski struct rpc_nbd_get_disks {
3261170628eSXiaodong Liu 	char *nbd_device;
3271170628eSXiaodong Liu };
3281170628eSXiaodong Liu 
3291170628eSXiaodong Liu static void
free_rpc_nbd_get_disks(struct rpc_nbd_get_disks * r)3305456a430SPawel Kaminski free_rpc_nbd_get_disks(struct rpc_nbd_get_disks *r)
3311170628eSXiaodong Liu {
3321170628eSXiaodong Liu 	free(r->nbd_device);
3331170628eSXiaodong Liu }
3341170628eSXiaodong Liu 
3355456a430SPawel Kaminski static const struct spdk_json_object_decoder rpc_nbd_get_disks_decoders[] = {
3365456a430SPawel Kaminski 	{"nbd_device", offsetof(struct rpc_nbd_get_disks, nbd_device), spdk_json_decode_string, true},
3371170628eSXiaodong Liu };
3381170628eSXiaodong Liu 
3391170628eSXiaodong Liu static void
rpc_nbd_get_disks(struct spdk_jsonrpc_request * request,const struct spdk_json_val * params)3400be5557cSSeth Howell rpc_nbd_get_disks(struct spdk_jsonrpc_request *request,
3411170628eSXiaodong Liu 		  const struct spdk_json_val *params)
3421170628eSXiaodong Liu {
3435456a430SPawel Kaminski 	struct rpc_nbd_get_disks req = {};
3441170628eSXiaodong Liu 	struct spdk_json_write_ctx *w;
3451170628eSXiaodong Liu 	struct spdk_nbd_disk *nbd = NULL;
3461170628eSXiaodong Liu 
3471170628eSXiaodong Liu 	if (params != NULL) {
3485456a430SPawel Kaminski 		if (spdk_json_decode_object(params, rpc_nbd_get_disks_decoders,
3495456a430SPawel Kaminski 					    SPDK_COUNTOF(rpc_nbd_get_disks_decoders),
3501170628eSXiaodong Liu 					    &req)) {
3511170628eSXiaodong Liu 			SPDK_ERRLOG("spdk_json_decode_object failed\n");
3526fdd36e1SPawel Kaminski 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
3536fdd36e1SPawel Kaminski 							 "spdk_json_decode_object failed");
3541170628eSXiaodong Liu 			goto invalid;
3551170628eSXiaodong Liu 		}
3561170628eSXiaodong Liu 
357e95f0bb7SDaniel Verkamp 		if (req.nbd_device) {
35817b53caaSSeth Howell 			nbd = nbd_disk_find_by_nbd_path(req.nbd_device);
3591170628eSXiaodong Liu 			if (nbd == NULL) {
3601170628eSXiaodong Liu 				SPDK_ERRLOG("nbd device '%s' does not exist\n", req.nbd_device);
3616fdd36e1SPawel Kaminski 				spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
3621170628eSXiaodong Liu 				goto invalid;
3631170628eSXiaodong Liu 			}
3641170628eSXiaodong Liu 
3655456a430SPawel Kaminski 			free_rpc_nbd_get_disks(&req);
3661170628eSXiaodong Liu 		}
3671170628eSXiaodong Liu 	}
3681170628eSXiaodong Liu 
3691170628eSXiaodong Liu 	w = spdk_jsonrpc_begin_result(request);
3701170628eSXiaodong Liu 	spdk_json_write_array_begin(w);
3711170628eSXiaodong Liu 
3721170628eSXiaodong Liu 	if (nbd != NULL) {
3730be5557cSSeth Howell 		rpc_dump_nbd_info(w, nbd);
3741170628eSXiaodong Liu 	} else {
37517b53caaSSeth Howell 		for (nbd = nbd_disk_first(); nbd != NULL; nbd = nbd_disk_next(nbd)) {
3760be5557cSSeth Howell 			rpc_dump_nbd_info(w, nbd);
3771170628eSXiaodong Liu 		}
3781170628eSXiaodong Liu 	}
3791170628eSXiaodong Liu 
3801170628eSXiaodong Liu 	spdk_json_write_array_end(w);
3811170628eSXiaodong Liu 
3821170628eSXiaodong Liu 	spdk_jsonrpc_end_result(request, w);
3831170628eSXiaodong Liu 
3841170628eSXiaodong Liu 	return;
3851170628eSXiaodong Liu 
3861170628eSXiaodong Liu invalid:
3875456a430SPawel Kaminski 	free_rpc_nbd_get_disks(&req);
3881170628eSXiaodong Liu }
3890be5557cSSeth Howell SPDK_RPC_REGISTER("nbd_get_disks", rpc_nbd_get_disks, SPDK_RPC_RUNTIME)
390