Commit 3b05a8e91bf15e1858f3f3618069dbc78e55b88e

Authored by ths
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