[Libguestfs] [PATCH nbdkit 4/4] fua: Add unsafe fuamode=discard.

Richard W.M. Jones rjones at redhat.com
Fri May 22 21:32:34 UTC 2020


This drops all FUA and flush requests.
---
 filters/fua/nbdkit-fua-filter.pod | 27 +++++++++++++++++----
 filters/fua/fua.c                 | 39 +++++++++++++++++++++++++++----
 tests/test-fua.sh                 | 33 ++++++++++++++++----------
 3 files changed, 79 insertions(+), 20 deletions(-)

diff --git a/filters/fua/nbdkit-fua-filter.pod b/filters/fua/nbdkit-fua-filter.pod
index 3d20b56a..4f564fab 100644
--- a/filters/fua/nbdkit-fua-filter.pod
+++ b/filters/fua/nbdkit-fua-filter.pod
@@ -9,10 +9,12 @@ nbdkit-fua-filter - modify nbdkit flush and Forced Unit Access (FUA)
 =head1 DESCRIPTION
 
 C<nbdkit-fua-filter> is a filter that intentionally modifies handling
-of the S<“Forced Unit Access”> (FUA) flag across the NBD protocol.  It
-is mainly useful for testing client or server fallbacks, and for
-evaluating timing differences between proper use of FUA compared to a
-full flush.
+of the S<“Forced Unit Access”> (FUA) flag across the NBD protocol.
+
+This filter can be used to disable FUA and flush requests for speed
+(although this is unsafe).  Also it can be used to test client or
+server fallbacks, and for evaluating timing differences between proper
+use of FUA compared to a full flush.
 
 =head1 PARAMETERS
 
@@ -53,6 +55,15 @@ returns C<NBDKIT_FUA_NONE>.
 Pass through FUA and flush requests unchanged.  Turns the filter into
 a no-op.
 
+=item B<fuamode=discard>
+
+The filter will discard FUA and flush requests.
+
+B<This mode is unsafe>: If the NBD disk contains a filesystem then you
+will likely lose data in the event of a crash.  It should only be used
+for ephemeral data which you can easily recreate, such as caches,
+builds, test data, etc.
+
 =back
 
 =head1 EXAMPLES
@@ -86,6 +97,14 @@ always requested FUA:
 
  nbdkit --filter=fua file fuamode=force disk.img
 
+=item *
+
+Serve the file F<disk.img> discarding all FUA and flush requests.
+This can greatly improve performance, but you will likely lose data if
+there is a crash, so it is not safe.
+
+ nbdkit --filter=discard file fuamode=force disk.img
+
 =back
 
 =head1 FILES
diff --git a/filters/fua/fua.c b/filters/fua/fua.c
index 6bc62a02..229d83db 100644
--- a/filters/fua/fua.c
+++ b/filters/fua/fua.c
@@ -47,6 +47,7 @@ static enum FuaMode {
   NATIVE,
   FORCE,
   PASS,
+  DISCARD,
 } fuamode;
 
 static int
