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
41 #define NBDKIT_API_VERSION 2
42 #include <nbdkit-plugin.h>
44 #include "array-size.h"
45 #include "const-string-vector.h"
48 #define MAX_BOUNCE_BUFFER (64 * 1024 * 1024)
50 /* libblkio could do parallel, but we would need to reimplement this
51 * plugin to use the libblkio event model.
53 #define THREAD_MODEL NBDKIT_THREAD_MODEL_SERIALIZE_REQUESTS
58 bool value_needs_free
;
60 DEFINE_VECTOR_TYPE (properties
, struct property
);
62 static const char *driver
= NULL
; /* driver name - required */
63 static properties props
= empty_vector
; /* other command line params */
64 static const_string_vector get_params
= empty_vector
; /* get= parameters */
66 /* XXX Should be possible to query this from libblkio. */
68 is_preconnect_property (const char *name
)
70 static const char *preconnect_props
[] = {
71 "can-add-queues", "driver", "fd", "path", "read-only"
75 for (i
= 0; i
< ARRAY_SIZE (preconnect_props
); ++i
)
76 if (strcmp (name
, preconnect_props
[i
]) == 0)
81 /* Path properties need to be rewritten using nbdkit_absolute_path. */
83 is_path_property (const char *name
)
85 static const char *path_props
[] = {
90 for (i
= 0; i
< ARRAY_SIZE (path_props
); ++i
)
91 if (strcmp (name
, path_props
[i
]) == 0)
101 for (i
= 0; i
< props
.len
; ++i
)
102 if (props
.ptr
[i
].value_needs_free
)
103 free (props
.ptr
[i
].value
);
104 properties_reset (&props
);
106 const_string_vector_reset (&get_params
);
109 /* Called for each key=value passed on the command line. */
111 bio_config (const char *key
, const char *value
)
113 if (strcmp (key
, "driver") == 0) {
114 if (driver
!= NULL
) {
115 nbdkit_error ("'driver' property set more than once");
120 else if (strcmp (key
, "get") == 0) {
121 if (const_string_vector_append (&get_params
, value
) == -1)
124 else if (strcmp (key
, "read-only") == 0) {
125 nbdkit_error ("do not set the libblkio \"read-only\" parameter, "
126 "use the nbdkit -r flag if read-only is required");
129 else if (is_path_property (key
) == 0) {
130 char *path
= nbdkit_absolute_path (value
);
131 struct property prop
= { .name
= key
, .value
= path
,
132 .value_needs_free
= true };
134 if (path
== NULL
|| properties_append (&props
, prop
) == -1)
137 else /* general property */ {
138 struct property prop
= { .name
= key
, .value
= (char *) value
,
139 .value_needs_free
= false };
141 if (properties_append (&props
, prop
) == -1)
148 /* Check the user did pass a driver parameter. */
150 bio_config_complete (void)
152 if (driver
== NULL
) {
153 nbdkit_error ("you must supply the driver=<DRIVER> parameter "
154 "after the plugin name on the command line");
161 #define bio_config_help \
162 "driver=<DRIVER> (required) Driver name (eg. \"nvme-io_uring\").\n" \
163 "PROPERTY=VALUE Set arbitrary libblkio property.\n" \
164 "get=PROPERTY Print property name after connection."
168 struct blkio_mem_region mem_region
;
171 /* Create the per-connection handle. */
173 bio_open (int readonly
)
180 h
= calloc (1, sizeof *h
);
182 nbdkit_error ("calloc: %m");
186 r
= blkio_create (driver
, &h
->b
);
188 nbdkit_error ("blkio_create: error opening driver: %s: %s", driver
,
189 blkio_get_error_msg ());
193 /* If the readonly flag (nbdkit -r) is set, set that property.
194 * However don't change the property otherwise. In can_write below
195 * we will check the final read-only status of the device.
197 * XXX This doesn't work for all drivers. Somehow the user has to
198 * just "know" that a device is read-only (or not) and must set this
199 * property, otherwise libblkio fails to start with error "Device is
203 r
= blkio_set_bool (h
->b
, "read-only", true);
205 nbdkit_error ("error setting property: read-only=true: %s",
206 blkio_get_error_msg ());
211 /* Set the pre-connect properties. */
212 for (i
= 0; i
< props
.len
; ++i
) {
213 const struct property
*prop
= &props
.ptr
[i
];
215 if (is_preconnect_property (prop
->name
)) {
216 r
= blkio_set_str (h
->b
, prop
->name
, prop
->value
);
218 nbdkit_error ("error setting property: %s=%s: %s",
219 prop
->name
, prop
->value
,
220 blkio_get_error_msg ());
227 r
= blkio_connect (h
->b
);
229 nbdkit_error ("blkio_connect: failed to connect to device: %s",
230 blkio_get_error_msg ());
234 /* Set the post-connect properties. */
235 for (i
= 0; i
< props
.len
; ++i
) {
236 const struct property
*prop
= &props
.ptr
[i
];
238 if (! is_preconnect_property (prop
->name
)) {
239 r
= blkio_set_str (h
->b
, prop
->name
, prop
->value
);
241 nbdkit_error ("error setting property: %s=%s: %s",
242 prop
->name
, prop
->value
,
243 blkio_get_error_msg ());
249 /* Start the block device. */
250 r
= blkio_start (h
->b
);
252 nbdkit_error ("blkio_start: failed to start device: %s",
253 blkio_get_error_msg ());
257 /* Print any properties requested on the command line (get=...). */
258 for (i
= 0; i
< get_params
.len
; ++i
) {
259 const char *name
= get_params
.ptr
[i
];
262 if (blkio_get_str (h
->b
, name
, &value
) == 0)
263 nbdkit_debug ("get %s = %s", name
, value
);
265 nbdkit_debug ("could not get property %s: %m", name
);
269 /* If memory regions are required, allocate them using the
270 * convenience functions. Note we allocate one buffer per handle.
271 * It is attached to the handle so blkio_destroy will remove it.
273 r
= blkio_get_bool (h
->b
, "needs-mem-regions", &b
);
275 nbdkit_error ("error reading 'needs-mem-regions' property: %s",
276 blkio_get_error_msg ());
280 nbdkit_debug ("driver %s requires a bounce buffer", driver
);
282 r
= blkio_alloc_mem_region (h
->b
, &h
->mem_region
, MAX_BOUNCE_BUFFER
);
284 nbdkit_error ("blkio_alloc_mem_region: %s", blkio_get_error_msg ());
287 r
= blkio_map_mem_region (h
->b
, &h
->mem_region
);
289 nbdkit_error ("blkio_map_mem_region: %s", blkio_get_error_msg ());
298 blkio_destroy (&h
->b
);
303 /* Close the handle. */
305 bio_close (void *handle
)
307 struct handle
*h
= handle
;
309 blkio_destroy (&h
->b
);
313 /* Get the device size. */
315 bio_get_size (void *handle
)
317 struct handle
*h
= handle
;
321 r
= blkio_get_uint64 (h
->b
, "capacity", &ret
);
323 nbdkit_error ("error reading device capacity: %s",
324 blkio_get_error_msg ());
331 /* Block size preferences. */
333 bio_block_size (void *handle
, uint32_t *minimum
,
334 uint32_t *preferred
, uint32_t *maximum
)
336 struct handle
*h
= handle
;
337 int request_alignment
= 0, optimal_io_alignment
= 0;
339 /* Don't worry if these fail. We also assume 0 for unspecified. */
340 blkio_get_int (h
->b
, "request-alignment", &request_alignment
);
341 blkio_get_int (h
->b
, "optimal-io-alignment", &optimal_io_alignment
);
343 /* Ignore unspecified or bogusly large alignments. */
344 if (request_alignment
<= 0 || request_alignment
> 1024*1024 ||
345 optimal_io_alignment
< 0 ||
346 optimal_io_alignment
> 1024*1024) {
347 *minimum
= *preferred
= *maximum
= 0;
351 *minimum
= request_alignment
;
352 *preferred
= optimal_io_alignment
;
353 *maximum
= 0xffffffff;
357 /* Find out if the connection is writable. */
359 bio_can_write (void *handle
)
361 struct handle
*h
= handle
;
365 r
= blkio_get_bool (h
->b
, "read-only", &ro
);
367 nbdkit_error ("blkio_get_bool: read-only: %s",
368 blkio_get_error_msg ());
374 /* We always support FUA natively. */
376 bio_can_fua (void *handle
)
378 return NBDKIT_FUA_NATIVE
;
381 /* Read data from the device. */
383 bio_pread (void *handle
, void *buf
, uint32_t count
, uint64_t offset
,
386 struct handle
*h
= handle
;
388 struct blkioq
*q
= blkio_get_queue (h
->b
, 0);
389 struct blkio_completion completion
;
391 if (h
->mem_region
.addr
&& count
> MAX_BOUNCE_BUFFER
) {
392 nbdkit_error ("request too large for bounce buffer");
396 blkioq_read (q
, offset
, h
->mem_region
.addr
? : buf
, count
, NULL
, 0);
397 r
= blkioq_do_io (q
, &completion
, 1, 1, NULL
);
399 nbdkit_error ("blkioq_do_io: %s", blkio_get_error_msg ());
402 if (completion
.ret
!= 0) {
403 nbdkit_error ("blkioq_do_io: unexpected read completion.ret %d != 0",
407 if (h
->mem_region
.addr
)
408 memcpy (buf
, h
->mem_region
.addr
, count
);
413 /* Write data to the device. */
415 bio_pwrite (void *handle
, const void *buf
, uint32_t count
, uint64_t offset
,
418 const bool fua
= flags
& NBDKIT_FLAG_FUA
;
419 struct handle
*h
= handle
;
421 struct blkioq
*q
= blkio_get_queue (h
->b
, 0);
422 struct blkio_completion completion
;
425 if (h
->mem_region
.addr
&& count
> MAX_BOUNCE_BUFFER
) {
426 nbdkit_error ("request too large for bounce buffer");
431 if (fua
) bio_flags
|= BLKIO_REQ_FUA
;
432 if (h
->mem_region
.addr
)
433 memcpy (h
->mem_region
.addr
, buf
, count
);
434 blkioq_write (q
, offset
, h
->mem_region
.addr
? : buf
, count
, NULL
, bio_flags
);
435 r
= blkioq_do_io (q
, &completion
, 1, 1, NULL
);
437 nbdkit_error ("blkioq_do_io: %s", blkio_get_error_msg ());
440 if (completion
.ret
!= 0) {
441 nbdkit_error ("blkioq_do_io: unexpected write completion.ret %d != 0",
451 bio_flush (void *handle
, uint32_t flags
)
453 struct handle
*h
= handle
;
455 struct blkioq
*q
= blkio_get_queue (h
->b
, 0);
456 struct blkio_completion completion
;
458 blkioq_flush (q
, NULL
, 0);
459 r
= blkioq_do_io (q
, &completion
, 1, 1, NULL
);
461 nbdkit_error ("blkioq_do_io: %s", blkio_get_error_msg ());
464 if (completion
.ret
!= 0) {
465 nbdkit_error ("blkioq_do_io: unexpected flush completion.ret %d != 0",
475 bio_zero (void *handle
, uint32_t count
, uint64_t offset
, uint32_t flags
)
477 const bool fua
= flags
& NBDKIT_FLAG_FUA
;
478 const bool may_trim
= flags
& NBDKIT_FLAG_MAY_TRIM
;
479 struct handle
*h
= handle
;
481 struct blkioq
*q
= blkio_get_queue (h
->b
, 0);
482 struct blkio_completion completion
;
486 if (fua
) bio_flags
|= BLKIO_REQ_FUA
;
487 if (!may_trim
) bio_flags
|= BLKIO_REQ_NO_UNMAP
;
488 /* XXX Could support forcing fast zeroes too. */
489 blkioq_write_zeroes (q
, offset
, count
, NULL
, bio_flags
);
490 r
= blkioq_do_io (q
, &completion
, 1, 1, NULL
);
492 nbdkit_error ("blkioq_do_io: %s", blkio_get_error_msg ());
495 if (completion
.ret
!= 0) {
496 nbdkit_error ("blkioq_do_io: "
497 "unexpected write zeroes completion.ret %d != 0",
507 bio_trim (void *handle
, uint32_t count
, uint64_t offset
, uint32_t flags
)
509 const bool fua
= flags
& NBDKIT_FLAG_FUA
;
510 struct handle
*h
= handle
;
512 struct blkioq
*q
= blkio_get_queue (h
->b
, 0);
513 struct blkio_completion completion
;
517 if (fua
) bio_flags
|= BLKIO_REQ_FUA
;
518 blkioq_discard (q
, offset
, count
, NULL
, bio_flags
);
519 r
= blkioq_do_io (q
, &completion
, 1, 1, NULL
);
521 nbdkit_error ("blkioq_do_io: %s", blkio_get_error_msg ());
524 if (completion
.ret
!= 0) {
525 nbdkit_error ("blkioq_do_io: unexpected discard completion.ret %d != 0",
533 static struct nbdkit_plugin plugin
= {
535 .version
= PACKAGE_VERSION
,
536 .unload
= bio_unload
,
537 .config
= bio_config
,
538 .config_complete
= bio_config_complete
,
539 .config_help
= bio_config_help
,
540 .magic_config_key
= "driver",
543 .get_size
= bio_get_size
,
544 .block_size
= bio_block_size
,
545 .can_write
= bio_can_write
,
546 .can_flush
= bio_can_write
,
547 .can_trim
= bio_can_write
,
548 .can_zero
= bio_can_write
,
549 .can_fua
= bio_can_fua
,
551 .pwrite
= bio_pwrite
,
555 .errno_is_preserved
= 0,
558 NBDKIT_REGISTER_PLUGIN (plugin
)