[Libguestfs] [libnbd PATCH 2/2] tests: Test server response to oversize requests

Eric Blake eblake at redhat.com
Wed Nov 9 23:26:07 UTC 2022


Improve some existing tests to cover client safety valves for oversize
requests, and add a new test that tests libnbd behavior on server
errors to the same sort of requests.  The new test requires a parallel
patch posted to nbdkit to teach 'nbdkit eval' how to forcefully
disconnect the server on particarly oversize write requests, emulating
qemu-nbd behavior.
---
 tests/Makefile.am               |  15 +++-
 tests/errors-client-oversize.c  |  18 +++-
 tests/errors-server-oversize.c  | 151 ++++++++++++++++++++++++++++++++
 tests/errors-server-unaligned.c |   2 +
 .gitignore                      |   1 +
 5 files changed, 185 insertions(+), 2 deletions(-)
 create mode 100644 tests/errors-server-oversize.c

diff --git a/tests/Makefile.am b/tests/Makefile.am
index 70083e5c..0b9c454e 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -177,6 +177,7 @@ check_PROGRAMS += \
 	errors-multiple-disconnects \
 	errors-server-invalid-offset \
 	errors-client-oversize \
+	errors-server-oversize \
 	errors-client-unadvertised-cmd \
 	errors-server-unadvertised-cmd \
 	errors-client-unaligned \
@@ -247,6 +248,7 @@ TESTS += \
 	errors-multiple-disconnects \
 	errors-server-invalid-offset \
 	errors-client-oversize \
+	errors-server-oversize \
 	errors-client-unadvertised-cmd \
 	errors-server-unadvertised-cmd \
 	errors-client-unaligned \
@@ -343,9 +345,20 @@ errors_multiple_disconnects_LDADD = $(top_builddir)/lib/libnbd.la
 errors_server_invalid_offset_SOURCES = errors-server-invalid-offset.c
 errors_server_invalid_offset_LDADD = $(top_builddir)/lib/libnbd.la

-errors_client_oversize_SOURCES = errors-client-oversize.c
+errors_client_oversize_SOURCES = \
+	errors-client-oversize.c \
+	requires.c \
+	requires.h \
+	$(NULL)
 errors_client_oversize_LDADD = $(top_builddir)/lib/libnbd.la

+errors_server_oversize_SOURCES = \
+	errors-server-oversize.c \
+	requires.c \
+	requires.h \
+	$(NULL)
+errors_server_oversize_LDADD = $(top_builddir)/lib/libnbd.la
+
 errors_client_unadvertised_cmd_SOURCES = errors-client-unadvertised-cmd.c \
 				  requires.c requires.h
 errors_client_unadvertised_cmd_LDADD = $(top_builddir)/lib/libnbd.la
diff --git a/tests/errors-client-oversize.c b/tests/errors-client-oversize.c
index 7e5b5421..739b41e9 100644
--- a/tests/errors-client-oversize.c
+++ b/tests/errors-client-oversize.c
@@ -30,6 +30,7 @@
 #include <sys/stat.h>

 #include <libnbd.h>
+#include "requires.h"

 #define MAXSIZE 68157440 /* 65M, oversize on purpose */

