From nobody Fri May 10 15:25:06 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1668468859; cv=none; d=zohomail.com; s=zohoarc; b=NiJX0uFX/3NeR3DTe2loRRsu89r+V1+/JwJYLm/Iqaa5XDE6PIt9FGYZA3aSXj0GtimkC+m3ylR6NDXj/PW8ki06bC+54ECGw+VzHH07Q7ahfnnBKBtsQw8k1zYEQAhXsOmNowhwMR8uYzOwjt2hT8NTXSxV+x/W9xptNwV+pus= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1668468859; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=kzTEBYqs7XYX4CjhiYRYgBnv2AzlV5X742T2Py1Whn8=; b=KxHZ9i/dJqfD6HTMKIpnwJ5E+FlTBv1Mu3C/J6pATN7d5ME9T0DX0vi8MHiumVN5jA16YUffigPwLtGPCVKj0h8gDxr6RqlXONPjseCVGotLSde16n45qfSxwWpMu0QnvOmkmSsYcEkhA/2KgOFQq14w3Lqh8tku+kMVFwUs2i4= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1668468859169714.109185918895; Mon, 14 Nov 2022 15:34:19 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ouie4-0002Lh-Tq; Mon, 14 Nov 2022 18:13:40 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouids-0001eb-SA for qemu-devel@nongnu.org; Mon, 14 Nov 2022 18:13:28 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouiGC-0002Lv-BW for qemu-devel@nongnu.org; Mon, 14 Nov 2022 17:49:02 -0500 Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-584-2mtY7N2BO5aHhvGgVXZN8g-1; Mon, 14 Nov 2022 17:48:55 -0500 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 2B2BC85A59D; Mon, 14 Nov 2022 22:48:55 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.240]) by smtp.corp.redhat.com (Postfix) with ESMTP id 8B91940B48EA; Mon, 14 Nov 2022 22:48:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1668466139; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=kzTEBYqs7XYX4CjhiYRYgBnv2AzlV5X742T2Py1Whn8=; b=DiLJIHkJ17SkiiDpKQAyedNJApetQB/rkfXCxxT1/jFEKv41vmQXMcEiCCoPRmkX4wBYPo kiueSPyT1PBjUlzbEkromRc579zuvzIFfIUvUWrQsuLYNWtSZ1TPgJmyfQJy3W8PHeIF6F 34e8f6n3yfIr+/qLH0wVAlqXJxvNdRs= X-MC-Unique: 2mtY7N2BO5aHhvGgVXZN8g-1 From: Eric Blake To: qemu-devel@nongnu.org Cc: qemu-block@nongnu.org, libguestfs@redhat.com, nbd@other.debian.org, Vladimir Sementsov-Ogievskiy Subject: [PATCH v2 01/15] nbd/client: Add safety check on chunk payload length Date: Mon, 14 Nov 2022 16:48:34 -0600 Message-Id: <20221114224848.2186298-2-eblake@redhat.com> In-Reply-To: <20221114224848.2186298-1-eblake@redhat.com> References: <20221114224141.cm5jgyxfmvie5xb5@redhat.com> <20221114224848.2186298-1-eblake@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.2 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1668468859730100001 Content-Type: text/plain; charset="utf-8" Our existing use of structured replies either reads into a qiov capped at 32M (NBD_CMD_READ) or caps allocation to 1000 bytes (see NBD_MAX_MALLOC_PAYLOAD in block/nbd.c). But the existing length checks are rather late; if we encounter a buggy (or malicious) server that sends a super-large payload length, we should drop the connection right then rather than assuming the layer on top will be careful. This becomes more important when we permit 64-bit lengths which are even more likely to have the potential for attempted denial of service abuse. Signed-off-by: Eric Blake --- nbd/client.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/nbd/client.c b/nbd/client.c index 90a6b7b38b..cd97a2aa09 100644 --- a/nbd/client.c +++ b/nbd/client.c @@ -1412,6 +1412,18 @@ static int nbd_receive_structured_reply_chunk(QIOCha= nnel *ioc, chunk->handle =3D be64_to_cpu(chunk->handle); chunk->length =3D be32_to_cpu(chunk->length); + /* + * Because we use BLOCK_STATUS with REQ_ONE, and cap READ requests + * at 32M, no valid server should send us payload larger than + * this. Even if we stopped using REQ_ONE, sane servers will cap + * the number of extents they return for block status. + */ + if (chunk->length > NBD_MAX_BUFFER_SIZE + sizeof(NBDStructuredReadData= )) { + error_setg(errp, "server chunk %" PRIu32 " (%s) payload is too lon= g", + chunk->type, nbd_rep_lookup(chunk->type)); + return -EINVAL; + } + return 0; } --=20 2.38.1 From nobody Fri May 10 15:25:06 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1668469719; cv=none; d=zohomail.com; s=zohoarc; b=Mk7ZPWtfBKOF+0noxSDaMJEspYUb03Odze3pfAMDQs5ua6xz7LIfxxlDX5JD3nmzNBlJ6ruW9piTfJ4oJhp3kRbXs7vuCAVt+XsFmVCQ8rSuzgrvOgah8D4lFO7YolkxajBgOmrQP0YkIk7X3OtIj/xGHFykRBhe0OOxmHKHMpM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1668469719; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=IBlEmOz7AFEudruUrIHf052qJG5C7bw6++wHGQX2BBo=; b=GOJeOeMnIfaFasiagYNUkb88gm3Ffdq9ySM3VnXmZOV9v4bS0DNqRUSV0evZvYIBMAp0mJAGFodUcSz2/JwbpufneLKnevnu7OC5yAz1H1PVuiOhsC2VGScWgc7+Mfq8DKklAyta362ok0Xe4gQ7SPZLXGue2e9UIzI7qhN7Qas= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1668469719341687.5214647794595; Mon, 14 Nov 2022 15:48:39 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ouieH-000329-2X; Mon, 14 Nov 2022 18:13:54 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouids-0001df-Tg for qemu-devel@nongnu.org; Mon, 14 Nov 2022 18:13:28 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouiGC-0002Lx-BN for qemu-devel@nongnu.org; Mon, 14 Nov 2022 17:49:02 -0500 Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-626-Oy4igORSOAGbXY6IhiX6Dw-1; Mon, 14 Nov 2022 17:48:56 -0500 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 111221C07821; Mon, 14 Nov 2022 22:48:56 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.240]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5E31C40B48EA; Mon, 14 Nov 2022 22:48:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1668466139; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=IBlEmOz7AFEudruUrIHf052qJG5C7bw6++wHGQX2BBo=; b=Bcjd0PkkO3TjpFtFM1MWGPupwhaCpoh2nlKSjUQG+OVLjh7cUpsyeNA13O96QV5uMnYY2A JI7Hm3ssMfh6KXnIUFWZVK2Th1koW53OXhb8SQg9IOqvSxoNkvFsun10VVa/rScgnrRDTl /+IPWqJ0crAdxiKerp15g9mSYaHUWR0= X-MC-Unique: Oy4igORSOAGbXY6IhiX6Dw-1 From: Eric Blake To: qemu-devel@nongnu.org Cc: qemu-block@nongnu.org, libguestfs@redhat.com, nbd@other.debian.org, Vladimir Sementsov-Ogievskiy , Kevin Wolf , Hanna Reitz Subject: [PATCH v2 02/15] nbd/server: Prepare for alternate-size headers Date: Mon, 14 Nov 2022 16:48:35 -0600 Message-Id: <20221114224848.2186298-3-eblake@redhat.com> In-Reply-To: <20221114224848.2186298-1-eblake@redhat.com> References: <20221114224141.cm5jgyxfmvie5xb5@redhat.com> <20221114224848.2186298-1-eblake@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.2 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1668469720825100003 Content-Type: text/plain; charset="utf-8" An upcoming NBD extension wants to add the ability to do 64-bit effect lengths in requests. As part of that extension, the size of the reply headers will change in order to permit a 64-bit length in the reply for symmetry [*]. Additionally, where the reply header is currently 16 bytes for simple reply, and 20 bytes for structured reply; with the extension enabled, there will only be one structured reply type, of 32 bytes. Since we are already wired up to use iovecs, it is easiest to allow for this change in header size by splitting each structured reply across two iovecs, one for the header (which will become variable-length in a future patch according to client negotiation), and the other for the payload, and removing the header from the payload struct definitions. Interestingly, the client side code never utilized the packed types, so only the server code needs to be updated. [*] Note that on the surface, this is because some future server might permit a 4G+ NBD_CMD_READ and need to reply with that much data in one transaction. But even though the extended reply length is widened to 64 bits, at present we will still never send a reply payload larger than just over 32M (the maximum buffer we allow in NBD_CMD_READ; and we cap the number of extents we are willing to report in NBD_CMD_BLOCK_STATUS); for a future server to truly support a 4G read in one transaction, NBD_OPT_GO would need an extension of a new NBD_INFO_ field that provides for a 64-bit maximum transaction length. Where 64-bit fields really matter in the extension is in a later patch adding 64-bit support into a counterpart for REPLY_TYPE_BLOCK_STATUS. Signed-off-by: Eric Blake --- include/block/nbd.h | 8 +++--- nbd/server.c | 64 ++++++++++++++++++++++++++++----------------- 2 files changed, 44 insertions(+), 28 deletions(-) diff --git a/include/block/nbd.h b/include/block/nbd.h index 4ede3b2bd0..1330dbc18b 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -95,28 +95,28 @@ typedef union NBDReply { /* Header of chunk for NBD_REPLY_TYPE_OFFSET_DATA */ typedef struct NBDStructuredReadData { - NBDStructuredReplyChunk h; /* h.length >=3D 9 */ + /* header's .length >=3D 9 */ uint64_t offset; /* At least one byte of data payload follows, calculated from h.length= */ } QEMU_PACKED NBDStructuredReadData; /* Complete chunk for NBD_REPLY_TYPE_OFFSET_HOLE */ typedef struct NBDStructuredReadHole { - NBDStructuredReplyChunk h; /* h.length =3D=3D 12 */ + /* header's length =3D=3D 12 */ uint64_t offset; uint32_t length; } QEMU_PACKED NBDStructuredReadHole; /* Header of all NBD_REPLY_TYPE_ERROR* errors */ typedef struct NBDStructuredError { - NBDStructuredReplyChunk h; /* h.length >=3D 6 */ + /* header's length >=3D 6 */ uint32_t error; uint16_t message_length; } QEMU_PACKED NBDStructuredError; /* Header of NBD_REPLY_TYPE_BLOCK_STATUS */ typedef struct NBDStructuredMeta { - NBDStructuredReplyChunk h; /* h.length >=3D 12 (at least one extent) */ + /* header's length >=3D 12 (at least one extent) */ uint32_t context_id; /* extents follows */ } QEMU_PACKED NBDStructuredMeta; diff --git a/nbd/server.c b/nbd/server.c index ada16089f3..37f9c21d20 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -1888,9 +1888,12 @@ static int coroutine_fn nbd_co_send_iov(NBDClient *c= lient, struct iovec *iov, return ret; } -static inline void set_be_simple_reply(NBDSimpleReply *reply, uint64_t err= or, - uint64_t handle) +static inline void set_be_simple_reply(NBDClient *client, struct iovec *io= v, + uint64_t error, uint64_t handle) { + NBDSimpleReply *reply =3D iov->iov_base; + + iov->iov_len =3D sizeof(*reply); stl_be_p(&reply->magic, NBD_SIMPLE_REPLY_MAGIC); stl_be_p(&reply->error, error); stq_be_p(&reply->handle, handle); @@ -1903,23 +1906,27 @@ static int nbd_co_send_simple_reply(NBDClient *clie= nt, size_t len, Error **errp) { - NBDSimpleReply reply; + NBDReply hdr; int nbd_err =3D system_errno_to_nbd_errno(error); struct iovec iov[] =3D { - {.iov_base =3D &reply, .iov_len =3D sizeof(reply)}, + {.iov_base =3D &hdr}, {.iov_base =3D data, .iov_len =3D len} }; trace_nbd_co_send_simple_reply(handle, nbd_err, nbd_err_lookup(nbd_err= ), len); - set_be_simple_reply(&reply, nbd_err, handle); + set_be_simple_reply(client, &iov[0], nbd_err, handle); return nbd_co_send_iov(client, iov, len ? 2 : 1, errp); } -static inline void set_be_chunk(NBDStructuredReplyChunk *chunk, uint16_t f= lags, - uint16_t type, uint64_t handle, uint32_t l= ength) +static inline void set_be_chunk(NBDClient *client, struct iovec *iov, + uint16_t flags, uint16_t type, + uint64_t handle, uint32_t length) { + NBDStructuredReplyChunk *chunk =3D iov->iov_base; + + iov->iov_len =3D sizeof(*chunk); stl_be_p(&chunk->magic, NBD_STRUCTURED_REPLY_MAGIC); stw_be_p(&chunk->flags, flags); stw_be_p(&chunk->type, type); @@ -1931,13 +1938,14 @@ static int coroutine_fn nbd_co_send_structured_done= (NBDClient *client, uint64_t handle, Error **errp) { - NBDStructuredReplyChunk chunk; + NBDReply hdr; struct iovec iov[] =3D { - {.iov_base =3D &chunk, .iov_len =3D sizeof(chunk)}, + {.iov_base =3D &hdr}, }; trace_nbd_co_send_structured_done(handle); - set_be_chunk(&chunk, NBD_REPLY_FLAG_DONE, NBD_REPLY_TYPE_NONE, handle,= 0); + set_be_chunk(client, &iov[0], NBD_REPLY_FLAG_DONE, + NBD_REPLY_TYPE_NONE, handle, 0); return nbd_co_send_iov(client, iov, 1, errp); } @@ -1950,20 +1958,21 @@ static int coroutine_fn nbd_co_send_structured_read= (NBDClient *client, bool final, Error **errp) { + NBDReply hdr; NBDStructuredReadData chunk; struct iovec iov[] =3D { + {.iov_base =3D &hdr}, {.iov_base =3D &chunk, .iov_len =3D sizeof(chunk)}, {.iov_base =3D data, .iov_len =3D size} }; assert(size); trace_nbd_co_send_structured_read(handle, offset, data, size); - set_be_chunk(&chunk.h, final ? NBD_REPLY_FLAG_DONE : 0, - NBD_REPLY_TYPE_OFFSET_DATA, handle, - sizeof(chunk) - sizeof(chunk.h) + size); + set_be_chunk(client, &iov[0], final ? NBD_REPLY_FLAG_DONE : 0, + NBD_REPLY_TYPE_OFFSET_DATA, handle, iov[1].iov_len + size= ); stq_be_p(&chunk.offset, offset); - return nbd_co_send_iov(client, iov, 2, errp); + return nbd_co_send_iov(client, iov, 3, errp); } static int coroutine_fn nbd_co_send_structured_error(NBDClient *client, @@ -1972,9 +1981,11 @@ static int coroutine_fn nbd_co_send_structured_error= (NBDClient *client, const char *msg, Error **errp) { + NBDReply hdr; NBDStructuredError chunk; int nbd_err =3D system_errno_to_nbd_errno(error); struct iovec iov[] =3D { + {.iov_base =3D &hdr}, {.iov_base =3D &chunk, .iov_len =3D sizeof(chunk)}, {.iov_base =3D (char *)msg, .iov_len =3D msg ? strlen(msg) : 0}, }; @@ -1982,12 +1993,12 @@ static int coroutine_fn nbd_co_send_structured_erro= r(NBDClient *client, assert(nbd_err); trace_nbd_co_send_structured_error(handle, nbd_err, nbd_err_lookup(nbd_err), msg ? msg = : ""); - set_be_chunk(&chunk.h, NBD_REPLY_FLAG_DONE, NBD_REPLY_TYPE_ERROR, hand= le, - sizeof(chunk) - sizeof(chunk.h) + iov[1].iov_len); + set_be_chunk(client, &iov[0], NBD_REPLY_FLAG_DONE, + NBD_REPLY_TYPE_ERROR, handle, iov[1].iov_len + iov[2].iov= _len); stl_be_p(&chunk.error, nbd_err); - stw_be_p(&chunk.message_length, iov[1].iov_len); + stw_be_p(&chunk.message_length, iov[2].iov_len); - return nbd_co_send_iov(client, iov, 1 + !!iov[1].iov_len, errp); + return nbd_co_send_iov(client, iov, 2 + !!iov[2].iov_len, errp); } /* Do a sparse read and send the structured reply to the client. @@ -2025,19 +2036,22 @@ static int coroutine_fn nbd_co_send_sparse_read(NBD= Client *client, assert(pnum && pnum <=3D size - progress); final =3D progress + pnum =3D=3D size; if (status & BDRV_BLOCK_ZERO) { + NBDReply hdr; NBDStructuredReadHole chunk; struct iovec iov[] =3D { + {.iov_base =3D &hdr}, {.iov_base =3D &chunk, .iov_len =3D sizeof(chunk)}, }; trace_nbd_co_send_structured_read_hole(handle, offset + progre= ss, pnum); - set_be_chunk(&chunk.h, final ? NBD_REPLY_FLAG_DONE : 0, + set_be_chunk(client, &iov[0], + final ? NBD_REPLY_FLAG_DONE : 0, NBD_REPLY_TYPE_OFFSET_HOLE, - handle, sizeof(chunk) - sizeof(chunk.h)); + handle, iov[1].iov_len); stq_be_p(&chunk.offset, offset + progress); stl_be_p(&chunk.length, pnum); - ret =3D nbd_co_send_iov(client, iov, 1, errp); + ret =3D nbd_co_send_iov(client, iov, 2, errp); } else { ret =3D blk_pread(exp->common.blk, offset + progress, pnum, data + progress, 0); @@ -2201,8 +2215,10 @@ static int nbd_co_send_extents(NBDClient *client, ui= nt64_t handle, NBDExtentArray *ea, bool last, uint32_t context_id, Error **err= p) { + NBDReply hdr; NBDStructuredMeta chunk; struct iovec iov[] =3D { + {.iov_base =3D &hdr}, {.iov_base =3D &chunk, .iov_len =3D sizeof(chunk)}, {.iov_base =3D ea->extents, .iov_len =3D ea->count * sizeof(ea->ex= tents[0])} }; @@ -2211,12 +2227,12 @@ static int nbd_co_send_extents(NBDClient *client, u= int64_t handle, trace_nbd_co_send_extents(handle, ea->count, context_id, ea->total_len= gth, last); - set_be_chunk(&chunk.h, last ? NBD_REPLY_FLAG_DONE : 0, + set_be_chunk(client, &iov[0], last ? NBD_REPLY_FLAG_DONE : 0, NBD_REPLY_TYPE_BLOCK_STATUS, - handle, sizeof(chunk) - sizeof(chunk.h) + iov[1].iov_len); + handle, iov[1].iov_len + iov[2].iov_len); stl_be_p(&chunk.context_id, context_id); - return nbd_co_send_iov(client, iov, 2, errp); + return nbd_co_send_iov(client, iov, 3, errp); } /* Get block status from the exported device and send it to the client */ --=20 2.38.1 From nobody Fri May 10 15:25:06 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1668474496; cv=none; d=zohomail.com; s=zohoarc; b=GuAM6CKHC5kkNJ8T5hu7Wi30qmMPmVyIwWDu+zJXCcUHQazn7lF9VQ8ocVNsy/eMWcrTUJuWLH4S3Q/RMoPTAZ+h6kSEJpwOqmTZ9EqWS12um9o+z1pb0e0cyUefRph+PWPwjmeAHuAJ+zjEIndJhrrZfK2RCgxTOEb8Q7kKPU8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1668474496; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=kkDp22VhCHgXHpX0EtGWuYke14eCm1zRuaUm6FdI8a8=; b=fNmcR7GQeuEAtIIlCSdas1/mxzOwnG7Caqm3WaqmBNXCmgwLBiZ5QY3etea4ddtlx+qLbNbSeDo8bN663LxW+fae2zyzO+UP7cFExFKyC59hfLmL7D1O6l868LVNXVDjaHM/P01ECekW1FFHwpSUuqi9Sfs/x8JoQQfttznFeGM= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1668474496104218.97516857824075; Mon, 14 Nov 2022 17:08:16 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ouie8-0002Xb-R2; Mon, 14 Nov 2022 18:13:45 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouids-0001m0-Qm for qemu-devel@nongnu.org; Mon, 14 Nov 2022 18:13:28 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouiGD-0002MO-L2 for qemu-devel@nongnu.org; Mon, 14 Nov 2022 17:49:04 -0500 Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-638-ZYsuB1DCPOe47XHjIe02Zw-1; Mon, 14 Nov 2022 17:48:57 -0500 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id F1F211C0782B; Mon, 14 Nov 2022 22:48:56 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.240]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4EF1740AE7EF; Mon, 14 Nov 2022 22:48:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1668466141; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=kkDp22VhCHgXHpX0EtGWuYke14eCm1zRuaUm6FdI8a8=; b=EHjezvU2ZcJyo1F2BEqJfklWevqhx8ZfIwgeF3XBj5YPu/IDRWkNjKlCgKKEDIfkgps7Rs f1HXrpA2cbBmNeFOausWXQVpz9hBX5dohTqB5jqNm2xWp8ryJYad3HM3FJAzl5ms0YMd2F ILyYUv6krLfZ/OuoM0x0AqubhOZ+rTY= X-MC-Unique: ZYsuB1DCPOe47XHjIe02Zw-1 From: Eric Blake To: qemu-devel@nongnu.org Cc: qemu-block@nongnu.org, libguestfs@redhat.com, nbd@other.debian.org, Vladimir Sementsov-Ogievskiy , Kevin Wolf , Hanna Reitz Subject: [PATCH v2 03/15] nbd: Prepare for 64-bit request effect lengths Date: Mon, 14 Nov 2022 16:48:36 -0600 Message-Id: <20221114224848.2186298-4-eblake@redhat.com> In-Reply-To: <20221114224848.2186298-1-eblake@redhat.com> References: <20221114224141.cm5jgyxfmvie5xb5@redhat.com> <20221114224848.2186298-1-eblake@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.2 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1668474498017100004 Content-Type: text/plain; charset="utf-8" Widen the length field of NBDRequest to 64-bits, although we can assert that all current uses are still under 32 bits. Move the request magic number to nbd.h, to live alongside the reply magic number. Add the necessary bools that will eventually track whether the client successfully negotiated extended headers with the server, allowing the nbd driver to pass larger requests along where possible; although in this patch they always remain false for no semantic change yet. Signed-off-by: Eric Blake --- include/block/nbd.h | 21 ++++++++++++--------- nbd/nbd-internal.h | 3 +-- block/nbd.c | 35 ++++++++++++++++++++++++----------- nbd/client.c | 9 ++++++--- nbd/server.c | 12 +++++++++--- nbd/trace-events | 8 ++++---- 6 files changed, 56 insertions(+), 32 deletions(-) diff --git a/include/block/nbd.h b/include/block/nbd.h index 1330dbc18b..e357452a57 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -52,17 +52,16 @@ typedef struct NBDOptionReplyMetaContext { /* Transmission phase structs * - * Note: these are _NOT_ the same as the network representation of an NBD - * request and reply! + * Note: NBDRequest is _NOT_ the same as the network representation of an = NBD + * request! */ -struct NBDRequest { +typedef struct NBDRequest { uint64_t handle; - uint64_t from; - uint32_t len; + uint64_t from; /* Offset touched by the command */ + uint64_t len; /* Effect length; 32 bit limit without extended header= s */ uint16_t flags; /* NBD_CMD_FLAG_* */ - uint16_t type; /* NBD_CMD_* */ -}; -typedef struct NBDRequest NBDRequest; + uint16_t type; /* NBD_CMD_* */ +} NBDRequest; typedef struct NBDSimpleReply { uint32_t magic; /* NBD_SIMPLE_REPLY_MAGIC */ @@ -235,6 +234,9 @@ enum { */ #define NBD_MAX_STRING_SIZE 4096 +/* Transmission request structure */ +#define NBD_REQUEST_MAGIC 0x25609513 + /* Two types of reply structures */ #define NBD_SIMPLE_REPLY_MAGIC 0x67446698 #define NBD_STRUCTURED_REPLY_MAGIC 0x668e33ef @@ -293,6 +295,7 @@ struct NBDExportInfo { /* In-out fields, set by client before nbd_receive_negotiate() and * updated by server results during nbd_receive_negotiate() */ bool structured_reply; + bool extended_headers; bool base_allocation; /* base:allocation context for NBD_CMD_BLOCK_STA= TUS */ /* Set by server results during nbd_receive_negotiate() and @@ -322,7 +325,7 @@ int nbd_receive_export_list(QIOChannel *ioc, QCryptoTLS= Creds *tlscreds, Error **errp); int nbd_init(int fd, QIOChannelSocket *sioc, NBDExportInfo *info, Error **errp); -int nbd_send_request(QIOChannel *ioc, NBDRequest *request); +int nbd_send_request(QIOChannel *ioc, NBDRequest *request, bool ext_hdr); int coroutine_fn nbd_receive_reply(BlockDriverState *bs, QIOChannel *ioc, NBDReply *reply, Error **errp); int nbd_client(int fd); diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h index 1b2141ab4b..0016793ff4 100644 --- a/nbd/nbd-internal.h +++ b/nbd/nbd-internal.h @@ -1,7 +1,7 @@ /* * NBD Internal Declarations * - * Copyright (C) 2016 Red Hat, Inc. + * Copyright (C) 2016-2021 Red Hat, Inc. * * This work is licensed under the terms of the GNU GPL, version 2 or late= r. * See the COPYING file in the top-level directory. @@ -45,7 +45,6 @@ #define NBD_OLDSTYLE_NEGOTIATE_SIZE (8 + 8 + 8 + 4 + 124) #define NBD_INIT_MAGIC 0x4e42444d41474943LL /* ASCII "NBDMAGI= C" */ -#define NBD_REQUEST_MAGIC 0x25609513 #define NBD_OPTS_MAGIC 0x49484156454F5054LL /* ASCII "IHAVEOP= T" */ #define NBD_CLIENT_MAGIC 0x0000420281861253LL #define NBD_REP_MAGIC 0x0003e889045565a9LL diff --git a/block/nbd.c b/block/nbd.c index 7d485c86d2..32681d2867 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -2,7 +2,7 @@ * QEMU Block driver for NBD * * Copyright (c) 2019 Virtuozzo International GmbH. - * Copyright (C) 2016 Red Hat, Inc. + * Copyright (C) 2016-2022 Red Hat, Inc. * Copyright (C) 2008 Bull S.A.S. * Author: Laurent Vivier * @@ -340,7 +340,7 @@ int coroutine_fn nbd_co_do_establish_connection(BlockDr= iverState *bs, */ NBDRequest request =3D { .type =3D NBD_CMD_DISC }; - nbd_send_request(s->ioc, &request); + nbd_send_request(s->ioc, &request, s->info.extended_headers); yank_unregister_function(BLOCKDEV_YANK_INSTANCE(s->bs->node_name), nbd_yank, bs); @@ -524,14 +524,14 @@ static int coroutine_fn nbd_co_send_request(BlockDriv= erState *bs, if (qiov) { qio_channel_set_cork(s->ioc, true); - rc =3D nbd_send_request(s->ioc, request); + rc =3D nbd_send_request(s->ioc, request, s->info.extended_headers); if (rc >=3D 0 && qio_channel_writev_all(s->ioc, qiov->iov, qiov->n= iov, NULL) < 0) { rc =3D -EIO; } qio_channel_set_cork(s->ioc, false); } else { - rc =3D nbd_send_request(s->ioc, request); + rc =3D nbd_send_request(s->ioc, request, s->info.extended_headers); } qemu_co_mutex_unlock(&s->send_mutex); @@ -1298,10 +1298,11 @@ static int coroutine_fn nbd_client_co_pwrite_zeroes= (BlockDriverState *bs, int64_ NBDRequest request =3D { .type =3D NBD_CMD_WRITE_ZEROES, .from =3D offset, - .len =3D bytes, /* .len is uint32_t actually */ + .len =3D bytes, }; - assert(bytes <=3D UINT32_MAX); /* rely on max_pwrite_zeroes */ + /* rely on max_pwrite_zeroes */ + assert(bytes <=3D UINT32_MAX || s->info.extended_headers); assert(!(s->info.flags & NBD_FLAG_READ_ONLY)); if (!(s->info.flags & NBD_FLAG_SEND_WRITE_ZEROES)) { @@ -1348,10 +1349,11 @@ static int coroutine_fn nbd_client_co_pdiscard(Bloc= kDriverState *bs, int64_t off NBDRequest request =3D { .type =3D NBD_CMD_TRIM, .from =3D offset, - .len =3D bytes, /* len is uint32_t */ + .len =3D bytes, }; - assert(bytes <=3D UINT32_MAX); /* rely on max_pdiscard */ + /* rely on max_pdiscard */ + assert(bytes <=3D UINT32_MAX || s->info.extended_headers); assert(!(s->info.flags & NBD_FLAG_READ_ONLY)); if (!(s->info.flags & NBD_FLAG_SEND_TRIM) || !bytes) { @@ -1373,8 +1375,7 @@ static int coroutine_fn nbd_client_co_block_status( NBDRequest request =3D { .type =3D NBD_CMD_BLOCK_STATUS, .from =3D offset, - .len =3D MIN(QEMU_ALIGN_DOWN(INT_MAX, bs->bl.request_alignment), - MIN(bytes, s->info.size - offset)), + .len =3D MIN(bytes, s->info.size - offset), .flags =3D NBD_CMD_FLAG_REQ_ONE, }; @@ -1384,6 +1385,10 @@ static int coroutine_fn nbd_client_co_block_status( *file =3D bs; return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID; } + if (!s->info.extended_headers) { + request.len =3D MIN(QEMU_ALIGN_DOWN(INT_MAX, bs->bl.request_alignm= ent), + request.len); + } /* * Work around the fact that the block layer doesn't do @@ -1462,7 +1467,7 @@ static void nbd_client_close(BlockDriverState *bs) NBDRequest request =3D { .type =3D NBD_CMD_DISC }; if (s->ioc) { - nbd_send_request(s->ioc, &request); + nbd_send_request(s->ioc, &request, s->info.extended_headers); } nbd_teardown_connection(bs); @@ -1953,6 +1958,14 @@ static void nbd_refresh_limits(BlockDriverState *bs,= Error **errp) bs->bl.max_pwrite_zeroes =3D max; bs->bl.max_transfer =3D max; + /* + * Assume that if the server supports extended headers, it also + * supports unlimited size zero and trim commands. + */ + if (s->info.extended_headers) { + bs->bl.max_pdiscard =3D bs->bl.max_pwrite_zeroes =3D 0; + } + if (s->info.opt_block && s->info.opt_block > bs->bl.opt_transfer) { bs->bl.opt_transfer =3D s->info.opt_block; diff --git a/nbd/client.c b/nbd/client.c index cd97a2aa09..2480a48ec6 100644 --- a/nbd/client.c +++ b/nbd/client.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2019 Red Hat, Inc. + * Copyright (C) 2016-2022 Red Hat, Inc. * Copyright (C) 2005 Anthony Liguori * * Network Block Device Client Side @@ -1033,6 +1033,7 @@ int nbd_receive_negotiate(AioContext *aio_context, QI= OChannel *ioc, info->structured_reply, &zeroes, errp); info->structured_reply =3D false; + info->extended_headers =3D false; info->base_allocation =3D false; if (tlscreds && *outioc) { ioc =3D *outioc; @@ -1221,7 +1222,7 @@ int nbd_receive_export_list(QIOChannel *ioc, QCryptoT= LSCreds *tlscreds, if (nbd_drop(ioc, 124, NULL) =3D=3D 0) { NBDRequest request =3D { .type =3D NBD_CMD_DISC }; - nbd_send_request(ioc, &request); + nbd_send_request(ioc, &request, false); } break; default: @@ -1345,10 +1346,12 @@ int nbd_disconnect(int fd) #endif /* __linux__ */ -int nbd_send_request(QIOChannel *ioc, NBDRequest *request) +int nbd_send_request(QIOChannel *ioc, NBDRequest *request, bool ext_hdr) { uint8_t buf[NBD_REQUEST_SIZE]; + assert(!ext_hdr); + assert(request->len <=3D UINT32_MAX); trace_nbd_send_request(request->from, request->len, request->handle, request->flags, request->type, nbd_cmd_lookup(request->type)); diff --git a/nbd/server.c b/nbd/server.c index 37f9c21d20..7738f5f899 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -142,6 +142,7 @@ struct NBDClient { uint32_t check_align; /* If non-zero, check for aligned client request= s */ bool structured_reply; + bool extended_headers; NBDExportMetaContexts export_meta; uint32_t opt; /* Current option being negotiated */ @@ -1436,7 +1437,7 @@ static int nbd_receive_request(NBDClient *client, NBD= Request *request, request->type =3D lduw_be_p(buf + 6); request->handle =3D ldq_be_p(buf + 8); request->from =3D ldq_be_p(buf + 16); - request->len =3D ldl_be_p(buf + 24); + request->len =3D ldl_be_p(buf + 24); /* widen 32 to 64 bits */ trace_nbd_receive_request(magic, request->flags, request->type, request->from, request->len); @@ -2343,7 +2344,7 @@ static int nbd_co_receive_request(NBDRequestData *req= , NBDRequest *request, request->type =3D=3D NBD_CMD_CACHE) { if (request->len > NBD_MAX_BUFFER_SIZE) { - error_setg(errp, "len (%" PRIu32" ) is larger than max len (%u= )", + error_setg(errp, "len (%" PRIu64" ) is larger than max len (%u= )", request->len, NBD_MAX_BUFFER_SIZE); return -EINVAL; } @@ -2359,6 +2360,7 @@ static int nbd_co_receive_request(NBDRequestData *req= , NBDRequest *request, } if (request->type =3D=3D NBD_CMD_WRITE) { + assert(request->len <=3D NBD_MAX_BUFFER_SIZE); if (nbd_read(client->ioc, req->data, request->len, "CMD_WRITE data= ", errp) < 0) { @@ -2380,7 +2382,7 @@ static int nbd_co_receive_request(NBDRequestData *req= , NBDRequest *request, } if (request->from > client->exp->size || request->len > client->exp->size - request->from) { - error_setg(errp, "operation past EOF; From: %" PRIu64 ", Len: %" P= RIu32 + error_setg(errp, "operation past EOF; From: %" PRIu64 ", Len: %" P= RIu64 ", Size: %" PRIu64, request->from, request->len, client->exp->size); return (request->type =3D=3D NBD_CMD_WRITE || @@ -2443,6 +2445,7 @@ static coroutine_fn int nbd_do_cmd_read(NBDClient *cl= ient, NBDRequest *request, NBDExport *exp =3D client->exp; assert(request->type =3D=3D NBD_CMD_READ); + assert(request->len <=3D NBD_MAX_BUFFER_SIZE); /* XXX: NBD Protocol only documents use of FUA with WRITE */ if (request->flags & NBD_CMD_FLAG_FUA) { @@ -2494,6 +2497,7 @@ static coroutine_fn int nbd_do_cmd_cache(NBDClient *c= lient, NBDRequest *request, NBDExport *exp =3D client->exp; assert(request->type =3D=3D NBD_CMD_CACHE); + assert(request->len <=3D NBD_MAX_BUFFER_SIZE); ret =3D blk_co_preadv(exp->common.blk, request->from, request->len, NULL, BDRV_REQ_COPY_ON_READ | BDRV_REQ_PREFETCH); @@ -2527,6 +2531,7 @@ static coroutine_fn int nbd_handle_request(NBDClient = *client, if (request->flags & NBD_CMD_FLAG_FUA) { flags |=3D BDRV_REQ_FUA; } + assert(request->len <=3D NBD_MAX_BUFFER_SIZE); ret =3D blk_pwrite(exp->common.blk, request->from, request->len, d= ata, flags); return nbd_send_generic_reply(client, request->handle, ret, @@ -2570,6 +2575,7 @@ static coroutine_fn int nbd_handle_request(NBDClient = *client, return nbd_send_generic_reply(client, request->handle, -EINVAL, "need non-zero length", errp); } + assert(request->len <=3D UINT32_MAX); if (client->export_meta.count) { bool dont_fragment =3D request->flags & NBD_CMD_FLAG_REQ_ONE; int contexts_remaining =3D client->export_meta.count; diff --git a/nbd/trace-events b/nbd/trace-events index b7032ca277..e2c1d68688 100644 --- a/nbd/trace-events +++ b/nbd/trace-events @@ -31,7 +31,7 @@ nbd_client_loop(void) "Doing NBD loop" nbd_client_loop_ret(int ret, const char *error) "NBD loop returned %d: %s" nbd_client_clear_queue(void) "Clearing NBD queue" nbd_client_clear_socket(void) "Clearing NBD socket" -nbd_send_request(uint64_t from, uint32_t len, uint64_t handle, uint16_t fl= ags, uint16_t type, const char *name) "Sending request to server: { .from = =3D %" PRIu64", .len =3D %" PRIu32 ", .handle =3D %" PRIu64 ", .flags =3D 0= x%" PRIx16 ", .type =3D %" PRIu16 " (%s) }" +nbd_send_request(uint64_t from, uint64_t len, uint64_t handle, uint16_t fl= ags, uint16_t type, const char *name) "Sending request to server: { .from = =3D %" PRIu64", .len =3D %" PRIu64 ", .handle =3D %" PRIu64 ", .flags =3D 0= x%" PRIx16 ", .type =3D %" PRIu16 " (%s) }" nbd_receive_simple_reply(int32_t error, const char *errname, uint64_t hand= le) "Got simple reply: { .error =3D %" PRId32 " (%s), handle =3D %" PRIu64"= }" nbd_receive_structured_reply_chunk(uint16_t flags, uint16_t type, const ch= ar *name, uint64_t handle, uint32_t length) "Got structured reply chunk: { = flags =3D 0x%" PRIx16 ", type =3D %d (%s), handle =3D %" PRIu64 ", length = =3D %" PRIu32 " }" @@ -60,7 +60,7 @@ nbd_negotiate_options_check_option(uint32_t option, const= char *name) "Checking nbd_negotiate_begin(void) "Beginning negotiation" nbd_negotiate_new_style_size_flags(uint64_t size, unsigned flags) "adverti= sing size %" PRIu64 " and flags 0x%x" nbd_negotiate_success(void) "Negotiation succeeded" -nbd_receive_request(uint32_t magic, uint16_t flags, uint16_t type, uint64_= t from, uint32_t len) "Got request: { magic =3D 0x%" PRIx32 ", .flags =3D 0= x%" PRIx16 ", .type =3D 0x%" PRIx16 ", from =3D %" PRIu64 ", len =3D %" PRI= u32 " }" +nbd_receive_request(uint32_t magic, uint16_t flags, uint16_t type, uint64_= t from, uint64_t len) "Got request: { magic =3D 0x%" PRIx32 ", .flags =3D 0= x%" PRIx16 ", .type =3D 0x%" PRIx16 ", from =3D %" PRIu64 ", len =3D %" PRI= u64 " }" nbd_blk_aio_attached(const char *name, void *ctx) "Export %s: Attaching cl= ients to AIO context %p" nbd_blk_aio_detach(const char *name, void *ctx) "Export %s: Detaching clie= nts from AIO context %p" nbd_co_send_simple_reply(uint64_t handle, uint32_t error, const char *errn= ame, int len) "Send simple reply: handle =3D %" PRIu64 ", error =3D %" PRIu= 32 " (%s), len =3D %d" @@ -70,8 +70,8 @@ nbd_co_send_structured_read_hole(uint64_t handle, uint64_= t offset, size_t size) nbd_co_send_extents(uint64_t handle, unsigned int extents, uint32_t id, ui= nt64_t length, int last) "Send block status reply: handle =3D %" PRIu64 ", = extents =3D %u, context =3D %d (extents cover %" PRIu64 " bytes, last chunk= =3D %d)" nbd_co_send_structured_error(uint64_t handle, int err, const char *errname= , const char *msg) "Send structured error reply: handle =3D %" PRIu64 ", er= ror =3D %d (%s), msg =3D '%s'" nbd_co_receive_request_decode_type(uint64_t handle, uint16_t type, const c= har *name) "Decoding type: handle =3D %" PRIu64 ", type =3D %" PRIu16 " (%s= )" -nbd_co_receive_request_payload_received(uint64_t handle, uint32_t len) "Pa= yload received: handle =3D %" PRIu64 ", len =3D %" PRIu32 -nbd_co_receive_align_compliance(const char *op, uint64_t from, uint32_t le= n, uint32_t align) "client sent non-compliant unaligned %s request: from=3D= 0x%" PRIx64 ", len=3D0x%" PRIx32 ", align=3D0x%" PRIx32 +nbd_co_receive_request_payload_received(uint64_t handle, uint64_t len) "Pa= yload received: handle =3D %" PRIu64 ", len =3D %" PRIu64 +nbd_co_receive_align_compliance(const char *op, uint64_t from, uint64_t le= n, uint32_t align) "client sent non-compliant unaligned %s request: from=3D= 0x%" PRIx64 ", len=3D0x%" PRIx64 ", align=3D0x%" PRIx32 nbd_trip(void) "Reading request" # client-connection.c --=20 2.38.1 From nobody Fri May 10 15:25:06 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1668475131; cv=none; d=zohomail.com; s=zohoarc; b=kaIJo1Tck5dAFQNp8laXkqwK2lKWe75VEWwRtiNeKRdc2hHqk9XRMBQxY2Q2oz9wvcuEeXJc7yH4RNImvXBIJZk7wcHEmXWFOh5GQD9hy7qvNsnL58XkZB4ruyAFplGvRCywPfmmlWeiB2H7ZorHUWfpjpfj1Uy0dUSIKTuFuqk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1668475131; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=7qUQF2DlBRbwRO1HcKnhprmAUuC1nB/mgXeuD1zXdH8=; b=Ac285f4YDxXJXeQwJuJJ+dMigKb8GbDj6Nawy9Z2kT3w43xarH3piCx9Z7gtEuR7l5juLYIGlyiR5PrGTev/0EuUiARFx1tHJUow1n03bYImcRAdyJHFKNHIVDHY8jrN6ZNTUnheH6XxOTQJQcHZx+0JYiBw75zSDRtJpyeLQE8= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1668475130925869.9687110255287; Mon, 14 Nov 2022 17:18:50 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ouie8-0002VW-7q; Mon, 14 Nov 2022 18:13:44 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouidr-0001o2-I5 for qemu-devel@nongnu.org; Mon, 14 Nov 2022 18:13:27 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouiGL-0002Pe-OO for qemu-devel@nongnu.org; Mon, 14 Nov 2022 17:49:11 -0500 Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-630-BvEPDguPN5Ouex-5iCRoOg-1; Mon, 14 Nov 2022 17:48:58 -0500 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id CA59729DD9BC; Mon, 14 Nov 2022 22:48:57 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.240]) by smtp.corp.redhat.com (Postfix) with ESMTP id 346FF40AE7EF; Mon, 14 Nov 2022 22:48:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1668466149; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=7qUQF2DlBRbwRO1HcKnhprmAUuC1nB/mgXeuD1zXdH8=; b=bhejqcNrWh6dTBxvRAgGW0aYIDaSVR3TuyoI5p69EIX/J9kKqXuocj8UfiinYm5/Ul/yxG SmG5pDRsngA/dq/o8cNWB7guER3p7swDA5tS1NMkjKJXmRZTQSaIqEM5tXVBzCALfHEgX5 dCFii+7+c2//vjyzsR+VMdvqwO2cXpI= X-MC-Unique: BvEPDguPN5Ouex-5iCRoOg-1 From: Eric Blake To: qemu-devel@nongnu.org Cc: qemu-block@nongnu.org, libguestfs@redhat.com, nbd@other.debian.org, Vladimir Sementsov-Ogievskiy , Kevin Wolf , Hanna Reitz Subject: [PATCH v2 04/15] nbd: Add types for extended headers Date: Mon, 14 Nov 2022 16:48:37 -0600 Message-Id: <20221114224848.2186298-5-eblake@redhat.com> In-Reply-To: <20221114224848.2186298-1-eblake@redhat.com> References: <20221114224141.cm5jgyxfmvie5xb5@redhat.com> <20221114224848.2186298-1-eblake@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.2 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1668475132269100001 Content-Type: text/plain; charset="utf-8" Add the constants and structs necessary for later patches to start implementing the NBD_OPT_EXTENDED_HEADERS extension in both the client and server, matching recent commit XXX[*] in the upstream nbd project. This patch does not change any existing behavior, but merely sets the stage. This patch does not change the status quo that neither the client nor server use a packed-struct representation for the request header. Signed-off-by: Eric Blake --- [*]tweak commit message once nbd commit id available --- docs/interop/nbd.txt | 1 + include/block/nbd.h | 74 ++++++++++++++++++++++++++++++++------------ nbd/common.c | 10 +++++- 3 files changed, 65 insertions(+), 20 deletions(-) diff --git a/docs/interop/nbd.txt b/docs/interop/nbd.txt index f5ca25174a..988c072697 100644 --- a/docs/interop/nbd.txt +++ b/docs/interop/nbd.txt @@ -69,3 +69,4 @@ NBD_CMD_BLOCK_STATUS for "qemu:dirty-bitmap:", NBD_CMD_CA= CHE NBD_CMD_FLAG_FAST_ZERO * 5.2: NBD_CMD_BLOCK_STATUS for "qemu:allocation-depth" * 7.1: NBD_FLAG_CAN_MULTI_CONN for shareable writable exports +* 7.2: NBD_OPT_EXTENDED_HEADERS diff --git a/include/block/nbd.h b/include/block/nbd.h index e357452a57..357121ce76 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -78,13 +78,24 @@ typedef struct NBDStructuredReplyChunk { uint32_t length; /* length of payload */ } QEMU_PACKED NBDStructuredReplyChunk; +typedef struct NBDExtendedReplyChunk { + uint32_t magic; /* NBD_EXTENDED_REPLY_MAGIC */ + uint16_t flags; /* combination of NBD_REPLY_FLAG_* */ + uint16_t type; /* NBD_REPLY_TYPE_* */ + uint64_t handle; /* request handle */ + uint64_t offset; /* request offset */ + uint64_t length; /* length of payload */ +} QEMU_PACKED NBDExtendedReplyChunk; + typedef union NBDReply { NBDSimpleReply simple; NBDStructuredReplyChunk structured; + NBDExtendedReplyChunk extended; struct { - /* @magic and @handle fields have the same offset and size both in - * simple reply and structured reply chunk, so let them be accessi= ble - * without ".simple." or ".structured." specification + /* + * @magic and @handle fields have the same offset and size in all + * forms of replies, so let them be accessible without ".simple.", + * ".structured.", or ".extended." specifications. */ uint32_t magic; uint32_t _skip; @@ -117,15 +128,29 @@ typedef struct NBDStructuredError { typedef struct NBDStructuredMeta { /* header's length >=3D 12 (at least one extent) */ uint32_t context_id; - /* extents follows */ + /* NBDExtent extents[] follows, array length implied by header */ } QEMU_PACKED NBDStructuredMeta; -/* Extent chunk for NBD_REPLY_TYPE_BLOCK_STATUS */ +/* Extent array for NBD_REPLY_TYPE_BLOCK_STATUS */ typedef struct NBDExtent { uint32_t length; uint32_t flags; /* NBD_STATE_* */ } QEMU_PACKED NBDExtent; +/* Header of NBD_REPLY_TYPE_BLOCK_STATUS_EXT */ +typedef struct NBDStructuredMetaExt { + /* header's length >=3D 24 (at least one extent) */ + uint32_t context_id; + uint32_t count; /* header length must be count * 16 + 8 */ + /* NBDExtentExt extents[count] follows */ +} QEMU_PACKED NBDStructuredMetaExt; + +/* Extent array for NBD_REPLY_TYPE_BLOCK_STATUS_EXT */ +typedef struct NBDExtentExt { + uint64_t length; + uint64_t flags; /* NBD_STATE_* */ +} QEMU_PACKED NBDExtentExt; + /* Transmission (export) flags: sent from server to client during handshak= e, but describe what will happen during transmission */ enum { @@ -178,6 +203,7 @@ enum { #define NBD_OPT_STRUCTURED_REPLY (8) #define NBD_OPT_LIST_META_CONTEXT (9) #define NBD_OPT_SET_META_CONTEXT (10) +#define NBD_OPT_EXTENDED_HEADERS (11) /* Option reply types. */ #define NBD_REP_ERR(value) ((UINT32_C(1) << 31) | (value)) @@ -195,6 +221,8 @@ enum { #define NBD_REP_ERR_UNKNOWN NBD_REP_ERR(6) /* Export unknown */ #define NBD_REP_ERR_SHUTDOWN NBD_REP_ERR(7) /* Server shutting dow= n */ #define NBD_REP_ERR_BLOCK_SIZE_REQD NBD_REP_ERR(8) /* Need INFO_BLOCK_SIZ= E */ +#define NBD_REP_ERR_TOO_BIG NBD_REP_ERR(9) /* Payload size overfl= ow */ +#define NBD_REP_ERR_EXT_HEADER_REQD NBD_REP_ERR(10) /* Need extended heade= rs */ /* Info types, used during NBD_REP_INFO */ #define NBD_INFO_EXPORT 0 @@ -203,12 +231,14 @@ enum { #define NBD_INFO_BLOCK_SIZE 3 /* Request flags, sent from client to server during transmission phase */ -#define NBD_CMD_FLAG_FUA (1 << 0) /* 'force unit access' during wri= te */ -#define NBD_CMD_FLAG_NO_HOLE (1 << 1) /* don't punch hole on zero run */ -#define NBD_CMD_FLAG_DF (1 << 2) /* don't fragment structured read= */ -#define NBD_CMD_FLAG_REQ_ONE (1 << 3) /* only one extent in BLOCK_STATUS - * reply chunk */ -#define NBD_CMD_FLAG_FAST_ZERO (1 << 4) /* fail if WRITE_ZEROES is not fa= st */ +#define NBD_CMD_FLAG_FUA (1 << 0) /* 'force unit access' during wr= ite */ +#define NBD_CMD_FLAG_NO_HOLE (1 << 1) /* don't punch hole on zero run = */ +#define NBD_CMD_FLAG_DF (1 << 2) /* don't fragment structured rea= d */ +#define NBD_CMD_FLAG_REQ_ONE (1 << 3) \ + /* only one extent in BLOCK_STATUS reply chunk */ +#define NBD_CMD_FLAG_FAST_ZERO (1 << 4) /* fail if WRITE_ZEROES is not f= ast */ +#define NBD_CMD_FLAG_PAYLOAD_LEN (1 << 5) \ + /* length describes payload, not effect; only with ext header */ /* Supported request types */ enum { @@ -234,12 +264,17 @@ enum { */ #define NBD_MAX_STRING_SIZE 4096 -/* Transmission request structure */ +/* Two types of request structures, a given client will only use 1 */ #define NBD_REQUEST_MAGIC 0x25609513 +#define NBD_EXTENDED_REQUEST_MAGIC 0x21e41c71 -/* Two types of reply structures */ +/* + * Three types of reply structures, but what a client expects depends + * on NBD_OPT_STRUCTURED_REPLY and NBD_OPT_EXTENDED_HEADERS. + */ #define NBD_SIMPLE_REPLY_MAGIC 0x67446698 #define NBD_STRUCTURED_REPLY_MAGIC 0x668e33ef +#define NBD_EXTENDED_REPLY_MAGIC 0x6e8a278c /* Structured reply flags */ #define NBD_REPLY_FLAG_DONE (1 << 0) /* This reply-chunk is last = */ @@ -247,12 +282,13 @@ enum { /* Structured reply types */ #define NBD_REPLY_ERR(value) ((1 << 15) | (value)) -#define NBD_REPLY_TYPE_NONE 0 -#define NBD_REPLY_TYPE_OFFSET_DATA 1 -#define NBD_REPLY_TYPE_OFFSET_HOLE 2 -#define NBD_REPLY_TYPE_BLOCK_STATUS 5 -#define NBD_REPLY_TYPE_ERROR NBD_REPLY_ERR(1) -#define NBD_REPLY_TYPE_ERROR_OFFSET NBD_REPLY_ERR(2) +#define NBD_REPLY_TYPE_NONE 0 +#define NBD_REPLY_TYPE_OFFSET_DATA 1 +#define NBD_REPLY_TYPE_OFFSET_HOLE 2 +#define NBD_REPLY_TYPE_BLOCK_STATUS 5 +#define NBD_REPLY_TYPE_BLOCK_STATUS_EXT 6 +#define NBD_REPLY_TYPE_ERROR NBD_REPLY_ERR(1) +#define NBD_REPLY_TYPE_ERROR_OFFSET NBD_REPLY_ERR(2) /* Extent flags for base:allocation in NBD_REPLY_TYPE_BLOCK_STATUS */ #define NBD_STATE_HOLE (1 << 0) diff --git a/nbd/common.c b/nbd/common.c index ddfe7d1183..137466defd 100644 --- a/nbd/common.c +++ b/nbd/common.c @@ -79,6 +79,8 @@ const char *nbd_opt_lookup(uint32_t opt) return "list meta context"; case NBD_OPT_SET_META_CONTEXT: return "set meta context"; + case NBD_OPT_EXTENDED_HEADERS: + return "extended headers"; default: return ""; } @@ -112,6 +114,10 @@ const char *nbd_rep_lookup(uint32_t rep) return "server shutting down"; case NBD_REP_ERR_BLOCK_SIZE_REQD: return "block size required"; + case NBD_REP_ERR_TOO_BIG: + return "option payload too big"; + case NBD_REP_ERR_EXT_HEADER_REQD: + return "extended headers required"; default: return ""; } @@ -170,7 +176,9 @@ const char *nbd_reply_type_lookup(uint16_t type) case NBD_REPLY_TYPE_OFFSET_HOLE: return "hole"; case NBD_REPLY_TYPE_BLOCK_STATUS: - return "block status"; + return "block status (32-bit)"; + case NBD_REPLY_TYPE_BLOCK_STATUS_EXT: + return "block status (64-bit)"; case NBD_REPLY_TYPE_ERROR: return "generic error"; case NBD_REPLY_TYPE_ERROR_OFFSET: --=20 2.38.1 From nobody Fri May 10 15:25:06 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1668470274; cv=none; d=zohomail.com; s=zohoarc; b=fBvMKWaLwN5gtNz985G4mOj4ile4FSB3l6hRK1rIyHBLlc1aTqssmE0qmues08UD1xJHPpoiKbC/Faj8yMGjYX+xL6tSUr71xjmZK5mLn5bleb8hKhhfqaI/kdOfEjXn5i3XTQo3RNBhyf9+UtISzltBXa3HmQ1axnq33KU1JsY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1668470274; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=1NrkZVHAocJOLpKWjaSIw4pPOaz/H1tbWxK3Giv3VKM=; b=W8JTCRFAwX0HD8RT3kmsD1MH531E9I5/wMr4b1BfzvAqhueVCILzcAlHF7AcA7T405DsxyMCbPvZagu7Lox3ukcdKQhRKbi9HeH4CbiYD11laiXilItCUWx8PMdAHNpoPsqAf+Vq34gMXAuEwl+vWrDRiA/ClT7bozGjbGxoJMo= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1668470273999858.2376215124171; Mon, 14 Nov 2022 15:57:53 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ouieR-0003cQ-Bq; Mon, 14 Nov 2022 18:14:03 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouids-0001o2-Dj for qemu-devel@nongnu.org; Mon, 14 Nov 2022 18:13:28 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouiGF-0002Mr-0b for qemu-devel@nongnu.org; Mon, 14 Nov 2022 17:49:04 -0500 Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-183-ngUCwPe3OpGx83CvUIPf1w-1; Mon, 14 Nov 2022 17:48:58 -0500 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 7FB3B101AA45; Mon, 14 Nov 2022 22:48:58 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.240]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0940D40AE7EF; Mon, 14 Nov 2022 22:48:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1668466142; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=1NrkZVHAocJOLpKWjaSIw4pPOaz/H1tbWxK3Giv3VKM=; b=C8/Lw3vyDOgpxP8QdJTkqgtzQsNxoMq3D6FBJ/5gvpNsCk9XKofZG7QSBgpeWp5w/F4nHN IexFLZwH0QnLm2A/jYg+9mSEiXuCyyTkfYHr6S7H6Ey+KRItZ+alh98ldo72sJx4eaIoFj 28RZcmXFxA+xVzkVXl7/tjqL7cT3fLI= X-MC-Unique: ngUCwPe3OpGx83CvUIPf1w-1 From: Eric Blake To: qemu-devel@nongnu.org Cc: qemu-block@nongnu.org, libguestfs@redhat.com, nbd@other.debian.org, Vladimir Sementsov-Ogievskiy Subject: [PATCH v2 05/15] nbd/server: Refactor handling of request payload Date: Mon, 14 Nov 2022 16:48:38 -0600 Message-Id: <20221114224848.2186298-6-eblake@redhat.com> In-Reply-To: <20221114224848.2186298-1-eblake@redhat.com> References: <20221114224141.cm5jgyxfmvie5xb5@redhat.com> <20221114224848.2186298-1-eblake@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.2 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1668470275766100001 Content-Type: text/plain; charset="utf-8" Upcoming additions to support NBD 64-bit effect lengths allow for the possibility to distinguish between payload length (capped at 32M) and effect length (up to 63 bits). Without that extension, only the NBD_CMD_WRITE request has a payload; but with the extension, it makes sense to allow at least NBD_CMD_BLOCK_STATUS to have both a payload and effect length (where the payload is a limited-size struct that in turns gives the real effect length as well as a subset of known ids for which status is requested). Other future NBD commands may also have a request payload, so the 64-bit extension introduces a new NBD_CMD_FLAG_PAYLOAD_LEN that distinguishes between whether the header length is a payload length or an effect length, rather than hard-coding the decision based on the command. Note that we do not support the payload version of BLOCK_STATUS yet. For this patch, no semantic change is intended for a compliant client. For a non-compliant client, it is possible that the error behavior changes (a different message, a change on whether the connection is killed or remains alive for the next command, or so forth), but all errors should still be handled gracefully. Signed-off-by: Eric Blake --- nbd/server.c | 53 ++++++++++++++++++++++++++++++++---------------- nbd/trace-events | 1 + 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/nbd/server.c b/nbd/server.c index 7738f5f899..ad5c2052b5 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -2316,6 +2316,8 @@ static int nbd_co_receive_request(NBDRequestData *req= , NBDRequest *request, Error **errp) { NBDClient *client =3D req->client; + bool extended_with_payload; + int payload_len =3D 0; int valid_flags; int ret; @@ -2329,27 +2331,40 @@ static int nbd_co_receive_request(NBDRequestData *r= eq, NBDRequest *request, trace_nbd_co_receive_request_decode_type(request->handle, request->typ= e, nbd_cmd_lookup(request->type)= ); - if (request->type !=3D NBD_CMD_WRITE) { - /* No payload, we are ready to read the next request. */ - req->complete =3D true; - } - if (request->type =3D=3D NBD_CMD_DISC) { /* Special case: we're going to disconnect without a reply, * whether or not flags, from, or len are bogus */ + req->complete =3D true; return -EIO; } + /* Payload and buffer handling. */ + extended_with_payload =3D client->extended_headers && + (request->flags & NBD_CMD_FLAG_PAYLOAD_LEN); if (request->type =3D=3D NBD_CMD_READ || request->type =3D=3D NBD_CMD_= WRITE || - request->type =3D=3D NBD_CMD_CACHE) - { + request->type =3D=3D NBD_CMD_CACHE || extended_with_payload) { if (request->len > NBD_MAX_BUFFER_SIZE) { error_setg(errp, "len (%" PRIu64" ) is larger than max len (%u= )", request->len, NBD_MAX_BUFFER_SIZE); return -EINVAL; } - if (request->type !=3D NBD_CMD_CACHE) { + if (request->type =3D=3D NBD_CMD_WRITE || extended_with_payload) { + payload_len =3D request->len; + if (request->type !=3D NBD_CMD_WRITE) { + /* + * For now, we don't support payloads on other + * commands; but we can keep the connection alive. + */ + request->len =3D 0; + } else if (client->extended_headers && !extended_with_payload)= { + /* The client is noncompliant. Trace it, but proceed. */ + trace_nbd_co_receive_ext_payload_compliance(request->from, + request->len); + } + } + + if (request->type =3D=3D NBD_CMD_WRITE || request->type =3D=3D NBD= _CMD_READ) { req->data =3D blk_try_blockalign(client->exp->common.blk, request->len); if (req->data =3D=3D NULL) { @@ -2359,18 +2374,20 @@ static int nbd_co_receive_request(NBDRequestData *r= eq, NBDRequest *request, } } - if (request->type =3D=3D NBD_CMD_WRITE) { - assert(request->len <=3D NBD_MAX_BUFFER_SIZE); - if (nbd_read(client->ioc, req->data, request->len, "CMD_WRITE data= ", - errp) < 0) - { + if (payload_len) { + if (req->data) { + ret =3D nbd_read(client->ioc, req->data, payload_len, + "CMD_WRITE data", errp); + } else { + ret =3D nbd_drop(client->ioc, payload_len, errp); + } + if (ret < 0) { return -EIO; } - req->complete =3D true; - trace_nbd_co_receive_request_payload_received(request->handle, - request->len); + payload_len); } + req->complete =3D true; /* Sanity checks. */ if (client->exp->nbdflags & NBD_FLAG_READ_ONLY && @@ -2400,7 +2417,9 @@ static int nbd_co_receive_request(NBDRequestData *req= , NBDRequest *request, client->check_align); } valid_flags =3D NBD_CMD_FLAG_FUA; - if (request->type =3D=3D NBD_CMD_READ && client->structured_reply) { + if (request->type =3D=3D NBD_CMD_WRITE && client->extended_headers) { + valid_flags |=3D NBD_CMD_FLAG_PAYLOAD_LEN; + } else if (request->type =3D=3D NBD_CMD_READ && client->structured_rep= ly) { valid_flags |=3D NBD_CMD_FLAG_DF; } else if (request->type =3D=3D NBD_CMD_WRITE_ZEROES) { valid_flags |=3D NBD_CMD_FLAG_NO_HOLE | NBD_CMD_FLAG_FAST_ZERO; diff --git a/nbd/trace-events b/nbd/trace-events index e2c1d68688..adf5666e20 100644 --- a/nbd/trace-events +++ b/nbd/trace-events @@ -71,6 +71,7 @@ nbd_co_send_extents(uint64_t handle, unsigned int extents= , uint32_t id, uint64_t nbd_co_send_structured_error(uint64_t handle, int err, const char *errname= , const char *msg) "Send structured error reply: handle =3D %" PRIu64 ", er= ror =3D %d (%s), msg =3D '%s'" nbd_co_receive_request_decode_type(uint64_t handle, uint16_t type, const c= har *name) "Decoding type: handle =3D %" PRIu64 ", type =3D %" PRIu16 " (%s= )" nbd_co_receive_request_payload_received(uint64_t handle, uint64_t len) "Pa= yload received: handle =3D %" PRIu64 ", len =3D %" PRIu64 +nbd_co_receive_ext_payload_compliance(uint64_t from, uint64_t len) "client= sent non-compliant write without payload flag: from=3D0x%" PRIx64 ", len= =3D0x%" PRIx64 nbd_co_receive_align_compliance(const char *op, uint64_t from, uint64_t le= n, uint32_t align) "client sent non-compliant unaligned %s request: from=3D= 0x%" PRIx64 ", len=3D0x%" PRIx64 ", align=3D0x%" PRIx32 nbd_trip(void) "Reading request" --=20 2.38.1 From nobody Fri May 10 15:25:06 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1668471969; cv=none; d=zohomail.com; s=zohoarc; b=BaOvoQx5HJWycpvE4NaE1TMws7TZ+D/ulMBJufPanhvLvVgLa+/SSEAiveyNByaC3ujZycGW96+pFG9IxHrRRw+a9QBzQlPAeovKlFLNYnXe2/mT2qoSKGMs2d61vveyJptyadZAgzBfFGt0Jub2fysJE0W+rcfZ/JGH71P/hoo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1668471969; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=jhXWmjjMMvetiJJGQOaMHI4cWIKTWMJVS4R37MRRDFY=; b=ktIL6F/3lutusCTNbjBiSb0YEUowpyQVOgkX4TIldYauo/Rysobr0XANb5HlANEe02hrW02t//2UhEvADsHREhy0BmBiepjzx/ElDef+cbx5hwlQUS7vHZAcU5wziZ7xyS/JJqa9EZJvqcbYonn6UmPfVmE5FeJ+GPkQL+lUJ04= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1668471969657608.4712440350131; Mon, 14 Nov 2022 16:26:09 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ouie3-0002Hg-S2; Mon, 14 Nov 2022 18:13:39 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouidq-0001df-Fe for qemu-devel@nongnu.org; Mon, 14 Nov 2022 18:13:26 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouiGS-0002RT-Qf for qemu-devel@nongnu.org; Mon, 14 Nov 2022 17:49:18 -0500 Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-557-HOZzzlkEMVK76COZWP2WeA-1; Mon, 14 Nov 2022 17:48:59 -0500 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 2E52D1C08792; Mon, 14 Nov 2022 22:48:59 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.240]) by smtp.corp.redhat.com (Postfix) with ESMTP id AC33040AE7EF; Mon, 14 Nov 2022 22:48:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1668466156; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=jhXWmjjMMvetiJJGQOaMHI4cWIKTWMJVS4R37MRRDFY=; b=HOYPRgc7I/irY9HFg6PFajmibb2GPme/jYwHjLLKrRFxbE+JfONmviRpcTi4Z0bBN1pFpb tw2J3MFhiHSOFn8V1q3MNEAEWEJGEA1NFxVzCALCzOe4qiEEmk4o8ZFXHrXxvbo1zKz6v4 ZaM8Ag23rpdD9H6jyrihoA729i3ZV9k= X-MC-Unique: HOZzzlkEMVK76COZWP2WeA-1 From: Eric Blake To: qemu-devel@nongnu.org Cc: qemu-block@nongnu.org, libguestfs@redhat.com, nbd@other.debian.org, Vladimir Sementsov-Ogievskiy Subject: [PATCH v2 06/15] nbd/server: Refactor to pass full request around Date: Mon, 14 Nov 2022 16:48:39 -0600 Message-Id: <20221114224848.2186298-7-eblake@redhat.com> In-Reply-To: <20221114224848.2186298-1-eblake@redhat.com> References: <20221114224141.cm5jgyxfmvie5xb5@redhat.com> <20221114224848.2186298-1-eblake@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.2 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1668471970827100001 Content-Type: text/plain; charset="utf-8" Part of NBD's 64-bit headers extension involves passing the client's requested offset back as part of the reply header (one reason for this change: converting absolute offsets stored in NBD_REPLY_TYPE_OFFSET_DATA to relative offsets within the buffer is easier if the absolute offset of the buffer is also available). This is a refactoring patch to pass the full request around the reply stack, rather than just the handle, so that later patches can then access request->from when extended headers are active. But for this patch, there are no semantic changes. Signed-off-by: Eric Blake --- nbd/server.c | 109 ++++++++++++++++++++++++++------------------------- 1 file changed, 55 insertions(+), 54 deletions(-) diff --git a/nbd/server.c b/nbd/server.c index ad5c2052b5..4d1400430b 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -1890,18 +1890,17 @@ static int coroutine_fn nbd_co_send_iov(NBDClient *= client, struct iovec *iov, } static inline void set_be_simple_reply(NBDClient *client, struct iovec *io= v, - uint64_t error, uint64_t handle) + uint64_t error, NBDRequest *request) { NBDSimpleReply *reply =3D iov->iov_base; iov->iov_len =3D sizeof(*reply); stl_be_p(&reply->magic, NBD_SIMPLE_REPLY_MAGIC); stl_be_p(&reply->error, error); - stq_be_p(&reply->handle, handle); + stq_be_p(&reply->handle, request->handle); } -static int nbd_co_send_simple_reply(NBDClient *client, - uint64_t handle, +static int nbd_co_send_simple_reply(NBDClient *client, NBDRequest *request, uint32_t error, void *data, size_t len, @@ -1914,16 +1913,16 @@ static int nbd_co_send_simple_reply(NBDClient *clie= nt, {.iov_base =3D data, .iov_len =3D len} }; - trace_nbd_co_send_simple_reply(handle, nbd_err, nbd_err_lookup(nbd_err= ), - len); - set_be_simple_reply(client, &iov[0], nbd_err, handle); + trace_nbd_co_send_simple_reply(request->handle, nbd_err, + nbd_err_lookup(nbd_err), len); + set_be_simple_reply(client, &iov[0], nbd_err, request); return nbd_co_send_iov(client, iov, len ? 2 : 1, errp); } static inline void set_be_chunk(NBDClient *client, struct iovec *iov, uint16_t flags, uint16_t type, - uint64_t handle, uint32_t length) + NBDRequest *request, uint32_t length) { NBDStructuredReplyChunk *chunk =3D iov->iov_base; @@ -1931,12 +1930,12 @@ static inline void set_be_chunk(NBDClient *client, = struct iovec *iov, stl_be_p(&chunk->magic, NBD_STRUCTURED_REPLY_MAGIC); stw_be_p(&chunk->flags, flags); stw_be_p(&chunk->type, type); - stq_be_p(&chunk->handle, handle); + stq_be_p(&chunk->handle, request->handle); stl_be_p(&chunk->length, length); } static int coroutine_fn nbd_co_send_structured_done(NBDClient *client, - uint64_t handle, + NBDRequest *request, Error **errp) { NBDReply hdr; @@ -1944,15 +1943,15 @@ static int coroutine_fn nbd_co_send_structured_done= (NBDClient *client, {.iov_base =3D &hdr}, }; - trace_nbd_co_send_structured_done(handle); + trace_nbd_co_send_structured_done(request->handle); set_be_chunk(client, &iov[0], NBD_REPLY_FLAG_DONE, - NBD_REPLY_TYPE_NONE, handle, 0); + NBD_REPLY_TYPE_NONE, request, 0); return nbd_co_send_iov(client, iov, 1, errp); } static int coroutine_fn nbd_co_send_structured_read(NBDClient *client, - uint64_t handle, + NBDRequest *request, uint64_t offset, void *data, size_t size, @@ -1968,16 +1967,16 @@ static int coroutine_fn nbd_co_send_structured_read= (NBDClient *client, }; assert(size); - trace_nbd_co_send_structured_read(handle, offset, data, size); + trace_nbd_co_send_structured_read(request->handle, offset, data, size); set_be_chunk(client, &iov[0], final ? NBD_REPLY_FLAG_DONE : 0, - NBD_REPLY_TYPE_OFFSET_DATA, handle, iov[1].iov_len + size= ); + NBD_REPLY_TYPE_OFFSET_DATA, request, iov[1].iov_len + siz= e); stq_be_p(&chunk.offset, offset); return nbd_co_send_iov(client, iov, 3, errp); } static int coroutine_fn nbd_co_send_structured_error(NBDClient *client, - uint64_t handle, + NBDRequest *request, uint32_t error, const char *msg, Error **errp) @@ -1992,10 +1991,11 @@ static int coroutine_fn nbd_co_send_structured_erro= r(NBDClient *client, }; assert(nbd_err); - trace_nbd_co_send_structured_error(handle, nbd_err, + trace_nbd_co_send_structured_error(request->handle, nbd_err, nbd_err_lookup(nbd_err), msg ? msg = : ""); set_be_chunk(client, &iov[0], NBD_REPLY_FLAG_DONE, - NBD_REPLY_TYPE_ERROR, handle, iov[1].iov_len + iov[2].iov= _len); + NBD_REPLY_TYPE_ERROR, request, + iov[1].iov_len + iov[2].iov_len); stl_be_p(&chunk.error, nbd_err); stw_be_p(&chunk.message_length, iov[2].iov_len); @@ -2007,7 +2007,7 @@ static int coroutine_fn nbd_co_send_structured_error(= NBDClient *client, * reported to the client, at which point this function succeeds. */ static int coroutine_fn nbd_co_send_sparse_read(NBDClient *client, - uint64_t handle, + NBDRequest *request, uint64_t offset, uint8_t *data, size_t size, @@ -2029,7 +2029,7 @@ static int coroutine_fn nbd_co_send_sparse_read(NBDCl= ient *client, char *msg =3D g_strdup_printf("unable to check for holes: %s", strerror(-status)); - ret =3D nbd_co_send_structured_error(client, handle, -status, = msg, + ret =3D nbd_co_send_structured_error(client, request, -status,= msg, errp); g_free(msg); return ret; @@ -2044,12 +2044,12 @@ static int coroutine_fn nbd_co_send_sparse_read(NBD= Client *client, {.iov_base =3D &chunk, .iov_len =3D sizeof(chunk)}, }; - trace_nbd_co_send_structured_read_hole(handle, offset + progre= ss, + trace_nbd_co_send_structured_read_hole(request->handle, + offset + progress, pnum); set_be_chunk(client, &iov[0], final ? NBD_REPLY_FLAG_DONE : 0, - NBD_REPLY_TYPE_OFFSET_HOLE, - handle, iov[1].iov_len); + NBD_REPLY_TYPE_OFFSET_HOLE, request, iov[1].iov_l= en); stq_be_p(&chunk.offset, offset + progress); stl_be_p(&chunk.length, pnum); ret =3D nbd_co_send_iov(client, iov, 2, errp); @@ -2060,7 +2060,8 @@ static int coroutine_fn nbd_co_send_sparse_read(NBDCl= ient *client, error_setg_errno(errp, -ret, "reading from file failed"); break; } - ret =3D nbd_co_send_structured_read(client, handle, offset + p= rogress, + ret =3D nbd_co_send_structured_read(client, request, + offset + progress, data + progress, pnum, final, errp); } @@ -2212,7 +2213,7 @@ static int blockalloc_to_extents(BlockDriverState *bs= , uint64_t offset, * @ea is converted to BE by the function * @last controls whether NBD_REPLY_FLAG_DONE is sent. */ -static int nbd_co_send_extents(NBDClient *client, uint64_t handle, +static int nbd_co_send_extents(NBDClient *client, NBDRequest *request, NBDExtentArray *ea, bool last, uint32_t context_id, Error **err= p) { @@ -2226,18 +2227,18 @@ static int nbd_co_send_extents(NBDClient *client, u= int64_t handle, nbd_extent_array_convert_to_be(ea); - trace_nbd_co_send_extents(handle, ea->count, context_id, ea->total_len= gth, - last); + trace_nbd_co_send_extents(request->handle, ea->count, context_id, + ea->total_length, last); set_be_chunk(client, &iov[0], last ? NBD_REPLY_FLAG_DONE : 0, NBD_REPLY_TYPE_BLOCK_STATUS, - handle, iov[1].iov_len + iov[2].iov_len); + request, iov[1].iov_len + iov[2].iov_len); stl_be_p(&chunk.context_id, context_id); return nbd_co_send_iov(client, iov, 3, errp); } /* Get block status from the exported device and send it to the client */ -static int nbd_co_send_block_status(NBDClient *client, uint64_t handle, +static int nbd_co_send_block_status(NBDClient *client, NBDRequest *request, BlockDriverState *bs, uint64_t offset, uint32_t length, bool dont_fragment, bool last, uint32_t context_id, @@ -2254,10 +2255,10 @@ static int nbd_co_send_block_status(NBDClient *clie= nt, uint64_t handle, } if (ret < 0) { return nbd_co_send_structured_error( - client, handle, -ret, "can't get block status", errp); + client, request, -ret, "can't get block status", errp); } - return nbd_co_send_extents(client, handle, ea, last, context_id, errp); + return nbd_co_send_extents(client, request, ea, last, context_id, errp= ); } /* Populate @ea from a dirty bitmap. */ @@ -2292,7 +2293,7 @@ static void bitmap_to_extents(BdrvDirtyBitmap *bitmap, bdrv_dirty_bitmap_unlock(bitmap); } -static int nbd_co_send_bitmap(NBDClient *client, uint64_t handle, +static int nbd_co_send_bitmap(NBDClient *client, NBDRequest *request, BdrvDirtyBitmap *bitmap, uint64_t offset, uint32_t length, bool dont_fragment, bool la= st, uint32_t context_id, Error **errp) @@ -2302,7 +2303,7 @@ static int nbd_co_send_bitmap(NBDClient *client, uint= 64_t handle, bitmap_to_extents(bitmap, offset, length, ea); - return nbd_co_send_extents(client, handle, ea, last, context_id, errp); + return nbd_co_send_extents(client, request, ea, last, context_id, errp= ); } /* nbd_co_receive_request @@ -2440,16 +2441,16 @@ static int nbd_co_receive_request(NBDRequestData *r= eq, NBDRequest *request, * Returns 0 if connection is still live, -errno on failure to talk to cli= ent */ static coroutine_fn int nbd_send_generic_reply(NBDClient *client, - uint64_t handle, + NBDRequest *request, int ret, const char *error_msg, Error **errp) { if (client->structured_reply && ret < 0) { - return nbd_co_send_structured_error(client, handle, -ret, error_ms= g, + return nbd_co_send_structured_error(client, request, -ret, error_m= sg, errp); } else { - return nbd_co_send_simple_reply(client, handle, ret < 0 ? -ret : 0, + return nbd_co_send_simple_reply(client, request, ret < 0 ? -ret : = 0, NULL, 0, errp); } } @@ -2470,7 +2471,7 @@ static coroutine_fn int nbd_do_cmd_read(NBDClient *cl= ient, NBDRequest *request, if (request->flags & NBD_CMD_FLAG_FUA) { ret =3D blk_co_flush(exp->common.blk); if (ret < 0) { - return nbd_send_generic_reply(client, request->handle, ret, + return nbd_send_generic_reply(client, request, ret, "flush failed", errp); } } @@ -2478,26 +2479,26 @@ static coroutine_fn int nbd_do_cmd_read(NBDClient *= client, NBDRequest *request, if (client->structured_reply && !(request->flags & NBD_CMD_FLAG_DF) && request->len) { - return nbd_co_send_sparse_read(client, request->handle, request->f= rom, + return nbd_co_send_sparse_read(client, request, request->from, data, request->len, errp); } ret =3D blk_pread(exp->common.blk, request->from, request->len, data, = 0); if (ret < 0) { - return nbd_send_generic_reply(client, request->handle, ret, + return nbd_send_generic_reply(client, request, ret, "reading from file failed", errp); } if (client->structured_reply) { if (request->len) { - return nbd_co_send_structured_read(client, request->handle, + return nbd_co_send_structured_read(client, request, request->from, data, request->len, true, errp); } else { - return nbd_co_send_structured_done(client, request->handle, er= rp); + return nbd_co_send_structured_done(client, request, errp); } } else { - return nbd_co_send_simple_reply(client, request->handle, 0, + return nbd_co_send_simple_reply(client, request, 0, data, request->len, errp); } } @@ -2521,7 +2522,7 @@ static coroutine_fn int nbd_do_cmd_cache(NBDClient *c= lient, NBDRequest *request, ret =3D blk_co_preadv(exp->common.blk, request->from, request->len, NULL, BDRV_REQ_COPY_ON_READ | BDRV_REQ_PREFETCH); - return nbd_send_generic_reply(client, request->handle, ret, + return nbd_send_generic_reply(client, request, ret, "caching data failed", errp); } @@ -2553,7 +2554,7 @@ static coroutine_fn int nbd_handle_request(NBDClient = *client, assert(request->len <=3D NBD_MAX_BUFFER_SIZE); ret =3D blk_pwrite(exp->common.blk, request->from, request->len, d= ata, flags); - return nbd_send_generic_reply(client, request->handle, ret, + return nbd_send_generic_reply(client, request, ret, "writing to file failed", errp); case NBD_CMD_WRITE_ZEROES: @@ -2569,7 +2570,7 @@ static coroutine_fn int nbd_handle_request(NBDClient = *client, } ret =3D blk_pwrite_zeroes(exp->common.blk, request->from, request-= >len, flags); - return nbd_send_generic_reply(client, request->handle, ret, + return nbd_send_generic_reply(client, request, ret, "writing to file failed", errp); case NBD_CMD_DISC: @@ -2578,7 +2579,7 @@ static coroutine_fn int nbd_handle_request(NBDClient = *client, case NBD_CMD_FLUSH: ret =3D blk_co_flush(exp->common.blk); - return nbd_send_generic_reply(client, request->handle, ret, + return nbd_send_generic_reply(client, request, ret, "flush failed", errp); case NBD_CMD_TRIM: @@ -2586,12 +2587,12 @@ static coroutine_fn int nbd_handle_request(NBDClien= t *client, if (ret >=3D 0 && request->flags & NBD_CMD_FLAG_FUA) { ret =3D blk_co_flush(exp->common.blk); } - return nbd_send_generic_reply(client, request->handle, ret, + return nbd_send_generic_reply(client, request, ret, "discard failed", errp); case NBD_CMD_BLOCK_STATUS: if (!request->len) { - return nbd_send_generic_reply(client, request->handle, -EINVAL, + return nbd_send_generic_reply(client, request, -EINVAL, "need non-zero length", errp); } assert(request->len <=3D UINT32_MAX); @@ -2600,7 +2601,7 @@ static coroutine_fn int nbd_handle_request(NBDClient = *client, int contexts_remaining =3D client->export_meta.count; if (client->export_meta.base_allocation) { - ret =3D nbd_co_send_block_status(client, request->handle, + ret =3D nbd_co_send_block_status(client, request, blk_bs(exp->common.blk), request->from, request->len, dont_fragment, @@ -2613,7 +2614,7 @@ static coroutine_fn int nbd_handle_request(NBDClient = *client, } if (client->export_meta.allocation_depth) { - ret =3D nbd_co_send_block_status(client, request->handle, + ret =3D nbd_co_send_block_status(client, request, blk_bs(exp->common.blk), request->from, request->len, dont_fragment, @@ -2629,7 +2630,7 @@ static coroutine_fn int nbd_handle_request(NBDClient = *client, if (!client->export_meta.bitmaps[i]) { continue; } - ret =3D nbd_co_send_bitmap(client, request->handle, + ret =3D nbd_co_send_bitmap(client, request, client->exp->export_bitmaps[i], request->from, request->len, dont_fragment, !--contexts_remain= ing, @@ -2643,7 +2644,7 @@ static coroutine_fn int nbd_handle_request(NBDClient = *client, return 0; } else { - return nbd_send_generic_reply(client, request->handle, -EINVAL, + return nbd_send_generic_reply(client, request, -EINVAL, "CMD_BLOCK_STATUS not negotiated= ", errp); } @@ -2651,7 +2652,7 @@ static coroutine_fn int nbd_handle_request(NBDClient = *client, default: msg =3D g_strdup_printf("invalid request type (%" PRIu32 ") receiv= ed", request->type); - ret =3D nbd_send_generic_reply(client, request->handle, -EINVAL, m= sg, + ret =3D nbd_send_generic_reply(client, request, -EINVAL, msg, errp); g_free(msg); return ret; @@ -2712,7 +2713,7 @@ static coroutine_fn void nbd_trip(void *opaque) Error *export_err =3D local_err; local_err =3D NULL; - ret =3D nbd_send_generic_reply(client, request.handle, -EINVAL, + ret =3D nbd_send_generic_reply(client, &request, -EINVAL, error_get_pretty(export_err), &local_= err); error_free(export_err); } else { --=20 2.38.1 From nobody Fri May 10 15:25:06 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1668468435; cv=none; d=zohomail.com; s=zohoarc; b=Z0k3ShfVvjFzHNZ1tBUNyYuVdK/DA4gRU+ZIzUrw/V0tKlRGPlthNdyxccHrLxdRSHH1huJQ7uST3RcY/in3OZdCM0o8HyDneGMu9cpMinZQkXT77gXgSOYMvycOSHb/tk2BfFwZvB4PcvGxex8ERxAsQcyHge9/epIIuEthFOI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1668468435; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=zhjaJStUuLPK/R3vMxs8VI5rugu1a9ay15tYrbDlKAg=; b=mcQe4Z1RZoUyR5tDyev46gMQumY01LLzALjxa3lZg3OPjDSvlDmdXs5BHE4bqOxGkc9LOw51qjOpihqGD0vCK3nHSlsHZWNNwtLBTsfswZnkYdmeunTYgfHXml4gybaYl3S24dGnNFdkqgyDcDYnEm4XY9+JF1dX8w6CL7c00SE= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1668468435167981.1229003716941; Mon, 14 Nov 2022 15:27:15 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ouieC-0002jN-Gx; Mon, 14 Nov 2022 18:13:48 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouidr-0001df-Vm for qemu-devel@nongnu.org; Mon, 14 Nov 2022 18:13:28 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouiGI-0002OZ-E4 for qemu-devel@nongnu.org; Mon, 14 Nov 2022 17:49:09 -0500 Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-86-c9vmJOToNCSgezP9DKJmmg-1; Mon, 14 Nov 2022 17:49:00 -0500 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id D1B791C087B7; Mon, 14 Nov 2022 22:48:59 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.240]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5A32F40AE7F0; Mon, 14 Nov 2022 22:48:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1668466145; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=zhjaJStUuLPK/R3vMxs8VI5rugu1a9ay15tYrbDlKAg=; b=ZAWo4+K3LUMODgmZdygtrBRlOr56IN5A0cWwtiJPVoCoFbMpWESpgQcNd9kKEGFun60zPX W/UM0PQ3KTTuRops/v3iZNpcXG8mop63XGpw3jDwTqa2bnBXx/Y0tWa4cxcn7QrMfXxUU0 GMalw3nMrgtO2xjSdbgQEHZQL+i6rbk= X-MC-Unique: c9vmJOToNCSgezP9DKJmmg-1 From: Eric Blake To: qemu-devel@nongnu.org Cc: qemu-block@nongnu.org, libguestfs@redhat.com, nbd@other.debian.org, Vladimir Sementsov-Ogievskiy Subject: [PATCH v2 07/15] nbd/server: Initial support for extended headers Date: Mon, 14 Nov 2022 16:48:40 -0600 Message-Id: <20221114224848.2186298-8-eblake@redhat.com> In-Reply-To: <20221114224848.2186298-1-eblake@redhat.com> References: <20221114224141.cm5jgyxfmvie5xb5@redhat.com> <20221114224848.2186298-1-eblake@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.2 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1668468437745100003 Content-Type: text/plain; charset="utf-8" Even though the NBD spec has been altered to allow us to accept NBD_CMD_READ larger than the max payload size (provided our response is a hole or broken up over more than one data chunk), we are not planning to take advantage of that, and continue to cap NBD_CMD_READ to 32M regardless of header size. For NBD_CMD_WRITE_ZEROES and NBD_CMD_TRIM, the block layer already supports 64-bit operations without any effort on our part. For NBD_CMD_BLOCK_STATUS, the client's length is a hint; the easiest approach for now is to truncate our answer back to 32 bits, which lets us delay the effort of implementing NBD_REPLY_TYPE_BLOCK_STATUS_EXT to a separate patch. Signed-off-by: Eric Blake --- nbd/nbd-internal.h | 7 ++- nbd/server.c | 132 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 108 insertions(+), 31 deletions(-) diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h index 0016793ff4..f9fe0b6ce3 100644 --- a/nbd/nbd-internal.h +++ b/nbd/nbd-internal.h @@ -1,7 +1,7 @@ /* * NBD Internal Declarations * - * Copyright (C) 2016-2021 Red Hat, Inc. + * Copyright (C) 2016-2022 Red Hat, Inc. * * This work is licensed under the terms of the GNU GPL, version 2 or late= r. * See the COPYING file in the top-level directory. @@ -35,8 +35,11 @@ * https://github.com/yoe/nbd/blob/master/doc/proto.md */ -/* Size of all NBD_OPT_*, without payload */ +/* Size of all compact NBD_CMD_*, without payload */ #define NBD_REQUEST_SIZE (4 + 2 + 2 + 8 + 8 + 4) +/* Size of all extended NBD_CMD_*, without payload */ +#define NBD_EXTENDED_REQUEST_SIZE (4 + 2 + 2 + 8 + 8 + 8) + /* Size of all NBD_REP_* sent in answer to most NBD_OPT_*, without payload= */ #define NBD_REPLY_SIZE (4 + 4 + 8) /* Size of reply to NBD_OPT_EXPORT_NAME */ diff --git a/nbd/server.c b/nbd/server.c index 4d1400430b..b46655b4d8 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -141,7 +141,7 @@ struct NBDClient { uint32_t check_align; /* If non-zero, check for aligned client request= s */ - bool structured_reply; + bool structured_reply; /* also set true if extended_headers is set */ bool extended_headers; NBDExportMetaContexts export_meta; @@ -1260,6 +1260,10 @@ static int nbd_negotiate_options(NBDClient *client, = Error **errp) case NBD_OPT_STRUCTURED_REPLY: if (length) { ret =3D nbd_reject_length(client, false, errp); + } else if (client->extended_headers) { + ret =3D nbd_negotiate_send_rep_err( + client, NBD_REP_ERR_EXT_HEADER_REQD, errp, + "extended headers already negotiated"); } else if (client->structured_reply) { ret =3D nbd_negotiate_send_rep_err( client, NBD_REP_ERR_INVALID, errp, @@ -1276,6 +1280,19 @@ static int nbd_negotiate_options(NBDClient *client, = Error **errp) errp); break; + case NBD_OPT_EXTENDED_HEADERS: + if (length) { + ret =3D nbd_reject_length(client, false, errp); + } else if (client->extended_headers) { + ret =3D nbd_negotiate_send_rep_err( + client, NBD_REP_ERR_INVALID, errp, + "extended headers already negotiated"); + } else { + ret =3D nbd_negotiate_send_rep(client, NBD_REP_ACK, er= rp); + client->structured_reply =3D client->extended_headers = =3D true; + } + break; + default: ret =3D nbd_opt_drop(client, NBD_REP_ERR_UNSUP, errp, "Unsupported option %" PRIu32 " (%s)", @@ -1411,11 +1428,13 @@ nbd_read_eof(NBDClient *client, void *buffer, size_= t size, Error **errp) static int nbd_receive_request(NBDClient *client, NBDRequest *request, Error **errp) { - uint8_t buf[NBD_REQUEST_SIZE]; - uint32_t magic; + uint8_t buf[NBD_EXTENDED_REQUEST_SIZE]; + uint32_t magic, expect; int ret; + size_t size =3D client->extended_headers ? NBD_EXTENDED_REQUEST_SIZE + : NBD_REQUEST_SIZE; - ret =3D nbd_read_eof(client, buf, sizeof(buf), errp); + ret =3D nbd_read_eof(client, buf, size, errp); if (ret < 0) { return ret; } @@ -1423,13 +1442,21 @@ static int nbd_receive_request(NBDClient *client, N= BDRequest *request, return -EIO; } - /* Request - [ 0 .. 3] magic (NBD_REQUEST_MAGIC) - [ 4 .. 5] flags (NBD_CMD_FLAG_FUA, ...) - [ 6 .. 7] type (NBD_CMD_READ, ...) - [ 8 .. 15] handle - [16 .. 23] from - [24 .. 27] len + /* + * Compact request + * [ 0 .. 3] magic (NBD_REQUEST_MAGIC) + * [ 4 .. 5] flags (NBD_CMD_FLAG_FUA, ...) + * [ 6 .. 7] type (NBD_CMD_READ, ...) + * [ 8 .. 15] handle + * [16 .. 23] from + * [24 .. 27] len + * Extended request + * [ 0 .. 3] magic (NBD_EXTENDED_REQUEST_MAGIC) + * [ 4 .. 5] flags (NBD_CMD_FLAG_FUA, NBD_CMD_FLAG_PAYLOAD_LEN, = ...) + * [ 6 .. 7] type (NBD_CMD_READ, ...) + * [ 8 .. 15] handle + * [16 .. 23] from + * [24 .. 31] len */ magic =3D ldl_be_p(buf); @@ -1437,12 +1464,18 @@ static int nbd_receive_request(NBDClient *client, N= BDRequest *request, request->type =3D lduw_be_p(buf + 6); request->handle =3D ldq_be_p(buf + 8); request->from =3D ldq_be_p(buf + 16); - request->len =3D ldl_be_p(buf + 24); /* widen 32 to 64 bits */ + if (client->extended_headers) { + request->len =3D ldq_be_p(buf + 24); + expect =3D NBD_EXTENDED_REQUEST_MAGIC; + } else { + request->len =3D ldl_be_p(buf + 24); /* widen 32 to 64 bits */ + expect =3D NBD_REQUEST_MAGIC; + } trace_nbd_receive_request(magic, request->flags, request->type, request->from, request->len); - if (magic !=3D NBD_REQUEST_MAGIC) { + if (magic !=3D expect) { error_setg(errp, "invalid magic (got 0x%" PRIx32 ")", magic); return -EINVAL; } @@ -1890,14 +1923,37 @@ static int coroutine_fn nbd_co_send_iov(NBDClient *= client, struct iovec *iov, } static inline void set_be_simple_reply(NBDClient *client, struct iovec *io= v, - uint64_t error, NBDRequest *request) + uint32_t error, NBDStructuredError = *err, + NBDRequest *request) { - NBDSimpleReply *reply =3D iov->iov_base; + if (client->extended_headers) { + NBDExtendedReplyChunk *chunk =3D iov->iov_base; - iov->iov_len =3D sizeof(*reply); - stl_be_p(&reply->magic, NBD_SIMPLE_REPLY_MAGIC); - stl_be_p(&reply->error, error); - stq_be_p(&reply->handle, request->handle); + iov->iov_len =3D sizeof(*chunk); + stl_be_p(&chunk->magic, NBD_EXTENDED_REPLY_MAGIC); + stw_be_p(&chunk->flags, NBD_REPLY_FLAG_DONE); + stq_be_p(&chunk->handle, request->handle); + stq_be_p(&chunk->offset, request->from); + if (error) { + assert(!iov[1].iov_base); + iov[1].iov_base =3D err; + iov[1].iov_len =3D sizeof(*err); + stw_be_p(&chunk->type, NBD_REPLY_TYPE_ERROR); + stq_be_p(&chunk->length, sizeof(*err)); + stl_be_p(&err->error, error); + stw_be_p(&err->message_length, 0); + } else { + stw_be_p(&chunk->type, NBD_REPLY_TYPE_NONE); + stq_be_p(&chunk->length, 0); + } + } else { + NBDSimpleReply *reply =3D iov->iov_base; + + iov->iov_len =3D sizeof(*reply); + stl_be_p(&reply->magic, NBD_SIMPLE_REPLY_MAGIC); + stl_be_p(&reply->error, error); + stq_be_p(&reply->handle, request->handle); + } } static int nbd_co_send_simple_reply(NBDClient *client, NBDRequest *request, @@ -1908,30 +1964,44 @@ static int nbd_co_send_simple_reply(NBDClient *clie= nt, NBDRequest *request, { NBDReply hdr; int nbd_err =3D system_errno_to_nbd_errno(error); + NBDStructuredError err; struct iovec iov[] =3D { {.iov_base =3D &hdr}, {.iov_base =3D data, .iov_len =3D len} }; + assert(!len || !nbd_err); trace_nbd_co_send_simple_reply(request->handle, nbd_err, nbd_err_lookup(nbd_err), len); - set_be_simple_reply(client, &iov[0], nbd_err, request); + set_be_simple_reply(client, &iov[0], nbd_err, &err, request); - return nbd_co_send_iov(client, iov, len ? 2 : 1, errp); + return nbd_co_send_iov(client, iov, iov[1].iov_len ? 2 : 1, errp); } static inline void set_be_chunk(NBDClient *client, struct iovec *iov, uint16_t flags, uint16_t type, NBDRequest *request, uint32_t length) { - NBDStructuredReplyChunk *chunk =3D iov->iov_base; + if (client->extended_headers) { + NBDExtendedReplyChunk *chunk =3D iov->iov_base; - iov->iov_len =3D sizeof(*chunk); - stl_be_p(&chunk->magic, NBD_STRUCTURED_REPLY_MAGIC); - stw_be_p(&chunk->flags, flags); - stw_be_p(&chunk->type, type); - stq_be_p(&chunk->handle, request->handle); - stl_be_p(&chunk->length, length); + iov->iov_len =3D sizeof(*chunk); + stl_be_p(&chunk->magic, NBD_EXTENDED_REPLY_MAGIC); + stw_be_p(&chunk->flags, flags); + stw_be_p(&chunk->type, type); + stq_be_p(&chunk->handle, request->handle); + stq_be_p(&chunk->offset, request->from); + stq_be_p(&chunk->length, length); + } else { + NBDStructuredReplyChunk *chunk =3D iov->iov_base; + + iov->iov_len =3D sizeof(*chunk); + stl_be_p(&chunk->magic, NBD_STRUCTURED_REPLY_MAGIC); + stw_be_p(&chunk->flags, flags); + stw_be_p(&chunk->type, type); + stq_be_p(&chunk->handle, request->handle); + stl_be_p(&chunk->length, length); + } } static int coroutine_fn nbd_co_send_structured_done(NBDClient *client, @@ -2595,7 +2665,11 @@ static coroutine_fn int nbd_handle_request(NBDClient= *client, return nbd_send_generic_reply(client, request, -EINVAL, "need non-zero length", errp); } - assert(request->len <=3D UINT32_MAX); + if (request->len > UINT32_MAX) { + /* For now, truncate our response to a 32 bit window */ + request->len =3D QEMU_ALIGN_DOWN(BDRV_REQUEST_MAX_BYTES, + client->check_align ?: 1); + } if (client->export_meta.count) { bool dont_fragment =3D request->flags & NBD_CMD_FLAG_REQ_ONE; int contexts_remaining =3D client->export_meta.count; --=20 2.38.1 From nobody Fri May 10 15:25:06 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1668467966; cv=none; d=zohomail.com; s=zohoarc; b=We/gXAxDPkK9Rc7CBO0P9fIBBzkhIhdg2mZUhaU6haGzSr9gxff7l+PJ9SS1crLPTFk+OZ+Hn2VfcNozgVbPpb3IYzJIWzOdAz8zvnOsbhuE7qhqC/R6RbljCv8D1inY/IJrp9+wpMFYztT6yKx8TFvSH6Iwo++wd9mPyWlCDmc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1668467966; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=arqevMePL9jAQyKPEZW3LJy1uVj4/5W9Ai4SJGjTr2w=; b=cOMl9TEA/jY81OgJtfKUPh+zXSewtxE3YApoGM9PNWfcHuCJNtimH3I3nQ2uJbm6/8UXabzsToSTXBRS91UQ8+R52izRXRZPO0YD8WsNwVx65k3mq0LtGL+P5DoMkUap+44BPGNc1yuVsLrPDTgDyCf5z5BoMjkowRnZ1FoLfuA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1668467966623136.42607218084981; Mon, 14 Nov 2022 15:19:26 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ouieP-0003XR-94; Mon, 14 Nov 2022 18:14:01 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouids-0001hU-Da for qemu-devel@nongnu.org; Mon, 14 Nov 2022 18:13:28 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouiGE-0002Mp-RV for qemu-devel@nongnu.org; Mon, 14 Nov 2022 17:49:04 -0500 Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-610-Kw0mlnUeNdWlBOVKCDboWw-1; Mon, 14 Nov 2022 17:49:00 -0500 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 7E7913C0DDD0; Mon, 14 Nov 2022 22:49:00 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.240]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0840C40AE7EF; Mon, 14 Nov 2022 22:48:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1668466142; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=arqevMePL9jAQyKPEZW3LJy1uVj4/5W9Ai4SJGjTr2w=; b=YQJg2KGsDpCfrKQioAY42WpgV2XDPbwo0yoTbYS+GbPFKe39ZvYw/f/LbqMWwxRPaE2IJU v/skCYKJfodtFTN9+uVL2xp7R6B/8Pl3yKBZJnE8j/OELaxSTI/p0uF9jePezOYfYAO6S2 GjozBqK6X+kPmSddEH+tbbCn+Re2stQ= X-MC-Unique: Kw0mlnUeNdWlBOVKCDboWw-1 From: Eric Blake To: qemu-devel@nongnu.org Cc: qemu-block@nongnu.org, libguestfs@redhat.com, nbd@other.debian.org, Vladimir Sementsov-Ogievskiy Subject: [PATCH v2 08/15] nbd/server: Support 64-bit block status Date: Mon, 14 Nov 2022 16:48:41 -0600 Message-Id: <20221114224848.2186298-9-eblake@redhat.com> In-Reply-To: <20221114224848.2186298-1-eblake@redhat.com> References: <20221114224141.cm5jgyxfmvie5xb5@redhat.com> <20221114224848.2186298-1-eblake@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.2 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1668467968620100003 Content-Type: text/plain; charset="utf-8" The previous patch handled extended headers by truncating large block status requests from the client back to 32 bits. But this is not ideal; for cases where we can truly determine the status of the entire image quickly (for example, when reporting the entire image as non-sparse because we lack the ability to probe for holes), this causes more network traffic for the client to iterate through 4G chunks than for us to just report the entire image at once. For ease of implementation, if extended headers were negotiated, then we always reply with 64-bit block status replies, even when the result could have fit in the older 32-bit block status chunk (clients supporting extended headers have to be prepared for either chunk type, so temporarily reverting this patch proves whether a client is compliant). For now, all metacontexts that we know how to export never populate more than 32 bits of information, so we don't have to worry about NBD_REP_ERR_EXT_HEADER_REQD or filtering during handshake, and we always send all zeroes for the upper 32 bits of status during NBD_CMD_BLOCK_STATUS. Note that we previously had some interesting size-juggling on call chains, such as: nbd_co_send_block_status(uint32_t length) -> blockstatus_to_extents(uint32_t bytes) -> bdrv_block_status_above(bytes, &uint64_t num) -> nbd_extent_array_add(uint64_t num) -> store num in 32-bit length But we were lucky that it never overflowed: bdrv_block_status_above never sets num larger than bytes, and we had previously been capping 'bytes' at 32 bits (either by the protocol, or in the previous patch with an explicit truncation). This patch adds some assertions that ensure we continue to avoid overflowing 32 bits for a narrow client, while fully utilizing 64-bits all the way through when the client understands that. Signed-off-by: Eric Blake --- nbd/server.c | 86 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 59 insertions(+), 27 deletions(-) diff --git a/nbd/server.c b/nbd/server.c index b46655b4d8..f21f8098c1 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -2145,20 +2145,30 @@ static int coroutine_fn nbd_co_send_sparse_read(NBD= Client *client, } typedef struct NBDExtentArray { - NBDExtent *extents; + union { + NBDStructuredMeta id; + NBDStructuredMetaExt meta; + }; + union { + NBDExtent *narrow; + NBDExtentExt *extents; + }; unsigned int nb_alloc; unsigned int count; uint64_t total_length; + bool extended; /* Whether 64-bit extents are allowed */ bool can_add; bool converted_to_be; } NBDExtentArray; -static NBDExtentArray *nbd_extent_array_new(unsigned int nb_alloc) +static NBDExtentArray *nbd_extent_array_new(unsigned int nb_alloc, + bool extended) { NBDExtentArray *ea =3D g_new0(NBDExtentArray, 1); ea->nb_alloc =3D nb_alloc; - ea->extents =3D g_new(NBDExtent, nb_alloc); + ea->extents =3D g_new(NBDExtentExt, nb_alloc); + ea->extended =3D extended; ea->can_add =3D true; return ea; @@ -2172,17 +2182,37 @@ static void nbd_extent_array_free(NBDExtentArray *e= a) G_DEFINE_AUTOPTR_CLEANUP_FUNC(NBDExtentArray, nbd_extent_array_free) /* Further modifications of the array after conversion are abandoned */ -static void nbd_extent_array_convert_to_be(NBDExtentArray *ea) +static void nbd_extent_array_convert_to_be(NBDExtentArray *ea, + uint32_t context_id, + struct iovec *iov) { int i; assert(!ea->converted_to_be); + assert(iov[0].iov_base =3D=3D &ea->meta); + assert(iov[1].iov_base =3D=3D ea->extents); ea->can_add =3D false; ea->converted_to_be =3D true; - for (i =3D 0; i < ea->count; i++) { - ea->extents[i].flags =3D cpu_to_be32(ea->extents[i].flags); - ea->extents[i].length =3D cpu_to_be32(ea->extents[i].length); + stl_be_p(&ea->meta.context_id, context_id); + if (ea->extended) { + stl_be_p(&ea->meta.count, ea->count); + for (i =3D 0; i < ea->count; i++) { + ea->extents[i].length =3D cpu_to_be64(ea->extents[i].length); + ea->extents[i].flags =3D cpu_to_be64(ea->extents[i].flags); + } + iov[0].iov_len =3D sizeof(ea->meta); + iov[1].iov_len =3D ea->count * sizeof(ea->extents[0]); + } else { + /* Conversion reduces memory usage, order of iteration matters */ + for (i =3D 0; i < ea->count; i++) { + assert(ea->extents[i].length <=3D UINT32_MAX); + assert((uint32_t) ea->extents[i].flags =3D=3D ea->extents[i].f= lags); + ea->narrow[i].length =3D cpu_to_be32(ea->extents[i].length); + ea->narrow[i].flags =3D cpu_to_be32(ea->extents[i].flags); + } + iov[0].iov_len =3D sizeof(ea->id); + iov[1].iov_len =3D ea->count * sizeof(ea->narrow[0]); } } @@ -2196,19 +2226,23 @@ static void nbd_extent_array_convert_to_be(NBDExten= tArray *ea) * would result in an incorrect range reported to the client) */ static int nbd_extent_array_add(NBDExtentArray *ea, - uint32_t length, uint32_t flags) + uint64_t length, uint32_t flags) { assert(ea->can_add); if (!length) { return 0; } + if (!ea->extended) { + assert(length <=3D UINT32_MAX); + } /* Extend previous extent if flags are the same */ if (ea->count > 0 && flags =3D=3D ea->extents[ea->count - 1].flags) { - uint64_t sum =3D (uint64_t)length + ea->extents[ea->count - 1].len= gth; + uint64_t sum =3D length + ea->extents[ea->count - 1].length; - if (sum <=3D UINT32_MAX) { + assert(sum >=3D length); + if (sum <=3D UINT32_MAX || ea->extended) { ea->extents[ea->count - 1].length =3D sum; ea->total_length +=3D length; return 0; @@ -2221,7 +2255,7 @@ static int nbd_extent_array_add(NBDExtentArray *ea, } ea->total_length +=3D length; - ea->extents[ea->count] =3D (NBDExtent) {.length =3D length, .flags =3D= flags}; + ea->extents[ea->count] =3D (NBDExtentExt) {.length =3D length, .flags = =3D flags}; ea->count++; return 0; @@ -2288,21 +2322,20 @@ static int nbd_co_send_extents(NBDClient *client, N= BDRequest *request, bool last, uint32_t context_id, Error **err= p) { NBDReply hdr; - NBDStructuredMeta chunk; struct iovec iov[] =3D { {.iov_base =3D &hdr}, - {.iov_base =3D &chunk, .iov_len =3D sizeof(chunk)}, - {.iov_base =3D ea->extents, .iov_len =3D ea->count * sizeof(ea->ex= tents[0])} + {.iov_base =3D &ea->meta}, + {.iov_base =3D ea->extents} }; - nbd_extent_array_convert_to_be(ea); + nbd_extent_array_convert_to_be(ea, context_id, &iov[1]); trace_nbd_co_send_extents(request->handle, ea->count, context_id, ea->total_length, last); set_be_chunk(client, &iov[0], last ? NBD_REPLY_FLAG_DONE : 0, - NBD_REPLY_TYPE_BLOCK_STATUS, + client->extended_headers ? NBD_REPLY_TYPE_BLOCK_STATUS_EXT + : NBD_REPLY_TYPE_BLOCK_STATUS, request, iov[1].iov_len + iov[2].iov_len); - stl_be_p(&chunk.context_id, context_id); return nbd_co_send_iov(client, iov, 3, errp); } @@ -2310,13 +2343,14 @@ static int nbd_co_send_extents(NBDClient *client, N= BDRequest *request, /* Get block status from the exported device and send it to the client */ static int nbd_co_send_block_status(NBDClient *client, NBDRequest *request, BlockDriverState *bs, uint64_t offset, - uint32_t length, bool dont_fragment, + uint64_t length, bool dont_fragment, bool last, uint32_t context_id, Error **errp) { int ret; unsigned int nb_extents =3D dont_fragment ? 1 : NBD_MAX_BLOCK_STATUS_E= XTENTS; - g_autoptr(NBDExtentArray) ea =3D nbd_extent_array_new(nb_extents); + g_autoptr(NBDExtentArray) ea =3D + nbd_extent_array_new(nb_extents, client->extended_headers); if (context_id =3D=3D NBD_META_ID_BASE_ALLOCATION) { ret =3D blockstatus_to_extents(bs, offset, length, ea); @@ -2343,7 +2377,8 @@ static void bitmap_to_extents(BdrvDirtyBitmap *bitmap, bdrv_dirty_bitmap_lock(bitmap); for (start =3D offset; - bdrv_dirty_bitmap_next_dirty_area(bitmap, start, end, INT32_MAX, + bdrv_dirty_bitmap_next_dirty_area(bitmap, start, end, + es->extended ? INT64_MAX : INT3= 2_MAX, &dirty_start, &dirty_count); start =3D dirty_start + dirty_count) { @@ -2365,11 +2400,12 @@ static void bitmap_to_extents(BdrvDirtyBitmap *bitm= ap, static int nbd_co_send_bitmap(NBDClient *client, NBDRequest *request, BdrvDirtyBitmap *bitmap, uint64_t offset, - uint32_t length, bool dont_fragment, bool la= st, + uint64_t length, bool dont_fragment, bool la= st, uint32_t context_id, Error **errp) { unsigned int nb_extents =3D dont_fragment ? 1 : NBD_MAX_BLOCK_STATUS_E= XTENTS; - g_autoptr(NBDExtentArray) ea =3D nbd_extent_array_new(nb_extents); + g_autoptr(NBDExtentArray) ea =3D + nbd_extent_array_new(nb_extents, client->extended_headers); bitmap_to_extents(bitmap, offset, length, ea); @@ -2665,11 +2701,7 @@ static coroutine_fn int nbd_handle_request(NBDClient= *client, return nbd_send_generic_reply(client, request, -EINVAL, "need non-zero length", errp); } - if (request->len > UINT32_MAX) { - /* For now, truncate our response to a 32 bit window */ - request->len =3D QEMU_ALIGN_DOWN(BDRV_REQUEST_MAX_BYTES, - client->check_align ?: 1); - } + assert(client->extended_headers || request->len <=3D UINT32_MAX); if (client->export_meta.count) { bool dont_fragment =3D request->flags & NBD_CMD_FLAG_REQ_ONE; int contexts_remaining =3D client->export_meta.count; --=20 2.38.1 From nobody Fri May 10 15:25:06 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1668468892; cv=none; d=zohomail.com; s=zohoarc; b=hM/uRD9oGxE3RAyZFnKqUgf3pZP0G2Pf03WCd7FqhKlHmrhdaF8iPVipH7PiY5n3c9Qqhj43EH2FHFOjuI1FT5c9QKQKKaDCSk9TrX0HD5KCpT9rmoRKDzrRk2l54qpZkBAekULm7E8fXcOVNoY7BNvEXBwks6w8ARKQXvv1MoM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1668468892; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=PS+9G0eQgrAzbNlU7enH1i26FFIUC7sSv8GZMmvWhks=; b=BqSjsAr/NXUZawmZSXUglsLQ63YefUbY5lA3gCRyNIOGB8DroFt+KnUn/vZd4+/AZYioH1PL82MKbb+0g79weG3p8IsOiISn/+7w7CuHRUt2LNligJF5Q9i+cXd3bb6FvvoEfFeqaf4nrYL2sjjqa2ZP1T4HjSYYh6Nj8icwr3Y= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1668468892805189.71811420348035; Mon, 14 Nov 2022 15:34:52 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ouieD-0002p8-RJ; Mon, 14 Nov 2022 18:13:49 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouidr-0001eb-VR for qemu-devel@nongnu.org; Mon, 14 Nov 2022 18:13:28 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouiGH-0002OJ-RT for qemu-devel@nongnu.org; Mon, 14 Nov 2022 17:49:07 -0500 Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-262-wRz522GnMMapbMDV41tsog-1; Mon, 14 Nov 2022 17:49:01 -0500 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 5A4B8101E14C; Mon, 14 Nov 2022 22:49:01 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.240]) by smtp.corp.redhat.com (Postfix) with ESMTP id B81E440E42F2; Mon, 14 Nov 2022 22:49:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1668466145; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=PS+9G0eQgrAzbNlU7enH1i26FFIUC7sSv8GZMmvWhks=; b=SQ+uNEuZXyWm6Qpz95tbZ4isdo07OOppHU1IAE/yomHsYImPOxt8Z+ddFUDjigvpGvnhKy 5cqc1fknOkjSC5CVf4SXtiku3s1YudXYiLivPcHZKzMLGHnfJ2Itp6BljQCMbm0LDNMy4m dA7nPOenfawk3M0rB3QPj6RBwLmYafU= X-MC-Unique: wRz522GnMMapbMDV41tsog-1 From: Eric Blake To: qemu-devel@nongnu.org Cc: qemu-block@nongnu.org, libguestfs@redhat.com, nbd@other.debian.org, Vladimir Sementsov-Ogievskiy , Kevin Wolf , Hanna Reitz Subject: [PATCH v2 09/15] nbd/client: Initial support for extended headers Date: Mon, 14 Nov 2022 16:48:42 -0600 Message-Id: <20221114224848.2186298-10-eblake@redhat.com> In-Reply-To: <20221114224848.2186298-1-eblake@redhat.com> References: <20221114224141.cm5jgyxfmvie5xb5@redhat.com> <20221114224848.2186298-1-eblake@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.2 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1668468893925100005 Content-Type: text/plain; charset="utf-8" Update the client code to be able to send an extended request, and parse an extended header from the server. Note that since we reject any structured reply with a too-large payload, we can always normalize a valid header back into the compact form, so that the caller need not deal with two branches of a union. Still, until a later patch lets the client negotiate extended headers, the code added here should not be reached. Note that because of the different magic numbers, it is just as easy to trace and then tolerate a non-compliant server sending the wrong header reply as it would be to insist that the server is compliant. The only caller to nbd_receive_reply() always passed NULL for errp; since we are changing the signature anyways, I decided to sink the decision to ignore errors one layer lower. Signed-off-by: Eric Blake --- include/block/nbd.h | 2 +- block/nbd.c | 3 +- nbd/client.c | 84 ++++++++++++++++++++++++++++++--------------- nbd/trace-events | 1 + 4 files changed, 61 insertions(+), 29 deletions(-) diff --git a/include/block/nbd.h b/include/block/nbd.h index 357121ce76..02e31b2261 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -363,7 +363,7 @@ int nbd_init(int fd, QIOChannelSocket *sioc, NBDExportI= nfo *info, Error **errp); int nbd_send_request(QIOChannel *ioc, NBDRequest *request, bool ext_hdr); int coroutine_fn nbd_receive_reply(BlockDriverState *bs, QIOChannel *ioc, - NBDReply *reply, Error **errp); + NBDReply *reply, bool ext_hdrs); int nbd_client(int fd); int nbd_disconnect(int fd); int nbd_errno_to_system_errno(int err); diff --git a/block/nbd.c b/block/nbd.c index 32681d2867..a8b1bc1054 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -457,7 +457,8 @@ static coroutine_fn int nbd_receive_replies(BDRVNBDStat= e *s, uint64_t handle) /* We are under mutex and handle is 0. We have to do the dirty wor= k. */ assert(s->reply.handle =3D=3D 0); - ret =3D nbd_receive_reply(s->bs, s->ioc, &s->reply, NULL); + ret =3D nbd_receive_reply(s->bs, s->ioc, &s->reply, + s->info.extended_headers); if (ret <=3D 0) { ret =3D ret ? ret : -EIO; nbd_channel_error(s, ret); diff --git a/nbd/client.c b/nbd/client.c index 2480a48ec6..70f06ce637 100644 --- a/nbd/client.c +++ b/nbd/client.c @@ -1348,22 +1348,28 @@ int nbd_disconnect(int fd) int nbd_send_request(QIOChannel *ioc, NBDRequest *request, bool ext_hdr) { - uint8_t buf[NBD_REQUEST_SIZE]; + uint8_t buf[NBD_EXTENDED_REQUEST_SIZE]; + size_t len; - assert(!ext_hdr); - assert(request->len <=3D UINT32_MAX); trace_nbd_send_request(request->from, request->len, request->handle, request->flags, request->type, nbd_cmd_lookup(request->type)); - stl_be_p(buf, NBD_REQUEST_MAGIC); + stl_be_p(buf, ext_hdr ? NBD_EXTENDED_REQUEST_MAGIC : NBD_REQUEST_MAGIC= ); stw_be_p(buf + 4, request->flags); stw_be_p(buf + 6, request->type); stq_be_p(buf + 8, request->handle); stq_be_p(buf + 16, request->from); - stl_be_p(buf + 24, request->len); + if (ext_hdr) { + stq_be_p(buf + 24, request->len); + len =3D NBD_EXTENDED_REQUEST_SIZE; + } else { + assert(request->len <=3D UINT32_MAX); + stl_be_p(buf + 24, request->len); + len =3D NBD_REQUEST_SIZE; + } - return nbd_write(ioc, buf, sizeof(buf), NULL); + return nbd_write(ioc, buf, len, NULL); } /* nbd_receive_simple_reply @@ -1392,28 +1398,34 @@ static int nbd_receive_simple_reply(QIOChannel *ioc= , NBDSimpleReply *reply, /* nbd_receive_structured_reply_chunk * Read structured reply chunk except magic field (which should be already - * read). + * read). Normalize into the compact form. * Payload is not read. */ -static int nbd_receive_structured_reply_chunk(QIOChannel *ioc, - NBDStructuredReplyChunk *chu= nk, +static int nbd_receive_structured_reply_chunk(QIOChannel *ioc, NBDReply *c= hunk, Error **errp) { int ret; + size_t len; + uint64_t payload_len; - assert(chunk->magic =3D=3D NBD_STRUCTURED_REPLY_MAGIC); + if (chunk->magic =3D=3D NBD_STRUCTURED_REPLY_MAGIC) { + len =3D sizeof(chunk->structured); + } else { + assert(chunk->magic =3D=3D NBD_EXTENDED_REPLY_MAGIC); + len =3D sizeof(chunk->extended); + } ret =3D nbd_read(ioc, (uint8_t *)chunk + sizeof(chunk->magic), - sizeof(*chunk) - sizeof(chunk->magic), "structured chun= k", + len - sizeof(chunk->magic), "structured chunk", errp); if (ret < 0) { return ret; } - chunk->flags =3D be16_to_cpu(chunk->flags); - chunk->type =3D be16_to_cpu(chunk->type); - chunk->handle =3D be64_to_cpu(chunk->handle); - chunk->length =3D be32_to_cpu(chunk->length); + /* flags, type, and handle occupy same space between forms */ + chunk->structured.flags =3D be16_to_cpu(chunk->structured.flags); + chunk->structured.type =3D be16_to_cpu(chunk->structured.type); + chunk->structured.handle =3D be64_to_cpu(chunk->structured.handle); /* * Because we use BLOCK_STATUS with REQ_ONE, and cap READ requests @@ -1421,11 +1433,20 @@ static int nbd_receive_structured_reply_chunk(QIOCh= annel *ioc, * this. Even if we stopped using REQ_ONE, sane servers will cap * the number of extents they return for block status. */ - if (chunk->length > NBD_MAX_BUFFER_SIZE + sizeof(NBDStructuredReadData= )) { + if (chunk->magic =3D=3D NBD_STRUCTURED_REPLY_MAGIC) { + payload_len =3D be32_to_cpu(chunk->structured.length); + } else { + /* For now, we are ignoring the extended header offset. */ + payload_len =3D be64_to_cpu(chunk->extended.length); + chunk->magic =3D NBD_STRUCTURED_REPLY_MAGIC; + } + if (payload_len > NBD_MAX_BUFFER_SIZE + sizeof(NBDStructuredReadData))= { error_setg(errp, "server chunk %" PRIu32 " (%s) payload is too lon= g", - chunk->type, nbd_rep_lookup(chunk->type)); + chunk->structured.type, + nbd_rep_lookup(chunk->structured.type)); return -EINVAL; } + chunk->structured.length =3D payload_len; return 0; } @@ -1472,30 +1493,35 @@ nbd_read_eof(BlockDriverState *bs, QIOChannel *ioc,= void *buffer, size_t size, /* nbd_receive_reply * - * Decreases bs->in_flight while waiting for a new reply. This yield is wh= ere - * we wait indefinitely and the coroutine must be able to be safely reente= red - * for nbd_client_attach_aio_context(). + * Wait for a new reply. If this yields, the coroutine must be able to be + * safely reentered for nbd_client_attach_aio_context(). @ext_hdrs determ= ines + * which reply magic we are expecting, although this normalizes the result + * so that the caller only has to work with compact headers. * * Returns 1 on success - * 0 on eof, when no data was read (errp is not set) - * negative errno on failure (errp is set) + * 0 on eof, when no data was read + * negative errno on failure */ int coroutine_fn nbd_receive_reply(BlockDriverState *bs, QIOChannel *ioc, - NBDReply *reply, Error **errp) + NBDReply *reply, bool ext_hdrs) { int ret; const char *type; - ret =3D nbd_read_eof(bs, ioc, &reply->magic, sizeof(reply->magic), err= p); + ret =3D nbd_read_eof(bs, ioc, &reply->magic, sizeof(reply->magic), NUL= L); if (ret <=3D 0) { return ret; } reply->magic =3D be32_to_cpu(reply->magic); + /* Diagnose but accept wrong-width header */ switch (reply->magic) { case NBD_SIMPLE_REPLY_MAGIC: - ret =3D nbd_receive_simple_reply(ioc, &reply->simple, errp); + if (ext_hdrs) { + trace_nbd_receive_wrong_header(reply->magic); + } + ret =3D nbd_receive_simple_reply(ioc, &reply->simple, NULL); if (ret < 0) { break; } @@ -1504,7 +1530,11 @@ int coroutine_fn nbd_receive_reply(BlockDriverState = *bs, QIOChannel *ioc, reply->handle); break; case NBD_STRUCTURED_REPLY_MAGIC: - ret =3D nbd_receive_structured_reply_chunk(ioc, &reply->structured= , errp); + case NBD_EXTENDED_REPLY_MAGIC: + if (ext_hdrs !=3D (reply->magic =3D=3D NBD_EXTENDED_REPLY_MAGIC)) { + trace_nbd_receive_wrong_header(reply->magic); + } + ret =3D nbd_receive_structured_reply_chunk(ioc, reply, NULL); if (ret < 0) { break; } @@ -1515,7 +1545,7 @@ int coroutine_fn nbd_receive_reply(BlockDriverState *= bs, QIOChannel *ioc, reply->structured.length); break; default: - error_setg(errp, "invalid magic (got 0x%" PRIx32 ")", reply->magic= ); + trace_nbd_receive_wrong_header(reply->magic); return -EINVAL; } if (ret < 0) { diff --git a/nbd/trace-events b/nbd/trace-events index adf5666e20..c20df33a43 100644 --- a/nbd/trace-events +++ b/nbd/trace-events @@ -34,6 +34,7 @@ nbd_client_clear_socket(void) "Clearing NBD socket" nbd_send_request(uint64_t from, uint64_t len, uint64_t handle, uint16_t fl= ags, uint16_t type, const char *name) "Sending request to server: { .from = =3D %" PRIu64", .len =3D %" PRIu64 ", .handle =3D %" PRIu64 ", .flags =3D 0= x%" PRIx16 ", .type =3D %" PRIu16 " (%s) }" nbd_receive_simple_reply(int32_t error, const char *errname, uint64_t hand= le) "Got simple reply: { .error =3D %" PRId32 " (%s), handle =3D %" PRIu64"= }" nbd_receive_structured_reply_chunk(uint16_t flags, uint16_t type, const ch= ar *name, uint64_t handle, uint32_t length) "Got structured reply chunk: { = flags =3D 0x%" PRIx16 ", type =3D %d (%s), handle =3D %" PRIu64 ", length = =3D %" PRIu32 " }" +nbd_receive_wrong_header(uint32_t magic) "Server sent unexpected magic 0x%= " PRIx32 # common.c nbd_unknown_error(int err) "Squashing unexpected error %d to EINVAL" --=20 2.38.1 From nobody Fri May 10 15:25:06 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1668469127; cv=none; d=zohomail.com; s=zohoarc; b=KQoi3yw97aWtRD/dQQPZoZgedStRrattlFzryotdetvRcOC5qNLiYUSG7R0CakHJPoVJ6r81gSKldNiXrdZr3p9PNdrVQr0k0YA1+l3cVPYwsee/R6bn3pgyd4qOPJO/+dG7xKM3SA8dZY8iFVnKqvGinfMeAvlWIhif8tZD094= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1668469127; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=dNpwGX13xWfOmVQIRvlGoXlq2hyxspUY7BXP43GdQ8I=; b=EmPQnsyt/HtdBq/sL0LdvhzAIPa1DcjToHqLCMWRcYCosh0kBAYlKpwT7ZrgjQsOzv0sQX351wLjtxC0/2pjfqIrDVMx3l6/clV8ebt/r7hgkqNBUs6YjV4JR/pRc7Sxb1MhBySHZ1QAB8Q0/VVcobVlfzlSsiiL+XBjCqbbQzI= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1668469127347359.99733736678934; Mon, 14 Nov 2022 15:38:47 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ouieF-0002vb-CM; Mon, 14 Nov 2022 18:13:51 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouidr-0001m0-VS for qemu-devel@nongnu.org; Mon, 14 Nov 2022 18:13:28 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouiGH-0002OD-Fk for qemu-devel@nongnu.org; Mon, 14 Nov 2022 17:49:08 -0500 Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-330-TFGQOHzJMxOLsHPn4RMPlw-1; Mon, 14 Nov 2022 17:49:02 -0500 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 321EE38164C1; Mon, 14 Nov 2022 22:49:02 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.240]) by smtp.corp.redhat.com (Postfix) with ESMTP id 8E85140E42E3; Mon, 14 Nov 2022 22:49:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1668466145; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=dNpwGX13xWfOmVQIRvlGoXlq2hyxspUY7BXP43GdQ8I=; b=MLFIW/imWoze90C1UdDWFt64FcFEoWg2OSg+Shtpxoej1HJI+Niws+TzqMP34z0eTi8mXY MJyje0Wis1DMrj46v3z5QfSKIspMRWHs5AUtFe4mESE9Dqo0tU4kWjWf/RFTECnHPxUtHx lt6Szk6n+Mj0ypetMi334sIHm4ZRHOE= X-MC-Unique: TFGQOHzJMxOLsHPn4RMPlw-1 From: Eric Blake To: qemu-devel@nongnu.org Cc: qemu-block@nongnu.org, libguestfs@redhat.com, nbd@other.debian.org, Vladimir Sementsov-Ogievskiy , Kevin Wolf , Hanna Reitz Subject: [PATCH v2 10/15] nbd/client: Accept 64-bit block status chunks Date: Mon, 14 Nov 2022 16:48:43 -0600 Message-Id: <20221114224848.2186298-11-eblake@redhat.com> In-Reply-To: <20221114224848.2186298-1-eblake@redhat.com> References: <20221114224141.cm5jgyxfmvie5xb5@redhat.com> <20221114224848.2186298-1-eblake@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.2 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1668469127689100013 Content-Type: text/plain; charset="utf-8" Because we use NBD_CMD_FLAG_REQ_ONE with NBD_CMD_BLOCK_STATUS, a client in narrow mode should not be able to provoke a server into sending a block status result larger than the client's 32-bit request. But in extended mode, a 64-bit status request must be able to handle a 64-bit status result, once a future patch enables the client requesting extended mode. We can also tolerate a non-compliant server sending the new chunk even when it should not. In normal execution, we are only requesting "base:allocation" which never exceeds 32 bits. But during testing with x-dirty-bitmap, we can force qemu to connect to some other context that might have 64-bit status bit; however, we ignore those upper bits (other than mapping qemu:allocation-depth into something that 'qemu-img map --output=3Djson' can expose), and since it is only testing, we really don't bother with checking whether more than the two least-significant bits are set. Signed-off-by: Eric Blake --- block/nbd.c | 38 +++++++++++++++++++++++++++----------- block/trace-events | 1 + 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/block/nbd.c b/block/nbd.c index a8b1bc1054..44ab5437ea 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -608,13 +608,16 @@ static int nbd_parse_offset_hole_payload(BDRVNBDState= *s, */ static int nbd_parse_blockstatus_payload(BDRVNBDState *s, NBDStructuredReplyChunk *chunk, - uint8_t *payload, uint64_t orig_l= ength, - NBDExtent *extent, Error **errp) + uint8_t *payload, bool wide, + uint64_t orig_length, + NBDExtentExt *extent, Error **err= p) { uint32_t context_id; + uint32_t count =3D 0; + size_t len =3D wide ? sizeof(*extent) : sizeof(NBDExtent); /* The server succeeded, so it must have sent [at least] one extent */ - if (chunk->length < sizeof(context_id) + sizeof(*extent)) { + if (chunk->length < sizeof(context_id) + wide * sizeof(count) + len) { error_setg(errp, "Protocol error: invalid payload for " "NBD_REPLY_TYPE_BLOCK_STATUS"); return -EINVAL; @@ -629,8 +632,14 @@ static int nbd_parse_blockstatus_payload(BDRVNBDState = *s, return -EINVAL; } - extent->length =3D payload_advance32(&payload); - extent->flags =3D payload_advance32(&payload); + if (wide) { + count =3D payload_advance32(&payload); + extent->length =3D payload_advance64(&payload); + extent->flags =3D payload_advance64(&payload); + } else { + extent->length =3D payload_advance32(&payload); + extent->flags =3D payload_advance32(&payload); + } if (extent->length =3D=3D 0) { error_setg(errp, "Protocol error: server sent status chunk with " @@ -670,7 +679,8 @@ static int nbd_parse_blockstatus_payload(BDRVNBDState *= s, * connection; just ignore trailing extents, and clamp things to * the length of our request. */ - if (chunk->length > sizeof(context_id) + sizeof(*extent)) { + if (count > 1 || + chunk->length > sizeof(context_id) + wide * sizeof(count) + len) { trace_nbd_parse_blockstatus_compliance("more than one extent"); } if (extent->length > orig_length) { @@ -1114,7 +1124,7 @@ static int coroutine_fn nbd_co_receive_cmdread_reply(= BDRVNBDState *s, uint64_t h static int coroutine_fn nbd_co_receive_blockstatus_reply(BDRVNBDState *s, uint64_t handle, = uint64_t length, - NBDExtent *extent, + NBDExtentExt *ext= ent, int *request_ret,= Error **errp) { NBDReplyChunkIter iter; @@ -1131,6 +1141,11 @@ static int coroutine_fn nbd_co_receive_blockstatus_r= eply(BDRVNBDState *s, assert(nbd_reply_is_structured(&reply)); switch (chunk->type) { + case NBD_REPLY_TYPE_BLOCK_STATUS_EXT: + if (!s->info.extended_headers) { + trace_nbd_extended_headers_compliance("block_status_ext"); + } + /* fallthrough */ case NBD_REPLY_TYPE_BLOCK_STATUS: if (received) { nbd_channel_error(s, -EINVAL); @@ -1139,9 +1154,10 @@ static int coroutine_fn nbd_co_receive_blockstatus_r= eply(BDRVNBDState *s, } received =3D true; - ret =3D nbd_parse_blockstatus_payload(s, &reply.structured, - payload, length, extent, - &local_err); + ret =3D nbd_parse_blockstatus_payload( + s, &reply.structured, payload, + chunk->type =3D=3D NBD_REPLY_TYPE_BLOCK_STATUS_EXT, + length, extent, &local_err); if (ret < 0) { nbd_channel_error(s, ret); nbd_iter_channel_error(&iter, ret, &local_err); @@ -1369,7 +1385,7 @@ static int coroutine_fn nbd_client_co_block_status( int64_t *pnum, int64_t *map, BlockDriverState **file) { int ret, request_ret; - NBDExtent extent =3D { 0 }; + NBDExtentExt extent =3D { 0 }; BDRVNBDState *s =3D (BDRVNBDState *)bs->opaque; Error *local_err =3D NULL; diff --git a/block/trace-events b/block/trace-events index 48dbf10c66..b84a5155a3 100644 --- a/block/trace-events +++ b/block/trace-events @@ -168,6 +168,7 @@ iscsi_xcopy(void *src_lun, uint64_t src_off, void *dst_= lun, uint64_t dst_off, ui # nbd.c nbd_parse_blockstatus_compliance(const char *err) "ignoring extra data fro= m non-compliant server: %s" nbd_structured_read_compliance(const char *type) "server sent non-complian= t unaligned read %s chunk" +nbd_extended_headers_compliance(const char *type) "server sent non-complia= nt %s chunk without extended headers" nbd_read_reply_entry_fail(int ret, const char *err) "ret =3D %d, err: %s" nbd_co_request_fail(uint64_t from, uint32_t len, uint64_t handle, uint16_t= flags, uint16_t type, const char *name, int ret, const char *err) "Request= failed { .from =3D %" PRIu64", .len =3D %" PRIu32 ", .handle =3D %" PRIu64= ", .flags =3D 0x%" PRIx16 ", .type =3D %" PRIu16 " (%s) } ret =3D %d, err:= %s" nbd_client_handshake(const char *export_name) "export '%s'" --=20 2.38.1 From nobody Fri May 10 15:25:06 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1668469039; cv=none; d=zohomail.com; s=zohoarc; b=RXT45C+j94z/bJ/Rs0ts4K0KtKcR1lTT9govnr1UPprt7sAWruWazk8cm/ISE9Wr5sfWAntSvulQEmLwmDIQxizWbxE+i8nPmh+UVyv66xyRgxxAxp4+dTjbXhMvVeDmlx90MyFnAVkTG01DWQ48mcQTQeKqGx3xbMeI1i4IkdI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1668469039; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=PZNu2AF6MBsi9Ah1ozXMZKmwajLMlwncx100VmFpWow=; b=ks7bpjbgqJF4BoYrjzMyTioG6CU4T6RXOBv8+94xzg22Cv5RakQ6zRHRzjdl2/XTPs+rU/bBeXY4QyP/xOJtV2MVh3hgsARermQZ7KUXDeS9GXOSRbcx/uZejLYWPxI/tcmqHDJvYQqw0vxC5/FF27tsHaROLEcplSSAB11kLNo= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1668469039480607.2574775656319; Mon, 14 Nov 2022 15:37:19 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ouieM-0003Mz-7K; Mon, 14 Nov 2022 18:13:58 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouidr-0001X6-Vq for qemu-devel@nongnu.org; Mon, 14 Nov 2022 18:13:28 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouiGJ-0002Op-PT for qemu-devel@nongnu.org; Mon, 14 Nov 2022 17:49:09 -0500 Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-104-EqmQR09AN4eyXcyymeTgpw-1; Mon, 14 Nov 2022 17:49:03 -0500 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 190C0811E67; Mon, 14 Nov 2022 22:49:03 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.240]) by smtp.corp.redhat.com (Postfix) with ESMTP id 7421240E42E5; Mon, 14 Nov 2022 22:49:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1668466146; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=PZNu2AF6MBsi9Ah1ozXMZKmwajLMlwncx100VmFpWow=; b=c0n6//uAQqCyTLiLdPdpPD+YSGEc4FK9h12b7Sfy3Y18wRSsktKYtyOeYSKACi2E2aHlbF w5Yh2wKfQKU7dVYyWz8xDVgjwJSz/tO925ywqWa5MlMfTBm7YK+rgSLBpKIHvug9qkc6AV 478sHh5TzNF+rNygfxHxXUAO+RWvzJo= X-MC-Unique: EqmQR09AN4eyXcyymeTgpw-1 From: Eric Blake To: qemu-devel@nongnu.org Cc: qemu-block@nongnu.org, libguestfs@redhat.com, nbd@other.debian.org, Vladimir Sementsov-Ogievskiy , Kevin Wolf , Hanna Reitz Subject: [PATCH v2 11/15] nbd/client: Request extended headers during negotiation Date: Mon, 14 Nov 2022 16:48:44 -0600 Message-Id: <20221114224848.2186298-12-eblake@redhat.com> In-Reply-To: <20221114224848.2186298-1-eblake@redhat.com> References: <20221114224141.cm5jgyxfmvie5xb5@redhat.com> <20221114224848.2186298-1-eblake@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.2 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1668469041266100001 Content-Type: text/plain; charset="utf-8" All the pieces are in place for a client to finally request extended headers. Note that we must not request extended headers when qemu-nbd is used to connect to the kernel module (as nbd.ko does not expect them), but there is no harm in all other clients requesting them. Extended headers are not essential to the information collected during 'qemu-nbd --list', but probing for it gives us one more piece of information in that output. Update the iotests affected by the new line of output. Signed-off-by: Eric Blake --- nbd/client-connection.c | 1 + nbd/client.c | 35 +++++++++++++------ qemu-nbd.c | 2 ++ tests/qemu-iotests/223.out | 6 ++++ tests/qemu-iotests/233.out | 5 +++ tests/qemu-iotests/241.out | 3 ++ tests/qemu-iotests/307.out | 5 +++ .../tests/nbd-qemu-allocation.out | 1 + 8 files changed, 48 insertions(+), 10 deletions(-) diff --git a/nbd/client-connection.c b/nbd/client-connection.c index 0c5f917efa..3576190d09 100644 --- a/nbd/client-connection.c +++ b/nbd/client-connection.c @@ -93,6 +93,7 @@ NBDClientConnection *nbd_client_connection_new(const Sock= etAddress *saddr, .initial_info.request_sizes =3D true, .initial_info.structured_reply =3D true, + .initial_info.extended_headers =3D true, .initial_info.base_allocation =3D true, .initial_info.x_dirty_bitmap =3D g_strdup(x_dirty_bitmap), .initial_info.name =3D g_strdup(export_name ?: "") diff --git a/nbd/client.c b/nbd/client.c index 70f06ce637..413304f553 100644 --- a/nbd/client.c +++ b/nbd/client.c @@ -878,12 +878,13 @@ static int nbd_list_meta_contexts(QIOChannel *ioc, * 1: server is newstyle, but can only accept EXPORT_NAME * 2: server is newstyle, but lacks structured replies * 3: server is newstyle and set up for structured replies + * 4: server is newstyle and set up for extended headers */ static int nbd_start_negotiate(AioContext *aio_context, QIOChannel *ioc, QCryptoTLSCreds *tlscreds, const char *hostname, QIOChannel **outioc, - bool structured_reply, bool *zeroes, - Error **errp) + bool structured_reply, bool ext_hdrs, + bool *zeroes, Error **errp) { ERRP_GUARD(); uint64_t magic; @@ -960,15 +961,23 @@ static int nbd_start_negotiate(AioContext *aio_contex= t, QIOChannel *ioc, if (fixedNewStyle) { int result =3D 0; - if (structured_reply) { + if (ext_hdrs) { + result =3D nbd_request_simple_option(ioc, + NBD_OPT_EXTENDED_HEADER= S, + false, errp); + if (result) { + return result < 0 ? -EINVAL : 4; + } + } + if (structured_reply && !result) { result =3D nbd_request_simple_option(ioc, NBD_OPT_STRUCTURED_REPL= Y, false, errp); - if (result < 0) { - return -EINVAL; + if (result) { + return result < 0 ? -EINVAL : 3; } } - return 2 + result; + return 2; } else { return 1; } @@ -1030,7 +1039,8 @@ int nbd_receive_negotiate(AioContext *aio_context, QI= OChannel *ioc, trace_nbd_receive_negotiate_name(info->name); result =3D nbd_start_negotiate(aio_context, ioc, tlscreds, hostname, o= utioc, - info->structured_reply, &zeroes, errp); + info->structured_reply, + info->extended_headers, &zeroes, errp); info->structured_reply =3D false; info->extended_headers =3D false; @@ -1040,6 +1050,9 @@ int nbd_receive_negotiate(AioContext *aio_context, QI= OChannel *ioc, } switch (result) { + case 4: /* newstyle, with extended headers */ + info->extended_headers =3D true; + /* fall through */ case 3: /* newstyle, with structured replies */ info->structured_reply =3D true; if (base_allocation) { @@ -1151,7 +1164,7 @@ int nbd_receive_export_list(QIOChannel *ioc, QCryptoT= LSCreds *tlscreds, *info =3D NULL; result =3D nbd_start_negotiate(NULL, ioc, tlscreds, hostname, &sioc, t= rue, - NULL, errp); + true, NULL, errp); if (tlscreds && sioc) { ioc =3D sioc; } @@ -1159,6 +1172,7 @@ int nbd_receive_export_list(QIOChannel *ioc, QCryptoT= LSCreds *tlscreds, switch (result) { case 2: case 3: + case 4: /* newstyle - use NBD_OPT_LIST to populate array, then try * NBD_OPT_INFO on each array member. If structured replies * are enabled, also try NBD_OPT_LIST_META_CONTEXT. */ @@ -1179,7 +1193,8 @@ int nbd_receive_export_list(QIOChannel *ioc, QCryptoT= LSCreds *tlscreds, memset(&array[count - 1], 0, sizeof(*array)); array[count - 1].name =3D name; array[count - 1].description =3D desc; - array[count - 1].structured_reply =3D result =3D=3D 3; + array[count - 1].structured_reply =3D result >=3D 3; + array[count - 1].extended_headers =3D result >=3D 4; } for (i =3D 0; i < count; i++) { @@ -1195,7 +1210,7 @@ int nbd_receive_export_list(QIOChannel *ioc, QCryptoT= LSCreds *tlscreds, break; } - if (result =3D=3D 3 && + if (result >=3D 3 && nbd_list_meta_contexts(ioc, &array[i], errp) < 0) { goto out; } diff --git a/qemu-nbd.c b/qemu-nbd.c index 0cd5aa6f02..9404164487 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -238,6 +238,8 @@ static int qemu_nbd_client_list(SocketAddress *saddr, Q= CryptoTLSCreds *tls, printf(" opt block: %u\n", list[i].opt_block); printf(" max block: %u\n", list[i].max_block); } + printf(" transaction size: %s\n", + list[i].extended_headers ? "64-bit" : "32-bit"); if (list[i].n_contexts) { printf(" available meta contexts: %d\n", list[i].n_contexts); for (j =3D 0; j < list[i].n_contexts; j++) { diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out index 26fb347c5d..b98582c38e 100644 --- a/tests/qemu-iotests/223.out +++ b/tests/qemu-iotests/223.out @@ -87,6 +87,7 @@ exports available: 3 min block: 1 opt block: 4096 max block: 33554432 + transaction size: 64-bit available meta contexts: 2 base:allocation qemu:dirty-bitmap:b @@ -97,6 +98,7 @@ exports available: 3 min block: 1 opt block: 4096 max block: 33554432 + transaction size: 64-bit available meta contexts: 2 base:allocation qemu:dirty-bitmap:b2 @@ -106,6 +108,7 @@ exports available: 3 min block: 1 opt block: 4096 max block: 33554432 + transaction size: 64-bit available meta contexts: 2 base:allocation qemu:dirty-bitmap:b3 @@ -206,6 +209,7 @@ exports available: 3 min block: 1 opt block: 4096 max block: 33554432 + transaction size: 64-bit available meta contexts: 2 base:allocation qemu:dirty-bitmap:b @@ -216,6 +220,7 @@ exports available: 3 min block: 1 opt block: 4096 max block: 33554432 + transaction size: 64-bit available meta contexts: 2 base:allocation qemu:dirty-bitmap:b2 @@ -225,6 +230,7 @@ exports available: 3 min block: 1 opt block: 4096 max block: 33554432 + transaction size: 64-bit available meta contexts: 2 base:allocation qemu:dirty-bitmap:b3 diff --git a/tests/qemu-iotests/233.out b/tests/qemu-iotests/233.out index 237c82767e..33cb622ecf 100644 --- a/tests/qemu-iotests/233.out +++ b/tests/qemu-iotests/233.out @@ -53,6 +53,11 @@ exports available: 1 export: '' size: 67108864 min block: 1 + opt block: 4096 + max block: 33554432 + transaction size: 64-bit + available meta contexts: 1 + base:allocation =3D=3D check TLS with different CA fails =3D=3D qemu-img: Could not open 'driver=3Dnbd,host=3D127.0.0.1,port=3DPORT,tls-cr= eds=3Dtls0': The certificate hasn't got a known issuer diff --git a/tests/qemu-iotests/241.out b/tests/qemu-iotests/241.out index 88e8cfcd7e..a9efb87652 100644 --- a/tests/qemu-iotests/241.out +++ b/tests/qemu-iotests/241.out @@ -6,6 +6,7 @@ exports available: 1 export: '' size: 1024 min block: 1 + transaction size: 64-bit [{ "start": 0, "length": 1000, "depth": 0, "present": true, "zero": false,= "data": true, "offset": OFFSET}, { "start": 1000, "length": 24, "depth": 0, "present": true, "zero": true, = "data": false, "offset": OFFSET}] 1 KiB (0x400) bytes allocated at offset 0 bytes (0x0) @@ -16,6 +17,7 @@ exports available: 1 export: '' size: 1024 min block: 512 + transaction size: 64-bit [{ "start": 0, "length": 1024, "depth": 0, "present": true, "zero": false,= "data": true, "offset": OFFSET}] 1 KiB (0x400) bytes allocated at offset 0 bytes (0x0) WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing g= uessed raw. @@ -28,6 +30,7 @@ exports available: 1 export: '' size: 1024 min block: 1 + transaction size: 64-bit [{ "start": 0, "length": 1000, "depth": 0, "present": true, "zero": false,= "data": true, "offset": OFFSET}, { "start": 1000, "length": 24, "depth": 0, "present": true, "zero": true, = "data": false, "offset": OFFSET}] 1 KiB (0x400) bytes allocated at offset 0 bytes (0x0) diff --git a/tests/qemu-iotests/307.out b/tests/qemu-iotests/307.out index 390f05d1b7..2b9a6a67a1 100644 --- a/tests/qemu-iotests/307.out +++ b/tests/qemu-iotests/307.out @@ -19,6 +19,7 @@ exports available: 1 min block: XXX opt block: XXX max block: XXX + transaction size: 64-bit available meta contexts: 1 base:allocation @@ -47,6 +48,7 @@ exports available: 1 min block: XXX opt block: XXX max block: XXX + transaction size: 64-bit available meta contexts: 1 base:allocation @@ -78,6 +80,7 @@ exports available: 2 min block: XXX opt block: XXX max block: XXX + transaction size: 64-bit available meta contexts: 1 base:allocation export: 'export1' @@ -87,6 +90,7 @@ exports available: 2 min block: XXX opt block: XXX max block: XXX + transaction size: 64-bit available meta contexts: 1 base:allocation @@ -113,6 +117,7 @@ exports available: 1 min block: XXX opt block: XXX max block: XXX + transaction size: 64-bit available meta contexts: 1 base:allocation diff --git a/tests/qemu-iotests/tests/nbd-qemu-allocation.out b/tests/qemu-= iotests/tests/nbd-qemu-allocation.out index 9d938db24e..659276032b 100644 --- a/tests/qemu-iotests/tests/nbd-qemu-allocation.out +++ b/tests/qemu-iotests/tests/nbd-qemu-allocation.out @@ -21,6 +21,7 @@ exports available: 1 min block: 1 opt block: 4096 max block: 33554432 + transaction size: 64-bit available meta contexts: 2 base:allocation qemu:allocation-depth --=20 2.38.1 From nobody Fri May 10 15:25:06 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1668472359; cv=none; d=zohomail.com; s=zohoarc; b=bSuOyTDqLkOcX7oivGaLlAvO6IqbCfD6rZO3D4QaTOxtt7UtTiKeagLI9puc9p/C7JSjfhSlazjosFHu2TgWLq3QUlXc/M32dgSJ/QwkfMZpTX7RZhF/AwKLdCZJsHP1iTdXUnFKd8y7j3vGr5/F08NUqLfrzHhnGt/lNDJd+nI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1668472359; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=XyzxNnPOskLIUQT0IYlcm+4U9bzcrXQAt9wSC9NhVmI=; b=dKaWRgjWWz5z+jD2NVKhusqYzzlRaMN95cVQ72vUkR/H3fCK0jxK4F8h9a+asqNgGBRXsqgAj3iGBdDs8vggsg7jpoIPAAvrpOw46+dKOHkgeFZzwSq61cAHw8t5dN6tOm7RrT6Rtuo3THfAMysDQN/nFLA5R8eXX4yD1nQRXg0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1668472359729473.829981528192; Mon, 14 Nov 2022 16:32:39 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ouie6-0002Qt-O3; Mon, 14 Nov 2022 18:13:42 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouidr-0001hU-6l for qemu-devel@nongnu.org; Mon, 14 Nov 2022 18:13:27 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouiGM-0002Pq-9v for qemu-devel@nongnu.org; Mon, 14 Nov 2022 17:49:12 -0500 Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-631-MElPXoAmM-2NVGbsZaveEQ-1; Mon, 14 Nov 2022 17:49:04 -0500 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id DDF7B1C0878D; Mon, 14 Nov 2022 22:49:03 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.240]) by smtp.corp.redhat.com (Postfix) with ESMTP id 48CD140E42EF; Mon, 14 Nov 2022 22:49:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1668466149; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=XyzxNnPOskLIUQT0IYlcm+4U9bzcrXQAt9wSC9NhVmI=; b=ShKMFgve7yckXHNcwDGuQcLKfJExKwA4DlzT5AU1ry5o0T5BEjT2wvBRsv3u3ykjcitDlm pcY9nF5i8PX6XDf7c1fxXvuaRN5WBip+sgSNW+DvWlMOk2RFA75wrg11njcRVZRuwycdB4 dNet9eUW+YaNzxjZNezc15BRdLBilew= X-MC-Unique: MElPXoAmM-2NVGbsZaveEQ-1 From: Eric Blake To: qemu-devel@nongnu.org Cc: qemu-block@nongnu.org, libguestfs@redhat.com, nbd@other.debian.org, Vladimir Sementsov-Ogievskiy , Kevin Wolf , Hanna Reitz Subject: [PATCH v2 12/15] nbd/server: Prepare for per-request filtering of BLOCK_STATUS Date: Mon, 14 Nov 2022 16:48:45 -0600 Message-Id: <20221114224848.2186298-13-eblake@redhat.com> In-Reply-To: <20221114224848.2186298-1-eblake@redhat.com> References: <20221114224141.cm5jgyxfmvie5xb5@redhat.com> <20221114224848.2186298-1-eblake@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.2 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1668472361205100003 Content-Type: text/plain; charset="utf-8" The next commit will add support for the new addition of NBD_CMD_FLAG_PAYLOAD during NBD_CMD_BLOCK_STATUS, where the client can request that the server only return a subset of negotiated contexts, rather than all contexts. To make that task easier, this patch populates the list of contexts to return on a per-command basis (for now, identical to the full set of negotiated contexts). Signed-off-by: Eric Blake --- include/block/nbd.h | 20 +++++++- nbd/server.c | 108 +++++++++++++++++++++++--------------------- 2 files changed, 75 insertions(+), 53 deletions(-) diff --git a/include/block/nbd.h b/include/block/nbd.h index 02e31b2261..9a8ac1c8a5 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -50,8 +50,23 @@ typedef struct NBDOptionReplyMetaContext { /* metadata context name follows */ } QEMU_PACKED NBDOptionReplyMetaContext; -/* Transmission phase structs - * +/* Transmission phase structs */ + +/* + * NBDMetaContexts represents a list of meta contexts in use, as + * selected by NBD_OPT_SET_META_CONTEXT. Also used for + * NBD_OPT_LIST_META_CONTEXT, and payload filtering in + * NBD_CMD_BLOCK_STATUS. + */ +typedef struct NBDMetaContexts { + size_t count; /* number of negotiated contexts */ + bool base_allocation; /* export base:allocation context (block status)= */ + bool allocation_depth; /* export qemu:allocation-depth */ + size_t nr_bitmaps; /* Length of bitmaps array */ + bool *bitmaps; /* export qemu:dirty-bitmap: */ +} NBDMetaContexts; + +/* * Note: NBDRequest is _NOT_ the same as the network representation of an = NBD * request! */ @@ -61,6 +76,7 @@ typedef struct NBDRequest { uint64_t len; /* Effect length; 32 bit limit without extended header= s */ uint16_t flags; /* NBD_CMD_FLAG_* */ uint16_t type; /* NBD_CMD_* */ + NBDMetaContexts contexts; /* Used by NBD_CMD_BLOCK_STATUS */ } NBDRequest; typedef struct NBDSimpleReply { diff --git a/nbd/server.c b/nbd/server.c index f21f8098c1..1fd1f32028 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -103,20 +103,6 @@ struct NBDExport { static QTAILQ_HEAD(, NBDExport) exports =3D QTAILQ_HEAD_INITIALIZER(export= s); -/* NBDExportMetaContexts represents a list of contexts to be exported, - * as selected by NBD_OPT_SET_META_CONTEXT. Also used for - * NBD_OPT_LIST_META_CONTEXT. */ -typedef struct NBDExportMetaContexts { - NBDExport *exp; - size_t count; /* number of negotiated contexts */ - bool base_allocation; /* export base:allocation context (block status)= */ - bool allocation_depth; /* export qemu:allocation-depth */ - bool *bitmaps; /* - * export qemu:dirty-bitmap:, - * sized by exp->nr_export_bitmaps - */ -} NBDExportMetaContexts; - struct NBDClient { int refcount; void (*close_fn)(NBDClient *client, bool negotiated); @@ -143,7 +129,8 @@ struct NBDClient { bool structured_reply; /* also set true if extended_headers is set */ bool extended_headers; - NBDExportMetaContexts export_meta; + NBDExport *context_exp; /* export of last OPT_SET_META_CONTEXT */ + NBDMetaContexts contexts; /* Negotiated meta contexts */ uint32_t opt; /* Current option being negotiated */ uint32_t optlen; /* remaining length of data in ioc for the option bei= ng @@ -456,8 +443,8 @@ static int nbd_negotiate_handle_list(NBDClient *client,= Error **errp) static void nbd_check_meta_export(NBDClient *client) { - if (client->exp !=3D client->export_meta.exp) { - client->export_meta.count =3D 0; + if (client->exp !=3D client->context_exp) { + client->contexts.count =3D 0; } } @@ -847,7 +834,7 @@ static bool nbd_strshift(const char **str, const char *= prefix) * Handle queries to 'base' namespace. For now, only the base:allocation * context is available. Return true if @query has been handled. */ -static bool nbd_meta_base_query(NBDClient *client, NBDExportMetaContexts *= meta, +static bool nbd_meta_base_query(NBDClient *client, NBDMetaContexts *meta, const char *query) { if (!nbd_strshift(&query, "base:")) { @@ -867,8 +854,8 @@ static bool nbd_meta_base_query(NBDClient *client, NBDE= xportMetaContexts *meta, * and qemu:allocation-depth contexts are available. Return true if @query * has been handled. */ -static bool nbd_meta_qemu_query(NBDClient *client, NBDExportMetaContexts *= meta, - const char *query) +static bool nbd_meta_qemu_query(NBDClient *client, NBDExport *exp, + NBDMetaContexts *meta, const char *query) { size_t i; @@ -879,9 +866,9 @@ static bool nbd_meta_qemu_query(NBDClient *client, NBDE= xportMetaContexts *meta, if (!*query) { if (client->opt =3D=3D NBD_OPT_LIST_META_CONTEXT) { - meta->allocation_depth =3D meta->exp->allocation_depth; - if (meta->exp->nr_export_bitmaps) { - memset(meta->bitmaps, 1, meta->exp->nr_export_bitmaps); + meta->allocation_depth =3D exp->allocation_depth; + if (meta->nr_bitmaps) { + memset(meta->bitmaps, 1, meta->nr_bitmaps); } } trace_nbd_negotiate_meta_query_parse("empty"); @@ -890,7 +877,7 @@ static bool nbd_meta_qemu_query(NBDClient *client, NBDE= xportMetaContexts *meta, if (strcmp(query, "allocation-depth") =3D=3D 0) { trace_nbd_negotiate_meta_query_parse("allocation-depth"); - meta->allocation_depth =3D meta->exp->allocation_depth; + meta->allocation_depth =3D exp->allocation_depth; return true; } @@ -898,17 +885,17 @@ static bool nbd_meta_qemu_query(NBDClient *client, NB= DExportMetaContexts *meta, trace_nbd_negotiate_meta_query_parse("dirty-bitmap:"); if (!*query) { if (client->opt =3D=3D NBD_OPT_LIST_META_CONTEXT && - meta->exp->nr_export_bitmaps) { - memset(meta->bitmaps, 1, meta->exp->nr_export_bitmaps); + exp->nr_export_bitmaps) { + memset(meta->bitmaps, 1, exp->nr_export_bitmaps); } trace_nbd_negotiate_meta_query_parse("empty"); return true; } - for (i =3D 0; i < meta->exp->nr_export_bitmaps; i++) { + for (i =3D 0; i < meta->nr_bitmaps; i++) { const char *bm_name; - bm_name =3D bdrv_dirty_bitmap_name(meta->exp->export_bitmaps[i= ]); + bm_name =3D bdrv_dirty_bitmap_name(exp->export_bitmaps[i]); if (strcmp(bm_name, query) =3D=3D 0) { meta->bitmaps[i] =3D true; trace_nbd_negotiate_meta_query_parse(query); @@ -932,8 +919,8 @@ static bool nbd_meta_qemu_query(NBDClient *client, NBDE= xportMetaContexts *meta, * * Return -errno on I/O error, 0 if option was completely handled by * sending a reply about inconsistent lengths, or 1 on success. */ -static int nbd_negotiate_meta_query(NBDClient *client, - NBDExportMetaContexts *meta, Error **e= rrp) +static int nbd_negotiate_meta_query(NBDClient *client, NBDExport *exp, + NBDMetaContexts *meta, Error **errp) { int ret; g_autofree char *query =3D NULL; @@ -960,7 +947,7 @@ static int nbd_negotiate_meta_query(NBDClient *client, if (nbd_meta_base_query(client, meta, query)) { return 1; } - if (nbd_meta_qemu_query(client, meta, query)) { + if (nbd_meta_qemu_query(client, exp, meta, query)) { return 1; } @@ -972,14 +959,15 @@ static int nbd_negotiate_meta_query(NBDClient *client, * Handle NBD_OPT_LIST_META_CONTEXT and NBD_OPT_SET_META_CONTEXT * * Return -errno on I/O error, or 0 if option was completely handled. */ -static int nbd_negotiate_meta_queries(NBDClient *client, - NBDExportMetaContexts *meta, Error *= *errp) +static int nbd_negotiate_meta_queries(NBDClient *client, Error **errp) { int ret; g_autofree char *export_name =3D NULL; /* Mark unused to work around https://bugs.llvm.org/show_bug.cgi?id=3D= 3888 */ g_autofree G_GNUC_UNUSED bool *bitmaps =3D NULL; - NBDExportMetaContexts local_meta =3D {0}; + NBDMetaContexts local_meta =3D {0}; + NBDMetaContexts *meta; + NBDExport *exp; uint32_t nb_queries; size_t i; size_t count =3D 0; @@ -994,6 +982,9 @@ static int nbd_negotiate_meta_queries(NBDClient *client, if (client->opt =3D=3D NBD_OPT_LIST_META_CONTEXT) { /* Only change the caller's meta on SET. */ meta =3D &local_meta; + } else { + meta =3D &client->contexts; + client->context_exp =3D NULL; } g_free(meta->bitmaps); @@ -1004,14 +995,15 @@ static int nbd_negotiate_meta_queries(NBDClient *cli= ent, return ret; } - meta->exp =3D nbd_export_find(export_name); - if (meta->exp =3D=3D NULL) { + exp =3D nbd_export_find(export_name); + if (exp =3D=3D NULL) { g_autofree char *sane_name =3D nbd_sanitize_name(export_name); return nbd_opt_drop(client, NBD_REP_ERR_UNKNOWN, errp, "export '%s' not present", sane_name); } - meta->bitmaps =3D g_new0(bool, meta->exp->nr_export_bitmaps); + meta->nr_bitmaps =3D exp->nr_export_bitmaps; + meta->bitmaps =3D g_new0(bool, exp->nr_export_bitmaps); if (client->opt =3D=3D NBD_OPT_LIST_META_CONTEXT) { bitmaps =3D meta->bitmaps; } @@ -1027,13 +1019,13 @@ static int nbd_negotiate_meta_queries(NBDClient *cl= ient, if (client->opt =3D=3D NBD_OPT_LIST_META_CONTEXT && !nb_queries) { /* enable all known contexts */ meta->base_allocation =3D true; - meta->allocation_depth =3D meta->exp->allocation_depth; - if (meta->exp->nr_export_bitmaps) { - memset(meta->bitmaps, 1, meta->exp->nr_export_bitmaps); + meta->allocation_depth =3D exp->allocation_depth; + if (exp->nr_export_bitmaps) { + memset(meta->bitmaps, 1, meta->nr_bitmaps); } } else { for (i =3D 0; i < nb_queries; ++i) { - ret =3D nbd_negotiate_meta_query(client, meta, errp); + ret =3D nbd_negotiate_meta_query(client, exp, meta, errp); if (ret <=3D 0) { return ret; } @@ -1060,7 +1052,7 @@ static int nbd_negotiate_meta_queries(NBDClient *clie= nt, count++; } - for (i =3D 0; i < meta->exp->nr_export_bitmaps; i++) { + for (i =3D 0; i < meta->nr_bitmaps; i++) { const char *bm_name; g_autofree char *context =3D NULL; @@ -1068,7 +1060,7 @@ static int nbd_negotiate_meta_queries(NBDClient *clie= nt, continue; } - bm_name =3D bdrv_dirty_bitmap_name(meta->exp->export_bitmaps[i]); + bm_name =3D bdrv_dirty_bitmap_name(exp->export_bitmaps[i]); context =3D g_strdup_printf("qemu:dirty-bitmap:%s", bm_name); ret =3D nbd_negotiate_send_meta_context(client, context, @@ -1083,6 +1075,9 @@ static int nbd_negotiate_meta_queries(NBDClient *clie= nt, ret =3D nbd_negotiate_send_rep(client, NBD_REP_ACK, errp); if (ret =3D=3D 0) { meta->count =3D count; + if (client->opt =3D=3D NBD_OPT_SET_META_CONTEXT) { + client->context_exp =3D exp; + } } return ret; @@ -1276,8 +1271,7 @@ static int nbd_negotiate_options(NBDClient *client, E= rror **errp) case NBD_OPT_LIST_META_CONTEXT: case NBD_OPT_SET_META_CONTEXT: - ret =3D nbd_negotiate_meta_queries(client, &client->export= _meta, - errp); + ret =3D nbd_negotiate_meta_queries(client, errp); break; case NBD_OPT_EXTENDED_HEADERS: @@ -1508,7 +1502,7 @@ void nbd_client_put(NBDClient *client) QTAILQ_REMOVE(&client->exp->clients, client, next); blk_exp_unref(&client->exp->common); } - g_free(client->export_meta.bitmaps); + g_free(client->contexts.bitmaps); g_free(client); } } @@ -2479,6 +2473,8 @@ static int nbd_co_receive_request(NBDRequestData *req= , NBDRequest *request, return -ENOMEM; } } + } else if (request->type =3D=3D NBD_CMD_BLOCK_STATUS) { + request->contexts =3D client->contexts; } if (payload_len) { @@ -2702,11 +2698,11 @@ static coroutine_fn int nbd_handle_request(NBDClien= t *client, "need non-zero length", errp); } assert(client->extended_headers || request->len <=3D UINT32_MAX); - if (client->export_meta.count) { + if (request->contexts.count) { bool dont_fragment =3D request->flags & NBD_CMD_FLAG_REQ_ONE; - int contexts_remaining =3D client->export_meta.count; + int contexts_remaining =3D request->contexts.count; - if (client->export_meta.base_allocation) { + if (request->contexts.base_allocation) { ret =3D nbd_co_send_block_status(client, request, blk_bs(exp->common.blk), request->from, @@ -2719,7 +2715,7 @@ static coroutine_fn int nbd_handle_request(NBDClient = *client, } } - if (client->export_meta.allocation_depth) { + if (request->contexts.allocation_depth) { ret =3D nbd_co_send_block_status(client, request, blk_bs(exp->common.blk), request->from, request->len, @@ -2732,8 +2728,10 @@ static coroutine_fn int nbd_handle_request(NBDClient= *client, } } + assert(request->contexts.nr_bitmaps =3D=3D + client->exp->nr_export_bitmaps); for (i =3D 0; i < client->exp->nr_export_bitmaps; i++) { - if (!client->export_meta.bitmaps[i]) { + if (!request->contexts.bitmaps[i]) { continue; } ret =3D nbd_co_send_bitmap(client, request, @@ -2749,6 +2747,10 @@ static coroutine_fn int nbd_handle_request(NBDClient= *client, assert(!contexts_remaining); return 0; + } else if (client->contexts.count) { + return nbd_send_generic_reply(client, request, -EINVAL, + "CMD_BLOCK_STATUS payload not va= lid", + errp); } else { return nbd_send_generic_reply(client, request, -EINVAL, "CMD_BLOCK_STATUS not negotiated= ", @@ -2825,6 +2827,10 @@ static coroutine_fn void nbd_trip(void *opaque) } else { ret =3D nbd_handle_request(client, &request, req->data, &local_err= ); } + if (request.type =3D=3D NBD_CMD_BLOCK_STATUS && + request.contexts.bitmaps !=3D client->contexts.bitmaps) { + g_free(request.contexts.bitmaps); + } if (ret < 0) { error_prepend(&local_err, "Failed to send reply: "); goto disconnect; --=20 2.38.1 From nobody Fri May 10 15:25:06 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1668472337; cv=none; d=zohomail.com; s=zohoarc; b=PZmnDTMxFkiNt2sEOgmtp8FNZUyKXldV8i5K4+aaphxHMuKSYT9TjX5jTMc8DyRdAtb5tEXba/Ez4XnL9LfqevEoWTU3RmEHBPjvgJ+R+0vQ5EjnKga0gfi7xZHkTEdcuh+Aa5208uuvkZknSXpZnWGkTwqE2aWoNk0M95lWrHg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1668472337; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=c7SMkdLnmr8zQDA/YEAOaatXmRMb68RmmXxsoqFCaBY=; b=k8Za4WvCkJMaa0ot6eglsvcBstO6O2uEfTCja8+8lUudG97M2o5Ul2Qyzrx49JT7l6Q2/95E2soq0RKg90FtIFXf7H4xH5o5UQVSVo1xNQu12JjEIeaNBeH5Y6KwaXzKIzCz3ps5DPs8Kuj3lJMWPeupnAev0OB3L0XNoZIV5aY= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1668472337228127.9136243039884; Mon, 14 Nov 2022 16:32:17 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ouie6-0002QQ-JK; Mon, 14 Nov 2022 18:13:42 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouidr-0001df-IM for qemu-devel@nongnu.org; Mon, 14 Nov 2022 18:13:27 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouiGL-0002PN-2S for qemu-devel@nongnu.org; Mon, 14 Nov 2022 17:49:11 -0500 Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-593-1zK3yDK6OMyfoYX5N6GVJg-1; Mon, 14 Nov 2022 17:49:05 -0500 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id C724C3C0DDDB; Mon, 14 Nov 2022 22:49:04 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.240]) by smtp.corp.redhat.com (Postfix) with ESMTP id 2E07E40E42E3; Mon, 14 Nov 2022 22:49:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1668466148; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=c7SMkdLnmr8zQDA/YEAOaatXmRMb68RmmXxsoqFCaBY=; b=Uy1mFv+iwV/gtyp6jAWSTzmgpNEYu9QmcFUW/CaltOrvkOAF4kkRT+PwliZFf/KAIvgWnF SSN3fn8PtkxlKUck1RwXq0ZnPnckgH1K6DU8mUK2LHOOapxga6Mp/JhQSYVrhoarSS+ULZ 9UBgw8J5BWx0m7cslqLsz8rmjLmSevs= X-MC-Unique: 1zK3yDK6OMyfoYX5N6GVJg-1 From: Eric Blake To: qemu-devel@nongnu.org Cc: qemu-block@nongnu.org, libguestfs@redhat.com, nbd@other.debian.org, Vladimir Sementsov-Ogievskiy , Kevin Wolf , Hanna Reitz Subject: [PATCH v2 13/15] nbd/server: Add FLAG_PAYLOAD support to CMD_BLOCK_STATUS Date: Mon, 14 Nov 2022 16:48:46 -0600 Message-Id: <20221114224848.2186298-14-eblake@redhat.com> In-Reply-To: <20221114224848.2186298-1-eblake@redhat.com> References: <20221114224141.cm5jgyxfmvie5xb5@redhat.com> <20221114224848.2186298-1-eblake@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.2 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1668472339093100003 Content-Type: text/plain; charset="utf-8" Allow a client to request a subset of negotiated meta contexts. For example, a client may ask to use a single connection to learn about both block status and dirty bitmaps, but where the dirty bitmap queries only need to be performed on a subset of the disk; forcing the server to compute that information on block status queries in the rest of the disk is wasted effort (both at the server, and on the amount of traffic sent over the wire to be parsed and ignored by the client). Qemu as an NBD client never requests to use more than one meta context, so it has no need to use block status payloads. Testing this instead requires support from libnbd, which CAN access multiple meta contexts in parallel from a single NBD connection; an interop test submitted to the libnbd project at the same time as this patch demonstrates the feature working, as well as testing some corner cases (for example, when the payload length is longer than the export length), although other corner cases (like passing the same id duplicated) requires a protocol fuzzer because libnbd is not wired up to break the protocol that badly. This also includes tweaks to 'qemu-nbd --list' to show when a server is advertising the capability, and to the testsuite to reflect the addition to that output. Signed-off-by: Eric Blake --- docs/interop/nbd.txt | 2 +- include/block/nbd.h | 32 ++++-- nbd/server.c | 106 +++++++++++++++++- qemu-nbd.c | 1 + nbd/trace-events | 1 + tests/qemu-iotests/223.out | 12 +- tests/qemu-iotests/307.out | 10 +- .../tests/nbd-qemu-allocation.out | 2 +- 8 files changed, 136 insertions(+), 30 deletions(-) diff --git a/docs/interop/nbd.txt b/docs/interop/nbd.txt index 988c072697..b7893043a3 100644 --- a/docs/interop/nbd.txt +++ b/docs/interop/nbd.txt @@ -69,4 +69,4 @@ NBD_CMD_BLOCK_STATUS for "qemu:dirty-bitmap:", NBD_CMD_CA= CHE NBD_CMD_FLAG_FAST_ZERO * 5.2: NBD_CMD_BLOCK_STATUS for "qemu:allocation-depth" * 7.1: NBD_FLAG_CAN_MULTI_CONN for shareable writable exports -* 7.2: NBD_OPT_EXTENDED_HEADERS +* 7.2: NBD_OPT_EXTENDED_HEADERS, NBD_FLAG_BLOCK_STATUS_PAYLOAD diff --git a/include/block/nbd.h b/include/block/nbd.h index 9a8ac1c8a5..2a65c606c9 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -167,6 +167,12 @@ typedef struct NBDExtentExt { uint64_t flags; /* NBD_STATE_* */ } QEMU_PACKED NBDExtentExt; +/* Client payload for limiting NBD_CMD_BLOCK_STATUS reply */ +typedef struct NBDBlockStatusPayload { + uint64_t effect_length; + /* uint32_t ids[] follows, array length implied by header */ +} QEMU_PACKED NBDBlockStatusPayload; + /* Transmission (export) flags: sent from server to client during handshak= e, but describe what will happen during transmission */ enum { @@ -183,20 +189,22 @@ enum { NBD_FLAG_SEND_RESIZE_BIT =3D 9, /* Send resize */ NBD_FLAG_SEND_CACHE_BIT =3D 10, /* Send CACHE (prefetch) */ NBD_FLAG_SEND_FAST_ZERO_BIT =3D 11, /* FAST_ZERO flag for WRITE_ZE= ROES */ + NBD_FLAG_BLOCK_STAT_PAYLOAD_BIT =3D 12, /* PAYLOAD flag for BLOCK_STAT= US */ }; -#define NBD_FLAG_HAS_FLAGS (1 << NBD_FLAG_HAS_FLAGS_BIT) -#define NBD_FLAG_READ_ONLY (1 << NBD_FLAG_READ_ONLY_BIT) -#define NBD_FLAG_SEND_FLUSH (1 << NBD_FLAG_SEND_FLUSH_BIT) -#define NBD_FLAG_SEND_FUA (1 << NBD_FLAG_SEND_FUA_BIT) -#define NBD_FLAG_ROTATIONAL (1 << NBD_FLAG_ROTATIONAL_BIT) -#define NBD_FLAG_SEND_TRIM (1 << NBD_FLAG_SEND_TRIM_BIT) -#define NBD_FLAG_SEND_WRITE_ZEROES (1 << NBD_FLAG_SEND_WRITE_ZEROES_BIT) -#define NBD_FLAG_SEND_DF (1 << NBD_FLAG_SEND_DF_BIT) -#define NBD_FLAG_CAN_MULTI_CONN (1 << NBD_FLAG_CAN_MULTI_CONN_BIT) -#define NBD_FLAG_SEND_RESIZE (1 << NBD_FLAG_SEND_RESIZE_BIT) -#define NBD_FLAG_SEND_CACHE (1 << NBD_FLAG_SEND_CACHE_BIT) -#define NBD_FLAG_SEND_FAST_ZERO (1 << NBD_FLAG_SEND_FAST_ZERO_BIT) +#define NBD_FLAG_HAS_FLAGS (1 << NBD_FLAG_HAS_FLAGS_BIT) +#define NBD_FLAG_READ_ONLY (1 << NBD_FLAG_READ_ONLY_BIT) +#define NBD_FLAG_SEND_FLUSH (1 << NBD_FLAG_SEND_FLUSH_BIT) +#define NBD_FLAG_SEND_FUA (1 << NBD_FLAG_SEND_FUA_BIT) +#define NBD_FLAG_ROTATIONAL (1 << NBD_FLAG_ROTATIONAL_BIT) +#define NBD_FLAG_SEND_TRIM (1 << NBD_FLAG_SEND_TRIM_BIT) +#define NBD_FLAG_SEND_WRITE_ZEROES (1 << NBD_FLAG_SEND_WRITE_ZEROES_BIT) +#define NBD_FLAG_SEND_DF (1 << NBD_FLAG_SEND_DF_BIT) +#define NBD_FLAG_CAN_MULTI_CONN (1 << NBD_FLAG_CAN_MULTI_CONN_BIT) +#define NBD_FLAG_SEND_RESIZE (1 << NBD_FLAG_SEND_RESIZE_BIT) +#define NBD_FLAG_SEND_CACHE (1 << NBD_FLAG_SEND_CACHE_BIT) +#define NBD_FLAG_SEND_FAST_ZERO (1 << NBD_FLAG_SEND_FAST_ZERO_BIT) +#define NBD_FLAG_BLOCK_STAT_PAYLOAD (1 << NBD_FLAG_BLOCK_STAT_PAYLOAD_BIT) /* New-style handshake (global) flags, sent from server to client, and control what will happen during handshake phase. */ diff --git a/nbd/server.c b/nbd/server.c index 1fd1f32028..cd280f1721 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -441,9 +441,9 @@ static int nbd_negotiate_handle_list(NBDClient *client,= Error **errp) return nbd_negotiate_send_rep(client, NBD_REP_ACK, errp); } -static void nbd_check_meta_export(NBDClient *client) +static void nbd_check_meta_export(NBDClient *client, NBDExport *exp) { - if (client->exp !=3D client->context_exp) { + if (exp !=3D client->context_exp) { client->contexts.count =3D 0; } } @@ -486,11 +486,15 @@ static int nbd_negotiate_handle_export_name(NBDClient= *client, bool no_zeroes, error_setg(errp, "export not found"); return -EINVAL; } + nbd_check_meta_export(client, client->exp); myflags =3D client->exp->nbdflags; if (client->structured_reply) { myflags |=3D NBD_FLAG_SEND_DF; } + if (client->extended_headers && client->contexts.count) { + myflags |=3D NBD_FLAG_BLOCK_STAT_PAYLOAD; + } trace_nbd_negotiate_new_style_size_flags(client->exp->size, myflags); stq_be_p(buf, client->exp->size); stw_be_p(buf + 8, myflags); @@ -503,7 +507,6 @@ static int nbd_negotiate_handle_export_name(NBDClient *= client, bool no_zeroes, QTAILQ_INSERT_TAIL(&client->exp->clients, client, next); blk_exp_ref(&client->exp->common); - nbd_check_meta_export(client); return 0; } @@ -623,6 +626,9 @@ static int nbd_negotiate_handle_info(NBDClient *client,= Error **errp) errp, "export '%s' not present", sane_name); } + if (client->opt =3D=3D NBD_OPT_GO) { + nbd_check_meta_export(client, exp); + } /* Don't bother sending NBD_INFO_NAME unless client requested it */ if (sendname) { @@ -676,6 +682,10 @@ static int nbd_negotiate_handle_info(NBDClient *client= , Error **errp) if (client->structured_reply) { myflags |=3D NBD_FLAG_SEND_DF; } + if (client->extended_headers && + (client->contexts.count || client->opt =3D=3D NBD_OPT_INFO)) { + myflags |=3D NBD_FLAG_BLOCK_STAT_PAYLOAD; + } trace_nbd_negotiate_new_style_size_flags(exp->size, myflags); stq_be_p(buf, exp->size); stw_be_p(buf + 8, myflags); @@ -711,7 +721,6 @@ static int nbd_negotiate_handle_info(NBDClient *client,= Error **errp) client->check_align =3D check_align; QTAILQ_INSERT_TAIL(&client->exp->clients, client, next); blk_exp_ref(&client->exp->common); - nbd_check_meta_export(client); rc =3D 1; } return rc; @@ -2406,6 +2415,83 @@ static int nbd_co_send_bitmap(NBDClient *client, NBD= Request *request, return nbd_co_send_extents(client, request, ea, last, context_id, errp= ); } +/* + * nbd_co_block_status_payload_read + * Called when a client wants a subset of negotiated contexts via a + * BLOCK_STATUS payload. Check the payload for valid length and + * contents. On success, return 0 with request updated to effective + * length. If request was invalid but payload consumed, return 0 with + * request->len and request->contexts.count set to 0 (which will + * trigger an appropriate NBD_EINVAL response later on). On I/O + * error, return -EIO. + */ +static int +nbd_co_block_status_payload_read(NBDClient *client, NBDRequest *request, + Error **errp) +{ + int payload_len =3D request->len; + g_autofree char *buf =3D NULL; + g_autofree bool *bitmaps =3D NULL; + size_t count, i; + uint32_t id; + + assert(request->len <=3D NBD_MAX_BUFFER_SIZE); + if (payload_len % sizeof(uint32_t) || + payload_len < sizeof(NBDBlockStatusPayload) || + payload_len > (sizeof(NBDBlockStatusPayload) + + sizeof(id) * client->contexts.count)) { + goto skip; + } + + buf =3D g_malloc(payload_len); + if (nbd_read(client->ioc, buf, payload_len, + "CMD_BLOCK_STATUS data", errp) < 0) { + return -EIO; + } + trace_nbd_co_receive_request_payload_received(request->handle, + payload_len); + memset(&request->contexts, 0, sizeof(request->contexts)); + request->contexts.nr_bitmaps =3D client->context_exp->nr_export_bitmap= s; + bitmaps =3D g_new0(bool, request->contexts.nr_bitmaps); + count =3D (payload_len - sizeof(NBDBlockStatusPayload)) / sizeof(id); + payload_len =3D 0; + + for (i =3D 0; i < count; i++) { + + id =3D ldl_be_p(buf + sizeof(NBDBlockStatusPayload) + sizeof(id) *= i); + if (id =3D=3D NBD_META_ID_BASE_ALLOCATION) { + if (request->contexts.base_allocation) { + goto skip; + } + request->contexts.base_allocation =3D true; + } else if (id =3D=3D NBD_META_ID_ALLOCATION_DEPTH) { + if (request->contexts.allocation_depth) { + goto skip; + } + request->contexts.allocation_depth =3D true; + } else { + if (id - NBD_META_ID_DIRTY_BITMAP > + request->contexts.nr_bitmaps || + bitmaps[id - NBD_META_ID_DIRTY_BITMAP]) { + goto skip; + } + bitmaps[id - NBD_META_ID_DIRTY_BITMAP] =3D true; + } + } + + request->len =3D ldq_be_p(buf); + request->contexts.count =3D count; + request->contexts.bitmaps =3D bitmaps; + bitmaps =3D NULL; + return 0; + + skip: + trace_nbd_co_receive_block_status_payload_compliance(request->from, + request->len); + request->len =3D request->contexts.count =3D 0; + return nbd_drop(client->ioc, payload_len, errp); +} + /* nbd_co_receive_request * Collect a client request. Return 0 if request looks valid, -EIO to drop * connection right away, -EAGAIN to indicate we were interrupted and the @@ -2452,7 +2538,14 @@ static int nbd_co_receive_request(NBDRequestData *re= q, NBDRequest *request, if (request->type =3D=3D NBD_CMD_WRITE || extended_with_payload) { payload_len =3D request->len; - if (request->type !=3D NBD_CMD_WRITE) { + if (request->type =3D=3D NBD_CMD_BLOCK_STATUS) { + payload_len =3D nbd_co_block_status_payload_read(client, + request, + errp); + if (payload_len < 0) { + return -EIO; + } + } else if (request->type !=3D NBD_CMD_WRITE) { /* * For now, we don't support payloads on other * commands; but we can keep the connection alive. @@ -2528,6 +2621,9 @@ static int nbd_co_receive_request(NBDRequestData *req= , NBDRequest *request, valid_flags |=3D NBD_CMD_FLAG_NO_HOLE | NBD_CMD_FLAG_FAST_ZERO; } else if (request->type =3D=3D NBD_CMD_BLOCK_STATUS) { valid_flags |=3D NBD_CMD_FLAG_REQ_ONE; + if (client->extended_headers && client->contexts.count) { + valid_flags |=3D NBD_CMD_FLAG_PAYLOAD_LEN; + } } if (request->flags & ~valid_flags) { error_setg(errp, "unsupported flags for command %s (got 0x%x)", diff --git a/qemu-nbd.c b/qemu-nbd.c index 9404164487..4ae5c5e73e 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -222,6 +222,7 @@ static int qemu_nbd_client_list(SocketAddress *saddr, Q= CryptoTLSCreds *tls, [NBD_FLAG_SEND_RESIZE_BIT] =3D "resize", [NBD_FLAG_SEND_CACHE_BIT] =3D "cache", [NBD_FLAG_SEND_FAST_ZERO_BIT] =3D "fast-zero", + [NBD_FLAG_BLOCK_STAT_PAYLOAD_BIT] =3D "block-status-payl= oad", }; printf(" size: %" PRIu64 "\n", list[i].size); diff --git a/nbd/trace-events b/nbd/trace-events index c20df33a43..da92fe1b56 100644 --- a/nbd/trace-events +++ b/nbd/trace-events @@ -70,6 +70,7 @@ nbd_co_send_structured_read(uint64_t handle, uint64_t off= set, void *data, size_t nbd_co_send_structured_read_hole(uint64_t handle, uint64_t offset, size_t = size) "Send structured read hole reply: handle =3D %" PRIu64 ", offset =3D = %" PRIu64 ", len =3D %zu" nbd_co_send_extents(uint64_t handle, unsigned int extents, uint32_t id, ui= nt64_t length, int last) "Send block status reply: handle =3D %" PRIu64 ", = extents =3D %u, context =3D %d (extents cover %" PRIu64 " bytes, last chunk= =3D %d)" nbd_co_send_structured_error(uint64_t handle, int err, const char *errname= , const char *msg) "Send structured error reply: handle =3D %" PRIu64 ", er= ror =3D %d (%s), msg =3D '%s'" +nbd_co_receive_block_status_payload_compliance(uint64_t from, int len) "cl= ient sent unusable block status payload: from=3D0x%" PRIx64 ", len=3D0x%x" nbd_co_receive_request_decode_type(uint64_t handle, uint16_t type, const c= har *name) "Decoding type: handle =3D %" PRIu64 ", type =3D %" PRIu16 " (%s= )" nbd_co_receive_request_payload_received(uint64_t handle, uint64_t len) "Pa= yload received: handle =3D %" PRIu64 ", len =3D %" PRIu64 nbd_co_receive_ext_payload_compliance(uint64_t from, uint64_t len) "client= sent non-compliant write without payload flag: from=3D0x%" PRIx64 ", len= =3D0x%" PRIx64 diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out index b98582c38e..b38f0b7963 100644 --- a/tests/qemu-iotests/223.out +++ b/tests/qemu-iotests/223.out @@ -83,7 +83,7 @@ exports available: 0 exports available: 3 export: 'n' size: 4194304 - flags: 0x58f ( readonly flush fua df multi cache ) + flags: 0x158f ( readonly flush fua df multi cache block-status-payload ) min block: 1 opt block: 4096 max block: 33554432 @@ -94,7 +94,7 @@ exports available: 3 export: 'n2' description: some text size: 4194304 - flags: 0xded ( flush fua trim zeroes df multi cache fast-zero ) + flags: 0x1ded ( flush fua trim zeroes df multi cache fast-zero block-sta= tus-payload ) min block: 1 opt block: 4096 max block: 33554432 @@ -104,7 +104,7 @@ exports available: 3 qemu:dirty-bitmap:b2 export: 'n3' size: 4194304 - flags: 0x58f ( readonly flush fua df multi cache ) + flags: 0x158f ( readonly flush fua df multi cache block-status-payload ) min block: 1 opt block: 4096 max block: 33554432 @@ -205,7 +205,7 @@ exports available: 0 exports available: 3 export: 'n' size: 4194304 - flags: 0x58f ( readonly flush fua df multi cache ) + flags: 0x158f ( readonly flush fua df multi cache block-status-payload ) min block: 1 opt block: 4096 max block: 33554432 @@ -216,7 +216,7 @@ exports available: 3 export: 'n2' description: some text size: 4194304 - flags: 0xded ( flush fua trim zeroes df multi cache fast-zero ) + flags: 0x1ded ( flush fua trim zeroes df multi cache fast-zero block-sta= tus-payload ) min block: 1 opt block: 4096 max block: 33554432 @@ -226,7 +226,7 @@ exports available: 3 qemu:dirty-bitmap:b2 export: 'n3' size: 4194304 - flags: 0x58f ( readonly flush fua df multi cache ) + flags: 0x158f ( readonly flush fua df multi cache block-status-payload ) min block: 1 opt block: 4096 max block: 33554432 diff --git a/tests/qemu-iotests/307.out b/tests/qemu-iotests/307.out index 2b9a6a67a1..f645f3315f 100644 --- a/tests/qemu-iotests/307.out +++ b/tests/qemu-iotests/307.out @@ -15,7 +15,7 @@ wrote 4096/4096 bytes at offset 0 exports available: 1 export: 'fmt' size: 67108864 - flags: 0x58f ( readonly flush fua df multi cache ) + flags: 0x158f ( readonly flush fua df multi cache block-status-payload ) min block: XXX opt block: XXX max block: XXX @@ -44,7 +44,7 @@ exports available: 1 exports available: 1 export: 'fmt' size: 67108864 - flags: 0x58f ( readonly flush fua df multi cache ) + flags: 0x158f ( readonly flush fua df multi cache block-status-payload ) min block: XXX opt block: XXX max block: XXX @@ -76,7 +76,7 @@ exports available: 1 exports available: 2 export: 'fmt' size: 67108864 - flags: 0x58f ( readonly flush fua df multi cache ) + flags: 0x158f ( readonly flush fua df multi cache block-status-payload ) min block: XXX opt block: XXX max block: XXX @@ -86,7 +86,7 @@ exports available: 2 export: 'export1' description: This is the writable second export size: 67108864 - flags: 0xded ( flush fua trim zeroes df multi cache fast-zero ) + flags: 0x1ded ( flush fua trim zeroes df multi cache fast-zero block-sta= tus-payload ) min block: XXX opt block: XXX max block: XXX @@ -113,7 +113,7 @@ exports available: 1 export: 'export1' description: This is the writable second export size: 67108864 - flags: 0xded ( flush fua trim zeroes df multi cache fast-zero ) + flags: 0x1ded ( flush fua trim zeroes df multi cache fast-zero block-sta= tus-payload ) min block: XXX opt block: XXX max block: XXX diff --git a/tests/qemu-iotests/tests/nbd-qemu-allocation.out b/tests/qemu-= iotests/tests/nbd-qemu-allocation.out index 659276032b..794d1bfce6 100644 --- a/tests/qemu-iotests/tests/nbd-qemu-allocation.out +++ b/tests/qemu-iotests/tests/nbd-qemu-allocation.out @@ -17,7 +17,7 @@ wrote 2097152/2097152 bytes at offset 1048576 exports available: 1 export: '' size: 4194304 - flags: 0x48f ( readonly flush fua df cache ) + flags: 0x148f ( readonly flush fua df cache block-status-payload ) min block: 1 opt block: 4096 max block: 33554432 --=20 2.38.1 From nobody Fri May 10 15:25:06 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1668467699; cv=none; d=zohomail.com; s=zohoarc; b=Tpf5LtbvRjsS1tiiKk63THAIskoOZPkRNGY9h2N/bIfW/K39qQWRmXPf7N2iUJIZGfThhzE0WCGkcFFF5K4yBoh9JGmpNSKRFHTF5f96PaeMmpbjtTUoti3QCy06Cma6W3sGmKrEomNHPPjeUhR+NzkPXcDFuyz34FO+KS5HAeY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1668467699; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=PSKFsd3WLLrsYRtlYZAlFwgEDN2comkk7iEfIBxymQM=; b=k5xgSRJ9LJ0+521FTOI9pTT0pPV69mS297OX3iSz0dqmJuOv4SOSMoq7d++Ds7tTkWxTNQHVKA7McteL9riVKIC8SEAuJF7CxW5YP5D1CqjQFK+TaVUocIvppp8QuQeG5ongh5UoZQYu0fhGTGwX3IVT53ovRiZf7jpLcKWHmsg= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1668467699284452.8068612522902; Mon, 14 Nov 2022 15:14:59 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ouieJ-00039M-3Z; Mon, 14 Nov 2022 18:13:55 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouidr-0001X6-6a for qemu-devel@nongnu.org; Mon, 14 Nov 2022 18:13:27 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouiGM-0002Pu-HD for qemu-devel@nongnu.org; Mon, 14 Nov 2022 17:49:12 -0500 Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-317-WJwDpn3APeGXsE-6Q8_8Dw-1; Mon, 14 Nov 2022 17:49:06 -0500 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 9AEB4101A528; Mon, 14 Nov 2022 22:49:05 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.240]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0566940E42E5; Mon, 14 Nov 2022 22:49:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1668466149; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=PSKFsd3WLLrsYRtlYZAlFwgEDN2comkk7iEfIBxymQM=; b=fMWcp1f/Xw6EwH0DWkNDimoEsX9EWAfid/gtr5jeTUdUTy9TxpelHyjfN6919SzmO4HByZ y/WVzFgWyUHOuymRsqyCqgVG+LILAfTJeaYySfFBm2kakkDCTiFJKA4fBIljgWC+9DXwVm wdML+C567BE/hQ8dI9KpIHc/Lfd9MQ4= X-MC-Unique: WJwDpn3APeGXsE-6Q8_8Dw-1 From: Eric Blake To: qemu-devel@nongnu.org Cc: qemu-block@nongnu.org, libguestfs@redhat.com, nbd@other.debian.org, Vladimir Sementsov-Ogievskiy , Kevin Wolf , Hanna Reitz Subject: [PATCH v2 14/15] RFC: nbd/client: Accept 64-bit hole chunks Date: Mon, 14 Nov 2022 16:48:47 -0600 Message-Id: <20221114224848.2186298-15-eblake@redhat.com> In-Reply-To: <20221114224848.2186298-1-eblake@redhat.com> References: <20221114224141.cm5jgyxfmvie5xb5@redhat.com> <20221114224848.2186298-1-eblake@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.2 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1668467700894100002 Content-Type: text/plain; charset="utf-8" As part of adding extended headers, the NBD spec debated about adding support for reading 64-bit holes. It was documented in a separate upstream commit XXX[*] to make it easier to decide whether 64-bit holes should be required of all clients supporting extended headers, or whether it is an unneeded feature; hence, the qemu work to support it is also pulled out into a separate commit. Note that we can also tolerate a non-compliant server sending the new chunk even when it should not. Signed-off-by: Eric Blake --- [*] Fix commit id if we actually go with idea --- include/block/nbd.h | 8 ++++++++ block/nbd.c | 26 ++++++++++++++++++++------ nbd/common.c | 4 +++- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/include/block/nbd.h b/include/block/nbd.h index 2a65c606c9..18b6bad038 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -133,6 +133,13 @@ typedef struct NBDStructuredReadHole { uint32_t length; } QEMU_PACKED NBDStructuredReadHole; +/* Complete chunk for NBD_REPLY_TYPE_OFFSET_HOLE_EXT */ +typedef struct NBDStructuredReadHoleExt { + /* header's length =3D=3D 16 */ + uint64_t offset; + uint64_t length; +} QEMU_PACKED NBDStructuredReadHoleExt; + /* Header of all NBD_REPLY_TYPE_ERROR* errors */ typedef struct NBDStructuredError { /* header's length >=3D 6 */ @@ -309,6 +316,7 @@ enum { #define NBD_REPLY_TYPE_NONE 0 #define NBD_REPLY_TYPE_OFFSET_DATA 1 #define NBD_REPLY_TYPE_OFFSET_HOLE 2 +#define NBD_REPLY_TYPE_OFFSET_HOLE_EXT 3 #define NBD_REPLY_TYPE_BLOCK_STATUS 5 #define NBD_REPLY_TYPE_BLOCK_STATUS_EXT 6 #define NBD_REPLY_TYPE_ERROR NBD_REPLY_ERR(1) diff --git a/block/nbd.c b/block/nbd.c index 44ab5437ea..968d5d8a37 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -570,20 +570,26 @@ static inline uint64_t payload_advance64(uint8_t **pa= yload) static int nbd_parse_offset_hole_payload(BDRVNBDState *s, NBDStructuredReplyChunk *chunk, - uint8_t *payload, uint64_t orig_o= ffset, + uint8_t *payload, bool wide, + uint64_t orig_offset, QEMUIOVector *qiov, Error **errp) { uint64_t offset; - uint32_t hole_size; + uint64_t hole_size; + size_t len =3D wide ? sizeof(hole_size) : sizeof(uint32_t); - if (chunk->length !=3D sizeof(offset) + sizeof(hole_size)) { + if (chunk->length !=3D sizeof(offset) + len) { error_setg(errp, "Protocol error: invalid payload for " "NBD_REPLY_TYPE_OFFSET_HOLE"); return -EINVAL; } offset =3D payload_advance64(&payload); - hole_size =3D payload_advance32(&payload); + if (wide) { + hole_size =3D payload_advance64(&payload); + } else { + hole_size =3D payload_advance32(&payload); + } if (!hole_size || offset < orig_offset || hole_size > qiov->size || offset > orig_offset + qiov->size - hole_size) { @@ -596,6 +602,7 @@ static int nbd_parse_offset_hole_payload(BDRVNBDState *= s, trace_nbd_structured_read_compliance("hole"); } + assert(hole_size <=3D SIZE_MAX); qemu_iovec_memset(qiov, offset - orig_offset, 0, hole_size); return 0; @@ -1094,9 +1101,16 @@ static int coroutine_fn nbd_co_receive_cmdread_reply= (BDRVNBDState *s, uint64_t h * in qiov */ break; + case NBD_REPLY_TYPE_OFFSET_HOLE_EXT: + if (!s->info.extended_headers) { + trace_nbd_extended_headers_compliance("hole_ext"); + } + /* fallthrough */ case NBD_REPLY_TYPE_OFFSET_HOLE: - ret =3D nbd_parse_offset_hole_payload(s, &reply.structured, pa= yload, - offset, qiov, &local_err); + ret =3D nbd_parse_offset_hole_payload( + s, &reply.structured, payload, + chunk->type =3D=3D NBD_REPLY_TYPE_OFFSET_HOLE_EXT, + offset, qiov, &local_err); if (ret < 0) { nbd_channel_error(s, ret); nbd_iter_channel_error(&iter, ret, &local_err); diff --git a/nbd/common.c b/nbd/common.c index 137466defd..54f7d6a4fd 100644 --- a/nbd/common.c +++ b/nbd/common.c @@ -174,7 +174,9 @@ const char *nbd_reply_type_lookup(uint16_t type) case NBD_REPLY_TYPE_OFFSET_DATA: return "data"; case NBD_REPLY_TYPE_OFFSET_HOLE: - return "hole"; + return "hole (32-bit)"; + case NBD_REPLY_TYPE_OFFSET_HOLE_EXT: + return "hole (64-bit)"; case NBD_REPLY_TYPE_BLOCK_STATUS: return "block status (32-bit)"; case NBD_REPLY_TYPE_BLOCK_STATUS_EXT: --=20 2.38.1 From nobody Fri May 10 15:25:06 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1668469124; cv=none; d=zohomail.com; s=zohoarc; b=QH5VyrRxAKDAsibWc3pGB+X9y8glLsGl1Myl4I3thQnV/Y4UW2xzujFKSE0pZm9/J5oyJAjSeI+R6/4av720Un1z3Wulo8gMyEjJATAnzwkarnmGjSzYSAiveUQpTxS8ZoSGQj+nALsY7IAJr08zZJJWhef4HUyLe1+xeFW9LyQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1668469124; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=CHsBQkgh32mZYDlsY0mZ2u45YAKMiJgOqFfn5u30FUM=; b=XePe3DUaKR3Eig+LnZtvLUd8yVWL3sVZdxuKOjDguw7EJHFSZa5bJiJW/jMFI/ix5YINlxtzt9WpVfqIfd9FzyaWHJbYmJvwDa04eazgp53fc7LTNEG6niETTWgbeYZbdtMGr7ukNDC8lnZKx+rNHgRblyu+LVRXtomNsumggvo= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1668469124072616.5178914588474; Mon, 14 Nov 2022 15:38:44 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ouie1-0002CA-R5; Mon, 14 Nov 2022 18:13:37 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouidr-0001df-6E for qemu-devel@nongnu.org; Mon, 14 Nov 2022 18:13:27 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouiGM-0002QB-Kx for qemu-devel@nongnu.org; Mon, 14 Nov 2022 17:49:12 -0500 Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-644-Y1SxJHrLPdCwHXu-gqXVEA-1; Mon, 14 Nov 2022 17:49:06 -0500 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 47AFC101E989; Mon, 14 Nov 2022 22:49:06 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.240]) by smtp.corp.redhat.com (Postfix) with ESMTP id C3AAE40E42E3; Mon, 14 Nov 2022 22:49:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1668466150; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=CHsBQkgh32mZYDlsY0mZ2u45YAKMiJgOqFfn5u30FUM=; b=eflHQfT6fgXpf9vgPxWhOSlcUIKdvxYwaL75zSzK4Rg5rXXbh/b08rOoIMk2S/zMR1DiGp RvPQxRvTHqzFSIgz0kGCuQcIRPsBU8HniwIDWM3X8chyDGIggJpcbLsEf8MgJZS/PUHvMV Mmquj8sxsFxLNNok/Zobfo1wBrO1HcQ= X-MC-Unique: Y1SxJHrLPdCwHXu-gqXVEA-1 From: Eric Blake To: qemu-devel@nongnu.org Cc: qemu-block@nongnu.org, libguestfs@redhat.com, nbd@other.debian.org, Vladimir Sementsov-Ogievskiy Subject: [PATCH v2 15/15] RFC: nbd/server: Send 64-bit hole chunk Date: Mon, 14 Nov 2022 16:48:48 -0600 Message-Id: <20221114224848.2186298-16-eblake@redhat.com> In-Reply-To: <20221114224848.2186298-1-eblake@redhat.com> References: <20221114224141.cm5jgyxfmvie5xb5@redhat.com> <20221114224848.2186298-1-eblake@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.2 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1668469125664100008 Content-Type: text/plain; charset="utf-8" Since we cap NBD_CMD_READ requests to 32M, we never have a reason to send a 64-bit chunk type for a hole; but it is worth producing these for interoperability testing of clients that want extended headers. --- nbd/server.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/nbd/server.c b/nbd/server.c index cd280f1721..04cb172f97 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -2112,9 +2112,13 @@ static int coroutine_fn nbd_co_send_sparse_read(NBDC= lient *client, if (status & BDRV_BLOCK_ZERO) { NBDReply hdr; NBDStructuredReadHole chunk; + NBDStructuredReadHoleExt chunk_ext; struct iovec iov[] =3D { {.iov_base =3D &hdr}, - {.iov_base =3D &chunk, .iov_len =3D sizeof(chunk)}, + {.iov_base =3D client->extended_headers ? &chunk_ext + : (void *) &chunk, + .iov_len =3D client->extended_headers ? sizeof(chunk_ext) + : sizeof(chunk)}, }; trace_nbd_co_send_structured_read_hole(request->handle, @@ -2122,9 +2126,17 @@ static int coroutine_fn nbd_co_send_sparse_read(NBDC= lient *client, pnum); set_be_chunk(client, &iov[0], final ? NBD_REPLY_FLAG_DONE : 0, - NBD_REPLY_TYPE_OFFSET_HOLE, request, iov[1].iov_l= en); - stq_be_p(&chunk.offset, offset + progress); - stl_be_p(&chunk.length, pnum); + client->extended_headers + ? NBD_REPLY_TYPE_OFFSET_HOLE_EXT + : NBD_REPLY_TYPE_OFFSET_HOLE, + request, iov[1].iov_len); + if (client->extended_headers) { + stq_be_p(&chunk_ext.offset, offset + progress); + stq_be_p(&chunk_ext.length, pnum); + } else { + stq_be_p(&chunk.offset, offset + progress); + stl_be_p(&chunk.length, pnum); + } ret =3D nbd_co_send_iov(client, iov, 2, errp); } else { ret =3D blk_pread(exp->common.blk, offset + progress, pnum, --=20 2.38.1