According to Stefan's suggestion, will loop over /dev/nbd%d to do "qemu-nbd -f disk.img", if fails, try next device. To make "qemu-nbd -c" and "qemu-nbd -f" share codes as more as possible, extract the shared codes to a function nbd_setup(). Current qemu-nbd functions work well still.
Signed-off-by: Chunyan Liu <cy...@suse.com> --- qemu-nbd.c | 300 ++++++++++++++++++++++++++++++++---------------------------- 1 files changed, 159 insertions(+), 141 deletions(-) diff --git a/qemu-nbd.c b/qemu-nbd.c index 291cba2..83ae30f 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -42,6 +42,18 @@ static int verbose; static char *device; static char *srcpath; static char *sockpath; +static int is_sockpath_option; +static int sigterm_fd[2]; +static off_t dev_offset; +static uint32_t nbdflags; +static bool disconnect; +static const char *bindto = "0.0.0.0"; +static int port = NBD_DEFAULT_PORT; +static int li; +static int flags = BDRV_O_RDWR; +static int partition = -1; +static int shared = 1; +static int persistent; static void usage(const char *name) { @@ -171,9 +183,7 @@ static int find_partition(BlockDriverState *bs, int partition, static void termsig_handler(int signum) { static int sigterm_reported; - if (!sigterm_reported) { - sigterm_reported = (write(sigterm_wfd, "", 1) == 1); - } + sigterm_reported = (write(sigterm_wfd, "", 1) == 1); } static void *show_parts(void *arg) @@ -244,18 +254,152 @@ out: return (void *) EXIT_FAILURE; } -int main(int argc, char **argv) +static int nbd_setup(void) { BlockDriverState *bs; - off_t dev_offset = 0; off_t offset = 0; - uint32_t nbdflags = 0; - bool disconnect = false; - const char *bindto = "0.0.0.0"; - int port = NBD_DEFAULT_PORT; struct sockaddr_in addr; socklen_t addr_len = sizeof(addr); off_t fd_size; + uint8_t *data; + fd_set fds; + int *sharing_fds; + int fd; + int i; + int nb_fds = 0; + int max_fd; + pthread_t client_thread; + int ret; + + if (device) { + /* Open before spawning new threads. In the future, we may + * drop privileges after opening. + */ + fd = open(device, O_RDWR); + if (fd == -1) { + err(EXIT_FAILURE, "Failed to open %s", device); + } + + if (sockpath == NULL) { + sockpath = g_malloc(128); + snprintf(sockpath, 128, SOCKET_PATH, basename(device)); + } + } + + bs = bdrv_new("hda"); + if ((ret = bdrv_open(bs, srcpath, flags, NULL)) < 0) { + errno = -ret; + err(EXIT_FAILURE, "Failed to bdrv_open '%s'", srcpath); + } + + fd_size = bs->total_sectors * 512; + + if (partition != -1 && + find_partition(bs, partition, &dev_offset, &fd_size)) { + err(EXIT_FAILURE, "Could not find partition %d", partition); + } + + sharing_fds = g_malloc((shared + 1) * sizeof(int)); + + if (sockpath) { + sharing_fds[0] = unix_socket_incoming(sockpath); + } else { + sharing_fds[0] = tcp_socket_incoming(bindto, port); + } + + if (sharing_fds[0] == -1) + return 1; + + if (device) { + int ret; + + ret = pthread_create(&client_thread, NULL, nbd_client_thread, &fd); + if (ret != 0) { + errx(EXIT_FAILURE, "Failed to create client thread: %s", + strerror(ret)); + } + } else { + /* Shut up GCC warnings. */ + memset(&client_thread, 0, sizeof(client_thread)); + } + + max_fd = sharing_fds[0]; + nb_fds++; + + data = qemu_blockalign(bs, NBD_BUFFER_SIZE); + if (data == NULL) { + errx(EXIT_FAILURE, "Cannot allocate data buffer"); + } + + do { + FD_ZERO(&fds); + FD_SET(sigterm_fd[0], &fds); + for (i = 0; i < nb_fds; i++) + FD_SET(sharing_fds[i], &fds); + + do { + ret = select(max_fd + 1, &fds, NULL, NULL, NULL); + } while (ret == -1 && errno == EINTR); + if (ret == -1 || FD_ISSET(sigterm_fd[0], &fds)) { + int sigbuf[1]; + read(sigterm_fd[0], sigbuf, 1); + break; + } + + if (FD_ISSET(sharing_fds[0], &fds)) + ret--; + for (i = 1; i < nb_fds && ret; i++) { + if (FD_ISSET(sharing_fds[i], &fds)) { + if (nbd_trip(bs, sharing_fds[i], fd_size, dev_offset, + &offset, nbdflags, data, NBD_BUFFER_SIZE) != 0) { + close(sharing_fds[i]); + nb_fds--; + sharing_fds[i] = sharing_fds[nb_fds]; + i--; + } + ret--; + } + } + /* new connection ? */ + if (FD_ISSET(sharing_fds[0], &fds)) { + if (nb_fds < shared + 1) { + sharing_fds[nb_fds] = accept(sharing_fds[0], + (struct sockaddr *)&addr, + &addr_len); + if (sharing_fds[nb_fds] != -1 && + nbd_negotiate(sharing_fds[nb_fds], fd_size, nbdflags) != -1) { + if (sharing_fds[nb_fds] > max_fd) + max_fd = sharing_fds[nb_fds]; + nb_fds++; + } + } + } + } while (persistent || nb_fds > 1); + qemu_vfree(data); + + close(sharing_fds[0]); + g_free(sharing_fds); + if (sockpath) { + unlink(sockpath); + } + if (bs) { + bdrv_delete(bs); + } + if (!is_sockpath_option) { + sockpath = NULL; + } + + if (device) { + void *ret; + pthread_join(client_thread, &ret); + return (ret != NULL) ? EXIT_FAILURE : EXIT_SUCCESS; + } else { + return EXIT_SUCCESS; + } +} + +int main(int argc, char **argv) +{ const char *sopt = "hVb:o:p:rsnP:c:dvk:e:t"; struct option lopt[] = { { "help", 0, NULL, 'h' }, @@ -277,27 +421,14 @@ int main(int argc, char **argv) }; int ch; int opt_ind = 0; - int li; char *end; - int flags = BDRV_O_RDWR; - int partition = -1; - int ret; - int shared = 1; - uint8_t *data; - fd_set fds; - int *sharing_fds; - int fd; - int i; - int nb_fds = 0; - int max_fd; - int persistent = 0; - pthread_t client_thread; + int ret = 0; /* The client thread uses SIGTERM to interrupt the server. A signal * handler ensures that "qemu-nbd -v -c" exits with a nice status code. */ struct sigaction sa_sigterm; - int sigterm_fd[2]; + if (qemu_pipe(sigterm_fd) == -1) { err(EXIT_FAILURE, "Error setting up communication pipe"); } @@ -352,6 +483,7 @@ int main(int argc, char **argv) sockpath = optarg; if (sockpath[0] != '/') errx(EXIT_FAILURE, "socket path must be absolute\n"); + is_sockpath_option = 1; break; case 'd': disconnect = true; @@ -395,6 +527,7 @@ int main(int argc, char **argv) } if (disconnect) { + int fd; fd = open(argv[optind], O_RDWR); if (fd == -1) err(EXIT_FAILURE, "Cannot open %s", argv[optind]); @@ -411,7 +544,6 @@ int main(int argc, char **argv) if (device && !verbose) { int stderr_fd[2]; pid_t pid; - int ret; if (qemu_pipe(stderr_fd) == -1) { err(EXIT_FAILURE, "Error setting up communication pipe"); @@ -460,125 +592,11 @@ int main(int argc, char **argv) } } - if (device) { - /* Open before spawning new threads. In the future, we may - * drop privileges after opening. - */ - fd = open(device, O_RDWR); - if (fd == -1) { - err(EXIT_FAILURE, "Failed to open %s", device); - } - - if (sockpath == NULL) { - sockpath = g_malloc(128); - snprintf(sockpath, 128, SOCKET_PATH, basename(device)); - } - } - bdrv_init(); atexit(bdrv_close_all); - - bs = bdrv_new("hda"); srcpath = argv[optind]; - if ((ret = bdrv_open(bs, srcpath, flags, NULL)) < 0) { - errno = -ret; - err(EXIT_FAILURE, "Failed to bdrv_open '%s'", argv[optind]); - } - - fd_size = bs->total_sectors * 512; - - if (partition != -1 && - find_partition(bs, partition, &dev_offset, &fd_size)) { - err(EXIT_FAILURE, "Could not find partition %d", partition); - } - - sharing_fds = g_malloc((shared + 1) * sizeof(int)); - - if (sockpath) { - sharing_fds[0] = unix_socket_incoming(sockpath); - } else { - sharing_fds[0] = tcp_socket_incoming(bindto, port); - } - - if (sharing_fds[0] == -1) - return 1; - - if (device) { - int ret; - - ret = pthread_create(&client_thread, NULL, nbd_client_thread, &fd); - if (ret != 0) { - errx(EXIT_FAILURE, "Failed to create client thread: %s", - strerror(ret)); - } - } else { - /* Shut up GCC warnings. */ - memset(&client_thread, 0, sizeof(client_thread)); - } - - max_fd = sharing_fds[0]; - nb_fds++; - - data = qemu_blockalign(bs, NBD_BUFFER_SIZE); - if (data == NULL) { - errx(EXIT_FAILURE, "Cannot allocate data buffer"); - } - - do { - FD_ZERO(&fds); - FD_SET(sigterm_fd[0], &fds); - for (i = 0; i < nb_fds; i++) - FD_SET(sharing_fds[i], &fds); - - do { - ret = select(max_fd + 1, &fds, NULL, NULL, NULL); - } while (ret == -1 && errno == EINTR); - if (ret == -1 || FD_ISSET(sigterm_fd[0], &fds)) { - break; - } - - if (FD_ISSET(sharing_fds[0], &fds)) - ret--; - for (i = 1; i < nb_fds && ret; i++) { - if (FD_ISSET(sharing_fds[i], &fds)) { - if (nbd_trip(bs, sharing_fds[i], fd_size, dev_offset, - &offset, nbdflags, data, NBD_BUFFER_SIZE) != 0) { - close(sharing_fds[i]); - nb_fds--; - sharing_fds[i] = sharing_fds[nb_fds]; - i--; - } - ret--; - } - } - /* new connection ? */ - if (FD_ISSET(sharing_fds[0], &fds)) { - if (nb_fds < shared + 1) { - sharing_fds[nb_fds] = accept(sharing_fds[0], - (struct sockaddr *)&addr, - &addr_len); - if (sharing_fds[nb_fds] != -1 && - nbd_negotiate(sharing_fds[nb_fds], fd_size, nbdflags) != -1) { - if (sharing_fds[nb_fds] > max_fd) - max_fd = sharing_fds[nb_fds]; - nb_fds++; - } - } - } - } while (persistent || nb_fds > 1); - qemu_vfree(data); - close(sharing_fds[0]); - g_free(sharing_fds); - if (sockpath) { - unlink(sockpath); - } + ret = nbd_setup(); - if (device) { - void *ret; - pthread_join(client_thread, &ret); - exit(ret != NULL); - } else { - exit(EXIT_SUCCESS); - } + exit(ret); } -- 1.7.3.4