[Libguestfs] [nbdkit PATCH 06/10] plugins: Wire up shell plugin support for NBD_INFO_INIT_STATE

Eric Blake eblake at redhat.com
Mon Feb 10 21:43:59 UTC 2020


The NBD protocol is adding an extension to let servers advertise
initialization state to the client: whether the image contains holes,
and whether it is known to read as all zeroes.  For shell-based
plugins (sh and eval), it's relatively straightforward to expose the
two new functions.  Likewise, testing with the eval plugin is rather
easy.

Signed-off-by: Eric Blake <eblake at redhat.com>
---
 plugins/eval/eval.c                 |  4 +++
 plugins/eval/nbdkit-eval-plugin.pod |  9 +++--
 plugins/sh/example.sh               | 14 ++++++++
 plugins/sh/methods.c                | 18 +++++++++-
 plugins/sh/methods.h                |  4 ++-
 plugins/sh/nbdkit-sh-plugin.pod     |  8 ++++-
 plugins/sh/sh.c                     |  4 ++-
 tests/Makefile.am                   |  3 +-
 tests/test-eval-init.sh             | 54 +++++++++++++++++++++++++++++
 9 files changed, 111 insertions(+), 7 deletions(-)
 create mode 100755 tests/test-eval-init.sh

diff --git a/plugins/eval/eval.c b/plugins/eval/eval.c
index 094cac5..0c26628 100644
--- a/plugins/eval/eval.c
+++ b/plugins/eval/eval.c
@@ -71,6 +71,8 @@ static const char *known_methods[] = {
   "extents",
   "flush",
   "get_size",
+  "init_sparse",
+  "init_zero",
   "is_rotational",
   "missing",
   "open",
@@ -419,6 +421,8 @@ static struct nbdkit_plugin plugin = {
   .can_multi_conn    = sh_can_multi_conn,
   .can_cache         = sh_can_cache,
   .can_fast_zero     = sh_can_fast_zero,
+  .init_sparse       = sh_init_sparse,
+  .init_zero         = sh_init_zero,

   .pread             = sh_pread,
   .pwrite            = sh_pwrite,
diff --git a/plugins/eval/nbdkit-eval-plugin.pod b/plugins/eval/nbdkit-eval-plugin.pod
index cbb4133..48937de 100644
--- a/plugins/eval/nbdkit-eval-plugin.pod
+++ b/plugins/eval/nbdkit-eval-plugin.pod
@@ -51,7 +51,8 @@ all other methods are identical).
 Create a 64M read-only disk of zeroes:

  nbdkit eval get_size=' echo 64M ' \
-                pread=' dd if=/dev/zero count=$3 iflag=count_bytes '
+                pread=' dd if=/dev/zero count=$3 iflag=count_bytes ' \
+            init_zero=' exit 0 '

 The following command is the eval plugin equivalent of
 L<nbdkit-file-plugin(1)> (except not as fast and missing many
@@ -102,6 +103,10 @@ features):

 =item B<get_size=>SCRIPT

+=item B<init_sparse=>SCRIPT
+
+=item B<init_zero=>SCRIPT
+
 =item B<is_rotational=>SCRIPT

 =item B<open=>SCRIPT
@@ -191,4 +196,4 @@ Richard W.M. Jones

 =head1 COPYRIGHT

-Copyright (C) 2019 Red Hat Inc.
+Copyright (C) 2019-2020 Red Hat Inc.
diff --git a/plugins/sh/example.sh b/plugins/sh/example.sh
index 99e4e89..638fea0 100755
--- a/plugins/sh/example.sh
+++ b/plugins/sh/example.sh
@@ -184,6 +184,20 @@ case "$1" in
         echo "file"
         ;;

+    init_sparse)
+        # Return true if file is known to be sparse at client open.
+        # This heuristic has false negatives, but gets many cases right.
+        test 1 == $(( $(stat -L -c '%b * %B < %s' $f) )) || exit 3
+        ;;
+
+    init_zero)
+        # Return true if file has all zero content at client open.
+        # A slower 'cmp $f /dev/zero' might catch more cases.
+        # Be careful: blindly returning true may break a second client
+        # if a first client modifies the file.
+        test 0 == $(stat -L -c '%b' $f) || exit 3
+        ;;
+
     *)
         # Unknown methods must exit with code 2.
         exit 2
