Richard W.M. Jones
2023-May-17 10:06 UTC
[Libguestfs] [PATCH nbdkit v2 5/6] New plugin: ones
Returns a fully allocated disk containing all 0xff (all ones), or another byte of your choice. --- plugins/data/nbdkit-data-plugin.pod | 1 + plugins/full/nbdkit-full-plugin.pod | 1 + plugins/null/nbdkit-null-plugin.pod | 1 + plugins/ones/nbdkit-ones-plugin.pod | 77 +++++++ plugins/pattern/nbdkit-pattern-plugin.pod | 4 +- plugins/random/nbdkit-random-plugin.pod | 1 + .../nbdkit-sparse-random-plugin.pod | 1 + plugins/zero/nbdkit-zero-plugin.pod | 1 + configure.ac | 2 + plugins/ones/Makefile.am | 70 +++++++ tests/Makefile.am | 4 + plugins/ones/ones.c | 191 ++++++++++++++++++ tests/test-ones.sh | 53 +++++ 13 files changed, 406 insertions(+), 1 deletion(-) diff --git a/plugins/data/nbdkit-data-plugin.pod b/plugins/data/nbdkit-data-plugin.pod index cec1af7f7..46daa859e 100644 --- a/plugins/data/nbdkit-data-plugin.pod +++ b/plugins/data/nbdkit-data-plugin.pod @@ -404,6 +404,7 @@ L<nbdkit-plugin(3)>, L<nbdkit-info-plugin(1)>, L<nbdkit-memory-plugin(1)>, L<nbdkit-null-plugin(1)>, +L<nbdkit-ones-plugin(1)>, L<nbdkit-partitioning-plugin(1)>, L<nbdkit-pattern-plugin(1)>, L<nbdkit-random-plugin(1)>, diff --git a/plugins/full/nbdkit-full-plugin.pod b/plugins/full/nbdkit-full-plugin.pod index 5664aa2da..18c86a327 100644 --- a/plugins/full/nbdkit-full-plugin.pod +++ b/plugins/full/nbdkit-full-plugin.pod @@ -65,6 +65,7 @@ L<nbdkit(1)>, L<nbdkit-plugin(3)>, L<nbdkit-error-filter(1)>, L<nbdkit-null-plugin(1)>, +L<nbdkit-ones-plugin(1)>, L<nbdkit-pattern-plugin(1)>, L<nbdkit-random-plugin(1)>. L<nbdkit-sparse-random-plugin(1)>, diff --git a/plugins/null/nbdkit-null-plugin.pod b/plugins/null/nbdkit-null-plugin.pod index 27fe68746..c71dc2c6f 100644 --- a/plugins/null/nbdkit-null-plugin.pod +++ b/plugins/null/nbdkit-null-plugin.pod @@ -55,6 +55,7 @@ C<nbdkit-null-plugin> first appeared in nbdkit 1.2. L<nbdkit(1)>, L<nbdkit-plugin(3)>, L<nbdkit-full-plugin(1)>, +L<nbdkit-ones-plugin(1)>, L<nbdkit-pattern-plugin(1)>, L<nbdkit-random-plugin(1)>. L<nbdkit-sparse-random-plugin(1)>, diff --git a/plugins/ones/nbdkit-ones-plugin.pod b/plugins/ones/nbdkit-ones-plugin.pod new file mode 100644 index 000000000..50ccfe272 --- /dev/null +++ b/plugins/ones/nbdkit-ones-plugin.pod @@ -0,0 +1,77 @@ +=head1 NAME + +nbdkit-ones-plugin - nbdkit plugin filled with repeated 0xff or other bytes + +=head1 SYNOPSIS + + nbdkit ones [[size=]SIZE] [byte=N] + +=head1 DESCRIPTION + +C<nbdkit-ones-plugin> is a plugin for L<nbdkit(1)>. Any read returns +a repeating pattern of C<0xff> (all ones) bytes, or another repeating +byte if you use the C<byte> parameter. Everything written to the +virtual device is discarded. + +Most NBD consumers will be very confused by this device. It is mainly +useful for testing. L<nbdkit-data-plugin(1)> can be used to create a +modifiable RAM disk initialized with fixed data. + +=head1 PARAMETERS + +=over 4 + +=item B<byte=>N + +Set the repeating byte to C<N>. The default is C<0xff> (all ones). + +Instead of C<byte=0> it is more efficient to use +L<nbdkit-null-plugin(1)>. + +=item [B<size=>]SIZE + +Specify the virtual size of the disk image. + +This parameter is optional. If omitted then a zero-sized device is +created. + +C<size=> is a magic config key and may be omitted in most cases. +See L<nbdkit(1)/Magic parameters>. + +=back + +=head1 FILES + +=over 4 + +=item F<$plugindir/nbdkit-ones-plugin.so> + +The plugin. + +Use C<nbdkit --dump-config> to find the location of C<$plugindir>. + +=back + +=head1 VERSION + +C<nbdkit-ones-plugin> first appeared in nbdkit 1.36. + +=head1 SEE ALSO + +L<nbdkit(1)>, +L<nbdkit-plugin(3)>, +L<nbdkit-data-plugin(1)>, +L<nbdkit-full-plugin(1)>, +L<nbdkit-null-plugin(1)>, +L<nbdkit-pattern-plugin(1)>, +L<nbdkit-random-plugin(1)>. +L<nbdkit-sparse-random-plugin(1)>, +L<nbdkit-zero-plugin(1)>. + +=head1 AUTHORS + +Richard W.M. Jones + +=head1 COPYRIGHT + +Copyright Red Hat diff --git a/plugins/pattern/nbdkit-pattern-plugin.pod b/plugins/pattern/nbdkit-pattern-plugin.pod index c5d4f0d36..f4ae324ed 100644 --- a/plugins/pattern/nbdkit-pattern-plugin.pod +++ b/plugins/pattern/nbdkit-pattern-plugin.pod @@ -11,7 +11,8 @@ nbdkit-pattern-plugin - plugin to serve a fixed pattern of data for testing C<nbdkit-pattern-plugin> is a plugin for L<nbdkit(1)> which serves a fixed pattern of data, read only. This is used for testing nbdkit filters and NBD clients. To create test disks filled with other -repeated patterns use L<nbdkit-data-plugin(1)> instead. +repeated patterns use L<nbdkit-data-plugin(1)> or +L<nbdkit-ones-plugin(1)> instead. The fixed pattern is the offset, as a 64 bit big endian integer, every 8 bytes. In hexadecimal this looks like: @@ -88,6 +89,7 @@ L<nbdkit-plugin(3)>, L<nbdkit-data-plugin(1)>, L<nbdkit-full-plugin(1)>, L<nbdkit-null-plugin(1)>, +L<nbdkit-ones-plugin(1)>, L<nbdkit-offset-filter(1)>, L<nbdkit-random-plugin(1)>, L<nbdkit-sparse-random-plugin(1)>, diff --git a/plugins/random/nbdkit-random-plugin.pod b/plugins/random/nbdkit-random-plugin.pod index 040d86bfc..0d6da8d5f 100644 --- a/plugins/random/nbdkit-random-plugin.pod +++ b/plugins/random/nbdkit-random-plugin.pod @@ -76,6 +76,7 @@ L<nbdkit-plugin(3)>, L<nbdkit-data-plugin(1)>, L<nbdkit-full-plugin(1)>, L<nbdkit-null-plugin(1)>, +L<nbdkit-ones-plugin(1)>, L<nbdkit-pattern-plugin(1)>, L<nbdkit-sparse-random-plugin(1)>, L<nbdkit-zero-plugin(1)>, diff --git a/plugins/sparse-random/nbdkit-sparse-random-plugin.pod b/plugins/sparse-random/nbdkit-sparse-random-plugin.pod index 03e98ee16..5636e76c4 100644 --- a/plugins/sparse-random/nbdkit-sparse-random-plugin.pod +++ b/plugins/sparse-random/nbdkit-sparse-random-plugin.pod @@ -110,6 +110,7 @@ L<nbdkit-plugin(3)>, L<nbdkit-data-plugin(1)>, L<nbdkit-full-plugin(1)>, L<nbdkit-null-plugin(1)>, +L<nbdkit-ones-plugin(1)>, L<nbdkit-pattern-plugin(1)>, L<nbdkit-random-plugin(1)>, L<nbdkit-zero-plugin(1)>, diff --git a/plugins/zero/nbdkit-zero-plugin.pod b/plugins/zero/nbdkit-zero-plugin.pod index 03544ad6e..2ac846027 100644 --- a/plugins/zero/nbdkit-zero-plugin.pod +++ b/plugins/zero/nbdkit-zero-plugin.pod @@ -37,6 +37,7 @@ L<nbdkit-plugin(3)>, L<nbdkit-data-plugin(1)>, L<nbdkit-full-plugin(1)>, L<nbdkit-null-plugin(1)>, +L<nbdkit-ones-plugin(1)>, L<nbdkit-pattern-plugin(1)>, L<nbdkit-random-plugin(1)>, L<nbdkit-sparse-random-plugin(1)>. diff --git a/configure.ac b/configure.ac index dafddcc29..310de7ac1 100644 --- a/configure.ac +++ b/configure.ac @@ -95,6 +95,7 @@ non_lang_plugins="\ nbd \ null \ ondemand \ + ones \ partitioning \ pattern \ random \ @@ -1500,6 +1501,7 @@ AC_CONFIG_FILES([Makefile plugins/null/Makefile plugins/ocaml/Makefile plugins/ondemand/Makefile + plugins/ones/Makefile plugins/partitioning/Makefile plugins/pattern/Makefile plugins/perl/Makefile diff --git a/plugins/ones/Makefile.am b/plugins/ones/Makefile.am new file mode 100644 index 000000000..9f8cbc4e2 --- /dev/null +++ b/plugins/ones/Makefile.am @@ -0,0 +1,70 @@ +# nbdkit +# Copyright Red Hat +# +# 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-ones-plugin.pod + +plugin_LTLIBRARIES = nbdkit-ones-plugin.la + +nbdkit_ones_plugin_la_SOURCES = \ + ones.c \ + $(top_srcdir)/include/nbdkit-plugin.h \ + $(NULL) + +nbdkit_ones_plugin_la_CPPFLAGS = \ + -I$(top_srcdir)/include \ + -I$(top_builddir)/include \ + $(NULL) +nbdkit_ones_plugin_la_CFLAGS = $(WARNINGS_CFLAGS) +nbdkit_ones_plugin_la_LIBADD = \ + $(IMPORT_LIBRARY_ON_WINDOWS) \ + $(NULL) +nbdkit_ones_plugin_la_LDFLAGS = \ + -module -avoid-version -shared $(NO_UNDEFINED_ON_WINDOWS) \ + $(NULL) +if USE_LINKER_SCRIPT +nbdkit_ones_plugin_la_LDFLAGS += \ + -Wl,--version-script=$(top_srcdir)/plugins/plugins.syms +endif + +if HAVE_POD + +man_MANS = nbdkit-ones-plugin.1 +CLEANFILES += $(man_MANS) + +nbdkit-ones-plugin.1: nbdkit-ones-plugin.pod \ + $(top_builddir)/podwrapper.pl + $(PODWRAPPER) --section=1 --man $@ \ + --html $(top_builddir)/html/$@.html \ + $< + +endif HAVE_POD diff --git a/tests/Makefile.am b/tests/Makefile.am index 3c8123f45..3ae13d660 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -955,6 +955,10 @@ EXTRA_DIST += \ test-ondemand-locking.sh \ $(NULL) +# ones plugin test. +TESTS += test-ones.sh +EXTRA_DIST += test-ones.sh + # partitioning plugin test. TESTS += \ test-partitioning1.sh \ diff --git a/plugins/ones/ones.c b/plugins/ones/ones.c new file mode 100644 index 000000000..2ff1ed028 --- /dev/null +++ b/plugins/ones/ones.c @@ -0,0 +1,191 @@ +/* nbdkit + * Copyright Red Hat + * + * 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 <errno.h> + +#define NBDKIT_API_VERSION 2 + +#include <nbdkit-plugin.h> + +/* The size of disk in bytes (initialized by size=<SIZE> parameter). */ +static int64_t size = 0; + +/* Repeating byte. */ +static uint8_t byte = 0xff; + +static int +ones_config (const char *key, const char *value) +{ + int64_t r; + + if (strcmp (key, "size") == 0) { + r = nbdkit_parse_size (value); + if (r == -1) + return -1; + size = r; + } + else if (strcmp (key, "byte") == 0) { + if (nbdkit_parse_uint8_t ("byte", value, &byte) == -1) + return -1; + } + else { + nbdkit_error ("unknown parameter '%s'", key); + return -1; + } + + return 0; +} + +#define ones_config_help \ + "byte=<BYTE> Repeating byte to use (default: 0xff).\n" \ + "size=<SIZE> Size of the backing disk." + +/* Create the per-connection handle. */ +static void * +ones_open (int readonly) +{ + return NBDKIT_HANDLE_NOT_NEEDED; +} + +#define THREAD_MODEL NBDKIT_THREAD_MODEL_PARALLEL + +/* Get the disk size. */ +static int64_t +ones_get_size (void *handle) +{ + return size; +} + +/* Serves the same data over multiple connections. */ +static int +ones_can_multi_conn (void *handle) +{ + return 1; +} + +/* Cache. */ +static int +ones_can_cache (void *handle) +{ + /* Everything is already in memory, returning this without + * implementing .cache lets nbdkit do the correct no-op. + */ + return NBDKIT_CACHE_NATIVE; +} + +/* Read data. */ +static int +ones_pread (void *handle, void *buf, uint32_t count, uint64_t offset, + uint32_t flags) +{ + memset (buf, byte, count); + return 0; +} + +/* Write data. */ +static int +ones_pwrite (void *handle, const void *buf, uint32_t count, uint64_t offset, + uint32_t flags) +{ + /* nothing */ + return 0; +} + +/* Write zeroes. */ +static int +ones_zero (void *handle, uint32_t count, uint64_t offset, uint32_t flags) +{ + /* nothing */ + return 0; +} + +/* Flush is a no-op, so advertise native FUA support */ +static int +ones_can_fua (void *handle) +{ + return NBDKIT_FUA_NATIVE; +} + +/* Trim. */ +static int +ones_trim (void *handle, uint32_t count, uint64_t offset, uint32_t flags) +{ + /* nothing */ + return 0; +} + +/* Nothing is persistent, so flush is trivially supported */ +static int +ones_flush (void *handle, uint32_t flags) +{ + return 0; +} + +/* Extents. */ +static int +ones_extents (void *handle, uint32_t count, uint64_t offset, uint32_t flags, + struct nbdkit_extents *extents) +{ + /* Return a fully allocated data extent covering the entire disk. */ + return nbdkit_add_extent (extents, 0, size, 0); +} + +static struct nbdkit_plugin plugin = { + .name = "ones", + .version = PACKAGE_VERSION, + .config = ones_config, + .config_help = ones_config_help, + .magic_config_key = "size", + .open = ones_open, + .get_size = ones_get_size, + .can_multi_conn = ones_can_multi_conn, + .can_cache = ones_can_cache, + .pread = ones_pread, + .pwrite = ones_pwrite, + .zero = ones_zero, + .trim = ones_trim, + .can_fua = ones_can_fua, + .flush = ones_flush, + .extents = ones_extents, + /* In this plugin, errno is preserved properly along error return + * paths from failed system calls. + */ + .errno_is_preserved = 1, +}; + +NBDKIT_REGISTER_PLUGIN (plugin) diff --git a/tests/test-ones.sh b/tests/test-ones.sh new file mode 100755 index 000000000..1a2b22caf --- /dev/null +++ b/tests/test-ones.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +# nbdkit +# Copyright Red Hat +# +# 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. + +source ./functions.sh +set -e +set -x + +requires_plugin ones +requires_nbdsh_uri +requires_nbdinfo + +# Check the disk contains 0xff by default. +nbdkit -U - ones 1024 --run ' +nbdsh -u "$uri" -c "assert (h.pread(1024,0) == b\"\\xff\"*1024)" +' + +# Change the byte. +nbdkit -U - ones 1024 byte=0x5a --run ' +nbdsh -u "$uri" -c "assert (h.pread(1024,0) == b\"\\x5a\"*1024)" +' + +# Check the disk is fully allocated. +nbdkit -U - ones 1G --run 'nbdinfo --map "$uri"' | \ + grep -E '0[[:space:]]+1073741824[[:space:]]+0[[:space:]]+data' -- 2.39.2
On Wed, May 17, 2023 at 11:06:58AM +0100, Richard W.M. Jones wrote:> Returns a fully allocated disk containing all 0xff (all ones), or > another byte of your choice. > --- > + > +=item B<byte=>N > + > +Set the repeating byte to C<N>. The default is C<0xff> (all ones). > + > +Instead of C<byte=0> it is more efficient to use > +L<nbdkit-null-plugin(1)>.Good catch. On v1, I suggested nbdkit-zero-plugin, but re-reading the difference between those two, I see you got the one I meant. (For the casual reader: zero-plugin has size zero, while the null plugin has non-zero size that reads as zero) Reviewed-by: Eric Blake <eblake at redhat.com> -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org
On Wed, May 17, 2023 at 11:06:58AM +0100, Richard W.M. Jones wrote:> Returns a fully allocated disk containing all 0xff (all ones), or > another byte of your choice. > --- > plugins/data/nbdkit-data-plugin.pod | 1 + > plugins/full/nbdkit-full-plugin.pod | 1 + > plugins/null/nbdkit-null-plugin.pod | 1 + > plugins/ones/nbdkit-ones-plugin.pod | 77 +++++++ > plugins/pattern/nbdkit-pattern-plugin.pod | 4 +- > plugins/random/nbdkit-random-plugin.pod | 1 + > .../nbdkit-sparse-random-plugin.pod | 1 + > plugins/zero/nbdkit-zero-plugin.pod | 1 + > configure.ac | 2 + > plugins/ones/Makefile.am | 70 +++++++ > tests/Makefile.am | 4 + > plugins/ones/ones.c | 191 ++++++++++++++++++ > tests/test-ones.sh | 53 +++++ > 13 files changed, 406 insertions(+), 1 deletion(-) > > +++ b/plugins/ones/ones.c > @@ -0,0 +1,191 @@> + > +/* Write zeroes. */ > +static int > +ones_zero (void *handle, uint32_t count, uint64_t offset, uint32_t flags) > +{ > + /* nothing */ > + return 0; > +}Since writing zeroes is a no-op...> +static struct nbdkit_plugin plugin = { > + .name = "ones", > + .version = PACKAGE_VERSION, > + .config = ones_config, > + .config_help = ones_config_help, > + .magic_config_key = "size", > + .open = ones_open, > + .get_size = ones_get_size, > + .can_multi_conn = ones_can_multi_conn, > + .can_cache = ones_can_cache, > + .pread = ones_pread, > + .pwrite = ones_pwrite, > + .zero = ones_zero, > + .trim = ones_trim, > + .can_fua = ones_can_fua, > + .flush = ones_flush, > + .extents = ones_extents, > + /* In this plugin, errno is preserved properly along error return > + * paths from failed system calls. > + */ > + .errno_is_preserved = 1, > +};...we probably also want to supply .can_fast_zero with a function that returns true. -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org