4 * Copyright (c) Intel Corporation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include "spdk/string.h"
37 #include "spdk/util.h"
39 #include <linux/nbd.h>
41 #include "nbd_internal.h"
42 #include "spdk_internal/log.h"
44 struct rpc_start_nbd_disk
{
47 /* Used to search one available nbd device */
49 bool nbd_idx_specified
;
50 struct spdk_jsonrpc_request
*request
;
54 free_rpc_start_nbd_disk(struct rpc_start_nbd_disk
*req
)
57 free(req
->nbd_device
);
61 static const struct spdk_json_object_decoder rpc_start_nbd_disk_decoders
[] = {
62 {"bdev_name", offsetof(struct rpc_start_nbd_disk
, bdev_name
), spdk_json_decode_string
},
63 {"nbd_device", offsetof(struct rpc_start_nbd_disk
, nbd_device
), spdk_json_decode_string
, true},
66 /* Return 0 to indicate the nbd_device might be available,
67 * or non-zero to indicate the nbd_device is invalid or in using.
70 check_available_nbd_disk(char *nbd_device
)
72 char nbd_block_path
[256];
76 struct spdk_nbd_disk
*nbd
;
78 /* nbd device path must be in format of /dev/nbd<num>, with no tail. */
79 rc
= sscanf(nbd_device
, "/dev/nbd%u%1s", &nbd_idx
, tail
);
84 /* make sure nbd_device is not registered inside SPDK */
85 nbd
= spdk_nbd_disk_find_by_nbd_path(nbd_device
);
87 /* nbd_device is in using */
91 /* A valid pid file in /sys/block indicates the device is in using */
92 snprintf(nbd_block_path
, 256, "/sys/block/nbd%u/pid", nbd_idx
);
94 rc
= open(nbd_block_path
, O_RDONLY
);
96 if (errno
== ENOENT
) {
97 /* nbd_device might be available */
100 SPDK_ERRLOG("Failed to check PID file %s: %s\n", nbd_block_path
, spdk_strerror(errno
));
107 /* nbd_device is in using */
112 find_available_nbd_disk(int nbd_idx
, int *next_nbd_idx
)
117 for (i
= nbd_idx
; ; i
++) {
118 snprintf(nbd_device
, 20, "/dev/nbd%d", i
);
119 /* Check whether an nbd device exists in order to reach the last one nbd device */
120 rc
= access(nbd_device
, F_OK
);
125 rc
= check_available_nbd_disk(nbd_device
);
127 if (next_nbd_idx
!= NULL
) {
128 *next_nbd_idx
= i
+ 1;
131 return strdup(nbd_device
);
139 spdk_rpc_start_nbd_done(void *cb_arg
, struct spdk_nbd_disk
*nbd
, int rc
)
141 struct rpc_start_nbd_disk
*req
= cb_arg
;
142 struct spdk_jsonrpc_request
*request
= req
->request
;
143 struct spdk_json_write_ctx
*w
;
145 /* Check whether it's automatic nbd-device assignment */
146 if (rc
== -EBUSY
&& req
->nbd_idx_specified
== false) {
147 free(req
->nbd_device
);
149 req
->nbd_device
= find_available_nbd_disk(req
->nbd_idx
, &req
->nbd_idx
);
150 if (req
->nbd_device
!= NULL
) {
151 spdk_nbd_start(req
->bdev_name
, req
->nbd_device
,
152 spdk_rpc_start_nbd_done
, req
);
156 SPDK_INFOLOG(SPDK_LOG_NBD
, "There is no available nbd device.\n");
160 spdk_jsonrpc_send_error_response(request
, SPDK_JSONRPC_ERROR_INVALID_PARAMS
, "Invalid parameters");
164 w
= spdk_jsonrpc_begin_result(request
);
169 spdk_json_write_string(w
, spdk_nbd_get_path(nbd
));
170 spdk_jsonrpc_end_result(request
, w
);
172 free_rpc_start_nbd_disk(req
);
176 spdk_rpc_start_nbd_disk(struct spdk_jsonrpc_request
*request
,
177 const struct spdk_json_val
*params
)
179 struct rpc_start_nbd_disk
*req
;
182 req
= calloc(1, sizeof(*req
));
184 SPDK_ERRLOG("could not allocate start_nbd_disk request.\n");
185 spdk_jsonrpc_send_error_response(request
, SPDK_JSONRPC_ERROR_INTERNAL_ERROR
, "Out of memory");
189 if (spdk_json_decode_object(params
, rpc_start_nbd_disk_decoders
,
190 SPDK_COUNTOF(rpc_start_nbd_disk_decoders
),
192 SPDK_ERRLOG("spdk_json_decode_object failed\n");
196 if (req
->bdev_name
== NULL
) {
200 if (req
->nbd_device
!= NULL
) {
201 req
->nbd_idx_specified
= true;
202 rc
= check_available_nbd_disk(req
->nbd_device
);
204 SPDK_DEBUGLOG(SPDK_LOG_NBD
, "NBD device %s is in using.\n", req
->nbd_device
);
209 SPDK_DEBUGLOG(SPDK_LOG_NBD
, "Illegal nbd_device %s.\n", req
->nbd_device
);
214 req
->nbd_device
= find_available_nbd_disk(req
->nbd_idx
, &req
->nbd_idx
);
215 if (req
->nbd_device
== NULL
) {
216 SPDK_INFOLOG(SPDK_LOG_NBD
, "There is no available nbd device.\n");
221 req
->request
= request
;
222 spdk_nbd_start(req
->bdev_name
, req
->nbd_device
,
223 spdk_rpc_start_nbd_done
, req
);
228 free_rpc_start_nbd_disk(req
);
229 spdk_jsonrpc_send_error_response(request
, SPDK_JSONRPC_ERROR_INVALID_PARAMS
, "Invalid parameters");
232 SPDK_RPC_REGISTER("start_nbd_disk", spdk_rpc_start_nbd_disk
, SPDK_RPC_RUNTIME
)
234 struct rpc_stop_nbd_disk
{
239 free_rpc_stop_nbd_disk(struct rpc_stop_nbd_disk
*req
)
241 free(req
->nbd_device
);
244 static const struct spdk_json_object_decoder rpc_stop_nbd_disk_decoders
[] = {
245 {"nbd_device", offsetof(struct rpc_stop_nbd_disk
, nbd_device
), spdk_json_decode_string
},
248 struct nbd_disconnect_arg
{
249 struct spdk_jsonrpc_request
*request
;
250 struct spdk_nbd_disk
*nbd
;
254 nbd_disconnect_thread(void *arg
)
256 struct nbd_disconnect_arg
*thd_arg
= arg
;
257 struct spdk_json_write_ctx
*w
;
259 spdk_unaffinitize_thread();
261 nbd_disconnect(thd_arg
->nbd
);
263 w
= spdk_jsonrpc_begin_result(thd_arg
->request
);
268 spdk_json_write_bool(w
, true);
269 spdk_jsonrpc_end_result(thd_arg
->request
, w
);
277 spdk_rpc_stop_nbd_disk(struct spdk_jsonrpc_request
*request
,
278 const struct spdk_json_val
*params
)
280 struct rpc_stop_nbd_disk req
= {};
281 struct spdk_nbd_disk
*nbd
;
283 struct nbd_disconnect_arg
*thd_arg
= NULL
;
286 if (spdk_json_decode_object(params
, rpc_stop_nbd_disk_decoders
,
287 SPDK_COUNTOF(rpc_stop_nbd_disk_decoders
),
289 SPDK_ERRLOG("spdk_json_decode_object failed\n");
290 spdk_jsonrpc_send_error_response(request
, SPDK_JSONRPC_ERROR_INVALID_PARAMS
,
291 "Invalid parameters");
295 if (req
.nbd_device
== NULL
) {
296 spdk_jsonrpc_send_error_response(request
, SPDK_JSONRPC_ERROR_INVALID_PARAMS
,
297 "Invalid parameters");
301 /* make sure nbd_device is registered */
302 nbd
= spdk_nbd_disk_find_by_nbd_path(req
.nbd_device
);
304 spdk_jsonrpc_send_error_response(request
, SPDK_JSONRPC_ERROR_INVALID_PARAMS
,
305 "Invalid parameters");
310 * thd_arg should be freed by created thread
311 * if thread is created successfully.
313 thd_arg
= malloc(sizeof(*thd_arg
));
315 SPDK_ERRLOG("could not allocate nbd disconnect thread arg\n");
316 spdk_jsonrpc_send_error_response(request
, SPDK_JSONRPC_ERROR_INTERNAL_ERROR
, "Out of memory");
320 thd_arg
->request
= request
;
324 * NBD ioctl of disconnect will block until data are flushed.
325 * Create separate thread to execute it.
327 rc
= pthread_create(&tid
, NULL
, nbd_disconnect_thread
, (void *)thd_arg
);
329 SPDK_ERRLOG("could not create nbd disconnect thread: %s\n", spdk_strerror(rc
));
330 spdk_jsonrpc_send_error_response(request
, SPDK_JSONRPC_ERROR_INTERNAL_ERROR
, spdk_strerror(rc
));
335 rc
= pthread_detach(tid
);
337 SPDK_ERRLOG("could not detach nbd disconnect thread: %s\n", spdk_strerror(rc
));
342 free_rpc_stop_nbd_disk(&req
);
345 SPDK_RPC_REGISTER("stop_nbd_disk", spdk_rpc_stop_nbd_disk
, SPDK_RPC_RUNTIME
)
348 spdk_rpc_dump_nbd_info(struct spdk_json_write_ctx
*w
,
349 struct spdk_nbd_disk
*nbd
)
351 spdk_json_write_object_begin(w
);
353 spdk_json_write_named_string(w
, "nbd_device", spdk_nbd_disk_get_nbd_path(nbd
));
355 spdk_json_write_named_string(w
, "bdev_name", spdk_nbd_disk_get_bdev_name(nbd
));
357 spdk_json_write_object_end(w
);
360 struct rpc_get_nbd_disks
{
365 free_rpc_get_nbd_disks(struct rpc_get_nbd_disks
*r
)
370 static const struct spdk_json_object_decoder rpc_get_nbd_disks_decoders
[] = {
371 {"nbd_device", offsetof(struct rpc_get_nbd_disks
, nbd_device
), spdk_json_decode_string
, true},
375 spdk_rpc_get_nbd_disks(struct spdk_jsonrpc_request
*request
,
376 const struct spdk_json_val
*params
)
378 struct rpc_get_nbd_disks req
= {};
379 struct spdk_json_write_ctx
*w
;
380 struct spdk_nbd_disk
*nbd
= NULL
;
382 if (params
!= NULL
) {
383 if (spdk_json_decode_object(params
, rpc_get_nbd_disks_decoders
,
384 SPDK_COUNTOF(rpc_get_nbd_disks_decoders
),
386 SPDK_ERRLOG("spdk_json_decode_object failed\n");
390 if (req
.nbd_device
) {
391 nbd
= spdk_nbd_disk_find_by_nbd_path(req
.nbd_device
);
393 SPDK_ERRLOG("nbd device '%s' does not exist\n", req
.nbd_device
);
397 free_rpc_get_nbd_disks(&req
);
401 w
= spdk_jsonrpc_begin_result(request
);
406 spdk_json_write_array_begin(w
);
409 spdk_rpc_dump_nbd_info(w
, nbd
);
411 for (nbd
= spdk_nbd_disk_first(); nbd
!= NULL
; nbd
= spdk_nbd_disk_next(nbd
)) {
412 spdk_rpc_dump_nbd_info(w
, nbd
);
416 spdk_json_write_array_end(w
);
418 spdk_jsonrpc_end_result(request
, w
);
423 spdk_jsonrpc_send_error_response(request
, SPDK_JSONRPC_ERROR_INVALID_PARAMS
, "Invalid parameters");
425 free_rpc_get_nbd_disks(&req
);
427 SPDK_RPC_REGISTER("get_nbd_disks", spdk_rpc_get_nbd_disks
, SPDK_RPC_RUNTIME
)