[Libguestfs] [nbdkit PATCH 2/2] python: Support zero callback

Eric Blake eblake at redhat.com
Tue Jan 24 03:13:25 UTC 2017


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 <eblake at 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




More information about the Libguestfs mailing list