nbd/server: Prepare for per-request filtering of BLOCK_STATUS

The next commit will add support for the optional extension
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 <eblake@redhat.com>
Message-ID: <20230925192229.3186470-25-eblake@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
This commit is contained in:
Eric Blake 2023-09-25 14:22:41 -05:00
parent fd358d8390
commit 1dec4643d1
2 changed files with 18 additions and 5 deletions

View file

@ -77,6 +77,7 @@ typedef struct NBDRequest {
uint16_t flags; /* NBD_CMD_FLAG_* */ uint16_t flags; /* NBD_CMD_FLAG_* */
uint16_t type; /* NBD_CMD_* */ uint16_t type; /* NBD_CMD_* */
NBDMode mode; /* Determines which network representation to use */ NBDMode mode; /* Determines which network representation to use */
NBDMetaContexts *contexts; /* Used by NBD_CMD_BLOCK_STATUS */
} NBDRequest; } NBDRequest;
typedef struct NBDSimpleReply { typedef struct NBDSimpleReply {

View file

@ -2505,6 +2505,7 @@ static int coroutine_fn nbd_co_receive_request(NBDRequestData *req,
break; break;
case NBD_CMD_BLOCK_STATUS: case NBD_CMD_BLOCK_STATUS:
request->contexts = &client->contexts;
valid_flags |= NBD_CMD_FLAG_REQ_ONE; valid_flags |= NBD_CMD_FLAG_REQ_ONE;
break; break;
@ -2748,17 +2749,18 @@ static coroutine_fn int nbd_handle_request(NBDClient *client,
"discard failed", errp); "discard failed", errp);
case NBD_CMD_BLOCK_STATUS: case NBD_CMD_BLOCK_STATUS:
assert(request->contexts);
if (!request->len) { if (!request->len) {
return nbd_send_generic_reply(client, request, -EINVAL, return nbd_send_generic_reply(client, request, -EINVAL,
"need non-zero length", errp); "need non-zero length", errp);
} }
assert(client->mode >= NBD_MODE_EXTENDED || assert(client->mode >= NBD_MODE_EXTENDED ||
request->len <= UINT32_MAX); request->len <= UINT32_MAX);
if (client->contexts.count) { if (request->contexts->count) {
bool dont_fragment = request->flags & NBD_CMD_FLAG_REQ_ONE; bool dont_fragment = request->flags & NBD_CMD_FLAG_REQ_ONE;
int contexts_remaining = client->contexts.count; int contexts_remaining = request->contexts->count;
if (client->contexts.base_allocation) { if (request->contexts->base_allocation) {
ret = nbd_co_send_block_status(client, request, ret = nbd_co_send_block_status(client, request,
exp->common.blk, exp->common.blk,
request->from, request->from,
@ -2771,7 +2773,7 @@ static coroutine_fn int nbd_handle_request(NBDClient *client,
} }
} }
if (client->contexts.allocation_depth) { if (request->contexts->allocation_depth) {
ret = nbd_co_send_block_status(client, request, ret = nbd_co_send_block_status(client, request,
exp->common.blk, exp->common.blk,
request->from, request->len, request->from, request->len,
@ -2784,8 +2786,9 @@ static coroutine_fn int nbd_handle_request(NBDClient *client,
} }
} }
assert(request->contexts->exp == client->exp);
for (i = 0; i < client->exp->nr_export_bitmaps; i++) { for (i = 0; i < client->exp->nr_export_bitmaps; i++) {
if (!client->contexts.bitmaps[i]) { if (!request->contexts->bitmaps[i]) {
continue; continue;
} }
ret = nbd_co_send_bitmap(client, request, ret = nbd_co_send_bitmap(client, request,
@ -2801,6 +2804,10 @@ static coroutine_fn int nbd_handle_request(NBDClient *client,
assert(!contexts_remaining); assert(!contexts_remaining);
return 0; return 0;
} else if (client->contexts.count) {
return nbd_send_generic_reply(client, request, -EINVAL,
"CMD_BLOCK_STATUS payload not valid",
errp);
} else { } else {
return nbd_send_generic_reply(client, request, -EINVAL, return nbd_send_generic_reply(client, request, -EINVAL,
"CMD_BLOCK_STATUS not negotiated", "CMD_BLOCK_STATUS not negotiated",
@ -2879,6 +2886,11 @@ static coroutine_fn void nbd_trip(void *opaque)
} else { } else {
ret = nbd_handle_request(client, &request, req->data, &local_err); ret = nbd_handle_request(client, &request, req->data, &local_err);
} }
if (request.contexts && request.contexts != &client->contexts) {
assert(request.type == NBD_CMD_BLOCK_STATUS);
g_free(request.contexts->bitmaps);
g_free(request.contexts);
}
if (ret < 0) { if (ret < 0) {
error_prepend(&local_err, "Failed to send reply: "); error_prepend(&local_err, "Failed to send reply: ");
goto disconnect; goto disconnect;