On Mon, Jun 22, 2020 at 02:00:50PM -0500, Eric Blake wrote: > >+++ b/docs/nbdkit-filter.pod > > >+=head2 C<.after_fork> > >+ > >+ int (*after_fork) (nbdkit_next_after_fork *next, void *nxdata); > >+ > >+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). > >+ > >+If there is an error, C<.after_fork> should call C<nbdkit_error> with > >+an error message and return C<-1>. > > Should the backend code guarantee that .after_fork is called for all > layers in the backend chain? The only flexibility I see us gaining > by letting the filter choose when .after_fork is called is > fine-grained control over what threads the filter can start before > or after the plugin's .after_fork, but is that flexibility really > needed, or are we equally safe if the backend just always calls > .after_fork and the filter doesn't have to worry about calling > next(nxdata)? > > Of course, given that filters are in-tree, we can change this > signature as needed later on, even if we make it void for now we can > hook it into passing .after_fork later if we find a use for that > finer-grained call semantics.
In theory a filter that wanted background threads would have exactly the same problem as a plugin and would need to add an .after_fork callback to create them. I can't think of a situation where a filter would be correct to not call the plugin's .after_fork, but I suppose it's plausible it might want to do something before or after the plugin. The biggest practical problem at the moment however is ... At this point I would link to the TODO file on github, but it seems like github is down. If you look at the TODO file you'll see I mentioned a general problem with background threads in filters. Anyway as you say they're all in tree so we can worry about this later. > >+=item C<.after_fork> > >+ > >+In normal operation, C<.after_fork> is called after the server has > >+forked into the background and changed UID and directory. If a plugin > >+needs to create background threads (or uses an external library that > >+creates threads) it should do so here, because background threads are > >+killed by fork. > > s/killed/invalidated/ (they are still alive in the parent process, > but after the fork we are no longer in the parent process to > interact with them) OK, I'll change this. It's also of course a point that if a plugin creates background threads before the fork and they grab locks then that could lead to problems. So I need to add a note to .get_ready saying that you shouldn't create background threads there. > >+ > >+Because the server may have forked into the background, error messages > >+and failures from C<.after_fork> cannot be seen by the user unless > >+they look through syslog. An error in C<.after_fork> can appear to > >+the user as if nbdkit “just died”. So in almost all cases it is > >+better to use C<.get_ready> instead of this callback, or to do as much > >+preparation work as possible in C<.get_ready> and only start > >+background threads here. > >+ > >+The server doesn't always fork (eg. if the I<-f> flag is used), but > >+even so this callback will be called. If you want to find out if the > >+server forked between C<.get_ready> and C<.after_fork> use > >+L<getpid(2)>. > > Thinking about back-compat: > We promise that plugins compiled against older nbdkit will continue > to run against newer nbdkit, and that is preserved here. > What we do not promise is that plugins compiled against newer nbdkit > will work wehn loaded by older nbdkit. This is one of those cases: > anything you stick in .after_fork will not be called by older nbdkit > which didn't know about the callback. > > At present, we silently ignore the tail of 'struct plugin' from any > plugin compiled against newer nbdkit when loaded by older nbdkit. > Should we tweak that to instead output a warning that the plugin > might rely on features present only in newer nbdkit and therefore > might not work in the current nbdkit version? Of course, that > doesn't help the fact that existing older nbdkit is lacking this > safety check. It should probably only do that if the tail of the struct is non-zero, because who cares if it contains NULL pointers. But that's another patch. > Do we need to instead add some sort of API for plugins to be able to > learn which features are provided by the nbdkit loading the plugin, > so that a plugin that requires the use of 1.22 nbdkit features (such > as .after_fork) can gracefully fail during .config_complete (or > similar) when loaded by a 1.20 nbdkit, rather than mysteriously > failing to work when .after_fork is not called? [In a distro > setting, the solution is version dependencies: you could make it so > that installing the nbdkit-vddk-plugin package forces an upgrade of > the nbdkit package to 1.22 - but this is more a question for > situations not covered by distro packaging setups] TBH this is a non-supported case so if it fails you get to keep all the pieces. > >+=head2 C<.after_fork> > >+ > >+ int after_ready (void); > > Typo in the function name. Oops. > >+++ b/server/filters.c > >@@ -193,6 +193,28 @@ filter_get_ready (struct backend *b) > > b->next->get_ready (b->next); > > } > >+static int > >+next_after_fork (struct backend *b) > >+{ > >+ b->after_fork (b); > >+ return 0; > >+} > >+ > >+static void > >+filter_after_fork (struct backend *b) > >+{ > >+ struct backend_filter *f = container_of (b, struct backend_filter, > >backend); > >+ > >+ debug ("%s: after_fork", b->name); > >+ > >+ if (f->filter.after_fork) { > >+ if (f->filter.after_fork (next_after_fork, b->next) == -1) > >+ exit (EXIT_FAILURE); > >+ } > >+ else > >+ b->next->after_fork (b->next); > >+} > > This code changes if we decide that filters could live with 'void' > instead of next_after_fork, because we mandate the chain traversal > through the backend rather than leaving it up to the filters. > > Still a few tweaks needed, but the idea looks sane. 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/ _______________________________________________ Libguestfs mailing list Libguestfs@redhat.com https://www.redhat.com/mailman/listinfo/libguestfs