V3: Remove file lock in main(). Try to find new free nbd device and connect to it if connecting to the first first found free nbd device failed.
Signed-off-by: Chunyan Liu <cy...@suse.com> --- qemu-nbd.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 79 insertions(+), 1 deletions(-) diff --git a/qemu-nbd.c b/qemu-nbd.c index 291cba2..fcaaf50 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -32,6 +32,7 @@ #include <signal.h> #include <libgen.h> #include <pthread.h> +#include <fcntl.h> #define SOCKET_PATH "/var/lock/qemu-nbd-%s" @@ -244,6 +245,60 @@ out: return (void *) EXIT_FAILURE; } +static int is_nbd_used(int minor) +{ + FILE *proc; + int NBDMAJOR = 43; + char buf[BUFSIZ]; + int find = 0; + + proc = fopen("/proc/partitions", "r"); + if (proc != NULL) { + while (fgets(buf, sizeof(buf), proc)) { + int m, n; + unsigned long long sz; + char name[16]; + char *pname = name; + char *end; + + if (sscanf(buf, " %d %d %llu %128[^\n ]", + &m, &n, &sz, name) != 4) + continue; + if (m != NBDMAJOR) + continue; + if (strncmp(name, "nbd", 3)) + continue; + pname += 3; + n = strtol(pname, &end, 10); + if (end && end != pname && *end == '\0' && n == minor) { + find = 1; + break; + } + } + fclose(proc); + } + + return find; +} + +static char *find_free_nbd_device(void) +{ + int i; + int nbds_max = 16; + char name[16]; + char *devname = NULL; + + for (i = 0; i < nbds_max; i++) { + if (!is_nbd_used(i)) { + snprintf(name, sizeof(name), "/dev/nbd%d", i); + devname = strdup(name); + break; + } + } + + return devname; +} + int main(int argc, char **argv) { BlockDriverState *bs; @@ -256,7 +311,7 @@ int main(int argc, char **argv) struct sockaddr_in addr; socklen_t addr_len = sizeof(addr); off_t fd_size; - const char *sopt = "hVb:o:p:rsnP:c:dvk:e:t"; + const char *sopt = "hVb:o:p:rsnP:c:dvk:e:tf"; struct option lopt[] = { { "help", 0, NULL, 'h' }, { "version", 0, NULL, 'V' }, @@ -273,6 +328,7 @@ int main(int argc, char **argv) { "shared", 1, NULL, 'e' }, { "persistent", 0, NULL, 't' }, { "verbose", 0, NULL, 'v' }, + { "find", 0, NULL, 'f' }, { NULL, 0, NULL, 0 } }; int ch; @@ -292,6 +348,8 @@ int main(int argc, char **argv) int max_fd; int persistent = 0; pthread_t client_thread; + char *devname = NULL; + int find = 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. @@ -374,6 +432,18 @@ int main(int argc, char **argv) case 'v': verbose = 1; break; + case 'f': + find = 1; + devname = find_free_nbd_device(); + if (devname == NULL) + exit(1); + if (argc == optind) { + printf("%s\n", devname); + free(devname); + exit(0); + } + device = devname; + break; case 'V': version(argv[0]); exit(0); @@ -464,6 +534,7 @@ int main(int argc, char **argv) /* Open before spawning new threads. In the future, we may * drop privileges after opening. */ +retry: fd = open(device, O_RDWR); if (fd == -1) { err(EXIT_FAILURE, "Failed to open %s", device); @@ -577,6 +648,13 @@ int main(int argc, char **argv) if (device) { void *ret; pthread_join(client_thread, &ret); + if (ret != EXIT_SUCCESS && find) { + free(device); + device = find_free_nbd_device(); + if (!device) + err(EXIT_FAILURE, "Could not find free nbd device"); + goto retry; + } exit(ret != NULL); } else { exit(EXIT_SUCCESS); -- 1.7.3.4