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(a)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=ca4414804114fd0095b317785b...
--
2.9.3