Add a perl language binding for the .zero callback, used for
implementing NBD_CMD_WRITE_ZEROES. Unlike the pwrite callback
with no return type, and unlike C where we can manipulate errno,
we need a way to distinguish between hard error (the usual die),
and the fallback error (return false so the binding can turn it
into EOPNOTSUPP), so success requires returning true.
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
plugins/perl/nbdkit-perl-plugin.pod | 25 +++++++++++++++++++++++++
plugins/perl/perl.c | 37 +++++++++++++++++++++++++++++++++++++
2 files changed, 62 insertions(+)
diff --git a/plugins/perl/nbdkit-perl-plugin.pod b/plugins/perl/nbdkit-perl-plugin.pod
index 3d0ce14..39df7b1 100644
--- a/plugins/perl/nbdkit-perl-plugin.pod
+++ b/plugins/perl/nbdkit-perl-plugin.pod
@@ -271,6 +271,31 @@ store.
If there is an error, the function should call C<die>.
+=item C<zero>
+
+(Optional)
+
+ sub zero
+ {
+ my $handle = shift;
+ my $count = shift;
+ my $offset = shift;
+ my $may_trim = shift;
+ my $bool = ...;
+ return $bool;
+ }
+
+The body of your C<zero> function should ensure that C<$count> bytes
+of the disk, starting at C<$offset>, will read back as zero. If
+C<$may_trim> is true, the operation may be optimized as a trim as long
+as subsequent reads see zeroes. Return true if the write was
+successful, and false to trigger a graceful fallback to C<pwrite>.
+
+NBD only supports whole writes, so your function should try to write
+the whole region (perhaps requiring a loop). If the write fails or is
+partial, and you do not want the fallback to C<pwrite>, your function
+should C<die>.
+
=back
=head2 MISSING CALLBACKS
diff --git a/plugins/perl/perl.c b/plugins/perl/perl.c
index 935e1ba..ba42864 100644
--- a/plugins/perl/perl.c
+++ b/plugins/perl/perl.c
@@ -494,6 +494,42 @@ perl_can_trim (void *handle)
}
static int
+perl_zero (void *handle, uint32_t count, uint64_t offset, int may_trim)
+{
+ dSP;
+ SV *sv;
+ int r = 0;
+
+ if (callback_defined ("zero")) {
+ ENTER;
+ SAVETMPS;
+ PUSHMARK (SP);
+ XPUSHs (handle);
+ XPUSHs (sv_2mortal (newSViv (count)));
+ XPUSHs (sv_2mortal (newSViv (offset)));
+ XPUSHs (sv_2mortal (newSViv (may_trim)));
+ PUTBACK;
+ call_pv ("zero", G_EVAL|G_SCALAR);
+ SPAGAIN;
+ sv = POPs;
+ r = SvIV (sv);
+ PUTBACK;
+ FREETMPS;
+ LEAVE;
+
+ if (check_perl_failure () == -1)
+ return -1;
+
+ if (r)
+ return 0;
+ }
+
+ nbdkit_debug ("zero falling back to pwrite");
+ errno = EOPNOTSUPP;
+ return -1;
+}
+
+static int
perl_is_rotational (void *handle)
{
dSP;
@@ -614,6 +650,7 @@ static struct nbdkit_plugin plugin = {
.pwrite = perl_pwrite,
.flush = perl_flush,
.trim = perl_trim,
+ .zero = perl_zero,
};
NBDKIT_REGISTER_PLUGIN(plugin)
--
2.9.3