Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2017 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/stdinc.h"
7 : : #include "spdk/string.h"
8 : :
9 : : #include <linux/nbd.h>
10 : :
11 : : #include "spdk/nbd.h"
12 : : #include "nbd_internal.h"
13 : : #include "spdk/bdev.h"
14 : : #include "spdk/endian.h"
15 : : #include "spdk/env.h"
16 : : #include "spdk/likely.h"
17 : : #include "spdk/log.h"
18 : : #include "spdk/util.h"
19 : : #include "spdk/thread.h"
20 : :
21 : : #include "spdk/queue.h"
22 : :
23 : : #define GET_IO_LOOP_COUNT 16
24 : : #define NBD_START_BUSY_WAITING_MS 1000
25 : : #define NBD_STOP_BUSY_WAITING_MS 10000
26 : : #define NBD_BUSY_POLLING_INTERVAL_US 20000
27 : : #define NBD_IO_TIMEOUT_S 60
28 : :
29 : : enum nbd_io_state_t {
30 : : /* Receiving or ready to receive nbd request header */
31 : : NBD_IO_RECV_REQ = 0,
32 : : /* Receiving write payload */
33 : : NBD_IO_RECV_PAYLOAD,
34 : : /* Transmitting or ready to transmit nbd response header */
35 : : NBD_IO_XMIT_RESP,
36 : : /* Transmitting read payload */
37 : : NBD_IO_XMIT_PAYLOAD,
38 : : };
39 : :
40 : : struct nbd_io {
41 : : struct spdk_nbd_disk *nbd;
42 : : enum nbd_io_state_t state;
43 : :
44 : : void *payload;
45 : : uint32_t payload_size;
46 : :
47 : : struct nbd_request req;
48 : : struct nbd_reply resp;
49 : :
50 : : /*
51 : : * Tracks current progress on reading/writing a request,
52 : : * response, or payload from the nbd socket.
53 : : */
54 : : uint32_t offset;
55 : :
56 : : /* for bdev io_wait */
57 : : struct spdk_bdev_io_wait_entry bdev_io_wait;
58 : :
59 : : TAILQ_ENTRY(nbd_io) tailq;
60 : : };
61 : :
62 : : struct spdk_nbd_disk {
63 : : struct spdk_bdev *bdev;
64 : : struct spdk_bdev_desc *bdev_desc;
65 : : struct spdk_io_channel *ch;
66 : : int dev_fd;
67 : : char *nbd_path;
68 : : int kernel_sp_fd;
69 : : int spdk_sp_fd;
70 : : struct spdk_poller *nbd_poller;
71 : : struct spdk_interrupt *intr;
72 : : bool interrupt_mode;
73 : : uint32_t buf_align;
74 : :
75 : : struct spdk_poller *retry_poller;
76 : : int retry_count;
77 : : /* Synchronize nbd_start_kernel pthread and nbd_stop */
78 : : bool has_nbd_pthread;
79 : :
80 : : struct nbd_io *io_in_recv;
81 : : TAILQ_HEAD(, nbd_io) received_io_list;
82 : : TAILQ_HEAD(, nbd_io) executed_io_list;
83 : : TAILQ_HEAD(, nbd_io) processing_io_list;
84 : :
85 : : bool is_started;
86 : : bool is_closing;
87 : : /* count of nbd_io in spdk_nbd_disk */
88 : : int io_count;
89 : :
90 : : TAILQ_ENTRY(spdk_nbd_disk) tailq;
91 : : };
92 : :
93 : : struct spdk_nbd_disk_globals {
94 : : TAILQ_HEAD(, spdk_nbd_disk) disk_head;
95 : : };
96 : :
97 : : static struct spdk_nbd_disk_globals g_spdk_nbd;
98 : : static spdk_nbd_fini_cb g_fini_cb_fn;
99 : : static void *g_fini_cb_arg;
100 : :
101 : : static void _nbd_fini(void *arg1);
102 : :
103 : : static int nbd_submit_bdev_io(struct spdk_nbd_disk *nbd, struct nbd_io *io);
104 : : static int nbd_io_recv_internal(struct spdk_nbd_disk *nbd);
105 : :
106 : : int
107 : 1451 : spdk_nbd_init(void)
108 : : {
109 [ + - ]: 1451 : TAILQ_INIT(&g_spdk_nbd.disk_head);
110 : :
111 : 1451 : return 0;
112 : : }
113 : :
114 : : static void
115 : 1451 : _nbd_fini(void *arg1)
116 : : {
117 : : struct spdk_nbd_disk *nbd, *nbd_tmp;
118 : :
119 [ + + # # : 1451 : TAILQ_FOREACH_SAFE(nbd, &g_spdk_nbd.disk_head, tailq, nbd_tmp) {
# # # # -
+ ]
120 [ # # # # : 0 : if (!nbd->is_closing) {
# # # # ]
121 : 0 : spdk_nbd_stop(nbd);
122 : 0 : }
123 : 0 : }
124 : :
125 : : /* Check if all nbds closed */
126 [ + - ]: 1451 : if (!TAILQ_FIRST(&g_spdk_nbd.disk_head)) {
127 [ - + + - ]: 1451 : g_fini_cb_fn(g_fini_cb_arg);
128 : 25 : } else {
129 : 0 : spdk_thread_send_msg(spdk_get_thread(),
130 : : _nbd_fini, NULL);
131 : : }
132 : 1451 : }
133 : :
134 : : void
135 : 1451 : spdk_nbd_fini(spdk_nbd_fini_cb cb_fn, void *cb_arg)
136 : : {
137 : 1451 : g_fini_cb_fn = cb_fn;
138 : 1451 : g_fini_cb_arg = cb_arg;
139 : :
140 : 1451 : _nbd_fini(NULL);
141 : 1451 : }
142 : :
143 : : static int
144 : 486 : nbd_disk_register(struct spdk_nbd_disk *nbd)
145 : : {
146 : : /* Make sure nbd_path is not used in this SPDK app */
147 [ + + + - : 486 : if (nbd_disk_find_by_nbd_path(nbd->nbd_path)) {
+ - ]
148 [ # # # # ]: 0 : SPDK_NOTICELOG("%s is already exported\n", nbd->nbd_path);
149 : 0 : return -EBUSY;
150 : : }
151 : :
152 [ + - + - : 486 : TAILQ_INSERT_TAIL(&g_spdk_nbd.disk_head, nbd, tailq);
+ - + - +
- + - + -
+ - + - +
- + - +
- ]
153 : :
154 : 486 : return 0;
155 : 6 : }
156 : :
157 : : static void
158 : 486 : nbd_disk_unregister(struct spdk_nbd_disk *nbd)
159 : : {
160 : : struct spdk_nbd_disk *nbd_idx, *nbd_tmp;
161 : :
162 : : /*
163 : : * nbd disk may be stopped before registered.
164 : : * check whether it was registered.
165 : : */
166 [ + + + - : 498 : TAILQ_FOREACH_SAFE(nbd_idx, &g_spdk_nbd.disk_head, tailq, nbd_tmp) {
+ - + - -
+ ]
167 [ + + ]: 498 : if (nbd == nbd_idx) {
168 [ + + + - : 486 : TAILQ_REMOVE(&g_spdk_nbd.disk_head, nbd_idx, tailq);
+ - + + +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - ]
169 : 486 : break;
170 : : }
171 : 0 : }
172 : 486 : }
173 : :
174 : : struct spdk_nbd_disk *
175 : 2495 : nbd_disk_find_by_nbd_path(const char *nbd_path)
176 : : {
177 : : struct spdk_nbd_disk *nbd;
178 : :
179 : : /*
180 : : * check whether nbd has already been registered by nbd path.
181 : : */
182 [ + + - + : 7247 : TAILQ_FOREACH(nbd, &g_spdk_nbd.disk_head, tailq) {
- + - + ]
183 [ + + + + : 6275 : if (!strcmp(nbd->nbd_path, nbd_path)) {
+ + + - +
+ ]
184 : 1523 : return nbd;
185 : : }
186 : 6 : }
187 : :
188 : 972 : return NULL;
189 : 24 : }
190 : :
191 : 224 : struct spdk_nbd_disk *nbd_disk_first(void)
192 : : {
193 : 224 : return TAILQ_FIRST(&g_spdk_nbd.disk_head);
194 : : }
195 : :
196 : 358 : struct spdk_nbd_disk *nbd_disk_next(struct spdk_nbd_disk *prev)
197 : : {
198 [ + - + - : 358 : return TAILQ_NEXT(prev, tailq);
+ - ]
199 : : }
200 : :
201 : : const char *
202 : 358 : nbd_disk_get_nbd_path(struct spdk_nbd_disk *nbd)
203 : : {
204 [ + - + - ]: 358 : return nbd->nbd_path;
205 : : }
206 : :
207 : : const char *
208 : 358 : nbd_disk_get_bdev_name(struct spdk_nbd_disk *nbd)
209 : : {
210 [ + - + - ]: 358 : return spdk_bdev_get_name(nbd->bdev);
211 : : }
212 : :
213 : : void
214 : 121 : spdk_nbd_write_config_json(struct spdk_json_write_ctx *w)
215 : : {
216 : : struct spdk_nbd_disk *nbd;
217 : :
218 : 121 : spdk_json_write_array_begin(w);
219 : :
220 [ - + # # : 121 : TAILQ_FOREACH(nbd, &g_spdk_nbd.disk_head, tailq) {
# # # # ]
221 : 0 : spdk_json_write_object_begin(w);
222 : :
223 : 0 : spdk_json_write_named_string(w, "method", "nbd_start_disk");
224 : :
225 : 0 : spdk_json_write_named_object_begin(w, "params");
226 : 0 : spdk_json_write_named_string(w, "nbd_device", nbd_disk_get_nbd_path(nbd));
227 : 0 : spdk_json_write_named_string(w, "bdev_name", nbd_disk_get_bdev_name(nbd));
228 : 0 : spdk_json_write_object_end(w);
229 : :
230 : 0 : spdk_json_write_object_end(w);
231 : 0 : }
232 : :
233 : 121 : spdk_json_write_array_end(w);
234 : 121 : }
235 : :
236 : : void
237 : 485 : nbd_disconnect(struct spdk_nbd_disk *nbd)
238 : : {
239 : : /*
240 : : * nbd soft-disconnection to terminate transmission phase.
241 : : * After receiving this ioctl command, nbd kernel module will send
242 : : * a NBD_CMD_DISC type io to nbd server in order to inform server.
243 : : */
244 [ + - + - : 485 : ioctl(nbd->dev_fd, NBD_DISCONNECT);
+ - - + +
- - + + -
- + + - ]
245 : 485 : }
246 : :
247 : : static struct nbd_io *
248 : 1654424 : nbd_get_io(struct spdk_nbd_disk *nbd)
249 : : {
250 : : struct nbd_io *io;
251 : :
252 : 1654424 : io = calloc(1, sizeof(*io));
253 [ + + ]: 1654424 : if (!io) {
254 : 0 : return NULL;
255 : : }
256 : :
257 [ - + - + ]: 1654424 : io->nbd = nbd;
258 [ - + - + ]: 1654424 : to_be32(&io->resp.magic, NBD_REPLY_MAGIC);
259 : :
260 [ - + - + ]: 1654424 : nbd->io_count++;
261 : :
262 : 1654424 : return io;
263 : 2224 : }
264 : :
265 : : static void
266 : 1654424 : nbd_put_io(struct spdk_nbd_disk *nbd, struct nbd_io *io)
267 : : {
268 [ + + + - : 1654424 : if (io->payload) {
+ + ]
269 [ + - + - ]: 1653402 : spdk_free(io->payload);
270 : 2212 : }
271 : 1654424 : free(io);
272 : :
273 [ + - + - ]: 1654424 : nbd->io_count--;
274 : 1654424 : }
275 : :
276 : : /*
277 : : * Check whether received nbd_io are all executed,
278 : : * and put back executed nbd_io instead of transmitting them
279 : : *
280 : : * \return 1 there is still some nbd_io under executing
281 : : * 0 all nbd_io gotten are freed.
282 : : */
283 : : static int
284 : 487 : nbd_cleanup_io(struct spdk_nbd_disk *nbd)
285 : : {
286 : : /* Try to read the remaining nbd commands in the socket */
287 [ - + ]: 487 : while (nbd_io_recv_internal(nbd) > 0);
288 : :
289 : : /* free io_in_recv */
290 [ + - + - : 487 : if (nbd->io_in_recv != NULL) {
+ - ]
291 [ + - + - ]: 487 : nbd_put_io(nbd, nbd->io_in_recv);
292 [ + - + - ]: 487 : nbd->io_in_recv = NULL;
293 : 6 : }
294 : :
295 : : /*
296 : : * Some nbd_io may be under executing in bdev.
297 : : * Wait for their done operation.
298 : : */
299 [ + + + - : 487 : if (nbd->io_count != 0) {
- + ]
300 : 0 : return 1;
301 : : }
302 : :
303 : 487 : return 0;
304 : 6 : }
305 : :
306 : : static int
307 : 893 : _nbd_stop(void *arg)
308 : : {
309 : 893 : struct spdk_nbd_disk *nbd = arg;
310 : :
311 [ + + + - : 893 : if (nbd->nbd_poller) {
+ + ]
312 [ + - ]: 486 : spdk_poller_unregister(&nbd->nbd_poller);
313 : 6 : }
314 : :
315 [ + + + - : 893 : if (nbd->intr) {
+ - ]
316 [ # # ]: 0 : spdk_interrupt_unregister(&nbd->intr);
317 : 0 : }
318 : :
319 [ + + + - : 893 : if (nbd->spdk_sp_fd >= 0) {
+ + ]
320 [ + - + - ]: 486 : close(nbd->spdk_sp_fd);
321 [ + - + - ]: 486 : nbd->spdk_sp_fd = -1;
322 : 6 : }
323 : :
324 [ + + + - : 893 : if (nbd->kernel_sp_fd >= 0) {
+ + ]
325 [ + - + - ]: 486 : close(nbd->kernel_sp_fd);
326 [ + - + - ]: 486 : nbd->kernel_sp_fd = -1;
327 : 6 : }
328 : :
329 : : /* Continue the stop procedure after the exit of nbd_start_kernel pthread */
330 [ + + + + : 893 : if (nbd->has_nbd_pthread) {
+ - + + ]
331 [ + - + - : 407 : if (nbd->retry_poller == NULL) {
- + ]
332 [ + - + - ]: 407 : nbd->retry_count = NBD_STOP_BUSY_WAITING_MS * 1000ULL / NBD_BUSY_POLLING_INTERVAL_US;
333 [ + - + - ]: 407 : nbd->retry_poller = SPDK_POLLER_REGISTER(_nbd_stop, nbd,
334 : : NBD_BUSY_POLLING_INTERVAL_US);
335 : 407 : return SPDK_POLLER_BUSY;
336 : : }
337 : :
338 [ # # # # : 0 : if (nbd->retry_count-- > 0) {
# # ]
339 : 0 : return SPDK_POLLER_BUSY;
340 : : }
341 : :
342 : 0 : SPDK_ERRLOG("Failed to wait for returning of NBD_DO_IT ioctl.\n");
343 : 0 : }
344 : :
345 [ + + + - : 486 : if (nbd->retry_poller) {
- + ]
346 [ + - ]: 407 : spdk_poller_unregister(&nbd->retry_poller);
347 : 6 : }
348 : :
349 [ + - + - : 486 : if (nbd->dev_fd >= 0) {
- + ]
350 : : /* Clear nbd device only if it is occupied by SPDK app */
351 [ + - + - : 486 : if (nbd->nbd_path && nbd_disk_find_by_nbd_path(nbd->nbd_path)) {
+ - + - +
- + - ]
352 [ + - + - : 486 : ioctl(nbd->dev_fd, NBD_CLEAR_QUE);
+ - - + +
- - + + -
- + + - ]
353 [ + - + - : 486 : ioctl(nbd->dev_fd, NBD_CLEAR_SOCK);
+ - - + +
- - + + -
- + + - ]
354 : 6 : }
355 [ + - + - ]: 486 : close(nbd->dev_fd);
356 : 6 : }
357 : :
358 [ + - + - : 486 : if (nbd->nbd_path) {
- + ]
359 [ + - + - ]: 486 : free(nbd->nbd_path);
360 : 6 : }
361 : :
362 [ + - + - : 486 : if (nbd->ch) {
- + ]
363 [ + - + - ]: 486 : spdk_put_io_channel(nbd->ch);
364 [ + - + - ]: 486 : nbd->ch = NULL;
365 : 6 : }
366 : :
367 [ + - + - : 486 : if (nbd->bdev_desc) {
- + ]
368 [ + - + - ]: 486 : spdk_bdev_close(nbd->bdev_desc);
369 [ + - + - ]: 486 : nbd->bdev_desc = NULL;
370 : 6 : }
371 : :
372 : 486 : nbd_disk_unregister(nbd);
373 : :
374 : 486 : free(nbd);
375 : :
376 : 486 : return 0;
377 : 12 : }
378 : :
379 : : int
380 : 486 : spdk_nbd_stop(struct spdk_nbd_disk *nbd)
381 : : {
382 : 486 : int rc = 0;
383 : :
384 [ + + ]: 486 : if (nbd == NULL) {
385 : 0 : return rc;
386 : : }
387 : :
388 [ + - + - ]: 486 : nbd->is_closing = true;
389 : :
390 : : /* if nbd is not started, it will continue to call nbd stop later */
391 [ + + + + : 486 : if (!nbd->is_started) {
+ - + - ]
392 : 0 : return 1;
393 : : }
394 : :
395 : : /*
396 : : * Stop action should be called only after all nbd_io are executed.
397 : : */
398 : :
399 : 486 : rc = nbd_cleanup_io(nbd);
400 [ + + ]: 486 : if (!rc) {
401 : 486 : _nbd_stop(nbd);
402 : 6 : }
403 : :
404 : 486 : return rc;
405 : 6 : }
406 : :
407 : : static int64_t
408 : 469678198 : nbd_socket_rw(int fd, void *buf, size_t length, bool read_op)
409 : : {
410 : : ssize_t rc;
411 : :
412 [ + + + + ]: 469678198 : if (read_op) {
413 : 467452033 : rc = read(fd, buf, length);
414 : 3546659 : } else {
415 : 2226165 : rc = write(fd, buf, length);
416 : : }
417 : :
418 [ + + ]: 469678198 : if (rc == 0) {
419 : 0 : return -EIO;
420 [ + + ]: 469678198 : } else if (rc == -1) {
421 [ + + - + ]: 464704856 : if (errno != EAGAIN) {
422 [ # # # # ]: 0 : return -errno;
423 : : }
424 : 464704856 : return 0;
425 : : } else {
426 : 4973342 : return rc;
427 : : }
428 : 3549543 : }
429 : :
430 : : static void
431 : 1653452 : nbd_io_done(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
432 : : {
433 : 1653452 : struct nbd_io *io = cb_arg;
434 [ + - + - ]: 1653452 : struct spdk_nbd_disk *nbd = io->nbd;
435 : :
436 [ + + + + ]: 1653452 : if (success) {
437 [ + - + - : 1653384 : io->resp.error = 0;
+ - ]
438 : 2208 : } else {
439 [ + - + - ]: 68 : to_be32(&io->resp.error, EIO);
440 : : }
441 : :
442 [ + - + - : 1653452 : memcpy(&io->resp.handle, &io->req.handle, sizeof(io->resp.handle));
+ - + - +
- + - + -
+ - ]
443 : :
444 : : /* When there begins to have executed_io, enable socket writable notice in order to
445 : : * get it processed in nbd_io_xmit
446 : : */
447 [ + + + + : 1653452 : if (nbd->interrupt_mode && TAILQ_EMPTY(&nbd->executed_io_list)) {
+ - - + #
# # # # #
# # ]
448 [ # # # # ]: 0 : spdk_interrupt_set_event_types(nbd->intr, SPDK_INTERRUPT_EVENT_IN | SPDK_INTERRUPT_EVENT_OUT);
449 : 0 : }
450 : :
451 [ + + + - : 1653452 : TAILQ_REMOVE(&nbd->processing_io_list, io, tailq);
+ - + + +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - ]
452 [ + - + - : 1653452 : TAILQ_INSERT_TAIL(&nbd->executed_io_list, io, tailq);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - ]
453 : :
454 [ + + ]: 1653452 : if (bdev_io != NULL) {
455 : 1653419 : spdk_bdev_free_io(bdev_io);
456 : 2208 : }
457 : 1653452 : }
458 : :
459 : : static void
460 : 0 : nbd_resubmit_io(void *arg)
461 : : {
462 : 0 : struct nbd_io *io = (struct nbd_io *)arg;
463 [ # # # # ]: 0 : struct spdk_nbd_disk *nbd = io->nbd;
464 : 0 : int rc = 0;
465 : :
466 : 0 : rc = nbd_submit_bdev_io(nbd, io);
467 [ # # ]: 0 : if (rc) {
468 [ # # # # : 0 : SPDK_INFOLOG(nbd, "nbd: io resubmit for dev %s , io_type %d, returned %d.\n",
# # # # #
# ]
469 : : nbd_disk_get_bdev_name(nbd), from_be32(&io->req.type), rc);
470 : 0 : }
471 : 0 : }
472 : :
473 : : static void
474 : 0 : nbd_queue_io(struct nbd_io *io)
475 : : {
476 : : int rc;
477 [ # # # # : 0 : struct spdk_bdev *bdev = io->nbd->bdev;
# # # # ]
478 : :
479 [ # # # # : 0 : io->bdev_io_wait.bdev = bdev;
# # ]
480 [ # # # # : 0 : io->bdev_io_wait.cb_fn = nbd_resubmit_io;
# # ]
481 [ # # # # : 0 : io->bdev_io_wait.cb_arg = io;
# # ]
482 : :
483 [ # # # # : 0 : rc = spdk_bdev_queue_io_wait(bdev, io->nbd->ch, &io->bdev_io_wait);
# # # # #
# ]
484 [ # # ]: 0 : if (rc != 0) {
485 : 0 : SPDK_ERRLOG("Queue io failed in nbd_queue_io, rc=%d.\n", rc);
486 : 0 : nbd_io_done(NULL, false, io);
487 : 0 : }
488 : 0 : }
489 : :
490 : : static int
491 : 1653419 : nbd_submit_bdev_io(struct spdk_nbd_disk *nbd, struct nbd_io *io)
492 : : {
493 [ + - + - ]: 1653419 : struct spdk_bdev_desc *desc = nbd->bdev_desc;
494 [ + - + - ]: 1653419 : struct spdk_io_channel *ch = nbd->ch;
495 : 1653419 : int rc = 0;
496 : :
497 [ + + + + : 1653419 : switch (from_be32(&io->req.type)) {
- + + -
- ]
498 : 565415 : case NBD_CMD_READ:
499 [ + - + - : 566759 : rc = spdk_bdev_read(desc, ch, io->payload, from_be64(&io->req.from),
+ - + - ]
500 [ + - + - ]: 566087 : io->payload_size, nbd_io_done, io);
501 : 566087 : break;
502 : 1085746 : case NBD_CMD_WRITE:
503 [ + - + - : 1088818 : rc = spdk_bdev_write(desc, ch, io->payload, from_be64(&io->req.from),
+ - + - ]
504 [ + - + - ]: 1087282 : io->payload_size, nbd_io_done, io);
505 : 1087282 : break;
506 : : #ifdef NBD_FLAG_SEND_FLUSH
507 : 0 : case NBD_CMD_FLUSH:
508 : 0 : rc = spdk_bdev_flush(desc, ch, 0,
509 [ # # # # : 0 : spdk_bdev_get_num_blocks(nbd->bdev) * spdk_bdev_get_block_size(nbd->bdev),
# # # # ]
510 : 0 : nbd_io_done, io);
511 : 0 : break;
512 : : #endif
513 : : #ifdef NBD_FLAG_SEND_TRIM
514 : 50 : case NBD_CMD_TRIM:
515 [ # # # # ]: 50 : rc = spdk_bdev_unmap(desc, ch, from_be64(&io->req.from),
516 [ # # # # ]: 50 : from_be32(&io->req.len), nbd_io_done, io);
517 : 50 : break;
518 : : #endif
519 : 0 : default:
520 : 0 : rc = -1;
521 : 0 : }
522 : :
523 [ + + ]: 1653419 : if (rc < 0) {
524 [ # # ]: 0 : if (rc == -ENOMEM) {
525 [ # # # # : 0 : SPDK_INFOLOG(nbd, "No memory, start to queue io.\n");
# # ]
526 : 0 : nbd_queue_io(io);
527 : 0 : } else {
528 : 0 : SPDK_ERRLOG("nbd io failed in nbd_queue_io, rc=%d.\n", rc);
529 : 0 : nbd_io_done(NULL, false, io);
530 : : }
531 : 0 : }
532 : :
533 : 1653419 : return 0;
534 : : }
535 : :
536 : : static int
537 : 29148113 : nbd_io_exec(struct spdk_nbd_disk *nbd)
538 : : {
539 : : struct nbd_io *io, *io_tmp;
540 : 29148113 : int io_count = 0;
541 : 29148113 : int ret = 0;
542 : :
543 [ + + + - : 30801532 : TAILQ_FOREACH_SAFE(io, &nbd->received_io_list, tailq, io_tmp) {
+ - + + +
- + - + -
+ + ]
544 [ + + + - : 1653419 : TAILQ_REMOVE(&nbd->received_io_list, io, tailq);
+ - + + +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - ]
545 [ + - + - : 1653419 : TAILQ_INSERT_TAIL(&nbd->processing_io_list, io, tailq);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - ]
546 : 1653419 : ret = nbd_submit_bdev_io(nbd, io);
547 [ + + ]: 1653419 : if (ret < 0) {
548 : 0 : return ret;
549 : : }
550 : :
551 [ + - ]: 1653419 : io_count++;
552 : 2208 : }
553 : :
554 : 29148113 : return io_count;
555 : 221573 : }
556 : :
557 : : static int
558 : 466364751 : nbd_io_recv_internal(struct spdk_nbd_disk *nbd)
559 : : {
560 : : struct nbd_io *io;
561 : 466364751 : int ret = 0;
562 : 466364751 : int received = 0;
563 : :
564 [ + + + - : 466364751 : if (nbd->io_in_recv == NULL) {
+ + ]
565 [ + - + - ]: 1654424 : nbd->io_in_recv = nbd_get_io(nbd);
566 [ + + + - : 1654424 : if (!nbd->io_in_recv) {
+ - ]
567 : 0 : return -ENOMEM;
568 : : }
569 : 2224 : }
570 : :
571 [ + - + - ]: 466364751 : io = nbd->io_in_recv;
572 : :
573 [ + + + - : 466364751 : if (io->state == NBD_IO_RECV_REQ) {
+ + ]
574 [ + - + - : 550848308 : ret = nbd_socket_rw(nbd->spdk_sp_fd, (char *)&io->req + io->offset,
+ - + - +
- + - ]
575 [ + - + - ]: 466090327 : sizeof(io->req) - io->offset, true);
576 [ - + ]: 466090327 : if (ret < 0) {
577 : 0 : nbd_put_io(nbd, io);
578 [ # # # # ]: 0 : nbd->io_in_recv = NULL;
579 : 0 : return ret;
580 : : }
581 : :
582 [ + - + - ]: 466090327 : io->offset += ret;
583 : 466090327 : received = ret;
584 : :
585 : : /* request is fully received */
586 [ + + + - : 466090327 : if (io->offset == sizeof(io->req)) {
+ + ]
587 [ + - + - ]: 1653937 : io->offset = 0;
588 : :
589 : : /* req magic check */
590 [ + + + - : 1653937 : if (from_be32(&io->req.magic) != NBD_REQUEST_MAGIC) {
- + ]
591 : 0 : SPDK_ERRLOG("invalid request magic\n");
592 : 0 : nbd_put_io(nbd, io);
593 [ # # # # ]: 0 : nbd->io_in_recv = NULL;
594 : 0 : return -EINVAL;
595 : : }
596 : :
597 [ + + + - : 1653937 : if (from_be32(&io->req.type) == NBD_CMD_DISC) {
+ + ]
598 [ + - + - ]: 485 : nbd->is_closing = true;
599 [ + - + - ]: 485 : nbd->io_in_recv = NULL;
600 [ + + + + : 485 : if (nbd->interrupt_mode && TAILQ_EMPTY(&nbd->executed_io_list)) {
+ - - + #
# # # # #
# # ]
601 [ # # # # ]: 0 : spdk_interrupt_set_event_types(nbd->intr, SPDK_INTERRUPT_EVENT_IN | SPDK_INTERRUPT_EVENT_OUT);
602 : 0 : }
603 : 485 : nbd_put_io(nbd, io);
604 : : /* After receiving NBD_CMD_DISC, nbd will not receive any new commands */
605 : 485 : return received;
606 : : }
607 : :
608 : : /* io except read/write should ignore payload */
609 [ + + + + : 2219622 : if (from_be32(&io->req.type) == NBD_CMD_WRITE ||
+ + + - ]
610 [ + - + - ]: 566170 : from_be32(&io->req.type) == NBD_CMD_READ) {
611 [ + - + - : 1653402 : io->payload_size = from_be32(&io->req.len);
+ - + - ]
612 : 2212 : } else {
613 [ # # # # ]: 50 : io->payload_size = 0;
614 : : }
615 : :
616 : : /* io payload allocate */
617 [ + + + - : 1653452 : if (io->payload_size) {
+ - ]
618 [ + - + - : 1653402 : io->payload = spdk_malloc(io->payload_size, nbd->buf_align, NULL,
+ - + - +
- + - ]
619 : : SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
620 [ + + + - : 1653402 : if (io->payload == NULL) {
+ - ]
621 [ # # # # ]: 0 : SPDK_ERRLOG("could not allocate io->payload of size %d\n", io->payload_size);
622 : 0 : nbd_put_io(nbd, io);
623 [ # # # # ]: 0 : nbd->io_in_recv = NULL;
624 : 0 : return -ENOMEM;
625 : : }
626 : 2212 : } else {
627 [ # # # # ]: 50 : io->payload = NULL;
628 : : }
629 : :
630 : : /* next io step */
631 [ + + + - : 1653452 : if (from_be32(&io->req.type) == NBD_CMD_WRITE) {
+ + ]
632 [ + - + - ]: 1087282 : io->state = NBD_IO_RECV_PAYLOAD;
633 : 1536 : } else {
634 [ + - + - ]: 566170 : io->state = NBD_IO_XMIT_RESP;
635 [ + + + - : 566170 : if (spdk_likely((!nbd->is_closing) && nbd->is_started)) {
+ + + + +
- + - + -
+ + ]
636 [ + - + - : 566137 : TAILQ_INSERT_TAIL(&nbd->received_io_list, io, tailq);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - ]
637 : 672 : } else {
638 [ - + - + : 33 : TAILQ_INSERT_TAIL(&nbd->processing_io_list, io, tailq);
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + ]
639 : 33 : nbd_io_done(NULL, false, io);
640 : : }
641 [ + - + - ]: 566170 : nbd->io_in_recv = NULL;
642 : : }
643 : 2212 : }
644 : 3545114 : }
645 : :
646 [ + + + - : 466364266 : if (io->state == NBD_IO_RECV_PAYLOAD) {
+ + ]
647 [ + - + - : 1361706 : ret = nbd_socket_rw(nbd->spdk_sp_fd, io->payload + io->offset, io->payload_size - io->offset, true);
+ - + - +
- + - + -
+ - + - +
- ]
648 [ + + ]: 1361706 : if (ret < 0) {
649 : 0 : nbd_put_io(nbd, io);
650 [ # # # # ]: 0 : nbd->io_in_recv = NULL;
651 : 0 : return ret;
652 : : }
653 : :
654 [ + - + - ]: 1361706 : io->offset += ret;
655 [ + - ]: 1361706 : received += ret;
656 : :
657 : : /* request payload is fully received */
658 [ + + + - : 1361706 : if (io->offset == io->payload_size) {
+ - + - +
+ ]
659 [ + - + - ]: 1087282 : io->offset = 0;
660 [ + - + - ]: 1087282 : io->state = NBD_IO_XMIT_RESP;
661 [ + + + - : 1087282 : if (spdk_likely((!nbd->is_closing) && nbd->is_started)) {
+ + + + +
- + - + -
- + ]
662 [ + - + - : 1087282 : TAILQ_INSERT_TAIL(&nbd->received_io_list, io, tailq);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - ]
663 : 1536 : } else {
664 [ # # # # : 0 : TAILQ_INSERT_TAIL(&nbd->processing_io_list, io, tailq);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
665 : 0 : nbd_io_done(NULL, false, io);
666 : : }
667 [ + - + - ]: 1087282 : nbd->io_in_recv = NULL;
668 : 1536 : }
669 : :
670 : 1539 : }
671 : :
672 : 466364266 : return received;
673 : 3545123 : }
674 : :
675 : : static int
676 : 29148113 : nbd_io_recv(struct spdk_nbd_disk *nbd)
677 : : {
678 : 29148113 : int i, rc, ret = 0;
679 : :
680 : : /*
681 : : * nbd server should not accept request after closing command
682 : : */
683 [ + + + + : 29148113 : if (nbd->is_closing) {
+ - - + ]
684 : 1 : return 0;
685 : : }
686 : :
687 [ + + + - ]: 495511891 : for (i = 0; i < GET_IO_LOOP_COUNT; i++) {
688 : 466364264 : rc = nbd_io_recv_internal(nbd);
689 [ + + ]: 466364264 : if (rc < 0) {
690 : 0 : return rc;
691 : : }
692 [ + - ]: 466364264 : ret += rc;
693 [ + + + + : 466364264 : if (nbd->is_closing) {
+ - + + ]
694 : 485 : break;
695 : : }
696 : 3545111 : }
697 : :
698 : 29148112 : return ret;
699 : 221573 : }
700 : :
701 : : static int
702 : 1660078 : nbd_io_xmit_internal(struct spdk_nbd_disk *nbd)
703 : : {
704 : : struct nbd_io *io;
705 : 1660078 : int ret = 0;
706 : 1660078 : int sent = 0;
707 : :
708 [ + - + - : 1660078 : io = TAILQ_FIRST(&nbd->executed_io_list);
+ - ]
709 [ - + ]: 1660078 : if (io == NULL) {
710 : 0 : return 0;
711 : : }
712 : :
713 : : /* Remove IO from list now assuming it will be completed. It will be inserted
714 : : * back to the head if it cannot be completed. This approach is specifically
715 : : * taken to work around a scan-build use-after-free mischaracterization.
716 : : */
717 [ + + + - : 1660078 : TAILQ_REMOVE(&nbd->executed_io_list, io, tailq);
+ - + + +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - ]
718 : :
719 : : /* resp error and handler are already set in io_done */
720 : :
721 [ + + + - : 1660078 : if (io->state == NBD_IO_XMIT_RESP) {
- + ]
722 [ + - + - : 1673406 : ret = nbd_socket_rw(nbd->spdk_sp_fd, (char *)&io->resp + io->offset,
+ - + - +
- + - ]
723 [ + - + - ]: 1654182 : sizeof(io->resp) - io->offset, false);
724 [ + + ]: 1654182 : if (ret <= 0) {
725 : 730 : goto reinsert;
726 : : }
727 : :
728 [ + - + - ]: 1653452 : io->offset += ret;
729 : 1653452 : sent = ret;
730 : :
731 : : /* response is fully transmitted */
732 [ + - + - : 1653452 : if (io->offset == sizeof(io->resp)) {
- + ]
733 [ + - + - ]: 1653452 : io->offset = 0;
734 : :
735 : : /* transmit payload only when NBD_CMD_READ with no resp error */
736 [ + + + + : 1653452 : if (from_be32(&io->req.type) != NBD_CMD_READ || io->resp.error != 0) {
+ + + - +
- + - +
+ ]
737 : 1087365 : nbd_put_io(nbd, io);
738 : 1087365 : return 0;
739 : : } else {
740 [ + - + - ]: 566087 : io->state = NBD_IO_XMIT_PAYLOAD;
741 : : }
742 : 672 : }
743 : 672 : }
744 : :
745 [ + - + - : 571983 : if (io->state == NBD_IO_XMIT_PAYLOAD) {
- + ]
746 [ + - + - : 571983 : ret = nbd_socket_rw(nbd->spdk_sp_fd, io->payload + io->offset, io->payload_size - io->offset,
+ - + - +
- + - + -
+ - + - +
- ]
747 : : false);
748 [ + + ]: 571983 : if (ret <= 0) {
749 : 5849 : goto reinsert;
750 : : }
751 : :
752 [ + - + - ]: 566134 : io->offset += ret;
753 [ + - ]: 566134 : sent += ret;
754 : :
755 : : /* read payload is fully transmitted */
756 [ + + + - : 566134 : if (io->offset == io->payload_size) {
+ - + - +
- ]
757 : 566087 : nbd_put_io(nbd, io);
758 : 566087 : return sent;
759 : : }
760 : 0 : }
761 : :
762 : 47 : reinsert:
763 [ + + # # : 6626 : TAILQ_INSERT_HEAD(&nbd->executed_io_list, io, tailq);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
764 [ - + ]: 6626 : return ret < 0 ? ret : sent;
765 : 2212 : }
766 : :
767 : : static int
768 : 29148113 : nbd_io_xmit(struct spdk_nbd_disk *nbd)
769 : : {
770 : 29148113 : int ret = 0;
771 : : int rc;
772 : :
773 [ + + + - : 30808191 : while (!TAILQ_EMPTY(&nbd->executed_io_list)) {
+ - + + ]
774 : 1660078 : rc = nbd_io_xmit_internal(nbd);
775 [ + + ]: 1660078 : if (rc < 0) {
776 : 0 : return rc;
777 : : }
778 : :
779 [ + - ]: 1660078 : ret += rc;
780 : : }
781 : :
782 : : /* When there begins to have no executed_io, disable socket writable notice */
783 [ + + + + : 29148113 : if (nbd->interrupt_mode) {
+ - + - ]
784 [ # # # # ]: 0 : spdk_interrupt_set_event_types(nbd->intr, SPDK_INTERRUPT_EVENT_IN);
785 : 0 : }
786 : :
787 : 29148113 : return ret;
788 : 221573 : }
789 : :
790 : : /**
791 : : * Poll an NBD instance.
792 : : *
793 : : * \return 0 on success or negated errno values on error (e.g. connection closed).
794 : : */
795 : : static int
796 : 29148113 : _nbd_poll(struct spdk_nbd_disk *nbd)
797 : : {
798 : : int received, sent, executed;
799 : :
800 : : /* transmit executed io first */
801 : 29148113 : sent = nbd_io_xmit(nbd);
802 [ + + ]: 29148113 : if (sent < 0) {
803 : 0 : return sent;
804 : : }
805 : :
806 : 29148113 : received = nbd_io_recv(nbd);
807 [ + + ]: 29148113 : if (received < 0) {
808 : 0 : return received;
809 : : }
810 : :
811 : 29148113 : executed = nbd_io_exec(nbd);
812 [ + + ]: 29148113 : if (executed < 0) {
813 : 0 : return executed;
814 : : }
815 : :
816 [ + - + - ]: 29148113 : return sent + received + executed;
817 : 221573 : }
818 : :
819 : : static int
820 : 29148113 : nbd_poll(void *arg)
821 : : {
822 : 29148113 : struct spdk_nbd_disk *nbd = arg;
823 : : int rc;
824 : :
825 : 29148113 : rc = _nbd_poll(nbd);
826 [ + + ]: 29148113 : if (rc < 0) {
827 [ # # # # : 0 : SPDK_INFOLOG(nbd, "nbd_poll() returned %s (%d); closing connection\n",
# # # # ]
828 : : spdk_strerror(-rc), rc);
829 : 0 : _nbd_stop(nbd);
830 : 0 : return SPDK_POLLER_IDLE;
831 : : }
832 [ + + + + : 29148113 : if (nbd->is_closing && nbd->io_count == 0) {
+ - + + +
- + - -
+ ]
833 : 486 : spdk_nbd_stop(nbd);
834 : 6 : }
835 : :
836 : 29148113 : return rc == 0 ? SPDK_POLLER_IDLE : SPDK_POLLER_BUSY;
837 : 221573 : }
838 : :
839 : : struct spdk_nbd_start_ctx {
840 : : struct spdk_nbd_disk *nbd;
841 : : spdk_nbd_start_cb cb_fn;
842 : : void *cb_arg;
843 : : struct spdk_thread *thread;
844 : : };
845 : :
846 : : static void
847 : 486 : nbd_start_complete(void *arg)
848 : : {
849 : 486 : struct spdk_nbd_start_ctx *ctx = arg;
850 : :
851 [ + - + - : 486 : if (ctx->cb_fn) {
+ - ]
852 [ + - + - : 486 : ctx->cb_fn(ctx->cb_arg, ctx->nbd, 0);
- + + - +
- + - + -
+ - ]
853 : 6 : }
854 : :
855 : : /* nbd will possibly receive stop command while initing */
856 [ + - + - : 486 : ctx->nbd->is_started = true;
+ - + - ]
857 : :
858 : 486 : free(ctx);
859 : 486 : }
860 : :
861 : : static void *
862 : 492 : nbd_start_kernel(void *arg)
863 : : {
864 : 492 : struct spdk_nbd_start_ctx *ctx = arg;
865 [ + - + - ]: 492 : struct spdk_nbd_disk *nbd = ctx->nbd;
866 : :
867 : 492 : spdk_unaffinitize_thread();
868 : :
869 : : /* Send a message to complete the start context - this is the
870 : : * latest point we can do it, since the NBD_DO_IT ioctl will
871 : : * block in the kernel.
872 : : */
873 [ + - + - ]: 492 : spdk_thread_send_msg(ctx->thread, nbd_start_complete, ctx);
874 : :
875 : : /* This will block in the kernel until we close the spdk_sp_fd. */
876 [ + - + - : 492 : ioctl(nbd->dev_fd, NBD_DO_IT);
+ - + + +
- + + + -
+ + # # ]
877 : :
878 [ # # # # ]: 480 : nbd->has_nbd_pthread = false;
879 : :
880 [ # # ]: 480 : pthread_exit(NULL);
881 : : }
882 : :
883 : : static void
884 : 1 : nbd_bdev_hot_remove(struct spdk_nbd_disk *nbd)
885 : : {
886 : : struct nbd_io *io, *io_tmp;
887 : :
888 [ # # # # ]: 1 : nbd->is_closing = true;
889 : 1 : nbd_cleanup_io(nbd);
890 : :
891 [ - + # # : 1 : TAILQ_FOREACH_SAFE(io, &nbd->received_io_list, tailq, io_tmp) {
# # # # #
# # # # #
# # ]
892 [ # # # # : 0 : TAILQ_REMOVE(&nbd->received_io_list, io, tailq);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
893 : 0 : nbd_io_done(NULL, false, io);
894 : 0 : }
895 : 1 : }
896 : :
897 : : static void
898 : 2 : nbd_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
899 : : void *event_ctx)
900 : : {
901 [ + + ]: 2 : switch (type) {
902 : 1 : case SPDK_BDEV_EVENT_REMOVE:
903 : 1 : nbd_bdev_hot_remove(event_ctx);
904 : 1 : break;
905 : 1 : default:
906 : 1 : SPDK_NOTICELOG("Unsupported bdev event: type %d\n", type);
907 : 1 : break;
908 : : }
909 : 2 : }
910 : :
911 : : static void
912 : 0 : nbd_poller_set_interrupt_mode(struct spdk_poller *poller, void *cb_arg, bool interrupt_mode)
913 : : {
914 : 0 : struct spdk_nbd_disk *nbd = cb_arg;
915 : :
916 [ # # # # : 0 : nbd->interrupt_mode = interrupt_mode;
# # ]
917 : 0 : }
918 : :
919 : : static void
920 : 486 : nbd_start_continue(struct spdk_nbd_start_ctx *ctx)
921 : : {
922 : : int rc;
923 : 327 : pthread_t tid;
924 : 486 : unsigned long nbd_flags = 0;
925 : :
926 [ + - + - : 486 : rc = ioctl(ctx->nbd->dev_fd, NBD_SET_BLKSIZE, spdk_bdev_get_block_size(ctx->nbd->bdev));
+ - + - +
- - + + -
- + + - -
+ + - + -
+ - + - +
- ]
927 [ + + ]: 486 : if (rc == -1) {
928 [ # # ]: 0 : SPDK_ERRLOG("ioctl(NBD_SET_BLKSIZE) failed: %s\n", spdk_strerror(errno));
929 [ # # # # ]: 0 : rc = -errno;
930 : 0 : goto err;
931 : : }
932 : :
933 [ + - + - : 486 : rc = ioctl(ctx->nbd->dev_fd, NBD_SET_SIZE_BLOCKS, spdk_bdev_get_num_blocks(ctx->nbd->bdev));
+ - + - +
- - + + -
- + + - -
+ + - + -
+ - + - +
- ]
934 [ + + ]: 486 : if (rc == -1) {
935 [ # # ]: 0 : SPDK_ERRLOG("ioctl(NBD_SET_SIZE_BLOCKS) failed: %s\n", spdk_strerror(errno));
936 [ # # # # ]: 0 : rc = -errno;
937 : 0 : goto err;
938 : : }
939 : :
940 : : #ifdef NBD_SET_TIMEOUT
941 [ + - + - : 486 : rc = ioctl(ctx->nbd->dev_fd, NBD_SET_TIMEOUT, NBD_IO_TIMEOUT_S);
+ - + - +
- - + + -
- + + - -
+ + - ]
942 [ + + ]: 486 : if (rc == -1) {
943 [ # # ]: 0 : SPDK_ERRLOG("ioctl(NBD_SET_TIMEOUT) failed: %s\n", spdk_strerror(errno));
944 [ # # # # ]: 0 : rc = -errno;
945 : 0 : goto err;
946 : : }
947 : : #else
948 : : SPDK_NOTICELOG("ioctl(NBD_SET_TIMEOUT) is not supported.\n");
949 : : #endif
950 : :
951 : : #ifdef NBD_FLAG_SEND_FLUSH
952 [ + + + - : 486 : if (spdk_bdev_io_type_supported(ctx->nbd->bdev, SPDK_BDEV_IO_TYPE_FLUSH)) {
+ - + - -
+ ]
953 [ - + + - ]: 375 : nbd_flags |= NBD_FLAG_SEND_FLUSH;
954 : 6 : }
955 : : #endif
956 : : #ifdef NBD_FLAG_SEND_TRIM
957 [ + + + - : 486 : if (spdk_bdev_io_type_supported(ctx->nbd->bdev, SPDK_BDEV_IO_TYPE_UNMAP)) {
+ - + - -
+ ]
958 [ - + + - ]: 437 : nbd_flags |= NBD_FLAG_SEND_TRIM;
959 : 6 : }
960 : : #endif
961 : :
962 [ + + ]: 486 : if (nbd_flags) {
963 [ + - + - : 445 : rc = ioctl(ctx->nbd->dev_fd, NBD_SET_FLAGS, nbd_flags);
+ - + - +
- - + + -
- + + - -
+ + - ]
964 [ + + ]: 445 : if (rc == -1) {
965 [ # # ]: 0 : SPDK_ERRLOG("ioctl(NBD_SET_FLAGS, 0x%lx) failed: %s\n", nbd_flags, spdk_strerror(errno));
966 [ # # # # ]: 0 : rc = -errno;
967 : 0 : goto err;
968 : : }
969 : 6 : }
970 : :
971 [ + - + - : 486 : ctx->nbd->has_nbd_pthread = true;
+ - + - ]
972 [ + - + - ]: 486 : rc = pthread_create(&tid, NULL, nbd_start_kernel, ctx);
973 [ - + ]: 486 : if (rc != 0) {
974 [ # # # # : 0 : ctx->nbd->has_nbd_pthread = false;
# # # # ]
975 : 0 : SPDK_ERRLOG("could not create thread: %s\n", spdk_strerror(rc));
976 [ # # ]: 0 : rc = -rc;
977 : 0 : goto err;
978 : : }
979 : :
980 : 486 : rc = pthread_detach(tid);
981 [ + + ]: 486 : if (rc != 0) {
982 : 0 : SPDK_ERRLOG("could not detach thread for nbd kernel: %s\n", spdk_strerror(rc));
983 [ # # ]: 0 : rc = -rc;
984 : 0 : goto err;
985 : : }
986 : :
987 [ + + ]: 486 : if (spdk_interrupt_mode_is_enabled()) {
988 [ # # # # : 0 : ctx->nbd->intr = SPDK_INTERRUPT_REGISTER(ctx->nbd->spdk_sp_fd, nbd_poll, ctx->nbd);
# # # # #
# # # # #
# # # # #
# ]
989 : 0 : }
990 : :
991 [ + - + - : 486 : ctx->nbd->nbd_poller = SPDK_POLLER_REGISTER(nbd_poll, ctx->nbd, 0);
+ - + - +
- + - ]
992 [ + - + - : 486 : spdk_poller_register_interrupt(ctx->nbd->nbd_poller, nbd_poller_set_interrupt_mode, ctx->nbd);
+ - + - +
- + - ]
993 : 486 : return;
994 : :
995 : 0 : err:
996 [ # # # # ]: 0 : _nbd_stop(ctx->nbd);
997 [ # # # # : 0 : if (ctx->cb_fn) {
# # ]
998 [ # # # # : 0 : ctx->cb_fn(ctx->cb_arg, NULL, rc);
# # # # #
# # # ]
999 : 0 : }
1000 : 0 : free(ctx);
1001 : 6 : }
1002 : :
1003 : : static int
1004 : 486 : nbd_enable_kernel(void *arg)
1005 : : {
1006 : 486 : struct spdk_nbd_start_ctx *ctx = arg;
1007 : : int rc;
1008 : :
1009 : : /* Declare device setup by this process */
1010 [ + - + - : 486 : rc = ioctl(ctx->nbd->dev_fd, NBD_SET_SOCK, ctx->nbd->kernel_sp_fd);
+ - + - +
- - + + -
- + + - -
+ + - + -
+ - + - +
- ]
1011 : :
1012 [ - + ]: 486 : if (rc) {
1013 [ # # # # ]: 0 : if (errno == EBUSY) {
1014 [ # # # # : 0 : if (ctx->nbd->retry_poller == NULL) {
# # # # #
# ]
1015 [ # # # # : 0 : ctx->nbd->retry_count = NBD_START_BUSY_WAITING_MS * 1000ULL / NBD_BUSY_POLLING_INTERVAL_US;
# # # # ]
1016 [ # # # # : 0 : ctx->nbd->retry_poller = SPDK_POLLER_REGISTER(nbd_enable_kernel, ctx,
# # # # ]
1017 : : NBD_BUSY_POLLING_INTERVAL_US);
1018 : 0 : return SPDK_POLLER_BUSY;
1019 [ # # # # : 0 : } else if (ctx->nbd->retry_count-- > 0) {
# # # # #
# ]
1020 : : /* Repeatedly unregister and register retry poller to avoid scan-build error */
1021 [ # # # # : 0 : spdk_poller_unregister(&ctx->nbd->retry_poller);
# # ]
1022 [ # # # # : 0 : ctx->nbd->retry_poller = SPDK_POLLER_REGISTER(nbd_enable_kernel, ctx,
# # # # ]
1023 : : NBD_BUSY_POLLING_INTERVAL_US);
1024 : 0 : return SPDK_POLLER_BUSY;
1025 : : }
1026 : 0 : }
1027 : :
1028 [ # # ]: 0 : SPDK_ERRLOG("ioctl(NBD_SET_SOCK) failed: %s\n", spdk_strerror(errno));
1029 [ # # # # : 0 : if (ctx->nbd->retry_poller) {
# # # # #
# ]
1030 [ # # # # : 0 : spdk_poller_unregister(&ctx->nbd->retry_poller);
# # ]
1031 : 0 : }
1032 : :
1033 [ # # # # ]: 0 : _nbd_stop(ctx->nbd);
1034 : :
1035 [ # # # # : 0 : if (ctx->cb_fn) {
# # ]
1036 [ # # # # : 0 : ctx->cb_fn(ctx->cb_arg, NULL, -errno);
# # # # #
# # # # #
# # ]
1037 : 0 : }
1038 : :
1039 : 0 : free(ctx);
1040 : 0 : return SPDK_POLLER_BUSY;
1041 : : }
1042 : :
1043 [ + + + - : 486 : if (ctx->nbd->retry_poller) {
+ - + - +
- ]
1044 [ # # # # : 0 : spdk_poller_unregister(&ctx->nbd->retry_poller);
# # ]
1045 : 0 : }
1046 : :
1047 : 486 : nbd_start_continue(ctx);
1048 : :
1049 : 486 : return SPDK_POLLER_BUSY;
1050 : 6 : }
1051 : :
1052 : : void
1053 : 486 : spdk_nbd_start(const char *bdev_name, const char *nbd_path,
1054 : : spdk_nbd_start_cb cb_fn, void *cb_arg)
1055 : : {
1056 : 486 : struct spdk_nbd_start_ctx *ctx = NULL;
1057 : 486 : struct spdk_nbd_disk *nbd = NULL;
1058 : : struct spdk_bdev *bdev;
1059 : : int rc;
1060 : 327 : int sp[2];
1061 : :
1062 : 486 : nbd = calloc(1, sizeof(*nbd));
1063 [ + + ]: 486 : if (nbd == NULL) {
1064 : 0 : rc = -ENOMEM;
1065 : 0 : goto err;
1066 : : }
1067 : :
1068 [ + - + - ]: 486 : nbd->dev_fd = -1;
1069 [ + - + - ]: 486 : nbd->spdk_sp_fd = -1;
1070 [ + - + - ]: 486 : nbd->kernel_sp_fd = -1;
1071 : :
1072 : 486 : ctx = calloc(1, sizeof(*ctx));
1073 [ + + ]: 486 : if (ctx == NULL) {
1074 : 0 : rc = -ENOMEM;
1075 : 0 : goto err;
1076 : : }
1077 : :
1078 [ + - + - ]: 486 : ctx->nbd = nbd;
1079 [ + - + - ]: 486 : ctx->cb_fn = cb_fn;
1080 [ + - + - ]: 486 : ctx->cb_arg = cb_arg;
1081 [ + - + - ]: 486 : ctx->thread = spdk_get_thread();
1082 : :
1083 [ + - ]: 486 : rc = spdk_bdev_open_ext(bdev_name, true, nbd_bdev_event_cb, nbd, &nbd->bdev_desc);
1084 [ - + ]: 486 : if (rc != 0) {
1085 : 0 : SPDK_ERRLOG("could not open bdev %s, error=%d\n", bdev_name, rc);
1086 : 0 : goto err;
1087 : : }
1088 : :
1089 [ + - + - ]: 486 : bdev = spdk_bdev_desc_get_bdev(nbd->bdev_desc);
1090 [ + - + - ]: 486 : nbd->bdev = bdev;
1091 : :
1092 [ + - + - : 486 : nbd->ch = spdk_bdev_get_io_channel(nbd->bdev_desc);
+ - + - ]
1093 [ + + + - : 486 : nbd->buf_align = spdk_max(spdk_bdev_get_buf_align(bdev), 64);
+ - ]
1094 : :
1095 : 486 : rc = socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, sp);
1096 [ - + ]: 486 : if (rc != 0) {
1097 : 0 : SPDK_ERRLOG("socketpair failed\n");
1098 [ # # # # ]: 0 : rc = -errno;
1099 : 0 : goto err;
1100 : : }
1101 : :
1102 [ + - + - : 486 : nbd->spdk_sp_fd = sp[0];
+ - + - ]
1103 [ + - + - : 486 : nbd->kernel_sp_fd = sp[1];
+ - + - +
- ]
1104 [ + + + - : 486 : nbd->nbd_path = strdup(nbd_path);
+ - ]
1105 [ + + + - : 486 : if (!nbd->nbd_path) {
- + ]
1106 : 0 : SPDK_ERRLOG("strdup allocation failure\n");
1107 : 0 : rc = -ENOMEM;
1108 : 0 : goto err;
1109 : : }
1110 : :
1111 [ + - + - : 486 : TAILQ_INIT(&nbd->received_io_list);
+ - + - +
- + - + -
+ - ]
1112 [ + - + - : 486 : TAILQ_INIT(&nbd->executed_io_list);
+ - + - +
- + - + -
+ - ]
1113 [ + - + - : 486 : TAILQ_INIT(&nbd->processing_io_list);
+ - + - +
- + - + -
+ - ]
1114 : :
1115 : : /* Add nbd_disk to the end of disk list */
1116 [ + - + - ]: 486 : rc = nbd_disk_register(ctx->nbd);
1117 [ - + ]: 486 : if (rc != 0) {
1118 : 0 : goto err;
1119 : : }
1120 : :
1121 [ + + + - : 486 : nbd->dev_fd = open(nbd_path, O_RDWR | O_DIRECT);
+ - ]
1122 [ + + + - : 486 : if (nbd->dev_fd == -1) {
+ - ]
1123 [ # # ]: 0 : SPDK_ERRLOG("open(\"%s\") failed: %s\n", nbd_path, spdk_strerror(errno));
1124 [ # # # # ]: 0 : rc = -errno;
1125 : 0 : goto err;
1126 : : }
1127 : :
1128 [ + + + + : 486 : SPDK_INFOLOG(nbd, "Enabling kernel access to bdev %s via %s\n",
+ - ]
1129 : : bdev_name, nbd_path);
1130 : :
1131 : 486 : nbd_enable_kernel(ctx);
1132 : 486 : return;
1133 : :
1134 : 0 : err:
1135 : 0 : free(ctx);
1136 [ # # ]: 0 : if (nbd) {
1137 : 0 : _nbd_stop(nbd);
1138 : 0 : }
1139 : :
1140 [ # # ]: 0 : if (cb_fn) {
1141 [ # # # # ]: 0 : cb_fn(cb_arg, NULL, rc);
1142 : 0 : }
1143 : 6 : }
1144 : :
1145 : : const char *
1146 : 486 : spdk_nbd_get_path(struct spdk_nbd_disk *nbd)
1147 : : {
1148 [ + - + - ]: 486 : return nbd->nbd_path;
1149 : : }
1150 : :
1151 : 1519 : SPDK_LOG_REGISTER_COMPONENT(nbd)
|