When structured replies are negotiated, the server may advertise
support for the DF flag (the server promises to return at most one
data/hole chunk, or to fail with EOVERFLOW if the chunk would be too
large). As both nbdkit and qemu-nbd support this flag (the former only
trivially, but the latter by not compressing holes over the wire), it
is worth exposing to clients. While most clients will probably not be
using it, especially as long as we don't have an aio method for
getting at individual chunks, supporting the flag now at least helps
in testing server implementations.
---
generator/generator | 21 +++++++++++++++++++--
lib/flags.c | 11 +++++++++++
lib/rw.c | 8 +++++++-
3 files changed, 37 insertions(+), 3 deletions(-)
diff --git a/generator/generator b/generator/generator
index 919341c..3f300fd 100755
--- a/generator/generator
+++ b/generator/generator
@@ -1165,6 +1165,18 @@ the server does not. Can return an error if we have not
connected to and completed the handshake with the server.";
};
+ "can_df", {
+ default_call with
+ args = []; ret = RBool;
+ shortdesc = "does the server support the don't fragment flag to
pread?";
+ longdesc = "\
+Returns true if the server supports structured reads with an
+ability to request a non-fragmented read (see C<nbd_pread>,
+C<nbd_aio_pread>). Returns false if the server does not.
+Can return an error if we have not connected to and completed
+the handshake with the server.";
+ };
+
"can_multi_conn", {
default_call with
args = []; ret = RBool;
@@ -1230,8 +1242,12 @@ can only read all or nothing using this call. The call
returns when the data has been read fully into C<buf> or there is an
error.
-The C<flags> parameter must be C<0> for now (it exists for future NBD
-protocol extensions).";
+The C<flags> parameter may be C<0> for no flags, or may contain
+C<LIBNBD_CMD_FLAG_DF> meaning that the server should not fragment
+a read reply across more than one packet, even if using multiple
+packets would otherwise allow a more efficient representation of
+holes contained in the region (if that is supported - some servers
+cannot do this, see C<nbd_can_df>).";
};
"pwrite", {
@@ -1774,6 +1790,7 @@ let constants = [
"CMD_FLAG_FUA", 1 lsl 0;
"CMD_FLAG_NO_HOLE", 1 lsl 1;
+ "CMD_FLAG_DF", 1 lsl 2;
"CMD_FLAG_REQ_ONE", 1 lsl 3;
]
diff --git a/lib/flags.c b/lib/flags.c
index 421a7d2..cdbc28f 100644
--- a/lib/flags.c
+++ b/lib/flags.c
@@ -42,6 +42,11 @@ nbd_internal_set_size_and_flags (struct nbd_handle *h,
return -1;
}
+ if (eflags & NBD_FLAG_SEND_DF && !h->structured_replies) {
+ debug (h, "server lacks structured replies, ignoring claim of df");
+ eflags &= ~NBD_FLAG_SEND_DF;
+ }
+
h->exportsize = exportsize;
h->eflags = eflags;
return 0;
@@ -95,6 +100,12 @@ nbd_unlocked_can_zero (struct nbd_handle *h)
return get_flag (h, NBD_FLAG_SEND_WRITE_ZEROES);
}
+int
+nbd_unlocked_can_df (struct nbd_handle *h)
+{
+ return get_flag (h, NBD_FLAG_SEND_DF);
+}
+
int
nbd_unlocked_can_multi_conn (struct nbd_handle *h)
{
diff --git a/lib/rw.c b/lib/rw.c
index feaf468..343c340 100644
--- a/lib/rw.c
+++ b/lib/rw.c
@@ -234,11 +234,17 @@ int64_t
nbd_unlocked_aio_pread (struct nbd_handle *h, void *buf,
size_t count, uint64_t offset, uint32_t flags)
{
- if (flags != 0) {
+ if ((flags & ~LIBNBD_CMD_FLAG_DF) != 0) {
set_error (EINVAL, "invalid flag: %" PRIu32, flags);
return -1;
}
+ if ((flags & LIBNBD_CMD_FLAG_DF) != 0 &&
+ nbd_unlocked_can_df (h) != 1) {
+ set_error (EINVAL, "server does not support the DF flag");
+ return -1;
+ }
+
return nbd_internal_command_common (h, 0, NBD_CMD_READ, offset, count,
buf, NULL);
}
--
2.20.1