nbd/server: fix sparse read

In case of io error in nbd_co_send_sparse_read we should not
"goto reply:", as it was a fatal error and the common behavior
is to disconnect in this case. We should not try to send the
client an additional error reply, since we already hit a
channel-io error on our previous attempt to send one.

Fix this by handling block-status error in nbd_co_send_sparse_read,
so nbd_co_send_sparse_read fails only on io error. Then just skip
common "reply:" code path in nbd_trip.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-Id: <20180308184636.178534-3-vsementsov@virtuozzo.com>
[eblake: grammar tweaks]
Signed-off-by: Eric Blake <eblake@redhat.com>
master
Vladimir Sementsov-Ogievskiy 2018-03-08 21:46:33 +03:00 committed by Eric Blake
parent 60ace2bacf
commit 37e02aebf8
1 changed files with 14 additions and 3 deletions

View File

@ -1366,6 +1366,10 @@ static int coroutine_fn nbd_co_send_structured_error(NBDClient *client,
return nbd_co_send_iov(client, iov, 1 + !!iov[1].iov_len, errp);
}
/* Do a sparse read and send the structured reply to the client.
* Returns -errno if sending fails. bdrv_block_status_above() failure is
* reported to the client, at which point this function succeeds.
*/
static int coroutine_fn nbd_co_send_sparse_read(NBDClient *client,
uint64_t handle,
uint64_t offset,
@ -1386,8 +1390,13 @@ static int coroutine_fn nbd_co_send_sparse_read(NBDClient *client,
bool final;
if (status < 0) {
error_setg_errno(errp, -status, "unable to check for holes");
return status;
char *msg = g_strdup_printf("unable to check for holes: %s",
strerror(-status));
ret = nbd_co_send_structured_error(client, handle, -status, msg,
errp);
g_free(msg);
return ret;
}
assert(pnum && pnum <= size - progress);
final = progress + pnum == size;
@ -1568,7 +1577,7 @@ static coroutine_fn void nbd_trip(void *opaque)
request.from, req->data, request.len,
&local_err);
if (ret < 0) {
goto reply;
goto replied;
}
goto done;
}
@ -1665,6 +1674,8 @@ reply:
req->data, reply_data_len, &local_err);
}
g_free(msg);
replied:
if (ret < 0) {
error_prepend(&local_err, "Failed to send reply: ");
goto disconnect;