Add a python 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 exception), and the fallback error (return false so the binding can turn it into EOPNOTSUPP), so success requires returning true.
Signed-off-by: Eric Blake <ebl...@redhat.com> --- plugins/python/nbdkit-python-plugin.pod | 18 +++++++++++++++++ plugins/python/python.c | 35 +++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/plugins/python/nbdkit-python-plugin.pod b/plugins/python/nbdkit-python-plugin.pod index 9b0f0ef..b3eb883 100644 --- a/plugins/python/nbdkit-python-plugin.pod +++ b/plugins/python/nbdkit-python-plugin.pod @@ -196,6 +196,24 @@ L<fdatasync(2)> or equivalent on the backing store. The body of your C<trim> function should "punch a hole" in the backing store. +=item C<zero> + +(Optional) + + def zero(h, count, offset, may_trim): + # return a boolean + +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 throw an exception. + =back =head2 MISSING CALLBACKS diff --git a/plugins/python/python.c b/plugins/python/python.c index 0504715..46f50f2 100644 --- a/plugins/python/python.c +++ b/plugins/python/python.c @@ -423,6 +423,40 @@ py_trim (void *handle, uint32_t count, uint64_t offset) } static int +py_zero (void *handle, uint32_t count, uint64_t offset, int may_trim) +{ + PyObject *obj = handle; + PyObject *fn; + PyObject *args; + PyObject *r; + int ret; + + if (callback_defined ("zero", &fn)) { + PyErr_Clear (); + + args = PyTuple_New (4); + Py_INCREF (obj); /* decremented by Py_DECREF (args) */ + PyTuple_SetItem (args, 0, obj); + PyTuple_SetItem (args, 1, PyLong_FromUnsignedLongLong (count)); + PyTuple_SetItem (args, 2, PyLong_FromUnsignedLongLong (offset)); + PyTuple_SetItem (args, 3, PyBool_FromLong (may_trim)); + r = PyObject_CallObject (fn, args); + Py_DECREF (fn); + Py_DECREF (args); + if (check_python_failure ("zero") == -1) + return -1; + ret = r == Py_True; + Py_DECREF (r); + if (ret) + return 0; + } + + nbdkit_debug ("zero falling back to pwrite"); + errno = EOPNOTSUPP; + return -1; +} + +static int py_can_write (void *handle) { PyObject *obj = handle; @@ -579,6 +613,7 @@ static struct nbdkit_plugin plugin = { .pwrite = py_pwrite, .flush = py_flush, .trim = py_trim, + .zero = py_zero, }; NBDKIT_REGISTER_PLUGIN(plugin) -- 2.9.3 _______________________________________________ Libguestfs mailing list Libguestfs@redhat.com https://www.redhat.com/mailman/listinfo/libguestfs