qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Laurent.Vivier@bull.net
To: qemu-devel@nongnu.org
Cc: Laurent.Vivier@bull.net
Subject: [Qemu-devel] [patch 4/5] qemu-nbd: allow to share a disk image
Date: Fri, 27 Jun 2008 13:02:08 +0200	[thread overview]
Message-ID: <20080627110247.935215812@bull.net> (raw)
In-Reply-To: 20080627110204.818732368@bull.net

[-- Attachment #1: qemu-nbd-shared.patch --]
[-- Type: text/plain, Size: 6352 bytes --]

This patch allows to share a disk image using an NBD server.

You must specify by how many clients it could be shared:

server$ qemu-nbd --share=2 my_disk.qcow2

client1# nbd-client server 1024 /dev/nbd0
client2# nbd-client server 1024 /dev/nbd0

if you start a third client, it will hang until one of the previous connected
clients disconnects.
---
 qemu-nbd.c    |   92 ++++++++++++++++++++++++++++++++++++++++++++++------------
 qemu-nbd.texi |    2 +
 2 files changed, 75 insertions(+), 19 deletions(-)

Index: qemu/qemu-nbd.c
===================================================================
--- qemu.orig/qemu-nbd.c	2008-06-27 11:34:38.000000000 +0200
+++ qemu/qemu-nbd.c	2008-06-27 11:34:41.000000000 +0200
@@ -55,6 +55,7 @@ static void usage(const char *name)
 "  -n, --nocache        disable host cache\n"
 "  -c, --connect=DEV    connect FILE to the local NBD device DEV\n"
 "  -d, --disconnect     disconnect the specified device\n"
+"  -e, --shared=NUM     device can be shared by NUM clients (default '1')\n"
 "  -v, --verbose        display extra debugging information\n"
 "  -h, --help           display this help and exit\n"
 "  -V, --version        output version information and exit\n"
@@ -182,14 +183,13 @@ int main(int argc, char **argv)
     bool disconnect = false;
     const char *bindto = "0.0.0.0";
     int port = 1024;
-    int sock, csock;
     struct sockaddr_in addr;
     socklen_t addr_len = sizeof(addr);
     off_t fd_size;
     char *device = NULL;
     char *socket = NULL;
     char sockpath[128];
-    const char *sopt = "hVbo:p:rsnP:c:dvk:";
+    const char *sopt = "hVbo:p:rsnP:c:dvk:e:";
     struct option lopt[] = {
         { "help", 0, 0, 'h' },
         { "version", 0, 0, 'V' },
@@ -203,6 +203,7 @@ int main(int argc, char **argv)
         { "disconnect", 0, 0, 'd' },
         { "snapshot", 0, 0, 's' },
         { "nocache", 0, 0, 'n' },
+        { "shared", 1, 0, 'e' },
         { "verbose", 0, 0, 'v' },
         { NULL, 0, 0, 0 }
     };
@@ -212,9 +213,15 @@ int main(int argc, char **argv)
     char *end;
     int flags = 0;
     int partition = -1;
-    int fd;
     int ret;
+    int shared = 1;
     uint8_t *data;
+    fd_set fds;
+    int *sharing_fds;
+    int fd;
+    int i;
+    int nb_fds = 0;
+    int max_fd;
 
     while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
         switch (ch) {
@@ -267,6 +274,15 @@ int main(int argc, char **argv)
         case 'c':
             device = optarg;
             break;
+        case 'e':
+            shared = strtol(optarg, &end, 0);
+            if (*end) {
+                errx(EINVAL, "Invalid shared device number '%s'", optarg);
+            }
+            if (shared < 1) {
+                errx(EINVAL, "Shared device number must be greater than 0\n");
+            }
+            break;
         case 'v':
             verbose = 1;
             break;
@@ -321,6 +337,8 @@ int main(int argc, char **argv)
 
     if (device) {
 	pid_t pid;
+        int sock;
+
 	if (!verbose)
             daemon(0, 0);	/* detach client and server */
 
@@ -384,33 +402,69 @@ exit:
         /* children */
     }
 
+    sharing_fds = qemu_malloc((shared + 1) * sizeof(int));
+    if (sharing_fds == NULL)
+        errx(ENOMEM, "Cannot allocate sharing fds");
+
     if (socket) {
-        sock = unix_socket_incoming(socket);
+        sharing_fds[0] = unix_socket_incoming(socket);
     } else {
-        sock = tcp_socket_incoming(bindto, port);
+        sharing_fds[0] = tcp_socket_incoming(bindto, port);
     }
 
-    if (sock == -1)
+    if (sharing_fds[0] == -1)
         return 1;
+    max_fd = sharing_fds[0];
+    nb_fds++;
 
-    csock = accept(sock,
-               (struct sockaddr *)&addr,
-               &addr_len);
-    if (csock == -1)
-        return 1;
+    data = qemu_memalign(512, NBD_BUFFER_SIZE);
+    if (data == NULL)
+        errx(ENOMEM, "Cannot allocate data buffer");
 
-    /* new fd_size is calculated by find_partition */
-    if (nbd_negotiate(bs, csock, fd_size) == -1)
-        return 1;
+    do {
 
-    data = qemu_memalign(512, NBD_BUFFER_SIZE);
-    while (nbd_trip(bs, csock, fd_size, dev_offset, &offset, readonly,
-                    data, NBD_BUFFER_SIZE) == 0);
+        FD_ZERO(&fds);
+        for (i = 0; i < nb_fds; i++)
+            FD_SET(sharing_fds[i], &fds);
+
+        ret = select(max_fd + 1, &fds, NULL, NULL, NULL);
+        if (ret == -1)
+            break;
+
+        if (FD_ISSET(sharing_fds[0], &fds))
+            ret--;
+        for (i = 1; i < nb_fds && ret; i++) {
+            if (FD_ISSET(sharing_fds[i], &fds)) {
+                if (nbd_trip(bs, sharing_fds[i], fd_size, dev_offset,
+                    &offset, readonly, data, NBD_BUFFER_SIZE) != 0) {
+                    close(sharing_fds[i]);
+                    nb_fds--;
+                    sharing_fds[i] = sharing_fds[nb_fds];
+                    i--;
+                }
+                ret--;
+            }
+        }
+        /* new connection ? */
+        if (FD_ISSET(sharing_fds[0], &fds)) {
+            if (nb_fds < shared + 1) {
+                sharing_fds[nb_fds] = accept(sharing_fds[0],
+                                             (struct sockaddr *)&addr,
+                                             &addr_len);
+                if (sharing_fds[nb_fds] != -1 &&
+                    nbd_negotiate(bs, sharing_fds[nb_fds], fd_size) != -1) {
+                        if (sharing_fds[nb_fds] > max_fd)
+                            max_fd = sharing_fds[nb_fds];
+                        nb_fds++;
+                }
+            }
+        }
+    } while (nb_fds > 1);
     qemu_free(data);
 
-    close(csock);
-    close(sock);
+    close(sharing_fds[0]);
     bdrv_close(bs);
+    qemu_free(sharing_fds);
     if (socket)
         unlink(socket);
 
Index: qemu/qemu-nbd.texi
===================================================================
--- qemu.orig/qemu-nbd.texi	2008-06-27 11:34:38.000000000 +0200
+++ qemu/qemu-nbd.texi	2008-06-27 11:34:41.000000000 +0200
@@ -34,6 +34,8 @@ Export Qemu disk image using NBD protoco
   connect FILE to NBD device DEV
 @item -d, --disconnect
   disconnect the specified device
+@item -e, --shared=NUM
+  device can be shared by NUM clients (default '1')
 @item -v, --verbose
   display extra debugging information
 @item -h, --help

--

  parent reply	other threads:[~2008-06-27 11:03 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-06-27 11:02 [Qemu-devel] [patch 0/5] NBD support improvement Laurent.Vivier
2008-06-27 11:02 ` [Qemu-devel] [patch 1/5] qemu-nbd: cleanup Laurent.Vivier
2008-06-27 11:02 ` [Qemu-devel] [patch 2/5] qemu-nbd: merge NBD client/server Laurent.Vivier
2008-07-02 21:26   ` Thiemo Seufer
2008-07-03  7:21     ` Kevin Wolf
2008-07-03  8:13       ` Laurent Vivier
2008-07-03 10:27         ` Thiemo Seufer
2008-06-27 11:02 ` [Qemu-devel] [patch 3/5] qemu-nbd: add a parameter to disable host cache Laurent.Vivier
2008-06-27 11:02 ` Laurent.Vivier [this message]
2008-06-27 11:02 ` [Qemu-devel] [patch 5/5] Allow QEMU to connect directly to an NBD server Laurent.Vivier

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080627110247.935215812@bull.net \
    --to=laurent.vivier@bull.net \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).