On Thu, May 25, 2023 at 08:01:06AM -0500, Eric Blake wrote: > Prove that we can round-trip a block status request larger than 4G > through a new-enough qemu-nbd. Also serves as a unit test of our shim > for converting internal 64-bit representation back to the older 32-bit > nbd_block_status callback interface.
I think it would be best to call this test "large-block-status.{c,sh}" as "large-status" is ambiguous. (Or even "block-status-64"?) The test itself is fine, so if renamed: Reviewed-by: Richard W.M. Jones <rjo...@redhat.com> > Signed-off-by: Eric Blake <ebl...@redhat.com> > --- > interop/Makefile.am | 6 ++ > interop/large-status.c | 186 ++++++++++++++++++++++++++++++++++++++++ > interop/large-status.sh | 49 +++++++++++ > .gitignore | 1 + > 4 files changed, 242 insertions(+) > create mode 100644 interop/large-status.c > create mode 100755 interop/large-status.sh > > diff --git a/interop/Makefile.am b/interop/Makefile.am > index 3f81df0c..9a7a5967 100644 > --- a/interop/Makefile.am > +++ b/interop/Makefile.am > @@ -21,6 +21,7 @@ EXTRA_DIST = \ > dirty-bitmap.sh \ > interop-qemu-storage-daemon.sh \ > interop-qemu-block-size.sh \ > + large-status.sh \ > list-exports-nbd-config \ > list-exports-test-dir/disk1 \ > list-exports-test-dir/disk2 \ > @@ -134,6 +135,7 @@ check_PROGRAMS += \ > list-exports-qemu-nbd \ > socket-activation-qemu-nbd \ > dirty-bitmap \ > + large-status \ > structured-read \ > opt-extended-headers \ > $(NULL) > @@ -144,6 +146,7 @@ TESTS += \ > list-exports-qemu-nbd \ > socket-activation-qemu-nbd \ > dirty-bitmap.sh \ > + large-status.sh \ > structured-read.sh \ > interop-qemu-block-size.sh \ > opt-extended-headers.sh \ > @@ -235,6 +238,9 @@ socket_activation_qemu_nbd_LDADD = > $(top_builddir)/lib/libnbd.la > dirty_bitmap_SOURCES = dirty-bitmap.c > dirty_bitmap_LDADD = $(top_builddir)/lib/libnbd.la > > +large_status_SOURCES = large-status.c > +large_status_LDADD = $(top_builddir)/lib/libnbd.la > + > structured_read_SOURCES = structured-read.c > structured_read_LDADD = $(top_builddir)/lib/libnbd.la > > diff --git a/interop/large-status.c b/interop/large-status.c > new file mode 100644 > index 00000000..36415653 > --- /dev/null > +++ b/interop/large-status.c > @@ -0,0 +1,186 @@ > +/* NBD client library in userspace > + * Copyright Red Hat > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + */ > + > +/* Test 64-bit block status with qemu. */ > + > +#include <config.h> > + > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> > +#include <assert.h> > +#include <stdbool.h> > +#include <errno.h> > + > +#include <libnbd.h> > + > +static const char *bitmap; > + > +struct data { > + bool req_one; /* input: true if req_one was passed to request */ > + int count; /* input: count of expected remaining calls */ > + bool seen_base; /* output: true if base:allocation encountered */ > + bool seen_dirty; /* output: true if qemu:dirty-bitmap encountered */ > +}; > + > +static int > +cb32 (void *opaque, const char *metacontext, uint64_t offset, > + uint32_t *entries, size_t len, int *error) > +{ > + struct data *data = opaque; > + > + assert (offset == 0); > + assert (data->count-- > 0); > + > + if (strcmp (metacontext, LIBNBD_CONTEXT_BASE_ALLOCATION) == 0) { > + assert (!data->seen_base); > + data->seen_base = true; > + > + /* Data block offset 0 size 64k, remainder is hole */ > + assert (len == 4); > + assert (entries[0] == 65536); > + assert (entries[1] == 0); > + /* libnbd had to truncate qemu's >4G answer */ > + assert (entries[2] == 4227858432); > + assert (entries[3] == (LIBNBD_STATE_HOLE|LIBNBD_STATE_ZERO)); > + } > + else if (strcmp (metacontext, bitmap) == 0) { > + assert (!data->seen_dirty); > + data->seen_dirty = true; > + > + /* Dirty block at offset 5G-64k, remainder is clean */ > + /* libnbd had to truncate qemu's >4G answer */ > + assert (len == 2); > + assert (entries[0] == 4227858432); > + assert (entries[1] == 0); > + } > + else { > + fprintf (stderr, "unexpected context %s\n", metacontext); > + exit (EXIT_FAILURE); > + } > + return 0; > +} > + > +static int > +cb64 (void *opaque, const char *metacontext, uint64_t offset, > + nbd_extent *entries, size_t len, int *error) > +{ > + struct data *data = opaque; > + > + assert (offset == 0); > + assert (data->count-- > 0); > + > + if (strcmp (metacontext, LIBNBD_CONTEXT_BASE_ALLOCATION) == 0) { > + assert (!data->seen_base); > + data->seen_base = true; > + > + /* Data block offset 0 size 64k, remainder is hole */ > + assert (len == 2); > + assert (entries[0].length == 65536); > + assert (entries[0].flags == 0); > + assert (entries[1].length == 5368643584ULL); > + assert (entries[1].flags == (LIBNBD_STATE_HOLE|LIBNBD_STATE_ZERO)); > + } > + else if (strcmp (metacontext, bitmap) == 0) { > + assert (!data->seen_dirty); > + data->seen_dirty = true; > + > + /* Dirty block at offset 5G-64k, remainder is clean */ > + assert (len == 2); > + assert (entries[0].length == 5368643584ULL); > + assert (entries[0].flags == 0); > + assert (entries[1].length == 65536); > + assert (entries[1].flags == 1); > + } > + else { > + fprintf (stderr, "unexpected context %s\n", metacontext); > + exit (EXIT_FAILURE); > + } > + return 0; > +} > + > +int > +main (int argc, char *argv[]) > +{ > + struct nbd_handle *nbd; > + int64_t exportsize; > + struct data data; > + > + if (argc < 3) { > + fprintf (stderr, "%s bitmap qemu-nbd [args ...]\n", argv[0]); > + exit (EXIT_FAILURE); > + } > + bitmap = argv[1]; > + > + nbd = nbd_create (); > + if (nbd == NULL) { > + fprintf (stderr, "%s\n", nbd_get_error ()); > + exit (EXIT_FAILURE); > + } > + > + nbd_add_meta_context (nbd, LIBNBD_CONTEXT_BASE_ALLOCATION); > + nbd_add_meta_context (nbd, bitmap); > + > + if (nbd_connect_systemd_socket_activation (nbd, &argv[2]) == -1) { > + fprintf (stderr, "%s\n", nbd_get_error ()); > + exit (EXIT_FAILURE); > + } > + > + exportsize = nbd_get_size (nbd); > + if (exportsize == -1) { > + fprintf (stderr, "%s\n", nbd_get_error ()); > + exit (EXIT_FAILURE); > + } > + > + if (nbd_get_extended_headers_negotiated (nbd) != 1) { > + fprintf (stderr, "skipping: qemu-nbd lacks extended headers\n"); > + exit (77); > + } > + > + /* Prove that we can round-trip a >4G block status request */ > + data = (struct data) { .count = 2, }; > + if (nbd_block_status_64 (nbd, exportsize, 0, > + (nbd_extent64_callback) { .callback = cb64, > + .user_data = &data }, > + 0) == -1) { > + fprintf (stderr, "%s\n", nbd_get_error ()); > + exit (EXIT_FAILURE); > + } > + assert (data.seen_base && data.seen_dirty); > + > + /* Check libnbd's handling of a >4G response through older interface */ > + data = (struct data) { .count = 2, }; > + if (nbd_block_status (nbd, exportsize, 0, > + (nbd_extent_callback) { .callback = cb32, > + .user_data = &data }, > + 0) == -1) { > + fprintf (stderr, "%s\n", nbd_get_error ()); > + exit (EXIT_FAILURE); > + } > + assert (data.seen_base && data.seen_dirty); > + > + if (nbd_shutdown (nbd, 0) == -1) { > + fprintf (stderr, "%s\n", nbd_get_error ()); > + exit (EXIT_FAILURE); > + } > + > + nbd_close (nbd); > + > + exit (EXIT_SUCCESS); > +} > diff --git a/interop/large-status.sh b/interop/large-status.sh > new file mode 100755 > index 00000000..46810dc3 > --- /dev/null > +++ b/interop/large-status.sh > @@ -0,0 +1,49 @@ > +#!/usr/bin/env bash > +# nbd client library in userspace > +# Copyright Red Hat > +# > +# This library is free software; you can redistribute it and/or > +# modify it under the terms of the GNU Lesser General Public > +# License as published by the Free Software Foundation; either > +# version 2 of the License, or (at your option) any later version. > +# > +# This library is distributed in the hope that it will be useful, > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > +# Lesser General Public License for more details. > +# > +# You should have received a copy of the GNU Lesser General Public > +# License along with this library; if not, write to the Free Software > +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + > +# Test reading qemu dirty-bitmap. > + > +source ../tests/functions.sh > +set -e > +set -x > + > +requires qemu-img bitmap --help > +requires qemu-nbd --version > + > +# This test uses the qemu-nbd -B option. > +if ! qemu-nbd --help | grep -sq -- -B; then > + echo "$0: skipping because qemu-nbd does not support the -B option" > + exit 77 > +fi > + > +files="large-status.qcow2" > +rm -f $files > +cleanup_fn rm -f $files > + > +# Create mostly-sparse file with intentionally different data vs. dirty areas > +# (64k data, 5G-64k hole,zero; 5G-64k clean, 64k dirty) > +qemu-img create -f qcow2 large-status.qcow2 5G > +qemu-img bitmap --add --enable -f qcow2 large-status.qcow2 bitmap0 > +qemu-io -f qcow2 -c "w -z $((5*1024*1024*1024 - 64*1024)) 64k" \ > + large-status.qcow2 > +qemu-img bitmap --disable -f qcow2 large-status.qcow2 bitmap0 > +qemu-io -f qcow2 -c 'w 0 64k' large-status.qcow2 > + > +# Run the test. > +$VG ./large-status qemu:dirty-bitmap:bitmap0 \ > + qemu-nbd -f qcow2 -B bitmap0 large-status.qcow2 > diff --git a/.gitignore b/.gitignore > index 24642748..fd81357b 100644 > --- a/.gitignore > +++ b/.gitignore > @@ -114,6 +114,7 @@ Makefile.in > /interop/interop-qemu-nbd > /interop/interop-qemu-nbd-tls-certs > /interop/interop-qemu-nbd-tls-psk > +/interop/large-status > /interop/list-exports-nbd-server > /interop/list-exports-nbdkit > /interop/list-exports-qemu-nbd Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com virt-builder quickly builds VMs from scratch http://libguestfs.org/virt-builder.1.html _______________________________________________ Libguestfs mailing list Libguestfs@redhat.com https://listman.redhat.com/mailman/listinfo/libguestfs