New nbdkit already knows how to gracefully handle a plugin that defines .pwrite_fua but not .pwrite, making it possible to write a plugin that does not have to provide duplicate boilerplate code. But for maximum cross-version compatibility, we must make sure that older nbdkit, which doesn't know about the existance of the .pwrite_fua callback, can still perform writes when loading such a newer plugin. The trick is to make our registration macro provide sane fallback definitions, marked such that gcc won't warn if the fallbacks are not needed.
Signed-off-by: Eric Blake <[email protected]> --- docs/nbdkit.pod | 11 +++++------ include/nbdkit-plugin.h | 26 ++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/docs/nbdkit.pod b/docs/nbdkit.pod index 2b868d9..a72c9b1 100644 --- a/docs/nbdkit.pod +++ b/docs/nbdkit.pod @@ -785,12 +785,11 @@ information about that plugin, eg: [etc] 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, there are cases where a newer plugin may not be fully -supported by an older nbdkit binary (for example, a plugin that -supplies C<.pwrite_fua> but not C<.pwrite> may not support writes -when loaded by the older nbdkit). +corresponding nbdkit binary. The nbdkit binary will always be able to +utilize plugins compiled against an older version of the header; the +converse direction of an older nbdkit driving a newer plugin is not +guaranteed to work, although the design tries hard to preserve +back-compatibility. =head2 Detect if a plugin is installed diff --git a/include/nbdkit-plugin.h b/include/nbdkit-plugin.h index d3b0050..0c6e67e 100644 --- a/include/nbdkit-plugin.h +++ b/include/nbdkit-plugin.h @@ -117,6 +117,12 @@ extern char *nbdkit_absolute_path (const char *path); extern int64_t nbdkit_parse_size (const char *str); extern int nbdkit_read_password (const char *value, char **password); +#ifdef __GNUC__ +#define NBDKIT_UNUSED __attribute__ (( __unused__ )) +#else +#define NBDKIT_UNUSED /* empty */ +#endif + #ifdef __cplusplus #define NBDKIT_CXX_LANG_C extern "C" #else @@ -124,6 +130,20 @@ extern int nbdkit_read_password (const char *value, char **password); #endif #define NBDKIT_REGISTER_PLUGIN(plugin) \ + static int NBDKIT_UNUSED \ + nbdkit_pwrite_no_fua (void *handle, const void *buf, uint32_t count, \ + uint64_t offset) { \ + return (plugin).pwrite_fua (handle, buf, count, offset, 0); \ + } \ + static int NBDKIT_UNUSED \ + nbdkit_zero_no_fua (void *handle, uint32_t count, uint64_t offset, \ + int may_trim) { \ + return (plugin).zero_fua (handle, count, offset, may_trim, 0); \ + } \ + static int NBDKIT_UNUSED \ + nbdkit_trim_no_fua (void *handle, uint32_t count, uint64_t offset) { \ + return (plugin).trim_fua (handle, count, offset, 0); \ + } \ NBDKIT_CXX_LANG_C \ struct nbdkit_plugin * \ plugin_init (void) \ @@ -131,6 +151,12 @@ extern int nbdkit_read_password (const char *value, char **password); (plugin)._struct_size = sizeof (plugin); \ (plugin)._api_version = NBDKIT_API_VERSION; \ (plugin)._thread_model = THREAD_MODEL; \ + if ((plugin).pwrite_fua && !(plugin).pwrite) \ + (plugin).pwrite = nbdkit_pwrite_no_fua; \ + if ((plugin).zero_fua && !(plugin).zero) \ + (plugin).zero = nbdkit_zero_no_fua; \ + if ((plugin).trim_fua && !(plugin).trim) \ + (plugin).trim = nbdkit_trim_no_fua; \ return &(plugin); \ } -- 2.14.3 _______________________________________________ Libguestfs mailing list [email protected] https://www.redhat.com/mailman/listinfo/libguestfs
