New upstream version 1.1.12

- Enable Ruby plugin.
This commit is contained in:
Richard W.M. Jones 2016-06-08 14:59:47 +01:00
parent a85c67bc96
commit 3aedf9effc
13 changed files with 29 additions and 1684 deletions

View File

@ -1,39 +0,0 @@
From 5294b7d8cc011f8b5e068aad744f612df7414a82 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Sat, 31 Oct 2015 13:24:52 +0000
Subject: [PATCH 01/11] Add mandir to --dump-config output.
This is useful for external plugins that want to install
a man page.
---
src/Makefile.am | 1 +
src/main.c | 1 +
2 files changed, 2 insertions(+)
diff --git a/src/Makefile.am b/src/Makefile.am
index c0fb95a..fb46903 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -50,6 +50,7 @@ nbdkit_SOURCES = \
nbdkit_CPPFLAGS = \
-Dbindir=\"$(bindir)\" \
-Dlibdir=\"$(libdir)\" \
+ -Dmandir=\"$(mandir)\" \
-Dplugindir=\"$(plugindir)\" \
-Dsbindir=\"$(sbindir)\" \
-Dsysconfdir=\"$(sysconfdir)\" \
diff --git a/src/main.c b/src/main.c
index cd676c0..1248a8e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -129,6 +129,7 @@ dump_config (void)
{
printf ("%s=%s\n", "bindir", bindir);
printf ("%s=%s\n", "libdir", libdir);
+ printf ("%s=%s\n", "mandir", mandir);
printf ("%s=%s\n", "name", PACKAGE_NAME);
printf ("%s=%s\n", "plugindir", plugindir);
printf ("%s=%s\n", "sbindir", sbindir);
--
2.7.4

View File

@ -1,35 +0,0 @@
From 4b562134c3dad1a84aa92c1658e72046569e1570 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Mon, 11 Jan 2016 15:34:57 +0000
Subject: [PATCH 02/11] Update TODO.
---
TODO | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/TODO b/TODO
index bcf2276..a05aa5b 100644
--- a/TODO
+++ b/TODO
@@ -1,6 +1,8 @@
* There is a proposal to narrow the range of possible errnos that the
server can return, and also to encode them in an OS-independent way.
See: http://article.gmane.org/gmane.linux.drivers.nbd.general/3154
+ Implemented in QEMU already:
+ http://git.qemu.org/?p=qemu.git;a=commitdiff;h=ca4414804114fd0095b317785bc0b51862e62ebb
* Can we do language bindings using #!'s?
You would enter:
@@ -25,6 +27,9 @@
default that accepts all exportnames, or to divide the export name
"space" up using regexps or wildcards.
+ Annoyingly nbd-client dropped support for the oldstyle protocol (see
+ https://bugzilla.redhat.com/1297100).
+
* Implement true parallel request handling. Currently
NBDKIT_THREAD_MODEL_SERIALIZE_REQUESTS and
NBDKIT_THREAD_MODEL_PARALLEL are the same, because we handle
--
2.7.4

View File

@ -1,760 +0,0 @@
From f93807114634d58ca2ef0d64f7637ebd87e48a50 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Mon, 11 Jan 2016 17:08:51 +0000
Subject: [PATCH 03/11] Add support for newstyle NBD protocol (RHBZ#1297100).
---
.gitignore | 1 +
TODO | 10 +--
docs/nbdkit.pod | 67 +++++++++++++-
src/connections.c | 235 ++++++++++++++++++++++++++++++++++++++++++++++++--
src/internal.h | 1 +
src/main.c | 26 ++++--
src/protocol.h | 49 ++++++++++-
tests/Makefile.am | 8 ++
tests/test-newstyle.c | 102 ++++++++++++++++++++++
tests/test.c | 6 +-
tests/test.h | 2 +-
11 files changed, 483 insertions(+), 24 deletions(-)
create mode 100644 tests/test-newstyle.c
diff --git a/.gitignore b/.gitignore
index b1a8850..9ea072f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -43,6 +43,7 @@ Makefile.in
/tests/test-connect
/tests/test-file
/tests/test-gzip
+/tests/test-newstyle
/tests/test-ocaml
/tests/test-ocaml-plugin.so
/tests/test-perl
diff --git a/TODO b/TODO
index a05aa5b..d39e64c 100644
--- a/TODO
+++ b/TODO
@@ -17,9 +17,9 @@
* Performance - measure and improve it.
-* Implement the new protocol and export names. With export names it
- should be possible to have multiple plugins on the command line
- (each responding to a different export of course):
+* Implement export names. With export names it should be possible to
+ have multiple plugins on the command line (each responding to a
+ different export of course):
nbdkit --export /foo plugin.so --export /bar another-plugin.so
@@ -27,8 +27,8 @@
default that accepts all exportnames, or to divide the export name
"space" up using regexps or wildcards.
- Annoyingly nbd-client dropped support for the oldstyle protocol (see
- https://bugzilla.redhat.com/1297100).
+ Export names are not actually paths (although that is how they are
+ often used), but arbitrary UTF-8 text strings.
* Implement true parallel request handling. Currently
NBDKIT_THREAD_MODEL_SERIALIZE_REQUESTS and
diff --git a/docs/nbdkit.pod b/docs/nbdkit.pod
index 9ce75d3..7204a38 100644
--- a/docs/nbdkit.pod
+++ b/docs/nbdkit.pod
@@ -7,8 +7,8 @@ nbdkit - A toolkit for creating NBD servers
=head1 SYNOPSIS
nbdkit [--dump-config] [-f] [-g GROUP] [-i IPADDR]
- [-P PIDFILE] [-p PORT] [-r] [--run CMD] [-s]
- [-U SOCKET] [-u USER] [-v] [-V]
+ [--newstyle] [--oldstyle] [-P PIDFILE] [-p PORT] [-r]
+ [--run CMD] [-s] [-U SOCKET] [-u USER] [-v] [-V]
PLUGIN [key=value [key=value [...]]]
=head1 DESCRIPTION
@@ -103,6 +103,25 @@ See also I<-u>.
Listen on the specified interface. The default is to listen on all
interfaces. See also I<-p>.
+=item B<-n>
+
+=item B<--new-style>
+
+=item B<--newstyle>
+
+Use the newstyle NBD protocol instead of the default (oldstyle)
+protocol. See L</NEW STYLE VS OLD STYLE PROTOCOL> below.
+
+=item B<-o>
+
+=item B<--old-style>
+
+=item B<--oldstyle>
+
+Use the oldstyle NBD protocol. This is currently the default, so this
+flag does nothing, but it is possible we might change the default
+protocol in future. See L</NEW STYLE VS OLD STYLE PROTOCOL> below.
+
=item B<-P> PIDFILE
=item B<--pid-file> PIDFILE
@@ -280,6 +299,50 @@ Unix socket, like this:
nbdkit -U - plugin [args] --run '...'
+=head1 NEW STYLE VS OLD STYLE PROTOCOL
+
+The NBD protocol comes in two incompatible forms that we call
+"oldstyle" and "newstyle". Unfortunately which protocol you should
+use depends on the client and cannot be known in advance, nor can it
+be negotiated from the server side.
+
+nbdkit currently defaults to the oldstyle protocol for compatibility
+with qemu and libguestfs. This is also the same behaviour as
+qemu-nbd. Use the I<-n> or I<--newstyle> flag on the command line to
+use the newstyle protocol. Use the I<-o> or I<--oldstyle> flag to
+force the oldstyle protocol.
+
+Some common clients and the protocol they require:
+
+ Client Protocol
+ ------------------------------------------------------------
+ qemu without exportname oldstyle
+ qemu with exportname newstyle
+ nbd-client < 3.10 client can talk either protocol
+ nbd-client >= 3.10 newstyle
+
+If you use qemu without the exportname field against a newstyle
+server, it will give the error:
+
+ Server requires an export name
+
+If you use qemu with the exportname field against an oldstyle server,
+it will give the error:
+
+ Server does not support export names
+
+If you use the oldstyle protocol with nbd-client E<ge> 3.10, it will
+give the error:
+
+ Error: It looks like you're trying to connect to an oldstyle server.
+
+If you want to claim compatibility with what the NBD proto.txt
+document says should be the case (which isn't based in reality), then
+you should always use newstyle when using port 10809, and use oldstyle
+on all other ports.
+
+nbdkit ignores export names at present (see also the C<TODO> file).
+
=head1 SIGNALS
C<nbdkit> responds to the following signals:
diff --git a/src/connections.c b/src/connections.c
index 15f416b..6bdf4ef 100644
--- a/src/connections.c
+++ b/src/connections.c
@@ -1,5 +1,5 @@
/* nbdkit
- * Copyright (C) 2013 Red Hat Inc.
+ * Copyright (C) 2013-2016 Red Hat Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -52,6 +52,12 @@
/* Maximum read or write request that we will handle. */
#define MAX_REQUEST_SIZE (64 * 1024 * 1024)
+/* Maximum number of client options we allow before giving up. */
+#define MAX_NR_OPTIONS 32
+
+/* Maximum length of any option data (bytes). */
+#define MAX_OPTION_LENGTH 4096
+
static struct connection *new_connection (int sockin, int sockout);
static void free_connection (struct connection *conn);
static int negotiate_handshake (struct connection *conn);
@@ -143,11 +149,8 @@ free_connection (struct connection *conn)
free (conn);
}
-/* XXX Note because we don't support multiple plugins or export names,
- * we are using the old-style handshake. This will be fixed.
- */
static int
-_negotiate_handshake (struct connection *conn)
+_negotiate_handshake_oldstyle (struct connection *conn)
{
struct old_handshake handshake;
int64_t r;
@@ -201,7 +204,8 @@ _negotiate_handshake (struct connection *conn)
conn->can_trim = 1;
}
- debug ("flags: global 0x%x export 0x%x", gflags, eflags);
+ debug ("oldstyle negotiation: flags: global 0x%x export 0x%x",
+ gflags, eflags);
memset (&handshake, 0, sizeof handshake);
memcpy (handshake.nbdmagic, "NBDMAGIC", 8);
@@ -218,13 +222,230 @@ _negotiate_handshake (struct connection *conn)
return 0;
}
+/* Receive newstyle options.
+ *
+ * Currently we ignore NBD_OPT_EXPORT_NAME (see TODO), we close the
+ * connection if sent NBD_OPT_ABORT, we send a canned list of
+ * options for NBD_OPT_LIST, and we send NBD_REP_ERR_UNSUP for
+ * everything else.
+ */
+static int
+send_newstyle_option_reply (struct connection *conn,
+ uint32_t option, uint32_t reply)
+{
+ struct fixed_new_option_reply fixed_new_option_reply;
+
+ fixed_new_option_reply.magic = htobe64 (NEW_OPTION_REPLY);
+ fixed_new_option_reply.option = htobe32 (option);
+ fixed_new_option_reply.reply = htobe32 (reply);
+ fixed_new_option_reply.replylen = htobe32 (0);
+
+ if (xwrite (conn->sockout,
+ &fixed_new_option_reply, sizeof fixed_new_option_reply) == -1) {
+ nbdkit_error ("write: %m");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+_negotiate_handshake_newstyle_options (struct connection *conn)
+{
+ struct new_option new_option;
+ size_t nr_options;
+ uint64_t version;
+ uint32_t option;
+ uint32_t optlen;
+ char data[MAX_OPTION_LENGTH+1];
+
+ for (nr_options = 0; nr_options < MAX_NR_OPTIONS; ++nr_options) {
+ if (xread (conn->sockin, &new_option, sizeof new_option) == -1) {
+ nbdkit_error ("read: %m");
+ return -1;
+ }
+
+ version = be64toh (new_option.version);
+ if (version != NEW_VERSION) {
+ nbdkit_error ("unknown option version %" PRIx64
+ ", expecting %" PRIx64,
+ version, NEW_VERSION);
+ return -1;
+ }
+
+ /* There is a maximum option length we will accept, regardless
+ * of the option type.
+ */
+ optlen = be32toh (new_option.optlen);
+ if (optlen > MAX_OPTION_LENGTH) {
+ nbdkit_error ("client option data too long (%" PRIu32 ")", optlen);
+ return -1;
+ }
+
+ option = be32toh (new_option.option);
+ switch (option) {
+ case NBD_OPT_EXPORT_NAME:
+ if (xread (conn->sockin, data, optlen) == -1) {
+ nbdkit_error ("read: %m");
+ return -1;
+ }
+ /* Apart from printing it, ignore the export name. */
+ data[optlen] = '\0';
+ debug ("newstyle negotiation: client requested export '%s' (ignored)",
+ data);
+ break;
+
+ case NBD_OPT_ABORT:
+ if (send_newstyle_option_reply (conn, option, NBD_REP_ACK) == -1)
+ return -1;
+ nbdkit_error ("client sent NBD_OPT_ABORT to abort the connection");
+ return -1;
+
+ case NBD_OPT_LIST:
+ if (optlen != 0) {
+ if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
+ == -1)
+ return -1;
+ continue;
+ }
+
+ /* Since we don't support export names, there is nothing to list. */
+ if (send_newstyle_option_reply (conn, option, NBD_REP_ACK) == -1)
+ return -1;
+ break;
+
+ default:
+ /* Unknown option. */
+ if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_UNSUP) == -1)
+ return -1;
+ }
+
+ /* Note, since it's not very clear from the protocol doc, that the
+ * client must send NBD_OPT_EXPORT_NAME last, and that ends option
+ * negotiation.
+ */
+ if (option == NBD_OPT_EXPORT_NAME)
+ break;
+ }
+
+ if (nr_options >= MAX_NR_OPTIONS) {
+ nbdkit_error ("client exceeded maximum number of options (%d)",
+ MAX_NR_OPTIONS);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+_negotiate_handshake_newstyle (struct connection *conn)
+{
+ struct new_handshake handshake;
+ uint16_t gflags;
+ uint32_t cflags;
+ struct new_handshake_finish handshake_finish;
+ int64_t r;
+ uint64_t exportsize;
+ uint16_t eflags;
+ int fl;
+
+ gflags = NBD_FLAG_FIXED_NEWSTYLE;
+
+ debug ("newstyle negotiation: flags: global 0x%x", gflags);
+
+ memcpy (handshake.nbdmagic, "NBDMAGIC", 8);
+ handshake.version = htobe64 (NEW_VERSION);
+ handshake.gflags = htobe16 (gflags);
+
+ if (xwrite (conn->sockout, &handshake, sizeof handshake) == -1) {
+ nbdkit_error ("write: %m");
+ return -1;
+ }
+
+ /* Client now sends us its 32 bit flags word ... */
+ if (xread (conn->sockin, &cflags, sizeof cflags) == -1) {
+ nbdkit_error ("read: %m");
+ return -1;
+ }
+ cflags = be32toh (cflags);
+ /* ... which other than printing out, we ignore. */
+ debug ("newstyle negotiation: client flags: 0x%x", cflags);
+
+ /* Receive newstyle options. */
+ if (_negotiate_handshake_newstyle_options (conn) == -1)
+ return -1;
+
+ /* Finish the newstyle handshake. */
+ r = plugin_get_size (conn);
+ if (r == -1)
+ return -1;
+ if (r < 0) {
+ nbdkit_error (".get_size function returned invalid value "
+ "(%" PRIi64 ")", r);
+ return -1;
+ }
+ exportsize = (uint64_t) r;
+ conn->exportsize = exportsize;
+
+ eflags = NBD_FLAG_HAS_FLAGS;
+
+ fl = plugin_can_write (conn);
+ if (fl == -1)
+ return -1;
+ if (readonly || !fl) {
+ eflags |= NBD_FLAG_READ_ONLY;
+ conn->readonly = 1;
+ }
+
+ fl = plugin_can_flush (conn);
+ if (fl == -1)
+ return -1;
+ if (fl) {
+ eflags |= NBD_FLAG_SEND_FLUSH | NBD_FLAG_SEND_FUA;
+ conn->can_flush = 1;
+ }
+
+ fl = plugin_is_rotational (conn);
+ if (fl == -1)
+ return -1;
+ if (fl) {
+ eflags |= NBD_FLAG_ROTATIONAL;
+ conn->is_rotational = 1;
+ }
+
+ fl = plugin_can_trim (conn);
+ if (fl == -1)
+ return -1;
+ if (fl) {
+ eflags |= NBD_FLAG_SEND_TRIM;
+ conn->can_trim = 1;
+ }
+
+ debug ("newstyle negotiation: flags: export 0x%x", eflags);
+
+ memset (&handshake_finish, 0, sizeof handshake_finish);
+ handshake_finish.exportsize = htobe64 (exportsize);
+ handshake_finish.eflags = htobe16 (eflags);
+
+ if (xwrite (conn->sockout,
+ &handshake_finish, sizeof handshake_finish) == -1) {
+ nbdkit_error ("write: %m");
+ return -1;
+ }
+
+ return 0;
+}
+
static int
negotiate_handshake (struct connection *conn)
{
int r;
plugin_lock_request (conn);
- r = _negotiate_handshake (conn);
+ if (!newstyle)
+ r = _negotiate_handshake_oldstyle (conn);
+ else
+ r = _negotiate_handshake_newstyle (conn);
plugin_unlock_request (conn);
return r;
diff --git a/src/internal.h b/src/internal.h
index c834b14..0603779 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -49,6 +49,7 @@
/* main.c */
extern const char *ipaddr;
+extern int newstyle;
extern const char *port;
extern int readonly;
extern char *unixsocket;
diff --git a/src/main.c b/src/main.c
index 1248a8e..db4361e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,5 +1,5 @@
/* nbdkit
- * Copyright (C) 2013-2014 Red Hat Inc.
+ * Copyright (C) 2013-2016 Red Hat Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -67,11 +67,12 @@ static gid_t parsegroup (const char *);
int foreground; /* -f */
const char *ipaddr; /* -i */
-int listen_stdin; /* -s */
+int newstyle; /* -n */
char *pidfile; /* -P */
const char *port; /* -p */
int readonly; /* -r */
char *run; /* --run */
+int listen_stdin; /* -s */
char *unixsocket; /* -U */
const char *user, *group; /* -u & -g */
int verbose; /* -v */
@@ -83,7 +84,7 @@ static char *random_fifo = NULL;
enum { HELP_OPTION = CHAR_MAX + 1 };
-static const char *short_options = "fg:i:p:P:rsu:U:vV";
+static const char *short_options = "fg:i:nop:P:rsu:U:vV";
static const struct option long_options[] = {
{ "help", 0, NULL, HELP_OPTION },
{ "dump-config",0, NULL, 0 },
@@ -92,6 +93,10 @@ static const struct option long_options[] = {
{ "group", 1, NULL, 'g' },
{ "ip-addr", 1, NULL, 'i' },
{ "ipaddr", 1, NULL, 'i' },
+ { "new-style", 1, NULL, 'n' },
+ { "newstyle", 1, NULL, 'n' },
+ { "old-style", 1, NULL, 'o' },
+ { "oldstyle", 1, NULL, 'o' },
{ "pid-file", 1, NULL, 'P' },
{ "pidfile", 1, NULL, 'P' },
{ "port", 1, NULL, 'p' },
@@ -111,8 +116,8 @@ static void
usage (void)
{
printf ("nbdkit [--dump-config] [-f] [-g GROUP] [-i IPADDR]\n"
- " [-P PIDFILE] [-p PORT] [-r] [--run CMD] [-s]\n"
- " [-U SOCKET] [-u USER] [-v] [-V]\n"
+ " [--newstyle] [--oldstyle] [-P PIDFILE] [-p PORT] [-r]\n"
+ " [--run CMD] [-s] [-U SOCKET] [-u USER] [-v] [-V]\n"
" PLUGIN [key=value [key=value [...]]]\n"
"\n"
"Please read the nbdkit(1) manual page for full usage.\n");
@@ -180,6 +185,17 @@ main (int argc, char *argv[])
ipaddr = optarg;
break;
+ case 'n':
+ newstyle = 1;
+ break;
+
+ case 'o':
+ /* XXX When we add support for exportnames, we will need to
+ * ensure that the user does not use -o + --export.
+ */
+ newstyle = 0;
+ break;
+
case 'P':
pidfile = nbdkit_absolute_path (optarg);
if (pidfile == NULL)
diff --git a/src/protocol.h b/src/protocol.h
index 4449171..2f9a341 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -36,7 +36,7 @@
#include <stdint.h>
-/* Old-style handshake */
+/* Old-style handshake. */
struct old_handshake {
char nbdmagic[8]; /* "NBDMAGIC" */
uint64_t version; /* OLD_VERSION, in network byte order */
@@ -48,6 +48,41 @@ struct old_handshake {
#define OLD_VERSION UINT64_C(0x420281861253)
+/* New-style handshake. */
+struct new_handshake {
+ char nbdmagic[8]; /* "NBDMAGIC" */
+ uint64_t version; /* NEW_VERSION, in network byte order */
+ uint16_t gflags; /* global flags, in network byte order */
+} __attribute__((packed));
+
+#define NEW_VERSION UINT64_C(0x49484156454F5054)
+
+/* New-style handshake option (sent by the client to us). */
+struct new_option {
+ uint64_t version; /* NEW_VERSION, in network byte order */
+ uint32_t option; /* NBD_OPT_* */
+ uint32_t optlen; /* option data length */
+ /* option data follows */
+} __attribute__((packed));
+
+/* Fixed newstyle handshake reply message. */
+struct fixed_new_option_reply {
+ uint64_t magic; /* NEW_OPTION_REPLY, network byte order */
+ uint32_t option; /* option we are replying to */
+ uint32_t reply; /* NBD_REP_* */
+ uint32_t replylen; /* we always send zero at the moment */
+ /* reply data follows, but we currently never send any */
+};
+
+#define NEW_OPTION_REPLY UINT64_C(0x3e889045565a9)
+
+/* New-style handshake server reply. */
+struct new_handshake_finish {
+ uint64_t exportsize; /* in network byte order */
+ uint16_t eflags; /* per-export flags, in network byte order */
+ char zeroes[124]; /* must be sent as zero bytes */
+} __attribute__((packed));
+
/* Global flags. */
#define NBD_FLAG_FIXED_NEWSTYLE 1
@@ -59,6 +94,18 @@ struct old_handshake {
#define NBD_FLAG_ROTATIONAL 16
#define NBD_FLAG_SEND_TRIM 32
+/* NBD options (new style handshake only). */
+#define NBD_OPT_EXPORT_NAME 1
+#define NBD_OPT_ABORT 2
+#define NBD_OPT_LIST 3
+
+#define NBD_REP_ACK 1
+#define NBD_REP_SERVER 2
+#define NBD_REP_ERR_UNSUP 0x80000001
+#define NBD_REP_ERR_POLICY 0x80000002
+#define NBD_REP_ERR_INVALID 0x80000003
+#define NBD_REP_ERR_PLATFORM 0x80000004
+
/* Request (client -> server). */
struct request {
uint32_t magic; /* NBD_REQUEST_MAGIC. */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 511c39c..8d27032 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -103,6 +103,14 @@ file-data:
for f in `seq 1 512`; do echo -ne '\x01\x02\x03\x04\x05\x06\x07\x08'; done > $@-t
mv $@-t $@
+# newstyle protocol test.
+check_PROGRAMS += test-newstyle
+TESTS += test-newstyle
+
+test_newstyle_SOURCES = test-newstyle.c test.h
+test_newstyle_CFLAGS = $(WARNINGS_CFLAGS) $(LIBGUESTFS_CFLAGS)
+test_newstyle_LDADD = libtest.la $(LIBGUESTFS_LIBS)
+
# gzip plugin test.
if HAVE_ZLIB
if HAVE_GUESTFISH
diff --git a/tests/test-newstyle.c b/tests/test-newstyle.c
new file mode 100644
index 0000000..b1d8ce7
--- /dev/null
+++ b/tests/test-newstyle.c
@@ -0,0 +1,102 @@
+/* nbdkit
+ * Copyright (C) 2013-2016 Red Hat Inc.
+ * All rights reserved.
+ *
+ * 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 <inttypes.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <guestfs.h>
+
+#include "test.h"
+
+int
+main (int argc, char *argv[])
+{
+ guestfs_h *g;
+ int r;
+ char *data;
+ size_t i, size;
+
+ if (test_start_nbdkit ("-n", NBDKIT_PLUGIN ("file"), "file=file-data",
+ NULL) == -1)
+ exit (EXIT_FAILURE);
+
+ g = guestfs_create ();
+ if (g == NULL) {
+ perror ("guestfs_create");
+ exit (EXIT_FAILURE);
+ }
+
+ /* Using any exportname causes qemu to use the newstyle protocol. */
+ r = guestfs_add_drive_opts (g, "/" /* exportname */,
+ GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw",
+ GUESTFS_ADD_DRIVE_OPTS_PROTOCOL, "nbd",
+ GUESTFS_ADD_DRIVE_OPTS_SERVER, server,
+ -1);
+ if (r == -1)
+ exit (EXIT_FAILURE);
+
+ if (guestfs_launch (g) == -1)
+ exit (EXIT_FAILURE);
+
+ /* Check the data in the file is \x01-\x08 repeated 512 times. */
+ data = guestfs_pread_device (g, "/dev/sda", 8 * 512, 0, &size);
+ if (!data)
+ exit (EXIT_FAILURE);
+ if (size != 8 * 512) {
+ fprintf (stderr, "%s FAILED: unexpected size (actual: %zu, expected: 512)\n",
+ program_name, size);
+ exit (EXIT_FAILURE);
+ }
+
+ for (i = 0; i < 512 * 8; i += 8) {
+ if (data[i] != 1 || data[i+1] != 2 ||
+ data[i+2] != 3 || data[i+3] != 4 ||
+ data[i+4] != 5 || data[i+5] != 6 ||
+ data[i+6] != 7 || data[i+7] != 8) {
+ fprintf (stderr, "%s FAILED: unexpected data returned at offset %zu\n",
+ program_name, i);
+ exit (EXIT_FAILURE);
+ }
+ }
+
+ free (data);
+
+ guestfs_close (g);
+ exit (EXIT_SUCCESS);
+}
diff --git a/tests/test.c b/tests/test.c
index 55d13fd..111e6fa 100644
--- a/tests/test.c
+++ b/tests/test.c
@@ -68,7 +68,7 @@ cleanup (void)
}
int
-test_start_nbdkit (const char *plugin, ...)
+test_start_nbdkit (const char *arg, ...)
{
size_t i, len;
@@ -95,10 +95,10 @@ test_start_nbdkit (const char *plugin, ...)
argv[4] = pidpath;
argv[5] = "-f";
argv[6] = "-v";
- argv[7] = plugin;
+ argv[7] = arg;
i = 8;
- va_start (args, plugin);
+ va_start (args, arg);
while ((p = va_arg (args, const char *)) != NULL) {
if (i >= MAX_ARGS)
abort ();
diff --git a/tests/test.h b/tests/test.h
index 7abf5af..c369150 100644
--- a/tests/test.h
+++ b/tests/test.h
@@ -45,7 +45,7 @@
extern pid_t pid; /* PID of nbdkit process. */
extern const char *server[2]; /* server parameter for add_drive */
-extern int test_start_nbdkit (const char *plugin, ...);
+extern int test_start_nbdkit (const char *arg, ...);
/* Declare program_name. */
#if HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME == 1
--
2.7.4

View File

@ -1,49 +0,0 @@
From 0759d15aa3649d088eeae91fcd174d0b37e1ccde Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Mon, 11 Jan 2016 19:02:53 +0000
Subject: [PATCH 04/11] xz: Fix various printf warnings on 32 bit.
xzfile.c: In function 'xzfile_read_block':
xzfile.c:456:19: warning: format '%zu' expects argument of type 'size_t', but argument 2 has type 'uint64_t {aka long long unsigned int}' [-Wformat=]
nbdkit_error ("malloc (%zu bytes): %m\n"
^
xz.c: In function 'xz_close':
xz.c:191:17: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 2 has type 'size_t {aka unsigned int}' [-Wformat=]
nbdkit_debug ("cache: hits = %" PRIu64 ", misses = %" PRIu64,
^
xz.c:191:17: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 3 has type 'size_t {aka unsigned int}' [-Wformat=]
---
plugins/xz/xz.c | 3 +--
plugins/xz/xzfile.c | 2 +-
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/plugins/xz/xz.c b/plugins/xz/xz.c
index 9a1f5e5..437f798 100644
--- a/plugins/xz/xz.c
+++ b/plugins/xz/xz.c
@@ -188,8 +188,7 @@ xz_close (void *handle)
blkcache_get_stats (h->c, &stats);
- nbdkit_debug ("cache: hits = %" PRIu64 ", misses = %" PRIu64,
- stats.hits, stats.misses);
+ nbdkit_debug ("cache: hits = %zu, misses = %zu", stats.hits, stats.misses);
xzfile_close (h->xz);
free_blkcache (h->c);
diff --git a/plugins/xz/xzfile.c b/plugins/xz/xzfile.c
index fcc2937..3633099 100644
--- a/plugins/xz/xzfile.c
+++ b/plugins/xz/xzfile.c
@@ -453,7 +453,7 @@ xzfile_read_block (xzfile *xz, uint64_t offset,
data = malloc (*size_rtn);
if (data == NULL) {
- nbdkit_error ("malloc (%zu bytes): %m\n"
+ nbdkit_error ("malloc (%" PRIu64 " bytes): %m\n"
"NOTE: If this error occurs, you need to recompress your xz files with a smaller block size. Use: 'xz --block-size=16777216 ...'.",
*size_rtn);
goto err1;
--
2.7.4

View File

@ -1,28 +0,0 @@
From b6db2f65596470492f0ad76d1ed63ddb98b17167 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Mon, 11 Jan 2016 19:46:37 +0000
Subject: [PATCH 05/11] ocaml: Avoid race when building NBDKit.cmi.
If both the NBDKit.cmi and NBDKit.cmx builds run in parallel, both
will try to build NBDKit.cmi, resulting in a corrupt NBDKit.cmi file.
Avoid this by adding an extra dependency.
---
plugins/ocaml/Makefile.am | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/plugins/ocaml/Makefile.am b/plugins/ocaml/Makefile.am
index d4776b3..f63ba33 100644
--- a/plugins/ocaml/Makefile.am
+++ b/plugins/ocaml/Makefile.am
@@ -43,7 +43,7 @@ ocamllib_DATA = NBDKit.mli NBDKit.cmi NBDKit.cmx NBDKit.o
NBDKit.cmi: NBDKit.mli
$(OCAMLC) -c $<
-NBDKit.cmx: NBDKit.ml
+NBDKit.cmx: NBDKit.ml NBDKit.cmi
$(OCAMLOPT) $(OCAMLOPTFLAGS) -c $<
NBDKit.o: NBDKit.cmx
--
2.7.4

View File

@ -1,154 +0,0 @@
From 1c359d1140fee575cf478e2b4bf0c5ca0af9d05e Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Mon, 11 Jan 2016 20:34:28 +0000
Subject: [PATCH 06/11] Test the -o (oldstyle) command line option.
---
.gitignore | 1 +
tests/Makefile.am | 8 ++++
tests/test-oldstyle.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 111 insertions(+)
create mode 100644 tests/test-oldstyle.c
diff --git a/.gitignore b/.gitignore
index 9ea072f..bc151ca 100644
--- a/.gitignore
+++ b/.gitignore
@@ -46,6 +46,7 @@ Makefile.in
/tests/test-newstyle
/tests/test-ocaml
/tests/test-ocaml-plugin.so
+/tests/test-oldstyle
/tests/test-perl
/tests/test-python
/tests/test-streaming
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 8d27032..1e6114c 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -111,6 +111,14 @@ test_newstyle_SOURCES = test-newstyle.c test.h
test_newstyle_CFLAGS = $(WARNINGS_CFLAGS) $(LIBGUESTFS_CFLAGS)
test_newstyle_LDADD = libtest.la $(LIBGUESTFS_LIBS)
+# oldstyle protocol test.
+check_PROGRAMS += test-oldstyle
+TESTS += test-oldstyle
+
+test_oldstyle_SOURCES = test-oldstyle.c test.h
+test_oldstyle_CFLAGS = $(WARNINGS_CFLAGS) $(LIBGUESTFS_CFLAGS)
+test_oldstyle_LDADD = libtest.la $(LIBGUESTFS_LIBS)
+
# gzip plugin test.
if HAVE_ZLIB
if HAVE_GUESTFISH
diff --git a/tests/test-oldstyle.c b/tests/test-oldstyle.c
new file mode 100644
index 0000000..d809a0c
--- /dev/null
+++ b/tests/test-oldstyle.c
@@ -0,0 +1,102 @@
+/* nbdkit
+ * Copyright (C) 2013-2016 Red Hat Inc.
+ * All rights reserved.
+ *
+ * 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 <inttypes.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <guestfs.h>
+
+#include "test.h"
+
+int
+main (int argc, char *argv[])
+{
+ guestfs_h *g;
+ int r;
+ char *data;
+ size_t i, size;
+
+ if (test_start_nbdkit ("-o", NBDKIT_PLUGIN ("file"), "file=file-data",
+ NULL) == -1)
+ exit (EXIT_FAILURE);
+
+ g = guestfs_create ();
+ if (g == NULL) {
+ perror ("guestfs_create");
+ exit (EXIT_FAILURE);
+ }
+
+ /* Using exportname = "" causes qemu to use the oldstyle protocol. */
+ r = guestfs_add_drive_opts (g, "",
+ GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw",
+ GUESTFS_ADD_DRIVE_OPTS_PROTOCOL, "nbd",
+ GUESTFS_ADD_DRIVE_OPTS_SERVER, server,
+ -1);
+ if (r == -1)
+ exit (EXIT_FAILURE);
+
+ if (guestfs_launch (g) == -1)
+ exit (EXIT_FAILURE);
+
+ /* Check the data in the file is \x01-\x08 repeated 512 times. */
+ data = guestfs_pread_device (g, "/dev/sda", 8 * 512, 0, &size);
+ if (!data)
+ exit (EXIT_FAILURE);
+ if (size != 8 * 512) {
+ fprintf (stderr, "%s FAILED: unexpected size (actual: %zu, expected: 512)\n",
+ program_name, size);
+ exit (EXIT_FAILURE);
+ }
+
+ for (i = 0; i < 512 * 8; i += 8) {
+ if (data[i] != 1 || data[i+1] != 2 ||
+ data[i+2] != 3 || data[i+3] != 4 ||
+ data[i+4] != 5 || data[i+5] != 6 ||
+ data[i+6] != 7 || data[i+7] != 8) {
+ fprintf (stderr, "%s FAILED: unexpected data returned at offset %zu\n",
+ program_name, i);
+ exit (EXIT_FAILURE);
+ }
+ }
+
+ free (data);
+
+ guestfs_close (g);
+ exit (EXIT_SUCCESS);
+}
--
2.7.4

View File

@ -1,116 +0,0 @@
From f141228d1b6baddadcd516137d76b3d852af8cde Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Tue, 12 Jan 2016 12:16:48 +0000
Subject: [PATCH 07/11] protocol: Send limited range of errno values to the
client.
See the proposal here:
http://article.gmane.org/gmane.linux.drivers.nbd.general/3154
This implementation is based on Paolo Bonzini's for qemu-nbd:
http://git.qemu.org/?p=qemu.git;a=commitdiff;h=ca4414804114fd0095b317785bc0b51862e62ebb
---
TODO | 6 ------
src/connections.c | 36 +++++++++++++++++++++++++++++++++++-
src/protocol.h | 12 +++++++++++-
3 files changed, 46 insertions(+), 8 deletions(-)
diff --git a/TODO b/TODO
index d39e64c..177a07c 100644
--- a/TODO
+++ b/TODO
@@ -1,9 +1,3 @@
-* There is a proposal to narrow the range of possible errnos that the
- server can return, and also to encode them in an OS-independent way.
- See: http://article.gmane.org/gmane.linux.drivers.nbd.general/3154
- Implemented in QEMU already:
- http://git.qemu.org/?p=qemu.git;a=commitdiff;h=ca4414804114fd0095b317785bc0b51862e62ebb
-
* Can we do language bindings using #!'s?
You would enter:
nbdkit foo [args]
diff --git a/src/connections.c b/src/connections.c
index 6bdf4ef..f0a7662 100644
--- a/src/connections.c
+++ b/src/connections.c
@@ -639,6 +639,31 @@ skip_over_write_buffer (int sock, size_t count)
}
}
+/* Convert a system errno to an NBD_E* error code. */
+static int
+nbd_errno (int error)
+{
+ switch (error) {
+ case 0:
+ return NBD_SUCCESS;
+ case EPERM:
+ return NBD_EPERM;
+ case EIO:
+ return NBD_EIO;
+ case ENOMEM:
+ return NBD_ENOMEM;
+#ifdef EDQUOT
+ case EDQUOT:
+#endif
+ case EFBIG:
+ case ENOSPC:
+ return NBD_ENOSPC;
+ case EINVAL:
+ default:
+ return NBD_EINVAL;
+ }
+}
+
static int
recv_request_send_reply (struct connection *conn)
{
@@ -722,7 +747,16 @@ recv_request_send_reply (struct connection *conn)
send_reply:
reply.magic = htobe32 (NBD_REPLY_MAGIC);
reply.handle = request.handle;
- reply.error = htobe32 (error);
+ reply.error = htobe32 (nbd_errno (error));
+
+ if (error != 0) {
+ /* Since we're about to send only the limited NBD_E* errno to the
+ * client, don't lose the information about what really happened
+ * on the server side. Make sure there is a way for the operator
+ * to retrieve the real error.
+ */
+ debug ("sending error reply: %s", strerror (error));
+ }
r = xwrite (conn->sockout, &reply, sizeof reply);
if (r == -1) {
diff --git a/src/protocol.h b/src/protocol.h
index 2f9a341..fcbc145 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -118,7 +118,7 @@ struct request {
/* Reply (server -> client). */
struct reply {
uint32_t magic; /* NBD_REPLY_MAGIC. */
- uint32_t error; /* 0 = ok, error code */
+ uint32_t error; /* NBD_SUCCESS or one of NBD_E*. */
uint64_t handle; /* Opaque handle. */
} __attribute__((packed));
@@ -133,4 +133,14 @@ struct reply {
#define NBD_CMD_MASK_COMMAND 0xffff
#define NBD_CMD_FLAG_FUA (1<<16)
+/* Error codes (previously errno).
+ * See http://git.qemu.org/?p=qemu.git;a=commitdiff;h=ca4414804114fd0095b317785bc0b51862e62ebb
+ */
+#define NBD_SUCCESS 0
+#define NBD_EPERM 1
+#define NBD_EIO 5
+#define NBD_ENOMEM 12
+#define NBD_EINVAL 22
+#define NBD_ENOSPC 28
+
#endif /* NBDKIT_PROTOCOL_H */
--
2.7.4

View File

@ -1,27 +0,0 @@
From e5a945ea1e759e6441773c1e7663a1ac2492c8e4 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Tue, 17 May 2016 19:40:29 +0100
Subject: [PATCH 08/11] protocol: Pack fixed_new_option_reply struct.
This struct was not packed, but we were sending a reply by sending the
struct directly onto the wire. I think we got away with it, but not good.
---
src/protocol.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/protocol.h b/src/protocol.h
index fcbc145..de511a6 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -72,7 +72,7 @@ struct fixed_new_option_reply {
uint32_t reply; /* NBD_REP_* */
uint32_t replylen; /* we always send zero at the moment */
/* reply data follows, but we currently never send any */
-};
+} __attribute__((packed));
#define NEW_OPTION_REPLY UINT64_C(0x3e889045565a9)
--
2.7.4

View File

@ -1,48 +0,0 @@
From f989fbad9b0527925c38f4350190cb1536a4d8c2 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Tue, 17 May 2016 19:42:35 +0100
Subject: [PATCH 09/11] protocol: Rename NEW_OPTION_REPLY as NBD_REP_MAGIC.
To be consistent with qemu's implementation.
---
src/connections.c | 2 +-
src/protocol.h | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/connections.c b/src/connections.c
index f0a7662..34566b3 100644
--- a/src/connections.c
+++ b/src/connections.c
@@ -235,7 +235,7 @@ send_newstyle_option_reply (struct connection *conn,
{
struct fixed_new_option_reply fixed_new_option_reply;
- fixed_new_option_reply.magic = htobe64 (NEW_OPTION_REPLY);
+ fixed_new_option_reply.magic = htobe64 (NBD_REP_MAGIC);
fixed_new_option_reply.option = htobe32 (option);
fixed_new_option_reply.reply = htobe32 (reply);
fixed_new_option_reply.replylen = htobe32 (0);
diff --git a/src/protocol.h b/src/protocol.h
index de511a6..71a8098 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -67,14 +67,14 @@ struct new_option {
/* Fixed newstyle handshake reply message. */
struct fixed_new_option_reply {
- uint64_t magic; /* NEW_OPTION_REPLY, network byte order */
+ uint64_t magic; /* NBD_REP_MAGIC, network byte order */
uint32_t option; /* option we are replying to */
uint32_t reply; /* NBD_REP_* */
uint32_t replylen; /* we always send zero at the moment */
/* reply data follows, but we currently never send any */
} __attribute__((packed));
-#define NEW_OPTION_REPLY UINT64_C(0x3e889045565a9)
+#define NBD_REP_MAGIC UINT64_C(0x3e889045565a9)
/* New-style handshake server reply. */
struct new_handshake_finish {
--
2.7.4

View File

@ -1,360 +0,0 @@
From 0095b003b56894baad8e6789d523cf3c51905c05 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Tue, 17 May 2016 19:43:16 +0100
Subject: [PATCH 10/11] Implement newstyle export names.
This is now required by qemu >= 2.6. See this lengthy qemu-devel
thread for details:
https://lists.nongnu.org/archive/html/qemu-devel/2016-05/threads.html#02752
---
TODO | 13 -------------
docs/nbdkit.pod | 52 ++++++++++++++++++++++++++++++++-------------------
src/connections.c | 49 ++++++++++++++++++++++++++++++++++++++++--------
src/internal.h | 1 +
src/main.c | 32 +++++++++++++++++++++++--------
src/protocol.h | 3 +--
tests/test-newstyle.c | 7 +++++--
7 files changed, 105 insertions(+), 52 deletions(-)
diff --git a/TODO b/TODO
index 177a07c..30bf72e 100644
--- a/TODO
+++ b/TODO
@@ -11,19 +11,6 @@
* Performance - measure and improve it.
-* Implement export names. With export names it should be possible to
- have multiple plugins on the command line (each responding to a
- different export of course):
-
- nbdkit --export /foo plugin.so --export /bar another-plugin.so
-
- Note it should also be possible to either elect one plugin as the
- default that accepts all exportnames, or to divide the export name
- "space" up using regexps or wildcards.
-
- Export names are not actually paths (although that is how they are
- often used), but arbitrary UTF-8 text strings.
-
* Implement true parallel request handling. Currently
NBDKIT_THREAD_MODEL_SERIALIZE_REQUESTS and
NBDKIT_THREAD_MODEL_PARALLEL are the same, because we handle
diff --git a/docs/nbdkit.pod b/docs/nbdkit.pod
index 7204a38..728aad3 100644
--- a/docs/nbdkit.pod
+++ b/docs/nbdkit.pod
@@ -6,7 +6,7 @@ nbdkit - A toolkit for creating NBD servers
=head1 SYNOPSIS
- nbdkit [--dump-config] [-f] [-g GROUP] [-i IPADDR]
+ nbdkit [--dump-config] [-e EXPORTNAME] [-f] [-g GROUP] [-i IPADDR]
[--newstyle] [--oldstyle] [-P PIDFILE] [-p PORT] [-r]
[--run CMD] [-s] [-U SOCKET] [-u USER] [-v] [-V]
PLUGIN [key=value [key=value [...]]]
@@ -74,6 +74,19 @@ Display brief command line usage information and exit.
Dump out the compile-time configuration values and exit.
+=item B<-e> EXPORTNAME
+
+=item B<--export> EXPORTNAME
+
+=item B<--export-name> EXPORTNAME
+
+=item B<--exportname> EXPORTNAME
+
+Set the exportname and use the newstyle protocol (implies I<-n>).
+
+If not set, exportname C<""> (empty string) is used. Exportnames are
+not allowed with the oldstyle protocol.
+
=item B<-f>
=item B<--foreground>
@@ -118,9 +131,10 @@ protocol. See L</NEW STYLE VS OLD STYLE PROTOCOL> below.
=item B<--oldstyle>
-Use the oldstyle NBD protocol. This is currently the default, so this
-flag does nothing, but it is possible we might change the default
-protocol in future. See L</NEW STYLE VS OLD STYLE PROTOCOL> below.
+Use the oldstyle NBD protocol. This is currently the default (unless
+you use I<-n> or I<-e>), so this flag does nothing, but it is possible
+we might change the default protocol in future. See L</NEW STYLE VS
+OLD STYLE PROTOCOL> below.
=item B<-P> PIDFILE
@@ -307,27 +321,29 @@ use depends on the client and cannot be known in advance, nor can it
be negotiated from the server side.
nbdkit currently defaults to the oldstyle protocol for compatibility
-with qemu and libguestfs. This is also the same behaviour as
-qemu-nbd. Use the I<-n> or I<--newstyle> flag on the command line to
-use the newstyle protocol. Use the I<-o> or I<--oldstyle> flag to
-force the oldstyle protocol.
+with qemu and libguestfs. This is also the same behaviour as qemu-nbd
+E<le> 2.5. Use the I<-n> or I<--newstyle> flag on the command line to
+use the newstyle protocol. Use the I<-e> or I<--exportname> flag to
+set the exportname for the newstyle protocol. Use the I<-o> or
+I<--oldstyle> flag to force the oldstyle protocol.
Some common clients and the protocol they require:
- Client Protocol
+ Client Protocol
------------------------------------------------------------
- qemu without exportname oldstyle
- qemu with exportname newstyle
- nbd-client < 3.10 client can talk either protocol
- nbd-client >= 3.10 newstyle
+ qemu <= 2.5 without exportname oldstyle
+ qemu <= 2.5 with exportname newstyle
+ qemu >= 2.6 client can talk either protocol
+ nbd-client < 3.10 client can talk either protocol
+ nbd-client >= 3.10 newstyle
-If you use qemu without the exportname field against a newstyle
-server, it will give the error:
+If you use qemu E<le> 2.5 without the exportname field against a
+newstyle server, it will give the error:
Server requires an export name
-If you use qemu with the exportname field against an oldstyle server,
-it will give the error:
+If you use qemu E<le> 2.5 with the exportname field against an
+oldstyle server, it will give the error:
Server does not support export names
@@ -341,8 +357,6 @@ document says should be the case (which isn't based in reality), then
you should always use newstyle when using port 10809, and use oldstyle
on all other ports.
-nbdkit ignores export names at present (see also the C<TODO> file).
-
=head1 SIGNALS
C<nbdkit> responds to the following signals:
diff --git a/src/connections.c b/src/connections.c
index 34566b3..0c93f35 100644
--- a/src/connections.c
+++ b/src/connections.c
@@ -222,13 +222,8 @@ _negotiate_handshake_oldstyle (struct connection *conn)
return 0;
}
-/* Receive newstyle options.
- *
- * Currently we ignore NBD_OPT_EXPORT_NAME (see TODO), we close the
- * connection if sent NBD_OPT_ABORT, we send a canned list of
- * options for NBD_OPT_LIST, and we send NBD_REP_ERR_UNSUP for
- * everything else.
- */
+/* Receive newstyle options. */
+
static int
send_newstyle_option_reply (struct connection *conn,
uint32_t option, uint32_t reply)
@@ -250,6 +245,39 @@ send_newstyle_option_reply (struct connection *conn,
}
static int
+send_newstyle_option_reply_exportname (struct connection *conn,
+ uint32_t option, uint32_t reply,
+ const char *exportname)
+{
+ struct fixed_new_option_reply fixed_new_option_reply;
+ size_t name_len = strlen (exportname);
+ uint32_t len;
+
+ fixed_new_option_reply.magic = htobe64 (NBD_REP_MAGIC);
+ fixed_new_option_reply.option = htobe32 (option);
+ fixed_new_option_reply.reply = htobe32 (reply);
+ fixed_new_option_reply.replylen = htobe32 (name_len + sizeof (len));
+
+ if (xwrite (conn->sockout,
+ &fixed_new_option_reply, sizeof fixed_new_option_reply) == -1) {
+ nbdkit_error ("write: %m");
+ return -1;
+ }
+
+ len = htobe32 (name_len);
+ if (xwrite (conn->sockout, &len, sizeof len) == -1) {
+ nbdkit_error ("write: %m");
+ return -1;
+ }
+ if (xwrite (conn->sockout, exportname, name_len) == -1) {
+ nbdkit_error ("write: %m");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
_negotiate_handshake_newstyle_options (struct connection *conn)
{
struct new_option new_option;
@@ -309,7 +337,12 @@ _negotiate_handshake_newstyle_options (struct connection *conn)
continue;
}
- /* Since we don't support export names, there is nothing to list. */
+ /* Send back the exportname. */
+ debug ("newstyle negotiation: advertising export '%s'", exportname);
+ if (send_newstyle_option_reply_exportname (conn, option, NBD_REP_SERVER,
+ exportname) == -1)
+ return -1;
+
if (send_newstyle_option_reply (conn, option, NBD_REP_ACK) == -1)
return -1;
break;
diff --git a/src/internal.h b/src/internal.h
index 0603779..f58086a 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -48,6 +48,7 @@
#endif
/* main.c */
+extern const char *exportname;
extern const char *ipaddr;
extern int newstyle;
extern const char *port;
diff --git a/src/main.c b/src/main.c
index db4361e..9529f19 100644
--- a/src/main.c
+++ b/src/main.c
@@ -65,6 +65,7 @@ static void fork_into_background (void);
static uid_t parseuser (const char *);
static gid_t parsegroup (const char *);
+const char *exportname; /* -e */
int foreground; /* -f */
const char *ipaddr; /* -i */
int newstyle; /* -n */
@@ -84,10 +85,13 @@ static char *random_fifo = NULL;
enum { HELP_OPTION = CHAR_MAX + 1 };
-static const char *short_options = "fg:i:nop:P:rsu:U:vV";
+static const char *short_options = "e:fg:i:nop:P:rsu:U:vV";
static const struct option long_options[] = {
{ "help", 0, NULL, HELP_OPTION },
{ "dump-config",0, NULL, 0 },
+ { "export", 1, NULL, 'e' },
+ { "export-name",1, NULL, 'e' },
+ { "exportname", 1, NULL, 'e' },
{ "foreground", 0, NULL, 'f' },
{ "no-fork", 0, NULL, 'f' },
{ "group", 1, NULL, 'g' },
@@ -115,7 +119,7 @@ static const struct option long_options[] = {
static void
usage (void)
{
- printf ("nbdkit [--dump-config] [-f] [-g GROUP] [-i IPADDR]\n"
+ printf ("nbdkit [--dump-config] [-e EXPORTNAME] [-f] [-g GROUP] [-i IPADDR]\n"
" [--newstyle] [--oldstyle] [-P PIDFILE] [-p PORT] [-r]\n"
" [--run CMD] [-s] [-U SOCKET] [-u USER] [-v] [-V]\n"
" PLUGIN [key=value [key=value [...]]]\n"
@@ -173,6 +177,11 @@ main (int argc, char *argv[])
}
break;
+ case 'e':
+ exportname = optarg;
+ newstyle = 1;
+ break;
+
case 'f':
foreground = 1;
break;
@@ -190,9 +199,6 @@ main (int argc, char *argv[])
break;
case 'o':
- /* XXX When we add support for exportnames, we will need to
- * ensure that the user does not use -o + --export.
- */
newstyle = 0;
break;
@@ -263,12 +269,22 @@ main (int argc, char *argv[])
exit (EXIT_FAILURE);
}
+ /* Oldstyle protocol + exportname not allowed. */
+ if (newstyle == 0 && exportname != NULL) {
+ fprintf (stderr,
+ "%s: cannot use oldstyle protocol (-o) and exportname (-e)\n",
+ program_name);
+ exit (EXIT_FAILURE);
+ }
+
+ /* If exportname was not set on the command line, use "". */
+ if (exportname == NULL)
+ exportname = "";
+
/* Remaining command line arguments define the plugins and plugin
* configuration. If --help or --version was specified, we still
* partially parse these in order that we can display the per-plugin
- * help/version information. In future (when the new protocol and
- * export names are permitted) we will allow multiple plugins to be
- * given, but at the moment only one plugin is allowed.
+ * help/version information.
*/
while (optind < argc) {
const char *filename = argv[optind];
diff --git a/src/protocol.h b/src/protocol.h
index 71a8098..c885d9e 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -70,8 +70,7 @@ struct fixed_new_option_reply {
uint64_t magic; /* NBD_REP_MAGIC, network byte order */
uint32_t option; /* option we are replying to */
uint32_t reply; /* NBD_REP_* */
- uint32_t replylen; /* we always send zero at the moment */
- /* reply data follows, but we currently never send any */
+ uint32_t replylen;
} __attribute__((packed));
#define NBD_REP_MAGIC UINT64_C(0x3e889045565a9)
diff --git a/tests/test-newstyle.c b/tests/test-newstyle.c
index b1d8ce7..adcc568 100644
--- a/tests/test-newstyle.c
+++ b/tests/test-newstyle.c
@@ -44,6 +44,8 @@
#include "test.h"
+#define EXPORTNAME "/"
+
int
main (int argc, char *argv[])
{
@@ -52,7 +54,8 @@ main (int argc, char *argv[])
char *data;
size_t i, size;
- if (test_start_nbdkit ("-n", NBDKIT_PLUGIN ("file"), "file=file-data",
+ if (test_start_nbdkit ("-e", EXPORTNAME,
+ "-n", NBDKIT_PLUGIN ("file"), "file=file-data",
NULL) == -1)
exit (EXIT_FAILURE);
@@ -63,7 +66,7 @@ main (int argc, char *argv[])
}
/* Using any exportname causes qemu to use the newstyle protocol. */
- r = guestfs_add_drive_opts (g, "/" /* exportname */,
+ r = guestfs_add_drive_opts (g, EXPORTNAME,
GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw",
GUESTFS_ADD_DRIVE_OPTS_PROTOCOL, "nbd",
GUESTFS_ADD_DRIVE_OPTS_SERVER, server,
--
2.7.4

View File

@ -1,46 +0,0 @@
From 7938bbc463a694aeda888d51f1de446f23402d8f Mon Sep 17 00:00:00 2001
From: Eric Blake <eblake@redhat.com>
Date: Fri, 20 May 2016 08:04:05 -0600
Subject: [PATCH 11/11] protocol: Ignore rest of option when replying with
error
We must consume the payload of any option received, whether or
not we can answer the option successfully, in order to be in
sync for reading the next option. This is particularly true
once clients start using NBD_OPT_GO, as long as we don't happen
to service that option.
Signed-off-by: Eric Blake <eblake@redhat.com>
---
src/connections.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/src/connections.c b/src/connections.c
index 0c93f35..840e315 100644
--- a/src/connections.c
+++ b/src/connections.c
@@ -334,6 +334,10 @@ _negotiate_handshake_newstyle_options (struct connection *conn)
if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
== -1)
return -1;
+ if (xread (conn->sockin, data, optlen) == -1) {
+ nbdkit_error ("read: %m");
+ return -1;
+ }
continue;
}
@@ -351,6 +355,10 @@ _negotiate_handshake_newstyle_options (struct connection *conn)
/* Unknown option. */
if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_UNSUP) == -1)
return -1;
+ if (xread (conn->sockin, data, optlen) == -1) {
+ nbdkit_error ("read: %m");
+ return -1;
+ }
}
/* Note, since it's not very clear from the protocol doc, that the
--
2.7.4

View File

@ -5,8 +5,8 @@
%endif
Name: nbdkit
Version: 1.1.11
Release: 10%{?dist}
Version: 1.1.12
Release: 1%{?dist}
Summary: NBD server
License: BSD
@ -14,22 +14,6 @@ URL: https://github.com/libguestfs/nbdkit
Source0: http://libguestfs.org/download/nbdkit/%{name}-%{version}.tar.gz
# All patches are upstream since 1.1.11.
Patch0001: 0001-Add-mandir-to-dump-config-output.patch
Patch0002: 0002-Update-TODO.patch
Patch0003: 0003-Add-support-for-newstyle-NBD-protocol-RHBZ-1297100.patch
Patch0004: 0004-xz-Fix-various-printf-warnings-on-32-bit.patch
Patch0005: 0005-ocaml-Avoid-race-when-building-NBDKit.cmi.patch
Patch0006: 0006-Test-the-o-oldstyle-command-line-option.patch
Patch0007: 0007-protocol-Send-limited-range-of-errno-values-to-the-c.patch
Patch0008: 0008-protocol-Pack-fixed_new_option_reply-struct.patch
Patch0009: 0009-protocol-Rename-NEW_OPTION_REPLY-as-NBD_REP_MAGIC.patch
Patch0010: 0010-Implement-newstyle-export-names.patch
Patch0011: 0011-protocol-Ignore-rest-of-option-when-replying-with-er.patch
# Because patch3 & patch5 patches Makefile.am, we need:
BuildRequires: automake, autoconf, libtool
BuildRequires: /usr/bin/pod2man
%if 0%{?have_libguestfs}
BuildRequires: libguestfs-devel
@ -46,6 +30,7 @@ BuildRequires: python-devel
# http://caml.inria.fr/mantis/view.php?id=6693
BuildRequires: ocaml >= 4.02.2
%endif
BuildRequires: ruby-devel
# For complicated reasons, this is required so that
# /bin/kernel-install puts the kernel directly into /boot, instead of
@ -196,6 +181,17 @@ Requires: %{name}%{?_isa} = %{version}-%{release}
This package lets you write Python plugins for %{name}.
%package plugin-ruby
Summary: Ruby plugin for %{name}
License: BSD
Requires: %{name}%{?_isa} = %{version}-%{release}
%description plugin-ruby
This package lets you write Ruby plugins for %{name}.
%package plugin-streaming
Summary: Streaming file serving plugin for %{name}
License: BSD
@ -259,13 +255,12 @@ mkdir -p $HOME/.cache/libvirt
export LIBGUESTFS_DEBUG=1
export LIBGUESTFS_TRACE=1
# libguestfs 1.20 in Fedora 18 doesn't support NBD client protocol, so
# the tests cannot be run.
%if 0%{?fedora} >= 19
# Unlikely that libguestfs will work on ARM and PPC, so don't try running the
# tests there.
# Broken on i686 because of https://bugzilla.redhat.com/show_bug.cgi?id=1302071
%ifnarch %{arm} %{ix86} ppc %{power64}
# Broken on F25 because of https://bugzilla.redhat.com/show_bug.cgi?id=1344016
%if 0{?fedora} < 25
make check || {
cat tests/test-suite.log
exit 1
@ -350,6 +345,12 @@ make check || {
%{_mandir}/man3/nbdkit-python-plugin.3*
%files plugin-ruby
%doc LICENSE README
%{_libdir}/%{name}/plugins/nbdkit-ruby-plugin.so
%{_mandir}/man3/nbdkit-ruby-plugin.3*
%files plugin-streaming
%doc LICENSE README
%{_libdir}/%{name}/plugins/nbdkit-streaming-plugin.so
@ -368,11 +369,17 @@ make check || {
%doc plugins/example*/*.c
%doc plugins/perl/example.pl
%doc plugins/python/example.py
%doc plugins/ruby/example.rb
%{_includedir}/nbdkit-plugin.h
%{_mandir}/man3/nbdkit-plugin.3*
%changelog
* Wed Jun 08 2016 Richard W.M. Jones <rjones@redhat.com> - 1.1.12-1
- New upstream version 1.1.12
- Enable Ruby plugin.
- Disable tests on Rawhide because libvirt is broken again (RHBZ#1344016).
* Wed May 25 2016 Richard W.M. Jones <rjones@redhat.com> - 1.1.11-10
- Add another upstream patch since 1.1.11.

View File

@ -1 +1 @@
c03d66a7ad5f7f08a171d6845dc28c48 nbdkit-1.1.11.tar.gz
df80454541d5e2f523aaa10cd018bf42 nbdkit-1.1.12.tar.gz