From: "Richard W.M. Jones" <rjones(a)redhat.com>
See also:
https://www.redhat.com/archives/libguestfs/2020-July/msg00090.html
Message-Id: <20200722124201.1823468-2-rjones(a)redhat.com>
For now, this implementation is only for plugins; adding filter
support will come later (and probably requires further edits, for the
ability for any filter to open up an independent connection to the
plugin without being handed next_ops on entry).
---
docs/nbdkit-plugin.pod | 57 +++++++++++++++++++++++++++++++++++++---
docs/nbdkit-protocol.pod | 7 +++--
include/nbdkit-plugin.h | 3 +++
server/plugins.c | 10 +++++--
4 files changed, 69 insertions(+), 8 deletions(-)
diff --git a/docs/nbdkit-plugin.pod b/docs/nbdkit-plugin.pod
index f8e9962a..7ce89e9e 100644
--- a/docs/nbdkit-plugin.pod
+++ b/docs/nbdkit-plugin.pod
@@ -152,6 +152,9 @@ the plugin:
│ preconnect │ │
└──────┬─────┘ │
┌──────┴─────┐ │
+ │list_exports│ │
+ └──────┬─────┘ │
+ ┌──────┴─────┐ │
│ open │ │
└──────┬─────┘ │
┌──────┴─────┐ NBD option │
@@ -160,10 +163,10 @@ the plugin:
┌──────┴─────┐ ┌──────┴─────┐ client #2
│ get_size │ │ preconnect │
└──────┬─────┘ └──────┬─────┘
- ┌──────┴─────┐ data ┌──────┴─────┐
- │ pread │ serving │ open │
- └──────┬─────┘↺ └──────┬─────┘
- ┌──────┴─────┐ ...
+ ┌──────┴─────┐ data
+ │ pread │ serving
+ └──────┬─────┘↺ ...
+ ┌──────┴─────┐
│ pwrite │
└──────┬─────┘↺ ┌──────┴─────┐
┌──────┴─────┐ │ close │
@@ -236,6 +239,12 @@ L<getpid(2)>.
Called when a TCP connection has been made to the server. This
happens early, before NBD or TLS negotiation.
+=item C<.list_exports>
+
+Early in option negotiation the client may try to list the exports
+served by the plugin, and plugins can optionally implement this
+callback to answer the client. See L</EXPORT NAME> below.
+
=item C<.open>
A new client has connected and finished the NBD handshake. TLS
@@ -652,6 +661,46 @@ Returning C<0> will allow the connection to continue. If there
is an
error or you want to deny the connection, call C<nbdkit_error> with an
error message and return C<-1>.
+=head2 C<.list_exports>
+
+ int list_exports (int readonly, int default_only,
+ struct nbdkit_exports *exports);
+
+This optional callback is called if the client tries to list the
+exports served by the plugin (using C<NBD_OPT_LIST>). If the plugin
+does not supply this callback then a single export called C<""> is
+returned. The NBD protocol defines C<""> as the default export, so
+this is suitable for plugins which ignore the export name and always
+serve the same content. See also L</EXPORT NAME> below.
+
+The C<exports> parameter is an opaque object for collecting the list
+of exports. Call C<nbdkit_add_export> to add a single export to the
+list. If the plugin has a concept of a default export (usually but
+not always called C<"">) then it should return that first in the list.
+
+ int nbdkit_add_export (struct nbdkit_export *exports,
+ const char *name, const char *description);
+
+The C<name> must be a non-NULL, UTF-8 string between 0 and 4096 bytes
+in length. Export names must be unique. C<description> is an
+optional description of the export which some clients can display but
+which is otherwise unused (if you don't want a description, you can
+pass this parameter as C<NULL>). The string(s) are copied into the
+exports list so you may free them immediately after calling this
+function.
+
+If the C<default_only> flag then the client is querying for the name
+of the default export, and the plugin may add only a single export to
+the returned list (the default export name, usually C<"">). The
+plugin can ignore this flag and return all exports if it wants.
+
+The C<readonly> flag informs the plugin that the server was started
+with the I<-r> flag on the command line.
+
+Returning C<0> will send the list of exports back to the client. If
+there is an error, C<.list_exports> should call C<nbdkit_error> with
+an error message and return C<-1>.
+
=head2 C<.open>
void *open (int readonly);
diff --git a/docs/nbdkit-protocol.pod b/docs/nbdkit-protocol.pod
index 8fe8c67e..b1e182c1 100644
--- a/docs/nbdkit-protocol.pod
+++ b/docs/nbdkit-protocol.pod
@@ -99,12 +99,15 @@ Supported in nbdkit E<ge> 1.1.12, and the default in nbdkit
E<ge> 1.3.
=item export names
Partially supported in nbdkit E<ge> 1.1.12. Support for plugins to
-read the client export name added in nbdkit E<ge> 1.15.2.
+read the client export name added in nbdkit E<ge> 1.15.2. Support for
+C<NBD_OPT_LIST> was added in nbdkit E<ge> 1.21.20.
Versions of nbdkit before 1.16 could advertise a single export name to
clients, via a now deprecated side effect of the I<-e> option. In nbdkit
1.15.2, plugins could read the client requested export name using
-C<nbdkit_export_name()> and serve different content.
+C<nbdkit_export_name()> and serve different content. In nbdkit
+1.21.20, plugins could implement C<.list_exports> to answer
+C<NBD_OPT_LIST> queries.
=item C<NBD_FLAG_NO_ZEROES>
diff --git a/include/nbdkit-plugin.h b/include/nbdkit-plugin.h
index c6c1256c..86b8565d 100644
--- a/include/nbdkit-plugin.h
+++ b/include/nbdkit-plugin.h
@@ -139,6 +139,9 @@ struct nbdkit_plugin {
int (*get_ready) (void);
int (*after_fork) (void);
+
+ int (*list_exports) (int readonly, int default_only,
+ struct nbdkit_exports *exports);
};
extern void nbdkit_set_error (int err);
diff --git a/server/plugins.c b/server/plugins.c
index 8020046b..d4364cd2 100644
--- a/server/plugins.c
+++ b/server/plugins.c
@@ -161,6 +161,7 @@ plugin_dump_fields (struct backend *b)
HAS (get_ready);
HAS (after_fork);
HAS (preconnect);
+ HAS (list_exports);
HAS (open);
HAS (close);
HAS (get_size);
@@ -281,8 +282,13 @@ static int
plugin_list_exports (struct backend *b, int readonly, int default_only,
struct nbdkit_exports *exports)
{
- /* XXX No plugin support yet, so for now just advertise "" */
- return nbdkit_add_export (exports, "", NULL);
+ GET_CONN;
+ struct backend_plugin *p = container_of (b, struct backend_plugin, backend);
+
+ if (!p->plugin.list_exports)
+ return nbdkit_add_export (exports, "", NULL);
+
+ return p->plugin.list_exports (readonly, default_only, exports);
}
static void *
--
2.28.0