@@ -62,10 +63,15 @@ main (int argc, char *argv[])
 {
   struct nbd_handle *nbd;
   const char *cmd[] = {
-    "nbdkit", "-s", "-v", "--exit-with-parent", "memory", "68157440", NULL,
+    "nbdkit", "-s", "-v", "--exit-with-parent",
+    "memory", "68157440",
+    "--filter=blocksize-policy", "blocksize-maximum=32M",
+    "blocksize-error-policy=error",
+    NULL
   };

   progname = argv[0];
+  requires ("nbdkit --version --filter=blocksize-policy null");

   nbd = nbd_create ();
   if (nbd == NULL) {
@@ -87,6 +93,7 @@ main (int argc, char *argv[])
     exit (EXIT_FAILURE);
   }
   check (ERANGE, "nbd_pread: ");
+
   if (nbd_aio_pwrite (nbd, buf, MAXSIZE, 0,
                       NBD_NULL_COMPLETION, 0) != -1) {
     fprintf (stderr, "%s: test failed: "
@@ -96,6 +103,15 @@ main (int argc, char *argv[])
   }
   check (ERANGE, "nbd_aio_pwrite: ");

+  if (nbd_aio_pwrite (nbd, buf, 33*1024*1024, 0,
+                      NBD_NULL_COMPLETION, 0) != -1) {
+    fprintf (stderr, "%s: test failed: "
+             "nbd_aio_pwrite did not fail with oversize request\n",
+             argv[0]);
+    exit (EXIT_FAILURE);
+  }
+  check (ERANGE, "nbd_aio_pwrite: ");
+
   nbd_close (nbd);
   exit (EXIT_SUCCESS);
 }
diff --git a/tests/errors-server-oversize.c b/tests/errors-server-oversize.c
new file mode 100644
index 00000000..e55aafc3
--- /dev/null
+++ b/tests/errors-server-oversize.c
@@ -0,0 +1,151 @@
+/* NBD client library in userspace
+ * Copyright (C) 2013-2022 Red Hat Inc.
+ *
+ * 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
+ */
+
+/* Deliberately provoke some errors and check the error messages from
+ * nbd_get_error etc look reasonable.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <sys/stat.h>
+
+#include <libnbd.h>
+#include "requires.h"
+
+#define MAXSIZE 68157440 /* 65M, oversize on purpose */
+
+static char *progname;
+static char buf[MAXSIZE];
+
+static void
+check (int experr, const char *prefix)
+{
+  const char *msg = nbd_get_error ();
+  int errnum = nbd_get_errno ();
+
+  fprintf (stderr, "error: \"%s\"\n", msg);
+  fprintf (stderr, "errno: %d (%s)\n", errnum, strerror (errnum));
+  if (strncmp (msg, prefix, strlen (prefix)) != 0) {
+    fprintf (stderr, "%s: test failed: missing context prefix: %s\n",
+             progname, msg);
+    exit (EXIT_FAILURE);
+  }
+  if (errnum != experr) {
+    fprintf (stderr, "%s: test failed: "
+             "expected errno = %d (%s), but got %d\n",
+             progname, experr, strerror (experr), errnum);
+    exit (EXIT_FAILURE);
+  }
+}
+
+static void
+check_server_fail (struct nbd_handle *h, int64_t cookie,
+                   const char *cmd, int experr)
+{
+  int r;
+
+  if (cookie == -1) {
+    fprintf (stderr, "%s: test failed: %s not sent to server\n",
+             progname, cmd);
+    exit (EXIT_FAILURE);
+  }
+
+  while ((r = nbd_aio_command_completed (h, cookie)) == 0) {
+    if (nbd_poll (h, -1) == -1) {
+      fprintf (stderr, "%s: test failed: poll failed while awaiting %s: %s\n",
+               progname, cmd, nbd_get_error ());
+      exit (EXIT_FAILURE);
+    }
+  }
+
+  if (r != -1) {
+    fprintf (stderr, "%s: test failed: %s did not fail at server\n",
+             progname, cmd);
+    exit (EXIT_FAILURE);
+  }
+  check (experr, "nbd_aio_command_completed: ");
+}
+
+int
+main (int argc, char *argv[])
+{
+  struct nbd_handle *nbd;
+  const char *cmd[] = {
+    "nbdkit", "-s", "-v", "--exit-with-parent", "eval",
+    "get_size=    echo 68157440",
+    "block_size=  echo 1 512 16M",
+    "pread=       echo EIO >&2; exit 1",
+    "pwrite=      if test $3 -gt $((32*1024*1024)); then\n"
+    "               exit 6\n" /* Hard disconnect */
+    "             elif test $3 -gt $((16*1024*1024)); then\n"
+    "               echo EOVERFLOW >&2; exit 1\n"
+    "             fi\n"
+    "             cat >/dev/null",
+    NULL,
+  };
+  uint32_t strict;
+
+  progname = argv[0];
+  requires ("nbdkit --dump-plugin eval | grep ^max_known_status=");
+
+  nbd = nbd_create ();
+  if (nbd == NULL) {
+    fprintf (stderr, "%s\n", nbd_get_error ());
+    exit (EXIT_FAILURE);
+  }
+
+  /* Connect to the server. */
+  if (nbd_connect_command (nbd, (char **) cmd) == -1) {
+    fprintf (stderr, "%s: %s\n", argv[0], nbd_get_error ());
+    exit (EXIT_FAILURE);
+  }
+
+  /* Check the advertised max sizes. */
+  printf ("server block size maximum: %" PRIi64 "\n",
+          nbd_get_block_size (nbd, LIBNBD_SIZE_MAXIMUM));
+  printf ("libnbd payload size maximum: %" PRIi64 "\n",
+          nbd_get_block_size (nbd, LIBNBD_SIZE_PAYLOAD));
+
+  /* Disable client-side safety check */
+  strict = nbd_get_strict_mode (nbd) & ~LIBNBD_STRICT_PAYLOAD;
+  if (nbd_set_strict_mode (nbd, strict) == -1) {
+    fprintf (stderr, "%s\n", nbd_get_error ());
+    exit (EXIT_FAILURE);
+  }
+
+  /* Handle graceful server rejection of oversize request */
+  check_server_fail (nbd,
+                     nbd_aio_pwrite (nbd, buf, 17*1024*1024, 0,
+                                     NBD_NULL_COMPLETION, 0),
+                     "17M nbd_aio_pwrite", EINVAL);
+
+  /* Handle abrupt server rejection of oversize request */
+  check_server_fail (nbd,
+                     nbd_aio_pwrite (nbd, buf, 33*1024*1024, 0,
+                                     NBD_NULL_COMPLETION, 0),
+                     "33M nbd_aio_pwrite", ENOTCONN);
+
+  nbd_close (nbd);
+  exit (EXIT_SUCCESS);
+}
diff --git a/tests/errors-server-unaligned.c b/tests/errors-server-unaligned.c
index ac374976..6dbd6e29 100644
--- a/tests/errors-server-unaligned.c
+++ b/tests/errors-server-unaligned.c
@@ -123,6 +123,8 @@ main (int argc, char *argv[])
           nbd_get_block_size (nbd, LIBNBD_SIZE_PREFERRED));
   printf ("server block size maximum: %" PRIi64 "\n",
           nbd_get_block_size (nbd, LIBNBD_SIZE_MAXIMUM));
+  printf ("libnbd payload size maximum: %" PRIi64 "\n",
+          nbd_get_block_size (nbd, LIBNBD_SIZE_PAYLOAD));
   fflush (stdout);

   /* Send an unaligned read, server-side */
diff --git a/.gitignore b/.gitignore
index fe929d6d..f4273713 100644
--- a/.gitignore
+++ b/.gitignore
@@ -215,6 +215,7 @@ Makefile.in
 /tests/errors-poll-no-fd
 /tests/errors-pread-structured
 /tests/errors-server-invalid-offset
+/tests/errors-server-oversize
 /tests/errors-server-unadvertised-cmd
 /tests/errors-server-unaligned
 /tests/errors-server-unknown-flags
-- 
2.38.1



More information about the Libguestfs mailing list