4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
46 #include <semaphore.h>
49 #include <sys/socket.h>
53 #define NBDKIT_API_VERSION 2
55 #include <nbdkit-plugin.h>
57 #include "ascii-string.h"
58 #include "byte-swapping.h"
60 #include "const-string-vector.h"
63 #if !defined AF_VSOCK || !LIBNBD_HAVE_NBD_CONNECT_VSOCK
70 #pragma clang diagnostic warning "-Wdeprecated-declarations"
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 */
82 nbd_completion_callback cb
;
85 /* The per-connection handle */
87 /* These fields are read-only once initialized */
88 struct nbd_handle
*nbd
;
89 int fds
[2]; /* Pipe for kicking the reader thread */
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
;
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,
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 */
128 static struct handle
*shared_handle
;
130 /* Control TLS settings */
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
);
142 nbdplug_unload (void)
144 if (shared
&& shared_handle
)
145 nbdplug_close_handle (shared_handle
);
147 free (tls_certificates
);
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.
156 nbdplug_config (const char *key
, const char *value
)
160 if (strcmp (key
, "socket") == 0) {
161 /* See FILENAMES AND PATHS in nbdkit-plugin(3) */
163 sockname
= nbdkit_absolute_path (value
);
167 else if (strcmp (key
, "hostname") == 0)
169 else if (strcmp (key
, "port") == 0)
171 else if (strcmp (key
, "vsock") == 0 ||
172 strcmp (key
, "cid") == 0)
174 else if (strcmp (key
, "uri") == 0)
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");
182 else if (strcmp (key
, "socket-fd") == 0) {
183 if (nbdkit_parse_int ("socket-fd", value
, &socket_fd
) == -1)
186 nbdkit_error ("socket-fd must be >= 0");
190 else if (strcmp (key
, "export") == 0)
192 else if (strcmp (key
, "dynamic-export") == 0) {
193 r
= nbdkit_parse_bool (value
);
198 else if (strcmp (key
, "retry") == 0) {
199 if (nbdkit_parse_unsigned ("retry", value
, &retry
) == -1)
202 else if (strcmp (key
, "shared") == 0) {
203 r
= nbdkit_parse_bool (value
);
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
;
214 r
= nbdkit_parse_bool (value
);
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
)
226 else if (strcmp (key
, "tls-verify") == 0) {
227 r
= nbdkit_parse_bool (value
);
232 else if (strcmp (key
, "tls-username") == 0)
233 tls_username
= value
;
234 else if (strcmp (key
, "tls-psk") == 0) {
236 tls_psk
= nbdkit_absolute_path (value
);
241 nbdkit_error ("unknown parameter '%s'", key
);
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. */
256 nbdkit_error ("cannot mix Unix ‘socket’, TCP ‘hostname’/‘port’, ‘vsock’, "
257 "‘command’, ‘socket-fd’ and ‘uri’ parameters");
261 nbdkit_error ("exactly one of ‘socket’, ‘hostname’, ‘vsock’, ‘command’, "
262 "‘socket-fd’ and ‘uri’ parameters must be specified");
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 "
274 struct nbd_handle
*nbd
= nbd_create ();
277 nbdkit_error ("%s", nbd_get_error ());
280 if (!nbd_supports_uri (nbd
)) {
281 nbdkit_error ("libnbd was compiled without uri support");
288 struct sockaddr_un sock
;
290 if (strlen (sockname
) > sizeof sock
.sun_path
) {
291 nbdkit_error ("socket file name too large");
301 nbdkit_error ("libnbd was compiled without vsock support");
306 if (nbdkit_parse_uint32_t ("vsock_cid", raw_cid
, &cid
) == -1 ||
307 nbdkit_parse_uint32_t ("port", port
, &vport
) == -1)
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");
319 else if (socket_fd
>= 0) {
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
) {
332 nbdkit_error ("cannot mix 'dynamic-export' with explicit export name");
336 nbdkit_error ("cannot use 'dynamic-export' with shared connection");
339 #if !LIBNBD_HAVE_NBD_SET_OPT_MODE
341 nbdkit_error ("libnbd too old to support 'dynamic-export' with uri "
350 /* Check the other parameters. */
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 ();
358 nbdkit_error ("%s", nbd_get_error ());
361 if (!nbd_supports_tls (nbd
)) {
362 nbdkit_error ("libnbd was compiled without tls support");
371 /* Create the shared connection. Because this may create a background
372 * thread it must be done after we fork.
375 nbdplug_after_fork (void)
377 if (shared
&& (shared_handle
= nbdplug_open_handle (false, NULL
)) == NULL
)
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" \
403 nbdplug_dump_plugin (void)
405 struct nbd_handle
*nbd
= nbd_create ();
408 nbdkit_error ("%s", nbd_get_error ());
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");
418 printf ("libnbd_dynamic_list=0\n");
423 #define THREAD_MODEL NBDKIT_THREAD_MODEL_PARALLEL
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
)) {
436 struct pollfd fds
[2] = {
437 [0].fd
= nbd_aio_get_fd (h
->nbd
),
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");
455 dir
= nbd_aio_get_direction (h
->nbd
);
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
);
463 nbdkit_error ("%s", nbd_get_error ());
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");
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");
486 /* Callback used at end of a transaction. */
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
496 if (nbd_debug_verbose
)
497 nbdkit_debug ("cookie %" PRId64
" completed state machine, status %d",
498 trans
->cookie
, *error
);
500 if (sem_post (&trans
->sem
)) {
501 nbdkit_error ("failed to post semaphore: %m");
507 /* Prepare for a transaction. */
509 nbdplug_prepare (struct transaction
*trans
)
511 memset (trans
, 0, sizeof *trans
);
512 if (sem_init (&trans
->sem
, 0, 0))
514 trans
->cb
.callback
= nbdplug_notify
;
515 trans
->cb
.user_data
= trans
;
518 /* Register a cookie and kick the I/O thread. */
520 nbdplug_register (struct handle
*h
, struct transaction
*trans
, int64_t cookie
)
525 nbdkit_error ("%s", nbd_get_error ());
526 trans
->early_err
= nbd_get_errno ();
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. */
540 nbdplug_reply (struct handle
*h
, struct transaction
*trans
)
544 if (trans
->early_err
)
545 err
= trans
->early_err
;
547 while ((err
= sem_wait (&trans
->sem
)) == -1 && errno
== EINTR
)
550 nbdkit_debug ("failed to wait on semaphore: %m");
556 if (sem_destroy (&trans
->sem
))
562 /* Move an nbd handle from created to negotiating/ready. Error reporting
563 * is left to the caller.
566 nbdplug_connect (struct nbd_handle
*nbd
)
568 if (tls_certificates
&&
569 nbd_set_tls_certificates (nbd
, tls_certificates
) == -1)
571 if (tls_verify
>= 0 && nbd_set_tls_verify_peer (nbd
, tls_verify
) == -1)
573 if (tls_username
&& nbd_set_tls_username (nbd
, tls_username
) == -1)
575 if (tls_psk
&& nbd_set_tls_psk_file (nbd
, tls_psk
) == -1)
578 return nbd_connect_uri (nbd
, uri
);
580 return nbd_connect_unix (nbd
, sockname
);
582 return nbd_connect_tcp (nbd
, hostname
, port
);
587 return nbd_connect_vsock (nbd
, cid
, vport
);
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
);
597 /* Create the shared or per-connection handle. */
598 static struct handle
*
599 nbdplug_open_handle (int readonly
, const char *client_export
)
602 unsigned long retries
= retry
;
604 h
= calloc (1, sizeof *h
);
606 nbdkit_error ("malloc: %m");
610 if (pipe2 (h
->fds
, O_NONBLOCK
)) {
611 nbdkit_error ("pipe2: %m");
616 /* This plugin doesn't fork, so we don't care about CLOEXEC. Our use
617 * of pipe2 is merely for convenience.
620 nbdkit_error ("pipe: %m");
624 if (set_nonblock (h
->fds
[0]) == -1) {
629 if (set_nonblock (h
->fds
[1]) == -1) {
637 assert (client_export
);
639 client_export
= export
;
642 h
->nbd
= nbd_create ();
645 if (nbd_set_export_name (h
->nbd
, client_export
) == -1)
647 if (nbd_add_meta_context (h
->nbd
, LIBNBD_CONTEXT_BASE_ALLOCATION
) == -1)
649 #if LIBNBD_HAVE_NBD_SET_FULL_INFO
650 if (nbd_set_full_info (h
->nbd
, 1) == -1)
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)
662 if (dynamic_export
&& uri
) {
663 #if LIBNBD_HAVE_NBD_SET_OPT_MODE
664 if (nbd_set_opt_mode (h
->nbd
, 1) == -1)
667 abort (); /* Prevented by .config_complete */
670 if (nbd_set_tls (h
->nbd
, tls
) == -1)
672 if (nbdplug_connect (h
->nbd
) == -1) {
674 nbdkit_debug ("connect failed; will try again: %s", nbd_get_error ());
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)
687 if (nbd_opt_go (h
->nbd
) == -1)
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");
704 nbdkit_error ("%s", nbd_get_error ());
714 #if LIBNBD_HAVE_NBD_OPT_LIST
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 ());
724 #endif /* LIBNBD_HAVE_NBD_OPT_LIST */
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 ();
737 if (nbd_set_opt_mode (nbd
, 1) == -1)
739 if (nbdplug_connect (nbd
) == -1)
741 if (nbd_opt_list (nbd
, (nbd_list_callback
) { .callback
= collect_one
,
742 .user_data
= exports
}) == -1)
747 nbdkit_error ("%s", nbd_get_error ());
749 if (nbd_aio_is_negotiating (nbd
))
751 else if (nbd_aio_is_ready (nbd
))
752 nbd_shutdown (nbd
, 0);
758 return nbdkit_use_default_export (exports
);
761 /* Canonical name of default export. */
763 nbdplug_default_export (int readonly
, int is_tls
)
765 const char *ret
= "";
766 CLEANUP_FREE
char *name
= NULL
;
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 ();
779 if (nbd_set_full_info (nbd
, 1) == -1)
781 if (nbd_set_opt_mode (nbd
, 1) == -1)
783 if (nbdplug_connect (nbd
) == -1)
785 if (nbd_set_export_name (nbd
, "") == -1)
787 if (nbd_opt_info (nbd
) == -1)
789 name
= nbd_get_canonical_export_name (nbd
);
791 ret
= nbdkit_strdup_intern (name
);
794 if (nbd_aio_is_negotiating (nbd
))
796 else if (nbd_aio_is_ready (nbd
))
797 nbd_shutdown (nbd
, 0);
803 /* Create the per-connection handle. */
805 nbdplug_open (int readonly
)
808 return shared_handle
;
809 return nbdplug_open_handle (readonly
, nbdkit_export_name ());
812 /* Free up the shared or per-connection handle. */
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");
826 /* Free up the per-connection handle. */
828 nbdplug_close (void *handle
)
830 struct handle
*h
= handle
;
833 nbdplug_close_handle (h
);
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
);
844 return nbdkit_strdup_intern (desc
);
849 /* Get the file size. */
851 nbdplug_get_size (void *handle
)
853 struct handle
*h
= handle
;
854 int64_t size
= nbd_get_size (h
->nbd
);
857 nbdkit_error ("%s", nbd_get_error ());
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
;
871 r
= nbd_get_block_size (h
->nbd
, LIBNBD_SIZE_MINIMUM
);
873 nbdkit_error ("%s", nbd_get_error ());
878 if (r
> UINT32_MAX
) {
879 nbdkit_error ("nbd_get_block_size: LIBNBD_SIZE_MINIMUM: "
880 "value out of range");
885 r
= nbd_get_block_size (h
->nbd
, LIBNBD_SIZE_PREFERRED
);
887 nbdkit_error ("%s", nbd_get_error ());
892 if (r
> UINT32_MAX
) {
893 nbdkit_error ("nbd_get_block_size: LIBNBD_SIZE_PREFERRED: "
894 "value out of range");
899 r
= nbd_get_block_size (h
->nbd
, LIBNBD_SIZE_MAXIMUM
);
901 nbdkit_error ("%s", nbd_get_error ());
906 if (r
> UINT32_MAX
) {
907 nbdkit_error ("nbd_get_block_size: LIBNBD_SIZE_MAXIMUM: "
908 "value out of range");
915 #else /* !LIBNBD_HAVE_NBD_GET_BLOCK_SIZE */
920 /* We reach here if there was no error, but there was insufficient
921 * information about block size constraints.
923 *minimum
= *preferred
= *maximum
= 0;
928 nbdplug_can_write (void *handle
)
930 struct handle
*h
= handle
;
931 int i
= nbd_is_read_only (h
->nbd
);
934 nbdkit_error ("%s", nbd_get_error ());
937 return !(i
|| h
->readonly
);
941 nbdplug_can_flush (void *handle
)
943 struct handle
*h
= handle
;
944 int i
= nbd_can_flush (h
->nbd
);
947 nbdkit_error ("%s", nbd_get_error ());
954 nbdplug_is_rotational (void *handle
)
956 struct handle
*h
= handle
;
957 int i
= nbd_is_rotational (h
->nbd
);
960 nbdkit_error ("%s", nbd_get_error ());
967 nbdplug_can_trim (void *handle
)
969 struct handle
*h
= handle
;
970 int i
= nbd_can_trim (h
->nbd
);
973 nbdkit_error ("%s", nbd_get_error ());
980 nbdplug_can_zero (void *handle
)
982 struct handle
*h
= handle
;
983 int i
= nbd_can_zero (h
->nbd
);
986 nbdkit_error ("%s", nbd_get_error ());
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
);
1000 nbdkit_error ("%s", nbd_get_error ());
1005 /* libnbd 0.9.8 lacks fast zero support */
1011 nbdplug_can_fua (void *handle
)
1013 struct handle
*h
= handle
;
1014 int i
= nbd_can_fua (h
->nbd
);
1017 nbdkit_error ("%s", nbd_get_error ());
1020 return i
? NBDKIT_FUA_NATIVE
: NBDKIT_FUA_NONE
;
1024 nbdplug_can_multi_conn (void *handle
)
1026 struct handle
*h
= handle
;
1027 int i
= nbd_can_multi_conn (h
->nbd
);
1030 nbdkit_error ("%s", nbd_get_error ());
1037 nbdplug_can_cache (void *handle
)
1039 struct handle
*h
= handle
;
1040 int i
= nbd_can_cache (h
->nbd
);
1043 nbdkit_error ("%s", nbd_get_error ());
1046 return i
? NBDKIT_CACHE_NATIVE
: NBDKIT_CACHE_NONE
;
1050 nbdplug_can_extents (void *handle
)
1052 struct handle
*h
= handle
;
1053 int i
= nbd_can_meta_context (h
->nbd
, LIBNBD_CONTEXT_BASE_ALLOCATION
);
1056 nbdkit_error ("%s", nbd_get_error ());
1062 /* Read data from the file. */
1064 nbdplug_pread (void *handle
, void *buf
, uint32_t count
, uint64_t offset
,
1067 struct handle
*h
= handle
;
1068 struct transaction s
;
1071 nbdplug_prepare (&s
);
1072 nbdplug_register (h
, &s
, nbd_aio_pread (h
->nbd
, buf
, count
, offset
,
1074 return nbdplug_reply (h
, &s
);
1077 /* Write data to the file. */
1079 nbdplug_pwrite (void *handle
, const void *buf
, uint32_t count
, uint64_t offset
,
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
,
1090 return nbdplug_reply (h
, &s
);
1093 /* Write zeroes to the file. */
1095 nbdplug_zero (void *handle
, uint32_t count
, uint64_t offset
, uint32_t flags
)
1097 struct handle
*h
= handle
;
1098 struct transaction s
;
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
;
1112 assert (!(flags
& NBDKIT_FLAG_FAST_ZERO
));
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. */
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. */
1135 nbdplug_flush (void *handle
, uint32_t flags
)
1137 struct handle
*h
= handle
;
1138 struct transaction s
;
1141 nbdplug_prepare (&s
);
1142 nbdplug_register (h
, &s
, nbd_aio_flush (h
->nbd
, s
.cb
, 0));
1143 return nbdplug_reply (h
, &s
);
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) {
1160 offset
+= entries
[0];
1167 /* Read extents of the file. */
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
,
1181 return nbdplug_reply (h
, &s
);
1184 /* Cache a portion of the file. */
1186 nbdplug_cache (void *handle
, uint32_t count
, uint64_t offset
, uint32_t flags
)
1188 struct handle
*h
= handle
;
1189 struct transaction s
;
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
= {
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
)