On Thu, May 06, 2021 at 08:59:36PM -0500, Eric Blake wrote:
Allowing a filter to bypass the plugin's .get_ready or .after_fork makes no sense, and there are no other arguments to modify. Furthermore, now that filters have access to open a plugin context independently of a client connection, .after_fork would be an ideal place to do so with its existing nbdkit_backend argument (which we already documented was stable, although this test actually adds tests for that). Still, we will want to add a counterpart API (in a later patch) to tear that context down cleanly, where .unload is too late. But for that to work, we need to ensure that the plugin completes initialization before the filter is allowed to try to open a context into the plugin, which means swapping the visitation order to be inner-to-outer (similar to .prepare). --- docs/nbdkit-filter.pod | 24 +++++++++++------------ include/nbdkit-filter.h | 7 ++----- server/filters.c | 26 ++++++------------------- filters/exitwhen/exitwhen.c | 9 ++++----- filters/extentlist/extentlist.c | 5 ++--- filters/log/log.c | 9 ++++----- filters/multi-conn/multi-conn.c | 5 ++--- filters/pause/pause.c | 4 ++-- filters/rate/rate.c | 5 ++--- filters/stats/stats.c | 5 ++--- filters/tls-fallback/tls-fallback.c | 5 ++--- tests/test-layers-filter.c | 12 +++++------- tests/test-layers.c | 30 ++++++++++++++--------------- 13 files changed, 60 insertions(+), 86 deletions(-)
diff --git a/docs/nbdkit-filter.pod b/docs/nbdkit-filter.pod index 97f32e10..9816f4e8 100644 --- a/docs/nbdkit-filter.pod +++ b/docs/nbdkit-filter.pod @@ -127,8 +127,7 @@ 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_get_ready>, -C<nbdkit_next_after_fork>, C<nbdkit_next_preconnect>, +C<nbdkit_next_config_complete>, C<nbdkit_next_preconnect>, C<nbdkit_next_list_exports>, C<nbdkit_next_default_export>, 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 @@ -406,28 +405,29 @@ with an error message and return C<-1>.
=head2 C<.get_ready>
- int (*get_ready) (nbdkit_next_get_ready *next, void *nxdata, - int thread_model); + int (*get_ready) (int thread_model);
-This intercepts the plugin C<.get_ready> method and can be used by the -filter to get ready to serve requests. +This optional callback is reached if the plugin C<.get_ready> method +succeeded (if the plugin failed, nbdkit has already exited), and can +be used by the filter to get ready to serve requests.
The C<thread_model> parameter informs the filter about the final thread model chosen by nbdkit after considering the results of C<.thread_model> of all filters in the chain after -C<.config_complete>. This does not need to be passed on to C<next>, -as the model can no longer be altered at this point. +C<.config_complete>.
If there is an error, C<.get_ready> should call C<nbdkit_error> with an error message and return C<-1>.
=head2 C<.after_fork>
- int (*after_fork) (nbdkit_next_after_fork *next, nbdkit_backend *nxdata); + int (*after_fork) (nbdkit_backend *backend);
-This intercepts the plugin C<.after_fork> method and can be used by -the filter to start background threads (although these have limited -usefulness since they will not be able to access the plugin). +This optional callback is reached after the plugin C<.after_fork> +method has succeeded (if the plugin failed, nbdkit has already +exited), and can be used by the filter to start background threads. +The C<backend> parameter is valid until C<.unload>, for creating manual +contexts into the backend with C<nbdkit_next_context_open>.
If there is an error, C<.after_fork> should call C<nbdkit_error> with an error message and return C<-1>. diff --git a/include/nbdkit-filter.h b/include/nbdkit-filter.h index 86c41dd7..662f52cb 100644 --- a/include/nbdkit-filter.h +++ b/include/nbdkit-filter.h @@ -66,8 +66,6 @@ typedef struct nbdkit_next_ops nbdkit_next; 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_after_fork (nbdkit_backend *nxdata); typedef int nbdkit_next_preconnect (nbdkit_backend *nxdata, int readonly); typedef int nbdkit_next_list_exports (nbdkit_backend *nxdata, int readonly, struct nbdkit_exports *exports); @@ -197,9 +195,8 @@ 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 thread_model); - int (*after_fork) (nbdkit_next_after_fork *next, nbdkit_backend *nxdata); + int (*get_ready) (int thread_model); + int (*after_fork) (nbdkit_backend *backend); int (*preconnect) (nbdkit_next_preconnect *next, nbdkit_backend *nxdata, int readonly); int (*list_exports) (nbdkit_next_list_exports *next, nbdkit_backend *nxdata, diff --git a/server/filters.c b/server/filters.c index 31cf5c7e..136fa672 100644 --- a/server/filters.c +++ b/server/filters.c @@ -171,33 +171,19 @@ 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);
+ b->next->get_ready (b->next); /* exits on failure */ + debug ("%s: get_ready thread_model=%d", b->name, thread_model);
if (f->filter.get_ready) { - if (f->filter.get_ready (next_get_ready, b->next, thread_model) == -1) + if (f->filter.get_ready (thread_model) == -1) exit (EXIT_FAILURE); } - else - b->next->get_ready (b->next); -} - -static int -next_after_fork (struct backend *b) -{ - b->after_fork (b); - return 0; }
static void @@ -205,14 +191,14 @@ filter_after_fork (struct backend *b) { struct backend_filter *f = container_of (b, struct backend_filter, backend);
+ b->next->after_fork (b->next); /* exits on failure */ + debug ("%s: after_fork", b->name);
if (f->filter.after_fork) { - if (f->filter.after_fork (next_after_fork, b->next) == -1) + if (f->filter.after_fork (b->next) == -1) exit (EXIT_FAILURE); } - else - b->next->after_fork (b->next); }
[changes to filters omitted] Yes, this one is pretty obvious in hindsight. ACK. Might as well push this one now. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com virt-df lists disk usage of guests without needing to install any software inside the virtual machine. Supports Linux and Windows. http://people.redhat.com/~rjones/virt-df/