The NBD spec suggests that a server should never advertise a size inconsistent with its minimum block alignment, as that tail is effectively inaccessible to a compliant client obeying those block constraints. Although the block layer likes to round up, here, we'd prefer to truncate down to obey the spec, and note that it is the server's fault for advertising bogus size.
Does not impact either qemu (which always sends properly aligned sizes) or nbdkit (which does not send minimum block requirements yet); so this is mostly theoretical, to avoid potential asserts elsewhere in the code that assume the size is aligned. Signed-off-by: Eric Blake <ebl...@redhat.com> --- nbd/client.c | 8 +++++++- nbd/trace-events | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/nbd/client.c b/nbd/client.c index de7da48246b..be437051429 100644 --- a/nbd/client.c +++ b/nbd/client.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2018 Red Hat, Inc. + * Copyright (C) 2016-2019 Red Hat, Inc. * Copyright (C) 2005 Anthony Liguori <anth...@codemonkey.ws> * * Network Block Device Client Side @@ -426,6 +426,12 @@ static int nbd_opt_info_or_go(QIOChannel *ioc, uint32_t opt, nbd_send_opt_abort(ioc); return -1; } + if (info->min_block && + !QEMU_IS_ALIGNED(info->size, info->min_block)) { + trace_nbd_opt_info_go_unaligned_size(info->size, + info->min_block); + info->size = QEMU_ALIGN_DOWN(info->size, info->min_block); + } trace_nbd_receive_negotiate_size_flags(info->size, info->flags); break; diff --git a/nbd/trace-events b/nbd/trace-events index a6cca8fdf83..49dd48c9620 100644 --- a/nbd/trace-events +++ b/nbd/trace-events @@ -8,6 +8,7 @@ nbd_reply_err_unsup(uint32_t option, const char *name) "server doesn't understan nbd_receive_list(const char *name, const char *desc) "export list includes '%s', description '%s'" nbd_opt_info_go_start(const char *opt, const char *name) "Attempting %s for export '%s'" nbd_opt_info_go_success(const char *opt) "Export is ready after %s request" +nbd_opt_info_go_unaligned_size(uint64_t size, uint32_t align) "Server reported unaligned size 0x%" PRIx64 " for alignment 0x%x; truncating" nbd_opt_info_unknown(int info, const char *name) "Ignoring unknown info %d (%s)" nbd_opt_info_block_size(uint32_t minimum, uint32_t preferred, uint32_t maximum) "Block sizes are 0x%" PRIx32 ", 0x%" PRIx32 ", 0x%" PRIx32 nbd_receive_query_exports_start(const char *wantname) "Querying export list for '%s'" -- 2.20.1