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