aboutsummaryrefslogtreecommitdiff
path: root/nbd.c
diff options
context:
space:
mode:
authorLaurent Vivier <laurent@vivier.eu>2010-08-25 22:48:33 +0200
committerKevin Wolf <kwolf@redhat.com>2010-08-30 18:29:22 +0200
commit1d45f8b542f6b80b24c44533ef0dd9e1a3b17ea5 (patch)
treea94959416cdcfc3d9317d31e1026533563a59c79 /nbd.c
parent2aa326be0d2039f51192707bdb2fc935d0e87c21 (diff)
nbd: Introduce NBD named exports.
This patch allows to connect Qemu using NBD protocol to an nbd-server using named exports. For instance, if on the host "isoserver", in /etc/nbd-server/config, you have: [generic] [debian-500-ppc-netinst] exportname = /ISO/debian-500-powerpc-netinst.iso [Fedora-10-ppc-netinst] exportname = /ISO/Fedora-10-ppc-netinst.iso You can connect to it, using: qemu -cdrom nbd:isoserver:exportname=debian-500-ppc-netinst qemu -cdrom nbd:isoserver:exportname=Fedora-10-ppc-netinst NOTE: you need at least nbd-server 2.9.18 Signed-off-by: Laurent Vivier <laurent@vivier.eu> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Diffstat (limited to 'nbd.c')
-rw-r--r--nbd.c118
1 files changed, 106 insertions, 12 deletions
diff --git a/nbd.c b/nbd.c
index a9f295f2bb..30dec8d2c5 100644
--- a/nbd.c
+++ b/nbd.c
@@ -62,6 +62,8 @@
#define NBD_SET_SIZE_BLOCKS _IO(0xab, 7)
#define NBD_DISCONNECT _IO(0xab, 8)
+#define NBD_OPT_EXPORT_NAME (1 << 0)
+
/* That's all folks */
#define read_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, true)
@@ -296,22 +298,27 @@ int nbd_negotiate(int csock, off_t size)
return 0;
}
-int nbd_receive_negotiate(int csock, off_t *size, size_t *blocksize)
+int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
+ off_t *size, size_t *blocksize)
{
- char buf[8 + 8 + 8 + 128];
- uint64_t magic;
+ char buf[256];
+ uint64_t magic, s;
+ uint16_t tmp;
TRACE("Receiving negotation.");
- if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+ if (read_sync(csock, buf, 8) != 8) {
LOG("read failed");
errno = EINVAL;
return -1;
}
- magic = be64_to_cpup((uint64_t*)(buf + 8));
- *size = be64_to_cpup((uint64_t*)(buf + 16));
- *blocksize = 1024;
+ buf[8] = '\0';
+ if (strlen(buf) == 0) {
+ LOG("server connection closed");
+ errno = EINVAL;
+ return -1;
+ }
TRACE("Magic is %c%c%c%c%c%c%c%c",
qemu_isprint(buf[0]) ? buf[0] : '.',
@@ -322,8 +329,6 @@ int nbd_receive_negotiate(int csock, off_t *size, size_t *blocksize)
qemu_isprint(buf[5]) ? buf[5] : '.',
qemu_isprint(buf[6]) ? buf[6] : '.',
qemu_isprint(buf[7]) ? buf[7] : '.');
- TRACE("Magic is 0x%" PRIx64, magic);
- TRACE("Size is %" PRIu64, *size);
if (memcmp(buf, "NBDMAGIC", 8) != 0) {
LOG("Invalid magic received");
@@ -331,10 +336,99 @@ int nbd_receive_negotiate(int csock, off_t *size, size_t *blocksize)
return -1;
}
- TRACE("Checking magic");
+ if (read_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
+ LOG("read failed");
+ errno = EINVAL;
+ return -1;
+ }
+ magic = be64_to_cpu(magic);
+ TRACE("Magic is 0x%" PRIx64, magic);
+
+ if (name) {
+ uint32_t reserved = 0;
+ uint32_t opt;
+ uint32_t namesize;
+
+ TRACE("Checking magic (opts_magic)");
+ if (magic != 0x49484156454F5054LL) {
+ LOG("Bad magic received");
+ errno = EINVAL;
+ return -1;
+ }
+ if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
+ LOG("flags read failed");
+ errno = EINVAL;
+ return -1;
+ }
+ *flags = be16_to_cpu(tmp) << 16;
+ /* reserved for future use */
+ if (write_sync(csock, &reserved, sizeof(reserved)) !=
+ sizeof(reserved)) {
+ LOG("write failed (reserved)");
+ errno = EINVAL;
+ return -1;
+ }
+ /* write the export name */
+ magic = cpu_to_be64(magic);
+ if (write_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
+ LOG("write failed (magic)");
+ errno = EINVAL;
+ return -1;
+ }
+ opt = cpu_to_be32(NBD_OPT_EXPORT_NAME);
+ if (write_sync(csock, &opt, sizeof(opt)) != sizeof(opt)) {
+ LOG("write failed (opt)");
+ errno = EINVAL;
+ return -1;
+ }
+ namesize = cpu_to_be32(strlen(name));
+ if (write_sync(csock, &namesize, sizeof(namesize)) !=
+ sizeof(namesize)) {
+ LOG("write failed (namesize)");
+ errno = EINVAL;
+ return -1;
+ }
+ if (write_sync(csock, (char*)name, strlen(name)) != strlen(name)) {
+ LOG("write failed (name)");
+ errno = EINVAL;
+ return -1;
+ }
+ } else {
+ TRACE("Checking magic (cli_magic)");
+
+ if (magic != 0x00420281861253LL) {
+ LOG("Bad magic received");
+ errno = EINVAL;
+ return -1;
+ }
+ }
+
+ if (read_sync(csock, &s, sizeof(s)) != sizeof(s)) {
+ LOG("read failed");
+ errno = EINVAL;
+ return -1;
+ }
+ *size = be64_to_cpu(s);
+ *blocksize = 1024;
+ TRACE("Size is %" PRIu64, *size);
- if (magic != 0x00420281861253LL) {
- LOG("Bad magic received");
+ if (!name) {
+ if (read_sync(csock, flags, sizeof(*flags)) != sizeof(*flags)) {
+ LOG("read failed (flags)");
+ errno = EINVAL;
+ return -1;
+ }
+ *flags = be32_to_cpup(flags);
+ } else {
+ if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
+ LOG("read failed (tmp)");
+ errno = EINVAL;
+ return -1;
+ }
+ *flags |= be32_to_cpu(tmp);
+ }
+ if (read_sync(csock, &buf, 124) != 124) {
+ LOG("read failed (buf)");
errno = EINVAL;
return -1;
}