The NBD protocol is adding an extension to let servers advertise
initialization state to the client: whether the image contains holes,
and whether it is known to read as all zeroes. For python, the
hardest part was figuring out how to conditionally test things
depending on new-enough libnbd (and that wasn't hard).
Note that the python bindings do not yet support extents, so this is
one case where the new protocol addition is definitely useful when
dealing with an initially-empty destination.
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
plugins/python/nbdkit-python-plugin.pod | 14 ++++++++++++++
plugins/python/python.c | 16 +++++++++++++++-
tests/test-python-plugin.py | 8 +++++++-
tests/test_python.py | 22 +++++++++++++++++++++-
4 files changed, 57 insertions(+), 3 deletions(-)
diff --git a/plugins/python/nbdkit-python-plugin.pod
b/plugins/python/nbdkit-python-plugin.pod
index 4065ec7..c2d1257 100644
--- a/plugins/python/nbdkit-python-plugin.pod
+++ b/plugins/python/nbdkit-python-plugin.pod
@@ -245,6 +245,20 @@ contents will be garbage collected.
# return nbdkit.CACHE_NONE or nbdkit.CACHE_EMULATE
# or nbdkit.CACHE_NATIVE
+=item C<init_sparse>
+
+(Optional)
+
+ def init_sparse(h):
+ # return a boolean
+
+=item C<init_zero>
+
+(Optional)
+
+ def init_zero(h):
+ # return a boolean
+
=item C<pread>
(Required)
diff --git a/plugins/python/python.c b/plugins/python/python.c
index 5e2e526..5a4a702 100644
--- a/plugins/python/python.c
+++ b/plugins/python/python.c
@@ -1,5 +1,5 @@
/* nbdkit
- * Copyright (C) 2013-2018 Red Hat Inc.
+ * Copyright (C) 2013-2020 Red Hat Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -871,6 +871,18 @@ py_can_cache (void *handle)
return NBDKIT_CACHE_NONE;
}
+static int
+py_init_sparse (void *handle)
+{
+ return boolean_callback (handle, "init_sparse", NULL);
+}
+
+static int
+py_init_zero (void *handle)
+{
+ return boolean_callback (handle, "init_zero", NULL);
+}
+
#define py_config_help \
"script=<FILENAME> (required) The Python plugin to run.\n" \
"[other arguments may be used by the plugin that you load]"
@@ -902,6 +914,8 @@ static struct nbdkit_plugin plugin = {
.can_fast_zero = py_can_fast_zero,
.can_fua = py_can_fua,
.can_cache = py_can_cache,
+ .init_sparse = py_init_sparse,
+ .init_zero = py_init_zero,
.pread = py_pread,
.pwrite = py_pwrite,
diff --git a/tests/test-python-plugin.py b/tests/test-python-plugin.py
index 8e90bc2..0f3faaf 100644
--- a/tests/test-python-plugin.py
+++ b/tests/test-python-plugin.py
@@ -1,5 +1,5 @@
# nbdkit test plugin
-# Copyright (C) 2019 Red Hat Inc.
+# Copyright (C) 2019-2020 Red Hat Inc.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
@@ -95,6 +95,12 @@ def can_cache (h):
elif cache == "native":
return nbdkit.CACHE_NATIVE
+def init_sparse (h):
+ return cfg.get ('init_sparse', False)
+
+def init_zero (h):
+ return cfg.get ('init_zero', False)
+
def pread (h, buf, offset, flags):
assert flags == 0
end = offset + len(buf)
diff --git a/tests/test_python.py b/tests/test_python.py
index 6b9f297..e19b895 100755
--- a/tests/test_python.py
+++ b/tests/test_python.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# nbdkit
-# Copyright (C) 2019 Red Hat Inc.
+# Copyright (C) 2019-2020 Red Hat Inc.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
@@ -155,6 +155,26 @@ class Test (unittest.TestCase):
# Not yet implemented: can_extents.
+ def test_init_sparse_false (self):
+ self.connect ({"size": 512, "init_sparse": False})
+ if hasattr (self.h, "get_init_flags"):
+ assert not self.h.get_init_flags () & nbd.INIT_SPARSE
+
+ def test_init_sparse_true (self):
+ self.connect ({"size": 512, "init_sparse": True})
+ if hasattr (self.h, "get_init_flags"):
+ assert self.h.get_init_flags () & nbd.INIT_SPARSE
+
+ def test_init_zero_false (self):
+ self.connect ({"size": 512, "init_zero": False})
+ if hasattr (self.h, "get_init_flags"):
+ assert not self.h.get_init_flags () & nbd.INIT_ZERO
+
+ def test_init_zero_true (self):
+ self.connect ({"size": 512, "init_zero": True})
+ if hasattr (self.h, "get_init_flags"):
+ assert self.h.get_init_flags () & nbd.INIT_ZERO
+
def test_pread (self):
"""Test pread."""
self.connect ({"size": 512})
--
2.24.1