qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] Merge NBD client/server int qemu-nbd
@ 2008-06-13 15:15 Laurent Vivier
  2008-06-13 17:49 ` Anthony Liguori
  0 siblings, 1 reply; 18+ messages in thread
From: Laurent Vivier @ 2008-06-13 15:15 UTC (permalink / raw)
  To: qemu-devel@nongnu.org; +Cc: Anthony Liguori

[-- Attachment #1: Type: text/plain, Size: 931 bytes --]

Hi,

this patch allows to connect directly a disk image file to an NBD
device. It introduces the use of a unix socket (instead of inet).

- To connect a file to a device:

# qemu-nbd --connect=/dev/nbd0 my_disk.qcow2

Then you can see directly your disk (no need of nbd-client):

# fdisk -l /dev/nbd0

Disk /dev/nbd0: 4294 MB, 4294967296 bytes
255 heads, 63 sectors/track, 522 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

     Device Boot      Start         End      Blocks   Id  System
/dev/nbd0p1   *           1         492     3951958+  83  Linux
/dev/nbd0p2             493         522      240975    5  Extended
/dev/nbd0p5             493         522      240943+  82  Linux swap /
Solaris

- To disconnect the file from the device:

# qemu-nbd --disconnect /dev/nbd0

Regards,
Laurent
-- 
------------- Laurent.Vivier@bull.net ---------------
"The best way to predict the future is to invent it."
- Alan Kay

[-- Attachment #2: qemu-nbd-local.patch --]
[-- Type: text/x-patch, Size: 7873 bytes --]

Index: qemu/nbd.c
===================================================================
--- qemu.orig/nbd.c	2008-06-13 13:06:24.000000000 +0200
+++ qemu/nbd.c	2008-06-13 17:02:55.000000000 +0200
@@ -25,6 +25,7 @@
 #include <ctype.h>
 #include <inttypes.h>
 #include <sys/socket.h>
+#include <sys/un.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <arpa/inet.h>
@@ -183,6 +184,65 @@ error:
     return -1;
 }
 
+int unix_socket_incoming(const char *path)
+{
+    int s;
+    struct sockaddr_un addr;
+    int serrno;
+
+    s = socket(PF_UNIX, SOCK_STREAM, 0);
+    if (s == -1) {
+        return -1;
+    }
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sun_family = AF_UNIX;
+    pstrcpy(addr.sun_path, sizeof(addr.sun_path), path);
+
+    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+        goto error;
+    }
+
+    if (listen(s, 128) == -1) {
+        goto error;
+    }
+
+    return s;
+error:
+    serrno = errno;
+    close(s);
+    errno = serrno;
+    return -1;
+}
+
+int unix_socket_outgoing(const char *path)
+{
+    int s;
+    struct sockaddr_un addr;
+    int serrno;
+
+    s = socket(PF_UNIX, SOCK_STREAM, 0);
+    if (s == -1) {
+        return -1;
+    }
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sun_family = AF_UNIX;
+    pstrcpy(addr.sun_path, sizeof(addr.sun_path), path);
+
+    if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+        goto error;
+    }
+
+    return s;
+error:
+    serrno = errno;
+    close(s);
+    errno = serrno;
+    return -1;
+}
+
+
 /* Basic flow
 
    Server         Client
@@ -388,7 +448,7 @@ int nbd_trip(BlockDriverState *bs, int c
 	}
 
 	if (len > sizeof(data)) {
-		LOG("len (%u) is larger than max len (%u)",
+		LOG("len (%u) is larger than max len (%lu)",
 		    len, sizeof(data));
 		errno = EINVAL;
 		return -1;
Index: qemu/nbd.h
===================================================================
--- qemu.orig/nbd.h	2008-06-13 13:06:26.000000000 +0200
+++ qemu/nbd.h	2008-06-13 15:17:57.000000000 +0200
@@ -27,6 +27,8 @@
 #include "block_int.h"
 
 int tcp_socket_incoming(const char *address, uint16_t port);
+int unix_socket_outgoing(const char *path);
+int unix_socket_incoming(const char *path);
 
 int nbd_negotiate(BlockDriverState *bs, int csock, off_t size);
 int nbd_receive_negotiate(int fd, int csock);
Index: qemu/qemu-nbd.c
===================================================================
--- qemu.orig/qemu-nbd.c	2008-06-13 13:06:19.000000000 +0200
+++ qemu/qemu-nbd.c	2008-06-13 17:13:54.000000000 +0200
@@ -21,15 +21,18 @@
 #include "block_int.h"
 #include "nbd.h"
 
-#include <malloc.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <getopt.h>
 #include <err.h>
+#include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <arpa/inet.h>
+#include <signal.h>
+
+//#define DEBUG
 
 int verbose;
 
@@ -44,6 +47,8 @@ static void usage(const char *name)
 "  -b, --bind=IFACE     interface to bind to (default `0.0.0.0')\n"
 "  -r, --read-only      export read-only\n"
 "  -P, --partition=NUM  only expose partition NUM\n"
+"  -c, --connect=DEV    connect FILE to the local NBD device DEV\n"
+"  -d, --disconnect     disconnect the specified device\n"
 "  -v, --verbose        display extra debugging information\n"
 "  -h, --help           display this help and exit\n"
 "  -V, --version        output version information and exit\n"
@@ -145,19 +150,42 @@ static int find_partition(BlockDriverSta
     return -1;
 }
 
+static void show_parts(const char *device)
+{
+    if (fork() == 0) {
+        int nbd;
+
+	/* wait device */
+        sleep(1);
+        /* linux just needs an open() to trigger
+         * the partition table update
+         * but remember to load the module with max_part != 0 :
+         *     modprobe nbd max_part=63
+         */
+        nbd = open(device, O_RDWR);
+        if (nbd == -1)
+            return;
+        close(nbd);
+        exit(0);
+    }
+}
+
 int main(int argc, char **argv)
 {
     BlockDriverState *bs;
     off_t dev_offset = 0;
     off_t offset = 0;
     bool readonly = false;
+    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;
-    const char *sopt = "hVbo:p:rsP:v";
+    char *device;
+    char sockpath[128];
+    const char *sopt = "hVbo:p:rsP:c:dv?";
     struct option lopt[] = {
         { "help", 0, 0, 'h' },
         { "version", 0, 0, 'V' },
@@ -166,8 +194,11 @@ int main(int argc, char **argv)
         { "offset", 1, 0, 'o' },
         { "read-only", 0, 0, 'r' },
         { "partition", 1, 0, 'P' },
+        { "connect", 1, 0, 'c' },
+        { "disconnect", 0, 0, 'd' },
         { "snapshot", 0, 0, 's' },
         { "verbose", 0, 0, 'v' },
+	{ 0, 0, 0, 0 }
     };
     int ch;
     int opt_ind = 0;
@@ -175,6 +206,8 @@ int main(int argc, char **argv)
     char *end;
     bool snapshot = false;
     int partition = -1;
+    int fd;
+    int ret;
 
     while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
         switch (ch) {
@@ -213,6 +246,12 @@ int main(int argc, char **argv)
             if (partition < 1 || partition > 8)
                 errx(EINVAL, "Invalid partition %d", partition);
             break;
+        case 'd':
+            disconnect = true;
+            break;
+        case 'c':
+            device = optarg;
+            break;
         case 'v':
             verbose = 1;
             break;
@@ -236,6 +275,20 @@ int main(int argc, char **argv)
              argv[0]);
     }
 
