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 | 55 | " -n, --nocache disable host cache\n" |
| 56 | 56 | " -c, --connect=DEV connect FILE to the local NBD device DEV\n" |
| 57 | 57 | " -d, --disconnect disconnect the specified device\n" |
| 58 | +" -e, --shared=NUM device can be shared by NUM clients (default '1')\n" | |
| 58 | 59 | " -v, --verbose display extra debugging information\n" |
| 59 | 60 | " -h, --help display this help and exit\n" |
| 60 | 61 | " -V, --version output version information and exit\n" |
| ... | ... | @@ -182,14 +183,13 @@ int main(int argc, char **argv) |
| 182 | 183 | bool disconnect = false; |
| 183 | 184 | const char *bindto = "0.0.0.0"; |
| 184 | 185 | int port = 1024; |
| 185 | - int sock, csock; | |
| 186 | 186 | struct sockaddr_in addr; |
| 187 | 187 | socklen_t addr_len = sizeof(addr); |
| 188 | 188 | off_t fd_size; |
| 189 | 189 | char *device = NULL; |
| 190 | 190 | char *socket = NULL; |
| 191 | 191 | char sockpath[128]; |
| 192 | - const char *sopt = "hVbo:p:rsnP:c:dvk:"; | |
| 192 | + const char *sopt = "hVbo:p:rsnP:c:dvk:e:"; | |
| 193 | 193 | struct option lopt[] = { |
| 194 | 194 | { "help", 0, 0, 'h' }, |
| 195 | 195 | { "version", 0, 0, 'V' }, |
| ... | ... | @@ -203,6 +203,7 @@ int main(int argc, char **argv) |
| 203 | 203 | { "disconnect", 0, 0, 'd' }, |
| 204 | 204 | { "snapshot", 0, 0, 's' }, |
| 205 | 205 | { "nocache", 0, 0, 'n' }, |
| 206 | + { "shared", 1, 0, 'e' }, | |
| 206 | 207 | { "verbose", 0, 0, 'v' }, |
| 207 | 208 | { NULL, 0, 0, 0 } |
| 208 | 209 | }; |
| ... | ... | @@ -212,9 +213,15 @@ int main(int argc, char **argv) |
| 212 | 213 | char *end; |
| 213 | 214 | int flags = 0; |
| 214 | 215 | int partition = -1; |
| 215 | - int fd; | |
| 216 | 216 | int ret; |
| 217 | + int shared = 1; | |
| 217 | 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 | 226 | while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) { |
| 220 | 227 | switch (ch) { |
| ... | ... | @@ -267,6 +274,15 @@ int main(int argc, char **argv) |
| 267 | 274 | case 'c': |
| 268 | 275 | device = optarg; |
| 269 | 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 | 286 | case 'v': |
| 271 | 287 | verbose = 1; |
| 272 | 288 | break; |
| ... | ... | @@ -320,8 +336,10 @@ int main(int argc, char **argv) |
| 320 | 336 | errx(errno, "Could not find partition %d", partition); |
| 321 | 337 | |
| 322 | 338 | if (device) { |
| 323 | - pid_t pid; | |
| 324 | - if (!verbose) | |
| 339 | + pid_t pid; | |
| 340 | + int sock; | |
| 341 | + | |
| 342 | + if (!verbose) | |
| 325 | 343 | daemon(0, 0); /* detach client and server */ |
| 326 | 344 | |
| 327 | 345 | if (socket == NULL) { |
| ... | ... | @@ -384,33 +402,69 @@ int main(int argc, char **argv) |
| 384 | 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 | 409 | if (socket) { |
| 388 | - sock = unix_socket_incoming(socket); | |
| 410 | + sharing_fds[0] = unix_socket_incoming(socket); | |
| 389 | 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 | 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 | 463 | qemu_free(data); |
| 410 | 464 | |
| 411 | - close(csock); | |
| 412 | - close(sock); | |
| 465 | + close(sharing_fds[0]); | |
| 413 | 466 | bdrv_close(bs); |
| 467 | + qemu_free(sharing_fds); | |
| 414 | 468 | if (socket) |
| 415 | 469 | unlink(socket); |
| 416 | 470 | ... | ... |
qemu-nbd.texi
| ... | ... | @@ -34,6 +34,8 @@ Export Qemu disk image using NBD protocol. |
| 34 | 34 | connect FILE to NBD device DEV |
| 35 | 35 | @item -d, --disconnect |
| 36 | 36 | disconnect the specified device |
| 37 | +@item -e, --shared=NUM | |
| 38 | + device can be shared by NUM clients (default '1') | |
| 37 | 39 | @item -v, --verbose |
| 38 | 40 | display extra debugging information |
| 39 | 41 | @item -h, --help | ... | ... |