@@ -64,6 +65,8 @@ fua_config (nbdkit_next_config *next, void *nxdata,
       fuamode = FORCE;
     else if (strcmp (value, "pass") == 0)
       fuamode = PASS;
+    else if (strcmp (value, "discard") == 0)
+      fuamode = DISCARD;
     else {
       nbdkit_error ("unknown fuamode '%s'", value);
       return -1;
@@ -91,6 +94,7 @@ fua_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle,
   switch (fuamode) {
   case NONE:
   case PASS:
+  case DISCARD:
     break;
   case EMULATE:
     r = next_ops->can_flush (nxdata);
@@ -120,9 +124,17 @@ fua_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle,
 static int
 fua_can_flush (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle)
 {
-  if (fuamode == FORCE)
+  switch (fuamode) {
+  case FORCE:
+  case DISCARD:
     return 1; /* Advertise our no-op flush, even if plugin lacks it */
-  return next_ops->can_flush (nxdata);
+  case NONE:
+  case EMULATE:
+  case NATIVE:
+  case PASS:
+    return next_ops->can_flush (nxdata);
+  }
+  abort ();
 }
 
 /* Advertise desired fua mode. */
@@ -136,6 +148,7 @@ fua_can_fua (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle)
     return NBDKIT_FUA_EMULATE;
   case NATIVE:
   case FORCE:
+  case DISCARD:
     return NBDKIT_FUA_NATIVE;
   case PASS:
     return next_ops->can_fua (nxdata);
@@ -167,6 +180,9 @@ fua_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata,
   case FORCE:
     flags |= NBDKIT_FLAG_FUA;
     break;
+  case DISCARD:
+    flags &= ~NBDKIT_FLAG_FUA;
+    break;
   }
   r = next_ops->pwrite (nxdata, buf, count, offs, flags, err);
   if (r != -1 && need_flush)
@@ -178,9 +194,18 @@ static int
 fua_flush (struct nbdkit_next_ops *next_ops, void *nxdata,
            void *handle, uint32_t flags, int *err)
 {
-  if (fuamode == FORCE)
+  switch (fuamode) {
+  case FORCE:
     return 0; /* Nothing to flush, since all writes already used FUA */
-  return next_ops->flush (nxdata, flags, err);
+  case DISCARD:
+    return 0; /* Drop flushes! */
+  case NONE:
+  case EMULATE:
+  case NATIVE:
+  case PASS:
+    return next_ops->flush (nxdata, flags, err);
+  }
+  abort ();
 }
 
 static int
@@ -207,6 +232,9 @@ fua_trim (struct nbdkit_next_ops *next_ops, void *nxdata,
   case FORCE:
     flags |= NBDKIT_FLAG_FUA;
     break;
+  case DISCARD:
+    flags &= ~NBDKIT_FLAG_FUA;
+    break;
   }
   r = next_ops->trim (nxdata, count, offs, flags, err);
   if (r != -1 && need_flush)
@@ -238,6 +266,9 @@ fua_zero (struct nbdkit_next_ops *next_ops, void *nxdata,
   case FORCE:
     flags |= NBDKIT_FLAG_FUA;
     break;
+  case DISCARD:
+    flags &= ~NBDKIT_FLAG_FUA;
+    break;
   }
   r = next_ops->zero (nxdata, count, offs, flags, err);
   if (r != -1 && need_flush)
diff --git a/tests/test-fua.sh b/tests/test-fua.sh
index 5fb5e929..bf64e8da 100755
--- a/tests/test-fua.sh
+++ b/tests/test-fua.sh
@@ -40,7 +40,8 @@ files="fua.img
        fua2.log fua2.pid
        fua3.log fua3.pid
        fua4.log fua4.pid
-       fua5.log fua5.pid"
+       fua5.log fua5.pid
+       fua6.log fua6.pid"
 rm -f $files
 
 # Prep images, and check that qemu-io understands the actions we plan on
@@ -56,16 +57,10 @@ fi
 # on exit.
 cleanup ()
 {
-    echo "Log 1 file contents:"
-    cat fua1.log || :
-    echo "Log 2 file contents:"
-    cat fua2.log || :
-    echo "Log 3 file contents:"
-    cat fua3.log || :
-    echo "Log 4 file contents:"
-    cat fua4.log || :
-    echo "Log 5 file contents:"
-    cat fua5.log || :
+    for i in {1..6}; do
+        echo "Log $i file contents:"
+        cat fua$i.log || :
+    done
     rm -f $files
     rm -rf $sockdir
 }
@@ -77,6 +72,7 @@ cleanup_fn cleanup
 # 3: fuamode=native: log shows that blocksize preserves fua
 # 4: fuamode=force: log shows that fua is always enabled
 # 5: fuamode=pass: fua flag and flush unchanged
+# 6: fuamode=discard: discard all fua and flush
 start_nbdkit -P fua1.pid -U $sockdir/fua1.sock \
              --filter=log --filter=fua \
              file logfile=fua1.log fua.img
@@ -92,10 +88,13 @@ start_nbdkit -P fua4.pid -U $sockdir/fua4.sock \
 start_nbdkit -P fua5.pid -U $sockdir/fua5.sock \
              --filter=fua --filter=log \
              file logfile=fua5.log fua.img fuamode=pass
+start_nbdkit -P fua6.pid -U $sockdir/fua6.sock \
+             --filter=fua --filter=log \
+             file logfile=fua6.log fua.img fuamode=discard
 
 # Perform a flush, write, and zero, first without then with FUA
 for f in '' -f; do
-    for i in {1..5}; do
+    for i in {1..6}; do
 	qemu-io -f raw -t none -c flush -c "w $f 0 64k" -c "w -z $f 64k 64k" \
 		 "nbd+unix://?socket=$sockdir/fua$i.sock"
     done
@@ -139,3 +138,13 @@ grep 'connection=1 Write.*fua=0' fua5.log
 grep 'connection=2 Write.*fua=1' fua5.log
 grep 'connection=1 Zero.*fua=0' fua5.log
 grep 'connection=2 Zero.*fua=1' fua5.log
+
+# Test 6: Flush and fua=1 must not appear.
+if grep 'Flush' fua6.log; then
+    echo "filter should have elided flush"
+    exit 1
+fi
+if grep -E '(Write|Zero).*fua=1' fua6.log; then
+    echo "filter should have elided fua"
+    exit 1
+fi
-- 
2.25.0




More information about the Libguestfs mailing list