imageio does not have a FUA flag, but we can emulate it using the flush
feature. With flush=y, write or zero will issue a NBD_CMD_FLUSH at the
end, so the call returns only after the data is flushed to storage.
The plugin reports now that it supports FUA (based on can_flush), and
when FUA flag is set, it emulates fua by setting flush query (PUT) or
flag (PATCH).
For example, this nbd command:
NBD_CMD_WRITE flags=NBD_CMD_FUA_FLAG
Is translated to this http request:
PUT /path?flush=y
On imageio server, this translates back to:
NBD_CMD_WRITE flags=0
NBD_CMD_FLUSH
Imageio server uses preallocated buffer per connection. If the write
request is bigger than the buffer, it sends multiple write commands. The
request returns only when the flush is completed.
Signed-off-by: Nir Soffer <nsoffer(a)redhat.com>
---
v2v/rhv-upload-plugin.py | 22 +++++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py
index 0f8101dd..1c6f0603 100644
--- a/v2v/rhv-upload-plugin.py
+++ b/v2v/rhv-upload-plugin.py
@@ -161,6 +161,12 @@ def can_flush(h):
return h['can_flush']
+@failing
+def can_fua(h):
+ # imageio flush feature is is compatible with NBD_CMD_FLAG_FUA.
+ return h['can_flush']
+
+
@failing
def get_size(h):
return params['disk_size']
@@ -231,7 +237,9 @@ def pwrite(h, buf, offset, flags):
count = len(buf)
- http.putrequest("PUT", h['path'] + "?flush=n")
+ flush = "y" if (h['can_flush'] and (flags & nbdkit.FLAG_FUA))
else "n"
+
+ http.putrequest("PUT", h['path'] + "?flush=" + flush)
# The oVirt server only uses the first part of the range, and the
# content-length.
http.putheader("Content-Range", "bytes %d-%d/*" % (offset, offset
+ count - 1))
@@ -260,14 +268,16 @@ def zero(h, count, offset, flags):
# so nbdkit could call this even if the server doesn't support
# zeroing. If this is the case we must emulate.
if not h['can_zero']:
- emulate_zero(h, count, offset)
+ emulate_zero(h, count, offset, flags)
return
+ flush = bool(h['can_flush'] and (flags & nbdkit.FLAG_FUA))
+
# Construct the JSON request for zeroing.
buf = json.dumps({'op': "zero",
'offset': offset,
'size': count,
- 'flush': False}).encode()
+ 'flush': flush}).encode()
headers = {"Content-Type": "application/json",
"Content-Length": str(len(buf))}
@@ -283,10 +293,12 @@ def zero(h, count, offset, flags):
r.read()
-def emulate_zero(h, count, offset):
+def emulate_zero(h, count, offset, flags):
http = h['http']
- http.putrequest("PUT", h['path'])
+ flush = "y" if (h['can_flush'] and (flags & nbdkit.FLAG_FUA))
else "n"
+
+ http.putrequest("PUT", h['path'] + "?flush=" + flush)
http.putheader("Content-Range",
"bytes %d-%d/*" % (offset, offset + count - 1))
http.putheader("Content-Length", str(count))
--
2.26.2