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

Nir Soffer nirsof at gmail.com
Sun Jan 24 12:55:50 UTC 2021


imageio flush feature is compatible with NBC_CMD_FLAG_FUA. With flush=y,
write or zero will issue NBD_CMD_FLUSH at the end, so the call returns
only after the data is flush to storage.

The plugin reports now that it supports FUA (based on can_flush), and
when FUA flag is set, we translate it to 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

Future version of imageio[1] may improve this by translating back to
single command:

    NBD_CMD_WRITE flags=NBD_CMD_FUA_FLAG

qemu-img is not using FUA during conversion, but a future version may
use this feature.

[1] https://bugzilla.redhat.com/1919548

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