From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1KcdMQ-0004Wt-M2 for qemu-devel@nongnu.org; Mon, 08 Sep 2008 05:48:42 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1KcdMP-0004VN-7F for qemu-devel@nongnu.org; Mon, 08 Sep 2008 05:48:41 -0400 Received: from [199.232.76.173] (port=58643 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1KcdMO-0004Uv-SM for qemu-devel@nongnu.org; Mon, 08 Sep 2008 05:48:40 -0400 Received: from ecfrec.frec.bull.fr ([129.183.4.8]:44024) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1KcdMO-0006Tc-CE for qemu-devel@nongnu.org; Mon, 08 Sep 2008 05:48:40 -0400 Received: from localhost (localhost [127.0.0.1]) by ecfrec.frec.bull.fr (Postfix) with ESMTP id 766911A1020 for ; Mon, 8 Sep 2008 11:48:34 +0200 (CEST) Received: from ecfrec.frec.bull.fr ([127.0.0.1]) by localhost (ecfrec.frec.bull.fr [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 02888-04 for ; Mon, 8 Sep 2008 11:48:30 +0200 (CEST) Received: from cyclope.frec.bull.fr (cyclope.frec.bull.fr [129.183.4.9]) by ecfrec.frec.bull.fr (Postfix) with ESMTP id 1CEFD1A102C for ; Mon, 8 Sep 2008 11:47:27 +0200 (CEST) Received: from [129.183.101.63] (frecb007144.frec.bull.fr [129.183.101.63]) by cyclope.frec.bull.fr (Postfix) with ESMTP id 0A1712728D for ; Mon, 8 Sep 2008 11:47:25 +0200 (CEST) From: Laurent Vivier Content-Type: multipart/mixed; boundary="=-+7Y4aQ+25hbm841oWrzs" Date: Mon, 08 Sep 2008 11:47:31 +0200 Message-Id: <1220867251.4147.30.camel@frecb07144> Mime-Version: 1.0 Subject: [Qemu-devel] [PATCH][RFC] qemu-nbd:multiple files server 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" --=-+7Y4aQ+25hbm841oWrzs Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable This patch allows the NBD client to select the file to use. It modifies the NBD protocol to allow the client to provide a filename if the NBD server reports a disk size of 0. Example: # add in /etc/services nbd 1024/tcp # add in /etc/inetd.conf nbd stream tcp nowait root /usr/local/bin/qemu-nbd /usr/local/bin/qemu-n= bd --nocache --read-only --port 0 --directory /ISO In /ISO, there are: debian-31r0a-amd64-netinst.iso openSUSE-10.3-GM-x86_64-mini.iso debian-40r0-i386-netinst.iso ubuntu-6.06-desktop-amd64.iso debian-40r0-i386-xfce-CD-1.iso ubuntu-7.10-desktop-amd64.iso debian-40r1-amd64-netinst.iso ubuntu-8.04-desktop-i386.iso debian-40r1-powerpc-netinst.iso winxp_64.iso Then I can start qemu with: x86_64-softmmu/qemu-system-x86_64 -net nic -net tap -hda new_disk.qcow2 -= cdrom nbd:my_nbd_server:1024:ubuntu-6.06-desktop-amd64.iso -boot d or x86_64-softmmu/qemu-system-x86_64 -net nic -net tap -hda new_disk.qcow2 -= cdrom nbd:my_nbd_server:1024:winxp_64.iso -boot d My goal is to be able to provide an install CD server, without configuring BOOTD/DHCP/TFTP server. Signed-off-by: Laurent Vivier --=20 ----------------- Laurent.Vivier@bull.net ------------------ "La perfection est atteinte non quand il ne reste rien =C3=A0 ajouter mais quand il ne reste rien =C3=A0 enlever." Saint Exup=C3=A9ry --=-+7Y4aQ+25hbm841oWrzs Content-Disposition: attachment; filename=nbd-directory.patch Content-Type: text/x-vhdl; name=nbd-directory.patch; charset=UTF-8 Content-Transfer-Encoding: 7bit --- block-nbd.c | 16 ++++++++++++++ nbd.c | 47 +++++++++++++++++++++++++++++++++++++++++ nbd.h | 2 + qemu-nbd.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 124 insertions(+), 9 deletions(-) Index: qemu/nbd.c =================================================================== --- qemu.orig/nbd.c 2008-09-08 09:43:45.000000000 +0200 +++ qemu/nbd.c 2008-09-08 09:53:05.000000000 +0200 @@ -337,6 +337,53 @@ int nbd_receive_negotiate(int csock, off return 0; } +int nbd_filename(int csock, const char *filename) +{ + uint8_t len; + + if (!filename || strlen(filename) > 254) { + errno = EINVAL; + return -1; + } + + len = strlen(filename) + 1; + if (write_sync(csock, &len, sizeof(uint8_t)) != + sizeof(uint8_t)) { + LOG("read failed"); + errno = EINVAL; + return -1; + } + if (len && write_sync(csock, (char*)filename, len) != len) { + LOG("read failed"); + errno = EINVAL; + return -1; + } + return 0; +} + +int nbd_receive_filename(int csock, char *filename) +{ + uint8_t len; + filename[0] = '\0'; + if (read_sync(csock, &len, sizeof(uint8_t)) != sizeof(uint8_t)) { + LOG("read failed"); + errno = EINVAL; + return -1; + } + if (len == 0) { + LOG("read failed"); + errno = EINVAL; + return -1; + } + if (read_sync(csock, filename, len) != len) { + LOG("read failed"); + errno = EINVAL; + return -1; + } + filename[len] = 0; + return 0; +} + int nbd_init(int fd, int csock, off_t size, size_t blocksize) { TRACE("Setting block size to %lu", (unsigned long)blocksize); Index: qemu/nbd.h =================================================================== --- qemu.orig/nbd.h 2008-09-08 09:43:45.000000000 +0200 +++ qemu/nbd.h 2008-09-08 09:53:05.000000000 +0200 @@ -52,6 +52,8 @@ int unix_socket_incoming(const char *pat int nbd_negotiate(int csock, off_t size); int nbd_receive_negotiate(int csock, off_t *size, size_t *blocksize); +int nbd_filename(int csock, const char *filename); +int nbd_receive_filename(int csock, char *filename); 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); Index: qemu/block-nbd.c =================================================================== --- qemu.orig/block-nbd.c 2008-09-08 09:31:04.000000000 +0200 +++ qemu/block-nbd.c 2008-09-08 09:53:05.000000000 +0200 @@ -47,6 +47,7 @@ static int nbd_open(BlockDriverState *bs off_t size; size_t blocksize; int ret; + const char *name = NULL; if ((flags & BDRV_O_CREAT)) return -EINVAL; @@ -79,6 +80,10 @@ static int nbd_open(BlockDriverState *bs if (r == p) return -EINVAL; sock = tcp_socket_outgoing(hostname, port); + if (*r == ':') { + r++; + name = r; + } } if (sock == -1) @@ -88,6 +93,17 @@ static int nbd_open(BlockDriverState *bs if (ret == -1) return -errno; + if (size == 0) { + if (name == NULL) + return -EINVAL; + ret = nbd_filename(sock, name); + if (ret == -1) + return -errno; + ret = nbd_receive_negotiate(sock, &size, &blocksize); + if (ret == -1) + return -errno; + } + s->sock = sock; s->size = size; s->blocksize = blocksize; Index: qemu/qemu-nbd.c =================================================================== --- qemu.orig/qemu-nbd.c 2008-09-08 09:49:06.000000000 +0200 +++ qemu/qemu-nbd.c 2008-09-08 10:23:37.000000000 +0200 @@ -158,6 +158,42 @@ static int find_partition(BlockDriverSta return -1; } +static int negotiate_filename(int csock, BlockDriverState *bs, int flags, + const char *directory, off_t *fd_size) +{ + char filename[255]; + char path[PATH_MAX]; + const char *name; + int ret; + + ret = nbd_negotiate(csock, *fd_size); + if (ret == -1) + return -1; + + if (*fd_size) + return 0; + + if (directory == NULL) + return -1; + + if (nbd_receive_filename(csock, filename) == -1) + return -1; + + name = basename(filename); + if (strlen(directory) + strlen(name) + 1 > PATH_MAX) + return -1; + + sprintf(path, "%s/%s", directory, name); + if (bdrv_open(bs, path, flags) == -1) + return -1; + + *fd_size = bs->total_sectors * 512; + + ret = nbd_negotiate(csock, *fd_size); + + return ret; +} + static void show_parts(const char *device) { if (fork() == 0) { @@ -189,8 +225,9 @@ int main(int argc, char **argv) off_t fd_size; char *device = NULL; char *socket = NULL; + char *directory = NULL; char sockpath[128]; - const char *sopt = "hVbo:p:rsnP:c:dvk:e:t"; + const char *sopt = "hVbo:p:rsnP:c:dvk:e:ti:"; struct option lopt[] = { { "help", 0, 0, 'h' }, { "version", 0, 0, 'V' }, @@ -207,6 +244,7 @@ int main(int argc, char **argv) { "shared", 1, 0, 'e' }, { "persistent", 0, 0, 't' }, { "verbose", 0, 0, 'v' }, + { "directory", 1, 0, 'i' }, { NULL, 0, 0, 0 } }; int ch; @@ -300,13 +338,16 @@ int main(int argc, char **argv) usage(argv[0]); exit(0); break; + case 'i': + directory = optarg; + break; case '?': errx(EINVAL, "Try `%s --help' for more information.", argv[0]); } } - if ((argc - optind) != 1) { + if (directory == NULL && (argc - optind) != 1) { errx(EINVAL, "Invalid number of argument.\n" "Try `%s --help' for more information.", argv[0]); @@ -330,20 +371,28 @@ int main(int argc, char **argv) errx(EINVAL, "You cannot set port to 0 and use shared"); } + if (directory && port) { + errx(EINVAL, "--directory can only be used with --port=0"); + } + bdrv_init(); bs = bdrv_new("hda"); if (bs == NULL) return 1; - if (bdrv_open(bs, argv[optind], flags) == -1) - return 1; + if (directory) { + fd_size = 0; + } else { + if (bdrv_open(bs, argv[optind], flags) == -1) + return 1; - fd_size = bs->total_sectors * 512; + fd_size = bs->total_sectors * 512; - if (partition != -1 && - find_partition(bs, partition, &dev_offset, &fd_size)) - errx(errno, "Could not find partition %d", partition); + if (partition != -1 && + find_partition(bs, partition, &dev_offset, &fd_size)) + errx(errno, "Could not find partition %d", partition); + } if (device) { pid_t pid; @@ -425,7 +474,8 @@ int main(int argc, char **argv) } else { if (port == 0) { /* read and write on stdin/stdout */ - ret = nbd_negotiate(STDIN_FILENO, fd_size); + ret = negotiate_filename(STDIN_FILENO, bs, flags, directory, + &fd_size); while (ret != -1) { ret = nbd_trip(bs, STDIN_FILENO, fd_size, dev_offset, &offset, readonly, data, NBD_BUFFER_SIZE); --=-+7Y4aQ+25hbm841oWrzs--