This patch sets up the fd handler in nbd.c instead of qemu-nbd.c. It introduces NBDClient, which wraps the arguments to nbd_trip in a single structure, so that we can add a notifier to it. This way, qemu-nbd can know about disconnections.
Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> --- nbd.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- nbd.h | 4 ++- qemu-nbd.c | 13 ++--------- 3 files changed, 68 insertions(+), 12 deletions(-) diff --git a/nbd.c b/nbd.c index ae7f5ab..16c4c27 100644 --- a/nbd.c +++ b/nbd.c @@ -602,6 +602,37 @@ struct NBDExport { QSIMPLEQ_HEAD(, NBDRequest) requests; }; +struct NBDClient { + int refcount; + void (*close)(NBDClient *client); + + NBDExport *exp; + int sock; +}; + +static void nbd_client_get(NBDClient *client) +{ + client->refcount++; +} + +static void nbd_client_put(NBDClient *client) +{ + if (--client->refcount == 0) { + g_free(client); + } +} + +static void nbd_client_close(NBDClient *client) +{ + qemu_set_fd_handler2(client->sock, NULL, NULL, NULL, NULL); + close(client->sock); + client->sock = -1; + if (client->close) { + client->close(client); + } + nbd_client_put(client); +} + static NBDRequest *nbd_request_get(NBDExport *exp) { NBDRequest *req; @@ -714,9 +745,11 @@ out: return rc; } -int nbd_trip(NBDExport *exp, int csock) +static int nbd_trip(NBDClient *client) { + NBDExport *exp = client->exp; NBDRequest *req = nbd_request_get(exp); + int csock = client->sock; struct nbd_request request; struct nbd_reply reply; int rc = -1; @@ -837,3 +870,31 @@ out: nbd_request_put(exp, req); return rc; } + +static void nbd_read(void *opaque) +{ + NBDClient *client = opaque; + + nbd_client_get(client); + if (nbd_trip(client) != 0) { + nbd_client_close(client); + } + + nbd_client_put(client); +} + +NBDClient *nbd_client_new(NBDExport *exp, int csock, + void (*close)(NBDClient *)) +{ + NBDClient *client; + if (nbd_negotiate(csock, exp->size, exp->nbdflags) == -1) { + return NULL; + } + client = g_malloc0(sizeof(NBDClient)); + client->refcount = 1; + client->exp = exp; + client->sock = csock; + client->close = close; + qemu_set_fd_handler2(csock, NULL, nbd_read, NULL, client); + return client; +} diff --git a/nbd.h b/nbd.h index d368156..383c693 100644 --- a/nbd.h +++ b/nbd.h @@ -77,10 +77,12 @@ int nbd_client(int fd); int nbd_disconnect(int fd); typedef struct NBDExport NBDExport; +typedef struct NBDClient NBDClient; NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size, uint32_t nbdflags); void nbd_export_close(NBDExport *exp); -int nbd_trip(NBDExport *exp, int csock); +NBDClient *nbd_client_new(NBDExport *exp, int csock, + void (*close)(NBDClient *)); #endif diff --git a/qemu-nbd.c b/qemu-nbd.c index 7896e9b..2b29011 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -186,15 +186,9 @@ static int nbd_can_accept(void *opaque) return nb_fds < shared; } -static void nbd_read(void *opaque) +static void nbd_client_closed(NBDClient *client) { - int fd = (uintptr_t) opaque; - - if (nbd_trip(&exp, fd) != 0) { - qemu_set_fd_handler2(fd, NULL, NULL, NULL, NULL); - close(fd); - nb_fds--; - } + nb_fds--; } static void nbd_accept(void *opaque) @@ -204,8 +198,7 @@ static void nbd_accept(void *opaque) socklen_t addr_len = sizeof(addr); int fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len); - if (fd != -1 && nbd_negotiate(fd, exp.size, exp.nbdflags) != -1) { - qemu_set_fd_handler2(fd, NULL, nbd_read, NULL, (void *) (intptr_t) fd); + if (fd != -1 && nbd_client_new(exp, fd, nbd_client_closed)) { nb_fds++; } } -- 1.7.6