aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nbd/server.c48
-rw-r--r--nbd/trace-events1
2 files changed, 45 insertions, 4 deletions
diff --git a/nbd/server.c b/nbd/server.c
index e84d0125bb..49ed57455c 100644
--- a/nbd/server.c
+++ b/nbd/server.c
@@ -365,6 +365,8 @@ static int nbd_negotiate_handle_info(NBDClient *client, uint32_t length,
uint16_t request;
uint32_t namelen;
bool sendname = false;
+ bool blocksize = false;
+ uint32_t sizes[3];
char buf[sizeof(uint64_t) + sizeof(uint16_t)];
const char *msg;
@@ -412,11 +414,16 @@ static int nbd_negotiate_handle_info(NBDClient *client, uint32_t length,
length -= sizeof(request);
trace_nbd_negotiate_handle_info_request(request,
nbd_info_lookup(request));
- /* For now, we only care about NBD_INFO_NAME; everything else
- * is either a request we don't know or something we send
- * regardless of request. */
- if (request == NBD_INFO_NAME) {
+ /* We care about NBD_INFO_NAME and NBD_INFO_BLOCK_SIZE;
+ * everything else is either a request we don't know or
+ * something we send regardless of request */
+ switch (request) {
+ case NBD_INFO_NAME:
sendname = true;
+ break;
+ case NBD_INFO_BLOCK_SIZE:
+ blocksize = true;
+ break;
}
}
@@ -448,6 +455,27 @@ static int nbd_negotiate_handle_info(NBDClient *client, uint32_t length,
}
}
+ /* Send NBD_INFO_BLOCK_SIZE always, but tweak the minimum size
+ * according to whether the client requested it, and according to
+ * whether this is OPT_INFO or OPT_GO. */
+ /* minimum - 1 for back-compat, or 512 if client is new enough.
+ * TODO: consult blk_bs(blk)->bl.request_alignment? */
+ sizes[0] = (opt == NBD_OPT_INFO || blocksize) ? BDRV_SECTOR_SIZE : 1;
+ /* preferred - Hard-code to 4096 for now.
+ * TODO: is blk_bs(blk)->bl.opt_transfer appropriate? */
+ sizes[1] = 4096;
+ /* maximum - At most 32M, but smaller as appropriate. */
+ sizes[2] = MIN(blk_get_max_transfer(exp->blk), NBD_MAX_BUFFER_SIZE);
+ trace_nbd_negotiate_handle_info_block_size(sizes[0], sizes[1], sizes[2]);
+ cpu_to_be32s(&sizes[0]);
+ cpu_to_be32s(&sizes[1]);
+ cpu_to_be32s(&sizes[2]);
+ rc = nbd_negotiate_send_info(client, opt, NBD_INFO_BLOCK_SIZE,
+ sizeof(sizes), sizes, errp);
+ if (rc < 0) {
+ return rc;
+ }
+
/* Send NBD_INFO_EXPORT always */
trace_nbd_negotiate_new_style_size_flags(exp->size,
exp->nbdflags | myflags);
@@ -459,6 +487,18 @@ static int nbd_negotiate_handle_info(NBDClient *client, uint32_t length,
return rc;
}
+ /* If the client is just asking for NBD_OPT_INFO, but forgot to
+ * request block sizes, return an error.
+ * TODO: consult blk_bs(blk)->request_align, and only error if it
+ * is not 1? */
+ if (opt == NBD_OPT_INFO && !blocksize) {
+ return nbd_negotiate_send_rep_err(client->ioc,
+ NBD_REP_ERR_BLOCK_SIZE_REQD, opt,
+ errp,
+ "request NBD_INFO_BLOCK_SIZE to "
+ "use this export");
+ }
+
/* Final reply */
rc = nbd_negotiate_send_rep(client->ioc, NBD_REP_ACK, opt, errp);
if (rc < 0) {
diff --git a/nbd/trace-events b/nbd/trace-events
index bd09fab375..be3dce773e 100644
--- a/nbd/trace-events
+++ b/nbd/trace-events
@@ -39,6 +39,7 @@ nbd_negotiate_handle_export_name_request(const char *name) "Client requested exp
nbd_negotiate_send_info(int info, const char *name, uint32_t length) "Sending NBD_REP_INFO type %d (%s) with remaining length %" PRIu32
nbd_negotiate_handle_info_requests(int requests) "Client requested %d items of info"
nbd_negotiate_handle_info_request(int request, const char *name) "Client requested info %d (%s)"
+nbd_negotiate_handle_info_block_size(uint32_t minimum, uint32_t preferred, uint32_t maximum) "advertising minimum 0x%" PRIx32 ", preferred 0x%" PRIx32 ", maximum 0x%" PRIx32
nbd_negotiate_handle_starttls(void) "Setting up TLS"
nbd_negotiate_handle_starttls_handshake(void) "Starting TLS handshake"
nbd_negotiate_options_flags(uint32_t flags) "Received client flags 0x%" PRIx32