[Libguestfs] [nbdkit] Proposed (new) filter API
Richard W.M. Jones
rjones at redhat.com
Tue Jan 16 17:05:31 UTC 2018
On Tue, Jan 16, 2018 at 10:52:12AM -0600, Eric Blake wrote:
> > /* This header also defines some useful functions like nbdkit_debug
> > * and nbdkit_parse_size which are appropriate for filters to use.
>
> Too much copy-and-paste?
>
> > */
> > #include <nbdkit-plugin.h>
>
> I guess you get those useful functions by inclusion, rather than by
> direct definition.
Yes, that comment describes why we include the header. I guess I
could delete the comment if it's confusing.
> >
> > struct nbdkit_next {
> > int64_t (*get_size) (void *nxdata);
> >
> > int (*can_write) (void *nxdata);
> > int (*can_flush) (void *nxdata);
> > int (*is_rotational) (void *nxdata);
> > int (*can_trim) (void *nxdata);
> >
> > int (*pread) (void *nxdata, void *buf, uint32_t count, uint64_t offset);
> > int (*pwrite) (void *nxdata,
> > const void *buf, uint32_t count, uint64_t offset);
> > int (*flush) (void *nxdata);
> > int (*trim) (void *nxdata, uint32_t count, uint64_t offset);
> > int (*zero) (void *nxdata, uint32_t count, uint64_t offset, int may_trim);
> > };
>
> While we want to support plugins that use the old API, should we declare
> that filters only use the new API? Or does my work to add FUA
> passthrough need to be careful on how a filter does the work;
> particularly if mixing a filter without FUA knowledge with a backend
> that can do it? I guess as long as we stabilize all of the filter and
> FUA code into the same nbdkit release, it's okay if we tweak the filter
> definition slightly in the next few patches.
I was hoping we could combine the FUA patches (or rather, push them
all together) so that in the final version the filter .pwrite
definition above would contain a FUA/flags parameter.
> > struct nbdkit_filter {
> > /* Do not set these fields directly; use NBDKIT_REGISTER_FILTER.
> > * They exist so that we can support filters compiled against
> > * one version of the header with a runtime compiled against a
> > * different version with more (or fewer) fields.
> > */
> > uint64_t _struct_size;
> > int _api_version;
> >
> > /* New fields will only be added at the end of the struct. */
> > const char *name;
> > const char *longname;
> > const char *version;
> > const char *description;
> >
> > void (*load) (void);
> > void (*unload) (void);
> >
> > int (*config) (nbdkit_next_config *next, void *nxdata,
> > const char *key, const char *value);
> > int (*config_complete) (nbdkit_next_config_complete *next, void *nxdata);
> > const char *config_help;
> >
> > void * (*open) (int readonly);
>
> Is it conceivable that opening a filter may want to read data from the
> underlying backend?
One case where this could make sense would be with a "partition"
filter (which needs to read the partition table early), and I did
consider that. However I believe -- although haven't proven by
implementation -- that a partition filter can still be written, it
just needs to read the partition table once in one of the other
functions, whichever is called first, with a bit of mutex-ing.
The advantage to make open not be a passthrough is it somewhat
simplifies the implementation, otherwise it has to deal with the new
handle returned from the next element in the chain.
> Do we have guarantees on lifecycle ordering across
> the chain (if the command line uses filter1 filter2 plugin, we open
> plugin first, filter2 second, filter1 last; then close in reverse order)?
At the moment we open plugin, then filter2, then filter1, and close
them in the same order. I was hoping not to define the order, since I
don't think it matters(?)
It could also be different for load/unload vs open/close.
> > Different filters can be stacked:
> >
> > NBD ┌─────────┐ ┌─────────┐ ┌────────┐
> > client ───▶│ filter1 │───▶│ filter2 │── ─ ─ ──▶│ plugin │
> > request └─────────┘ └─────────┘ └────────┘
>
> Does conversion from POD to other formats preserve proper formatting of
> this ASCII-art?
We've used utf-8 in POD in libguestfs since forever.
> > =head2 C<.name>
> >
> > const char *name;
> >
> > This field (a string) is required, and B<must> contain only ASCII
> > alphanumeric characters and be unique amongst all filters.
>
> Do filters and plugins share the same namespace, or can you have a
> filter whose name matches a plugin?
Different namespaces because they go into different directories
(plugindir vs filterdir).
> > =head2 C<.open>
> >
> > void * (*open) (int readonly);
> >
> > This is called when a new client connection is opened and can be used
> > to allocate any per-connection data structures needed by the filter.
> > The handle (which is not the same as the plugin handle) is passed back
> > to other filter callbacks and could be freed in the C<.close>
> > callback.
> >
> > Note that the handle is completely opaque to nbdkit, but it must not
> > be NULL.
> >
> > If there is an error, C<.open> should call C<nbdkit_error> with an
> > error message and return C<NULL>.
>
> I guess if you wanted to be truly opaque and support NULL, you'd have to
> have something like:
>
> int (*open) (int readonly, void **result)
>
> which populates *result when returning 0, and returns -1 on failure.
> But I'm also fine with your choice of stating that the opaque data has
> to be anything other than NULL.
It's consistent with how plugins work 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/
More information about the Libguestfs
mailing list