+    if (disconnect) {
+        fd = open(argv[optind], O_RDWR);
+        if (fd == -1)
+            errx(errno, "Cannot open %s", argv[optind]);
+
+        nbd_disconnect(fd);
+
+        close(fd);
+
+        printf("%s disconnected\n", argv[optind]);
+
+	return 0;
+    }
+
     bdrv_init();
 
     bs = bdrv_new("hda");
@@ -251,7 +304,56 @@ int main(int argc, char **argv)
         find_partition(bs, partition, &dev_offset, &fd_size))
         errx(errno, "Could not find partition %d", partition);
 
-    sock = tcp_socket_incoming(bindto, port);
+    if (device) {
+	pid_t pid;
+	if (!verbose)
+            daemon(0, 0);	/* detach client and server */
+
+        sprintf(sockpath, "/var/lock/qemu-img-%s", basename(device));
+
+        pid = fork();
+        if (pid < 0)
+            return 1;
+	if (pid != 0) {
+            ret = 0;
+            bdrv_close(bs);
+
+            do {
+                sock = unix_socket_outgoing(sockpath);
+                if (sock == -1) {
+                    if (errno != ENOENT && errno != ECONNREFUSED)
+                        goto exit;
+                    sleep(1);	/* wait children */
+                }
+            } while (sock == -1);
+
+            fd = open(device, O_RDWR);
+            if (fd == -1) {
+                ret = -1;
+                goto exit;
+            }
+
+            ret = nbd_receive_negotiate(fd, sock);
+            if (ret == -1)
+                goto exit;
+
+            printf("NBD device %s is now connected to file %s\n",
+                    device, argv[optind]);
+
+            nbd_client(fd, sock);
+            close(fd);
+exit:
+            kill(pid, SIGTERM);
+            unlink(sockpath);
+
+            return ret;
+        }
+        /* children */
+        sock = unix_socket_incoming(sockpath);
+    } else {
+        sock = tcp_socket_incoming(bindto, port);
+    }
+
     if (sock == -1)
         return 1;
 
@@ -265,6 +367,11 @@ int main(int argc, char **argv)
     if (nbd_negotiate(bs, csock, fd_size) == -1)
         return 1;
 
+    /* if supported, update partition table */
+
+    if (device)
+        show_parts(device);
+
     while (nbd_trip(bs, csock, fd_size, dev_offset, &offset, readonly) == 0);
 
     close(csock);

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [PATCH] Merge NBD client/server int qemu-nbd
  2008-06-13 15:15 [Qemu-devel] [PATCH] Merge NBD client/server int qemu-nbd Laurent Vivier
@ 2008-06-13 17:49 ` Anthony Liguori
  2008-06-13 18:09   ` Avi Kivity
  2008-06-13 18:39   ` Laurent Vivier
  0 siblings, 2 replies; 18+ messages in thread
From: Anthony Liguori @ 2008-06-13 17:49 UTC (permalink / raw)
  To: qemu-devel@nongnu.org

Laurent Vivier wrote:
> Hi,
>
> this patch allows to connect directly a disk image file to an NBD
> device. It introduces the use of a unix socket (instead of inet).
>
> - To connect a file to a device:
>
> # qemu-nbd --connect=/dev/nbd0 my_disk.qcow2
>
> Then you can see directly your disk (no need of nbd-client):
>
> # fdisk -l /dev/nbd0
>
> Disk /dev/nbd0: 4294 MB, 4294967296 bytes
> 255 heads, 63 sectors/track, 522 cylinders
> Units = cylinders of 16065 * 512 = 8225280 bytes
>
>      Device Boot      Start         End      Blocks   Id  System
> /dev/nbd0p1   *           1         492     3951958+  83  Linux
> /dev/nbd0p2             493         522      240975    5  Extended
> /dev/nbd0p5             493         522      240943+  82  Linux swap /
> Solaris
>
> - To disconnect the file from the device:
>
> # qemu-nbd --disconnect /dev/nbd0
>
> Regards,
> Laurent
>   
> +static void show_parts(const char *device)
> +{
> +    if (fork() == 0) {
> +        int nbd;
> +
> +	/* wait device */
> +        sleep(1);
>   

This looks like a big red-herring.  What is this sleep waiting for any 
can it be possibly made into something less racy?

Regards,

Anthony Liguori

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [PATCH] Merge NBD client/server int qemu-nbd
  2008-06-13 17:49 ` Anthony Liguori
@ 2008-06-13 18:09   ` Avi Kivity
  2008-06-13 18:39   ` Laurent Vivier
  1 sibling, 0 replies; 18+ messages in thread
From: Avi Kivity @ 2008-06-13 18:09 UTC (permalink / raw)
  To: qemu-devel

