qemu-nbd: rewrite termination conditions to use a state machine

Use a simple state machine with the following states:

- RUNNING     => accepting connections
- TERMINATE   => main loop must call nbd_export_close/put, and not accept
  connections anymore
- TERMINATING => waiting for pending requests to finish
- TERMINATED  => the NBDExport has been closed

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Paolo Bonzini 2012-09-18 13:31:56 +02:00
parent 0ddf08db22
commit 7860a380ac

View file

@ -41,8 +41,8 @@ static NBDExport *exp;
static int verbose;
static char *srcpath;
static char *sockpath;
static bool sigterm_reported;
static bool nbd_started;
static int persistent = 0;
static enum { RUNNING, TERMINATE, TERMINATING, TERMINATED } state;
static int shared = 1;
static int nb_fds;
@ -186,7 +186,7 @@ static int find_partition(BlockDriverState *bs, int partition,
static void termsig_handler(int signum)
{
sigterm_reported = true;
state = TERMINATE;
qemu_notify_event();
}
@ -269,10 +269,20 @@ static int nbd_can_accept(void *opaque)
return nb_fds < shared;
}
static void nbd_export_closed(NBDExport *exp)
{
assert(state == TERMINATING);
state = TERMINATED;
}
static void nbd_client_closed(NBDClient *client)
{
nb_fds--;
if (nb_fds == 0 && !persistent && state == RUNNING) {
state = TERMINATE;
}
qemu_notify_event();
nbd_client_put(client);
}
static void nbd_accept(void *opaque)
@ -282,7 +292,11 @@ static void nbd_accept(void *opaque)
socklen_t addr_len = sizeof(addr);
int fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len);
nbd_started = true;
if (state >= TERMINATE) {
close(fd);
return;
}
if (fd >= 0 && nbd_client_new(exp, fd, nbd_client_closed)) {
nb_fds++;
}
@ -329,7 +343,6 @@ int main(int argc, char **argv)
int partition = -1;
int ret;
int fd;
int persistent = 0;
bool seen_cache = false;
#ifdef CONFIG_LINUX_AIO
bool seen_aio = false;
@ -546,7 +559,7 @@ int main(int argc, char **argv)
}
}
exp = nbd_export_new(bs, dev_offset, fd_size, nbdflags, NULL);
exp = nbd_export_new(bs, dev_offset, fd_size, nbdflags, nbd_export_closed);
if (sockpath) {
fd = unix_socket_incoming(sockpath);
@ -581,14 +594,18 @@ int main(int argc, char **argv)
err(EXIT_FAILURE, "Could not chdir to root directory");
}
state = RUNNING;
do {
main_loop_wait(false);
} while (!sigterm_reported && (persistent || !nbd_started || nb_fds > 0));
if (state == TERMINATE) {
state = TERMINATING;
nbd_export_close(exp);
nbd_export_put(exp);
exp = NULL;
}
} while (state != TERMINATED);
nbd_export_close(exp);
nbd_export_put(exp);
bdrv_close(bs);
if (sockpath) {
unlink(sockpath);
}