summaryrefslogtreecommitdiff
path: root/block
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2026-09-03 09:43:07 +0100
committerPeter Maydell <peter.maydell@linaro.org>2026-09-03 09:43:07 +0100
commit7eddb112ab207aa0b845e87a45204a87f2f4acd9 (patch)
tree542397ea5497c47dabef7aa456b6d42d38f2d263 /block
parent1a8f18541eef8761a709e44708758a4c08b50a15 (diff)
parent29ed9606ba15aa346eaec349d169f90eff56fd01 (diff)
downloadqemu-7eddb112ab207aa0b845e87a45204a87f2f4acd9.tar.gz
qemu-7eddb112ab207aa0b845e87a45204a87f2f4acd9.zip
Merge tag 'pull-nbd-2026-09-02' of https://gitlab.com/vsementsov/qemu into staging
block: nbd patches # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCgAdFiEEi5wmzbL9FHyIDoahVh8kwfGfefsFAmqX4VgACgkQVh8kwfGf # efv1KA//XpVJjBnou5RRgPvpGeTJz5G0ouI78sWsYFbqFRz1P/lvbvkl40a9wAJy # 5IAeNCAj1FtTKJ+GMTVWKfLKn4fVLWdhcPX+33gxpVLbqx5uHweqxKN38p+hAvcr # PtyVWX6kMRXGAyL7s3wb5qcvGqH/hf9+RG8hK+2KbrHnDJw7MRaicq17U7FL4Fzg # EKxQMwGsjPEBGZYWSbYj6TfZI1sglfFifBEv5Y+kC2pWgVmmmXNRqXZcRPGNVBNS # xMYus/nYPZAD3IdomCoQIERoccY5/mavy4UBQ2RdTNow4PiCMnjo+kRJRTrstBAE # LokC9nUVs0hQkAd7Cq+M6aqXREJDfg871S4hYZmdpAsi6lIJPx6JvnjZ9NbO1TQY # xvAThopZTA6qxgVc88K26/zwnJf3+tKgQ4JAKB7Pt25hPc4BJiYA/Uo8vIR7pu9H # o1R+DAMWETv/x8J17+pbH8OgjqSe/KzptgwEi94lplz5lOTJOGvHz/5njPam6AsC # 40DGtGG+ZoE7GTIKg2C3iYce+K0FtcM0ANuWj99bVO8vNdpKuv0TsCHLPSFViYev # v37s20UVCX7AO4Q2G868BWUPwLFXSI+ENiT6Xbiwa3hBLGZK5fjqWwJxJVwSOA3q # 3LpRNgCoDDO0kjkwqOh9000OjQhaBHOftax3mzW++Fb+TizW1n4= # =IST8 # -----END PGP SIGNATURE----- # gpg: Signature made Wed Sep 2 09:42:00 2026 BST # gpg: using RSA key 8B9C26CDB2FD147C880E86A1561F24C1F19F79FB # gpg: Good signature from "Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>" [unknown] # gpg: aka "Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 8B9C 26CD B2FD 147C 880E 86A1 561F 24C1 F19F 79FB * tag 'pull-nbd-2026-09-02' of https://gitlab.com/vsementsov/qemu: iotests/nbd-commands: cover the command flags and sparse replies iotests/nbd-commands: cover NBD_CMD_BLOCK_STATUS with a payload iotests/nbd-commands: exercise the simple and structured reply modes nbd/server: accept NBD_CMD_CACHE above the maximum payload size iotests: add coverage for NBD transmission commands block/nbd: clear reply.cookie under receive_mutex block/nbd: never index requests[] with an unchecked cookie block/nbd: clear reply.cookie when the reply is rejected Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'block')
-rw-r--r--block/nbd.c65
1 files changed, 43 insertions, 22 deletions
diff --git a/block/nbd.c b/block/nbd.c
index 5d231d5c4e..e5e16722ba 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -136,6 +136,19 @@ static void nbd_clear_bdrvstate(BlockDriverState *bs)
s->x_dirty_bitmap = NULL;
}
+static NBDClientRequest *nbd_request_by_cookie(BDRVNBDState *s, uint64_t cookie,
+ Error **errp)
+{
+ uint64_t ind = COOKIE_TO_INDEX(cookie);
+
+ if (ind >= MAX_NBD_REQUESTS || !s->requests[ind].coroutine) {
+ error_setg(errp, "unexpected cookie value");
+ return NULL;
+ }
+
+ return &s->requests[ind];
+}
+
/* Called with s->receive_mutex taken. */
static bool coroutine_fn nbd_recv_coroutine_wake_one(NBDClientRequest *req)
{
@@ -148,11 +161,11 @@ static bool coroutine_fn nbd_recv_coroutine_wake_one(NBDClientRequest *req)
return false;
}
+/* Called with s->receive_mutex taken. */
static void coroutine_fn nbd_recv_coroutines_wake(BDRVNBDState *s)
{
int i;
- QEMU_LOCK_GUARD(&s->receive_mutex);
for (i = 0; i < MAX_NBD_REQUESTS; i++) {
if (nbd_recv_coroutine_wake_one(&s->requests[i])) {
return;
@@ -422,7 +435,8 @@ static coroutine_fn int nbd_receive_replies(BDRVNBDState *s, uint64_t cookie,
Error **errp)
{
int ret;
- uint64_t ind = COOKIE_TO_INDEX(cookie), ind2;
+ NBDClientRequest *req = nbd_request_by_cookie(s, cookie, &error_abort);
+ NBDClientRequest *owner;
QEMU_LOCK_GUARD(&s->receive_mutex);
while (true) {
@@ -437,10 +451,10 @@ static coroutine_fn int nbd_receive_replies(BDRVNBDState *s, uint64_t cookie,
* woken by whoever set s->reply.cookie (or never wait in this
* yield). So, we should not wake it here.
*/
- ind2 = COOKIE_TO_INDEX(s->reply.cookie);
- assert(!s->requests[ind2].receiving);
+ owner = nbd_request_by_cookie(s, s->reply.cookie, &error_abort);
+ assert(!owner->receiving);
- s->requests[ind].receiving = true;
+ req->receiving = true;
qemu_co_mutex_unlock(&s->receive_mutex);
qemu_coroutine_yield();
@@ -454,7 +468,7 @@ static coroutine_fn int nbd_receive_replies(BDRVNBDState *s, uint64_t cookie,
*/
qemu_co_mutex_lock(&s->receive_mutex);
- assert(!s->requests[ind].receiving);
+ assert(!req->receiving);
continue;
}
@@ -466,27 +480,32 @@ static coroutine_fn int nbd_receive_replies(BDRVNBDState *s, uint64_t cookie,
error_setg(errp, "server dropped connection");
}
if (ret < 0) {
- nbd_channel_error(s, ret);
- return ret;
+ goto err;
}
if (nbd_reply_is_structured(&s->reply) &&
s->info.mode < NBD_MODE_STRUCTURED) {
- nbd_channel_error(s, -EINVAL);
+ ret = -EINVAL;
error_setg(errp, "unexpected structured reply");
- return -EINVAL;
+ goto err;
}
- ind2 = COOKIE_TO_INDEX(s->reply.cookie);
- if (ind2 >= MAX_NBD_REQUESTS || !s->requests[ind2].coroutine) {
- nbd_channel_error(s, -EINVAL);
- error_setg(errp, "unexpected cookie value");
- return -EINVAL;
+ owner = nbd_request_by_cookie(s, s->reply.cookie, errp);
+ if (!owner) {
+ ret = -EINVAL;
+ goto err;
}
if (s->reply.cookie == cookie) {
/* We are done */
return 0;
}
- nbd_recv_coroutine_wake_one(&s->requests[ind2]);
+ nbd_recv_coroutine_wake_one(owner);
}
+
+err:
+ /* Waiters look at this cookie, so do not leave a rejected one behind. */
+ s->reply.cookie = 0;
+ nbd_channel_error(s, ret);
+
+ return ret;
}
static int coroutine_fn GRAPH_RDLOCK
@@ -855,7 +874,6 @@ static coroutine_fn int nbd_co_do_receive_one_chunk(
{
ERRP_GUARD();
int ret;
- int i = COOKIE_TO_INDEX(cookie);
void *local_payload = NULL;
NBDStructuredReplyChunk *chunk;
@@ -913,8 +931,9 @@ static coroutine_fn int nbd_co_do_receive_one_chunk(
return -EINVAL;
}
- return nbd_co_receive_offset_data_payload(s, s->requests[i].offset,
- qiov, errp);
+ return nbd_co_receive_offset_data_payload(
+ s, nbd_request_by_cookie(s, cookie, &error_abort)->offset,
+ qiov, errp);
}
if (nbd_reply_type_is_error(chunk->type)) {
@@ -955,9 +974,11 @@ static coroutine_fn int nbd_co_receive_one_chunk(
/* For assert at loop start in nbd_connection_entry */
*reply = s->reply;
}
- s->reply.cookie = 0;
- nbd_recv_coroutines_wake(s);
+ WITH_QEMU_LOCK_GUARD(&s->receive_mutex) {
+ s->reply.cookie = 0;
+ nbd_recv_coroutines_wake(s);
+ }
return ret;
}
@@ -1061,7 +1082,7 @@ static bool coroutine_fn nbd_reply_chunk_iter_receive(BDRVNBDState *s,
break_loop:
qemu_mutex_lock(&s->requests_lock);
- s->requests[COOKIE_TO_INDEX(cookie)].coroutine = NULL;
+ nbd_request_by_cookie(s, cookie, &error_abort)->coroutine = NULL;
s->in_flight--;
qemu_co_queue_next(&s->free_sema);
qemu_mutex_unlock(&s->requests_lock);