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