Commit 37e02aeb authored by Vladimir Sementsov-Ogievskiy's avatar Vladimir Sementsov-Ogievskiy Committed by Eric Blake
Browse files

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: default avatarVladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-Id: <20180308184636.178534-3-vsementsov@virtuozzo.com>
[eblake: grammar tweaks]
Signed-off-by: default avatarEric Blake <eblake@redhat.com>
parent 60ace2ba
Loading
Loading
Loading
Loading
+14 −3
Original line number Diff line number Diff line
@@ -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;