Beispiel #1
0
static void nbd_teardown_connection(NbdClientSession *client)
{
    struct nbd_request request = {
        .type = NBD_CMD_DISC,
        .from = 0,
        .len = 0
    };

    nbd_send_request(client->sock, &request);

    /* finish any pending coroutines */
    shutdown(client->sock, 2);
    nbd_recv_coroutines_enter_all(client);

    qemu_aio_set_fd_handler(client->sock, NULL, NULL, NULL);
    closesocket(client->sock);
    client->sock = -1;
}

void nbd_client_session_close(NbdClientSession *client)
{
    if (!client->bs) {
        return;
    }

    nbd_teardown_connection(client);
    client->bs = NULL;
}

int nbd_client_session_init(NbdClientSession *client, BlockDriverState *bs,
    int sock, const char *export)
{
    int ret;

    /* NBD handshake */
    logout("session init %s\n", export);
    qemu_set_block(sock);
    ret = nbd_receive_negotiate(sock, export,
                                &client->nbdflags, &client->size,
                                &client->blocksize);
    if (ret < 0) {
        logout("Failed to negotiate with the NBD server\n");
        closesocket(sock);
        return ret;
    }

    qemu_co_mutex_init(&client->send_mutex);
    qemu_co_mutex_init(&client->free_sema);
    client->bs = bs;
    client->sock = sock;

    /* Now that we're connected, set the socket to be non-blocking and
     * kick the reply mechanism.  */
    qemu_set_nonblock(sock);
    qemu_aio_set_fd_handler(sock, nbd_reply_ready, NULL, client);

    logout("Established connection with NBD server\n");
    return 0;
}
Beispiel #2
0
static void nbd_teardown_connection(BlockDriverState *bs)
{
    NbdClientSession *client = nbd_get_client_session(bs);

    /* finish any pending coroutines */
    shutdown(client->sock, 2);
    nbd_recv_coroutines_enter_all(client);

    nbd_client_detach_aio_context(bs);
    closesocket(client->sock);
    client->sock = -1;
}
Beispiel #3
0
static coroutine_fn void nbd_read_reply_entry(void *opaque)
{
    NBDClientSession *s = opaque;
    uint64_t i;
    int ret;
    Error *local_err = NULL;

    for (;;) {
        assert(s->reply.handle == 0);
        ret = nbd_receive_reply(s->ioc, &s->reply, &local_err);
        if (ret < 0) {
            error_report_err(local_err);
        }
        if (ret <= 0) {
            break;
        }

        /* There's no need for a mutex on the receive side, because the
         * handler acts as a synchronization point and ensures that only
         * one coroutine is called until the reply finishes.
         */
        i = HANDLE_TO_INDEX(s, s->reply.handle);
        if (i >= MAX_NBD_REQUESTS || !s->recv_coroutine[i]) {
            break;
        }

        /* We're woken up by the recv_coroutine itself.  Note that there
         * is no race between yielding and reentering read_reply_co.  This
         * is because:
         *
         * - if recv_coroutine[i] runs on the same AioContext, it is only
         *   entered after we yield
         *
         * - if recv_coroutine[i] runs on a different AioContext, reentering
         *   read_reply_co happens through a bottom half, which can only
         *   run after we yield.
         */
        aio_co_wake(s->recv_coroutine[i]);
        qemu_coroutine_yield();
    }

    nbd_recv_coroutines_enter_all(s);
    s->read_reply_co = NULL;
}
Beispiel #4
0
static void nbd_teardown_connection(BlockDriverState *bs)
{
    NbdClientSession *client = nbd_get_client_session(bs);

    if (!client->ioc) { /* Already closed */
        return;
    }

    /* finish any pending coroutines */
    qio_channel_shutdown(client->ioc,
                         QIO_CHANNEL_SHUTDOWN_BOTH,
                         NULL);
    nbd_recv_coroutines_enter_all(client);

    nbd_client_detach_aio_context(bs);
    object_unref(OBJECT(client->sioc));
    client->sioc = NULL;
    object_unref(OBJECT(client->ioc));
    client->ioc = NULL;
}
Beispiel #5
0
static void nbd_reply_ready(void *opaque)
{
    NbdClientSession *s = opaque;
    uint64_t i;
    int ret;

    if (s->reply.handle == 0) {
        /* No reply already in flight.  Fetch a header.  It is possible
         * that another thread has done the same thing in parallel, so
         * the socket is not readable anymore.
         */
        ret = nbd_receive_reply(s->sock, &s->reply);
        if (ret == -EAGAIN) {
            return;
        }
        if (ret < 0) {
            s->reply.handle = 0;
            goto fail;
        }
    }

    /* There's no need for a mutex on the receive side, because the
     * handler acts as a synchronization point and ensures that only
     * one coroutine is called until the reply finishes.  */
    i = HANDLE_TO_INDEX(s, s->reply.handle);
    if (i >= MAX_NBD_REQUESTS) {
        goto fail;
    }

    if (s->recv_coroutine[i]) {
        qemu_coroutine_enter(s->recv_coroutine[i], NULL);
        return;
    }

fail:
    nbd_recv_coroutines_enter_all(s);
}