* [Qemu-devel] [patch 0/5] NBD support improvement
@ 2008-06-27 11:02 Laurent.Vivier
2008-06-27 11:02 ` [Qemu-devel] [patch 1/5] qemu-nbd: cleanup Laurent.Vivier
` (4 more replies)
0 siblings, 5 replies; 10+ messages in thread
From: Laurent.Vivier @ 2008-06-27 11:02 UTC (permalink / raw)
To: qemu-devel; +Cc: Laurent.Vivier
This series of patches improves NBD support in QEMU.
[PATCH 1/5] qemu-nbd: cleanup
[PATCH 2/5] qemu-nbd: merge NBD client/server
[PATCH 3/5] qemu-nbd: add a parameter to disable host cache.
[PATCH 4/5] qemu-nbd: allow to share a disk image
[PATCH 5/5] Allow QEMU to connect directly to an NBD server
Laurent
--
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Qemu-devel] [patch 1/5] qemu-nbd: cleanup
2008-06-27 11:02 [Qemu-devel] [patch 0/5] NBD support improvement Laurent.Vivier
@ 2008-06-27 11:02 ` Laurent.Vivier
2008-06-27 11:02 ` [Qemu-devel] [patch 2/5] qemu-nbd: merge NBD client/server Laurent.Vivier
` (3 subsequent siblings)
4 siblings, 0 replies; 10+ messages in thread
From: Laurent.Vivier @ 2008-06-27 11:02 UTC (permalink / raw)
To: qemu-devel; +Cc: Laurent.Vivier
[-- Attachment #1: nbd-cleanup.patch --]
[-- Type: text/plain, Size: 2254 bytes --]
This patch removes "#include <malloc.h>" and correct a printf format.
(from Carlo Marcelo Arenas Belon <carenas@sajinet.com.pe>).
Fill the last element of lopt (for getopt_long()) to mark the end of parameters
list. Add an entry in qemu-doc.texi.
---
nbd.c | 4 ++--
qemu-doc.texi | 6 ++++++
qemu-nbd.c | 2 +-
3 files changed, 9 insertions(+), 3 deletions(-)
Index: qemu/nbd.c
===================================================================
--- qemu.orig/nbd.c 2008-06-27 11:34:18.000000000 +0200
+++ qemu/nbd.c 2008-06-27 11:34:28.000000000 +0200
@@ -388,8 +388,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/qemu-nbd.c
===================================================================
--- qemu.orig/qemu-nbd.c 2008-06-27 11:34:18.000000000 +0200
+++ qemu/qemu-nbd.c 2008-06-27 11:34:28.000000000 +0200
@@ -21,7 +21,6 @@
#include "block_int.h"
#include "nbd.h"
-#include <malloc.h>
#include <stdarg.h>
#include <stdio.h>
#include <getopt.h>
@@ -168,6 +167,7 @@ int main(int argc, char **argv)
{ "partition", 1, 0, 'P' },
{ "snapshot", 0, 0, 's' },
{ "verbose", 0, 0, 'v' },
+ { NULL, 0, 0, 0 }
};
int ch;
int opt_ind = 0;
Index: qemu/qemu-doc.texi
===================================================================
--- qemu.orig/qemu-doc.texi 2008-06-27 11:34:18.000000000 +0200
+++ qemu/qemu-doc.texi 2008-06-27 11:34:28.000000000 +0200
@@ -1307,6 +1307,7 @@ snapshots.
* disk_images_snapshot_mode:: Snapshot mode
* vm_snapshots:: VM snapshots
* qemu_img_invocation:: qemu-img Invocation
+* qemu_nbd_invocation:: qemu-nbd Invocation
* host_drives:: Using host drives
* disk_images_fat_images:: Virtual FAT disk images
@end menu
@@ -1389,6 +1390,11 @@ state is not saved or restored properly
@include qemu-img.texi
+@node qemu_nbd_invocation
+@subsection @code{qemu-nbd} Invocation
+
+@include qemu-nbd.texi
+
@node host_drives
@subsection Using host drives
--
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Qemu-devel] [patch 2/5] qemu-nbd: merge NBD client/server
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 ` Laurent.Vivier
2008-07-02 21:26 ` Thiemo Seufer
2008-06-27 11:02 ` [Qemu-devel] [patch 3/5] qemu-nbd: add a parameter to disable host cache Laurent.Vivier
` (2 subsequent siblings)
4 siblings, 1 reply; 10+ messages in thread
From: Laurent.Vivier @ 2008-06-27 11:02 UTC (permalink / raw)
To: qemu-devel; +Cc: Laurent.Vivier
[-- Attachment #1: qemu-nbd-local.patch --]
[-- Type: text/plain, Size: 11968 bytes --]
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.
- v3: allow to specify unix socket name with "--socket" and update
documentation.
---
nbd.c | 74 ++++++++++++++++++++++++++++---
nbd.h | 5 +-
qemu-nbd.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
qemu-nbd.texi | 6 ++
4 files changed, 212 insertions(+), 10 deletions(-)
Index: qemu/nbd.c
===================================================================
--- qemu.orig/nbd.c 2008-06-27 11:34:28.000000000 +0200
+++ qemu/nbd.c 2008-06-27 11:34:35.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
@@ -225,12 +285,10 @@ int nbd_negotiate(BlockDriverState *bs,
return 0;
}
-int nbd_receive_negotiate(int fd, int csock)
+int nbd_receive_negotiate(int csock, off_t *size, size_t *blocksize)
{
char buf[8 + 8 + 8 + 128];
uint64_t magic;
- off_t size;
- size_t blocksize;
TRACE("Receiving negotation.");
@@ -241,8 +299,8 @@ int nbd_receive_negotiate(int fd, int cs
}
magic = be64_to_cpup((uint64_t*)(buf + 8));
- size = be64_to_cpup((uint64_t*)(buf + 16));
- blocksize = 1024;
+ *size = be64_to_cpup((uint64_t*)(buf + 16));
+ *blocksize = 1024;
TRACE("Magic is %c%c%c%c%c%c%c%c",
isprint(buf[0]) ? buf[0] : '.',
@@ -254,7 +312,7 @@ int nbd_receive_negotiate(int fd, int cs
isprint(buf[6]) ? buf[6] : '.',
isprint(buf[7]) ? buf[7] : '.');
TRACE("Magic is 0x%" PRIx64, magic);
- TRACE("Size is %" PRIu64, size);
+ TRACE("Size is %" PRIu64, *size);
if (memcmp(buf, "NBDMAGIC", 8) != 0) {
LOG("Invalid magic received");
@@ -269,7 +327,11 @@ int nbd_receive_negotiate(int fd, int cs
errno = EINVAL;
return -1;
}
+ return 0;
+}
+int nbd_init(int fd, int csock, off_t size, size_t blocksize)
+{
TRACE("Setting block size to %lu", (unsigned long)blocksize);
if (ioctl(fd, NBD_SET_BLKSIZE, blocksize) == -1) {
Index: qemu/nbd.h
===================================================================
--- qemu.orig/nbd.h 2008-06-27 11:34:18.000000000 +0200
+++ qemu/nbd.h 2008-06-27 11:34:35.000000000 +0200
@@ -27,9 +27,12 @@
#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);
+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_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset, off_t *offset, bool readonly);
int nbd_client(int fd, int csock);
int nbd_disconnect(int fd);
Index: qemu/qemu-nbd.c
===================================================================
--- qemu.orig/qemu-nbd.c 2008-06-27 11:34:28.000000000 +0200
+++ qemu/qemu-nbd.c 2008-06-27 11:34:35.000000000 +0200
@@ -25,10 +25,14 @@
#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 SOCKET_PATH "/var/lock/qemu-nbd-%s"
int verbose;
@@ -41,14 +45,18 @@ static void usage(const char *name)
" -p, --port=PORT port to listen on (default `1024')\n"
" -o, --offset=OFFSET offset into the image\n"
" -b, --bind=IFACE interface to bind to (default `0.0.0.0')\n"
+" -k, --socket=PATH path to the unix socket\n"
+" (default '"SOCKET_PATH"')\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"
"\n"
"Report bugs to <anthony@codemonkey.ws>\n"
- , name);
+ , name, "DEVICE");
}
static void version(const char *name)
@@ -144,27 +152,51 @@ 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 *socket = NULL;
+ char sockpath[128];
+ const char *sopt = "hVbo:p:rsP:c:dvk:";
struct option lopt[] = {
{ "help", 0, 0, 'h' },
{ "version", 0, 0, 'V' },
{ "bind", 1, 0, 'b' },
{ "port", 1, 0, 'p' },
+ { "socket", 1, 0, 'k' },
{ "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' },
{ NULL, 0, 0, 0 }
@@ -175,6 +207,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 +247,17 @@ int main(int argc, char **argv)
if (partition < 1 || partition > 8)
errx(EINVAL, "Invalid partition %d", partition);
break;
+ case 'k':
+ socket = optarg;
+ if (socket[0] != '/')
+ errx(EINVAL, "socket path must be absolute\n");
+ break;
+ case 'd':
+ disconnect = true;
+ break;
+ case 'c':
+ device = optarg;
+ break;
case 'v':
verbose = 1;
break;
@@ -236,6 +281,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 +310,77 @@ 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 */
+
+ if (socket == NULL) {
+ sprintf(sockpath, SOCKET_PATH, basename(device));
+ socket = sockpath;
+ }
+
+ pid = fork();
+ if (pid < 0)
+ return 1;
+ if (pid != 0) {
+ off_t size;
+ size_t blocksize;
+
+ ret = 0;
+ bdrv_close(bs);
+
+ do {
+ sock = unix_socket_outgoing(socket);
+ 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(sock, &size, &blocksize);
+ if (ret == -1) {
+ ret = 1;
+ goto exit;
+ }
+
+ ret = nbd_init(fd, sock, size, blocksize);
+ if (ret == -1) {
+ 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(socket);
+
+ return ret;
+ }
+ /* children */
+ }
+
+ if (socket) {
+ sock = unix_socket_incoming(socket);
+ } else {
+ sock = tcp_socket_incoming(bindto, port);
+ }
+
if (sock == -1)
return 1;
@@ -270,6 +399,8 @@ int main(int argc, char **argv)
close(csock);
close(sock);
bdrv_close(bs);
+ if (socket)
+ unlink(socket);
return 0;
}
Index: qemu/qemu-nbd.texi
===================================================================
--- qemu.orig/qemu-nbd.texi 2008-06-27 11:34:18.000000000 +0200
+++ qemu/qemu-nbd.texi 2008-06-27 11:34:35.000000000 +0200
@@ -20,10 +20,16 @@ Export Qemu disk image using NBD protoco
offset into the image
@item -b, --bind=IFACE
interface to bind to (default `0.0.0.0')
+@item -k, --socket=PATH
+ Use a unix socket with path PATH
@item -r, --read-only
export read-only
@item -P, --partition=NUM
only expose partition NUM
+@item -c, --connect
+ connect FILE to NBD device DEV
+@item -d, --disconnect
+ disconnect the specified device
@item -v, --verbose
display extra debugging information
@item -h, --help
--
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Qemu-devel] [patch 3/5] qemu-nbd: add a parameter to disable host cache.
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-06-27 11:02 ` Laurent.Vivier
2008-06-27 11:02 ` [Qemu-devel] [patch 4/5] qemu-nbd: allow to share a disk image Laurent.Vivier
2008-06-27 11:02 ` [Qemu-devel] [patch 5/5] Allow QEMU to connect directly to an NBD server Laurent.Vivier
4 siblings, 0 replies; 10+ messages in thread
From: Laurent.Vivier @ 2008-06-27 11:02 UTC (permalink / raw)
To: qemu-devel; +Cc: Laurent.Vivier
[-- Attachment #1: qemu-nbd-direct.patch --]
[-- Type: text/plain, Size: 8602 bytes --]
This patch add a parameter "--nocache" to disable host cache for disk image.
It avoid to duplicate page for NBD device and disk image file.
---
Makefile | 5 ++++-
block-raw-posix.c | 16 ++++++++--------
nbd.c | 13 ++++---------
nbd.h | 3 ++-
qemu-nbd.c | 22 +++++++++++++++++-----
qemu-nbd.texi | 4 ++++
6 files changed, 39 insertions(+), 24 deletions(-)
Index: qemu/Makefile
===================================================================
--- qemu.orig/Makefile 2008-06-27 11:34:17.000000000 +0200
+++ qemu/Makefile 2008-06-27 11:34:38.000000000 +0200
@@ -172,8 +172,11 @@ qemu-img-%.o: %.c
%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
+qemu-nbd-%.o: %.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -DQEMU_NBD -c -o $@ $<
+
qemu-nbd$(EXESUF): qemu-nbd.o nbd.o qemu-img-block.o \
- $(QEMU_IMG_BLOCK_OBJS)
+ osdep.o qemu-nbd-block-raw-posix.o $(BLOCK_OBJS)
$(CC) $(LDFLAGS) -o $@ $^ -lz $(LIBS)
# dyngen host tool
Index: qemu/block-raw-posix.c
===================================================================
--- qemu.orig/block-raw-posix.c 2008-06-27 11:34:18.000000000 +0200
+++ qemu/block-raw-posix.c 2008-06-27 11:34:38.000000000 +0200
@@ -22,7 +22,7 @@
* THE SOFTWARE.
*/
#include "qemu-common.h"
-#ifndef QEMU_IMG
+#if !defined(QEMU_IMG) && !defined(QEMU_NBD)
#include "qemu-timer.h"
#include "exec-all.h"
#endif
@@ -59,7 +59,7 @@
//#define DEBUG_FLOPPY
//#define DEBUG_BLOCK
-#if defined(DEBUG_BLOCK) && !defined(QEMU_IMG)
+#if defined(DEBUG_BLOCK) && !defined(QEMU_IMG) && !defined(QEMU_NBD)
#define DEBUG_BLOCK_PRINT(formatCstr, args...) do { if (loglevel != 0) \
{ fprintf(logfile, formatCstr, ##args); fflush(logfile); } } while (0)
#else
@@ -434,7 +434,7 @@ static int aio_initialized = 0;
static void aio_signal_handler(int signum)
{
-#ifndef QEMU_IMG
+#if !defined(QEMU_IMG) && !defined(QEMU_NBD)
CPUState *env = cpu_single_env;
if (env) {
/* stop the currently executing cpu because a timer occured */
@@ -544,7 +544,7 @@ void qemu_aio_wait(void)
sigset_t set;
int nb_sigs;
-#ifndef QEMU_IMG
+#if !defined(QEMU_IMG) && !defined(QEMU_NBD)
if (qemu_bh_poll())
return;
#endif
@@ -586,7 +586,7 @@ static RawAIOCB *raw_aio_setup(BlockDriv
return acb;
}
-#ifndef QEMU_IMG
+#if !defined(QEMU_IMG) && !defined(QEMU_NBD)
static void raw_aio_em_cb(void* opaque)
{
RawAIOCB *acb = opaque;
@@ -605,7 +605,7 @@ static BlockDriverAIOCB *raw_aio_read(Bl
* If O_DIRECT is used and the buffer is not aligned fall back
* to synchronous IO.
*/
-#if defined(O_DIRECT) && !defined(QEMU_IMG)
+#if defined(O_DIRECT) && !defined(QEMU_IMG) && !defined(QEMU_NBD)
BDRVRawState *s = bs->opaque;
if (unlikely(s->aligned_buf != NULL && ((uintptr_t) buf % 512))) {
@@ -638,7 +638,7 @@ static BlockDriverAIOCB *raw_aio_write(B
* If O_DIRECT is used and the buffer is not aligned fall back
* to synchronous IO.
*/
-#if defined(O_DIRECT) && !defined(QEMU_IMG)
+#if defined(O_DIRECT) && !defined(QEMU_IMG) && !defined(QEMU_NBD)
BDRVRawState *s = bs->opaque;
if (unlikely(s->aligned_buf != NULL && ((uintptr_t) buf % 512))) {
@@ -941,7 +941,7 @@ static int hdev_open(BlockDriverState *b
return 0;
}
-#if defined(__linux__) && !defined(QEMU_IMG)
+#if defined(__linux__) && !defined(QEMU_IMG) && !defined(QEMU_NBD)
/* Note: we do not have a reliable method to detect if the floppy is
present. The current method is to try to open the floppy at every
Index: qemu/nbd.c
===================================================================
--- qemu.orig/nbd.c 2008-06-27 11:34:35.000000000 +0200
+++ qemu/nbd.c 2008-06-27 11:34:38.000000000 +0200
@@ -404,13 +404,8 @@ int nbd_client(int fd, int csock)
return ret;
}
-int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset, off_t *offset, bool readonly)
+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)
{
-#ifndef _REENTRANT
- static uint8_t data[1024 * 1024]; // keep this off of the stack
-#else
- uint8_t data[1024 * 1024];
-#endif
uint8_t buf[4 + 4 + 8 + 8 + 4];
uint32_t magic;
uint32_t type;
@@ -449,9 +444,9 @@ int nbd_trip(BlockDriverState *bs, int c
return -1;
}
- if (len > sizeof(data)) {
- LOG("len (%u) is larger than max len (%lu)",
- len, (unsigned long)sizeof(data));
+ if (len > data_size) {
+ LOG("len (%u) is larger than max len (%u)",
+ len, data_size);
errno = EINVAL;
return -1;
}
Index: qemu/qemu-nbd.c
===================================================================
--- qemu.orig/qemu-nbd.c 2008-06-27 11:34:35.000000000 +0200
+++ qemu/qemu-nbd.c 2008-06-27 11:34:38.000000000 +0200
@@ -34,6 +34,8 @@
#define SOCKET_PATH "/var/lock/qemu-nbd-%s"
+#define NBD_BUFFER_SIZE (1024*1024)
+
int verbose;
static void usage(const char *name)
@@ -49,6 +51,8 @@ static void usage(const char *name)
" (default '"SOCKET_PATH"')\n"
" -r, --read-only export read-only\n"
" -P, --partition=NUM only expose partition NUM\n"
+" -s, --snapshot use snapshot file\n"
+" -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"
" -v, --verbose display extra debugging information\n"
@@ -185,7 +189,7 @@ int main(int argc, char **argv)
char *device = NULL;
char *socket = NULL;
char sockpath[128];
- const char *sopt = "hVbo:p:rsP:c:dvk:";
+ const char *sopt = "hVbo:p:rsnP:c:dvk:";
struct option lopt[] = {
{ "help", 0, 0, 'h' },
{ "version", 0, 0, 'V' },
@@ -198,6 +202,7 @@ int main(int argc, char **argv)
{ "connect", 1, 0, 'c' },
{ "disconnect", 0, 0, 'd' },
{ "snapshot", 0, 0, 's' },
+ { "nocache", 0, 0, 'n' },
{ "verbose", 0, 0, 'v' },
{ NULL, 0, 0, 0 }
};
@@ -205,15 +210,19 @@ int main(int argc, char **argv)
int opt_ind = 0;
int li;
char *end;
- bool snapshot = false;
+ int flags = 0;
int partition = -1;
int fd;
int ret;
+ uint8_t *data;
while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
switch (ch) {
case 's':
- snapshot = true;
+ flags |= BDRV_O_SNAPSHOT;
+ break;
+ case 'n':
+ flags |= BDRV_O_DIRECT;
break;
case 'b':
bindto = optarg;
@@ -301,7 +310,7 @@ int main(int argc, char **argv)
if (bs == NULL)
return 1;
- if (bdrv_open(bs, argv[optind], snapshot) == -1)
+ if (bdrv_open(bs, argv[optind], flags) == -1)
return 1;
fd_size = bs->total_sectors * 512;
@@ -394,7 +403,10 @@ exit:
if (nbd_negotiate(bs, csock, fd_size) == -1)
return 1;
- while (nbd_trip(bs, csock, fd_size, dev_offset, &offset, readonly) == 0);
+ data = qemu_memalign(512, NBD_BUFFER_SIZE);
+ while (nbd_trip(bs, csock, fd_size, dev_offset, &offset, readonly,
+ data, NBD_BUFFER_SIZE) == 0);
+ qemu_free(data);
close(csock);
close(sock);
Index: qemu/nbd.h
===================================================================
--- qemu.orig/nbd.h 2008-06-27 11:34:35.000000000 +0200
+++ qemu/nbd.h 2008-06-27 11:34:38.000000000 +0200
@@ -33,7 +33,8 @@ int unix_socket_incoming(const char *pat
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_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset, off_t *offset, bool readonly);
+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);
int nbd_disconnect(int fd);
Index: qemu/qemu-nbd.texi
===================================================================
--- qemu.orig/qemu-nbd.texi 2008-06-27 11:34:35.000000000 +0200
+++ qemu/qemu-nbd.texi 2008-06-27 11:34:38.000000000 +0200
@@ -26,6 +26,10 @@ Export Qemu disk image using NBD protoco
export read-only
@item -P, --partition=NUM
only expose partition NUM
+@item -s, --snapshot
+ use snapshot file
+@item -n, --nocache
+ disable host cache
@item -c, --connect
connect FILE to NBD device DEV
@item -d, --disconnect
--
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Qemu-devel] [patch 4/5] qemu-nbd: allow to share a disk image
2008-06-27 11:02 [Qemu-devel] [patch 0/5] NBD support improvement Laurent.Vivier
` (2 preceding siblings ...)
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
2008-06-27 11:02 ` [Qemu-devel] [patch 5/5] Allow QEMU to connect directly to an NBD server Laurent.Vivier
4 siblings, 0 replies; 10+ messages in thread
From: Laurent.Vivier @ 2008-06-27 11:02 UTC (permalink / raw)
To: qemu-devel; +Cc: Laurent.Vivier
[-- 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
--
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Qemu-devel] [patch 5/5] Allow QEMU to connect directly to an NBD server
2008-06-27 11:02 [Qemu-devel] [patch 0/5] NBD support improvement Laurent.Vivier
` (3 preceding siblings ...)
2008-06-27 11:02 ` [Qemu-devel] [patch 4/5] qemu-nbd: allow to share a disk image Laurent.Vivier
@ 2008-06-27 11:02 ` Laurent.Vivier
4 siblings, 0 replies; 10+ messages in thread
From: Laurent.Vivier @ 2008-06-27 11:02 UTC (permalink / raw)
To: qemu-devel; +Cc: Laurent.Vivier
[-- Attachment #1: block-nbd.patch --]
[-- Type: text/plain, Size: 22960 bytes --]
This patch add a new protocol to QEMU block interface: "nbd".
It allows to QEMU to connect to an NBD server without using kernel support
(/dev/nbd*).
example:
qemu linux.img -hdb nbd:my_nbd_server.mydomain.org:1024
If the NBD server is located on the same host, you can use an unix socket
instead of an inet socket:
qemu linux.img -hdb nbd:unix:/tmp/my_socket
In this case, the block device must be exported using qemu-nbd:
qemu-nbd --socket=/tmp/my_socket my_disk.qcow2
The use of qemu-nbd allows to share a disk between several guests:
qemu-nbd --socket=/tmp/my_socket --share=2 my_disk.qcow2
and then you can use it with two guests:
qemu linux1.img -hdb nbd:unix:/tmp/my_socket
qemu linux2.img -hdb nbd:unix:/tmp/my_socket
---
Makefile | 8 +-
block-nbd.c | 194 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
block.c | 1
block.h | 1
nbd.c | 196 ++++++++++++++++++++++++++++++++++++++++------------------
nbd.h | 22 ++++++
qemu-doc.texi | 35 ++++++++++
qemu-nbd.c | 10 ++
qemu-nbd.texi | 2
9 files changed, 403 insertions(+), 66 deletions(-)
Index: qemu/block-nbd.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ qemu/block-nbd.c 2008-06-27 11:35:14.000000000 +0200
@@ -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)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)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)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",
+};
Index: qemu/Makefile
===================================================================
--- qemu.orig/Makefile 2008-06-27 11:35:11.000000000 +0200
+++ qemu/Makefile 2008-06-27 11:35:14.000000000 +0200
@@ -42,7 +42,7 @@ recurse-all: $(SUBDIR_RULES)
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 @@ BLOCK_OBJS+=block-qcow2.o block-parallel
# 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
@@ -154,7 +154,7 @@ libqemu_user.a: $(USER_OBJS)
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
@@ -175,7 +175,7 @@ qemu-img-%.o: %.c
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)
Index: qemu/nbd.c
===================================================================
--- qemu.orig/nbd.c 2008-06-27 11:35:11.000000000 +0200
+++ qemu/nbd.c 2008-06-27 11:35:14.000000000 +0200
@@ -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 @@ extern int verbose;
/* 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 @@ static size_t wr_sync(int fd, void *buff
}
/* recoverable error */
- if (len == -1 && errno == EAGAIN) {
+ if (len == -1 && (errno == EAGAIN || errno == EINTR)) {
continue;
}
@@ -96,7 +100,7 @@ static size_t wr_sync(int fd, void *buff
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,15 +408,31 @@ int nbd_client(int fd, int csock)
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];
- uint32_t magic;
- uint32_t type;
- uint64_t from;
- uint32_t len;
- TRACE("Reading request.");
+ 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;
if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
LOG("read failed");
@@ -429,89 +449,150 @@ int nbd_trip(BlockDriverState *bs, int c
*/
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;
}
+}
+
+int nbd_receive_reply(int csock, struct nbd_reply *reply)
+{
+ uint8_t buf[4 + 4 + 8];
+ uint32_t magic;
+int i;
+
+for (i = 0; i < sizeof(buf); i++) buf[i] = 0xAA;
+
+ if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+ LOG("read failed");
+ errno = EINVAL;
+ return -1;
+ }
- if (len > data_size) {
+ /* 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;
-
- TRACE("Read %u byte(s)", len);
+ *offset += request.len;
- TRACE("Sending OK response");
+ TRACE("Read %u byte(s)", request.len);
- 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;
@@ -519,34 +600,29 @@ int nbd_trip(BlockDriverState *bs, int c
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;
}
Index: qemu/nbd.h
===================================================================
--- qemu.orig/nbd.h 2008-06-27 11:35:11.000000000 +0200
+++ qemu/nbd.h 2008-06-27 11:35:14.000000000 +0200
@@ -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 unix_socket_incoming(const char *pat
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);
Index: qemu/block.c
===================================================================
--- qemu.orig/block.c 2008-06-27 11:35:11.000000000 +0200
+++ qemu/block.c 2008-06-27 11:35:14.000000000 +0200
@@ -1332,6 +1332,7 @@ void bdrv_init(void)
bdrv_register(&bdrv_vvfat);
bdrv_register(&bdrv_qcow2);
bdrv_register(&bdrv_parallels);
+ bdrv_register(&bdrv_nbd);
}
void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb,
Index: qemu/block.h
===================================================================
--- qemu.orig/block.h 2008-06-27 11:35:11.000000000 +0200
+++ qemu/block.h 2008-06-27 11:35:14.000000000 +0200
@@ -16,6 +16,7 @@ extern BlockDriver bdrv_vpc;
extern BlockDriver bdrv_vvfat;
extern BlockDriver bdrv_qcow2;
extern BlockDriver bdrv_parallels;
+extern BlockDriver bdrv_nbd;
typedef struct BlockDriverInfo {
/* in bytes, 0 if irrelevant */
Index: qemu/qemu-nbd.c
===================================================================
--- qemu.orig/qemu-nbd.c 2008-06-27 11:35:11.000000000 +0200
+++ qemu/qemu-nbd.c 2008-06-27 11:35:14.000000000 +0200
@@ -56,6 +56,7 @@ static void usage(const char *name)
" -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 @@ int main(int argc, char **argv)
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 @@ int main(int argc, char **argv)
{ "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 main(int argc, char **argv)
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 @@ int main(int argc, char **argv)
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 @@ exit:
}
}
}
- } while (nb_fds > 1);
+ } while (persistent || nb_fds > 1);
qemu_free(data);
close(sharing_fds[0]);
Index: qemu/qemu-nbd.texi
===================================================================
--- qemu.orig/qemu-nbd.texi 2008-06-27 11:35:11.000000000 +0200
+++ qemu/qemu-nbd.texi 2008-06-27 11:35:14.000000000 +0200
@@ -36,6 +36,8 @@ Export Qemu disk image using NBD protoco
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
Index: qemu/qemu-doc.texi
===================================================================
--- qemu.orig/qemu-doc.texi 2008-06-27 11:35:11.000000000 +0200
+++ qemu/qemu-doc.texi 2008-06-27 11:35:14.000000000 +0200
@@ -1310,6 +1310,7 @@ snapshots.
* 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
@@ -1492,6 +1493,40 @@ What you should @emph{never} do:
@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
--
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Qemu-devel] [patch 2/5] qemu-nbd: merge NBD client/server
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
0 siblings, 1 reply; 10+ messages in thread
From: Thiemo Seufer @ 2008-07-02 21:26 UTC (permalink / raw)
To: qemu-devel; +Cc: Laurent.Vivier
Laurent.Vivier@bull.net wrote:
> 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.
> - v3: allow to specify unix socket name with "--socket" and update
> documentation.
There's still a call to sleep() in this patch.
Thiemo
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Qemu-devel] [patch 2/5] qemu-nbd: merge NBD client/server
2008-07-02 21:26 ` Thiemo Seufer
@ 2008-07-03 7:21 ` Kevin Wolf
2008-07-03 8:13 ` Laurent Vivier
0 siblings, 1 reply; 10+ messages in thread
From: Kevin Wolf @ 2008-07-03 7:21 UTC (permalink / raw)
To: qemu-devel; +Cc: Laurent.Vivier
Thiemo Seufer schrieb:
> Laurent.Vivier@bull.net wrote:
>> 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.
>> - v3: allow to specify unix socket name with "--socket" and update
>> documentation.
>
> There's still a call to sleep() in this patch.
And that's fine, IMHO. sleep() is not bad per se. The remaining call is
not a "guess it'll take at most a second" style sleep but waiting in a
loop until the child is ready. You don't want the loop to eat up 100%
CPU, do you?
Kevin
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Qemu-devel] [patch 2/5] qemu-nbd: merge NBD client/server
2008-07-03 7:21 ` Kevin Wolf
@ 2008-07-03 8:13 ` Laurent Vivier
2008-07-03 10:27 ` Thiemo Seufer
0 siblings, 1 reply; 10+ messages in thread
From: Laurent Vivier @ 2008-07-03 8:13 UTC (permalink / raw)
To: Kevin Wolf; +Cc: qemu-devel
Le jeudi 03 juillet 2008 à 09:21 +0200, Kevin Wolf a écrit :
> Thiemo Seufer schrieb:
> > Laurent.Vivier@bull.net wrote:
> >> 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.
> >> - v3: allow to specify unix socket name with "--socket" and update
> >> documentation.
> >
> > There's still a call to sleep() in this patch.
>
> And that's fine, IMHO. sleep() is not bad per se. The remaining call is
> not a "guess it'll take at most a second" style sleep but waiting in a
> loop until the child is ready. You don't want the loop to eat up 100%
> CPU, do you?
I agree.
Laurent
--
------------- Laurent.Vivier@bull.net ---------------
"The best way to predict the future is to invent it."
- Alan Kay
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Qemu-devel] [patch 2/5] qemu-nbd: merge NBD client/server
2008-07-03 8:13 ` Laurent Vivier
@ 2008-07-03 10:27 ` Thiemo Seufer
0 siblings, 0 replies; 10+ messages in thread
From: Thiemo Seufer @ 2008-07-03 10:27 UTC (permalink / raw)
To: Laurent Vivier; +Cc: Kevin Wolf, qemu-devel
Laurent Vivier wrote:
> Le jeudi 03 juillet 2008 à 09:21 +0200, Kevin Wolf a écrit :
> > Thiemo Seufer schrieb:
> > > Laurent.Vivier@bull.net wrote:
> > >> 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.
> > >> - v3: allow to specify unix socket name with "--socket" and update
> > >> documentation.
> > >
> > > There's still a call to sleep() in this patch.
> >
> > And that's fine, IMHO. sleep() is not bad per se. The remaining call is
> > not a "guess it'll take at most a second" style sleep but waiting in a
> > loop until the child is ready. You don't want the loop to eat up 100%
> > CPU, do you?
>
> I agree.
I committed it with a small change (exit is not the best name for a label).
Thiemo
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2008-07-03 10:27 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 ` [Qemu-devel] [patch 4/5] qemu-nbd: allow to share a disk image Laurent.Vivier
2008-06-27 11:02 ` [Qemu-devel] [patch 5/5] Allow QEMU to connect directly to an NBD server 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.