[Libguestfs] [PATCH v3 3/7] v2v: rhv-upload-plugin: Support FUA

Nir Soffer nirsof at gmail.com
Wed Feb 3 21:13:24 UTC 2021


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 at 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']
 
 
+ at 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




More information about the Libguestfs mailing list