diff --git a/plugins/sh/methods.c b/plugins/sh/methods.c
index ccedc6c..28112eb 100644
--- a/plugins/sh/methods.c
+++ b/plugins/sh/methods.c
@@ -1,5 +1,5 @@
 /* nbdkit
- * Copyright (C) 2018-2019 Red Hat Inc.
+ * Copyright (C) 2018-2020 Red Hat Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -568,6 +568,22 @@ sh_can_fast_zero (void *handle)
   return !r;
 }

+int
+sh_init_sparse (void *handle)
+{
+  const char *method = "init_sparse";
+  const char *script = get_script (method);
+  return boolean_method (script, method, handle, 0);
+}
+
+int
+sh_init_zero (void *handle)
+{
+  const char *method = "init_zero";
+  const char *script = get_script (method);
+  return boolean_method (script, method, handle, 0);
+}
+
 int
 sh_flush (void *handle, uint32_t flags)
 {
diff --git a/plugins/sh/methods.h b/plugins/sh/methods.h
index c5da214..31a8124 100644
--- a/plugins/sh/methods.h
+++ b/plugins/sh/methods.h
@@ -1,5 +1,5 @@
 /* nbdkit
- * Copyright (C) 2018 Red Hat Inc.
+ * Copyright (C) 2018-2020 Red Hat Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -58,6 +58,8 @@ extern int sh_can_fua (void *handle);
 extern int sh_can_multi_conn (void *handle);
 extern int sh_can_cache (void *handle);
 extern int sh_can_fast_zero (void *handle);
+extern int sh_init_sparse (void *handle);
+extern int sh_init_zero (void *handle);
 extern int sh_flush (void *handle, uint32_t flags);
 extern int sh_trim (void *handle, uint32_t count, uint64_t offset,
                     uint32_t flags);
diff --git a/plugins/sh/nbdkit-sh-plugin.pod b/plugins/sh/nbdkit-sh-plugin.pod
index 0c4f2f8..913a6b1 100644
--- a/plugins/sh/nbdkit-sh-plugin.pod
+++ b/plugins/sh/nbdkit-sh-plugin.pod
@@ -307,8 +307,14 @@ The script should exit with code C<0> for true or code C<3> for false.

 =item C<can_fast_zero>

+=item C<init_sparse>
+
+=item C<init_zero>
+
  /path/to/script is_rotational <handle>
  /path/to/script can_fast_zero <handle>
+ /path/to/script init_sparse <handle>
+ /path/to/script init_zero <handle>

 The script should exit with code C<0> for true or code C<3> for false.

@@ -467,4 +473,4 @@ Richard W.M. Jones

 =head1 COPYRIGHT

-Copyright (C) 2018-2019 Red Hat Inc.
+Copyright (C) 2018-2020 Red Hat Inc.
diff --git a/plugins/sh/sh.c b/plugins/sh/sh.c
index eddba8e..1aea290 100644
--- a/plugins/sh/sh.c
+++ b/plugins/sh/sh.c
@@ -1,5 +1,5 @@
 /* nbdkit
- * Copyright (C) 2018-2019 Red Hat Inc.
+ * Copyright (C) 2018-2020 Red Hat Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -325,6 +325,8 @@ static struct nbdkit_plugin plugin = {
   .can_multi_conn    = sh_can_multi_conn,
   .can_cache         = sh_can_cache,
   .can_fast_zero     = sh_can_fast_zero,
+  .init_sparse       = sh_init_sparse,
+  .init_zero         = sh_init_zero,

   .pread             = sh_pread,
   .pwrite            = sh_pwrite,
diff --git a/tests/Makefile.am b/tests/Makefile.am
index a8ff601..ca659d7 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -110,6 +110,7 @@ EXTRA_DIST = \
 	test-error100.sh \
 	test-error-triggered.sh \
 	test-eval.sh \
+	test-eval-init.sh \
 	test-export-name.sh \
 	test-extentlist.sh \
 	test-file-extents.sh \
@@ -515,7 +516,7 @@ test_data_CFLAGS = $(WARNINGS_CFLAGS) $(LIBGUESTFS_CFLAGS)
 test_data_LDADD = libtest.la $(LIBGUESTFS_LIBS)

 # eval plugin test.
-TESTS += test-eval.sh
+TESTS += test-eval.sh test-eval-init.sh

 # ext2 plugin test.
 if HAVE_EXT2
diff --git a/tests/test-eval-init.sh b/tests/test-eval-init.sh
new file mode 100755
index 0000000..b72b1fc
--- /dev/null
+++ b/tests/test-eval-init.sh
@@ -0,0 +1,54 @@
+#!/usr/bin/env bash
+# nbdkit
+# Copyright (C) 2020 Red Hat Inc.
+#
+# 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 initial state of the eval plugin.
+
+source ./functions.sh
+set -e
+
+requires nbdsh -c 'exit (not hasattr (h, "get_init_flags"))'
+
+# All four combinations of initial flags. Relies on values of NBD protocol.
+for val in 0 1 2 3; do
+    nbdkit -v -U - eval \
+       get_size='echo 1024' \
+       pread='dd if=/dev/zero count=$3 iflag=count_bytes' \
+       init_sparse="exit $((3 * !($val & 1)))" \
+       init_zero="exit $((3 * !($val & 2)))" \
+       --run 'nbdsh --uri $uri -c "assert (h.get_init_flags () == '$val')"'
+done
+
+# Omitting is the same as returning false (the safe default).
+nbdkit -v -U - eval \
+   get_size='echo 1024' \
+   pread='dd if=/dev/zero count=$3 iflag=count_bytes' \
+   --run 'nbdsh --uri $uri -c "assert (h.get_init_flags () == 0)"'
-- 
2.24.1




More information about the Libguestfs mailing list