Anthony Liguori wrote:
>>
>> # qemu-nbd --disconnect /dev/nbd0
>>
>> Regards,
>> Laurent
>>   +static void show_parts(const char *device)
>> +{
>> +    if (fork() == 0) {
>> +        int nbd;
>> +
>> +    /* wait device */
>> +        sleep(1);
>>   
>
> This looks like a big red-herring.  What is this sleep waiting for any 
> can it be possibly made into something less racy?

It's called udevsettle, if the host is running udev.

-- 
I have a truly marvellous patch that fixes the bug which this
signature is too narrow to contain.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [PATCH] Merge NBD client/server int qemu-nbd
  2008-06-13 17:49 ` Anthony Liguori
  2008-06-13 18:09   ` Avi Kivity
@ 2008-06-13 18:39   ` Laurent Vivier
  2008-06-14 15:12     ` Anthony Liguori
  2008-06-14 17:18     ` Avi Kivity
  1 sibling, 2 replies; 18+ messages in thread
From: Laurent Vivier @ 2008-06-13 18:39 UTC (permalink / raw)
  To: qemu-devel

Le vendredi 13 juin 2008 à 12:49 -0500, Anthony Liguori a écrit :
> Laurent Vivier wrote:
[...]
> > +static void show_parts(const char *device)
> > +{
> > +    if (fork() == 0) {
> > +        int nbd;
> > +
> > +	/* wait device */
> > +        sleep(1);
> >   
> 
> This looks like a big red-herring.  What is this sleep waiting for any 
> can it be possibly made into something less racy?

Yes, I know, it's BAD (and it can failed sometime...)

But show_parts() must wait its parent has entered in nbd_trip() loop.

Because the open() calls /dev/nbd0 which calls through the socket its
parent and IMHO there is no easy way to know if the server is ready to
process the request.

Perhaps something like:

int timeout = 5;
while ((fd = open(device, O_RDWR)) == -1 && timeout--)
    sleep(1);

Any suggestion ???

Regards,
Laurent
-- 
------------- Laurent.Vivier@bull.net ---------------
"The best way to predict the future is to invent it."
- Alan Kay

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [PATCH] Merge NBD client/server int qemu-nbd
  2008-06-13 18:39   ` Laurent Vivier
@ 2008-06-14 15:12     ` Anthony Liguori
  2008-06-14 18:47       ` Laurent Vivier
  2008-06-14 17:18     ` Avi Kivity
  1 sibling, 1 reply; 18+ messages in thread
From: Anthony Liguori @ 2008-06-14 15:12 UTC (permalink / raw)
  To: qemu-devel

Laurent Vivier wrote:
> Le vendredi 13 juin 2008 à 12:49 -0500, Anthony Liguori a écrit :
>   
>> Laurent Vivier wrote:
>>     
> [...]
>   
>>> +static void show_parts(const char *device)
>>> +{
>>> +    if (fork() == 0) {
>>> +        int nbd;
>>> +
>>> +	/* wait device */
>>> +        sleep(1);
>>>   
>>>       
>> This looks like a big red-herring.  What is this sleep waiting for any 
>> can it be possibly made into something less racy?
>>     
>
> Yes, I know, it's BAD (and it can failed sometime...)
>
> But show_parts() must wait its parent has entered in nbd_trip() loop.
>   

You mean, listen() has to be called on the fd in the server?  You have 
two choices I think.  You could wait to fork the child until after 
you've listen()'d which is probably the most elegant solution.  If 
that's difficult to do, you could have the child inherit one end of a 
pipe() and use that in the child to wait for the server to be ready.

Regards,

Anthony Liguori

> Because the open() calls /dev/nbd0 which calls through the socket its
> parent and IMHO there is no easy way to know if the server is ready to
> process the request.
>
> Perhaps something like:
>
> int timeout = 5;
> while ((fd = open(device, O_RDWR)) == -1 && timeout--)
>     sleep(1);
>
> Any suggestion ???
>
> Regards,
> Laurent
>   

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [PATCH] Merge NBD client/server int qemu-nbd
  2008-06-13 18:39   ` Laurent Vivier
  2008-06-14 15:12     ` Anthony Liguori
@ 2008-06-14 17:18     ` Avi Kivity
  2008-06-14 19:03       ` Laurent Vivier
  1 sibling, 1 reply; 18+ messages in thread
From: Avi Kivity @ 2008-06-14 17:18 UTC (permalink / raw)
  To: qemu-devel

Laurent Vivier wrote:
> int timeout = 5;
> while ((fd = open(device, O_RDWR)) == -1 && timeout--)
>     sleep(1);
>
> Any suggestion ???
>
>   

/sbin/udevsettle

-- 
I have a truly marvellous patch that fixes the bug which this
signature is too narrow to contain.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [PATCH] Merge NBD client/server int qemu-nbd
  2008-06-14 15:12     ` Anthony Liguori
@ 2008-06-14 18:47       ` Laurent Vivier
  0 siblings, 0 replies; 18+ messages in thread
From: Laurent Vivier @ 2008-06-14 18:47 UTC (permalink / raw)
  To: qemu-devel

Le samedi 14 juin 2008 à 10:12 -0500, Anthony Liguori a écrit :
> Laurent Vivier wrote:
> > Le vendredi 13 juin 2008 à 12:49 -0500, Anthony Liguori a écrit :
> >   
> >> Laurent Vivier wrote:
> >>     
> > [...]
> >   
> >>> +static void show_parts(const char *device)
> >>> +{
> >>> +    if (fork() == 0) {
> >>> +        int nbd;
> >>> +
> >>> +	/* wait device */
> >>> +        sleep(1);
> >>>   
> >>>       
> >> This looks like a big red-herring.  What is this sleep waiting for any 
> >> can it be possibly made into something less racy?
> >>     
> >
> > Yes, I know, it's BAD (and it can failed sometime...)
> >
> > But show_parts() must wait its parent has entered in nbd_trip() loop.
> >   
> 
> You mean, listen() has to be called on the fd in the server?  You have 
> two choices I think.  You could wait to fork the child until after 
> you've listen()'d which is probably the most elegant solution.  If 

It is already after the listen (even after the accept...).
It is why I call show_parts() from the server and not from client.

> that's difficult to do, you could have the child inherit one end of a 
> pipe() and use that in the child to wait for the server to be ready.

perhaps I'm wrong, but it seems the server must be waiting on the read()
to allow to have a success on the open(), so I don't see how the server
can launch show_parts() whereas it is already waiting on the read().

Regards,
Laurent
-- 
------------- Laurent.Vivier@bull.net ---------------
"The best way to predict the future is to invent it."
- Alan Kay

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [PATCH] Merge NBD client/server int qemu-nbd
  2008-06-14 17:18     ` Avi Kivity
@ 2008-06-14 19:03       ` Laurent Vivier
  2008-06-14 19:06         ` Avi Kivity
  0 siblings, 1 reply; 18+ messages in thread
From: Laurent Vivier @ 2008-06-14 19:03 UTC (permalink / raw)
  To: qemu-devel

Le samedi 14 juin 2008 à 20:18 +0300, Avi Kivity a écrit :
> Laurent Vivier wrote:
> > int timeout = 5;
> > while ((fd = open(device, O_RDWR)) == -1 && timeout--)
> >     sleep(1);
> >
> > Any suggestion ???
> >
> >   
> 
> /sbin/udevsettle

Why do you think udev is involved at this moment ?

/dev/nbd0 is created when the module is loaded (thus before) and the
partitions when the partition table is read (from within the open).

Regards,
Laurent
-- 
------------- Laurent.Vivier@bull.net ---------------
"The best way to predict the future is to invent it."
- Alan Kay

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [PATCH] Merge NBD client/server int qemu-nbd
  2008-06-14 19:03       ` Laurent Vivier
@ 2008-06-14 19:06         ` Avi Kivity
  2008-06-14 19:21           ` Laurent Vivier
  0 siblings, 1 reply; 18+ messages in thread
From: Avi Kivity @ 2008-06-14 19:06 UTC (permalink / raw)
  To: Laurent Vivier; +Cc: qemu-devel

Laurent Vivier wrote:
> Le samedi 14 juin 2008 à 20:18 +0300, Avi Kivity a écrit :
>   
>> Laurent Vivier wrote:
>>     
>>> int timeout = 5;
>>> while ((fd = open(device, O_RDWR)) == -1 && timeout--)
>>>     sleep(1);
>>>
>>> Any suggestion ???
>>>
>>>   
>>>       
>> /sbin/udevsettle
>>     
>
> Why do you think udev is involved at this moment ?
>
> /dev/nbd0 is created when the module is loaded (thus before) and the
> partitions when the partition table is read (from within the open).
>   

It is udev that creates the devices, based on events it receives from 
the kernel.  Calling udevsettle after the kernel instructs udev to 
create the device files will wait until they are actually created.

-- 
I have a truly marvellous patch that fixes the bug which this
signature is too narrow to contain.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [PATCH] Merge NBD client/server int qemu-nbd
  2008-06-14 19:06         ` Avi Kivity
@ 2008-06-14 19:21           ` Laurent Vivier
  2008-06-14 19:35             ` Avi Kivity
  0 siblings, 1 reply; 18+ messages in thread
From: Laurent Vivier @ 2008-06-14 19:21 UTC (permalink / raw)
  To: Avi Kivity; +Cc: qemu-devel

Le samedi 14 juin 2008 à 12:06 -0700, Avi Kivity a écrit :
> Laurent Vivier wrote:
> > Le samedi 14 juin 2008 à 20:18 +0300, Avi Kivity a écrit :
> >   
> >> Laurent Vivier wrote:
> >>     
> >>> int timeout = 5;
> >>> while ((fd = open(device, O_RDWR)) == -1 && timeout--)
> >>>     sleep(1);
> >>>
> >>> Any suggestion ???
> >>>
> >>>   
> >>>       
> >> /sbin/udevsettle
> >>     
> >
> > Why do you think udev is involved at this moment ?
> >
> > /dev/nbd0 is created when the module is loaded (thus before) and the
> > partitions when the partition table is read (from within the open).
> >   
> 
> It is udev that creates the devices, based on events it receives from 
> the kernel.  Calling udevsettle after the kernel instructs udev to 
> create the device files will wait until they are actually created.

Yes, I agree but the kernel events are generated by the open(), so I
think I can't use this to know if I can use open(). 

I've used udevmonitor to see what happen:
- without open() -> no events
- whith open() whithout sleep() -> no events
-> open() + sleep() -> events generated by the partition creation.

So, what do I miss ?

Laurent
-- 
------------- Laurent.Vivier@bull.net ---------------
"The best way to predict the future is to invent it."
- Alan Kay

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [PATCH] Merge NBD client/server int qemu-nbd
  2008-06-14 19:21           ` Laurent Vivier
@ 2008-06-14 19:35             ` Avi Kivity
  2008-06-14 19:54               ` Laurent Vivier
  0 siblings, 1 reply; 18+ messages in thread
From: Avi Kivity @ 2008-06-14 19:35 UTC (permalink / raw)
  To: Laurent Vivier; +Cc: qemu-devel

Laurent Vivier wrote:

  

>> It is udev that creates the devices, based on events it receives from 
>> the kernel.  Calling udevsettle after the kernel instructs udev to 
>> create the device files will wait until they are actually created.
>>     
>
> Yes, I agree but the kernel events are generated by the open(), so I
> think I can't use this to know if I can use open(). 
>
> I've used udevmonitor to see what happen:
> - without open() -> no events
> - whith open() whithout sleep() -> no events
> -> open() + sleep() -> events generated by the partition creation.
>
> So, what do I miss ?
>   

For this, it seems like sleep() generates the events, which is a little 
unlikely.  I suggest re-checking this.

There is also some ioctl which can be used to force re-reading the 
partition table, perhaps invoking that and then udevsettle will suffice.

-- 
I have a truly marvellous patch that fixes the bug which this
signature is too narrow to contain.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [PATCH] Merge NBD client/server int qemu-nbd
  2008-06-14 19:35             ` Avi Kivity
@ 2008-06-14 19:54               ` Laurent Vivier
  2008-06-15 14:25                 ` Anthony Liguori
  0 siblings, 1 reply; 18+ messages in thread
From: Laurent Vivier @ 2008-06-14 19:54 UTC (permalink / raw)
  To: Avi Kivity; +Cc: qemu-devel@nongnu.org

Le samedi 14 juin 2008 à 12:35 -0700, Avi Kivity a écrit :
> Laurent Vivier wrote:
> 
>   
> 
> >> It is udev that creates the devices, based on events it receives from 
> >> the kernel.  Calling udevsettle after the kernel instructs udev to 
> >> create the device files will wait until they are actually created.
> >>     
> >
> > Yes, I agree but the kernel events are generated by the open(), so I
> > think I can't use this to know if I can use open(). 
> >
> > I've used udevmonitor to see what happen:
> > - without open() -> no events
> > - whith open() whithout sleep() -> no events
> > -> open() + sleep() -> events generated by the partition creation.
> >
> > So, what do I miss ?
> >   
> 
> For this, it seems like sleep() generates the events, which is a little 
> unlikely.  I suggest re-checking this.

re-checked, no events with sleep() only.

events generated with sleep() + open() are:

UEVENT[1213473088.354639] change@/block/nbd0
ACTION=change
DEVPATH=/block/nbd0
SUBSYSTEM=block
MAJOR=43
MINOR=0
DEVTYPE=disk
SEQNUM=2921

UEVENT[1213473088.354721] add@/block/nbd0/nbd0p1
ACTION=add
DEVPATH=/block/nbd0/nbd0p1
SUBSYSTEM=block
MAJOR=43
MINOR=1
DEVTYPE=partition
SEQNUM=2922

UEVENT[1213473088.354781] add@/block/nbd0/nbd0p2
ACTION=add
DEVPATH=/block/nbd0/nbd0p2
SUBSYSTEM=block
MAJOR=43
MINOR=2
DEVTYPE=partition
SEQNUM=2923

UEVENT[1213473088.354842] add@/block/nbd0/nbd0p5
ACTION=add
DEVPATH=/block/nbd0/nbd0p5
SUBSYSTEM=block
MAJOR=43
MINOR=5
DEVTYPE=partition
SEQNUM=2924

UDEV  [1213473088.355617] change@/block/nbd0
UDEV_LOG=3
ACTION=change
DEVPATH=/block/nbd0
SUBSYSTEM=block
MAJOR=43
MINOR=0
DEVTYPE=disk
SEQNUM=2921
UDEVD_EVENT=1
DEVNAME=/dev/nbd0

UDEV  [1213473088.356818] add@/block/nbd0/nbd0p1
UDEV_LOG=3
ACTION=add
DEVPATH=/block/nbd0/nbd0p1
SUBSYSTEM=block
MAJOR=43
MINOR=1
DEVTYPE=partition
SEQNUM=2922
UDEVD_EVENT=1
DEVNAME=/dev/nbd0p1

UDEV  [1213473088.358335] add@/block/nbd0/nbd0p5
UDEV_LOG=3
ACTION=add
DEVPATH=/block/nbd0/nbd0p5
SUBSYSTEM=block
MAJOR=43
MINOR=5
DEVTYPE=partition
SEQNUM=2924
UDEVD_EVENT=1
DEVNAME=/dev/nbd0p5

UDEV  [1213473088.358390] add@/block/nbd0/nbd0p2
UDEV_LOG=3
ACTION=add
DEVPATH=/block/nbd0/nbd0p2
SUBSYSTEM=block
MAJOR=43
MINOR=2
DEVTYPE=partition
SEQNUM=2923
UDEVD_EVENT=1
DEVNAME=/dev/nbd0p2

> There is also some ioctl which can be used to force re-reading the 
> partition table, perhaps invoking that and then udevsettle will suffice.

Yes, I know that, but to make the ioctl() you need an open()... and the
open() is enough.

Regards,
Laurent
-- 
------------- Laurent.Vivier@bull.net ---------------
"The best way to predict the future is to invent it."
- Alan Kay

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [PATCH] Merge NBD client/server int qemu-nbd
  2008-06-14 19:54               ` Laurent Vivier
@ 2008-06-15 14:25                 ` Anthony Liguori
  2008-06-15 15:56                   ` Laurent Vivier
  0 siblings, 1 reply; 18+ messages in thread
From: Anthony Liguori @ 2008-06-15 14:25 UTC (permalink / raw)
  To: qemu-devel

Laurent Vivier wrote:
> Le samedi 14 juin 2008 à 12:35 -0700, Avi Kivity a écrit :
>   
>> Laurent Vivier wrote:
>>
>>   
>>
>>     
>>>> It is udev that creates the devices, based on events it receives from 
>>>> the kernel.  Calling udevsettle after the kernel instructs udev to 
>>>> create the device files will wait until they are actually created.
>>>>     
>>>>         
>>> Yes, I agree but the kernel events are generated by the open(), so I
>>> think I can't use this to know if I can use open(). 
>>>
>>> I've used udevmonitor to see what happen:
>>> - without open() -> no events
>>> - whith open() whithout sleep() -> no events
>>> -> open() + sleep() -> events generated by the partition creation.
>>>
>>> So, what do I miss ?
>>>   
>>>       
>> For this, it seems like sleep() generates the events, which is a little 
>> unlikely.  I suggest re-checking this.
>>     
>
> re-checked, no events with sleep() only.
>
> events generated with sleep() + open() are:
>   

I imagine the sleep() is causing another task to be scheduled (probably 
the server) which is what ends up generating the event.

Regards,

Anthony Liguori

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [PATCH] Merge NBD client/server int qemu-nbd
  2008-06-15 14:25                 ` Anthony Liguori
@ 2008-06-15 15:56                   ` Laurent Vivier
  2008-06-15 16:00                     ` Avi Kivity
  0 siblings, 1 reply; 18+ messages in thread
From: Laurent Vivier @ 2008-06-15 15:56 UTC (permalink / raw)
  To: qemu-devel

Le dimanche 15 juin 2008 à 09:25 -0500, Anthony Liguori a écrit :
> Laurent Vivier wrote:
> > Le samedi 14 juin 2008 à 12:35 -0700, Avi Kivity a écrit :
> >   
> >> Laurent Vivier wrote:
> >>
> >>   
> >>
> >>     
> >>>> It is udev that creates the devices, based on events it receives from 
> >>>> the kernel.  Calling udevsettle after the kernel instructs udev to 
> >>>> create the device files will wait until they are actually created.
> >>>>     
> >>>>         
> >>> Yes, I agree but the kernel events are generated by the open(), so I
> >>> think I can't use this to know if I can use open(). 
> >>>
> >>> I've used udevmonitor to see what happen:
> >>> - without open() -> no events
> >>> - whith open() whithout sleep() -> no events
> >>> -> open() + sleep() -> events generated by the partition creation.
> >>>
> >>> So, what do I miss ?
> >>>   
> >>>       
> >> For this, it seems like sleep() generates the events, which is a little 
> >> unlikely.  I suggest re-checking this.
> >>     
> >
> > re-checked, no events with sleep() only.
> >
> > events generated with sleep() + open() are:
> >   
> 
> I imagine the sleep() is causing another task to be scheduled (probably 
> the server) which is what ends up generating the event.

No, for me, the open() generates the events:

open() -> blkdev_open() -> do_open() -> rescan_partitions() ->
add_partitions() -> device_add() -> kobject_uevent()

If you remove show_parts() from the main(), the partitions appear only
on the first open on the device, for instance you can run manually
"cmp /dev/nbd0 /dev/zero" after "qemu-nbd --connect=/dev/nbd0 ...".

Laurent
-- 
------------- Laurent.Vivier@bull.net ---------------
"The best way to predict the future is to invent it."
- Alan Kay

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [PATCH] Merge NBD client/server int qemu-nbd
  2008-06-15 15:56                   ` Laurent Vivier
@ 2008-06-15 16:00                     ` Avi Kivity
  2008-06-15 17:39                       ` Laurent Vivier
  0 siblings, 1 reply; 18+ messages in thread
From: Avi Kivity @ 2008-06-15 16:00 UTC (permalink / raw)
  To: qemu-devel

Laurent Vivier wrote:
> No, for me, the open() generates the events:
>
> open() -> blkdev_open() -> do_open() -> rescan_partitions() ->
> add_partitions() -> device_add() -> kobject_uevent()
>
> If you remove show_parts() from the main(), the partitions appear only
> on the first open on the device, for instance you can run manually
> "cmp /dev/nbd0 /dev/zero" after "qemu-nbd --connect=/dev/nbd0 ...".
>
>   

Well then, simply call udevsettle after the open of the block device, 
after which you're guaranteed to have the paritions.

-- 
I have a truly marvellous patch that fixes the bug which this
signature is too narrow to contain.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [PATCH] Merge NBD client/server int qemu-nbd
  2008-06-15 16:00                     ` Avi Kivity
@ 2008-06-15 17:39                       ` Laurent Vivier
  2008-06-19  8:58                         ` [Qemu-devel] [PATCH][v2] " Laurent Vivier
  0 siblings, 1 reply; 18+ messages in thread
From: Laurent Vivier @ 2008-06-15 17:39 UTC (permalink / raw)
  To: qemu-devel

Le dimanche 15 juin 2008 à 09:00 -0700, Avi Kivity a écrit :
> Laurent Vivier wrote:
> > No, for me, the open() generates the events:
> >
> > open() -> blkdev_open() -> do_open() -> rescan_partitions() ->
> > add_partitions() -> device_add() -> kobject_uevent()
> >
> > If you remove show_parts() from the main(), the partitions appear only
> > on the first open on the device, for instance you can run manually
> > "cmp /dev/nbd0 /dev/zero" after "qemu-nbd --connect=/dev/nbd0 ...".
> >
> >   
> 
> Well then, simply call udevsettle after the open of the block device, 
> after which you're guaranteed to have the paritions.

Not possible: if I call the open too early the partitions are not
updated and thus udevsettle is useless (remember: this open() is here
only to update the partition table).

Laurent
-- 
------------- Laurent.Vivier@bull.net ---------------
"The best way to predict the future is to invent it."
- Alan Kay

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [Qemu-devel] [PATCH][v2] Merge NBD client/server int qemu-nbd
  2008-06-15 17:39                       ` Laurent Vivier
@ 2008-06-19  8:58                         ` Laurent Vivier
  2008-06-19  9:18                           ` Laurent Vivier
  0 siblings, 1 reply; 18+ messages in thread
From: Laurent Vivier @ 2008-06-19  8:58 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony Liguori

[-- Attachment #1: Type: text/plain, Size: 1104 bytes --]

Hi,

this patch allows to connect directly a disk image file to an NBD
device. It introduces the use of a unix socket (instead of inet).

- To connect a file to a device:

# qemu-nbd --connect=/dev/nbd0 my_disk.qcow2

Then you can see directly your disk (no need of nbd-client):

# fdisk -l /dev/nbd0

Disk /dev/nbd0: 4294 MB, 4294967296 bytes
255 heads, 63 sectors/track, 522 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

     Device Boot      Start         End      Blocks   Id  System
/dev/nbd0p1   *           1         492     3951958+  83  Linux
/dev/nbd0p2             493         522      240975    5  Extended
/dev/nbd0p5             493         522      240943+  82  Linux swap /
Solaris

- To disconnect the file from the device:

# qemu-nbd --disconnect /dev/nbd0

Changelog:
- v2: call show_parts() from client and avoid the sleep(1). Thank you to
Avi and Anthony. Include my cleanup patch and comments from Carlo
Marcelo Arenas Belon.

Regards,
Laurent
-- 
------------- Laurent.Vivier@bull.net ---------------
"The best way to predict the future is to invent it."
- Alan Kay

[-- Attachment #2: qemu-nbd-local.patch --]
[-- Type: text/x-patch, Size: 7624 bytes --]

Index: qemu/nbd.c
===================================================================
--- qemu.orig/nbd.c	2008-06-18 17:05:46.000000000 +0200
+++ qemu/nbd.c	2008-06-19 10:47:46.000000000 +0200
@@ -25,6 +25,7 @@
 #include <ctype.h>
 #include <inttypes.h>
 #include <sys/socket.h>
+#include <sys/un.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <arpa/inet.h>
@@ -183,6 +184,65 @@ error:
     return -1;
 }
 
+int unix_socket_incoming(const char *path)
+{
+    int s;
+    struct sockaddr_un addr;
+    int serrno;
+
+    s = socket(PF_UNIX, SOCK_STREAM, 0);
+    if (s == -1) {
+        return -1;
+    }
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sun_family = AF_UNIX;
+    pstrcpy(addr.sun_path, sizeof(addr.sun_path), path);
+
+    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+        goto error;
+    }
+
+    if (listen(s, 128) == -1) {
+        goto error;
+    }
+
+    return s;
+error:
+    serrno = errno;
+    close(s);
+    errno = serrno;
+    return -1;
+}
+
+int unix_socket_outgoing(const char *path)
+{
+    int s;
+    struct sockaddr_un addr;
+    int serrno;
+
+    s = socket(PF_UNIX, SOCK_STREAM, 0);
+    if (s == -1) {
+        return -1;
+    }
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sun_family = AF_UNIX;
+    pstrcpy(addr.sun_path, sizeof(addr.sun_path), path);
+
+    if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+        goto error;
+    }
+
+    return s;
+error:
+    serrno = errno;
+    close(s);
+    errno = serrno;
+    return -1;
+}
+
+
 /* Basic flow
 
    Server         Client
@@ -388,8 +448,8 @@ int nbd_trip(BlockDriverState *bs, int c
 	}
 
 	if (len > sizeof(data)) {
-		LOG("len (%u) is larger than max len (%u)",
-		    len, sizeof(data));
+		LOG("len (%u) is larger than max len (%lu)",
+		    len, (unsigned long)sizeof(data));
 		errno = EINVAL;
 		return -1;
 	}
Index: qemu/nbd.h
===================================================================
--- qemu.orig/nbd.h	2008-06-18 17:05:46.000000000 +0200
+++ qemu/nbd.h	2008-06-19 10:47:46.000000000 +0200
@@ -27,6 +27,8 @@
 #include "block_int.h"
 
 int tcp_socket_incoming(const char *address, uint16_t port);
+int unix_socket_outgoing(const char *path);
+int unix_socket_incoming(const char *path);
 
 int nbd_negotiate(BlockDriverState *bs, int csock, off_t size);
 int nbd_receive_negotiate(int fd, int csock);
Index: qemu/qemu-nbd.c
===================================================================
--- qemu.orig/qemu-nbd.c	2008-06-18 17:05:46.000000000 +0200
+++ qemu/qemu-nbd.c	2008-06-19 10:48:49.000000000 +0200
@@ -21,15 +21,18 @@
 #include "block_int.h"
 #include "nbd.h"
 
-#include <malloc.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <getopt.h>
 #include <err.h>
+#include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <arpa/inet.h>
+#include <signal.h>
+
+//#define DEBUG
 
 int verbose;
 
@@ -44,6 +47,8 @@ static void usage(const char *name)
 "  -b, --bind=IFACE     interface to bind to (default `0.0.0.0')\n"
 "  -r, --read-only      export read-only\n"
 "  -P, --partition=NUM  only expose partition NUM\n"
+"  -c, --connect=DEV    connect FILE to the local NBD device DEV\n"
+"  -d, --disconnect     disconnect the specified device\n"
 "  -v, --verbose        display extra debugging information\n"
 "  -h, --help           display this help and exit\n"
 "  -V, --version        output version information and exit\n"
@@ -145,19 +150,39 @@ static int find_partition(BlockDriverSta
     return -1;
 }
 
+static void show_parts(const char *device)
+{
+    if (fork() == 0) {
+        int nbd;
+
+        /* linux just needs an open() to trigger
+         * the partition table update
+         * but remember to load the module with max_part != 0 :
+         *     modprobe nbd max_part=63
+         */
+        nbd = open(device, O_RDWR);
+        if (nbd != -1)
+        	close(nbd);
+        exit(0);
+    }
+}
+
 int main(int argc, char **argv)
 {
     BlockDriverState *bs;
     off_t dev_offset = 0;
     off_t offset = 0;
     bool readonly = false;
+    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;
-    const char *sopt = "hVbo:p:rsP:v";
+    char *device;
+    char sockpath[128];
+    const char *sopt = "hVbo:p:rsP:c:dv?";
     struct option lopt[] = {
         { "help", 0, 0, 'h' },
         { "version", 0, 0, 'V' },
@@ -166,8 +191,11 @@ int main(int argc, char **argv)
         { "offset", 1, 0, 'o' },
         { "read-only", 0, 0, 'r' },
         { "partition", 1, 0, 'P' },
+        { "connect", 1, 0, 'c' },
+        { "disconnect", 0, 0, 'd' },
         { "snapshot", 0, 0, 's' },
         { "verbose", 0, 0, 'v' },
+	{ 0, 0, 0, 0 }
     };
     int ch;
     int opt_ind = 0;
@@ -175,6 +203,8 @@ int main(int argc, char **argv)
     char *end;
     bool snapshot = false;
     int partition = -1;
+    int fd;
+    int ret;
 
     while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
         switch (ch) {
@@ -213,6 +243,12 @@ int main(int argc, char **argv)
             if (partition < 1 || partition > 8)
                 errx(EINVAL, "Invalid partition %d", partition);
             break;
+        case 'd':
+            disconnect = true;
+            break;
+        case 'c':
+            device = optarg;
+            break;
         case 'v':
             verbose = 1;
             break;
@@ -236,6 +272,20 @@ int main(int argc, char **argv)
              argv[0]);
     }
 
+    if (disconnect) {
+        fd = open(argv[optind], O_RDWR);
+        if (fd == -1)
+            errx(errno, "Cannot open %s", argv[optind]);
+
+        nbd_disconnect(fd);
+
+        close(fd);
+
+        printf("%s disconnected\n", argv[optind]);
+
+	return 0;
+    }
+
     bdrv_init();
 
     bs = bdrv_new("hda");
@@ -251,7 +301,60 @@ int main(int argc, char **argv)
         find_partition(bs, partition, &dev_offset, &fd_size))
         errx(errno, "Could not find partition %d", partition);
 
-    sock = tcp_socket_incoming(bindto, port);
+    if (device) {
+	pid_t pid;
+	if (!verbose)
+            daemon(0, 0);	/* detach client and server */
+
+        sprintf(sockpath, "/var/lock/qemu-img-%s", basename(device));
+
+        pid = fork();
+        if (pid < 0)
+            return 1;
+	if (pid != 0) {
+            ret = 0;
+            bdrv_close(bs);
+
+            do {
+                sock = unix_socket_outgoing(sockpath);
+                if (sock == -1) {
+                    if (errno != ENOENT && errno != ECONNREFUSED)
+                        goto exit;
+                    sleep(1);	/* wait children */
+                }
+            } while (sock == -1);
+
+            fd = open(device, O_RDWR);
+            if (fd == -1) {
+                ret = -1;
+                goto exit;
+            }
+
+            ret = nbd_receive_negotiate(fd, sock);
+            if (ret == -1)
+                goto exit;
+
+            printf("NBD device %s is now connected to file %s\n",
+                    device, argv[optind]);
+
+	    /* if supported, update partition table */
+
+            show_parts(device);
+
+            nbd_client(fd, sock);
+            close(fd);
+exit:
+            kill(pid, SIGTERM);
+            unlink(sockpath);
+
+            return ret;
+        }
+        /* children */
+        sock = unix_socket_incoming(sockpath);
+    } else {
+        sock = tcp_socket_incoming(bindto, port);
+    }
+
     if (sock == -1)
         return 1;
 

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [PATCH][v2] Merge NBD client/server int qemu-nbd
  2008-06-19  8:58                         ` [Qemu-devel] [PATCH][v2] " Laurent Vivier
@ 2008-06-19  9:18                           ` Laurent Vivier
  0 siblings, 0 replies; 18+ messages in thread
From: Laurent Vivier @ 2008-06-19  9:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony Liguori

[-- Attachment #1: Type: text/plain, Size: 153 bytes --]

Oops, this one is up-to-date.
-- 
------------- Laurent.Vivier@bull.net ---------------
"The best way to predict the future is to invent it."
- Alan Kay

[-- Attachment #2: qemu-nbd-local.patch --]
[-- Type: text/x-patch, Size: 7597 bytes --]

Index: qemu/nbd.c
===================================================================
--- qemu.orig/nbd.c	2008-06-18 17:05:46.000000000 +0200
+++ qemu/nbd.c	2008-06-19 11:09:39.000000000 +0200
@@ -25,6 +25,7 @@
 #include <ctype.h>
 #include <inttypes.h>
 #include <sys/socket.h>
+#include <sys/un.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <arpa/inet.h>
@@ -183,6 +184,65 @@ error:
     return -1;
 }
 
+int unix_socket_incoming(const char *path)
+{
+    int s;
+    struct sockaddr_un addr;
+    int serrno;
+
+    s = socket(PF_UNIX, SOCK_STREAM, 0);
+    if (s == -1) {
+        return -1;
+    }
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sun_family = AF_UNIX;
+    pstrcpy(addr.sun_path, sizeof(addr.sun_path), path);
+
+    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+        goto error;
+    }
+
+    if (listen(s, 128) == -1) {
+        goto error;
+    }
+
+    return s;
+error:
+    serrno = errno;
+    close(s);
+    errno = serrno;
+    return -1;
+}
+
+int unix_socket_outgoing(const char *path)
+{
+    int s;
+    struct sockaddr_un addr;
+    int serrno;
+
+    s = socket(PF_UNIX, SOCK_STREAM, 0);
+    if (s == -1) {
+        return -1;
+    }
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sun_family = AF_UNIX;
+    pstrcpy(addr.sun_path, sizeof(addr.sun_path), path);
+
+    if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+        goto error;
+    }
+
+    return s;
+error:
+    serrno = errno;
+    close(s);
+    errno = serrno;
+    return -1;
+}
+
+
 /* Basic flow
 
    Server         Client
@@ -388,8 +448,8 @@ int nbd_trip(BlockDriverState *bs, int c
 	}
 
 	if (len > sizeof(data)) {
-		LOG("len (%u) is larger than max len (%u)",
-		    len, sizeof(data));
+		LOG("len (%u) is larger than max len (%lu)",
+		    len, (unsigned long)sizeof(data));
 		errno = EINVAL;
 		return -1;
 	}
Index: qemu/nbd.h
===================================================================
--- qemu.orig/nbd.h	2008-06-18 17:05:46.000000000 +0200
+++ qemu/nbd.h	2008-06-19 11:09:39.000000000 +0200
@@ -27,6 +27,8 @@
 #include "block_int.h"
 
 int tcp_socket_incoming(const char *address, uint16_t port);
+int unix_socket_outgoing(const char *path);
+int unix_socket_incoming(const char *path);
 
 int nbd_negotiate(BlockDriverState *bs, int csock, off_t size);
 int nbd_receive_negotiate(int fd, int csock);
Index: qemu/qemu-nbd.c
===================================================================
--- qemu.orig/qemu-nbd.c	2008-06-18 17:05:46.000000000 +0200
+++ qemu/qemu-nbd.c	2008-06-19 11:13:41.000000000 +0200
@@ -21,15 +21,16 @@
 #include "block_int.h"
 #include "nbd.h"
 
-#include <malloc.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <getopt.h>
 #include <err.h>
+#include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <arpa/inet.h>
+#include <signal.h>
 
 int verbose;
 
@@ -44,6 +45,8 @@ static void usage(const char *name)
 "  -b, --bind=IFACE     interface to bind to (default `0.0.0.0')\n"
 "  -r, --read-only      export read-only\n"
 "  -P, --partition=NUM  only expose partition NUM\n"
+"  -c, --connect=DEV    connect FILE to the local NBD device DEV\n"
+"  -d, --disconnect     disconnect the specified device\n"
 "  -v, --verbose        display extra debugging information\n"
 "  -h, --help           display this help and exit\n"
 "  -V, --version        output version information and exit\n"
@@ -145,19 +148,39 @@ static int find_partition(BlockDriverSta
     return -1;
 }
 
+static void show_parts(const char *device)
+{
+    if (fork() == 0) {
+        int nbd;
+
+        /* linux just needs an open() to trigger
+         * the partition table update
+         * but remember to load the module with max_part != 0 :
+         *     modprobe nbd max_part=63
+         */
+        nbd = open(device, O_RDWR);
+        if (nbd != -1)
+        	close(nbd);
+        exit(0);
+    }
+}
+
 int main(int argc, char **argv)
 {
     BlockDriverState *bs;
     off_t dev_offset = 0;
     off_t offset = 0;
     bool readonly = false;
+    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;
-    const char *sopt = "hVbo:p:rsP:v";
+    char *device = NULL;
+    char sockpath[128];
+    const char *sopt = "hVbo:p:rsP:c:dv";
     struct option lopt[] = {
         { "help", 0, 0, 'h' },
         { "version", 0, 0, 'V' },
@@ -166,8 +189,11 @@ int main(int argc, char **argv)
         { "offset", 1, 0, 'o' },
         { "read-only", 0, 0, 'r' },
         { "partition", 1, 0, 'P' },
+        { "connect", 1, 0, 'c' },
+        { "disconnect", 0, 0, 'd' },
         { "snapshot", 0, 0, 's' },
         { "verbose", 0, 0, 'v' },
+	{ 0, 0, 0, 0 }
     };
     int ch;
     int opt_ind = 0;
@@ -175,6 +201,8 @@ int main(int argc, char **argv)
     char *end;
     bool snapshot = false;
     int partition = -1;
+    int fd;
+    int ret;
 
     while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
         switch (ch) {
@@ -213,6 +241,12 @@ int main(int argc, char **argv)
             if (partition < 1 || partition > 8)
                 errx(EINVAL, "Invalid partition %d", partition);
             break;
+        case 'd':
+            disconnect = true;
+            break;
+        case 'c':
+            device = optarg;
+            break;
         case 'v':
             verbose = 1;
             break;
@@ -236,6 +270,20 @@ int main(int argc, char **argv)
              argv[0]);
     }
 
