[Libguestfs] [nbdkit PATCH 4/5] protocol: Implement NBD_CMD_WRITE_ZEROES

Eric Blake
2017-01-20T20:16:21Z

We always advertise this to the client (for writable exports), even
when the plugin does not have any optimized implementation, because
it allows for more efficient network traffic.

Signed-off-by: Eric Blake <eblake@redhat.com>
---
 src/connections.c | 26 ++++++++++++++++++++++++--
 src/protocol.h    | 17 ++++++++++-------
 2 files changed, 34 insertions(+), 9 deletions(-)

diff --git a/src/connections.c b/src/connections.c
index 44b7530..1b39547 100644
--- a/src/connections.c
+++ b/src/connections.c
@@ -180,6 +180,10 @@ _negotiate_handshake_oldstyle (struct connection *conn)
     eflags |= NBD_FLAG_READ_ONLY;
     conn->readonly = 1;
   }
+  if (!conn->readonly) {
+    eflags |= NBD_FLAG_SEND_WRITE_ZEROES;
+  }
+

   fl = plugin_can_flush (conn);
   if (fl == -1)
@@ -442,6 +446,9 @@ _negotiate_handshake_newstyle (struct connection *conn)
     eflags |= NBD_FLAG_READ_ONLY;
     conn->readonly = 1;
   }
+  if (!conn->readonly) {
+    eflags |= NBD_FLAG_SEND_WRITE_ZEROES;
+  }

   fl = plugin_can_flush (conn);
   if (fl == -1)
@@ -520,6 +527,7 @@ validate_request (struct connection *conn,
   case NBD_CMD_READ:
   case NBD_CMD_WRITE:
   case NBD_CMD_TRIM:
+  case NBD_CMD_WRITE_ZEROES:
     r = valid_range (conn, offset, count);
     if (r == -1)
       return -1;
@@ -547,11 +555,17 @@ validate_request (struct connection *conn,
   }

   /* Validate flags */
-  if (flags & ~NBD_CMD_FLAG_FUA) {
+  if (flags & ~(NBD_CMD_FLAG_FUA | NBD_CMD_FLAG_NO_HOLE)) {
     nbdkit_error ("invalid request: unknown flag (0x%x)", flags);
     *error = EINVAL;
     return 0;
   }
+  if ((flags & NBD_CMD_FLAG_NO_HOLE) &&
+      cmd != NBD_CMD_WRITE_ZEROES) {
+    nbdkit_error ("invalid request: NO_HOLE flag needs WRITE_ZEROES
request");
+    *error = EINVAL;
+    return 0;
+  }

   /* Refuse over-large read and write requests. */
   if ((cmd == NBD_CMD_WRITE || cmd == NBD_CMD_READ) &&
@@ -565,7 +579,7 @@ validate_request (struct connection *conn,
   /* Readonly connection? */
   if (conn->readonly &&
       (cmd == NBD_CMD_WRITE || cmd == NBD_CMD_FLUSH ||
-       cmd == NBD_CMD_TRIM)) {
+       cmd == NBD_CMD_TRIM || cmd == NBD_CMD_WRITE_ZEROES)) {
     nbdkit_error ("invalid request: write request on readonly
connection");
     *error = EROFS;
     return 0;
@@ -647,6 +661,14 @@ _handle_request (struct connection *conn,
     }
     break;

+  case NBD_CMD_WRITE_ZEROES:
+    r = plugin_zero (conn, count, offset, !(flags & NBD_CMD_FLAG_NO_HOLE));
+    if (r == -1) {
+      *error = errno ? errno : EIO;
+      return 0;
+    }
+    break;
+
   default:
     abort ();
   }
diff --git a/src/protocol.h b/src/protocol.h
index 23630a9..4571a3a 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -87,12 +87,13 @@ struct new_handshake_finish {
 #define NBD_FLAG_NO_ZEROES      2

 /* Per-export flags. */
-#define NBD_FLAG_HAS_FLAGS   1
-#define NBD_FLAG_READ_ONLY   2
-#define NBD_FLAG_SEND_FLUSH  4
-#define NBD_FLAG_SEND_FUA    8
-#define NBD_FLAG_ROTATIONAL 16
-#define NBD_FLAG_SEND_TRIM  32
+#define NBD_FLAG_HAS_FLAGS         (1 << 0)
+#define NBD_FLAG_READ_ONLY         (1 << 1)
+#define NBD_FLAG_SEND_FLUSH        (1 << 2)
+#define NBD_FLAG_SEND_FUA          (1 << 3)
+#define NBD_FLAG_ROTATIONAL        (1 << 4)
+#define NBD_FLAG_SEND_TRIM         (1 << 5)
+#define NBD_FLAG_SEND_WRITE_ZEROES (1 << 6)

 /* NBD options (new style handshake only). */
 #define NBD_OPT_EXPORT_NAME  1
@@ -130,8 +131,10 @@ struct reply {
 #define NBD_CMD_DISC              2 /* Disconnect. */
 #define NBD_CMD_FLUSH             3
 #define NBD_CMD_TRIM              4
+#define NBD_CMD_WRITE_ZEROES      6
 #define NBD_CMD_MASK_COMMAND 0xffff
-#define NBD_CMD_FLAG_FUA    (1<<16)
+#define NBD_CMD_FLAG_FUA     (1<<16)
+#define NBD_CMD_FLAG_NO_HOLE (2<<16)

 /* Error codes (previously errno).
  * See
http://git.qemu.org/?p=qemu.git;a=commitdiff;h=ca4414804114fd0095b317785bc0b51862e62ebb
--
2.9.3