All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [4838] Allow QEMU to connect directly to an NBD server, by Laurent Vivier.
@ 2008-07-03 13:41 Thiemo Seufer
  2008-07-04  1:33 ` chenqing
  0 siblings, 1 reply; 31+ messages in thread
From: Thiemo Seufer @ 2008-07-03 13:41 UTC (permalink / raw)
  To: qemu-devel

Revision: 4838
          http://svn.sv.gnu.org/viewvc/?view=rev&root=qemu&revision=4838
Author:   ths
Date:     2008-07-03 13:41:03 +0000 (Thu, 03 Jul 2008)

Log Message:
-----------
Allow QEMU to connect directly to an NBD server, by Laurent Vivier.

Modified Paths:
--------------
    trunk/Makefile
    trunk/block.c
    trunk/block.h
    trunk/nbd.c
    trunk/nbd.h
    trunk/qemu-doc.texi
    trunk/qemu-nbd.c
    trunk/qemu-nbd.texi

Added Paths:
-----------
    trunk/block-nbd.c

Modified: trunk/Makefile
===================================================================
--- trunk/Makefile	2008-07-03 12:45:02 UTC (rev 4837)
+++ trunk/Makefile	2008-07-03 13:41:03 UTC (rev 4838)
@@ -42,7 +42,7 @@
 BLOCK_OBJS=cutils.o qemu-malloc.o
 BLOCK_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o
 BLOCK_OBJS+=block-dmg.o block-bochs.o block-vpc.o block-vvfat.o
-BLOCK_OBJS+=block-qcow2.o block-parallels.o
+BLOCK_OBJS+=block-qcow2.o block-parallels.o block-nbd.o
 
 ######################################################################
 # libqemu_common.a: Target independent part of system emulation. The
@@ -50,7 +50,7 @@
 # system emulation, i.e. a single QEMU executable should support all
 # CPUs and machines.
 
-OBJS=$(BLOCK_OBJS)
+OBJS=nbd.o $(BLOCK_OBJS)
 OBJS+=readline.o console.o
 OBJS+=block.o
 
@@ -159,7 +159,7 @@
 	rm -f $@ 
 	$(AR) rcs $@ $(USER_OBJS)
 
-QEMU_IMG_BLOCK_OBJS = $(BLOCK_OBJS)
+QEMU_IMG_BLOCK_OBJS = nbd.o $(BLOCK_OBJS)
 ifdef CONFIG_WIN32
 QEMU_IMG_BLOCK_OBJS += qemu-img-block-raw-win32.o
 else
@@ -180,7 +180,7 @@
 qemu-nbd-%.o: %.c
 	$(CC) $(CFLAGS) $(CPPFLAGS) -DQEMU_NBD -c -o $@ $<
 
-qemu-nbd$(EXESUF):  qemu-nbd.o nbd.o qemu-img-block.o \
+qemu-nbd$(EXESUF):  qemu-nbd.o qemu-nbd-nbd.o qemu-img-block.o \
 		    osdep.o qemu-nbd-block-raw-posix.o $(BLOCK_OBJS)
 	$(CC) $(LDFLAGS) -o $@ $^ -lz $(LIBS)
 

Added: trunk/block-nbd.c
===================================================================
--- trunk/block-nbd.c	                        (rev 0)
+++ trunk/block-nbd.c	2008-07-03 13:41:03 UTC (rev 4838)
@@ -0,0 +1,194 @@
+/*
+ * QEMU Block driver for  NBD
+ *
+ * Copyright (C) 2008 Bull S.A.S.
+ *     Author: Laurent Vivier <Laurent.Vivier@bull;net>
+ *
+ * Some parts:
+ *    Copyright (C) 2007 Anthony Liguori <anthony@codemonkey.ws>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu-common.h"
+#include "nbd.h"
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <pthread.h>
+
+typedef struct BDRVNBDState {
+    int sock;
+    off_t size;
+    size_t blocksize;
+} BDRVNBDState;
+
+static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
+{
+    BDRVNBDState *s = bs->opaque;
+    const char *host;
+    const char *unixpath;
+    int sock;
+    off_t size;
+    size_t blocksize;
+    int ret;
+
+    if ((flags & BDRV_O_CREAT))
+        return -EINVAL;
+
+    if (!strstart(filename, "nbd:", &host))
+        return -EINVAL;
+
+    if (strstart(host, "unix:", &unixpath)) {
+
+        if (unixpath[0] != '/')
+            return -EINVAL;
+
+        sock = unix_socket_outgoing(unixpath);
+
+    } else {
+        uint16_t port;
+        char *p, *r;
+        char hostname[128];
+
+        pstrcpy(hostname, 128, host);
+
+        p = strchr(hostname, ':');
+        if (p == NULL)
+            return -EINVAL;
+
+        *p = '\0';
+        p++;
+
+        port = strtol(p, &r, 0);
+        if (r == p)
+            return -EINVAL;
+        sock = tcp_socket_outgoing(hostname, port);
+    }
+
+    if (sock == -1)
+        return -errno;
+
+    ret = nbd_receive_negotiate(sock, &size, &blocksize);
+    if (ret == -1)
+        return -errno;
+
+    s->sock = sock;
+    s->size = size;
+    s->blocksize = blocksize;
+
+    return 0;
+}
+
+static int nbd_read(BlockDriverState *bs, int64_t sector_num,
+                    uint8_t *buf, int nb_sectors)
+{
+    BDRVNBDState *s = bs->opaque;
+    struct nbd_request request;
+    struct nbd_reply reply;
+
+    request.type = NBD_CMD_READ;
+    request.handle = (uint64_t)(intptr_t)bs;
+    request.from = sector_num * 512;;
+    request.len = nb_sectors * 512;
+
+    if (nbd_send_request(s->sock, &request) == -1)
+        return -errno;
+
+    if (nbd_receive_reply(s->sock, &reply) == -1)
+        return -errno;
+
+    if (reply.error !=0)
+        return -reply.error;
+
+    if (reply.handle != request.handle)
+        return -EIO;
+
+    if (nbd_wr_sync(s->sock, buf, request.len, 1) != request.len)
+        return -EIO;
+
+    return 0;
+}
+
+static int nbd_write(BlockDriverState *bs, int64_t sector_num,
+                     const uint8_t *buf, int nb_sectors)
+{
+    BDRVNBDState *s = bs->opaque;
+    struct nbd_request request;
+    struct nbd_reply reply;
+
+    request.type = NBD_CMD_WRITE;
+    request.handle = (uint64_t)(intptr_t)bs;
+    request.from = sector_num * 512;;
+    request.len = nb_sectors * 512;
+
+    if (nbd_send_request(s->sock, &request) == -1)
+        return -errno;
+
+    if (nbd_wr_sync(s->sock, (uint8_t*)buf, request.len, 0) != request.len)
+        return -EIO;
+
+    if (nbd_receive_reply(s->sock, &reply) == -1)
+        return -errno;
+
+    if (reply.error !=0)
+        return -reply.error;
+
+    if (reply.handle != request.handle)
+        return -EIO;
+
+    return 0;
+}
+
+static void nbd_close(BlockDriverState *bs)
+{
+    BDRVNBDState *s = bs->opaque;
+    struct nbd_request request;
+
+    request.type = NBD_CMD_DISC;
+    request.handle = (uint64_t)(intptr_t)bs;
+    request.from = 0;
+    request.len = 0;
+    nbd_send_request(s->sock, &request);
+
+    close(s->sock);
+}
+
+static int64_t nbd_getlength(BlockDriverState *bs)
+{
+    BDRVNBDState *s = bs->opaque;
+
+    return s->size;
+}
+
+BlockDriver bdrv_nbd = {
+    "nbd",
+    sizeof(BDRVNBDState),
+    NULL, /* no probe for protocols */
+    nbd_open,
+    nbd_read,
+    nbd_write,
+    nbd_close,
+    .bdrv_getlength = nbd_getlength,
+    .protocol_name = "nbd",
+};

Modified: trunk/block.c
===================================================================
--- trunk/block.c	2008-07-03 12:45:02 UTC (rev 4837)
+++ trunk/block.c	2008-07-03 13:41:03 UTC (rev 4838)
@@ -1332,6 +1332,7 @@
     bdrv_register(&bdrv_vvfat);
     bdrv_register(&bdrv_qcow2);
     bdrv_register(&bdrv_parallels);
+    bdrv_register(&bdrv_nbd);
 }
 
 void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb,

Modified: trunk/block.h
===================================================================
--- trunk/block.h	2008-07-03 12:45:02 UTC (rev 4837)
+++ trunk/block.h	2008-07-03 13:41:03 UTC (rev 4838)
@@ -16,6 +16,7 @@
 extern BlockDriver bdrv_vvfat;
 extern BlockDriver bdrv_qcow2;
 extern BlockDriver bdrv_parallels;
+extern BlockDriver bdrv_nbd;
 
 typedef struct BlockDriverInfo {
     /* in bytes, 0 if irrelevant */

Modified: trunk/nbd.c
===================================================================
--- trunk/nbd.c	2008-07-03 12:45:02 UTC (rev 4837)
+++ trunk/nbd.c	2008-07-03 13:41:03 UTC (rev 4838)
@@ -1,4 +1,4 @@
-/*\
+/*
  *  Copyright (C) 2005  Anthony Liguori <anthony@codemonkey.ws>
  *
  *  Network Block Device
@@ -15,7 +15,7 @@
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-\*/
+ */
 
 #include "nbd.h"
 
@@ -31,17 +31,21 @@
 #include <arpa/inet.h>
 #include <netdb.h>
 
+#if defined(QEMU_NBD)
 extern int verbose;
+#else
+static int verbose = 0;
+#endif
 
+#define TRACE(msg, ...) do { \
+    if (verbose) LOG(msg, ## __VA_ARGS__); \
+} while(0)
+
 #define LOG(msg, ...) do { \
     fprintf(stderr, "%s:%s():L%d: " msg "\n", \
             __FILE__, __FUNCTION__, __LINE__, ## __VA_ARGS__); \
 } while(0)
 
-#define TRACE(msg, ...) do { \
-    if (verbose) LOG(msg, ## __VA_ARGS__); \
-} while(0)
-
 /* This is all part of the "official" NBD API */
 
 #define NBD_REQUEST_MAGIC       0x25609513
@@ -59,10 +63,10 @@
 
 /* That's all folks */
 
-#define read_sync(fd, buffer, size) wr_sync(fd, buffer, size, true)
-#define write_sync(fd, buffer, size) wr_sync(fd, buffer, size, false)
+#define read_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, true)
+#define write_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, false)
 
-static size_t wr_sync(int fd, void *buffer, size_t size, bool do_read)
+size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
 {
     size_t offset = 0;
 
@@ -76,7 +80,7 @@
         }
 
         /* recoverable error */
-        if (len == -1 && errno == EAGAIN) {
+        if (len == -1 && (errno == EAGAIN || errno == EINTR)) {
             continue;
         }
 
@@ -96,7 +100,7 @@
     return offset;
 }
 
-static int tcp_socket_outgoing(const char *address, uint16_t port)
+int tcp_socket_outgoing(const char *address, uint16_t port)
 {
     int s;
     struct in_addr in;
@@ -404,17 +408,32 @@
 	return ret;
 }
 
-int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
-             off_t *offset, bool readonly, uint8_t *data, int data_size)
+int nbd_send_request(int csock, struct nbd_request *request)
 {
 	uint8_t buf[4 + 4 + 8 + 8 + 4];
+
+	cpu_to_be32w((uint32_t*)buf, NBD_REQUEST_MAGIC);
+	cpu_to_be32w((uint32_t*)(buf + 4), request->type);
+	cpu_to_be64w((uint64_t*)(buf + 8), request->handle);
+	cpu_to_be64w((uint64_t*)(buf + 16), request->from);
+	cpu_to_be32w((uint32_t*)(buf + 24), request->len);
+
+	TRACE("Sending request to client");
+
+	if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+		LOG("writing to socket failed");
+		errno = EINVAL;
+		return -1;
+	}
+	return 0;
+}
+
+
+static int nbd_receive_request(int csock, struct nbd_request *request)
+{
+	uint8_t buf[4 + 4 + 8 + 8 + 4];
 	uint32_t magic;
-	uint32_t type;
-	uint64_t from;
-	uint32_t len;
 
-	TRACE("Reading request.");
-
 	if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
 		LOG("read failed");
 		errno = EINVAL;
@@ -422,97 +441,158 @@
 	}
 
 	/* Request
-	  [ 0 ..  3]   magic   (NBD_REQUEST_MAGIC)
-	  [ 4 ..  7]   type    (0 == READ, 1 == WRITE)
-	  [ 8 .. 15]   handle
-	  [16 .. 23]   from
-	  [24 .. 27]   len
+	   [ 0 ..  3]   magic   (NBD_REQUEST_MAGIC)
+	   [ 4 ..  7]   type    (0 == READ, 1 == WRITE)
+	   [ 8 .. 15]   handle
+	   [16 .. 23]   from
+	   [24 .. 27]   len
 	 */
 
 	magic = be32_to_cpup((uint32_t*)buf);
-	type  = be32_to_cpup((uint32_t*)(buf + 4));
-	from  = be64_to_cpup((uint64_t*)(buf + 16));
-	len   = be32_to_cpup((uint32_t*)(buf + 24));
+	request->type  = be32_to_cpup((uint32_t*)(buf + 4));
+	request->handle = be64_to_cpup((uint64_t*)(buf + 8));
+	request->from  = be64_to_cpup((uint64_t*)(buf + 16));
+	request->len   = be32_to_cpup((uint32_t*)(buf + 24));
 
 	TRACE("Got request: "
 	      "{ magic = 0x%x, .type = %d, from = %" PRIu64" , len = %u }",
-	      magic, type, from, len);
+	      magic, request->type, request->from, request->len);
 
-
 	if (magic != NBD_REQUEST_MAGIC) {
 		LOG("invalid magic (got 0x%x)", magic);
 		errno = EINVAL;
 		return -1;
 	}
+}
 
-	if (len > data_size) {
+int nbd_receive_reply(int csock, struct nbd_reply *reply)
+{
+	uint8_t buf[4 + 4 + 8];
+	uint32_t magic;
+
+	memset(buf, 0xAA, sizeof(buf));
+
+	if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+		LOG("read failed");
+		errno = EINVAL;
+		return -1;
+	}
+
+	/* Reply
+	   [ 0 ..  3]    magic   (NBD_REPLY_MAGIC)
+	   [ 4 ..  7]    error   (0 == no error)
+	   [ 7 .. 15]    handle
+	 */
+
+	magic = be32_to_cpup((uint32_t*)buf);
+	reply->error  = be32_to_cpup((uint32_t*)(buf + 4));
+	reply->handle = be64_to_cpup((uint64_t*)(buf + 8));
+
+	TRACE("Got reply: "
+	      "{ magic = 0x%x, .error = %d, handle = %" PRIu64" }",
+	      magic, reply->error, reply->handle);
+
+	if (magic != NBD_REPLY_MAGIC) {
+		LOG("invalid magic (got 0x%x)", magic);
+		errno = EINVAL;
+		return -1;
+	}
+	return 0;
+}
+
+static int nbd_send_reply(int csock, struct nbd_reply *reply)
+{
+	uint8_t buf[4 + 4 + 8];
+
+	/* Reply
+	   [ 0 ..  3]    magic   (NBD_REPLY_MAGIC)
+	   [ 4 ..  7]    error   (0 == no error)
+	   [ 7 .. 15]    handle
+	 */
+	cpu_to_be32w((uint32_t*)buf, NBD_REPLY_MAGIC);
+	cpu_to_be32w((uint32_t*)(buf + 4), reply->error);
+	cpu_to_be64w((uint64_t*)(buf + 8), reply->handle);
+
+	TRACE("Sending response to client");
+
+	if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+		LOG("writing to socket failed");
+		errno = EINVAL;
+		return -1;
+	}
+	return 0;
+}
+
+int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
+             off_t *offset, bool readonly, uint8_t *data, int data_size)
+{
+	struct nbd_request request;
+	struct nbd_reply reply;
+
+	TRACE("Reading request.");
+
+	if (nbd_receive_request(csock, &request) == -1)
+		return -1;
+
+	if (request.len > data_size) {
 		LOG("len (%u) is larger than max len (%u)",
-		    len, data_size);
+		    request.len, data_size);
 		errno = EINVAL;
 		return -1;
 	}
 
-	if ((from + len) < from) {
+	if ((request.from + request.len) < request.from) {
 		LOG("integer overflow detected! "
 		    "you're probably being attacked");
 		errno = EINVAL;
 		return -1;
 	}
 
-	if ((from + len) > size) {
+	if ((request.from + request.len) > size) {
 	        LOG("From: %" PRIu64 ", Len: %u, Size: %" PRIu64
 		    ", Offset: %" PRIu64 "\n",
-		     from, len, size, dev_offset);
+		     request.from, request.len, size, dev_offset);
 		LOG("requested operation past EOF--bad client?");
 		errno = EINVAL;
 		return -1;
 	}
 
-	/* Reply
-	 [ 0 ..  3]    magic   (NBD_REPLY_MAGIC)
-	 [ 4 ..  7]    error   (0 == no error)
-         [ 7 .. 15]    handle
-	 */
-	cpu_to_be32w((uint32_t*)buf, NBD_REPLY_MAGIC);
-	cpu_to_be32w((uint32_t*)(buf + 4), 0);
-
 	TRACE("Decoding type");
 
-	switch (type) {
-	case 0:
+	reply.handle = request.handle;
+	reply.error = 0;
+
+	switch (request.type) {
+	case NBD_CMD_READ:
 		TRACE("Request type is READ");
 
-		if (bdrv_read(bs, (from + dev_offset) / 512, data, len / 512) == -1) {
+		if (bdrv_read(bs, (request.from + dev_offset) / 512, data,
+			      request.len / 512) == -1) {
 			LOG("reading from file failed");
 			errno = EINVAL;
 			return -1;
 		}
-		*offset += len;
+		*offset += request.len;
 
-		TRACE("Read %u byte(s)", len);
+		TRACE("Read %u byte(s)", request.len);
 
-		TRACE("Sending OK response");
-
-		if (write_sync(csock, buf, 16) != 16) {
-			LOG("writing to socket failed");
-			errno = EINVAL;
+		if (nbd_send_reply(csock, &reply) == -1)
 			return -1;
-		}
 
 		TRACE("Sending data to client");
 
-		if (write_sync(csock, data, len) != len) {
+		if (write_sync(csock, data, request.len) != request.len) {
 			LOG("writing to socket failed");
 			errno = EINVAL;
 			return -1;
 		}
 		break;
-	case 1:
+	case NBD_CMD_WRITE:
 		TRACE("Request type is WRITE");
 
-		TRACE("Reading %u byte(s)", len);
+		TRACE("Reading %u byte(s)", request.len);
 
-		if (read_sync(csock, data, len) != len) {
+		if (read_sync(csock, data, request.len) != request.len) {
 			LOG("reading from socket failed");
 			errno = EINVAL;
 			return -1;
@@ -520,34 +600,29 @@
 
 		if (readonly) {
 			TRACE("Server is read-only, return error");
-
-			cpu_to_be32w((uint32_t*)(buf + 4), 1);
+			reply.error = 1;
 		} else {
 			TRACE("Writing to device");
 
-			if (bdrv_write(bs, (from + dev_offset) / 512, data, len / 512) == -1) {
+			if (bdrv_write(bs, (request.from + dev_offset) / 512,
+				       data, request.len / 512) == -1) {
 				LOG("writing to file failed");
 				errno = EINVAL;
 				return -1;
 			}
 
-			*offset += len;
+			*offset += request.len;
 		}
 
-		TRACE("Sending response to client");
-
-		if (write_sync(csock, buf, 16) != 16) {
-			LOG("writing to socket failed");
-			errno = EINVAL;
+		if (nbd_send_reply(csock, &reply) == -1)
 			return -1;
-		}
 		break;
-	case 2:
+	case NBD_CMD_DISC:
 		TRACE("Request type is DISCONNECT");
 		errno = 0;
 		return 1;
 	default:
-		LOG("invalid request type (%u) received", type);
+		LOG("invalid request type (%u) received", request.type);
 		errno = EINVAL;
 		return -1;
 	}

Modified: trunk/nbd.h
===================================================================
--- trunk/nbd.h	2008-07-03 12:45:02 UTC (rev 4837)
+++ trunk/nbd.h	2008-07-03 13:41:03 UTC (rev 4838)
@@ -1,4 +1,4 @@
-/*\
+/*
  *  Copyright (C) 2005  Anthony Liguori <anthony@codemonkey.ws>
  *
  *  Network Block Device
@@ -15,7 +15,7 @@
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-\*/
+ */
 
 #ifndef NBD_H
 #define NBD_H
@@ -26,6 +26,26 @@
 #include <qemu-common.h>
 #include "block_int.h"
 
+struct nbd_request {
+    uint32_t type;
+    uint64_t handle;
+    uint64_t from;
+    uint32_t len;
+};
+
+struct nbd_reply {
+    uint32_t error;
+    uint64_t handle;
+};
+
+enum {
+    NBD_CMD_READ = 0,
+    NBD_CMD_WRITE = 1,
+    NBD_CMD_DISC = 2
+};
+
+size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read);
+int tcp_socket_outgoing(const char *address, uint16_t port);
 int tcp_socket_incoming(const char *address, uint16_t port);
 int unix_socket_outgoing(const char *path);
 int unix_socket_incoming(const char *path);
@@ -33,6 +53,8 @@
 int nbd_negotiate(BlockDriverState *bs, int csock, off_t size);
 int nbd_receive_negotiate(int csock, off_t *size, size_t *blocksize);
 int nbd_init(int fd, int csock, off_t size, size_t blocksize);
+int nbd_send_request(int csock, struct nbd_request *request);
+int nbd_receive_reply(int csock, struct nbd_reply *reply);
 int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
              off_t *offset, bool readonly, uint8_t *data, int data_size);
 int nbd_client(int fd, int csock);

Modified: trunk/qemu-doc.texi
===================================================================
--- trunk/qemu-doc.texi	2008-07-03 12:45:02 UTC (rev 4837)
+++ trunk/qemu-doc.texi	2008-07-03 13:41:03 UTC (rev 4838)
@@ -1321,6 +1321,7 @@
 * qemu_nbd_invocation::       qemu-nbd Invocation
 * host_drives::               Using host drives
 * disk_images_fat_images::    Virtual FAT disk images
+* disk_images_nbd::           NBD access
 @end menu
 
 @node disk_images_quickstart
@@ -1503,6 +1504,40 @@
 @item write to the FAT directory on the host system while accessing it with the guest system.
 @end itemize
 
+@node disk_images_nbd
+@subsection NBD access
+
+QEMU can access directly to block device exported using the Network Block Device
+protocol.
+
+@example
+qemu linux.img -hdb nbd:my_nbd_server.mydomain.org:1024
+@end example
+
+If the NBD server is located on the same host, you can use an unix socket instead
+of an inet socket:
+
+@example
+qemu linux.img -hdb nbd:unix:/tmp/my_socket
+@end example
+
+In this case, the block device must be exported using qemu-nbd:
+
+@example
+qemu-nbd --socket=/tmp/my_socket my_disk.qcow2
+@end example
+
+The use of qemu-nbd allows to share a disk between several guests:
+@example
+qemu-nbd --socket=/tmp/my_socket --share=2 my_disk.qcow2
+@end example
+
+and then you can use it with two guests:
+@example
+qemu linux1.img -hdb nbd:unix:/tmp/my_socket
+qemu linux2.img -hdb nbd:unix:/tmp/my_socket
+@end example
+
 @node pcsys_network
 @section Network emulation
 

Modified: trunk/qemu-nbd.c
===================================================================
--- trunk/qemu-nbd.c	2008-07-03 12:45:02 UTC (rev 4837)
+++ trunk/qemu-nbd.c	2008-07-03 13:41:03 UTC (rev 4838)
@@ -56,6 +56,7 @@
 "  -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"
+"  -t, --persistent     don't exit on the last connection\n"
 "  -v, --verbose        display extra debugging information\n"
 "  -h, --help           display this help and exit\n"
 "  -V, --version        output version information and exit\n"
@@ -189,7 +190,7 @@
     char *device = NULL;
     char *socket = NULL;
     char sockpath[128];
-    const char *sopt = "hVbo:p:rsnP:c:dvk:e:";
+    const char *sopt = "hVbo:p:rsnP:c:dvk:e:t";
     struct option lopt[] = {
         { "help", 0, 0, 'h' },
         { "version", 0, 0, 'V' },
@@ -204,6 +205,7 @@
         { "snapshot", 0, 0, 's' },
         { "nocache", 0, 0, 'n' },
         { "shared", 1, 0, 'e' },
+        { "persistent", 0, 0, 't' },
         { "verbose", 0, 0, 'v' },
         { NULL, 0, 0, 0 }
     };
@@ -222,6 +224,7 @@
     int i;
     int nb_fds = 0;
     int max_fd;
+    int persistent = 0;
 
     while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
         switch (ch) {
@@ -283,6 +286,9 @@
                 errx(EINVAL, "Shared device number must be greater than 0\n");
             }
             break;
+	case 't':
+	    persistent = 1;
+	    break;
         case 'v':
             verbose = 1;
             break;
@@ -459,7 +465,7 @@
                 }
             }
         }
-    } while (nb_fds > 1);
+    } while (persistent || nb_fds > 1);
     qemu_free(data);
 
     close(sharing_fds[0]);

Modified: trunk/qemu-nbd.texi
===================================================================
--- trunk/qemu-nbd.texi	2008-07-03 12:45:02 UTC (rev 4837)
+++ trunk/qemu-nbd.texi	2008-07-03 13:41:03 UTC (rev 4838)
@@ -36,6 +36,8 @@
   disconnect the specified device
 @item -e, --shared=NUM
   device can be shared by NUM clients (default '1')
+@item -t, --persistent
+  don't exit on the last connection
 @item -v, --verbose
   display extra debugging information
 @item -h, --help

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

end of thread, other threads:[~2008-08-04 16:49 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-07-03 13:41 [Qemu-devel] [4838] Allow QEMU to connect directly to an NBD server, by Laurent Vivier Thiemo Seufer
2008-07-04  1:33 ` chenqing
2008-07-04  2:34   ` Thiemo Seufer
2008-07-04  3:51     ` chenqing
2008-07-04  8:42       ` Laurent Vivier
2008-07-04 20:32         ` Thiemo Seufer
2008-07-04 20:52           ` Johannes Schindelin
2008-07-04 22:02             ` [Qemu-devel] [PATCH] Fix compilation of nbd on Windows Johannes Schindelin
2008-07-05 11:58               ` Filip Navara
2008-07-05 22:41                 ` Jamie Lokier
2008-07-06  1:51                   ` Johannes Schindelin
2008-07-06 16:49                     ` Jamie Lokier
2008-07-06 17:23                       ` Johannes Schindelin
2008-07-08 19:22               ` Anthony Liguori
2008-07-09  0:14                 ` Johannes Schindelin
2008-07-18 14:24                   ` [Qemu-devel] " Sebastian Herbszt
2008-07-18 15:26                     ` Johannes Schindelin
2008-08-02 19:21               ` [Qemu-devel] [PATCH v2] " Johannes Schindelin
2008-08-03 17:11                 ` Anthony Liguori
2008-08-03 17:32                   ` Johannes Schindelin
2008-08-03 20:42                     ` Anthony Liguori
2008-08-03 20:58                       ` Johannes Schindelin
2008-08-03 21:09                         ` Anthony Liguori
2008-08-03 21:30                           ` Johannes Schindelin
2008-08-04 13:29                       ` Jamie Lokier
2008-08-04 16:49                         ` Thiemo Seufer
2008-08-03 21:21                     ` Anthony Liguori
2008-08-03 21:37                       ` Johannes Schindelin
2008-08-04 13:23                         ` Jamie Lokier
2008-08-03 21:57                     ` Andreas Färber
2008-07-04  8:01     ` [Qemu-devel] [4838] Allow QEMU to connect directly to an NBD server, by Laurent Vivier Laurent Vivier

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.