Update Red Hat Copyright Notices
[nbdkit.git] / plugins / nbd / nbd.c
blob55a7f289ec242bd8be34ffe2f2fc4c4e4975d31a
1 /* nbdkit
2 * Copyright Red Hat
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of Red Hat nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
33 #include <config.h>
35 #include <stdlib.h>
36 #include <stddef.h>
37 #include <stdbool.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <errno.h>
42 #include <inttypes.h>
43 #include <sys/un.h>
44 #include <assert.h>
45 #include <pthread.h>
46 #include <semaphore.h>
47 #include <poll.h>
48 #include <fcntl.h>
49 #include <sys/socket.h>
51 #include <libnbd.h>
53 #define NBDKIT_API_VERSION 2
55 #include <nbdkit-plugin.h>
57 #include "ascii-string.h"
58 #include "byte-swapping.h"
59 #include "cleanup.h"
60 #include "const-string-vector.h"
61 #include "utils.h"
63 #if !defined AF_VSOCK || !LIBNBD_HAVE_NBD_CONNECT_VSOCK
64 #define USE_VSOCK 0
65 #else
66 #define USE_VSOCK 1
67 #endif
69 #ifdef __APPLE__
70 #pragma clang diagnostic warning "-Wdeprecated-declarations"
71 #endif
73 /* Use '-D nbd.verbose=1' for verbose messages about the state machine. */
74 NBDKIT_DLL_PUBLIC int nbd_debug_verbose = 0;
76 /* The per-transaction details */
77 struct transaction {
78 int64_t cookie;
79 sem_t sem;
80 uint32_t early_err;
81 uint32_t err;
82 nbd_completion_callback cb;
85 /* The per-connection handle */
86 struct handle {
87 /* These fields are read-only once initialized */
88 struct nbd_handle *nbd;
89 int fds[2]; /* Pipe for kicking the reader thread */
90 bool readonly;
91 pthread_t reader;
94 /* Connect to server via URI */
95 static const char *uri;
97 /* Connect to server via absolute name of Unix socket */
98 static char *sockname;
100 /* Connect to server via TCP socket */
101 static const char *hostname;
103 /* Valid with TCP or VSOCK */
104 static const char *port;
106 /* Connect to server via AF_VSOCK socket */
107 static const char *raw_cid;
108 static uint32_t cid;
109 static uint32_t vport;
111 /* Connect to a command. */
112 static const_string_vector command = empty_vector;
114 /* Connect to a socket file descriptor. */
115 static int socket_fd = -1;
117 /* Name of export on remote server, default '', ignored for oldstyle,
118 * NULL if dynamic.
120 static const char *export;
121 static bool dynamic_export;
123 /* Number of retries */
124 static unsigned retry;
126 /* True to share single server connection among all clients */
127 static bool shared;
128 static struct handle *shared_handle;
130 /* Control TLS settings */
131 static int tls = -1;
132 static char *tls_certificates;
133 static int tls_verify = -1;
134 static const char *tls_username;
135 static char *tls_psk;
137 static struct handle *nbdplug_open_handle (int readonly,
138 const char *client_export);
139 static void nbdplug_close_handle (struct handle *h);
141 static void
142 nbdplug_unload (void)
144 if (shared && shared_handle)
145 nbdplug_close_handle (shared_handle);
146 free (sockname);
147 free (tls_certificates);
148 free (tls_psk);
149 free (command.ptr); /* the strings are statically allocated */
152 /* Called for each key=value passed on the command line. See
153 * nbdplug_config_help for the various keys recognized.
155 static int
156 nbdplug_config (const char *key, const char *value)
158 int r;
160 if (strcmp (key, "socket") == 0) {
161 /* See FILENAMES AND PATHS in nbdkit-plugin(3) */
162 free (sockname);
163 sockname = nbdkit_absolute_path (value);
164 if (!sockname)
165 return -1;
167 else if (strcmp (key, "hostname") == 0)
168 hostname = value;
169 else if (strcmp (key, "port") == 0)
170 port = value;
171 else if (strcmp (key, "vsock") == 0 ||
172 strcmp (key, "cid") == 0)
173 raw_cid = value;
174 else if (strcmp (key, "uri") == 0)
175 uri = value;
176 else if (strcmp (key, "command") == 0 || strcmp (key, "arg") == 0) {
177 if (const_string_vector_append (&command, value) == -1) {
178 nbdkit_error ("realloc: %m");
179 return -1;
182 else if (strcmp (key, "socket-fd") == 0) {
183 if (nbdkit_parse_int ("socket-fd", value, &socket_fd) == -1)
184 return -1;
185 if (socket_fd < 0) {
186 nbdkit_error ("socket-fd must be >= 0");
187 return -1;
190 else if (strcmp (key, "export") == 0)
191 export = value;
192 else if (strcmp (key, "dynamic-export") == 0) {
193 r = nbdkit_parse_bool (value);
194 if (r == -1)
195 return -1;
196 dynamic_export = r;
198 else if (strcmp (key, "retry") == 0) {
199 if (nbdkit_parse_unsigned ("retry", value, &retry) == -1)
200 return -1;
202 else if (strcmp (key, "shared") == 0) {
203 r = nbdkit_parse_bool (value);
204 if (r == -1)
205 return -1;
206 shared = r;
208 else if (strcmp (key, "tls") == 0) {
209 if (ascii_strcasecmp (value, "require") == 0 ||
210 ascii_strcasecmp (value, "required") == 0 ||
211 ascii_strcasecmp (value, "force") == 0)
212 tls = LIBNBD_TLS_REQUIRE;
213 else {
214 r = nbdkit_parse_bool (value);
215 if (r == -1)
216 exit (EXIT_FAILURE);
217 tls = r ? LIBNBD_TLS_ALLOW : LIBNBD_TLS_DISABLE;
220 else if (strcmp (key, "tls-certificates") == 0) {
221 free (tls_certificates);
222 tls_certificates = nbdkit_absolute_path (value);
223 if (!tls_certificates)
224 return -1;
226 else if (strcmp (key, "tls-verify") == 0) {
227 r = nbdkit_parse_bool (value);
228 if (r == -1)
229 return -1;
230 tls_verify = r;
232 else if (strcmp (key, "tls-username") == 0)
233 tls_username = value;
234 else if (strcmp (key, "tls-psk") == 0) {
235 free (tls_psk);
236 tls_psk = nbdkit_absolute_path (value);
237 if (!tls_psk)
238 return -1;
240 else {
241 nbdkit_error ("unknown parameter '%s'", key);
242 return -1;
245 return 0;
248 static int
249 nbdplug_config_complete (void)
251 int c = !!sockname + !!hostname + !!uri +
252 (command.len > 0) + (socket_fd >= 0) + !!raw_cid;
254 /* Check the user passed exactly one connection parameter. */
255 if (c > 1) {
256 nbdkit_error ("cannot mix Unix ‘socket’, TCP ‘hostname’/‘port’, ‘vsock’, "
257 "‘command’, ‘socket-fd’ and ‘uri’ parameters");
258 return -1;
260 if (c == 0) {
261 nbdkit_error ("exactly one of ‘socket’, ‘hostname’, ‘vsock’, ‘command’, "
262 "‘socket-fd’ and ‘uri’ parameters must be specified");
263 return -1;
266 /* Port, if present, should only be used with hostname or vsock. */
267 if (port && !(hostname || raw_cid)) {
268 nbdkit_error ("‘port’ parameter should only be used with ‘hostname’ or "
269 "‘vsock’");
270 return -1;
273 if (uri) {
274 struct nbd_handle *nbd = nbd_create ();
276 if (!nbd) {
277 nbdkit_error ("%s", nbd_get_error ());
278 return -1;
280 if (!nbd_supports_uri (nbd)) {
281 nbdkit_error ("libnbd was compiled without uri support");
282 nbd_close (nbd);
283 return -1;
285 nbd_close (nbd);
287 else if (sockname) {
288 struct sockaddr_un sock;
290 if (strlen (sockname) > sizeof sock.sun_path) {
291 nbdkit_error ("socket file name too large");
292 return -1;
295 else if (hostname) {
296 if (!port)
297 port = "10809";
299 else if (raw_cid) {
300 #if !USE_VSOCK
301 nbdkit_error ("libnbd was compiled without vsock support");
302 return -1;
303 #else
304 if (!port)
305 port = "10809";
306 if (nbdkit_parse_uint32_t ("vsock_cid", raw_cid, &cid) == -1 ||
307 nbdkit_parse_uint32_t ("port", port, &vport) == -1)
308 return -1;
309 #endif
311 else if (command.len > 0) {
312 /* Add NULL sentinel to the command. */
313 if (const_string_vector_append (&command, NULL) == -1) {
314 nbdkit_error ("realloc: %m");
315 return -1;
317 shared = true;
319 else if (socket_fd >= 0) {
320 shared = true;
322 else {
323 abort (); /* can't happen, if checks above were correct */
326 /* Can't mix dynamic-export with export or shared (including
327 * connection modes that imply shared). Also, it requires
328 * new-enough libnbd if uri was used.
330 if (dynamic_export) {
331 if (export) {
332 nbdkit_error ("cannot mix 'dynamic-export' with explicit export name");
333 return -1;
335 if (shared) {
336 nbdkit_error ("cannot use 'dynamic-export' with shared connection");
337 return -1;
339 #if !LIBNBD_HAVE_NBD_SET_OPT_MODE
340 if (uri) {
341 nbdkit_error ("libnbd too old to support 'dynamic-export' with uri "
342 "connection");
343 return -1;
345 #endif
347 else if (!export)
348 export = "";
350 /* Check the other parameters. */
351 if (tls == -1)
352 tls = (tls_certificates || tls_verify >= 0 || tls_username || tls_psk)
353 ? LIBNBD_TLS_ALLOW : LIBNBD_TLS_DISABLE;
354 if (tls != LIBNBD_TLS_DISABLE) {
355 struct nbd_handle *nbd = nbd_create ();
357 if (!nbd) {
358 nbdkit_error ("%s", nbd_get_error ());
359 return -1;
361 if (!nbd_supports_tls (nbd)) {
362 nbdkit_error ("libnbd was compiled without tls support");
363 nbd_close (nbd);
364 return -1;
366 nbd_close (nbd);
368 return 0;
371 /* Create the shared connection. Because this may create a background
372 * thread it must be done after we fork.
374 static int
375 nbdplug_after_fork (void)
377 if (shared && (shared_handle = nbdplug_open_handle (false, NULL)) == NULL)
378 return -1;
379 return 0;
382 #define nbdplug_config_help \
383 "[uri=]<URI> URI of an NBD socket to connect to (if supported).\n" \
384 "socket=<SOCKNAME> The Unix socket to connect to.\n" \
385 "hostname=<HOST> The hostname for the TCP socket to connect to.\n" \
386 "port=<PORT> TCP/VSOCK port or service name to use (default 10809).\n" \
387 "vsock=<CID> The cid for the VSOCK socket to connect to.\n" \
388 "command=<COMMAND> Command to run.\n" \
389 "arg=<ARG> Parameters for command.\n" \
390 "socket-fd=<FD> Socket file descriptor to connect to.\n" \
391 "export=<NAME> Export name to connect to (default \"\").\n" \
392 "dynamic-export=<BOOL> True to enable export name pass-through.\n" \
393 "retry=<N> Retry connection up to N seconds (default 0).\n" \
394 "shared=<BOOL> True to share one server connection among all clients,\n" \
395 " rather than a connection per client (default false).\n" \
396 "tls=<MODE> How to use TLS; one of 'off', 'on', or 'require'.\n" \
397 "tls-certificates=<DIR> Directory containing files for X.509 certificates.\n" \
398 "tls-verify=<BOOL> True (default for X.509) to validate server.\n" \
399 "tls-username=<NAME> Override username presented in X.509 TLS.\n" \
400 "tls-psk=<FILE> File containing Pre-Shared Key for TLS.\n" \
402 static void
403 nbdplug_dump_plugin (void)
405 struct nbd_handle *nbd = nbd_create ();
407 if (!nbd) {
408 nbdkit_error ("%s", nbd_get_error ());
409 exit (EXIT_FAILURE);
411 printf ("libnbd_version=%s\n", nbd_get_version (nbd));
412 printf ("libnbd_tls=%d\n", nbd_supports_tls (nbd));
413 printf ("libnbd_uri=%d\n", nbd_supports_uri (nbd));
414 printf ("libnbd_vsock=%d\n", USE_VSOCK);
415 #if LIBNBD_HAVE_NBD_OPT_LIST
416 printf ("libnbd_dynamic_list=1\n");
417 #else
418 printf ("libnbd_dynamic_list=0\n");
419 #endif
420 nbd_close (nbd);
423 #define THREAD_MODEL NBDKIT_THREAD_MODEL_PARALLEL
425 /* Reader loop. */
426 void *
427 nbdplug_reader (void *handle)
429 struct handle *h = handle;
431 if (nbd_debug_verbose)
432 nbdkit_debug ("nbd: started reader thread");
434 while (!nbd_aio_is_dead (h->nbd) && !nbd_aio_is_closed (h->nbd)) {
435 int r;
436 struct pollfd fds[2] = {
437 [0].fd = nbd_aio_get_fd (h->nbd),
438 [1].fd = h->fds[0],
439 [1].events = POLLIN,
441 unsigned dir;
443 dir = nbd_aio_get_direction (h->nbd);
444 if (nbd_debug_verbose)
445 nbdkit_debug ("polling, dir=%d", dir);
446 if (dir & LIBNBD_AIO_DIRECTION_READ)
447 fds[0].events |= POLLIN;
448 if (dir & LIBNBD_AIO_DIRECTION_WRITE)
449 fds[0].events |= POLLOUT;
450 if (poll (fds, 2, -1) == -1) {
451 nbdkit_error ("poll: %m");
452 break;
455 dir = nbd_aio_get_direction (h->nbd);
457 r = 0;
458 if ((dir & LIBNBD_AIO_DIRECTION_READ) && (fds[0].revents & POLLIN))
459 r = nbd_aio_notify_read (h->nbd);
460 else if ((dir & LIBNBD_AIO_DIRECTION_WRITE) && (fds[0].revents & POLLOUT))
461 r = nbd_aio_notify_write (h->nbd);
462 if (r == -1) {
463 nbdkit_error ("%s", nbd_get_error ());
464 break;
467 /* Check if we were kicked because a command was started */
468 if (fds[1].revents & POLLIN) {
469 char buf[10]; /* Larger than 1 to allow reduction of any backlog */
471 if (read (h->fds[0], buf, sizeof buf) == -1 && errno != EAGAIN) {
472 nbdkit_error ("failed to read pipe: %m");
473 break;
478 if (nbd_debug_verbose) {
479 nbdkit_debug ("state machine changed to %s",
480 nbd_connection_state (h->nbd));
481 nbdkit_debug ("exiting reader thread");
483 return NULL;
486 /* Callback used at end of a transaction. */
487 static int
488 nbdplug_notify (void *opaque, int *error)
490 struct transaction *trans = opaque;
492 /* There's a possible race here where trans->cookie has not yet been
493 * updated by nbdplug_register, but it's only an informational
494 * message.
496 if (nbd_debug_verbose)
497 nbdkit_debug ("cookie %" PRId64 " completed state machine, status %d",
498 trans->cookie, *error);
499 trans->err = *error;
500 if (sem_post (&trans->sem)) {
501 nbdkit_error ("failed to post semaphore: %m");
502 abort ();
504 return 1;
507 /* Prepare for a transaction. */
508 static void
509 nbdplug_prepare (struct transaction *trans)
511 memset (trans, 0, sizeof *trans);
512 if (sem_init (&trans->sem, 0, 0))
513 assert (false);
514 trans->cb.callback = nbdplug_notify;
515 trans->cb.user_data = trans;
518 /* Register a cookie and kick the I/O thread. */
519 static void
520 nbdplug_register (struct handle *h, struct transaction *trans, int64_t cookie)
522 char c = 0;
524 if (cookie == -1) {
525 nbdkit_error ("%s", nbd_get_error ());
526 trans->early_err = nbd_get_errno ();
527 return;
530 if (nbd_debug_verbose)
531 nbdkit_debug ("cookie %" PRId64 " started by state machine", cookie);
532 trans->cookie = cookie;
534 if (write (h->fds[1], &c, 1) == -1 && errno != EAGAIN)
535 nbdkit_debug ("failed to kick reader thread: %m");
538 /* Perform the reply half of a transaction. */
539 static int
540 nbdplug_reply (struct handle *h, struct transaction *trans)
542 int err;
544 if (trans->early_err)
545 err = trans->early_err;
546 else {
547 while ((err = sem_wait (&trans->sem)) == -1 && errno == EINTR)
548 /* try again */;
549 if (err) {
550 nbdkit_debug ("failed to wait on semaphore: %m");
551 err = EIO;
553 else
554 err = trans->err;
556 if (sem_destroy (&trans->sem))
557 abort ();
558 errno = err;
559 return err ? -1 : 0;
562 /* Move an nbd handle from created to negotiating/ready. Error reporting
563 * is left to the caller.
565 static int
566 nbdplug_connect (struct nbd_handle *nbd)
568 if (tls_certificates &&
569 nbd_set_tls_certificates (nbd, tls_certificates) == -1)
570 return -1;
571 if (tls_verify >= 0 && nbd_set_tls_verify_peer (nbd, tls_verify) == -1)
572 return -1;
573 if (tls_username && nbd_set_tls_username (nbd, tls_username) == -1)
574 return -1;
575 if (tls_psk && nbd_set_tls_psk_file (nbd, tls_psk) == -1)
576 return -1;
577 if (uri)
578 return nbd_connect_uri (nbd, uri);
579 else if (sockname)
580 return nbd_connect_unix (nbd, sockname);
581 else if (hostname)
582 return nbd_connect_tcp (nbd, hostname, port);
583 else if (raw_cid)
584 #if !USE_VSOCK
585 abort ();
586 #else
587 return nbd_connect_vsock (nbd, cid, vport);
588 #endif
589 else if (command.len > 0)
590 return nbd_connect_systemd_socket_activation (nbd, (char **) command.ptr);
591 else if (socket_fd >= 0)
592 return nbd_connect_socket (nbd, socket_fd);
593 else
594 abort ();
597 /* Create the shared or per-connection handle. */
598 static struct handle *
599 nbdplug_open_handle (int readonly, const char *client_export)
601 struct handle *h;
602 unsigned long retries = retry;
604 h = calloc (1, sizeof *h);
605 if (h == NULL) {
606 nbdkit_error ("malloc: %m");
607 return NULL;
609 #ifdef HAVE_PIPE2
610 if (pipe2 (h->fds, O_NONBLOCK)) {
611 nbdkit_error ("pipe2: %m");
612 free (h);
613 return NULL;
615 #else
616 /* This plugin doesn't fork, so we don't care about CLOEXEC. Our use
617 * of pipe2 is merely for convenience.
619 if (pipe (h->fds)) {
620 nbdkit_error ("pipe: %m");
621 free (h);
622 return NULL;
624 if (set_nonblock (h->fds[0]) == -1) {
625 close (h->fds[1]);
626 free (h);
627 return NULL;
629 if (set_nonblock (h->fds[1]) == -1) {
630 close (h->fds[0]);
631 free (h);
632 return NULL;
634 #endif
636 if (dynamic_export)
637 assert (client_export);
638 else
639 client_export = export;
641 retry:
642 h->nbd = nbd_create ();
643 if (!h->nbd)
644 goto errnbd;
645 if (nbd_set_export_name (h->nbd, client_export) == -1)
646 goto errnbd;
647 if (nbd_add_meta_context (h->nbd, LIBNBD_CONTEXT_BASE_ALLOCATION) == -1)
648 goto errnbd;
649 #if LIBNBD_HAVE_NBD_SET_FULL_INFO
650 if (nbd_set_full_info (h->nbd, 1) == -1)
651 goto errnbd;
652 #endif
653 #if LIBNBD_HAVE_NBD_SET_PREAD_INITIALIZE
654 /* nbdkit guarantees that the buffers passed to our .pread callback
655 * are pre-initialized; and we in turn ensure that the buffer is not
656 * dereferenced if the NBD server replied with an error. Thus, we
657 * are safe opting in to this libnbd speedup.
659 if (nbd_set_pread_initialize (h->nbd, false) == -1)
660 goto errnbd;
661 #endif
662 if (dynamic_export && uri) {
663 #if LIBNBD_HAVE_NBD_SET_OPT_MODE
664 if (nbd_set_opt_mode (h->nbd, 1) == -1)
665 goto errnbd;
666 #else
667 abort (); /* Prevented by .config_complete */
668 #endif
670 if (nbd_set_tls (h->nbd, tls) == -1)
671 goto errnbd;
672 if (nbdplug_connect (h->nbd) == -1) {
673 if (retries--) {
674 nbdkit_debug ("connect failed; will try again: %s", nbd_get_error ());
675 nbd_close (h->nbd);
676 sleep (1);
677 goto retry;
679 goto errnbd;
682 #if LIBNBD_HAVE_NBD_SET_OPT_MODE
683 /* Oldstyle servers can't change export name, but that's okay. */
684 if (uri && dynamic_export && nbd_aio_is_negotiating (h->nbd)) {
685 if (nbd_set_export_name (h->nbd, client_export) == -1)
686 goto errnbd;
687 if (nbd_opt_go (h->nbd) == -1)
688 goto errnbd;
690 #endif
692 if (readonly)
693 h->readonly = true;
695 /* Spawn a dedicated reader thread */
696 if ((errno = pthread_create (&h->reader, NULL, nbdplug_reader, h))) {
697 nbdkit_error ("failed to initialize reader thread: %m");
698 goto err;
701 return h;
703 errnbd:
704 nbdkit_error ("%s", nbd_get_error ());
705 err:
706 close (h->fds[0]);
707 close (h->fds[1]);
708 if (h->nbd)
709 nbd_close (h->nbd);
710 free (h);
711 return NULL;
714 #if LIBNBD_HAVE_NBD_OPT_LIST
715 static int
716 collect_one (void *opaque, const char *name, const char *desc)
718 struct nbdkit_exports *exports = opaque;
720 if (nbdkit_add_export (exports, name, desc) == -1)
721 nbdkit_debug ("unable to share export %s: %s", name, nbd_get_error ());
722 return 0;
724 #endif /* LIBNBD_HAVE_NBD_OPT_LIST */
726 /* Export list. */
727 static int
728 nbdplug_list_exports (int readonly, int is_tls, struct nbdkit_exports *exports)
730 #if LIBNBD_HAVE_NBD_OPT_LIST
731 if (dynamic_export) {
732 struct nbd_handle *nbd = nbd_create ();
733 int r = -1;
735 if (!nbd)
736 goto out;
737 if (nbd_set_opt_mode (nbd, 1) == -1)
738 goto out;
739 if (nbdplug_connect (nbd) == -1)
740 goto out;
741 if (nbd_opt_list (nbd, (nbd_list_callback) { .callback = collect_one,
742 .user_data = exports }) == -1)
743 goto out;
744 r = 0;
745 out:
746 if (r == -1)
747 nbdkit_error ("%s", nbd_get_error ());
748 if (nbd) {
749 if (nbd_aio_is_negotiating (nbd))
750 nbd_opt_abort (nbd);
751 else if (nbd_aio_is_ready (nbd))
752 nbd_shutdown (nbd, 0);
753 nbd_close (nbd);
755 return r;
757 #endif
758 return nbdkit_use_default_export (exports);
761 /* Canonical name of default export. */
762 static const char *
763 nbdplug_default_export (int readonly, int is_tls)
765 const char *ret = "";
766 CLEANUP_FREE char *name = NULL;
768 if (!dynamic_export)
769 return export;
770 #if LIBNBD_HAVE_NBD_SET_FULL_INFO
771 /* Best effort determination of server's canonical name. If it
772 * fails, we're fine using the default name on our end (NBD_OPT_GO
773 * might still work on "" later on).
775 struct nbd_handle *nbd = nbd_create ();
777 if (!nbd)
778 return "";
779 if (nbd_set_full_info (nbd, 1) == -1)
780 goto out;
781 if (nbd_set_opt_mode (nbd, 1) == -1)
782 goto out;
783 if (nbdplug_connect (nbd) == -1)
784 goto out;
785 if (nbd_set_export_name (nbd, "") == -1)
786 goto out;
787 if (nbd_opt_info (nbd) == -1)
788 goto out;
789 name = nbd_get_canonical_export_name (nbd);
790 if (name)
791 ret = nbdkit_strdup_intern (name);
793 out:
794 if (nbd_aio_is_negotiating (nbd))
795 nbd_opt_abort (nbd);
796 else if (nbd_aio_is_ready (nbd))
797 nbd_shutdown (nbd, 0);
798 nbd_close (nbd);
799 #endif
800 return ret;
803 /* Create the per-connection handle. */
804 static void *
805 nbdplug_open (int readonly)
807 if (shared)
808 return shared_handle;
809 return nbdplug_open_handle (readonly, nbdkit_export_name ());
812 /* Free up the shared or per-connection handle. */
813 static void
814 nbdplug_close_handle (struct handle *h)
816 if (nbd_aio_disconnect (h->nbd, 0) == -1)
817 nbdkit_debug ("%s", nbd_get_error ());
818 if ((errno = pthread_join (h->reader, NULL)))
819 nbdkit_debug ("failed to join reader thread: %m");
820 close (h->fds[0]);
821 close (h->fds[1]);
822 nbd_close (h->nbd);
823 free (h);
826 /* Free up the per-connection handle. */
827 static void
828 nbdplug_close (void *handle)
830 struct handle *h = handle;
832 if (!shared)
833 nbdplug_close_handle (h);
836 /* Description. */
837 static const char *
838 nbdplug_export_description (void *handle)
840 #if LIBNBD_HAVE_NBD_GET_EXPORT_DESCRIPTION
841 struct handle *h = handle;
842 CLEANUP_FREE char *desc = nbd_get_export_description (h->nbd);
843 if (desc)
844 return nbdkit_strdup_intern (desc);
845 #endif
846 return NULL;
849 /* Get the file size. */
850 static int64_t
851 nbdplug_get_size (void *handle)
853 struct handle *h = handle;
854 int64_t size = nbd_get_size (h->nbd);
856 if (size == -1) {
857 nbdkit_error ("%s", nbd_get_error ());
858 return -1;
860 return size;
863 static int
864 nbdplug_block_size (void *handle,
865 uint32_t *minimum, uint32_t *preferred, uint32_t *maximum)
867 #ifdef LIBNBD_HAVE_NBD_GET_BLOCK_SIZE
868 struct handle *h = handle;
869 int64_t r;
871 r = nbd_get_block_size (h->nbd, LIBNBD_SIZE_MINIMUM);
872 if (r == -1) {
873 nbdkit_error ("%s", nbd_get_error ());
874 return -1;
876 if (r == 0)
877 goto no_information;
878 if (r > UINT32_MAX) {
879 nbdkit_error ("nbd_get_block_size: LIBNBD_SIZE_MINIMUM: "
880 "value out of range");
881 return -1;
883 *minimum = r;
885 r = nbd_get_block_size (h->nbd, LIBNBD_SIZE_PREFERRED);
886 if (r == -1) {
887 nbdkit_error ("%s", nbd_get_error ());
888 return -1;
890 if (r == 0)
891 goto no_information;
892 if (r > UINT32_MAX) {
893 nbdkit_error ("nbd_get_block_size: LIBNBD_SIZE_PREFERRED: "
894 "value out of range");
895 return -1;
897 *preferred = r;
899 r = nbd_get_block_size (h->nbd, LIBNBD_SIZE_MAXIMUM);
900 if (r == -1) {
901 nbdkit_error ("%s", nbd_get_error ());
902 return -1;
904 if (r == 0)
905 goto no_information;
906 if (r > UINT32_MAX) {
907 nbdkit_error ("nbd_get_block_size: LIBNBD_SIZE_MAXIMUM: "
908 "value out of range");
909 return -1;
911 *maximum = r;
913 return 0;
915 #else /* !LIBNBD_HAVE_NBD_GET_BLOCK_SIZE */
916 goto no_information;
917 #endif
919 no_information:
920 /* We reach here if there was no error, but there was insufficient
921 * information about block size constraints.
923 *minimum = *preferred = *maximum = 0;
924 return 0;
927 static int
928 nbdplug_can_write (void *handle)
930 struct handle *h = handle;
931 int i = nbd_is_read_only (h->nbd);
933 if (i == -1) {
934 nbdkit_error ("%s", nbd_get_error ());
935 return -1;
937 return !(i || h->readonly);
940 static int
941 nbdplug_can_flush (void *handle)
943 struct handle *h = handle;
944 int i = nbd_can_flush (h->nbd);
946 if (i == -1) {
947 nbdkit_error ("%s", nbd_get_error ());
948 return -1;
950 return i;
953 static int
954 nbdplug_is_rotational (void *handle)
956 struct handle *h = handle;
957 int i = nbd_is_rotational (h->nbd);
959 if (i == -1) {
960 nbdkit_error ("%s", nbd_get_error ());
961 return -1;
963 return i;
966 static int
967 nbdplug_can_trim (void *handle)
969 struct handle *h = handle;
970 int i = nbd_can_trim (h->nbd);
972 if (i == -1) {
973 nbdkit_error ("%s", nbd_get_error ());
974 return -1;
976 return i;
979 static int
980 nbdplug_can_zero (void *handle)
982 struct handle *h = handle;
983 int i = nbd_can_zero (h->nbd);
985 if (i == -1) {
986 nbdkit_error ("%s", nbd_get_error ());
987 return -1;
989 return i;
992 static int
993 nbdplug_can_fast_zero (void *handle)
995 #if LIBNBD_HAVE_NBD_CAN_FAST_ZERO
996 struct handle *h = handle;
997 int i = nbd_can_fast_zero (h->nbd);
999 if (i == -1) {
1000 nbdkit_error ("%s", nbd_get_error ());
1001 return -1;
1003 return i;
1004 #else
1005 /* libnbd 0.9.8 lacks fast zero support */
1006 return 0;
1007 #endif
1010 static int
1011 nbdplug_can_fua (void *handle)
1013 struct handle *h = handle;
1014 int i = nbd_can_fua (h->nbd);
1016 if (i == -1) {
1017 nbdkit_error ("%s", nbd_get_error ());
1018 return -1;
1020 return i ? NBDKIT_FUA_NATIVE : NBDKIT_FUA_NONE;
1023 static int
1024 nbdplug_can_multi_conn (void *handle)
1026 struct handle *h = handle;
1027 int i = nbd_can_multi_conn (h->nbd);
1029 if (i == -1) {
1030 nbdkit_error ("%s", nbd_get_error ());
1031 return -1;
1033 return i;
1036 static int
1037 nbdplug_can_cache (void *handle)
1039 struct handle *h = handle;
1040 int i = nbd_can_cache (h->nbd);
1042 if (i == -1) {
1043 nbdkit_error ("%s", nbd_get_error ());
1044 return -1;
1046 return i ? NBDKIT_CACHE_NATIVE : NBDKIT_CACHE_NONE;
1049 static int
1050 nbdplug_can_extents (void *handle)
1052 struct handle *h = handle;
1053 int i = nbd_can_meta_context (h->nbd, LIBNBD_CONTEXT_BASE_ALLOCATION);
1055 if (i == -1) {
1056 nbdkit_error ("%s", nbd_get_error ());
1057 return -1;
1059 return i;
1062 /* Read data from the file. */
1063 static int
1064 nbdplug_pread (void *handle, void *buf, uint32_t count, uint64_t offset,
1065 uint32_t flags)
1067 struct handle *h = handle;
1068 struct transaction s;
1070 assert (!flags);
1071 nbdplug_prepare (&s);
1072 nbdplug_register (h, &s, nbd_aio_pread (h->nbd, buf, count, offset,
1073 s.cb, 0));
1074 return nbdplug_reply (h, &s);
1077 /* Write data to the file. */
1078 static int
1079 nbdplug_pwrite (void *handle, const void *buf, uint32_t count, uint64_t offset,
1080 uint32_t flags)
1082 struct handle *h = handle;
1083 struct transaction s;
1084 uint32_t f = flags & NBDKIT_FLAG_FUA ? LIBNBD_CMD_FLAG_FUA : 0;
1086 assert (!(flags & ~NBDKIT_FLAG_FUA));
1087 nbdplug_prepare (&s);
1088 nbdplug_register (h, &s, nbd_aio_pwrite (h->nbd, buf, count, offset,
1089 s.cb, f));
1090 return nbdplug_reply (h, &s);
1093 /* Write zeroes to the file. */
1094 static int
1095 nbdplug_zero (void *handle, uint32_t count, uint64_t offset, uint32_t flags)
1097 struct handle *h = handle;
1098 struct transaction s;
1099 uint32_t f = 0;
1101 assert (!(flags & ~(NBDKIT_FLAG_FUA | NBDKIT_FLAG_MAY_TRIM |
1102 NBDKIT_FLAG_FAST_ZERO)));
1104 if (!(flags & NBDKIT_FLAG_MAY_TRIM))
1105 f |= LIBNBD_CMD_FLAG_NO_HOLE;
1106 if (flags & NBDKIT_FLAG_FUA)
1107 f |= LIBNBD_CMD_FLAG_FUA;
1108 #if LIBNBD_HAVE_NBD_CAN_FAST_ZERO
1109 if (flags & NBDKIT_FLAG_FAST_ZERO)
1110 f |= LIBNBD_CMD_FLAG_FAST_ZERO;
1111 #else
1112 assert (!(flags & NBDKIT_FLAG_FAST_ZERO));
1113 #endif
1114 nbdplug_prepare (&s);
1115 nbdplug_register (h, &s, nbd_aio_zero (h->nbd, count, offset, s.cb, f));
1116 return nbdplug_reply (h, &s);
1119 /* Trim a portion of the file. */
1120 static int
1121 nbdplug_trim (void *handle, uint32_t count, uint64_t offset, uint32_t flags)
1123 struct handle *h = handle;
1124 struct transaction s;
1125 uint32_t f = flags & NBDKIT_FLAG_FUA ? LIBNBD_CMD_FLAG_FUA : 0;
1127 assert (!(flags & ~NBDKIT_FLAG_FUA));
1128 nbdplug_prepare (&s);
1129 nbdplug_register (h, &s, nbd_aio_trim (h->nbd, count, offset, s.cb, f));
1130 return nbdplug_reply (h, &s);
1133 /* Flush the file to disk. */
1134 static int
1135 nbdplug_flush (void *handle, uint32_t flags)
1137 struct handle *h = handle;
1138 struct transaction s;
1140 assert (!flags);
1141 nbdplug_prepare (&s);
1142 nbdplug_register (h, &s, nbd_aio_flush (h->nbd, s.cb, 0));
1143 return nbdplug_reply (h, &s);
1146 static int
1147 nbdplug_extent (void *opaque, const char *metacontext, uint64_t offset,
1148 uint32_t *entries, size_t nr_entries, int *error)
1150 struct nbdkit_extents *extents = opaque;
1152 assert (strcmp (metacontext, LIBNBD_CONTEXT_BASE_ALLOCATION) == 0);
1153 assert (nr_entries % 2 == 0);
1154 while (nr_entries) {
1155 /* We rely on the fact that NBDKIT_EXTENT_* match NBD_STATE_* */
1156 if (nbdkit_add_extent (extents, offset, entries[0], entries[1]) == -1) {
1157 *error = errno;
1158 return -1;
1160 offset += entries[0];
1161 entries += 2;
1162 nr_entries -= 2;
1164 return 0;
1167 /* Read extents of the file. */
1168 static int
1169 nbdplug_extents (void *handle, uint32_t count, uint64_t offset,
1170 uint32_t flags, struct nbdkit_extents *extents)
1172 struct handle *h = handle;
1173 struct transaction s;
1174 uint32_t f = flags & NBDKIT_FLAG_REQ_ONE ? LIBNBD_CMD_FLAG_REQ_ONE : 0;
1175 nbd_extent_callback extcb = { nbdplug_extent, extents };
1177 assert (!(flags & ~NBDKIT_FLAG_REQ_ONE));
1178 nbdplug_prepare (&s);
1179 nbdplug_register (h, &s, nbd_aio_block_status (h->nbd, count, offset,
1180 extcb, s.cb, f));
1181 return nbdplug_reply (h, &s);
1184 /* Cache a portion of the file. */
1185 static int
1186 nbdplug_cache (void *handle, uint32_t count, uint64_t offset, uint32_t flags)
1188 struct handle *h = handle;
1189 struct transaction s;
1191 assert (!flags);
1192 nbdplug_prepare (&s);
1193 nbdplug_register (h, &s, nbd_aio_cache (h->nbd, count, offset, s.cb, 0));
1194 return nbdplug_reply (h, &s);
1197 static struct nbdkit_plugin plugin = {
1198 .name = "nbd",
1199 .longname = "nbdkit nbd plugin",
1200 .version = PACKAGE_VERSION,
1201 .unload = nbdplug_unload,
1202 .config = nbdplug_config,
1203 .config_complete = nbdplug_config_complete,
1204 .config_help = nbdplug_config_help,
1205 .magic_config_key = "uri",
1206 .after_fork = nbdplug_after_fork,
1207 .dump_plugin = nbdplug_dump_plugin,
1208 .list_exports = nbdplug_list_exports,
1209 .default_export = nbdplug_default_export,
1210 .open = nbdplug_open,
1211 .close = nbdplug_close,
1212 .export_description = nbdplug_export_description,
1213 .get_size = nbdplug_get_size,
1214 .block_size = nbdplug_block_size,
1215 .can_write = nbdplug_can_write,
1216 .can_flush = nbdplug_can_flush,
1217 .is_rotational = nbdplug_is_rotational,
1218 .can_trim = nbdplug_can_trim,
1219 .can_zero = nbdplug_can_zero,
1220 .can_fast_zero = nbdplug_can_fast_zero,
1221 .can_fua = nbdplug_can_fua,
1222 .can_multi_conn = nbdplug_can_multi_conn,
1223 .can_extents = nbdplug_can_extents,
1224 .can_cache = nbdplug_can_cache,
1225 .pread = nbdplug_pread,
1226 .pwrite = nbdplug_pwrite,
1227 .zero = nbdplug_zero,
1228 .flush = nbdplug_flush,
1229 .trim = nbdplug_trim,
1230 .extents = nbdplug_extents,
1231 .cache = nbdplug_cache,
1232 .errno_is_preserved = 1,
1235 NBDKIT_REGISTER_PLUGIN (plugin)