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 | ... | ... |