+    if (disconnect) {
+        fd = open(argv[optind], O_RDWR);
+        if (fd == -1)
+            errx(errno, "Cannot open %s", argv[optind]);
+
+        nbd_disconnect(fd);
+
+        close(fd);
+
+        printf("%s disconnected\n", argv[optind]);
+
+	return 0;
+    }
+
     bdrv_init();
 
     bs = bdrv_new("hda");
@@ -251,7 +299,60 @@ int main(int argc, char **argv)
         find_partition(bs, partition, &dev_offset, &fd_size))
         errx(errno, "Could not find partition %d", partition);
 
-    sock = tcp_socket_incoming(bindto, port);
+    if (device) {
+	pid_t pid;
+	if (!verbose)
+            daemon(0, 0);	/* detach client and server */
+
+        sprintf(sockpath, "/var/lock/qemu-img-%s", basename(device));
+
+        pid = fork();
+        if (pid < 0)
+            return 1;
+	if (pid != 0) {
+            ret = 0;
+            bdrv_close(bs);
+
+            do {
+                sock = unix_socket_outgoing(sockpath);
+                if (sock == -1) {
+                    if (errno != ENOENT && errno != ECONNREFUSED)
+                        goto exit;
+                    sleep(1);	/* wait children */
+                }
+            } while (sock == -1);
+
+            fd = open(device, O_RDWR);
+            if (fd == -1) {
+                ret = -1;
+                goto exit;
+            }
+
+            ret = nbd_receive_negotiate(fd, sock);
+            if (ret == -1)
+                goto exit;
+
+            printf("NBD device %s is now connected to file %s\n",
+                    device, argv[optind]);
+
+	    /* update partition table */
+
+            show_parts(device);
+
+            nbd_client(fd, sock);
+            close(fd);
+exit:
+            kill(pid, SIGTERM);
+            unlink(sockpath);
+
+            return ret;
+        }
+        /* children */
+        sock = unix_socket_incoming(sockpath);
+    } else {
+        sock = tcp_socket_incoming(bindto, port);
+    }
+
     if (sock == -1)
         return 1;
 

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2008-06-19  9:18 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-06-13 15:15 [Qemu-devel] [PATCH] Merge NBD client/server int qemu-nbd Laurent Vivier
2008-06-13 17:49 ` Anthony Liguori
2008-06-13 18:09   ` Avi Kivity
2008-06-13 18:39   ` Laurent Vivier
2008-06-14 15:12     ` Anthony Liguori
2008-06-14 18:47       ` Laurent Vivier
2008-06-14 17:18     ` Avi Kivity
2008-06-14 19:03       ` Laurent Vivier
2008-06-14 19:06         ` Avi Kivity
2008-06-14 19:21           ` Laurent Vivier
2008-06-14 19:35             ` Avi Kivity
2008-06-14 19:54               ` Laurent Vivier
2008-06-15 14:25                 ` Anthony Liguori
2008-06-15 15:56                   ` Laurent Vivier
2008-06-15 16:00                     ` Avi Kivity
2008-06-15 17:39                       ` Laurent Vivier
2008-06-19  8:58                         ` [Qemu-devel] [PATCH][v2] " Laurent Vivier
2008-06-19  9:18                           ` Laurent Vivier

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