Richard W.M. Jones
2020-Feb-25 10:30 UTC
[Libguestfs] [PATCH nbdkit 0/5] server: Add .get_ready callback.
I like this change. I think we were overloading the config_complete
method before to do two different things (complete configuration; do
any allocation/housekeeping necessary before we can start serving).
The only questions in my mind are whether we want this before 1.18,
and whether the name ("get_ready") is a good one.
Rich.
Richard W.M. Jones
2020-Feb-25 10:30 UTC
[Libguestfs] [PATCH nbdkit 1/5] server: Add .get_ready callback.
This callback effectively splits config_complete into "complete the
config" and "get ready to start serving". There's no strict
need for
this new callback, but it makes the API slightly less confusing.
---
docs/nbdkit-filter.pod | 38 +++++++++++++++++++++++++-------------
docs/nbdkit-plugin.pod | 20 ++++++++++++++++----
include/nbdkit-filter.h | 2 ++
include/nbdkit-plugin.h | 2 ++
server/internal.h | 1 +
server/filters.c | 23 +++++++++++++++++++++++
server/main.c | 5 +++++
server/plugins.c | 16 ++++++++++++++++
tests/test-layers-filter.c | 9 +++++++++
tests/test-layers-plugin.c | 8 ++++++++
tests/test-layers.c | 12 ++++++++++++
11 files changed, 119 insertions(+), 17 deletions(-)
diff --git a/docs/nbdkit-filter.pod b/docs/nbdkit-filter.pod
index 4105b8b7..a9dffb56 100644
--- a/docs/nbdkit-filter.pod
+++ b/docs/nbdkit-filter.pod
@@ -127,22 +127,24 @@ which is required.
=head1 NEXT PLUGIN
F<nbdkit-filter.h> defines some function types
(C<nbdkit_next_config>,
-C<nbdkit_next_config_complete>, C<nbdkit_next_preconnect>,
-C<nbdkit_next_open>) and a structure called C<struct
nbdkit_next_ops>.
-These abstract the next plugin or filter in the chain. There is also
-an opaque pointer C<nxdata> which must be passed along when calling
-these functions. The value of C<nxdata> passed to C<.open> has a
-stable lifetime that lasts to the corresponding C<.close>, with all
-intermediate functions (such as C<.pread>) receiving the same value
-for convenience; the only exceptions where C<nxdata> is not reused are
-C<.config>, C<.config_complete>, and C<.preconnect>, which
are called
-outside the lifetime of a connection.
+C<nbdkit_next_config_complete>, C<nbdkit_next_get_ready>,
+C<nbdkit_next_preconnect>, C<nbdkit_next_open>) and a structure
called
+C<struct nbdkit_next_ops>. These abstract the next plugin or filter
+in the chain. There is also an opaque pointer C<nxdata> which must be
+passed along when calling these functions. The value of C<nxdata>
+passed to C<.open> has a stable lifetime that lasts to the
+corresponding C<.close>, with all intermediate functions (such as
+C<.pread>) receiving the same value for convenience; the only
+exceptions where C<nxdata> is not reused are C<.config>,
+C<.config_complete>, C<.get_ready>, and C<.preconnect>, which
are
+called outside the lifetime of a connection.
=head2 Next config, open and close
-The filter’s C<.config>, C<.config_complete> and C<.open>
methods may
-only call the next C<.config>, C<.config_complete> and
C<.open> method
-in the chain (optionally for C<.config>).
+The filter’s C<.config>, C<.config_complete>, C<.get_ready>
and
+C<.open> methods may only call the next C<.config>,
+C<.config_complete>, C<.get_ready> and C<.open> method in the
chain
+(optionally for C<.config>).
The filter’s C<.close> method is called when an old connection closed,
and this has no C<next> parameter because it cannot be
@@ -292,6 +294,16 @@ filter doesn't slow down other filters or plugins.
If there is an error, C<.thread_model> should call C<nbdkit_error>
with an error message and return C<-1>.
+=head2 C<.get_ready>
+
+ int (*get_ready) (nbdkit_next_get_ready *next, void *nxdata);
+
+This intercepts the plugin C<.get_ready> method and can be used by the
+filter to get ready to serve requests.
+
+If there is an error, C<.get_ready> should call C<nbdkit_error>
with
+an error message and return C<-1>.
+
=head2 C<.preconnect>
int (*preconnect) (nbdkit_next_preconnect *next, void *nxdata,
diff --git a/docs/nbdkit-plugin.pod b/docs/nbdkit-plugin.pod
index 41bffb7f..77f1a098 100644
--- a/docs/nbdkit-plugin.pod
+++ b/docs/nbdkit-plugin.pod
@@ -443,6 +443,18 @@ are silently ignored.
If there is an error, C<.thread_model> should call C<nbdkit_error>
with an error message and return C<-1>.
+=head2 C<.get_ready>
+
+ int get_ready (void);
+
+This optional callback is called before the server starts serving. It
+is called before the server forks or changes directory. It is the
+last chance to do any global preparation that is needed to serve
+connections.
+
+If there is an error, C<.get_ready> should call C<nbdkit_error>
with
+an error message and return C<-1>.
+
=head2 C<.preconnect>
int preconnect (int readonly);
@@ -1182,8 +1194,8 @@ absolute path: if it is relative, then all this function
does is
prepend the current working directory to the path, with no extra
checks.
-Note that this function works I<only> when used in the C<.config>,
and
-C<.config_complete> callbacks.
+Note that this function works I<only> when used in the C<.config>,
+C<.config_complete> and C<.get_ready> callbacks.
If conversion was not possible, this calls C<nbdkit_error> and returns
C<NULL>. Note that this function does not check that the file exists.
@@ -1199,8 +1211,8 @@ absolute path, resolving symlinks. Under the hood it uses
the
C<realpath> function, and thus it fails if the path does not exist,
or it is not possible to access to any of the components of the path.
-Note that this function works I<only> when used in the C<.config>,
and
-C<.config_complete> callbacks.
+Note that this function works I<only> when used in the C<.config>,
+C<.config_complete> and C<.get_ready> callbacks.
If the path resolution was not possible, this calls C<nbdkit_error>
and returns C<NULL>.
diff --git a/include/nbdkit-filter.h b/include/nbdkit-filter.h
index a44c689b..ca58e496 100644
--- a/include/nbdkit-filter.h
+++ b/include/nbdkit-filter.h
@@ -62,6 +62,7 @@ typedef void nbdkit_backend;
typedef int nbdkit_next_config (nbdkit_backend *nxdata,
const char *key, const char *value);
typedef int nbdkit_next_config_complete (nbdkit_backend *nxdata);
+typedef int nbdkit_next_get_ready (nbdkit_backend *nxdata);
typedef int nbdkit_next_preconnect (nbdkit_backend *nxdata, int readonly);
typedef int nbdkit_next_open (nbdkit_backend *nxdata, int readonly);
@@ -143,6 +144,7 @@ struct nbdkit_filter {
nbdkit_backend *nxdata);
const char *config_help;
int (*thread_model) (void);
+ int (*get_ready) (nbdkit_next_get_ready *next, nbdkit_backend *nxdata);
int (*preconnect) (nbdkit_next_preconnect *next, nbdkit_backend *nxdata,
int readonly);
diff --git a/include/nbdkit-plugin.h b/include/nbdkit-plugin.h
index b4ecf658..7e06a4b1 100644
--- a/include/nbdkit-plugin.h
+++ b/include/nbdkit-plugin.h
@@ -136,6 +136,8 @@ struct nbdkit_plugin {
int (*can_fast_zero) (void *handle);
int (*preconnect) (int readonly);
+
+ int (*get_ready) (void);
};
extern void nbdkit_set_error (int err);
diff --git a/server/internal.h b/server/internal.h
index eaec31ba..d8a589f2 100644
--- a/server/internal.h
+++ b/server/internal.h
@@ -344,6 +344,7 @@ struct backend {
void (*config) (struct backend *, const char *key, const char *value);
void (*config_complete) (struct backend *);
const char *(*magic_config_key) (struct backend *);
+ void (*get_ready) (struct backend *);
int (*preconnect) (struct backend *, int readonly);
void *(*open) (struct backend *, int readonly);
int (*prepare) (struct backend *, void *handle, int readonly);
diff --git a/server/filters.c b/server/filters.c
index 8985ebeb..f0371066 100644
--- a/server/filters.c
+++ b/server/filters.c
@@ -171,6 +171,28 @@ filter_config_complete (struct backend *b)
b->next->config_complete (b->next);
}
+static int
+next_get_ready (struct backend *b)
+{
+ b->get_ready (b);
+ return 0;
+}
+
+static void
+filter_get_ready (struct backend *b)
+{
+ struct backend_filter *f = container_of (b, struct backend_filter, backend);
+
+ debug ("%s: get_ready", b->name);
+
+ if (f->filter.get_ready) {
+ if (f->filter.get_ready (next_get_ready, b->next) == -1)
+ exit (EXIT_FAILURE);
+ }
+ else
+ b->next->get_ready (b->next);
+}
+
static int
filter_preconnect (struct backend *b, int readonly)
{
@@ -493,6 +515,7 @@ static struct backend filter_functions = {
.config = filter_config,
.config_complete = filter_config_complete,
.magic_config_key = plugin_magic_config_key,
+ .get_ready = filter_get_ready,
.preconnect = filter_preconnect,
.open = filter_open,
.prepare = filter_prepare,
diff --git a/server/main.c b/server/main.c
index 3cfd1e2e..6350d110 100644
--- a/server/main.c
+++ b/server/main.c
@@ -694,6 +694,11 @@ main (int argc, char *argv[])
exit (EXIT_FAILURE);
}
+ /* Tell the plugin that we are about to start serving. This must be
+ * called before we change user, fork, or open any sockets.
+ */
+ top->get_ready (top);
+
start_serving ();
top->free (top);
diff --git a/server/plugins.c b/server/plugins.c
index 16b4099b..78ed6723 100644
--- a/server/plugins.c
+++ b/server/plugins.c
@@ -158,6 +158,7 @@ plugin_dump_fields (struct backend *b)
HAS (config);
HAS (config_complete);
HAS (config_help);
+ HAS (get_ready);
HAS (preconnect);
HAS (open);
HAS (close);
@@ -234,6 +235,20 @@ plugin_magic_config_key (struct backend *b)
return p->plugin.magic_config_key;
}
+static void
+plugin_get_ready (struct backend *b)
+{
+ struct backend_plugin *p = container_of (b, struct backend_plugin, backend);
+
+ debug ("%s: get_ready", b->name);
+
+ if (!p->plugin.get_ready)
+ return;
+
+ if (p->plugin.get_ready () == -1)
+ exit (EXIT_FAILURE);
+}
+
static int
plugin_preconnect (struct backend *b, int readonly)
{
@@ -670,6 +685,7 @@ static struct backend plugin_functions = {
.config = plugin_config,
.config_complete = plugin_config_complete,
.magic_config_key = plugin_magic_config_key,
+ .get_ready = plugin_get_ready,
.preconnect = plugin_preconnect,
.open = plugin_open,
.prepare = plugin_prepare,
diff --git a/tests/test-layers-filter.c b/tests/test-layers-filter.c
index 44f62c6e..53427d2a 100644
--- a/tests/test-layers-filter.c
+++ b/tests/test-layers-filter.c
@@ -81,6 +81,14 @@ test_layers_filter_config_complete
(nbdkit_next_config_complete *next,
#define test_layers_filter_config_help \
"test_layers_" layer "_config_help"
+static int
+test_layers_filter_get_ready (nbdkit_next_get_ready *next,
+ void *nxdata)
+{
+ DEBUG_FUNCTION;
+ return next (nxdata);
+}
+
static int
test_layers_filter_preconnect (nbdkit_next_preconnect *next,
void *nxdata, int readonly)
@@ -349,6 +357,7 @@ static struct nbdkit_filter filter = {
.config = test_layers_filter_config,
.config_complete = test_layers_filter_config_complete,
.config_help = test_layers_filter_config_help,
+ .get_ready = test_layers_filter_get_ready,
.preconnect = test_layers_filter_preconnect,
.open = test_layers_filter_open,
.close = test_layers_filter_close,
diff --git a/tests/test-layers-plugin.c b/tests/test-layers-plugin.c
index 10cc6efe..8858bede 100644
--- a/tests/test-layers-plugin.c
+++ b/tests/test-layers-plugin.c
@@ -72,6 +72,13 @@ test_layers_plugin_config_complete (void)
#define test_layers_plugin_config_help
"test_layers_plugin_config_help"
+static int
+test_layers_plugin_get_ready (void)
+{
+ DEBUG_FUNCTION;
+ return 0;
+}
+
static int
test_layers_plugin_preconnect (int readonly)
{
@@ -231,6 +238,7 @@ static struct nbdkit_plugin plugin = {
.config = test_layers_plugin_config,
.config_complete = test_layers_plugin_config_complete,
.config_help = test_layers_plugin_config_help,
+ .get_ready = test_layers_plugin_get_ready,
.preconnect = test_layers_plugin_preconnect,
.open = test_layers_plugin_open,
.close = test_layers_plugin_close,
diff --git a/tests/test-layers.c b/tests/test-layers.c
index fafe68c4..33ae5a75 100644
--- a/tests/test-layers.c
+++ b/tests/test-layers.c
@@ -288,6 +288,18 @@ main (int argc, char *argv[])
"test_layers_plugin_config_complete",
NULL);
+ /* get_ready methods called in order. */
+ log_verify_seen_in_order
+ ("testlayersfilter3: get_ready",
+ "filter3: test_layers_filter_get_ready",
+ "testlayersfilter2: get_ready",
+ "filter2: test_layers_filter_get_ready",
+ "testlayersfilter1: get_ready",
+ "filter1: test_layers_filter_get_ready",
+ "testlayersplugin: get_ready",
+ "test_layers_plugin_get_ready",
+ NULL);
+
/* preconnect methods called in outer-to-inner order, complete
* in inner-to-outer order.
*/
--
2.25.0
Richard W.M. Jones
2020-Feb-25 10:30 UTC
[Libguestfs] [PATCH nbdkit 2/5] Use .get_ready method in miscellaneous plugins and filters.
For plugins/filters where .config_complete was "overloaded" as a place
to finish configuration and do some set up before we start serving,
use the new .get_ready callback.
---
plugins/floppy/floppy.c | 9 ++++++++-
plugins/floppy/virtual-floppy.c | 8 ++++----
plugins/iso/iso.c | 10 +++++++---
plugins/linuxdisk/linuxdisk.c | 9 ++++++++-
plugins/partitioning/partitioning.c | 9 ++++++++-
plugins/streaming/streaming.c | 7 +++++++
plugins/vddk/vddk.c | 14 ++++++++++----
filters/log/log.c | 14 +++++++++++---
filters/rate/rate.c | 4 ++--
filters/stats/stats.c | 11 +++++++++--
10 files changed, 74 insertions(+), 21 deletions(-)
diff --git a/plugins/floppy/floppy.c b/plugins/floppy/floppy.c
index 41a23644..1c2f645e 100644
--- a/plugins/floppy/floppy.c
+++ b/plugins/floppy/floppy.c
@@ -99,13 +99,19 @@ floppy_config_complete (void)
return -1;
}
- return create_virtual_floppy (dir, label, &floppy);
+ return 0;
}
#define floppy_config_help \
"dir=<DIRECTORY> (required) The directory to serve.\n" \
"label=<LABEL> The volume label." \
+static int
+floppy_get_ready (void)
+{
+ return create_virtual_floppy (dir, label, &floppy);
+}
+
static void *
floppy_open (int readonly)
{
@@ -204,6 +210,7 @@ static struct nbdkit_plugin plugin = {
.config_complete = floppy_config_complete,
.config_help = floppy_config_help,
.magic_config_key = "dir",
+ .get_ready = floppy_get_ready,
.open = floppy_open,
.get_size = floppy_get_size,
.can_multi_conn = floppy_can_multi_conn,
diff --git a/plugins/floppy/virtual-floppy.c b/plugins/floppy/virtual-floppy.c
index b5c29a46..fc0cafa8 100644
--- a/plugins/floppy/virtual-floppy.c
+++ b/plugins/floppy/virtual-floppy.c
@@ -256,10 +256,10 @@ visit (const char *dir, struct virtual_floppy *floppy)
floppy->nr_dirs++;
memset (&floppy->dirs[di], 0, sizeof (struct dir));
- /* Because this is called from config_complete, before nbdkit
- * daemonizes or starts any threads, it's safe to use chdir here and
- * greatly simplifies the code. However we must chdir back to the
- * original directory at the end.
+ /* Because this is called from get_ready, before nbdkit daemonizes
+ * or starts any threads, it's safe to use chdir here and greatly
+ * simplifies the code. However we must chdir back to the original
+ * directory at the end.
*/
origdir = get_current_dir_name ();
if (origdir == NULL) {
diff --git a/plugins/iso/iso.c b/plugins/iso/iso.c
index 5634bac9..92554ace 100644
--- a/plugins/iso/iso.c
+++ b/plugins/iso/iso.c
@@ -176,9 +176,6 @@ iso_config_complete (void)
return -1;
}
- if (make_iso () == -1)
- return -1;
-
return 0;
}
@@ -187,6 +184,12 @@ iso_config_complete (void)
"params='<PARAMS>' Extra parameters to
pass.\n" \
"prog=<ISOPROG> The program used to make
ISOs." \
+static int
+iso_get_ready (void)
+{
+ return make_iso ();
+}
+
static void *
iso_open (int readonly)
{
@@ -254,6 +257,7 @@ static struct nbdkit_plugin plugin = {
.config_complete = iso_config_complete,
.config_help = iso_config_help,
.magic_config_key = "dir",
+ .get_ready = iso_get_ready,
.open = iso_open,
.get_size = iso_get_size,
.can_multi_conn = iso_can_multi_conn,
diff --git a/plugins/linuxdisk/linuxdisk.c b/plugins/linuxdisk/linuxdisk.c
index 99dbc996..d7b52242 100644
--- a/plugins/linuxdisk/linuxdisk.c
+++ b/plugins/linuxdisk/linuxdisk.c
@@ -128,7 +128,7 @@ linuxdisk_config_complete (void)
return -1;
}
- return create_virtual_disk (&disk);
+ return 0;
}
#define linuxdisk_config_help \
@@ -137,6 +137,12 @@ linuxdisk_config_complete (void)
"type=ext2|ext3|ext4 The filesystem type.\n" \
"size=[+]<SIZE> The virtual filesystem size."
+static int
+linuxdisk_get_ready (void)
+{
+ return create_virtual_disk (&disk);
+}
+
static void *
linuxdisk_open (int readonly)
{
@@ -226,6 +232,7 @@ static struct nbdkit_plugin plugin = {
.config_complete = linuxdisk_config_complete,
.config_help = linuxdisk_config_help,
.magic_config_key = "dir",
+ .get_ready = linuxdisk_get_ready,
.open = linuxdisk_open,
.get_size = linuxdisk_get_size,
.can_multi_conn = linuxdisk_can_multi_conn,
diff --git a/plugins/partitioning/partitioning.c
b/plugins/partitioning/partitioning.c
index 6e426b93..865acd28 100644
--- a/plugins/partitioning/partitioning.c
+++ b/plugins/partitioning/partitioning.c
@@ -269,13 +269,19 @@ partitioning_config_complete (void)
return -1;
}
- return create_virtual_disk_layout ();
+ return 0;
}
#define partitioning_config_help \
"file=<FILENAME> (required) File(s) containing partitions\n"
\
"partition-type=mbr|gpt Partition type"
+static int
+partitioning_get_ready (void)
+{
+ return create_virtual_disk_layout ();
+}
+
/* Create the per-connection handle. */
static void *
partitioning_open (int readonly)
@@ -433,6 +439,7 @@ static struct nbdkit_plugin plugin = {
.config_complete = partitioning_config_complete,
.config_help = partitioning_config_help,
.magic_config_key = "file",
+ .get_ready = partitioning_get_ready,
.open = partitioning_open,
.get_size = partitioning_get_size,
.can_multi_conn = partitioning_can_multi_conn,
diff --git a/plugins/streaming/streaming.c b/plugins/streaming/streaming.c
index b2359540..71365c58 100644
--- a/plugins/streaming/streaming.c
+++ b/plugins/streaming/streaming.c
@@ -90,6 +90,12 @@ streaming_config_complete (void)
return -1;
}
+ return 0;
+}
+
+static int
+streaming_get_ready (void)
+{
/* Open the file blindly. If this fails with ENOENT then we create a
* FIFO and try again.
*/
@@ -248,6 +254,7 @@ static struct nbdkit_plugin plugin = {
.config = streaming_config,
.config_complete = streaming_config_complete,
.config_help = streaming_config_help,
+ .get_ready = streaming_get_ready,
.open = streaming_open,
.close = streaming_close,
.get_size = streaming_get_size,
diff --git a/plugins/vddk/vddk.c b/plugins/vddk/vddk.c
index 533c5605..7788a31b 100644
--- a/plugins/vddk/vddk.c
+++ b/plugins/vddk/vddk.c
@@ -60,8 +60,7 @@ int vddk_debug_extents;
int vddk_debug_datapath = 1;
/* For each VDDK API define a static global variable. These globals
- * are initialized when the plugin is loaded (by
- * vddk_config_complete).
+ * are initialized when the plugin is loaded (by vddk_get_ready).
*/
#define STUB(fn,ret,args) static ret (*fn) args
#define OPTIONAL_STUB(fn,ret,args) static ret (*fn) args
@@ -432,8 +431,6 @@ load_library (void)
static int
vddk_config_complete (void)
{
- VixError err;
-
if (filename == NULL) {
nbdkit_error ("you must supply the file=<FILENAME> parameter
"
"after the plugin name on the command line");
@@ -506,6 +503,14 @@ vddk_config_complete (void)
}
}
+ return 0;
+}
+
+static int
+vddk_get_ready (void)
+{
+ VixError err;
+
load_library ();
/* Initialize VDDK library. */
@@ -1017,6 +1022,7 @@ static struct nbdkit_plugin plugin = {
.config_help = vddk_config_help,
.magic_config_key = "file",
.dump_plugin = vddk_dump_plugin,
+ .get_ready = vddk_get_ready,
.open = vddk_open,
.close = vddk_close,
.get_size = vddk_get_size,
diff --git a/filters/log/log.c b/filters/log/log.c
index 7eb608c5..76d139eb 100644
--- a/filters/log/log.c
+++ b/filters/log/log.c
@@ -86,16 +86,23 @@ log_config (nbdkit_next_config *next, void *nxdata,
return next (nxdata, key, value);
}
-/* Open the logfile. */
static int
log_config_complete (nbdkit_next_config_complete *next, void *nxdata)
{
- int fd;
-
if (!logfilename) {
nbdkit_error ("missing logfile= parameter for the log filter");
return -1;
}
+
+ return next (nxdata);
+}
+
+/* Open the logfile. */
+static int
+log_get_ready (nbdkit_next_get_ready *next, void *nxdata)
+{
+ int fd;
+
/* Using fopen("ae"/"we") would be more convenient, but
as Haiku
* still lacks that, use this instead. Atomicity is not essential
* here since .config completes before threads that might fork, if
@@ -444,6 +451,7 @@ static struct nbdkit_filter filter = {
.config_complete = log_config_complete,
.config_help = log_config_help,
.unload = log_unload,
+ .get_ready = log_get_ready,
.open = log_open,
.close = log_close,
.prepare = log_prepare,
diff --git a/filters/rate/rate.c b/filters/rate/rate.c
index 2b105f91..f71e9cf3 100644
--- a/filters/rate/rate.c
+++ b/filters/rate/rate.c
@@ -145,7 +145,7 @@ rate_config (nbdkit_next_config *next, void *nxdata,
}
static int
-rate_config_complete (nbdkit_next_config_complete *next, void *nxdata)
+rate_get_ready (nbdkit_next_get_ready *next, void *nxdata)
{
/* Initialize the global buckets. */
bucket_init (&read_bucket, rate, BUCKET_CAPACITY);
@@ -312,8 +312,8 @@ static struct nbdkit_filter filter = {
.longname = "nbdkit rate filter",
.unload = rate_unload,
.config = rate_config,
- .config_complete = rate_config_complete,
.config_help = rate_config_help,
+ .get_ready = rate_get_ready,
.open = rate_open,
.close = rate_close,
.pread = rate_pread,
diff --git a/filters/stats/stats.c b/filters/stats/stats.c
index 0759cebe..05832561 100644
--- a/filters/stats/stats.c
+++ b/filters/stats/stats.c
@@ -201,13 +201,19 @@ stats_config (nbdkit_next_config *next, void *nxdata,
static int
stats_config_complete (nbdkit_next_config_complete *next, void *nxdata)
{
- int fd;
-
if (filename == NULL) {
nbdkit_error ("stats filter requires statsfile parameter");
return -1;
}
+ return next (nxdata);
+}
+
+static int
+stats_get_ready (nbdkit_next_get_ready *next, void *nxdata)
+{
+ int fd;
+
/* Using fopen("ae"/"we") would be more convenient, but
as Haiku
* still lacks that, use this instead. Atomicity is not essential
* here since .config completes before threads that might fork, if
@@ -372,6 +378,7 @@ static struct nbdkit_filter filter = {
.config = stats_config,
.config_complete = stats_config_complete,
.config_help = stats_config_help,
+ .get_ready = stats_get_ready,
.pread = stats_pread,
.pwrite = stats_pwrite,
.trim = stats_trim,
--
2.25.0
Richard W.M. Jones
2020-Feb-25 10:30 UTC
[Libguestfs] [PATCH nbdkit 3/5] ocaml: Implement get_ready method.
---
plugins/ocaml/ocaml.c | 25 +++++++++++++++++++++++++
plugins/ocaml/NBDKit.ml | 8 ++++++++
plugins/ocaml/NBDKit.mli | 2 ++
tests/test_ocaml_plugin.ml | 6 ++++++
4 files changed, 41 insertions(+)
diff --git a/plugins/ocaml/ocaml.c b/plugins/ocaml/ocaml.c
index 619a678b..82003343 100644
--- a/plugins/ocaml/ocaml.c
+++ b/plugins/ocaml/ocaml.c
@@ -106,6 +106,8 @@ static value config_fn;
static value config_complete_fn;
static value thread_model_fn;
+static value get_ready_fn;
+
static value preconnect_fn;
static value open_fn;
static value close_fn;
@@ -238,6 +240,25 @@ thread_model_wrapper (void)
CAMLreturnT (int, Int_val (rv));
}
+static int
+get_ready_wrapper (void)
+{
+ CAMLparam0 ();
+ CAMLlocal1 (rv);
+
+ caml_leave_blocking_section ();
+
+ rv = caml_callback_exn (get_ready_fn, Val_unit);
+ if (Is_exception_result (rv)) {
+ nbdkit_error ("%s", caml_format_exception (Extract_exception
(rv)));
+ caml_enter_blocking_section ();
+ CAMLreturnT (int, -1);
+ }
+
+ caml_enter_blocking_section ();
+ CAMLreturnT (int, 0);
+}
+
static int
preconnect_wrapper (int readonly)
{
@@ -799,6 +820,8 @@ SET(config)
SET(config_complete)
SET(thread_model)
+SET(get_ready)
+
SET(preconnect)
SET(open)
SET(close)
@@ -840,6 +863,8 @@ remove_roots (void)
REMOVE (config_complete);
REMOVE (thread_model);
+ REMOVE (get_ready);
+
REMOVE (preconnect);
REMOVE (open);
REMOVE (close);
diff --git a/plugins/ocaml/NBDKit.ml b/plugins/ocaml/NBDKit.ml
index e3b07ab5..ed636c72 100644
--- a/plugins/ocaml/NBDKit.ml
+++ b/plugins/ocaml/NBDKit.ml
@@ -69,6 +69,8 @@ type 'a plugin = {
config_help : string;
thread_model : (unit -> thread_model) option;
+ get_ready : (unit -> unit) option;
+
preconnect : (bool -> unit) option;
open_connection : (bool -> 'a) option;
close : ('a -> unit) option;
@@ -111,6 +113,8 @@ let default_callbacks = {
config_help = "";
thread_model = None;
+ get_ready = None;
+
preconnect = None;
open_connection = None;
close = None;
@@ -152,6 +156,8 @@ external set_config_complete : (unit -> unit) -> unit
= "ocaml_nbdkit_set_config
external set_config_help : string -> unit =
"ocaml_nbdkit_set_config_help" "noalloc"
external set_thread_model : (unit -> thread_model) -> unit =
"ocaml_nbdkit_set_thread_model"
+external set_get_ready : (unit -> unit) -> unit =
"ocaml_nbdkit_set_get_ready"
+
external set_preconnect : (bool -> unit) -> unit =
"ocaml_nbdkit_set_preconnect"
external set_open : (bool -> 'a) -> unit =
"ocaml_nbdkit_set_open"
external set_close : ('a -> unit) -> unit =
"ocaml_nbdkit_set_close"
@@ -214,6 +220,8 @@ let register_plugin plugin set_config_help
plugin.config_help;
may set_thread_model plugin.thread_model;
+ may set_get_ready plugin.get_ready;
+
may set_preconnect plugin.preconnect;
may set_open plugin.open_connection;
may set_close plugin.close;
diff --git a/plugins/ocaml/NBDKit.mli b/plugins/ocaml/NBDKit.mli
index 8cc4fed2..78019442 100644
--- a/plugins/ocaml/NBDKit.mli
+++ b/plugins/ocaml/NBDKit.mli
@@ -74,6 +74,8 @@ type 'a plugin = {
config_help : string;
thread_model : (unit -> thread_model) option;
+ get_ready : (unit -> unit) option;
+
preconnect : (bool -> unit) option;
open_connection : (bool -> 'a) option; (* required *)
close : ('a -> unit) option;
diff --git a/tests/test_ocaml_plugin.ml b/tests/test_ocaml_plugin.ml
index 3cf8fd90..753e51ab 100644
--- a/tests/test_ocaml_plugin.ml
+++ b/tests/test_ocaml_plugin.ml
@@ -19,6 +19,12 @@ let test_config_complete () let params = List.rev !params
in
assert (params = [ "a", "1"; "b",
"2"; "c", "3" ])
+let test_get_ready () + (* We could allocate the disk here, but it's
easier to allocate
+ * it statically above.
+ *)
+ NBDKit.debug "test ocaml plugin getting ready"
+
let test_open readonly NBDKit.debug "test ocaml plugin handle opened
readonly=%b" readonly;
()
--
2.25.0
Richard W.M. Jones
2020-Feb-25 10:30 UTC
[Libguestfs] [PATCH nbdkit 4/5] python: Implement get_ready method.
---
plugins/python/nbdkit-python-plugin.pod | 6 ++++++
plugins/python/python.c | 21 +++++++++++++++++++++
2 files changed, 27 insertions(+)
diff --git a/plugins/python/nbdkit-python-plugin.pod
b/plugins/python/nbdkit-python-plugin.pod
index 4065ec75..454a17ca 100644
--- a/plugins/python/nbdkit-python-plugin.pod
+++ b/plugins/python/nbdkit-python-plugin.pod
@@ -152,6 +152,12 @@ There are no arguments or return value.
There are no arguments or return value.
+=item C<get_ready>
+
+(Optional)
+
+There are no arguments or return value.
+
=item C<open>
(Required)
diff --git a/plugins/python/python.c b/plugins/python/python.c
index 5e2e5269..72f37dd7 100644
--- a/plugins/python/python.c
+++ b/plugins/python/python.c
@@ -436,6 +436,25 @@ py_config_complete (void)
return 0;
}
+static int
+py_get_ready (void)
+{
+ PyObject *fn;
+ PyObject *r;
+
+ if (callback_defined ("get_ready", &fn)) {
+ PyErr_Clear ();
+
+ r = PyObject_CallObject (fn, NULL);
+ Py_DECREF (fn);
+ if (check_python_failure ("get_ready") == -1)
+ return -1;
+ Py_DECREF (r);
+ }
+
+ return 0;
+}
+
static void *
py_open (int readonly)
{
@@ -889,6 +908,8 @@ static struct nbdkit_plugin plugin = {
.config_complete = py_config_complete,
.config_help = py_config_help,
+ .get_ready = py_get_ready,
+
.open = py_open,
.close = py_close,
--
2.25.0
Richard W.M. Jones
2020-Feb-25 10:30 UTC
[Libguestfs] [PATCH nbdkit 5/5] eval, sh: Implement get_ready method.
---
plugins/eval/nbdkit-eval-plugin.pod | 2 ++
plugins/sh/nbdkit-sh-plugin.pod | 4 ++++
plugins/sh/methods.h | 1 +
plugins/eval/eval.c | 2 ++
plugins/sh/methods.c | 25 +++++++++++++++++++++++++
plugins/sh/sh.c | 1 +
tests/test-eval.sh | 1 +
7 files changed, 36 insertions(+)
diff --git a/plugins/eval/nbdkit-eval-plugin.pod
b/plugins/eval/nbdkit-eval-plugin.pod
index a3601333..602fd3aa 100644
--- a/plugins/eval/nbdkit-eval-plugin.pod
+++ b/plugins/eval/nbdkit-eval-plugin.pod
@@ -100,6 +100,8 @@ features):
=item B<flush=>SCRIPT
+=item B<get_ready=>SCRIPT
+
=item B<get_size=>SCRIPT
=item B<is_rotational=>SCRIPT
diff --git a/plugins/sh/nbdkit-sh-plugin.pod b/plugins/sh/nbdkit-sh-plugin.pod
index 2f265b05..ffd0310f 100644
--- a/plugins/sh/nbdkit-sh-plugin.pod
+++ b/plugins/sh/nbdkit-sh-plugin.pod
@@ -246,6 +246,10 @@ actually gets selected.
If an error occurs, the script should output an error message and exit
with status C<1>; unrecognized output is ignored.
+=item C<get_ready>
+
+ /path/to/script get_ready
+
=item C<preconnect>
/path/to/script preconnect <readonly> <exportname>
diff --git a/plugins/sh/methods.h b/plugins/sh/methods.h
index 8a8f179c..f11e67e7 100644
--- a/plugins/sh/methods.h
+++ b/plugins/sh/methods.h
@@ -41,6 +41,7 @@ extern const char *get_script (const char *method);
extern void sh_dump_plugin (void);
extern int sh_thread_model (void);
+extern int sh_get_ready (void);
extern int sh_preconnect (int readonly);
extern void *sh_open (int readonly);
extern void sh_close (void *handle);
diff --git a/plugins/eval/eval.c b/plugins/eval/eval.c
index 9071b8c7..f09e49f3 100644
--- a/plugins/eval/eval.c
+++ b/plugins/eval/eval.c
@@ -70,6 +70,7 @@ static const char *known_methods[] = {
"dump_plugin",
"extents",
"flush",
+ "get_ready",
"get_size",
"is_rotational",
"missing",
@@ -409,6 +410,7 @@ static struct nbdkit_plugin plugin = {
.config_complete = eval_config_complete,
.config_help = eval_config_help,
.thread_model = sh_thread_model,
+ .get_ready = sh_get_ready,
.preconnect = sh_preconnect,
.open = sh_open,
diff --git a/plugins/sh/methods.c b/plugins/sh/methods.c
index e8011284..56e2d410 100644
--- a/plugins/sh/methods.c
+++ b/plugins/sh/methods.c
@@ -139,6 +139,31 @@ sh_thread_model (void)
}
}
+int
+sh_get_ready (void)
+{
+ const char *method = "get_ready";
+ const char *script = get_script (method);
+ const char *args[] = { script, method, NULL };
+
+ switch (call (args)) {
+ case OK:
+ case MISSING:
+ return 0;
+
+ case ERROR:
+ return -1;
+
+ case RET_FALSE:
+ nbdkit_error ("%s: %s method returned unexpected code (3/false)",
+ script, method);
+ errno = EIO;
+ return -1;
+
+ default: abort ();
+ }
+}
+
int
sh_preconnect (int readonly)
{
diff --git a/plugins/sh/sh.c b/plugins/sh/sh.c
index 0d24edb4..736b8ef0 100644
--- a/plugins/sh/sh.c
+++ b/plugins/sh/sh.c
@@ -310,6 +310,7 @@ static struct nbdkit_plugin plugin = {
.config_help = sh_config_help,
.magic_config_key = "script",
.thread_model = sh_thread_model,
+ .get_ready = sh_get_ready,
.preconnect = sh_preconnect,
.open = sh_open,
diff --git a/tests/test-eval.sh b/tests/test-eval.sh
index 868452f3..da7b8861 100755
--- a/tests/test-eval.sh
+++ b/tests/test-eval.sh
@@ -59,6 +59,7 @@ grep 'in missing: config_complete' eval.missing
grep 'in missing: thread_model' eval.missing
grep 'in missing: can_write' eval.missing
grep 'in missing: is_rotational' eval.missing
+grep 'in missing: get_ready' eval.missing
grep 'in missing: preconnect' eval.missing
grep 'in missing: open' eval.missing
grep 'in missing: close' eval.missing
--
2.25.0
Eric Blake
2020-Feb-26 12:36 UTC
Re: [Libguestfs] [PATCH nbdkit 0/5] server: Add .get_ready callback.
On 2/25/20 4:30 AM, Richard W.M. Jones wrote:> I like this change. I think we were overloading the config_complete > method before to do two different things (complete configuration; do > any allocation/housekeeping necessary before we can start serving). > > The only questions in my mind are whether we want this before 1.18, > and whether the name ("get_ready") is a good one.I'm not coming up with any better name. Once we release, we're stuck with the name, but I don't see it as too much of a problem. My idea about enhancing filters to get access to next_ops for all filter connections to multiplex on a single plugin is still doable on top (since we don't promise filter API stability), so I don't see any problem with this going in 1.18, if you're ready to include it now. -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3226 Virtualization: qemu.org | libvirt.org