If we bump NBDKIT_API_VERSION, we have forcefully made older nbdkit reject all plugins that opt to the newer API:
$ nbdkit ./plugins/nbd/.libs/nbdkit-nbd-plugin.so --dump-plugin nbdkit: ./plugins/nbd/.libs/nbdkit-nbd-plugin.so: plugin is incompatible with this version of nbdkit (_api_version = 2) But with a bit of finesse, we can make opting in to FUA support orthogonal to NBDKIT_API_VERSION, by introducing a new witness level that the user controls, and by providing sane fallbacks so that newer plugins correctly populate the fields expected by older nbdkit. --- v3: rework entirely, add new variable instead of NBDKIT_API_VERSION This patch is still RFC; if you like it, it's probably better to rebase portions of this patch into the rest of the series, rather than churning NBDKIT_API_VERSION temporarily to 2 and now back to 1 Signed-off-by: Eric Blake <[email protected]> --- docs/nbdkit-plugin.pod | 12 ++++----- docs/nbdkit.pod | 6 ++--- include/nbdkit-plugin.h | 71 ++++++++++++++++++++++++++++++++++++++++++++----- src/internal.h | 2 +- src/plugins.c | 4 +-- plugins/nbd/nbd.c | 2 +- plugins/null/null.c | 2 +- 7 files changed, 77 insertions(+), 22 deletions(-) diff --git a/docs/nbdkit-plugin.pod b/docs/nbdkit-plugin.pod index 933f710..a82ced8 100644 --- a/docs/nbdkit-plugin.pod +++ b/docs/nbdkit-plugin.pod @@ -6,7 +6,7 @@ nbdkit-plugin - How to write nbdkit plugins =head1 SYNOPSIS - #define NBDKIT_API_VERSION 2 + #define NBDKIT_PLUGIN_LEVEL 2 #include <nbdkit-plugin.h> @@ -65,22 +65,22 @@ L<nbdkit-perl-plugin(3)>, L<nbdkit-python-plugin(3)>, L<nbdkit-ruby-plugin(3)>. -=head1 C<#define NBDKIT_API_VERSION 2> +=head1 C<#define NBDKIT_PLUGIN_LEVEL 2> Plugins must choose which API version they want to use, by defining -NBDKIT_API_VERSION to a positive integer prior to including +NBDKIT_PLUGIN_LEVEL to a positive integer prior to including C<nbdkit-plugin.h> (or any other nbdkit header). The default version is 1 for backwards-compatibility with nbdkit v1.1.26 and earlier; however, it is recommended that new plugins be written to the maximum -version (currently 2) as it enables more features and better +level (currently 2) as it enables more features and better interaction with nbdkit filters. Therefore, the rest of this document only covers the version 2 interface. A newer nbdkit will always -support plugins compiled against any prior API version. +support plugins compiled against any prior API level. =head1 C<nbdkit-plugin.h> All plugins should start by including this header file, after -optionally choosing an API version: +optionally choosing an API level: #include <nbdkit-plugin.h> diff --git a/docs/nbdkit.pod b/docs/nbdkit.pod index d49ae53..ee27d54 100644 --- a/docs/nbdkit.pod +++ b/docs/nbdkit.pod @@ -829,10 +829,8 @@ information about that plugin, eg: Plugins which ship with nbdkit usually have the same version as the corresponding nbdkit binary. The nbdkit binary will always be able to utilize plugins compiled against an older version of the header; -however, newer plugins may not be fully supported by an older nbdkit -binary (for example, a plugin compiled with C<NBDKIT_API_VERSION> of 2 -fails to load with an older nbdkit that only knows -C<NBDKIT_API_VERSION> 1). +however, although the design tries hard to allow it, newer plugins may +not be fully supported by an older nbdkit binary. =head2 Detect if a plugin is installed diff --git a/include/nbdkit-plugin.h b/include/nbdkit-plugin.h index 3f541a1..9ecddeb 100644 --- a/include/nbdkit-plugin.h +++ b/include/nbdkit-plugin.h @@ -42,11 +42,15 @@ extern "C" { #endif -/* By default, a plugin gets API version 1; but you may request - * version 2 prior to including this header */ -#ifndef NBDKIT_API_VERSION -#define NBDKIT_API_VERSION 1 -#elif (NBDKIT_API_VERSION - 0) < 1 || NBDKIT_API_VERSION > 2 +/* Remaining compatible with API version 1 allows plugins compiled + * against newer nbdkit headers to run with older nbdkit binaries. */ +#define NBDKIT_API_VERSION 1 + +/* By default, a plugin gets API version 1 level 1; but you may + * request version 1 level 2 prior to including this header. */ +#ifndef NBDKIT_PLUGIN_LEVEL +#define NBDKIT_PLUGIN_LEVEL 1 +#elif (NBDKIT_PLUGIN_LEVEL - 0) < 1 || NBDKIT_PLUGIN_LEVEL > 2 #error Unsupported API version #endif @@ -86,7 +90,7 @@ struct nbdkit_plugin { int (*is_rotational) (void *handle); int (*can_trim) (void *handle); -#if NBDKIT_API_VERSION == 1 +#if NBDKIT_PLUGIN_LEVEL == 1 int (*pread) (void *handle, void *buf, uint32_t count, uint64_t offset); int (*pwrite) (void *handle, const void *buf, uint32_t count, uint64_t offset); int (*flush) (void *handle); @@ -105,7 +109,7 @@ struct nbdkit_plugin { void (*dump_plugin) (void); int (*can_fua) (void *handle); -#if NBDKIT_API_VERSION == 1 +#if NBDKIT_PLUGIN_LEVEL == 1 int (*_unused1) (void *, void *, uint32_t, uint64_t); int (*_unused2) (void *, const void *, uint32_t, uint64_t, uint32_t); int (*_unused3) (void *, uint32_t); @@ -125,6 +129,7 @@ struct nbdkit_plugin { extern void nbdkit_set_error (int err); +#if NBDKIT_PLUGIN_LEVEL == 1 #define NBDKIT_REGISTER_PLUGIN(plugin) \ NBDKIT_CXX_LANG_C \ struct nbdkit_plugin * \ @@ -136,6 +141,58 @@ extern void nbdkit_set_error (int err); return &(plugin); \ } +#else +#define NBDKIT_REGISTER_PLUGIN(plugin) \ + static int \ + nbdkit_pread_old (void *handle, void *buf, uint32_t count, \ + uint64_t offset) \ + { \ + return (plugin).pread (handle, buf, count, offset, 0); \ + } \ + static int \ + nbdkit_pwrite_old (void *handle, const void *buf, uint32_t count, \ + uint64_t offset) \ + { \ + return (plugin).pwrite (handle, buf, count, offset, 0); \ + } \ + static int \ + nbdkit_flush_old (void *handle) \ + { \ + return (plugin).flush (handle, 0); \ + } \ + static int \ + nbdkit_trim_old (void *handle, uint32_t count, uint64_t offset) \ + { \ + return (plugin).trim (handle, count, offset, 0); \ + } \ + static int \ + nbdkit_zero_old (void *handle, uint32_t count, uint64_t offset, \ + int may_trim) \ + { \ + return (plugin).zero (handle, count, offset, \ + may_trim ? NBDKIT_FLAG_MAY_TRIM : 0); \ + } \ + NBDKIT_CXX_LANG_C \ + struct nbdkit_plugin * \ + plugin_init (void) \ + { \ + (plugin)._struct_size = sizeof (plugin); \ + (plugin)._api_version = NBDKIT_API_VERSION; \ + (plugin)._thread_model = THREAD_MODEL; \ + (plugin)._pread_old = nbdkit_pread_old; \ + if ((plugin).pwrite) \ + (plugin)._pwrite_old = nbdkit_pwrite_old; \ + if ((plugin).flush) \ + (plugin)._flush_old = nbdkit_flush_old; \ + if ((plugin).trim) \ + (plugin)._trim_old = nbdkit_trim_old; \ + if ((plugin).zero) \ + (plugin)._zero_old = nbdkit_zero_old; \ + return &(plugin); \ + } + +#endif + #ifdef __cplusplus } #endif diff --git a/src/internal.h b/src/internal.h index ea3155c..e803875 100644 --- a/src/internal.h +++ b/src/internal.h @@ -40,7 +40,7 @@ #include <sys/socket.h> #include <pthread.h> -#define NBDKIT_API_VERSION 2 +#define NBDKIT_PLUGIN_LEVEL 2 #include "nbdkit-plugin.h" #include "nbdkit-filter.h" diff --git a/src/plugins.c b/src/plugins.c index d44e724..e583fac 100644 --- a/src/plugins.c +++ b/src/plugins.c @@ -389,7 +389,7 @@ plugin_can_fua (struct backend *b, struct connection *conn) if (p->plugin.can_fua) { r = p->plugin.can_fua (connection_get_handle (conn, 0)); - if (r > NBDKIT_FUA_EMULATE && p->plugin._api_version == 1) + if (r > NBDKIT_FUA_EMULATE && !p->plugin.pread) r = NBDKIT_FUA_EMULATE; return r; } @@ -655,7 +655,7 @@ plugin_register (size_t index, const char *filename, } /* Check for incompatible future versions. */ - if (plugin->_api_version < 0 || plugin->_api_version > 2) { + if (plugin->_api_version != NBDKIT_API_VERSION) { fprintf (stderr, "%s: %s: plugin is incompatible with this version of nbdkit (_api_version = %d)\n", program_name, p->filename, plugin->_api_version); exit (EXIT_FAILURE); diff --git a/plugins/nbd/nbd.c b/plugins/nbd/nbd.c index db53746..bd1b48b 100644 --- a/plugins/nbd/nbd.c +++ b/plugins/nbd/nbd.c @@ -46,7 +46,7 @@ #include <assert.h> #include <pthread.h> -#define NBDKIT_API_VERSION 2 +#define NBDKIT_PLUGIN_LEVEL 2 #include <nbdkit-plugin.h> #include "protocol.h" diff --git a/plugins/null/null.c b/plugins/null/null.c index 905cc64..436892d 100644 --- a/plugins/null/null.c +++ b/plugins/null/null.c @@ -39,7 +39,7 @@ #include <string.h> #include <errno.h> -#define NBDKIT_API_VERSION 2 +#define NBDKIT_PLUGIN_LEVEL 2 #include <nbdkit-plugin.h> -- 2.14.3 _______________________________________________ Libguestfs mailing list [email protected] https://www.redhat.com/mailman/listinfo/libguestfs
