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@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