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; }
static void nbd_close(BlockDriverState *bs) { BDRVNBDState *s = bs->opaque; g_free(s->export_name); g_free(s->host_spec); nbd_teardown_connection(bs); }
void nbd_client_close(BlockDriverState *bs) { NBDClientSession *client = nbd_get_client_session(bs); NBDRequest request = { .type = NBD_CMD_DISC }; if (client->ioc == NULL) { return; } nbd_send_request(client->ioc, &request); nbd_teardown_connection(bs); }
void nbd_client_close(BlockDriverState *bs) { NbdClientSession *client = nbd_get_client_session(bs); struct nbd_request request = { .type = NBD_CMD_DISC, .from = 0, .len = 0 }; if (client->sock == -1) { return; } nbd_send_request(client->sock, &request); nbd_teardown_connection(bs); } int nbd_client_init(BlockDriverState *bs, int sock, const char *export, Error **errp) { NbdClientSession *client = nbd_get_client_session(bs); 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, errp); 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->sock = sock; /* Now that we're connected, set the socket to be non-blocking and * kick the reply mechanism. */ qemu_set_nonblock(sock); nbd_client_attach_aio_context(bs, bdrv_get_aio_context(bs)); logout("Established connection with NBD server\n"); return 0; }
static void nbd_reply_ready(void *opaque) { BlockDriverState *bs = opaque; NbdClientSession *s = nbd_get_client_session(bs); uint64_t i; int ret; if (!s->ioc) { /* Already closed */ return; } 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->ioc, &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_teardown_connection(bs); }
void nbd_client_close(BlockDriverState *bs) { NbdClientSession *client = nbd_get_client_session(bs); struct nbd_request request = { .type = NBD_CMD_DISC, .from = 0, .len = 0 }; if (client->ioc == NULL) { return; } nbd_send_request(client->ioc, &request); nbd_teardown_connection(bs); } int nbd_client_init(BlockDriverState *bs, QIOChannelSocket *sioc, const char *export, QCryptoTLSCreds *tlscreds, const char *hostname, Error **errp) { NbdClientSession *client = nbd_get_client_session(bs); int ret; /* NBD handshake */ logout("session init %s\n", export); qio_channel_set_blocking(QIO_CHANNEL(sioc), true, NULL); ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), export, &client->nbdflags, tlscreds, hostname, &client->ioc, &client->size, errp); if (ret < 0) { logout("Failed to negotiate with the NBD server\n"); return ret; } qemu_co_mutex_init(&client->send_mutex); qemu_co_mutex_init(&client->free_sema); client->sioc = sioc; object_ref(OBJECT(client->sioc)); if (!client->ioc) { client->ioc = QIO_CHANNEL(sioc); object_ref(OBJECT(client->ioc)); } /* Now that we're connected, set the socket to be non-blocking and * kick the reply mechanism. */ qio_channel_set_blocking(QIO_CHANNEL(sioc), false, NULL); nbd_client_attach_aio_context(bs, bdrv_get_aio_context(bs)); logout("Established connection with NBD server\n"); return 0; }