Update Red Hat Copyright Notices
[nbdkit.git] / plugins / blkio / blkio.c
blobd589664ddf55984c798649bd2fad2c596687db29
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 <stdio.h>
36 #include <stdlib.h>
37 #include <stdbool.h>
39 #include <blkio.h>
41 #define NBDKIT_API_VERSION 2
42 #include <nbdkit-plugin.h>
44 #include "array-size.h"
45 #include "const-string-vector.h"
46 #include "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
55 struct property {
56 const char *name;
57 char *value;
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. */
67 static bool
68 is_preconnect_property (const char *name)
70 static const char *preconnect_props[] = {
71 "can-add-queues", "driver", "fd", "path", "read-only"
73 size_t i;
75 for (i = 0; i < ARRAY_SIZE (preconnect_props); ++i)
76 if (strcmp (name, preconnect_props[i]) == 0)
77 return true;
78 return false;
81 /* Path properties need to be rewritten using nbdkit_absolute_path. */
82 static bool
83 is_path_property (const char *name)
85 static const char *path_props[] = {
86 "path"
88 size_t i;
90 for (i = 0; i < ARRAY_SIZE (path_props); ++i)
91 if (strcmp (name, path_props[i]) == 0)
92 return true;
93 return false;
96 static void
97 bio_unload (void)
99 size_t i;
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. */
110 static int
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");
116 return -1;
118 driver = value;
120 else if (strcmp (key, "get") == 0) {
121 if (const_string_vector_append (&get_params, value) == -1)
122 return -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");
127 return -1;
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)
135 return -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)
142 return -1;
145 return 0;
148 /* Check the user did pass a driver parameter. */
149 static int
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");
155 return -1;
158 return 0;
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."
166 struct handle {
167 struct blkio *b;
168 struct blkio_mem_region mem_region;
171 /* Create the per-connection handle. */
172 static void *
173 bio_open (int readonly)
175 struct handle *h;
176 int r;
177 size_t i;
178 bool b;
180 h = calloc (1, sizeof *h);
181 if (h == NULL) {
182 nbdkit_error ("calloc: %m");
183 return NULL;
186 r = blkio_create (driver, &h->b);
187 if (r < 0) {
188 nbdkit_error ("blkio_create: error opening driver: %s: %s", driver,
189 blkio_get_error_msg ());
190 goto error;
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
200 * read-only".
202 if (readonly) {
203 r = blkio_set_bool (h->b, "read-only", true);
204 if (r < 0) {
205 nbdkit_error ("error setting property: read-only=true: %s",
206 blkio_get_error_msg ());
207 goto error;
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);
217 if (r < 0) {
218 nbdkit_error ("error setting property: %s=%s: %s",
219 prop->name, prop->value,
220 blkio_get_error_msg ());
221 goto error;
226 /* Connect. */
227 r = blkio_connect (h->b);
228 if (r < 0) {
229 nbdkit_error ("blkio_connect: failed to connect to device: %s",
230 blkio_get_error_msg ());
231 goto error;
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);
240 if (r < 0) {
241 nbdkit_error ("error setting property: %s=%s: %s",
242 prop->name, prop->value,
243 blkio_get_error_msg ());
244 goto error;
249 /* Start the block device. */
250 r = blkio_start (h->b);
251 if (r < 0) {
252 nbdkit_error ("blkio_start: failed to start device: %s",
253 blkio_get_error_msg ());
254 goto error;
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];
260 char *value = NULL;
262 if (blkio_get_str (h->b, name, &value) == 0)
263 nbdkit_debug ("get %s = %s", name, value);
264 else
265 nbdkit_debug ("could not get property %s: %m", name);
266 free (value);
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);
274 if (r < 0) {
275 nbdkit_error ("error reading 'needs-mem-regions' property: %s",
276 blkio_get_error_msg ());
277 goto error;
279 if (b) {
280 nbdkit_debug ("driver %s requires a bounce buffer", driver);
282 r = blkio_alloc_mem_region (h->b, &h->mem_region, MAX_BOUNCE_BUFFER);
283 if (r < 0) {
284 nbdkit_error ("blkio_alloc_mem_region: %s", blkio_get_error_msg ());
285 goto error;
287 r = blkio_map_mem_region (h->b, &h->mem_region);
288 if (r < 0) {
289 nbdkit_error ("blkio_map_mem_region: %s", blkio_get_error_msg ());
290 goto error;
294 return h;
296 error:
297 if (h->b)
298 blkio_destroy (&h->b);
299 free (h);
300 return NULL;
303 /* Close the handle. */
304 static void
305 bio_close (void *handle)
307 struct handle *h = handle;
309 blkio_destroy (&h->b);
310 free (h);
313 /* Get the device size. */
314 static int64_t
315 bio_get_size (void *handle)
317 struct handle *h = handle;
318 int r;
319 uint64_t ret;
321 r = blkio_get_uint64 (h->b, "capacity", &ret);
322 if (r < 0) {
323 nbdkit_error ("error reading device capacity: %s",
324 blkio_get_error_msg ());
325 return -1;
328 return ret;
331 /* Block size preferences. */
332 static int
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;
348 return 0;
351 *minimum = request_alignment;
352 *preferred = optimal_io_alignment;
353 *maximum = 0xffffffff;
354 return 0;
357 /* Find out if the connection is writable. */
358 static int
359 bio_can_write (void *handle)
361 struct handle *h = handle;
362 int r;
363 bool ro = true;
365 r = blkio_get_bool (h->b, "read-only", &ro);
366 if (r < 0) {
367 nbdkit_error ("blkio_get_bool: read-only: %s",
368 blkio_get_error_msg ());
369 return -1;
371 return !ro;
374 /* We always support FUA natively. */
375 static int
376 bio_can_fua (void *handle)
378 return NBDKIT_FUA_NATIVE;
381 /* Read data from the device. */
382 static int
383 bio_pread (void *handle, void *buf, uint32_t count, uint64_t offset,
384 uint32_t flags)
386 struct handle *h = handle;
387 int r;
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");
393 return -1;
396 blkioq_read (q, offset, h->mem_region.addr ? : buf, count, NULL, 0);
397 r = blkioq_do_io (q, &completion, 1, 1, NULL);
398 if (r != 1) {
399 nbdkit_error ("blkioq_do_io: %s", blkio_get_error_msg ());
400 return -1;
402 if (completion.ret != 0) {
403 nbdkit_error ("blkioq_do_io: unexpected read completion.ret %d != 0",
404 completion.ret);
405 return -1;
407 if (h->mem_region.addr)
408 memcpy (buf, h->mem_region.addr, count);
410 return 0;
413 /* Write data to the device. */
414 static int
415 bio_pwrite (void *handle, const void *buf, uint32_t count, uint64_t offset,
416 uint32_t flags)
418 const bool fua = flags & NBDKIT_FLAG_FUA;
419 struct handle *h = handle;
420 int r;
421 struct blkioq *q = blkio_get_queue (h->b, 0);
422 struct blkio_completion completion;
423 uint32_t bio_flags;
425 if (h->mem_region.addr && count > MAX_BOUNCE_BUFFER) {
426 nbdkit_error ("request too large for bounce buffer");
427 return -1;
430 bio_flags = 0;
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);
436 if (r != 1) {
437 nbdkit_error ("blkioq_do_io: %s", blkio_get_error_msg ());
438 return -1;
440 if (completion.ret != 0) {
441 nbdkit_error ("blkioq_do_io: unexpected write completion.ret %d != 0",
442 completion.ret);
443 return -1;
446 return 0;
449 /* Flush. */
450 static int
451 bio_flush (void *handle, uint32_t flags)
453 struct handle *h = handle;
454 int r;
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);
460 if (r != 1) {
461 nbdkit_error ("blkioq_do_io: %s", blkio_get_error_msg ());
462 return -1;
464 if (completion.ret != 0) {
465 nbdkit_error ("blkioq_do_io: unexpected flush completion.ret %d != 0",
466 completion.ret);
467 return -1;
470 return 0;
473 /* Write zeroes. */
474 static int
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;
480 int r;
481 struct blkioq *q = blkio_get_queue (h->b, 0);
482 struct blkio_completion completion;
483 uint32_t bio_flags;
485 bio_flags = 0;
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);
491 if (r != 1) {
492 nbdkit_error ("blkioq_do_io: %s", blkio_get_error_msg ());
493 return -1;
495 if (completion.ret != 0) {
496 nbdkit_error ("blkioq_do_io: "
497 "unexpected write zeroes completion.ret %d != 0",
498 completion.ret);
499 return -1;
502 return 0;
505 /* Discard. */
506 static int
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;
511 int r;
512 struct blkioq *q = blkio_get_queue (h->b, 0);
513 struct blkio_completion completion;
514 uint32_t bio_flags;
516 bio_flags = 0;
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);
520 if (r != 1) {
521 nbdkit_error ("blkioq_do_io: %s", blkio_get_error_msg ());
522 return -1;
524 if (completion.ret != 0) {
525 nbdkit_error ("blkioq_do_io: unexpected discard completion.ret %d != 0",
526 completion.ret);
527 return -1;
530 return 0;
533 static struct nbdkit_plugin plugin = {
534 .name = "blkio",
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",
541 .open = bio_open,
542 .close = bio_close,
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,
550 .pread = bio_pread,
551 .pwrite = bio_pwrite,
552 .flush = bio_flush,
553 .zero = bio_zero,
554 .trim = bio_trim,
555 .errno_is_preserved = 0,
558 NBDKIT_REGISTER_PLUGIN (plugin)