From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1KELyo-0000gK-73 for qemu-devel@nongnu.org; Thu, 03 Jul 2008 06:23:58 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1KELym-0000cX-7N for qemu-devel@nongnu.org; Thu, 03 Jul 2008 06:23:56 -0400 Received: from [199.232.76.173] (port=34100 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1KELyl-0000cB-9u for qemu-devel@nongnu.org; Thu, 03 Jul 2008 06:23:55 -0400 Received: from savannah.gnu.org ([199.232.41.3]:56973 helo=sv.gnu.org) by monty-python.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1KELyj-0003qX-Fq for qemu-devel@nongnu.org; Thu, 03 Jul 2008 06:23:53 -0400 Received: from cvs.savannah.gnu.org ([199.232.41.69]) by sv.gnu.org with esmtp (Exim 4.63) (envelope-from ) id 1KELyi-0006yj-7V for qemu-devel@nongnu.org; Thu, 03 Jul 2008 10:23:52 +0000 Received: from ths by cvs.savannah.gnu.org with local (Exim 4.63) (envelope-from ) id 1KELyh-0006yc-U2 for qemu-devel@nongnu.org; Thu, 03 Jul 2008 10:23:52 +0000 MIME-Version: 1.0 Errors-To: ths Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: Thiemo Seufer Message-Id: Date: Thu, 03 Jul 2008 10:23:51 +0000 Subject: [Qemu-devel] [4834] Merge NBD client/server, by Laurent Vivier. Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Revision: 4834 http://svn.sv.gnu.org/viewvc/?view=rev&root=qemu&revision=4834 Author: ths Date: 2008-07-03 10:23:51 +0000 (Thu, 03 Jul 2008) Log Message: ----------- Merge NBD client/server, by Laurent Vivier. Modified Paths: -------------- trunk/nbd.c trunk/nbd.h trunk/qemu-nbd.c trunk/qemu-nbd.texi Modified: trunk/nbd.c =================================================================== --- trunk/nbd.c 2008-07-03 10:01:15 UTC (rev 4833) +++ trunk/nbd.c 2008-07-03 10:23:51 UTC (rev 4834) @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -183,6 +184,65 @@ 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 @@ 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 @@ } 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 @@ 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 @@ 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) { Modified: trunk/nbd.h =================================================================== --- trunk/nbd.h 2008-07-03 10:01:15 UTC (rev 4833) +++ trunk/nbd.h 2008-07-03 10:23:51 UTC (rev 4834) @@ -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); Modified: trunk/qemu-nbd.c =================================================================== --- trunk/qemu-nbd.c 2008-07-03 10:01:15 UTC (rev 4833) +++ trunk/qemu-nbd.c 2008-07-03 10:23:51 UTC (rev 4834) @@ -1,4 +1,4 @@ -/*\ +/* * Copyright (C) 2005 Anthony Liguori * * Network Block Device @@ -25,11 +25,15 @@ #include #include #include +#include #include #include #include #include +#include +#define SOCKET_PATH "/var/lock/qemu-nbd-%s" + int verbose; static void usage(const char *name) @@ -41,14 +45,18 @@ " -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 \n" - , name); + , name, "DEVICE"); } static void version(const char *name) @@ -144,27 +152,51 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 out; + sleep(1); /* wait children */ + } + } while (sock == -1); + + fd = open(device, O_RDWR); + if (fd == -1) { + ret = 1; + goto out; + } + + ret = nbd_receive_negotiate(sock, &size, &blocksize); + if (ret == -1) { + ret = 1; + goto out; + } + + ret = nbd_init(fd, sock, size, blocksize); + if (ret == -1) { + ret = 1; + goto out; + } + + 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); + out: + 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 @@ close(csock); close(sock); bdrv_close(bs); + if (socket) + unlink(socket); return 0; } Modified: trunk/qemu-nbd.texi =================================================================== --- trunk/qemu-nbd.texi 2008-07-03 10:01:15 UTC (rev 4833) +++ trunk/qemu-nbd.texi 2008-07-03 10:23:51 UTC (rev 4834) @@ -20,10 +20,16 @@ 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