Add a perl language binding for the .zero callback, used for implementing NBD_CMD_WRITE_ZEROES. The caller doesn't have to return anything, but should use Nbdkit::set_error(POSIX::EOPNOTSUPP) to get an automatic fallback to pwrite.
Enhance the example to show the use of the fallback mechanism, and to serve as a test of Nbdkit::set_error(). Signed-off-by: Eric Blake <ebl...@redhat.com> --- plugins/perl/example.pl | 16 +++++++++++++ plugins/perl/nbdkit-perl-plugin.pod | 26 +++++++++++++++++++++ plugins/perl/perl.c | 45 ++++++++++++++++++++++++++++++++++++- 3 files changed, 86 insertions(+), 1 deletion(-) diff --git a/plugins/perl/example.pl b/plugins/perl/example.pl index fcdac33..7ea24ff 100644 --- a/plugins/perl/example.pl +++ b/plugins/perl/example.pl @@ -1,4 +1,5 @@ use strict; +use POSIX (); # Example Perl plugin. # @@ -83,3 +84,18 @@ sub pwrite substr ($disk, $offset, $count) = $buf; } + +sub zero +{ + my $h = shift; + my $count = shift; + my $offset = shift; + my $may_trim = shift; + + if ($may_trim) { + substr ($disk, $offset, $count) = "\0" x $count; + } else { + Nbdkit::set_error(POSIX::EOPNOTSUPP); + die "fall back to pwrite"; + } +} diff --git a/plugins/perl/nbdkit-perl-plugin.pod b/plugins/perl/nbdkit-perl-plugin.pod index 82766d0..920bdef 100644 --- a/plugins/perl/nbdkit-perl-plugin.pod +++ b/plugins/perl/nbdkit-perl-plugin.pod @@ -290,6 +290,32 @@ store. If there is an error, the function should call C<die>, optionally using C<Nbdkit::set_error> first. +=item C<zero> + +(Optional) + + sub zero + { + my $handle = shift; + my $count = shift; + my $offset = shift; + my $may_trim = shift; + # No return value + } + +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. + +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, your function should C<die>, optionally using +C<Nbdkit::set_error> first. In particular, if you would like to +automatically fall back to C<pwrite> (perhaps because there is nothing +to optimize if C<$may_trim> is false), use +C<Nbdkit::set_error(POSIX::EOPNOTSUPP)>. + =back =head2 MISSING CALLBACKS diff --git a/plugins/perl/perl.c b/plugins/perl/perl.c index 9fb189c..52694d9 100644 --- a/plugins/perl/perl.c +++ b/plugins/perl/perl.c @@ -141,12 +141,15 @@ check_perl_failure (void) return 0; } +static int last_error; + XS(set_error) { dXSARGS; /* Is it worth adding error checking for bad arguments? */ if (items >= 1) - nbdkit_set_error (SvIV (ST (0))); + last_error = SvIV (ST (0)); + nbdkit_set_error (last_error); XSRETURN_EMPTY; } @@ -514,6 +517,45 @@ perl_can_trim (void *handle) } static int +perl_zero (void *handle, uint32_t count, uint64_t offset, int may_trim) +{ + dSP; + + if (callback_defined ("zero")) { + last_error = 0; + 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; + PUTBACK; + FREETMPS; + LEAVE; + + if (last_error == EOPNOTSUPP) { + /* When user requests this particular error, we want to + gracefully fall back, and to accomodate both a normal return + and an exception. */ + nbdkit_debug ("zero requested falling back to pwrite"); + return -1; + } + if (check_perl_failure () == -1) + return -1; + + return 0; + } + + nbdkit_debug ("zero falling back to pwrite"); + nbdkit_set_error (EOPNOTSUPP); + return -1; +} + +static int perl_is_rotational (void *handle) { dSP; @@ -644,6 +686,7 @@ static struct nbdkit_plugin plugin = { .pwrite = perl_pwrite, .flush = perl_flush, .trim = perl_trim, + .zero = perl_zero, .errno_is_reliable = perl_errno_is_reliable, }; -- 2.9.3 _______________________________________________ Libguestfs mailing list Libguestfs@redhat.com https://www.redhat.com/mailman/listinfo/libguestfs