The NBD spec is clarifying [1] that a server may want to advertise different limits for READ/WRITE (in our case, 32M) than for TRIM/ZERO (in our case, nearly 4G). Implement the server side support for these alternate limits, by always advertising the new information (a compliant client must ignore a gratuitous advertisement if it is unknown).
[1] https://lists.debian.org/nbd/2018/03/msg00048.html Signed-off-by: Eric Blake <ebl...@redhat.com> --- The given URL for the NBD spec was v3; it will change to be a v4 version of that patch in part to point back to this qemu commit as a proof of implementation. --- nbd/server.c | 30 ++++++++++++++++++++++++++++++ nbd/trace-events | 2 ++ 2 files changed, 32 insertions(+) diff --git a/nbd/server.c b/nbd/server.c index 9e1f2271784..39502b58446 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -617,6 +617,36 @@ static int nbd_negotiate_handle_info(NBDClient *client, uint16_t myflags, return rc; } + /* Send NBD_INFO_TRIM_SIZE always. */ + /* minimum - Hard-code to 4096 for now, matching preferred block. + * TODO: consult blk_bs(blk)->bl.pdiscard_alignment? */ + sizes[0] = 4096; + /* maximum - < 2G (then block layer fragments to bl.max_pdiscard). */ + sizes[1] = QEMU_ALIGN_DOWN(BDRV_REQUEST_MAX_BYTES, sizes[0]); + trace_nbd_negotiate_handle_info_trim_size(sizes[0], sizes[1]); + cpu_to_be32s(&sizes[0]); + cpu_to_be32s(&sizes[1]); + rc = nbd_negotiate_send_info(client, NBD_INFO_TRIM_SIZE, + 2 * sizeof(sizes[0]), sizes, errp); + if (rc < 0) { + return rc; + } + + /* Send NBD_INFO_ZERO_SIZE always. */ + /* minimum - Hard-code to 4096 for now, matching preferred block. + * TODO: consult blk_bs(blk)->bl.pwrite_zeroes_alignment? */ + sizes[0] = 4096; + /* maximum - < 2G (then block layer fragments to bl.max_pwrite_zeroes). */ + sizes[1] = QEMU_ALIGN_DOWN(BDRV_REQUEST_MAX_BYTES, sizes[0]); + trace_nbd_negotiate_handle_info_zero_size(sizes[0], sizes[1]); + cpu_to_be32s(&sizes[0]); + cpu_to_be32s(&sizes[1]); + rc = nbd_negotiate_send_info(client, NBD_INFO_ZERO_SIZE, + 2 * sizeof(sizes[0]), sizes, errp); + if (rc < 0) { + return rc; + } + /* Send NBD_INFO_EXPORT always */ trace_nbd_negotiate_new_style_size_flags(exp->size, exp->nbdflags | myflags); diff --git a/nbd/trace-events b/nbd/trace-events index ddb9d0a2b3e..d8849c43b21 100644 --- a/nbd/trace-events +++ b/nbd/trace-events @@ -46,6 +46,8 @@ nbd_negotiate_send_info(int info, const char *name, uint32_t length) "Sending NB 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_info_trim_size(uint32_t minimum, uint32_t maximum) "advertising minimum 0x%" PRIx32 ", maximum 0x%" PRIx32 +nbd_negotiate_handle_info_zero_size(uint32_t minimum, uint32_t maximum) "advertising minimum 0x%" PRIx32 ", maximum 0x%" PRIx32 nbd_negotiate_handle_starttls(void) "Setting up TLS" nbd_negotiate_handle_starttls_handshake(void) "Starting TLS handshake" nbd_negotiate_meta_context(const char *optname, const char *export, uint32_t queries) "Client requested %s for export %s, with %" PRIu32 " queries" -- 2.14.3