Commit 3b05a8e91bf15e1858f3f3618069dbc78e55b88e
1 parent
2f726488
Allow to share a disk image via nbd, by Laurent Vivier.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4837 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
77 additions
and
21 deletions
qemu-nbd.c
| @@ -55,6 +55,7 @@ static void usage(const char *name) | @@ -55,6 +55,7 @@ static void usage(const char *name) | ||
| 55 | " -n, --nocache disable host cache\n" | 55 | " -n, --nocache disable host cache\n" |
| 56 | " -c, --connect=DEV connect FILE to the local NBD device DEV\n" | 56 | " -c, --connect=DEV connect FILE to the local NBD device DEV\n" |
| 57 | " -d, --disconnect disconnect the specified device\n" | 57 | " -d, --disconnect disconnect the specified device\n" |
| 58 | +" -e, --shared=NUM device can be shared by NUM clients (default '1')\n" | ||
| 58 | " -v, --verbose display extra debugging information\n" | 59 | " -v, --verbose display extra debugging information\n" |
| 59 | " -h, --help display this help and exit\n" | 60 | " -h, --help display this help and exit\n" |
| 60 | " -V, --version output version information and exit\n" | 61 | " -V, --version output version information and exit\n" |
| @@ -182,14 +183,13 @@ int main(int argc, char **argv) | @@ -182,14 +183,13 @@ int main(int argc, char **argv) | ||
| 182 | bool disconnect = false; | 183 | bool disconnect = false; |
| 183 | const char *bindto = "0.0.0.0"; | 184 | const char *bindto = "0.0.0.0"; |
| 184 | int port = 1024; | 185 | int port = 1024; |
| 185 | - int sock, csock; | ||
| 186 | struct sockaddr_in addr; | 186 | struct sockaddr_in addr; |
| 187 | socklen_t addr_len = sizeof(addr); | 187 | socklen_t addr_len = sizeof(addr); |
| 188 | off_t fd_size; | 188 | off_t fd_size; |
| 189 | char *device = NULL; | 189 | char *device = NULL; |
| 190 | char *socket = NULL; | 190 | char *socket = NULL; |
| 191 | char sockpath[128]; | 191 | char sockpath[128]; |
| 192 | - const char *sopt = "hVbo:p:rsnP:c:dvk:"; | 192 | + const char *sopt = "hVbo:p:rsnP:c:dvk:e:"; |
| 193 | struct option lopt[] = { | 193 | struct option lopt[] = { |
| 194 | { "help", 0, 0, 'h' }, | 194 | { "help", 0, 0, 'h' }, |
| 195 | { "version", 0, 0, 'V' }, | 195 | { "version", 0, 0, 'V' }, |
| @@ -203,6 +203,7 @@ int main(int argc, char **argv) | @@ -203,6 +203,7 @@ int main(int argc, char **argv) | ||
| 203 | { "disconnect", 0, 0, 'd' }, | 203 | { "disconnect", 0, 0, 'd' }, |
| 204 | { "snapshot", 0, 0, 's' }, | 204 | { "snapshot", 0, 0, 's' }, |
| 205 | { "nocache", 0, 0, 'n' }, | 205 | { "nocache", 0, 0, 'n' }, |
| 206 | + { "shared", 1, 0, 'e' }, | ||
| 206 | { "verbose", 0, 0, 'v' }, | 207 | { "verbose", 0, 0, 'v' }, |
| 207 | { NULL, 0, 0, 0 } | 208 | { NULL, 0, 0, 0 } |
| 208 | }; | 209 | }; |
| @@ -212,9 +213,15 @@ int main(int argc, char **argv) | @@ -212,9 +213,15 @@ int main(int argc, char **argv) | ||
| 212 | char *end; | 213 | char *end; |
| 213 | int flags = 0; | 214 | int flags = 0; |
| 214 | int partition = -1; | 215 | int partition = -1; |
| 215 | - int fd; | ||
| 216 | int ret; | 216 | int ret; |
| 217 | + int shared = 1; | ||
| 217 | uint8_t *data; | 218 | uint8_t *data; |
| 219 | + fd_set fds; | ||
| 220 | + int *sharing_fds; | ||
| 221 | + int fd; | ||
| 222 | + int i; | ||
| 223 | + int nb_fds = 0; | ||
| 224 | + int max_fd; | ||
| 218 | 225 | ||
| 219 | while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) { | 226 | while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) { |
| 220 | switch (ch) { | 227 | switch (ch) { |
| @@ -267,6 +274,15 @@ int main(int argc, char **argv) | @@ -267,6 +274,15 @@ int main(int argc, char **argv) | ||
| 267 | case 'c': | 274 | case 'c': |
| 268 | device = optarg; | 275 | device = optarg; |
| 269 | break; | 276 | break; |
| 277 | + case 'e': | ||
| 278 | + shared = strtol(optarg, &end, 0); | ||
| 279 | + if (*end) { | ||
| 280 | + errx(EINVAL, "Invalid shared device number '%s'", optarg); | ||
| 281 | + } | ||
| 282 | + if (shared < 1) { | ||
| 283 | + errx(EINVAL, "Shared device number must be greater than 0\n"); | ||
| 284 | + } | ||
| 285 | + break; | ||
| 270 | case 'v': | 286 | case 'v': |
| 271 | verbose = 1; | 287 | verbose = 1; |
| 272 | break; | 288 | break; |
| @@ -320,8 +336,10 @@ int main(int argc, char **argv) | @@ -320,8 +336,10 @@ int main(int argc, char **argv) | ||
| 320 | errx(errno, "Could not find partition %d", partition); | 336 | errx(errno, "Could not find partition %d", partition); |
| 321 | 337 | ||
| 322 | if (device) { | 338 | if (device) { |
| 323 | - pid_t pid; | ||
| 324 | - if (!verbose) | 339 | + pid_t pid; |
| 340 | + int sock; | ||
| 341 | + | ||
| 342 | + if (!verbose) | ||
| 325 | daemon(0, 0); /* detach client and server */ | 343 | daemon(0, 0); /* detach client and server */ |
| 326 | 344 | ||
| 327 | if (socket == NULL) { | 345 | if (socket == NULL) { |
| @@ -384,33 +402,69 @@ int main(int argc, char **argv) | @@ -384,33 +402,69 @@ int main(int argc, char **argv) | ||
| 384 | /* children */ | 402 | /* children */ |
| 385 | } | 403 | } |
| 386 | 404 | ||
| 405 | + sharing_fds = qemu_malloc((shared + 1) * sizeof(int)); | ||
| 406 | + if (sharing_fds == NULL) | ||
| 407 | + errx(ENOMEM, "Cannot allocate sharing fds"); | ||
| 408 | + | ||
| 387 | if (socket) { | 409 | if (socket) { |
| 388 | - sock = unix_socket_incoming(socket); | 410 | + sharing_fds[0] = unix_socket_incoming(socket); |
| 389 | } else { | 411 | } else { |
| 390 | - sock = tcp_socket_incoming(bindto, port); | 412 | + sharing_fds[0] = tcp_socket_incoming(bindto, port); |
| 391 | } | 413 | } |
| 392 | 414 | ||
| 393 | - if (sock == -1) | 415 | + if (sharing_fds[0] == -1) |
| 394 | return 1; | 416 | return 1; |
| 417 | + max_fd = sharing_fds[0]; | ||
| 418 | + nb_fds++; | ||
| 395 | 419 | ||
| 396 | - csock = accept(sock, | ||
| 397 | - (struct sockaddr *)&addr, | ||
| 398 | - &addr_len); | ||
| 399 | - if (csock == -1) | ||
| 400 | - return 1; | 420 | + data = qemu_memalign(512, NBD_BUFFER_SIZE); |
| 421 | + if (data == NULL) | ||
| 422 | + errx(ENOMEM, "Cannot allocate data buffer"); | ||
| 401 | 423 | ||
| 402 | - /* new fd_size is calculated by find_partition */ | ||
| 403 | - if (nbd_negotiate(bs, csock, fd_size) == -1) | ||
| 404 | - return 1; | 424 | + do { |
| 405 | 425 | ||
| 406 | - data = qemu_memalign(512, NBD_BUFFER_SIZE); | ||
| 407 | - while (nbd_trip(bs, csock, fd_size, dev_offset, &offset, readonly, | ||
| 408 | - data, NBD_BUFFER_SIZE) == 0); | 426 | + FD_ZERO(&fds); |
| 427 | + for (i = 0; i < nb_fds; i++) | ||
| 428 | + FD_SET(sharing_fds[i], &fds); | ||
| 429 | + | ||
| 430 | + ret = select(max_fd + 1, &fds, NULL, NULL, NULL); | ||
| 431 | + if (ret == -1) | ||
| 432 | + break; | ||
| 433 | + | ||
| 434 | + if (FD_ISSET(sharing_fds[0], &fds)) | ||
| 435 | + ret--; | ||
| 436 | + for (i = 1; i < nb_fds && ret; i++) { | ||
| 437 | + if (FD_ISSET(sharing_fds[i], &fds)) { | ||
| 438 | + if (nbd_trip(bs, sharing_fds[i], fd_size, dev_offset, | ||
| 439 | + &offset, readonly, data, NBD_BUFFER_SIZE) != 0) { | ||
| 440 | + close(sharing_fds[i]); | ||
| 441 | + nb_fds--; | ||
| 442 | + sharing_fds[i] = sharing_fds[nb_fds]; | ||
| 443 | + i--; | ||
| 444 | + } | ||
| 445 | + ret--; | ||
| 446 | + } | ||
| 447 | + } | ||
| 448 | + /* new connection ? */ | ||
| 449 | + if (FD_ISSET(sharing_fds[0], &fds)) { | ||
| 450 | + if (nb_fds < shared + 1) { | ||
| 451 | + sharing_fds[nb_fds] = accept(sharing_fds[0], | ||
| 452 | + (struct sockaddr *)&addr, | ||
| 453 | + &addr_len); | ||
| 454 | + if (sharing_fds[nb_fds] != -1 && | ||
| 455 | + nbd_negotiate(bs, sharing_fds[nb_fds], fd_size) != -1) { | ||
| 456 | + if (sharing_fds[nb_fds] > max_fd) | ||
| 457 | + max_fd = sharing_fds[nb_fds]; | ||
| 458 | + nb_fds++; | ||
| 459 | + } | ||
| 460 | + } | ||
| 461 | + } | ||
| 462 | + } while (nb_fds > 1); | ||
| 409 | qemu_free(data); | 463 | qemu_free(data); |
| 410 | 464 | ||
| 411 | - close(csock); | ||
| 412 | - close(sock); | 465 | + close(sharing_fds[0]); |
| 413 | bdrv_close(bs); | 466 | bdrv_close(bs); |
| 467 | + qemu_free(sharing_fds); | ||
| 414 | if (socket) | 468 | if (socket) |
| 415 | unlink(socket); | 469 | unlink(socket); |
| 416 | 470 |
qemu-nbd.texi
| @@ -34,6 +34,8 @@ Export Qemu disk image using NBD protocol. | @@ -34,6 +34,8 @@ Export Qemu disk image using NBD protocol. | ||
| 34 | connect FILE to NBD device DEV | 34 | connect FILE to NBD device DEV |
| 35 | @item -d, --disconnect | 35 | @item -d, --disconnect |
| 36 | disconnect the specified device | 36 | disconnect the specified device |
| 37 | +@item -e, --shared=NUM | ||
| 38 | + device can be shared by NUM clients (default '1') | ||
| 37 | @item -v, --verbose | 39 | @item -v, --verbose |
| 38 | display extra debugging information | 40 | display extra debugging information |
| 39 | @item -h, --help | 41 | @item -h, --help |