This allows us to add the following callbacks:
- can_zero returns boolean
- can_fua should print "none", "emulate" or "native"
Furthermore the following callbacks are modified in a backwards
compatible manner:
- pwrite adding flags parameter
- trim adding flags parameter
This change is not backwards compatible:
- zero may_trim parameter replaced by flags parameter
---
plugins/sh/nbdkit-sh-plugin.pod | 41 +++++++++++---
plugins/sh/sh.c | 99 +++++++++++++++++++++++++++------
2 files changed, 115 insertions(+), 25 deletions(-)
diff --git a/plugins/sh/nbdkit-sh-plugin.pod b/plugins/sh/nbdkit-sh-plugin.pod
index 0644c36..ebd3cfb 100644
--- a/plugins/sh/nbdkit-sh-plugin.pod
+++ b/plugins/sh/nbdkit-sh-plugin.pod
@@ -196,17 +196,21 @@ This method is required.
=item C<can_trim>
+=item C<can_zero>
+
Unlike in other languages, you B<must> provide the C<can_*> methods
otherwise they are assumed to all return false and your C<pwrite>,
-C<flush> and C<trim> methods will never be called. The reason for
-this is obscure: In other languages we can detect if (eg) a C<pwrite>
-method is defined and synthesize an appropriate response if no actual
-C<can_write> method is defined. However detecting if methods are
-present without running them is not possible with this plugin.
+C<flush>, C<trim> and C<zero> methods will never be called. The
+reason for this is obscure: In other languages we can detect if (eg) a
+C<pwrite> method is defined and synthesize an appropriate response if
+no actual C<can_write> method is defined. However detecting if
+methods are present without running them is not possible with this
+plugin.
/path/to/script can_write <handle>
/path/to/script can_flush <handle>
/path/to/script can_trim <handle>
+ /path/to/script can_zero <handle>
The script should exit with code C<0> for true or code C<3> for false.
@@ -216,6 +220,15 @@ The script should exit with code C<0> for true or code
C<3> for false.
The script should exit with code C<0> for true or code C<3> for false.
+=item C<can_fua>
+
+ /path/to/script can_fua <handle>
+
+This controls Forced Unit Access (FUA) behaviour of the core server.
+Unlike the other C<can_*> callbacks, this one is I<not> a boolean. It
+must print either "none", "emulate" or "native". The
meaning of these
+is described in L<nbdkit-plugin(3)>.
+
=item C<pread>
/path/to/script pread <handle> <count> <offset>
@@ -227,10 +240,13 @@ This method is required.
=item C<pwrite>
- /path/to/script pwrite <handle> <count> <offset>
+ /path/to/script pwrite <handle> <count> <offset> <flags>
The script should read the binary data to be written from stdin.
+The C<flags> parameter can be an empty string or C<"fua">. In
future
+a comma-separated list of flags may be present.
+
Unlike in other languages, if you provide a C<pwrite> method you
B<must> also provide a C<can_write> method which exits with code C<0>
(true).
@@ -245,16 +261,23 @@ B<must> also provide a C<can_flush> method which exits
with code C<0>
=item C<trim>
- /path/to/script trim <handle> <count> <offset>
+ /path/to/script trim <handle> <count> <offset> <flags>
+
+The C<flags> parameter can be an empty string or C<"fua">. In
future
+a comma-separated list of flags may be present.
Unlike in other languages, if you provide a C<trim> method you B<must>
also provide a C<can_trim> method which exits with code C<0> (true).
=item C<zero>
- /path/to/script zero <handle> <count> <offset> <may_trim>
+ /path/to/script zero <handle> <count> <offset> <flags>
-C<may_trim> will be either C<true> or C<false>.
+The C<flags> parameter can be an empty string or C<"fua">. In
future
+a comma-separated list of flags may be present.
+
+Unlike in other languages, if you provide a C<zero> method you B<must>
+also provide a C<can_zero> method which exits with code C<0> (true).
=back
diff --git a/plugins/sh/sh.c b/plugins/sh/sh.c
index fcd839b..58693fb 100644
--- a/plugins/sh/sh.c
+++ b/plugins/sh/sh.c
@@ -41,6 +41,8 @@
#include <errno.h>
#include <sys/stat.h>
+#define NBDKIT_API_VERSION 2
+
#include <nbdkit-plugin.h>
#include "call.h"
@@ -360,7 +362,8 @@ sh_get_size (void *handle)
}
static int
-sh_pread (void *handle, void *buf, uint32_t count, uint64_t offset)
+sh_pread (void *handle, void *buf, uint32_t count, uint64_t offset,
+ uint32_t flags)
{
char *h = handle;
char cbuf[32], obuf[32];
@@ -404,12 +407,14 @@ sh_pread (void *handle, void *buf, uint32_t count, uint64_t offset)
}
static int
-sh_pwrite (void *handle, const void *buf,
- uint32_t count, uint64_t offset)
+sh_pwrite (void *handle, const void *buf, uint32_t count, uint64_t offset,
+ uint32_t flags)
{
char *h = handle;
char cbuf[32], obuf[32];
- const char *args[] = { script, "pwrite", h, cbuf, obuf, NULL };
+ /* In future, comma-separated list of flags. */
+ const char *sflags = flags & NBDKIT_FLAG_FUA ? "fua" : "";
+ const char *args[] = { script, "pwrite", h, cbuf, obuf, sflags, NULL };
snprintf (cbuf, sizeof cbuf, "%" PRIu32, count);
snprintf (obuf, sizeof obuf, "%" PRIu64, offset);
@@ -467,12 +472,6 @@ sh_can_flush (void *handle)
return boolean_method (handle, "can_flush");
}
-static int
-sh_can_trim (void *handle)
-{
- return boolean_method (handle, "can_trim");
-}
-
static int
sh_is_rotational (void *handle)
{
@@ -480,7 +479,70 @@ sh_is_rotational (void *handle)
}
static int
-sh_flush (void *handle)
+sh_can_trim (void *handle)
+{
+ return boolean_method (handle, "can_trim");
+}
+
+static int
+sh_can_zero (void *handle)
+{
+ return boolean_method (handle, "can_zero");
+}
+
+static int
+sh_can_fua (void *handle)
+{
+ char *h = handle;
+ const char *args[] = { script, "can_fua", h, NULL };
+ char *s = NULL;
+ size_t slen;
+ int r;
+
+ switch (call_read (&s, &slen, args)) {
+ case OK:
+ if (slen > 0 && s[slen-1] == '\n')
+ s[slen-1] = '\0';
+ if (strcmp (s, "none") == 0)
+ r = NBDKIT_FUA_NONE;
+ else if (strcmp (s, "emulate") == 0)
+ r = NBDKIT_FUA_EMULATE;
+ else if (strcmp (s, "native") == 0)
+ r = NBDKIT_FUA_NATIVE;
+ else {
+ nbdkit_error ("%s: could not parse output from can_fua method: %s",
+ script, s);
+ free (s);
+ return -1;
+ }
+ free (s);
+ return r;
+
+ case MISSING:
+ free (s);
+ /* NBDKIT_FUA_EMULATE means that nbdkit will call .flush. However
+ * we cannot know if that callback exists, so the safest default
+ * is to return NBDKIT_FUA_NONE.
+ */
+ return NBDKIT_FUA_NONE;
+
+ case ERROR:
+ free (s);
+ return -1;
+
+ case RET_FALSE:
+ free (s);
+ nbdkit_error ("%s: %s method returned unexpected code (3/false)",
+ script, "can_fua");
+ errno = EIO;
+ return -1;
+
+ default: abort ();
+ }
+}
+
+static int
+sh_flush (void *handle, uint32_t flags)
{
char *h = handle;
const char *args[] = { script, "flush", h, NULL };
@@ -507,11 +569,13 @@ sh_flush (void *handle)
}
static int
-sh_trim (void *handle, uint32_t count, uint64_t offset)
+sh_trim (void *handle, uint32_t count, uint64_t offset, uint32_t flags)
{
char *h = handle;
char cbuf[32], obuf[32];
- const char *args[] = { script, "trim", h, cbuf, obuf, NULL };
+ /* In future, comma-separated list of flags. */
+ const char *sflags = flags & NBDKIT_FLAG_FUA ? "fua" : "";
+ const char *args[] = { script, "trim", h, cbuf, obuf, sflags, NULL };
snprintf (cbuf, sizeof cbuf, "%" PRIu32, count);
snprintf (obuf, sizeof obuf, "%" PRIu64, offset);
@@ -538,12 +602,13 @@ sh_trim (void *handle, uint32_t count, uint64_t offset)
}
static int
-sh_zero (void *handle, uint32_t count, uint64_t offset, int may_trim)
+sh_zero (void *handle, uint32_t count, uint64_t offset, uint32_t flags)
{
char *h = handle;
char cbuf[32], obuf[32];
- const char *args[] = { script, "zero", h, cbuf, obuf,
- may_trim ? "true" : "false", NULL };
+ /* In future, comma-separated list of flags. */
+ const char *sflags = flags & NBDKIT_FLAG_FUA ? "fua" : "";
+ const char *args[] = { script, "zero", h, cbuf, obuf, sflags, NULL };
snprintf (cbuf, sizeof cbuf, "%" PRIu32, count);
snprintf (obuf, sizeof obuf, "%" PRIu64, offset);
@@ -596,6 +661,8 @@ static struct nbdkit_plugin plugin = {
.can_flush = sh_can_flush,
.is_rotational = sh_is_rotational,
.can_trim = sh_can_trim,
+ .can_zero = sh_can_zero,
+ .can_fua = sh_can_fua,
.pread = sh_pread,
.pwrite = sh_pwrite,
--
2.19.2