Richard W.M. Jones
2018-Aug-01 11:10 UTC
[Libguestfs] [PATCH v2 nbdkit 0/6] Add truncate filter and other fixes.
I have dropped the map filter from this series for now while I try to get it working. However I think the truncate filter is in a good shape. This incorporates all feedback from Eric's review. Also there are three small fixes to the filter code, all revealed when I was testing using multiple filters which we'd not done much of before. Rich.
Richard W.M. Jones
2018-Aug-01 11:10 UTC
[Libguestfs] [PATCH v2 nbdkit 1/6] filters: Call all .prepare and .finalize methods, not just the first one.
These methods are not chained through the next_ops structure, so we must do that work in src/filters.c. This fixes the behaviour of filters when you layer multiple filters in front of a plugin. --- src/filters.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/filters.c b/src/filters.c index 18948bc..67f06d6 100644 --- a/src/filters.c +++ b/src/filters.c @@ -367,10 +367,17 @@ filter_prepare (struct backend *b, struct connection *conn) debug ("prepare"); - if (f->filter.prepare) - return f->filter.prepare (&next_ops, &nxdata, handle); - else - return f->backend.next->prepare (f->backend.next, conn); + /* Call these in order starting from the filter closest to the + * plugin. + */ + if (f->backend.next->prepare (f->backend.next, conn) == -1) + return -1; + + if (f->filter.prepare && + f->filter.prepare (&next_ops, &nxdata, handle) == -1) + return -1; + + return 0; } static int @@ -382,10 +389,14 @@ filter_finalize (struct backend *b, struct connection *conn) debug ("finalize"); - if (f->filter.finalize) - return f->filter.finalize (&next_ops, &nxdata, handle); - else - return f->backend.next->finalize (f->backend.next, conn); + /* Call these in reverse order to .prepare above, starting from the + * filter furthest away from the plugin. + */ + if (f->filter.finalize && + f->filter.finalize (&next_ops, &nxdata, handle) == -1) + return -1; + + return f->backend.next->finalize (f->backend.next, conn); } static int64_t -- 2.18.0
Richard W.M. Jones
2018-Aug-01 11:10 UTC
[Libguestfs] [PATCH v2 nbdkit 2/6] filters: Fix filter.plugin_name method so it returns the name of the plugin.
This function was completely bogus, the effect being that the threadlocal name was always set to the name of the second filter. Also fixes an adjacent comment. --- src/filters.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/filters.c b/src/filters.c index 67f06d6..b68afab 100644 --- a/src/filters.c +++ b/src/filters.c @@ -103,15 +103,15 @@ filter_thread_model (struct backend *b) return thread_model; } -/* These are actually passing through to the final plugin, hence - * the function names. +/* This is actually passing the request through to the final plugin, + * hence the function name. */ static const char * plugin_name (struct backend *b) { struct backend_filter *f = container_of (b, struct backend_filter, backend); - return f->backend.next->name (f->backend.next); + return f->backend.next->plugin_name (f->backend.next); } static const char * -- 2.18.0
Richard W.M. Jones
2018-Aug-01 11:10 UTC
[Libguestfs] [PATCH v2 nbdkit 3/6] filters: Print filter name in debugging messages.
nbdkit_debug implicitly prints the plugin name. However this leads to confusing debug messages such as: nbdkit: pattern[1]: debug: prepare nbdkit: pattern[1]: debug: prepare (in this instance, two different prepare functions were called in different filters, but neither filter name was shown). By printing the filter name in the debug message we improve the output: nbdkit: pattern[1]: debug: truncate: prepare nbdkit: pattern[1]: debug: map: prepare Another example of the improved output is: nbdkit: pattern[1]: debug: truncate: can_flush # filter nbdkit: pattern[1]: debug: map: can_flush # filter nbdkit: pattern[1]: debug: can_flush # plugin --- src/filters.c | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/filters.c b/src/filters.c index b68afab..d0692e1 100644 --- a/src/filters.c +++ b/src/filters.c @@ -76,7 +76,7 @@ filter_free (struct backend *b) */ lock_unload (); - debug ("%s: unload", f->filename); + debug ("%s: unload", f->name); if (f->filter.unload) f->filter.unload (); @@ -172,7 +172,7 @@ filter_config (struct backend *b, const char *key, const char *value) struct backend_filter *f = container_of (b, struct backend_filter, backend); debug ("%s: config key=%s, value=%s", - f->filename, key, value); + f->name, key, value); if (f->filter.config) { if (f->filter.config (next_config, f->backend.next, key, value) == -1) @@ -195,7 +195,7 @@ filter_config_complete (struct backend *b) { struct backend_filter *f = container_of (b, struct backend_filter, backend); - debug ("%s: config_complete", f->filename); + debug ("%s: config_complete", f->name); if (f->filter.config_complete) { if (f->filter.config_complete (next_config_complete, f->backend.next) == -1) @@ -220,7 +220,7 @@ filter_open (struct backend *b, struct connection *conn, int readonly) struct b_conn nxdata = { .b = f->backend.next, .conn = conn }; void *handle; - debug ("%s: open readonly=%d", f->filename, readonly); + debug ("%s: open readonly=%d", f->name, readonly); if (f->filter.open) { handle = f->filter.open (next_open, &nxdata, readonly); @@ -239,7 +239,7 @@ filter_close (struct backend *b, struct connection *conn) struct backend_filter *f = container_of (b, struct backend_filter, backend); void *handle = connection_get_handle (conn, f->backend.i); - debug ("close"); + debug ("%s: close", f->name); if (f->filter.close) f->filter.close (handle); @@ -365,7 +365,7 @@ filter_prepare (struct backend *b, struct connection *conn) void *handle = connection_get_handle (conn, f->backend.i); struct b_conn nxdata = { .b = f->backend.next, .conn = conn }; - debug ("prepare"); + debug ("%s: prepare", f->name); /* Call these in order starting from the filter closest to the * plugin. @@ -387,7 +387,7 @@ filter_finalize (struct backend *b, struct connection *conn) void *handle = connection_get_handle (conn, f->backend.i); struct b_conn nxdata = { .b = f->backend.next, .conn = conn }; - debug ("finalize"); + debug ("%s: finalize", f->name); /* Call these in reverse order to .prepare above, starting from the * filter furthest away from the plugin. @@ -406,7 +406,7 @@ filter_get_size (struct backend *b, struct connection *conn) void *handle = connection_get_handle (conn, f->backend.i); struct b_conn nxdata = { .b = f->backend.next, .conn = conn }; - debug ("get_size"); + debug ("%s: get_size", f->name); if (f->filter.get_size) return f->filter.get_size (&next_ops, &nxdata, handle); @@ -421,7 +421,7 @@ filter_can_write (struct backend *b, struct connection *conn) void *handle = connection_get_handle (conn, f->backend.i); struct b_conn nxdata = { .b = f->backend.next, .conn = conn }; - debug ("can_write"); + debug ("%s: can_write", f->name); if (f->filter.can_write) return f->filter.can_write (&next_ops, &nxdata, handle); @@ -436,7 +436,7 @@ filter_can_flush (struct backend *b, struct connection *conn) void *handle = connection_get_handle (conn, f->backend.i); struct b_conn nxdata = { .b = f->backend.next, .conn = conn }; - debug ("can_flush"); + debug ("%s: can_flush", f->name); if (f->filter.can_flush) return f->filter.can_flush (&next_ops, &nxdata, handle); @@ -451,7 +451,7 @@ filter_is_rotational (struct backend *b, struct connection *conn) void *handle = connection_get_handle (conn, f->backend.i); struct b_conn nxdata = { .b = f->backend.next, .conn = conn }; - debug ("is_rotational"); + debug ("%s: is_rotational", f->name); if (f->filter.is_rotational) return f->filter.is_rotational (&next_ops, &nxdata, handle); @@ -466,7 +466,7 @@ filter_can_trim (struct backend *b, struct connection *conn) void *handle = connection_get_handle (conn, f->backend.i); struct b_conn nxdata = { .b = f->backend.next, .conn = conn }; - debug ("can_trim"); + debug ("%s: can_trim", f->name); if (f->filter.can_trim) return f->filter.can_trim (&next_ops, &nxdata, handle); @@ -481,7 +481,7 @@ filter_can_zero (struct backend *b, struct connection *conn) void *handle = connection_get_handle (conn, f->backend.i); struct b_conn nxdata = { .b = f->backend.next, .conn = conn }; - debug ("can_zero"); + debug ("%s: can_zero", f->name); if (f->filter.can_zero) return f->filter.can_zero (&next_ops, &nxdata, handle); @@ -496,7 +496,7 @@ filter_can_fua (struct backend *b, struct connection *conn) void *handle = connection_get_handle (conn, f->backend.i); struct b_conn nxdata = { .b = f->backend.next, .conn = conn }; - debug ("can_fua"); + debug ("%s: can_fua", f->name); if (f->filter.can_fua) return f->filter.can_fua (&next_ops, &nxdata, handle); @@ -515,8 +515,8 @@ filter_pread (struct backend *b, struct connection *conn, assert (flags == 0); - debug ("pread count=%" PRIu32 " offset=%" PRIu64 " flags=0x%" PRIx32, - count, offset, flags); + debug ("%s: pread count=%" PRIu32 " offset=%" PRIu64 " flags=0x%" PRIx32, + f->name, count, offset, flags); if (f->filter.pread) return f->filter.pread (&next_ops, &nxdata, handle, @@ -537,8 +537,8 @@ filter_pwrite (struct backend *b, struct connection *conn, assert (!(flags & ~NBDKIT_FLAG_FUA)); - debug ("pwrite count=%" PRIu32 " offset=%" PRIu64 " flags=0x%" PRIx32, - count, offset, flags); + debug ("%s: pwrite count=%" PRIu32 " offset=%" PRIu64 " flags=0x%" PRIx32, + f->name, count, offset, flags); if (f->filter.pwrite) return f->filter.pwrite (&next_ops, &nxdata, handle, @@ -558,7 +558,7 @@ filter_flush (struct backend *b, struct connection *conn, uint32_t flags, assert (flags == 0); - debug ("flush flags=0x%" PRIx32, flags); + debug ("%s: flush flags=0x%" PRIx32, f->name, flags); if (f->filter.flush) return f->filter.flush (&next_ops, &nxdata, handle, flags, err); @@ -577,8 +577,8 @@ filter_trim (struct backend *b, struct connection *conn, assert (flags == 0); - debug ("trim count=%" PRIu32 " offset=%" PRIu64 " flags=0x%" PRIx32, - count, offset, flags); + debug ("%s: trim count=%" PRIu32 " offset=%" PRIu64 " flags=0x%" PRIx32, + f->name, count, offset, flags); if (f->filter.trim) return f->filter.trim (&next_ops, &nxdata, handle, count, offset, flags, @@ -598,8 +598,8 @@ filter_zero (struct backend *b, struct connection *conn, assert (!(flags & ~(NBDKIT_FLAG_MAY_TRIM | NBDKIT_FLAG_FUA))); - debug ("zero count=%" PRIu32 " offset=%" PRIu64 " flags=0x%" PRIx32, - count, offset, flags); + debug ("%s: zero count=%" PRIu32 " offset=%" PRIu64 " flags=0x%" PRIx32, + f->name, count, offset, flags); if (f->filter.zero) return f->filter.zero (&next_ops, &nxdata, handle, @@ -719,7 +719,7 @@ filter_register (struct backend *next, size_t index, const char *filename, debug ("registered filter %s (name %s)", f->filename, f->name); /* Call the on-load callback if it exists. */ - debug ("%s: load", f->filename); + debug ("%s: load", f->name); if (f->filter.load) f->filter.load (); -- 2.18.0
Richard W.M. Jones
2018-Aug-01 11:10 UTC
[Libguestfs] [PATCH v2 nbdkit 4/6] common: Add a directory for common code shared by plugins and filters.
Currently this adds two useful header files containing functions which will be consumed by filters in later commits. --- Makefile.am | 5 +++- common/include/Makefile.am | 39 ++++++++++++++++++++++++ common/include/ispowerof2.h | 50 +++++++++++++++++++++++++++++++ common/include/iszero.h | 60 +++++++++++++++++++++++++++++++++++++ configure.ac | 1 + 5 files changed, 154 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 6a3a377..09dbdb9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -53,7 +53,10 @@ SUBDIRS = \ src if HAVE_PLUGINS -SUBDIRS += plugins filters +SUBDIRS += \ + common/include \ + plugins \ + filters endif SUBDIRS += tests diff --git a/common/include/Makefile.am b/common/include/Makefile.am new file mode 100644 index 0000000..4ce1723 --- /dev/null +++ b/common/include/Makefile.am @@ -0,0 +1,39 @@ +# nbdkit +# Copyright (C) 2018 Red Hat Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of Red Hat nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +include $(top_srcdir)/common-rules.mk + +# These headers contain only common code shared by plugins and +# filters. They are not installed. +EXTRA_DIST = \ + ispowerof2.h \ + iszero.h diff --git a/common/include/ispowerof2.h b/common/include/ispowerof2.h new file mode 100644 index 0000000..41844b3 --- /dev/null +++ b/common/include/ispowerof2.h @@ -0,0 +1,50 @@ +/* nbdkit + * Copyright (C) 2018 Red Hat Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Red Hat nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef NBDKIT_ISPOWEROF2_H +#define NBDKIT_ISPOWEROF2_H + +#include <stdbool.h> + +/* Returns true if v is a power of 2. + * + * Uses the algorithm described at + * http://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2 + */ +static inline bool +is_power_of_2 (unsigned long v) +{ + return v && ((v & (v - 1)) == 0); +} + +#endif /* NBDKIT_ISPOWEROF2_H */ diff --git a/common/include/iszero.h b/common/include/iszero.h new file mode 100644 index 0000000..331614c --- /dev/null +++ b/common/include/iszero.h @@ -0,0 +1,60 @@ +/* nbdkit + * Copyright (C) 2018 Red Hat Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Red Hat nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef NBDKIT_ISZERO_H +#define NBDKIT_ISZERO_H + +#include <string.h> +#include <stdbool.h> + +/* Return true iff the buffer is all zero bytes. + * + * The clever approach here was suggested by Eric Blake. See: + * https://www.redhat.com/archives/libguestfs/2017-April/msg00171.html + */ +static inline bool +is_zero (const char *buffer, size_t size) +{ + size_t i; + const size_t limit = size < 16 ? size : 16; + + for (i = 0; i < limit; ++i) + if (buffer[i]) + return false; + if (size != limit) + return ! memcmp (buffer, buffer + 16, size - 16); + + return true; +} + +#endif /* NBDKIT_ISZERO_H */ diff --git a/configure.ac b/configure.ac index b87efb9..774f290 100644 --- a/configure.ac +++ b/configure.ac @@ -538,6 +538,7 @@ AC_CONFIG_FILES([podwrapper.pl], [chmod +x,-w podwrapper.pl]) AC_CONFIG_FILES([Makefile bash/Makefile + common/include/Makefile docs/Makefile include/Makefile plugins/Makefile -- 2.18.0
Richard W.M. Jones
2018-Aug-01 11:10 UTC
[Libguestfs] [PATCH v2 nbdkit 5/6] Add truncate filter for truncating or extending the size of plugins.
This can truncate, extend, or round up/down to a multiple. --- common-rules.mk | 3 +- configure.ac | 1 + filters/offset/nbdkit-offset-filter.pod | 7 +- filters/partition/nbdkit-partition-filter.pod | 1 + filters/truncate/Makefile.am | 61 ++++ filters/truncate/nbdkit-truncate-filter.pod | 88 +++++ filters/truncate/truncate.c | 301 ++++++++++++++++++ 7 files changed, 459 insertions(+), 3 deletions(-) diff --git a/common-rules.mk b/common-rules.mk index 01beff5..f600293 100644 --- a/common-rules.mk +++ b/common-rules.mk @@ -68,7 +68,8 @@ filters = \ log \ nozero \ offset \ - partition + partition \ + truncate plugindir = $(libdir)/nbdkit/plugins filterdir = $(libdir)/nbdkit/filters diff --git a/configure.ac b/configure.ac index 774f290..d68fdb7 100644 --- a/configure.ac +++ b/configure.ac @@ -579,6 +579,7 @@ AC_CONFIG_FILES([Makefile filters/nozero/Makefile filters/offset/Makefile filters/partition/Makefile + filters/truncate/Makefile src/Makefile src/nbdkit.pc tests/Makefile]) diff --git a/filters/offset/nbdkit-offset-filter.pod b/filters/offset/nbdkit-offset-filter.pod index ee8061b..6d8f9be 100644 --- a/filters/offset/nbdkit-offset-filter.pod +++ b/filters/offset/nbdkit-offset-filter.pod @@ -32,7 +32,9 @@ file/device. =back Note it is an error if the offset and/or range specify data which lies -beyond the end of the underlying device. +beyond the end of the underlying device. Use +L<nbdkit-truncate-filter(1)> to truncate or extend the size of +plugins. =head1 EXAMPLES @@ -65,7 +67,8 @@ You can then serve the partition only using: L<nbdkit(1)>, L<nbdkit-file-plugin(1)>, L<nbdkit-filter(3)>, -L<nbdkit-partition-filter(1)>. +L<nbdkit-partition-filter(1)>, +L<nbdkit-truncate-filter(1)>. =head1 AUTHORS diff --git a/filters/partition/nbdkit-partition-filter.pod b/filters/partition/nbdkit-partition-filter.pod index bc5f346..71a7a3a 100644 --- a/filters/partition/nbdkit-partition-filter.pod +++ b/filters/partition/nbdkit-partition-filter.pod @@ -46,6 +46,7 @@ L<nbdkit(1)>, L<nbdkit-file-plugin(1)>, L<nbdkit-filter(3)>, L<nbdkit-offset-filter(1)>, +L<nbdkit-truncate-filter(1)>, L<parted(8)>. =head1 AUTHORS diff --git a/filters/truncate/Makefile.am b/filters/truncate/Makefile.am new file mode 100644 index 0000000..cab2ca9 --- /dev/null +++ b/filters/truncate/Makefile.am @@ -0,0 +1,61 @@ +# nbdkit +# Copyright (C) 2018 Red Hat Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of Red Hat nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +include $(top_srcdir)/common-rules.mk + +EXTRA_DIST = nbdkit-truncate-filter.pod + +filter_LTLIBRARIES = nbdkit-truncate-filter.la + +nbdkit_truncate_filter_la_SOURCES = \ + truncate.c \ + $(top_srcdir)/include/nbdkit-filter.h + +nbdkit_truncate_filter_la_CPPFLAGS = \ + -I$(top_srcdir)/include \ + -I$(top_srcdir)/common/include +nbdkit_truncate_filter_la_CFLAGS = \ + $(WARNINGS_CFLAGS) +nbdkit_truncate_filter_la_LDFLAGS = \ + -module -avoid-version -shared + +if HAVE_POD + +man_MANS = nbdkit-truncate-filter.1 +CLEANFILES += $(man_MANS) + +nbdkit-truncate-filter.1: nbdkit-truncate-filter.pod + $(PODWRAPPER) --section=1 --man $@ \ + --html $(top_builddir)/html/$@.html \ + $< + +endif HAVE_POD diff --git a/filters/truncate/nbdkit-truncate-filter.pod b/filters/truncate/nbdkit-truncate-filter.pod new file mode 100644 index 0000000..5b145a4 --- /dev/null +++ b/filters/truncate/nbdkit-truncate-filter.pod @@ -0,0 +1,88 @@ +=head1 NAME + +nbdkit-truncate-filter - change the size of plugins + +=head1 SYNOPSIS + + nbdkit --filter=truncate plugin [truncate=SIZE] + [round-up=N] [round-down=N] + +=head1 DESCRIPTION + +C<nbdkit-truncate-filter> is a filter that changes the size of +the underlying plugin. It can: + +=over 4 + +=item * + +Make the plugin smaller (truncate it). Use the C<truncate=SIZE> +parameter to set the smaller size. + +=item * + +Make the plugin larger (the additional bytes read back as zeroes). +Use C<truncate=SIZE> to set the larger size. + +=item * + +Round the size of the plugin up or down to the next multiple of C<N>. +Use either C<round-up=N> or C<round-down=N>. + +=back + +A common use for this filter is to handle NBD clients which have a +problem dealing with device sizes which are not a multiple of 512 +bytes. Use C<round-up=512> to round the size up to the next multiple +of 512 bytes. If the size is already a multiple of 512 bytes then +this has no effect. + +=head1 PARAMETERS + +=over 4 + +=item B<truncate=SIZE> + +Set the absolute size in bytes of the apparent device. This may be +smaller or larger or the same as the underlying plugin. + +If the size is larger than the underlying plugin, reading the extra +space returns zeroes. Writes are also permitted to the extra space, +but you must only write zeroes (any attempts to write non-zero bytes +will return an error back to the client). + +This parameter is optional. + +=item B<round-up=N> + +Round the size up to the next multiple of C<N> bytes. If the size of +the underlying plugin is already a multiple of C<N> bytes, this has no +effect. + +This parameter is optional. + +=item B<round-down=N> + +Round the size down to a multiple of C<N> bytes. If the size of the +underlying plugin is already a multiple of C<N> bytes, this has no +effect. + +This parameter is optional. + +=back + +=head1 SEE ALSO + +L<nbdkit(1)>, +L<nbdkit-file-plugin(1)>, +L<nbdkit-filter(3)>, +L<nbdkit-offset-filter(1)>, +L<nbdkit-partition-filter(1)>. + +=head1 AUTHORS + +Richard W.M. Jones + +=head1 COPYRIGHT + +Copyright (C) 2018 Red Hat Inc. diff --git a/filters/truncate/truncate.c b/filters/truncate/truncate.c new file mode 100644 index 0000000..5d146c4 --- /dev/null +++ b/filters/truncate/truncate.c @@ -0,0 +1,301 @@ +/* nbdkit + * Copyright (C) 2018 Red Hat Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Red Hat nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <limits.h> +#include <errno.h> + +#include <pthread.h> + +#include <nbdkit-filter.h> + +#include "ispowerof2.h" +#include "iszero.h" + +#define THREAD_MODEL NBDKIT_THREAD_MODEL_PARALLEL + +/* These are the parameters. */ +static int64_t truncate = -1; +static unsigned round_up = 0, round_down = 0; + +/* The real size of the underlying plugin. */ +static uint64_t real_size; + +/* The calculated size after applying the parameters. */ +static uint64_t size; + +/* This lock protects the real_size and size fields. */ +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + +static int +parse_round_param (const char *key, const char *value, unsigned *ret) +{ + int64_t r; + unsigned u; + + /* Parse it as a "size" quantity so we allow round-up=1M and similar. */ + r = nbdkit_parse_size (value); + if (r == -1) + return -1; + + /* Must not be zero or larger than an unsigned int. */ + if (r == 0) { + nbdkit_error ("if set, the %s parameter must be > 0", key); + return -1; + } + if (r > UINT_MAX) { + nbdkit_error ("the %s parameter is too large", key); + return -1; + } + u = r; + + /* Must be a power of 2. We could relax this in future. */ + if (!is_power_of_2 (u)) { + nbdkit_error ("the %s parameter must be a power of 2", key); + return -1; + } + + *ret = u; + return 0; +} + +/* Called for each key=value passed on the command line. */ +static int +truncate_config (nbdkit_next_config *next, void *nxdata, + const char *key, const char *value) +{ + if (strcmp (key, "truncate") == 0) { + truncate = nbdkit_parse_size (value); + if (truncate == -1) + return -1; + return 0; + } + else if (strcmp (key, "round-up") == 0) { + return parse_round_param (key, value, &round_up); + } + else if (strcmp (key, "round-down") == 0) { + return parse_round_param (key, value, &round_down); + } + else + return next (nxdata, key, value); +} + +#define truncate_config_help \ + "truncate=<SIZE> The new size.\n" \ + "round-up=<N> Round up to next multiple of N.\n" \ + "round-down=<N> Round down to multiple of N." + +static int64_t truncate_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle); + +/* In prepare, force a call to get_size which sets the real_size & size + * globals. + */ +static int +truncate_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, + void *handle) +{ + int64_t r; + + r = truncate_get_size (next_ops, nxdata, handle); + return r >= 0 ? 0 : -1; +} + +/* Get the size. As a side effect, calculate the size to serve. */ +static int64_t +truncate_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, + void *handle) +{ + int64_t r, ret; + + r = next_ops->get_size (nxdata); + if (r == -1) + return -1; + + pthread_mutex_lock (&lock); + + real_size = size = r; + + /* The truncate, round-up and round-down parameters are treated as + * separate operations. It's possible to specify more than one, + * although perhaps not very useful. + */ + if (truncate >= 0) + size = truncate; + if (round_up > 0) + size = (size + round_up - 1) & ~(round_up-1); + if (round_down > 0) + size &= ~(round_down-1); + ret = size; + + pthread_mutex_unlock (&lock); + + return ret; +} + +/* Read data. */ +static int +truncate_pread (struct nbdkit_next_ops *next_ops, void *nxdata, + void *handle, void *buf, uint32_t count, uint64_t offset, + uint32_t flags, int *err) +{ + int r; + uint32_t n; + uint64_t real_size_copy; + + pthread_mutex_lock (&lock); + real_size_copy = real_size; + pthread_mutex_unlock (&lock); + + if (offset < real_size_copy) { + if (offset + count <= real_size_copy) + n = count; + else + n = real_size_copy - offset; + r = next_ops->pread (nxdata, buf, n, offset, flags, err); + if (r == -1) + return -1; + count -= n; + buf += n; + } + + if (count > 0) + memset (buf, 0, count); + + return 0; +} + +/* Write data. */ +static int +truncate_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, + void *handle, + const void *buf, uint32_t count, uint64_t offset, + uint32_t flags, int *err) +{ + int r; + uint32_t n; + uint64_t real_size_copy; + + pthread_mutex_lock (&lock); + real_size_copy = real_size; + pthread_mutex_unlock (&lock); + + if (offset < real_size_copy) { + if (offset + count <= real_size_copy) + n = count; + else + n = real_size_copy - offset; + r = next_ops->pwrite (nxdata, buf, n, offset, flags, err); + if (r == -1) + return -1; + count -= n; + buf += n; + } + + if (count > 0) { + /* The caller must be writing zeroes, else it's an error. */ + if (!is_zero (buf, count)) { + nbdkit_error ("truncate: write beyond end of underlying device"); + *err = EIO; + return -1; + } + } + + return 0; +} + +/* Trim data. */ +static int +truncate_trim (struct nbdkit_next_ops *next_ops, void *nxdata, + void *handle, uint32_t count, uint64_t offset, + uint32_t flags, int *err) +{ + uint32_t n; + uint64_t real_size_copy; + + pthread_mutex_lock (&lock); + real_size_copy = real_size; + pthread_mutex_unlock (&lock); + + if (offset < real_size_copy) { + if (offset + count <= real_size_copy) + n = count; + else + n = real_size_copy - offset; + return next_ops->trim (nxdata, n, offset, flags, err); + } + return 0; +} + +/* Zero data. */ +static int +truncate_zero (struct nbdkit_next_ops *next_ops, void *nxdata, + void *handle, uint32_t count, uint64_t offset, + uint32_t flags, int *err) +{ + uint32_t n; + uint64_t real_size_copy; + + pthread_mutex_lock (&lock); + real_size_copy = real_size; + pthread_mutex_unlock (&lock); + + if (offset < real_size_copy) { + if (offset + count <= real_size_copy) + n = count; + else + n = real_size_copy - offset; + return next_ops->zero (nxdata, n, offset, flags, err); + } + return 0; +} + +static struct nbdkit_filter filter = { + .name = "truncate", + .longname = "nbdkit truncate filter", + .version = PACKAGE_VERSION, + .config = truncate_config, + .config_help = truncate_config_help, + .prepare = truncate_prepare, + .get_size = truncate_get_size, + .pread = truncate_pread, + .pwrite = truncate_pwrite, + .trim = truncate_trim, + .zero = truncate_zero, +}; + +NBDKIT_REGISTER_FILTER(filter) -- 2.18.0
Richard W.M. Jones
2018-Aug-01 11:10 UTC
[Libguestfs] [PATCH v2 nbdkit 6/6] tests: truncate: Add two simple tests of the truncate filter.
--- tests/Makefile.am | 7 +++ tests/test-truncate1.sh | 120 ++++++++++++++++++++++++++++++++++++++++ tests/test-truncate2.sh | 120 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 247 insertions(+) diff --git a/tests/Makefile.am b/tests/Makefile.am index 12b7aae..4c602d7 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -79,6 +79,8 @@ EXTRA_DIST = \ test-random-sock.sh \ test-tls.sh \ test-tls-psk.sh \ + test-truncate1.sh \ + test-truncate2.sh \ test-vddk.sh \ test-version.sh \ test-version-filter.sh \ @@ -571,4 +573,9 @@ test_partition_SOURCES = test-partition.c test.h test_partition_CFLAGS = $(WARNINGS_CFLAGS) $(LIBGUESTFS_CFLAGS) test_partition_LDADD = libtest.la $(LIBGUESTFS_LIBS) +# truncate filter tests. +TESTS += \ + test-truncate1.sh \ + test-truncate2.sh + endif HAVE_PLUGINS diff --git a/tests/test-truncate1.sh b/tests/test-truncate1.sh new file mode 100755 index 0000000..61d2a50 --- /dev/null +++ b/tests/test-truncate1.sh @@ -0,0 +1,120 @@ +#!/bin/bash - +# nbdkit +# Copyright (C) 2018 Red Hat Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of Red Hat nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +# Test the truncate filter using the pattern plugin. + +set -e +set -x + +files="truncate1.out truncate1.pid truncate1.sock" +rm -f $files + +# Test that qemu-io works +if ! qemu-io --help >/dev/null; then + echo "$0: missing or broken qemu-io" + exit 77 +fi + +# Run nbdkit with pattern plugin and truncate filter in front. +nbdkit -P truncate1.pid -U truncate1.sock \ + --filter=truncate \ + pattern size=503 \ + truncate=512 + +# We may have to wait a short time for the pid file to appear. +for i in `seq 1 10`; do + if test -f truncate1.pid; then + break + fi + sleep 1 +done +if ! test -f truncate1.pid; then + echo "$0: PID file was not created" + exit 1 +fi + +pid="$(cat truncate1.pid)" + +# Kill the nbdkit process on exit. +cleanup () +{ + status=$? + + kill $pid + rm -f $files + + exit $status +} +trap cleanup INT QUIT TERM EXIT ERR + +qemu-io -r -f raw 'nbd+unix://?socket=truncate1.sock' \ + -c 'r -v 0 512' | grep -E '^[[:xdigit:]]+:' > truncate1.out +if [ "$(cat truncate1.out)" != "00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 ................ +00000010: 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 18 ................ +00000020: 00 00 00 00 00 00 00 20 00 00 00 00 00 00 00 28 ................ +00000030: 00 00 00 00 00 00 00 30 00 00 00 00 00 00 00 38 .......0.......8 +00000040: 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 48 ...............H +00000050: 00 00 00 00 00 00 00 50 00 00 00 00 00 00 00 58 .......P.......X +00000060: 00 00 00 00 00 00 00 60 00 00 00 00 00 00 00 68 ...............h +00000070: 00 00 00 00 00 00 00 70 00 00 00 00 00 00 00 78 .......p.......x +00000080: 00 00 00 00 00 00 00 80 00 00 00 00 00 00 00 88 ................ +00000090: 00 00 00 00 00 00 00 90 00 00 00 00 00 00 00 98 ................ +000000a0: 00 00 00 00 00 00 00 a0 00 00 00 00 00 00 00 a8 ................ +000000b0: 00 00 00 00 00 00 00 b0 00 00 00 00 00 00 00 b8 ................ +000000c0: 00 00 00 00 00 00 00 c0 00 00 00 00 00 00 00 c8 ................ +000000d0: 00 00 00 00 00 00 00 d0 00 00 00 00 00 00 00 d8 ................ +000000e0: 00 00 00 00 00 00 00 e0 00 00 00 00 00 00 00 e8 ................ +000000f0: 00 00 00 00 00 00 00 f0 00 00 00 00 00 00 00 f8 ................ +00000100: 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 08 ................ +00000110: 00 00 00 00 00 00 01 10 00 00 00 00 00 00 01 18 ................ +00000120: 00 00 00 00 00 00 01 20 00 00 00 00 00 00 01 28 ................ +00000130: 00 00 00 00 00 00 01 30 00 00 00 00 00 00 01 38 .......0.......8 +00000140: 00 00 00 00 00 00 01 40 00 00 00 00 00 00 01 48 ...............H +00000150: 00 00 00 00 00 00 01 50 00 00 00 00 00 00 01 58 .......P.......X +00000160: 00 00 00 00 00 00 01 60 00 00 00 00 00 00 01 68 ...............h +00000170: 00 00 00 00 00 00 01 70 00 00 00 00 00 00 01 78 .......p.......x +00000180: 00 00 00 00 00 00 01 80 00 00 00 00 00 00 01 88 ................ +00000190: 00 00 00 00 00 00 01 90 00 00 00 00 00 00 01 98 ................ +000001a0: 00 00 00 00 00 00 01 a0 00 00 00 00 00 00 01 a8 ................ +000001b0: 00 00 00 00 00 00 01 b0 00 00 00 00 00 00 01 b8 ................ +000001c0: 00 00 00 00 00 00 01 c0 00 00 00 00 00 00 01 c8 ................ +000001d0: 00 00 00 00 00 00 01 d0 00 00 00 00 00 00 01 d8 ................ +000001e0: 00 00 00 00 00 00 01 e0 00 00 00 00 00 00 01 e8 ................ +000001f0: 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 ................" ] +then + echo "$0: unexpected pattern:" + cat truncate1.out + exit 1 +fi + +# The cleanup() function is called implicitly on exit. diff --git a/tests/test-truncate2.sh b/tests/test-truncate2.sh new file mode 100755 index 0000000..5afef16 --- /dev/null +++ b/tests/test-truncate2.sh @@ -0,0 +1,120 @@ +#!/bin/bash - +# nbdkit +# Copyright (C) 2018 Red Hat Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of Red Hat nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +# Test the truncate filter using the pattern plugin. + +set -e +set -x + +files="truncate2.out truncate2.pid truncate2.sock" +rm -f $files + +# Test that qemu-io works +if ! qemu-io --help >/dev/null; then + echo "$0: missing or broken qemu-io" + exit 77 +fi + +# Run nbdkit with pattern plugin and truncate filter in front. +nbdkit -P truncate2.pid -U truncate2.sock \ + --filter=truncate \ + pattern size=503 \ + round-up=512 + +# We may have to wait a short time for the pid file to appear. +for i in `seq 1 10`; do + if test -f truncate2.pid; then + break + fi + sleep 1 +done +if ! test -f truncate2.pid; then + echo "$0: PID file was not created" + exit 1 +fi + +pid="$(cat truncate2.pid)" + +# Kill the nbdkit process on exit. +cleanup () +{ + status=$? + + kill $pid + rm -f $files + + exit $status +} +trap cleanup INT QUIT TERM EXIT ERR + +qemu-io -r -f raw 'nbd+unix://?socket=truncate2.sock' \ + -c 'r -v 0 512' | grep -E '^[[:xdigit:]]+:' > truncate2.out +if [ "$(cat truncate2.out)" != "00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 ................ +00000010: 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 18 ................ +00000020: 00 00 00 00 00 00 00 20 00 00 00 00 00 00 00 28 ................ +00000030: 00 00 00 00 00 00 00 30 00 00 00 00 00 00 00 38 .......0.......8 +00000040: 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 48 ...............H +00000050: 00 00 00 00 00 00 00 50 00 00 00 00 00 00 00 58 .......P.......X +00000060: 00 00 00 00 00 00 00 60 00 00 00 00 00 00 00 68 ...............h +00000070: 00 00 00 00 00 00 00 70 00 00 00 00 00 00 00 78 .......p.......x +00000080: 00 00 00 00 00 00 00 80 00 00 00 00 00 00 00 88 ................ +00000090: 00 00 00 00 00 00 00 90 00 00 00 00 00 00 00 98 ................ +000000a0: 00 00 00 00 00 00 00 a0 00 00 00 00 00 00 00 a8 ................ +000000b0: 00 00 00 00 00 00 00 b0 00 00 00 00 00 00 00 b8 ................ +000000c0: 00 00 00 00 00 00 00 c0 00 00 00 00 00 00 00 c8 ................ +000000d0: 00 00 00 00 00 00 00 d0 00 00 00 00 00 00 00 d8 ................ +000000e0: 00 00 00 00 00 00 00 e0 00 00 00 00 00 00 00 e8 ................ +000000f0: 00 00 00 00 00 00 00 f0 00 00 00 00 00 00 00 f8 ................ +00000100: 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 08 ................ +00000110: 00 00 00 00 00 00 01 10 00 00 00 00 00 00 01 18 ................ +00000120: 00 00 00 00 00 00 01 20 00 00 00 00 00 00 01 28 ................ +00000130: 00 00 00 00 00 00 01 30 00 00 00 00 00 00 01 38 .......0.......8 +00000140: 00 00 00 00 00 00 01 40 00 00 00 00 00 00 01 48 ...............H +00000150: 00 00 00 00 00 00 01 50 00 00 00 00 00 00 01 58 .......P.......X +00000160: 00 00 00 00 00 00 01 60 00 00 00 00 00 00 01 68 ...............h +00000170: 00 00 00 00 00 00 01 70 00 00 00 00 00 00 01 78 .......p.......x +00000180: 00 00 00 00 00 00 01 80 00 00 00 00 00 00 01 88 ................ +00000190: 00 00 00 00 00 00 01 90 00 00 00 00 00 00 01 98 ................ +000001a0: 00 00 00 00 00 00 01 a0 00 00 00 00 00 00 01 a8 ................ +000001b0: 00 00 00 00 00 00 01 b0 00 00 00 00 00 00 01 b8 ................ +000001c0: 00 00 00 00 00 00 01 c0 00 00 00 00 00 00 01 c8 ................ +000001d0: 00 00 00 00 00 00 01 d0 00 00 00 00 00 00 01 d8 ................ +000001e0: 00 00 00 00 00 00 01 e0 00 00 00 00 00 00 01 e8 ................ +000001f0: 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 ................" ] +then + echo "$0: unexpected pattern:" + cat truncate2.out + exit 1 +fi + +# The cleanup() function is called implicitly on exit. -- 2.18.0
Nir Soffer
2018-Aug-01 13:24 UTC
Re: [Libguestfs] [PATCH v2 nbdkit 4/6] common: Add a directory for common code shared by plugins and filters.
On Wed, Aug 1, 2018 at 2:14 PM Richard W.M. Jones <rjones@redhat.com> wrote:> Currently this adds two useful header files containing functions which > will be consumed by filters in later commits. > --- > Makefile.am | 5 +++- > common/include/Makefile.am | 39 ++++++++++++++++++++++++ > common/include/ispowerof2.h | 50 +++++++++++++++++++++++++++++++ > common/include/iszero.h | 60 +++++++++++++++++++++++++++++++++++++ > configure.ac | 1 + > 5 files changed, 154 insertions(+), 1 deletion(-) > > diff --git a/Makefile.am b/Makefile.am > index 6a3a377..09dbdb9 100644 > --- a/Makefile.am > +++ b/Makefile.am > @@ -53,7 +53,10 @@ SUBDIRS = \ > src > > if HAVE_PLUGINS > -SUBDIRS += plugins filters > +SUBDIRS += \ > + common/include \ > + plugins \ > + filters > endif > > SUBDIRS += tests > diff --git a/common/include/Makefile.am b/common/include/Makefile.am > new file mode 100644 > index 0000000..4ce1723 > --- /dev/null > +++ b/common/include/Makefile.am > @@ -0,0 +1,39 @@ > +# nbdkit > +# Copyright (C) 2018 Red Hat Inc. > +# All rights reserved. > +# > +# Redistribution and use in source and binary forms, with or without > +# modification, are permitted provided that the following conditions are > +# met: > +# > +# * Redistributions of source code must retain the above copyright > +# notice, this list of conditions and the following disclaimer. > +# > +# * Redistributions in binary form must reproduce the above copyright > +# notice, this list of conditions and the following disclaimer in the > +# documentation and/or other materials provided with the distribution. > +# > +# * Neither the name of Red Hat nor the names of its contributors may be > +# used to endorse or promote products derived from this software without > +# specific prior written permission. > +# > +# THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND > +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, > +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A > +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR > +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, > +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF > +# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND > +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, > +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT > +# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF > +# SUCH DAMAGE. > + > +include $(top_srcdir)/common-rules.mk > + > +# These headers contain only common code shared by plugins and > +# filters. They are not installed. > +EXTRA_DIST = \ > + ispowerof2.h \ > + iszero.h > diff --git a/common/include/ispowerof2.h b/common/include/ispowerof2.h > new file mode 100644 > index 0000000..41844b3 > --- /dev/null > +++ b/common/include/ispowerof2.h > @@ -0,0 +1,50 @@ > +/* nbdkit > + * Copyright (C) 2018 Red Hat Inc. > + * All rights reserved. > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions are > + * met: > + * > + * * Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * > + * * Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in the > + * documentation and/or other materials provided with the distribution. > + * > + * * Neither the name of Red Hat nor the names of its contributors may be > + * used to endorse or promote products derived from this software without > + * specific prior written permission. > + * > + * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND > + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, > + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A > + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR > + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, > + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF > + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND > + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, > + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT > + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF > + * SUCH DAMAGE. > + */ > + > +#ifndef NBDKIT_ISPOWEROF2_H > +#define NBDKIT_ISPOWEROF2_H > + > +#include <stdbool.h> > + > +/* Returns true if v is a power of 2. > + * > + * Uses the algorithm described at > + * > http://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2 > + */ > +static inline bool > +is_power_of_2 (unsigned long v) > +{ > + return v && ((v & (v - 1)) == 0); > +} > + > +#endif /* NBDKIT_ISPOWEROF2_H */ > diff --git a/common/include/iszero.h b/common/include/iszero.h > new file mode 100644 > index 0000000..331614c > --- /dev/null > +++ b/common/include/iszero.h > @@ -0,0 +1,60 @@ > +/* nbdkit > + * Copyright (C) 2018 Red Hat Inc. > + * All rights reserved. > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions are > + * met: > + * > + * * Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * > + * * Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in the > + * documentation and/or other materials provided with the distribution. > + * > + * * Neither the name of Red Hat nor the names of its contributors may be > + * used to endorse or promote products derived from this software without > + * specific prior written permission. > + * > + * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND > + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, > + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A > + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR > + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, > + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF > + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND > + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, > + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT > + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF > + * SUCH DAMAGE. > + */ > + > +#ifndef NBDKIT_ISZERO_H > +#define NBDKIT_ISZERO_H > + > +#include <string.h> > +#include <stdbool.h> > + > +/* Return true iff the buffer is all zero bytes. > + * > + * The clever approach here was suggested by Eric Blake. See: > + * https://www.redhat.com/archives/libguestfs/2017-April/msg00171.htmlIt would be nice to mention the original author: http://rusty.ozlabs.org/?p=560> > + */ > +static inline bool > +is_zero (const char *buffer, size_t size) > +{ > + size_t i; > + const size_t limit = size < 16 ? size : 16; > + > + for (i = 0; i < limit; ++i) > + if (buffer[i]) > + return false; > + if (size != limit) > + return ! memcmp (buffer, buffer + 16, size - 16); > + > + return true; > +} > + > +#endif /* NBDKIT_ISZERO_H */ > diff --git a/configure.ac b/configure.ac > index b87efb9..774f290 100644 > --- a/configure.ac > +++ b/configure.ac > @@ -538,6 +538,7 @@ AC_CONFIG_FILES([podwrapper.pl], > [chmod +x,-w podwrapper.pl]) > AC_CONFIG_FILES([Makefile > bash/Makefile > + common/include/Makefile > docs/Makefile > include/Makefile > plugins/Makefile > -- > 2.18.0 > > _______________________________________________ > Libguestfs mailing list > Libguestfs@redhat.com > https://www.redhat.com/mailman/listinfo/libguestfs >
Eric Blake
2018-Aug-01 14:00 UTC
Re: [Libguestfs] [PATCH v2 nbdkit 1/6] filters: Call all .prepare and .finalize methods, not just the first one.
On 08/01/2018 06:10 AM, Richard W.M. Jones wrote:> These methods are not chained through the next_ops structure, so we > must do that work in src/filters.c. > > This fixes the behaviour of filters when you layer multiple filters in > front of a plugin. > --- > src/filters.c | 27 +++++++++++++++++++-------- > 1 file changed, 19 insertions(+), 8 deletions(-)And at least test-fua.sh breaks, because the log filter is used as a second filter, and now outputs more information that needs to be accounted for. The change is desirable, so we just have to adjust the test to match. -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org
Eric Blake
2018-Aug-01 14:08 UTC
Re: [Libguestfs] [PATCH v2 nbdkit 2/6] filters: Fix filter.plugin_name method so it returns the name of the plugin.
On 08/01/2018 06:10 AM, Richard W.M. Jones wrote:> This function was completely bogus, the effect being that the > threadlocal name was always set to the name of the second filter. > > Also fixes an adjacent comment. > --- > src/filters.c | 6 +++--- > 1 file changed, 3 insertions(+), 3 deletions(-)ACK> > -/* These are actually passing through to the final plugin, hence > - * the function names.Probably refactoring woes, when an earlier version of filters did have more than one plugin_ passthrough (or at least the intent of a passthrough).> +/* This is actually passing the request through to the final plugin, > + * hence the function name. > */ > static const char * > plugin_name (struct backend *b) > { > struct backend_filter *f = container_of (b, struct backend_filter, backend); > > - return f->backend.next->name (f->backend.next); > + return f->backend.next->plugin_name (f->backend.next);Yeah, this is better ;) I'm surprised I didn't notice it. -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org
Eric Blake
2018-Aug-01 14:11 UTC
Re: [Libguestfs] [PATCH v2 nbdkit 3/6] filters: Print filter name in debugging messages.
On 08/01/2018 06:10 AM, Richard W.M. Jones wrote:> nbdkit_debug implicitly prints the plugin name. However this leads to > confusing debug messages such as: > > nbdkit: pattern[1]: debug: prepare > nbdkit: pattern[1]: debug: prepare > > (in this instance, two different prepare functions were called in > different filters, but neither filter name was shown). > > By printing the filter name in the debug message we improve the output: > > nbdkit: pattern[1]: debug: truncate: prepare > nbdkit: pattern[1]: debug: map: prepare > > Another example of the improved output is: > > nbdkit: pattern[1]: debug: truncate: can_flush # filter > nbdkit: pattern[1]: debug: map: can_flush # filter > nbdkit: pattern[1]: debug: can_flush # pluginYes, much easier to debug (even if the examples in the commit message require later patches before I can actually reproduce them). ACK. -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org
Eric Blake
2018-Aug-01 14:23 UTC
Re: [Libguestfs] [PATCH v2 nbdkit 6/6] tests: truncate: Add two simple tests of the truncate filter.
On 08/01/2018 06:10 AM, Richard W.M. Jones wrote:> --- > tests/Makefile.am | 7 +++ > tests/test-truncate1.sh | 120 ++++++++++++++++++++++++++++++++++++++++ > tests/test-truncate2.sh | 120 ++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 247 insertions(+) >> + > +# Test the truncate filter using the pattern plugin. > + > +set -e > +set -xDo you want both -e and -x? Is it worth combining them as 'set -ex'? (I'm personally not a fan of 'set -e'; it does not behave intuitively, especially when shell functions are involved; but I also understand copy-and-paste from other tests that use it).> +# Kill the nbdkit process on exit. > +cleanup () > +{ > + status=$? > + > + kill $pidMissing the additional cleanup fixes that you have in a separate patch (depending on which patch you push first...) Otherwise seems reasonable. -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org
Eric Blake
2018-Aug-01 16:06 UTC
Re: [Libguestfs] [PATCH v2 nbdkit 5/6] Add truncate filter for truncating or extending the size of plugins.
On 08/01/2018 06:10 AM, Richard W.M. Jones wrote:> This can truncate, extend, or round up/down to a multiple. > --- > common-rules.mk | 3 +- > configure.ac | 1 + > filters/offset/nbdkit-offset-filter.pod | 7 +- > filters/partition/nbdkit-partition-filter.pod | 1 + > filters/truncate/Makefile.am | 61 ++++ > filters/truncate/nbdkit-truncate-filter.pod | 88 +++++ > filters/truncate/truncate.c | 301 ++++++++++++++++++ > 7 files changed, 459 insertions(+), 3 deletions(-) >> + > +=item * > + > +Round the size of the plugin up or down to the next multiple of C<N>. > +Use either C<round-up=N> or C<round-down=N>.Worth mentioning that N must be a power of 2.> + > +#define THREAD_MODEL NBDKIT_THREAD_MODEL_PARALLEL > + > +/* These are the parameters. */ > +static int64_t truncate = -1; > +static unsigned round_up = 0, round_down = 0; > + > +/* The real size of the underlying plugin. */ > +static uint64_t real_size; > + > +/* The calculated size after applying the parameters. */ > +static uint64_t size; > + > +/* This lock protects the real_size and size fields. */ > +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;Do we need the lock, or can we rely on the fact that .prepare will get called before anything else, and treat these as always initialized after that point?> + /* The truncate, round-up and round-down parameters are treated as > + * separate operations. It's possible to specify more than one, > + * although perhaps not very useful. > + */ > + if (truncate >= 0) > + size = truncate; > + if (round_up > 0) > + size = (size + round_up - 1) & ~(round_up-1);Inconsistent spacing between the two instances of 'round_up - 1'; I think we favor the spaces everywhere...> + if (round_down > 0) > + size &= ~(round_down-1);...in which case the spacing here is also suspect.> + if (count > 0) { > + /* The caller must be writing zeroes, else it's an error. */ > + if (!is_zero (buf, count)) { > + nbdkit_error ("truncate: write beyond end of underlying device"); > + *err = EIO;Would ENOSPC be better here? -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org
Reasonably Related Threads
- [PATCH nbdkit 1/4] Add truncate filter for truncating or extending the size of plugins.
- [PATCH v2 nbdkit 5/6] Add truncate filter for truncating or extending the size of plugins.
- [nbdkit PATCH 0/4] Fix truncate handling of real_size
- [nbdkit PATCH] truncate: Detect large image overflow with round-up
- [nbdkit PATCH 2/4] truncate: Fix corruption when plugin changes per-connection size