diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2012-09-18 13:31:56 +0200 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2012-09-19 15:26:29 +0200 |
commit | 7860a380ac2a9fd09a6e8f31fd9db5318fc91285 (patch) | |
tree | 3f8850554633c9d9e0c14a8926862c31ac2cef54 | |
parent | 0ddf08db22a9ef6b122d8c4cfe5b25d2c2c51962 (diff) |
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>
-rw-r--r-- | qemu-nbd.c | 37 |
1 files changed, 27 insertions, 10 deletions
diff --git a/qemu-nbd.c b/qemu-nbd.c index 8b87dea5f6..15bcd08123 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -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); } |