Mailing List Archive

[xen-unstable] blktap2: The tap-ctl userspace control utility and library.
# HG changeset patch
# User Keir Fraser <keir.fraser@citrix.com>
# Date 1275980709 -3600
# Node ID 63d0f5348af242e6046e1e30d22841ba20f8e6d6
# Parent 54675b91b3c17093efd347bd88ea57fce7240f30
blktap2: The tap-ctl userspace control utility and library.

Tapdisk control in userspace, a replacement for the original blktap2
control stack, which had to pass a kernel space interface based on
sysfs nodes.

All tapdisk processes listen for commands on a unix stream socket. The
control library supports scanning the socket namespace for running
tapdisks, VBD minors allocated, associated images and state inquiry.

Control operations include allocating/releasing devices, spawning
tapdisks, opening/closing images, attaching disk images to
devices. disk pause/resume operations and runtime switching of disk
images.

Signed-off-by: Jake Wires <jake.wires@citrix.com>
Signed-off-by: Daniel Stodden <daniel.stodden@citrix.com>
---
tools/blktap2/drivers/blktap2.h | 66 --
tools/blktap2/Makefile | 1
tools/blktap2/control/Makefile | 57 ++
tools/blktap2/control/tap-ctl-allocate.c | 242 ++++++++
tools/blktap2/control/tap-ctl-attach.c | 61 ++
tools/blktap2/control/tap-ctl-check.c | 79 ++
tools/blktap2/control/tap-ctl-close.c | 87 +++
tools/blktap2/control/tap-ctl-create.c | 65 ++
tools/blktap2/control/tap-ctl-destroy.c | 56 ++
tools/blktap2/control/tap-ctl-detach.c | 61 ++
tools/blktap2/control/tap-ctl-free.c | 54 ++
tools/blktap2/control/tap-ctl-ipc.c | 237 ++++++++
tools/blktap2/control/tap-ctl-list.c | 506 ++++++++++++++++++
tools/blktap2/control/tap-ctl-major.c | 69 ++
tools/blktap2/control/tap-ctl-open.c | 75 ++
tools/blktap2/control/tap-ctl-pause.c | 59 ++
tools/blktap2/control/tap-ctl-spawn.c | 174 ++++++
tools/blktap2/control/tap-ctl-unpause.c | 64 ++
tools/blktap2/control/tap-ctl.c | 815 ++++++++++++++++++++++++++++++
tools/blktap2/control/tap-ctl.h | 101 +++
tools/blktap2/drivers/Makefile | 4
tools/blktap2/drivers/tapdisk-control.c | 836 +++++++++++++++++++++++++++++++
tools/blktap2/drivers/tapdisk-control.h | 35 +
tools/blktap2/drivers/tapdisk-server.c | 83 ++-
tools/blktap2/drivers/tapdisk-server.h | 5
tools/blktap2/drivers/tapdisk-vbd.c | 105 ++-
tools/blktap2/drivers/tapdisk-vbd.h | 10
tools/blktap2/drivers/tapdisk2.c | 441 ++--------------
tools/blktap2/include/blktap2.h | 67 ++
tools/blktap2/include/tapdisk-message.h | 64 ++
30 files changed, 4071 insertions(+), 508 deletions(-)

diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/Makefile
--- a/tools/blktap2/Makefile Tue Jun 08 08:04:36 2010 +0100
+++ b/tools/blktap2/Makefile Tue Jun 08 08:05:09 2010 +0100
@@ -9,6 +9,7 @@ SUBDIRS-y += lvm
SUBDIRS-y += lvm
SUBDIRS-y += vhd
SUBDIRS-y += drivers
+SUBDIRS-y += control

clean:
rm -rf *.a *.so *.o *.rpm $(LIB) *~ $(DEPS) TAGS
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/Makefile Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,57 @@
+XEN_ROOT := ../../../
+include $(XEN_ROOT)/tools/Rules.mk
+
+IBIN = tap-ctl
+INST_DIR = /usr/sbin
+
+CFLAGS += -Werror
+CFLAGS += -Wno-unused
+CFLAGS += -I../include -I../drivers
+CFLAGS += -I$(XEN_INCLUDE) -I$(XEN_LIBXC)
+CFLAGS += -D_GNU_SOURCE
+CFLAGS += -DTAPCTL
+
+# Get gcc to generate the dependencies for us.
+CFLAGS += -Wp,-MD,.$(@F).d
+DEPS = .*.d
+
+CTL_OBJS := tap-ctl-ipc.o
+CTL_OBJS += tap-ctl-list.o
+CTL_OBJS += tap-ctl-allocate.o
+CTL_OBJS += tap-ctl-free.o
+CTL_OBJS += tap-ctl-create.o
+CTL_OBJS += tap-ctl-destroy.o
+CTL_OBJS += tap-ctl-spawn.o
+CTL_OBJS += tap-ctl-attach.o
+CTL_OBJS += tap-ctl-detach.o
+CTL_OBJS += tap-ctl-open.o
+CTL_OBJS += tap-ctl-close.o
+CTL_OBJS += tap-ctl-pause.o
+CTL_OBJS += tap-ctl-unpause.o
+CTL_OBJS += tap-ctl-major.o
+CTL_OBJS += tap-ctl-check.o
+
+OBJS = $(CTL_OBJS)
+LIBS = libblktapctl.a
+
+all: build
+
+build: $(IBIN)
+
+tap-ctl: tap-ctl.o libblktapctl.a
+ $(CC) $(CFLAGS) -o $@ $^
+
+libblktapctl.a: $(CTL_OBJS)
+ ar r $@ $^
+
+install: all
+ $(INSTALL_DIR) -p $(DESTDIR)$(INST_DIR)
+ $(INSTALL_PROG) $(IBIN) $(DESTDIR)$(INST_DIR)
+
+clean:
+ rm -f $(OBJS) $(DEPS) $(IBIN) $(LIBS)
+ rm -f *~
+
+.PHONY: all build clean install
+
+-include $(DEPS)
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-allocate.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-allocate.c Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+#include <libgen.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <linux/major.h>
+
+#include "tap-ctl.h"
+#include "blktap2.h"
+
+static int
+tap_ctl_prepare_directory(const char *dir)
+{
+ int err;
+ char *ptr, *name, *start;
+
+ err = access(dir, W_OK | R_OK);
+ if (!err)
+ return 0;
+
+ name = strdup(dir);
+ if (!name)
+ return ENOMEM;
+
+ start = name;
+
+ for (;;) {
+ ptr = strchr(start + 1, '/');
+ if (ptr)
+ *ptr = '\0';
+
+ err = mkdir(name, 0755);
+ if (err && errno != EEXIST) {
+ PERROR("mkdir %s", name);
+ err = errno;
+ break;
+ }
+
+ if (!ptr)
+ break;
+ else {
+ *ptr = '/';
+ start = ptr + 1;
+ }
+ }
+
+ free(name);
+ return err;
+}
+
+static int
+tap_ctl_make_device(const char *devname, const int major,
+ const int minor, const int perm)
+{
+ int err;
+ char *copy, *dir;
+
+ copy = strdup(devname);
+ if (!copy)
+ return ENOMEM;
+
+ dir = dirname(copy);
+
+ err = tap_ctl_prepare_directory(dir);
+ free(copy);
+
+ if (err)
+ return err;
+
+ if (!access(devname, F_OK))
+ if (unlink(devname)) {
+ PERROR("unlink %s", devname);
+ return errno;
+ }
+
+ err = mknod(devname, perm, makedev(major, minor));
+ if (err) {
+ PERROR("mknod %s", devname);
+ return errno;
+ }
+
+ return 0;
+}
+
+static int
+tap_ctl_check_environment(void)
+{
+ FILE *f;
+ int err, minor;
+ char name[256];
+
+ err = tap_ctl_prepare_directory(BLKTAP2_CONTROL_DIR);
+ if (err)
+ return err;
+
+ if (!access(BLKTAP2_CONTROL_DEVICE, R_OK | W_OK))
+ return 0;
+
+ memset(name, 0, sizeof(name));
+
+ f = fopen("/proc/misc", "r");
+ if (!f) {
+ EPRINTF("failed to open /proc/misc: %d\n", errno);
+ return errno;
+ }
+
+ while (fscanf(f, "%d %256s", &minor, name) == 2)
+ if (!strcmp(name, BLKTAP2_CONTROL_NAME)) {
+ err = tap_ctl_make_device(BLKTAP2_CONTROL_DEVICE,
+ MISC_MAJOR,
+ minor, S_IFCHR | 0600);
+ goto out;
+ }
+
+ err = ENOSYS;
+ EPRINTF("didn't find %s in /proc/misc\n", BLKTAP2_CONTROL_NAME);
+
+out:
+ fclose(f);
+ return err;
+}
+
+static int
+tap_ctl_allocate_device(int *minor, char **devname)
+{
+ char *name;
+ int fd, err;
+ struct blktap2_handle handle;
+
+ *minor = -1;
+ if (!devname)
+ return EINVAL;
+
+ fd = open(BLKTAP2_CONTROL_DEVICE, O_RDONLY);
+ if (fd == -1) {
+ EPRINTF("failed to open control device: %d\n", errno);
+ return errno;
+ }
+
+ err = ioctl(fd, BLKTAP2_IOCTL_ALLOC_TAP, &handle);
+ close(fd);
+ if (err == -1) {
+ EPRINTF("failed to allocate new device: %d\n", errno);
+ return errno;
+ }
+
+ err = asprintf(&name, "%s%d", BLKTAP2_RING_DEVICE, handle.minor);
+ if (err == -1) {
+ err = ENOMEM;
+ goto fail;
+ }
+
+ err = tap_ctl_make_device(name, handle.ring,
+ handle.minor, S_IFCHR | 0600);
+ free(name);
+ if (err) {
+ EPRINTF("creating ring device for %d failed: %d\n",
+ handle.minor, err);
+ goto fail;
+ }
+
+ if (*devname)
+ name = *devname;
+ else {
+ err = asprintf(&name, "%s%d",
+ BLKTAP2_IO_DEVICE, handle.minor);
+ if (err == -1) {
+ err = ENOMEM;
+ goto fail;
+ }
+ *devname = name;
+ }
+
+ err = tap_ctl_make_device(name, handle.device,
+ handle.minor, S_IFBLK | 0600);
+ if (err) {
+ EPRINTF("creating IO device for %d failed: %d\n",
+ handle.minor, err);
+ goto fail;
+ }
+
+ DBG("new interface: ring: %u, device: %u, minor: %u\n",
+ handle.ring, handle.device, handle.minor);
+
+ *minor = handle.minor;
+ return 0;
+
+fail:
+ tap_ctl_free(handle.minor);
+ return err;
+}
+
+int
+tap_ctl_allocate(int *minor, char **devname)
+{
+ int err;
+
+ *minor = -1;
+
+ err = tap_ctl_check_environment();
+ if (err)
+ return err;
+
+ err = tap_ctl_allocate_device(minor, devname);
+ if (err)
+ return err;
+
+ return 0;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-attach.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-attach.c Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+
+#include "tap-ctl.h"
+
+int
+tap_ctl_attach(const int id, const int minor)
+{
+ int err;
+ tapdisk_message_t message;
+
+ memset(&message, 0, sizeof(message));
+ message.type = TAPDISK_MESSAGE_ATTACH;
+ message.cookie = minor;
+
+ err = tap_ctl_connect_send_and_receive(id, &message, 5);
+ if (err)
+ return err;
+
+ if (message.type == TAPDISK_MESSAGE_ATTACH_RSP) {
+ err = message.u.response.error;
+ if (err)
+ EPRINTF("attach failed: %d\n", err);
+ } else {
+ EPRINTF("got unexpected result '%s' from %d\n",
+ tapdisk_message_name(message.type), id);
+ err = EINVAL;
+ }
+
+ return err;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-check.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-check.c Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "tap-ctl.h"
+#include "blktap2.h"
+
+int
+tap_ctl_check_blktap(const char **msg)
+{
+ FILE *f;
+ int err = 0, minor;
+ char name[32];
+
+ memset(name, 0, sizeof(name));
+
+ f = fopen("/proc/misc", "r");
+ if (!f) {
+ *msg = "failed to open /proc/misc";
+ return -errno;
+ }
+
+ while (fscanf(f, "%d %32s", &minor, name) == 2) {
+ if (!strcmp(name, BLKTAP2_CONTROL_NAME))
+ goto out;
+ }
+
+ err = -ENOSYS;
+ *msg = "blktap kernel module not installed";
+
+out:
+ fclose(f);
+ return err;
+}
+
+int
+tap_ctl_check(const char **msg)
+{
+ int err;
+ uid_t uid;
+
+ err = tap_ctl_check_blktap(msg);
+ if (err)
+ goto out;
+
+ err = 0;
+ *msg = "ok";
+
+out:
+ return err;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-close.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-close.c Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+
+#include "tap-ctl.h"
+
+static int
+__tap_ctl_close(const int id, const int minor, const int force)
+{
+ int err;
+ tapdisk_message_t message;
+
+ memset(&message, 0, sizeof(message));
+ message.type = TAPDISK_MESSAGE_CLOSE;
+ if (force)
+ message.type = TAPDISK_MESSAGE_FORCE_SHUTDOWN;
+ message.cookie = minor;
+
+ err = tap_ctl_connect_send_and_receive(id, &message, 5);
+ if (err)
+ return err;
+
+ if (message.type == TAPDISK_MESSAGE_CLOSE_RSP) {
+ err = message.u.response.error;
+ if (err)
+ EPRINTF("close failed: %d\n", err);
+ } else {
+ EPRINTF("got unexpected result '%s' from %d\n",
+ tapdisk_message_name(message.type), id);
+ err = EINVAL;
+ }
+
+ return err;
+}
+
+int
+tap_ctl_close(const int id, const int minor, const int force)
+{
+ int i, err;
+
+ for (i = 0; i < 20; i++) {
+ err = __tap_ctl_close(id, minor, force);
+ if (!err)
+ return 0;
+
+ err = (err < 0 ? -err : err);
+ if (err != EAGAIN) {
+ EPRINTF("close failed: %d\n", err);
+ return err;
+ }
+
+ usleep(1000);
+ }
+
+ EPRINTF("close timed out\n");
+ return EIO;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-create.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-create.c Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include "tap-ctl.h"
+#include "blktap2.h"
+
+int
+tap_ctl_create(const char *params, char **devname)
+{
+ int err, id, minor;
+
+ err = tap_ctl_allocate(&minor, devname);
+ if (err)
+ return err;
+
+ id = tap_ctl_spawn();
+ if (id < 0)
+ goto destroy;
+
+ err = tap_ctl_attach(id, minor);
+ if (err)
+ goto destroy;
+
+ err = tap_ctl_open(id, minor, params);
+ if (err)
+ goto detach;
+
+ return 0;
+
+detach:
+ tap_ctl_detach(id, minor);
+destroy:
+ tap_ctl_free(minor);
+ return err;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-destroy.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-destroy.c Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include "tap-ctl.h"
+#include "blktap2.h"
+
+int
+tap_ctl_destroy(const int id, const int minor)
+{
+ int err;
+
+ err = tap_ctl_close(id, minor, 0);
+ if (err)
+ return err;
+
+ err = tap_ctl_detach(id, minor);
+ if (err)
+ return err;
+
+ err = tap_ctl_free(minor);
+ if (err)
+ return err;
+
+ return 0;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-detach.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-detach.c Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+
+#include "tap-ctl.h"
+
+int
+tap_ctl_detach(const int id, const int minor)
+{
+ int err;
+ tapdisk_message_t message;
+
+ memset(&message, 0, sizeof(message));
+ message.type = TAPDISK_MESSAGE_DETACH;
+ message.cookie = minor;
+
+ err = tap_ctl_connect_send_and_receive(id, &message, 5);
+ if (err)
+ return err;
+
+ if (message.type == TAPDISK_MESSAGE_DETACH_RSP) {
+ err = message.u.response.error;
+ if (err < 0)
+ printf("detach failed: %d\n", err);
+ } else {
+ printf("got unexpected result '%s' from %d\n",
+ tapdisk_message_name(message.type), id);
+ err = EINVAL;
+ }
+
+ return err;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-free.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-free.c Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+
+#include "tap-ctl.h"
+#include "blktap2.h"
+
+int
+tap_ctl_free(const int minor)
+{
+ int fd, err;
+
+ fd = open(BLKTAP2_CONTROL_DEVICE, O_RDONLY);
+ if (fd == -1) {
+ EPRINTF("failed to open control device: %d\n", errno);
+ return errno;
+ }
+
+ err = ioctl(fd, BLKTAP2_IOCTL_FREE_TAP, minor);
+ close(fd);
+
+ return err;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-ipc.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-ipc.c Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "tap-ctl.h"
+#include "blktap2.h"
+
+int tap_ctl_debug = 0;
+
+int
+tap_ctl_read_message(int fd, tapdisk_message_t *message, int timeout)
+{
+ fd_set readfds;
+ int ret, len, offset;
+ struct timeval tv, *t;
+
+ t = NULL;
+ offset = 0;
+ len = sizeof(tapdisk_message_t);
+
+ if (timeout) {
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+ t = &tv;
+ }
+
+ memset(message, 0, sizeof(tapdisk_message_t));
+
+ while (offset < len) {
+ FD_ZERO(&readfds);
+ FD_SET(fd, &readfds);
+
+ ret = select(fd + 1, &readfds, NULL, NULL, t);
+ if (ret == -1)
+ break;
+ else if (FD_ISSET(fd, &readfds)) {
+ ret = read(fd, message + offset, len - offset);
+ if (ret <= 0)
+ break;
+ offset += ret;
+ } else
+ break;
+ }
+
+ if (offset != len) {
+ EPRINTF("failure reading message\n");
+ return -EIO;
+ }
+
+ DBG("received '%s' message (uuid = %u)\n",
+ tapdisk_message_name(message->type), message->cookie);
+
+ return 0;
+}
+
+int
+tap_ctl_write_message(int fd, tapdisk_message_t *message, int timeout)
+{
+ fd_set writefds;
+ int ret, len, offset;
+ struct timeval tv, *t;
+
+ t = NULL;
+ offset = 0;
+ len = sizeof(tapdisk_message_t);
+
+ if (timeout) {
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+ t = &tv;
+ }
+
+ DBG("sending '%s' message (uuid = %u)\n",
+ tapdisk_message_name(message->type), message->cookie);
+
+ while (offset < len) {
+ FD_ZERO(&writefds);
+ FD_SET(fd, &writefds);
+
+ /* we don't bother reinitializing tv. at worst, it will wait a
+ * bit more time than expected. */
+
+ ret = select(fd + 1, NULL, &writefds, NULL, t);
+ if (ret == -1)
+ break;
+ else if (FD_ISSET(fd, &writefds)) {
+ ret = write(fd, message + offset, len - offset);
+ if (ret <= 0)
+ break;
+ offset += ret;
+ } else
+ break;
+ }
+
+ if (offset != len) {
+ EPRINTF("failure writing message\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int
+tap_ctl_send_and_receive(int sfd, tapdisk_message_t *message, int timeout)
+{
+ int err;
+
+ err = tap_ctl_write_message(sfd, message, timeout);
+ if (err) {
+ EPRINTF("failed to send '%s' message\n",
+ tapdisk_message_name(message->type));
+ return err;
+ }
+
+ err = tap_ctl_read_message(sfd, message, timeout);
+ if (err) {
+ EPRINTF("failed to receive '%s' message\n",
+ tapdisk_message_name(message->type));
+ return err;
+ }
+
+ return 0;
+}
+
+char *
+tap_ctl_socket_name(int id)
+{
+ char *name;
+
+ if (asprintf(&name, "%s/%s%d",
+ BLKTAP2_CONTROL_DIR, BLKTAP2_CONTROL_SOCKET, id) == -1)
+ return NULL;
+
+ return name;
+}
+
+int
+tap_ctl_connect(const char *name, int *sfd)
+{
+ int fd, err;
+ struct sockaddr_un saddr;
+
+ *sfd = -1;
+
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd == -1) {
+ EPRINTF("couldn't create socket for %s: %d\n", name, errno);
+ return -errno;
+ }
+
+ memset(&saddr, 0, sizeof(saddr));
+ saddr.sun_family = AF_UNIX;
+ strcpy(saddr.sun_path, name);
+
+ err = connect(fd, (const struct sockaddr *)&saddr, sizeof(saddr));
+ if (err) {
+ EPRINTF("couldn't connect to %s: %d\n", name, errno);
+ close(fd);
+ return -errno;
+ }
+
+ *sfd = fd;
+ return 0;
+}
+
+int
+tap_ctl_connect_id(int id, int *sfd)
+{
+ int err;
+ char *name;
+
+ *sfd = -1;
+
+ if (id < 0) {
+ EPRINTF("invalid id %d\n", id);
+ return -EINVAL;
+ }
+
+ name = tap_ctl_socket_name(id);
+ if (!name) {
+ EPRINTF("couldn't name socket for %d\n", id);
+ return -ENOMEM;
+ }
+
+ err = tap_ctl_connect(name, sfd);
+ free(name);
+
+ return err;
+}
+
+int
+tap_ctl_connect_send_and_receive(int id, tapdisk_message_t *message, int timeout)
+{
+ int err, sfd;
+
+ err = tap_ctl_connect_id(id, &sfd);
+ if (err)
+ return err;
+
+ err = tap_ctl_send_and_receive(sfd, message, timeout);
+
+ close(sfd);
+ return err;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-list.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-list.c Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,506 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <glob.h>
+
+#include "tap-ctl.h"
+#include "blktap2.h"
+#include "list.h"
+
+static void
+free_list(tap_list_t *entry)
+{
+ if (entry->type) {
+ free(entry->type);
+ entry->type = NULL;
+ }
+
+ if (entry->path) {
+ free(entry->path);
+ entry->path = NULL;
+ }
+
+ free(entry);
+}
+
+int
+_parse_params(const char *params, char **type, char **path)
+{
+ char *ptr;
+ size_t len;
+
+ ptr = strchr(params, ':');
+ if (!ptr)
+ return -EINVAL;
+
+ len = ptr - params;
+
+ *type = strndup(params, len);
+ *path = strdup(params + len + 1);
+
+ if (!*type || !*path) {
+ free(*type);
+ *type = NULL;
+
+ free(*path);
+ *path = NULL;
+
+ return -errno;
+ }
+
+ return 0;
+}
+
+static int
+init_list(tap_list_t *entry,
+ int tap_id, pid_t tap_pid, int vbd_minor, int vbd_state,
+ const char *params)
+{
+ int err = 0;
+
+ entry->id = tap_id;
+ entry->pid = tap_pid;
+ entry->minor = vbd_minor;
+ entry->state = vbd_state;
+
+ if (params)
+ err = _parse_params(params, &entry->type, &entry->path);
+
+ return err;
+}
+
+void
+tap_ctl_free_list(tap_list_t **list)
+{
+ tap_list_t **_entry;
+
+ for (_entry = list; *_entry != NULL; ++_entry)
+ free_list(*_entry);
+
+ free(list);
+}
+
+static tap_list_t**
+tap_ctl_alloc_list(int n)
+{
+ tap_list_t **list, *entry;
+ size_t size;
+ int i;
+
+ size = sizeof(tap_list_t*) * (n+1);
+ list = malloc(size);
+ if (!list)
+ goto fail;
+
+ memset(list, 0, size);
+
+ for (i = 0; i < n; ++i) {
+ tap_list_t *entry;
+
+ entry = malloc(sizeof(tap_list_t));
+ if (!entry)
+ goto fail;
+
+ memset(entry, 0, sizeof(tap_list_t));
+
+ list[i] = entry;
+ }
+
+ return list;
+
+fail:
+ if (list)
+ tap_ctl_free_list(list);
+
+ return NULL;
+}
+
+static int
+tap_ctl_list_length(const tap_list_t **list)
+{
+ const tap_list_t **_entry;
+ int n;
+
+ n = 0;
+ for (_entry = list; *_entry != NULL; ++_entry)
+ n++;
+
+ return n;
+}
+
+static int
+_tap_minor_cmp(const void *a, const void *b)
+{
+ return *(int*)a - *(int*)b;
+}
+
+int
+_tap_ctl_find_minors(int **_minorv)
+{
+ glob_t glbuf = { 0 };
+ const char *pattern, *format;
+ int *minorv = NULL, n_minors = 0;
+ int err, i;
+
+ pattern = BLKTAP2_SYSFS_DIR"/blktap*";
+ format = BLKTAP2_SYSFS_DIR"/blktap%d";
+
+ n_minors = 0;
+ minorv = NULL;
+
+ err = glob(pattern, 0, NULL, &glbuf);
+ switch (err) {
+ case GLOB_NOMATCH:
+ goto done;
+
+ case GLOB_ABORTED:
+ case GLOB_NOSPACE:
+ err = -errno;
+ EPRINTF("%s: glob failed, err %d", pattern, err);
+ goto fail;
+ }
+
+ minorv = malloc(sizeof(int) * glbuf.gl_pathc);
+ if (!minorv) {
+ err = -errno;
+ goto fail;
+ }
+
+ for (i = 0; i < glbuf.gl_pathc; ++i) {
+ int n;
+
+ n = sscanf(glbuf.gl_pathv[i], format, &minorv[n_minors]);
+ if (n != 1)
+ continue;
+
+ n_minors++;
+ }
+
+ qsort(minorv, n_minors, sizeof(int), _tap_minor_cmp);
+
+done:
+ *_minorv = minorv;
+ err = 0;
+
+out:
+ if (glbuf.gl_pathv)
+ globfree(&glbuf);
+
+ return err ? : n_minors;
+
+fail:
+ if (minorv)
+ free(minorv);
+
+ goto out;
+}
+
+struct tapdisk {
+ int id;
+ pid_t pid;
+ struct list_head list;
+};
+
+static int
+_tap_tapdisk_cmp(const void *a, const void *b)
+{
+ return ((struct tapdisk*)a)->id - ((struct tapdisk*)b)->id;
+}
+
+int
+_tap_ctl_find_tapdisks(struct tapdisk **_tapv)
+{
+ glob_t glbuf = { 0 };
+ const char *pattern, *format;
+ struct tapdisk *tapv = NULL;
+ int err, i, n_taps = 0;
+
+ pattern = BLKTAP2_CONTROL_DIR"/"BLKTAP2_CONTROL_SOCKET"*";
+ format = BLKTAP2_CONTROL_DIR"/"BLKTAP2_CONTROL_SOCKET"%d";
+
+ n_taps = 0;
+ tapv = NULL;
+
+ err = glob(pattern, 0, NULL, &glbuf);
+ switch (err) {
+ case GLOB_NOMATCH:
+ goto done;
+
+ case GLOB_ABORTED:
+ case GLOB_NOSPACE:
+ err = -errno;
+ EPRINTF("%s: glob failed, err %d", pattern, err);
+ goto fail;
+ }
+
+ tapv = malloc(sizeof(struct tapdisk) * glbuf.gl_pathc);
+ if (!tapv) {
+ err = -errno;
+ goto fail;
+ }
+
+ for (i = 0; i < glbuf.gl_pathc; ++i) {
+ struct tapdisk *tap;
+ int n;
+
+ tap = &tapv[n_taps];
+
+ err = sscanf(glbuf.gl_pathv[i], format, &tap->id);
+ if (err != 1)
+ continue;
+
+ tap->pid = tap_ctl_get_pid(tap->id);
+ if (tap->pid < 0)
+ continue;
+
+ n_taps++;
+ }
+
+ qsort(tapv, n_taps, sizeof(struct tapdisk), _tap_tapdisk_cmp);
+
+ for (i = 0; i < n_taps; ++i)
+ INIT_LIST_HEAD(&tapv[i].list);
+
+done:
+ *_tapv = tapv;
+ err = 0;
+
+out:
+ if (glbuf.gl_pathv)
+ globfree(&glbuf);
+
+ return err ? : n_taps;
+
+fail:
+ if (tapv)
+ free(tapv);
+
+ goto out;
+}
+
+struct tapdisk_list {
+ int minor;
+ int state;
+ char *params;
+ struct list_head entry;
+};
+
+int
+_tap_ctl_list_tapdisk(int id, struct list_head *_list)
+{
+ tapdisk_message_t message;
+ struct list_head list;
+ struct tapdisk_list *tl, *next;
+ int err, sfd;
+
+ err = tap_ctl_connect_id(id, &sfd);
+ if (err)
+ return err;
+
+ memset(&message, 0, sizeof(message));
+ message.type = TAPDISK_MESSAGE_LIST;
+ message.cookie = -1;
+
+ err = tap_ctl_write_message(sfd, &message, 2);
+ if (err)
+ return err;
+
+ INIT_LIST_HEAD(&list);
+ do {
+ err = tap_ctl_read_message(sfd, &message, 2);
+ if (err) {
+ err = -EPROTO;
+ break;
+ }
+
+ if (message.u.list.count == 0)
+ break;
+
+ tl = malloc(sizeof(struct tapdisk_list));
+ if (!tl) {
+ err = -ENOMEM;
+ break;
+ }
+
+ tl->minor = message.u.list.minor;
+ tl->state = message.u.list.state;
+ if (message.u.list.path[0] != 0) {
+ tl->params = strndup(message.u.list.path,
+ sizeof(message.u.list.path));
+ if (!tl->params) {
+ err = -errno;
+ break;
+ }
+ } else
+ tl->params = NULL;
+
+ list_add(&tl->entry, &list);
+ } while (1);
+
+ if (err)
+ list_for_each_entry_safe(tl, next, &list, entry) {
+ list_del(&tl->entry);
+ free(tl->params);
+ free(tl);
+ }
+
+ close(sfd);
+ list_splice(&list, _list);
+ return err;
+}
+
+void
+_tap_ctl_free_tapdisks(struct tapdisk *tapv, int n_taps)
+{
+ struct tapdisk *tap;
+
+ for (tap = tapv; tap < &tapv[n_taps]; ++tap) {
+ struct tapdisk_list *tl;
+
+ list_for_each_entry(tl, &tap->list, entry) {
+ free(tl->params);
+ free(tl);
+ }
+ }
+
+ free(tapv);
+}
+
+int
+_tap_list_join3(int n_minors, int *minorv, int n_taps, struct tapdisk *tapv,
+ tap_list_t ***_list)
+{
+ tap_list_t **list, **_entry, *entry;
+ int i, _m, err;
+
+ list = tap_ctl_alloc_list(n_minors + n_taps);
+ if (!list) {
+ err = -ENOMEM;
+ goto fail;
+ }
+
+ _entry = list;
+
+ for (i = 0; i < n_taps; ++i) {
+ struct tapdisk *tap = &tapv[i];
+ struct tapdisk_list *tl;
+
+ /* orphaned tapdisk */
+ if (list_empty(&tap->list)) {
+ err = init_list(*_entry++, tap->id, tap->pid, -1, -1, NULL);
+ if (err)
+ goto fail;
+ continue;
+ }
+
+ list_for_each_entry(tl, &tap->list, entry) {
+
+ err = init_list(*_entry++,
+ tap->id, tap->pid,
+ tl->minor, tl->state, tl->params);
+ if (err)
+ goto fail;
+
+ if (tl->minor >= 0) {
+ /* clear minor */
+ for (_m = 0; _m < n_minors; ++_m) {
+ if (minorv[_m] == tl->minor) {
+ minorv[_m] = -1;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* orphaned minors */
+ for (_m = 0; _m < n_minors; ++_m) {
+ int minor = minorv[_m];
+ if (minor >= 0) {
+ err = init_list(*_entry++, -1, -1, minor, -1, NULL);
+ if (err)
+ goto fail;
+ }
+ }
+
+ /* free extraneous list entries */
+ for (; *_entry != NULL; ++entry) {
+ free_list(*_entry);
+ *_entry = NULL;
+ }
+
+ *_list = list;
+
+ return 0;
+
+fail:
+ if (list)
+ tap_ctl_free_list(list);
+
+ return err;
+}
+
+int
+tap_ctl_list(tap_list_t ***list)
+{
+ int n_taps, n_minors, err, *minorv;
+ struct tapdisk *tapv, *tap;
+
+ n_taps = -1;
+ n_minors = -1;
+
+ err = n_minors = _tap_ctl_find_minors(&minorv);
+ if (err < 0)
+ goto out;
+
+ err = n_taps = _tap_ctl_find_tapdisks(&tapv);
+ if (err < 0)
+ goto out;
+
+ for (tap = tapv; tap < &tapv[n_taps]; ++tap) {
+ err = _tap_ctl_list_tapdisk(tap->id, &tap->list);
+ if (err)
+ goto out;
+ }
+
+ err = _tap_list_join3(n_minors, minorv, n_taps, tapv, list);
+
+out:
+ if (n_taps > 0)
+ _tap_ctl_free_tapdisks(tapv, n_taps);
+
+ if (n_minors > 0)
+ free(minorv);
+
+ return err;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-major.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-major.c Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+
+#include "tap-ctl.h"
+
+int
+tap_ctl_blk_major(void)
+{
+ FILE *devices;
+ int rv, major;
+
+ devices = fopen("/proc/devices", "r");
+ if (!devices) {
+ rv = -errno;
+ goto out;
+ }
+
+ do {
+ char buf[32], *s;
+ int n, offset;
+
+ s = fgets(buf, sizeof(buf), devices);
+ if (!s)
+ break;
+
+ major = -ENODEV;
+ offset = 0;
+
+ n = sscanf(buf, "%d tapdev%n", &major, &offset);
+ if (n == 1 && offset)
+ break;
+ } while (1);
+
+ rv = major;
+
+out:
+ if (devices)
+ fclose(devices);
+
+ return rv;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-open.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-open.c Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+
+#include "tap-ctl.h"
+#include "blktaplib.h"
+
+int
+tap_ctl_open(const int id, const int minor, const char *params)
+{
+ int err;
+ tapdisk_message_t message;
+
+ memset(&message, 0, sizeof(message));
+ message.type = TAPDISK_MESSAGE_OPEN;
+ message.cookie = minor;
+ message.u.params.storage = TAPDISK_STORAGE_TYPE_DEFAULT;
+ message.u.params.devnum = minor;
+
+ err = snprintf(message.u.params.path,
+ sizeof(message.u.params.path) - 1, "%s", params);
+ if (err >= sizeof(message.u.params.path)) {
+ EPRINTF("name too long\n");
+ return ENAMETOOLONG;
+ }
+
+ err = tap_ctl_connect_send_and_receive(id, &message, 5);
+ if (err)
+ return err;
+
+ switch (message.type) {
+ case TAPDISK_MESSAGE_OPEN_RSP:
+ break;
+ case TAPDISK_MESSAGE_ERROR:
+ err = -message.u.response.error;
+ EPRINTF("open failed, err %d\n", err);
+ break;
+ default:
+ EPRINTF("got unexpected result '%s' from %d\n",
+ tapdisk_message_name(message.type), id);
+ err = EINVAL;
+ }
+
+ return err;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-pause.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-pause.c Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "tap-ctl.h"
+
+int
+tap_ctl_pause(const int id, const int minor)
+{
+ int err;
+ tapdisk_message_t message;
+
+ memset(&message, 0, sizeof(message));
+ message.type = TAPDISK_MESSAGE_PAUSE;
+ message.cookie = minor;
+
+ err = tap_ctl_connect_send_and_receive(id, &message, 5);
+ if (err)
+ return err;
+
+ if (message.type == TAPDISK_MESSAGE_PAUSE_RSP)
+ err = message.u.response.error;
+ else {
+ err = EINVAL;
+ EPRINTF("got unexpected result '%s' from %d\n",
+ tapdisk_message_name(message.type), id);
+ }
+
+ return err;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-spawn.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-spawn.c Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/wait.h>
+
+#include "tap-ctl.h"
+#include "blktap2.h"
+
+static pid_t
+__tap_ctl_spawn(int *readfd)
+{
+ int err, child, channel[2];
+ char *tapdisk;
+
+ if (pipe(channel)) {
+ EPRINTF("pipe failed: %d\n", errno);
+ return -errno;
+ }
+
+ if ((child = fork()) == -1) {
+ EPRINTF("fork failed: %d\n", errno);
+ return -errno;
+ }
+
+ if (child) {
+ close(channel[1]);
+ *readfd = channel[0];
+ return child;
+ }
+
+ if (dup2(channel[1], STDOUT_FILENO) == -1) {
+ EPRINTF("dup2 failed: %d\n", errno);
+ exit(errno);
+ }
+
+ if (dup2(channel[1], STDERR_FILENO) == -1) {
+ EPRINTF("dup2 failed: %d\n", errno);
+ exit(errno);
+ }
+
+ close(channel[0]);
+ close(channel[1]);
+
+ tapdisk = getenv("TAPDISK2");
+ if (!tapdisk)
+ tapdisk = "tapdisk2";
+
+ execlp(tapdisk, tapdisk, NULL);
+
+ EPRINTF("exec failed\n");
+ exit(1);
+}
+
+pid_t
+tap_ctl_get_pid(const int id)
+{
+ int err;
+ tapdisk_message_t message;
+
+ memset(&message, 0, sizeof(message));
+ message.type = TAPDISK_MESSAGE_PID;
+
+ err = tap_ctl_connect_send_and_receive(id, &message, 2);
+ if (err)
+ return err;
+
+ return message.u.tapdisk_pid;
+}
+
+static int
+tap_ctl_wait(pid_t child)
+{
+ pid_t pid;
+ int status;
+
+ pid = waitpid(child, &status, 0);
+ if (pid < 0) {
+ EPRINTF("wait(%d) failed, err %d\n", child, errno);
+ return -errno;
+ }
+
+ if (WIFEXITED(status)) {
+ int code = WEXITSTATUS(status);
+ if (code)
+ EPRINTF("tapdisk2[%d] failed, status %d\n", child, code);
+ return -code;
+ }
+
+ if (WIFSIGNALED(status)) {
+ int signo = WTERMSIG(status);
+ EPRINTF("tapdisk2[%d] killed by signal %d\n", child, signo);
+ return -EINTR;
+ }
+
+ EPRINTF("tapdisk2[%d]: unexpected status %#x\n", child, status);
+ return -EAGAIN;
+}
+
+static int
+tap_ctl_get_child_id(int readfd)
+{
+ int id;
+ FILE *f;
+
+ f = fdopen(readfd, "r");
+ if (!f) {
+ EPRINTF("fdopen failed: %d\n", errno);
+ return -1;
+ }
+
+ errno = 0;
+ if (fscanf(f, BLKTAP2_CONTROL_DIR"/"
+ BLKTAP2_CONTROL_SOCKET"%d", &id) != 1) {
+ errno = (errno ? : EINVAL);
+ EPRINTF("parsing id failed: %d\n", errno);
+ id = -1;
+ }
+
+ fclose(f);
+ return id;
+}
+
+int
+tap_ctl_spawn(void)
+{
+ pid_t child;
+ int err, id, readfd;
+
+ readfd = -1;
+
+ child = __tap_ctl_spawn(&readfd);
+ if (child < 0)
+ return child;
+
+ err = tap_ctl_wait(child);
+ if (err)
+ return err;
+
+ id = tap_ctl_get_child_id(readfd);
+ if (id < 0)
+ EPRINTF("get_id failed, child %d err %d\n", child, errno);
+
+ return id;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-unpause.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-unpause.c Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+
+#include "tap-ctl.h"
+
+int
+tap_ctl_unpause(const int id, const int minor, const char *params)
+{
+ int err;
+ tapdisk_message_t message;
+
+ memset(&message, 0, sizeof(message));
+ message.type = TAPDISK_MESSAGE_RESUME;
+ message.cookie = minor;
+
+ if (params)
+ strncpy(message.u.params.path, params,
+ sizeof(message.u.params.path) - 1);
+
+ err = tap_ctl_connect_send_and_receive(id, &message, 15);
+ if (err)
+ return err;
+
+ if (message.type == TAPDISK_MESSAGE_RESUME_RSP)
+ err = message.u.response.error;
+ else {
+ err = EINVAL;
+ EPRINTF("got unexpected result '%s' from %d\n",
+ tapdisk_message_name(message.type), id);
+ }
+
+ return err;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl.c Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,815 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include "tap-ctl.h"
+
+typedef int (*tap_ctl_func_t) (int, char **);
+
+struct command {
+ char *name;
+ tap_ctl_func_t func;
+};
+
+static void
+tap_cli_list_usage(FILE *stream)
+{
+ fprintf(stream,
+ "usage: list [-h] [-p pid] [-m minor] [-t type] [-f file]\n");
+}
+
+static void
+tap_ctl_list_row(tap_list_t *entry)
+{
+ char minor_str[10] = "-";
+ char state_str[10] = "-";
+ char pid_str[10] = "-";
+
+ if (entry->pid != -1)
+ sprintf(pid_str, "%d", entry->pid);
+
+ if (entry->minor != -1)
+ sprintf(minor_str, "%d", entry->minor);
+
+ if (entry->state != -1)
+ sprintf(state_str, "%x", entry->state);
+
+ printf("%8s %2s %4s %10s %s\n",
+ pid_str, minor_str, state_str,
+ entry->type ? : "-", entry->path ? : "-");
+}
+
+static void
+tap_ctl_list_dict(tap_list_t *entry)
+{
+ int d = 0;
+
+ if (entry->pid != -1) {
+ if (d) putc(' ', stdout);
+ d = printf("pid=%d", entry->pid);
+ }
+
+ if (entry->minor != -1) {
+ if (d) putc(' ', stdout);
+ d = printf("minor=%d", entry->minor);
+ }
+
+ if (entry->state != -1) {
+ if (d) putc(' ', stdout);
+ d = printf("state=%d", entry->state);
+ }
+
+ if (entry->type && entry->path) {
+ if (d) putc(' ', stdout);
+ d = printf("args=%s:%s", entry->type, entry->path);
+ }
+
+ putc('\n', stdout);
+}
+
+int
+tap_cli_list(int argc, char **argv)
+{
+ tap_list_t **list, **_entry;
+ int c, minor, tty, err;
+ const char *type, *file;
+ pid_t pid;
+
+ err = tap_ctl_list(&list);
+ if (err)
+ return -err;
+
+ pid = -1;
+ minor = -1;
+ type = NULL;
+ file = NULL;
+
+ while ((c = getopt(argc, argv, "m:p:t:f:h")) != -1) {
+ switch (c) {
+ case 'm':
+ minor = atoi(optarg);
+ break;
+ case 'p':
+ pid = atoi(optarg);
+ break;
+ case 't':
+ type = optarg;
+ break;
+ case 'f':
+ file = optarg;
+ break;
+ case '?':
+ goto usage;
+ case 'h':
+ tap_cli_list_usage(stdout);
+ return 0;
+ }
+ }
+
+ tty = isatty(STDOUT_FILENO);
+
+ for (_entry = list; *_entry != NULL; ++_entry) {
+ tap_list_t *entry = *_entry;
+
+ if (minor >= 0 && entry->minor != minor)
+ continue;
+
+ if (pid >= 0 && entry->pid != pid)
+ continue;
+
+ if (type && entry->type && strcmp(entry->type, type))
+ continue;
+
+ if (file && entry->path && strcmp(entry->path, file))
+ continue;
+
+ if (tty)
+ tap_ctl_list_row(entry);
+ else
+ tap_ctl_list_dict(entry);
+ }
+
+ tap_ctl_free_list(list);
+
+ return 0;
+
+usage:
+ tap_cli_list_usage(stderr);
+ return EINVAL;
+}
+
+static void
+tap_cli_allocate_usage(FILE *stream)
+{
+ fprintf(stream, "usage: allocate [-d device name]>\n");
+}
+
+static int
+tap_cli_allocate(int argc, char **argv)
+{
+ char *devname;
+ int c, minor, err;
+
+ devname = NULL;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "d:h")) != -1) {
+ switch (c) {
+ case 'd':
+ devname = optarg;
+ break;
+ case '?':
+ goto usage;
+ case 'h':
+ tap_cli_allocate_usage(stdout);
+ return 0;
+ }
+ }
+
+ err = tap_ctl_allocate(&minor, &devname);
+ if (!err)
+ printf("%s\n", devname);
+
+ return err;
+
+usage:
+ tap_cli_allocate_usage(stderr);
+ return EINVAL;
+}
+
+static void
+tap_cli_free_usage(FILE *stream)
+{
+ fprintf(stream, "usage: free <-m minor>\n");
+}
+
+static int
+tap_cli_free(int argc, char **argv)
+{
+ int c, minor;
+
+ minor = -1;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "m:h")) != -1) {
+ switch (c) {
+ case 'm':
+ minor = atoi(optarg);
+ break;
+ case '?':
+ goto usage;
+ case 'h':
+ tap_cli_free_usage(stdout);
+ return 0;
+ }
+ }
+
+ if (minor == -1)
+ goto usage;
+
+ return tap_ctl_free(minor);
+
+usage:
+ tap_cli_free_usage(stderr);
+ return EINVAL;
+}
+
+static void
+tap_cli_create_usage(FILE *stream)
+{
+ fprintf(stream, "usage: create <-a args> [-d device name]\n");
+}
+
+static int
+tap_cli_create(int argc, char **argv)
+{
+ int c, err;
+ char *args, *devname;
+
+ args = NULL;
+ devname = NULL;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "a:d:h")) != -1) {
+ switch (c) {
+ case 'a':
+ args = optarg;
+ break;
+ case 'd':
+ devname = optarg;
+ break;
+ case '?':
+ goto usage;
+ case 'h':
+ tap_cli_create_usage(stdout);
+ return 0;
+ }
+ }
+
+ if (!args)
+ goto usage;
+
+ err = tap_ctl_create(args, &devname);
+ if (!err)
+ printf("%s\n", devname);
+
+ return err;
+
+usage:
+ tap_cli_create_usage(stderr);
+ return EINVAL;
+}
+
+static void
+tap_cli_destroy_usage(FILE *stream)
+{
+ fprintf(stream, "usage: destroy <-p pid> <-m minor>\n");
+}
+
+static int
+tap_cli_destroy(int argc, char **argv)
+{
+ int c, pid, minor;
+
+ pid = -1;
+ minor = -1;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "p:m:h")) != -1) {
+ switch (c) {
+ case 'p':
+ pid = atoi(optarg);
+ break;
+ case 'm':
+ minor = atoi(optarg);
+ break;
+ case '?':
+ goto usage;
+ case 'h':
+ tap_cli_destroy_usage(stdout);
+ return 0;
+ }
+ }
+
+ if (pid == -1 || minor == -1)
+ goto usage;
+
+ return tap_ctl_destroy(pid, minor);
+
+usage:
+ tap_cli_destroy_usage(stderr);
+ return EINVAL;
+}
+
+static void
+tap_cli_spawn_usage(FILE *stream)
+{
+ fprintf(stream, "usage: spawn\n");
+}
+
+static int
+tap_cli_spawn(int argc, char **argv)
+{
+ int c;
+ pid_t task;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "h")) != -1) {
+ switch (c) {
+ case '?':
+ goto usage;
+ case 'h':
+ tap_cli_spawn_usage(stdout);
+ return 0;
+ }
+ }
+
+ task = tap_ctl_spawn();
+ if (task < 0) {
+ printf("spawn failed: %d\n", errno);
+ return task;
+ }
+
+ printf("tapdisk spawned with pid %d\n", task);
+ return 0;
+
+usage:
+ tap_cli_spawn_usage(stderr);
+ return EINVAL;
+}
+
+static void
+tap_cli_attach_usage(FILE *stream)
+{
+ fprintf(stream, "usage: attach <-p pid> <-m minor>\n");
+}
+
+static int
+tap_cli_attach(int argc, char **argv)
+{
+ int c, pid, minor;
+
+ pid = -1;
+ minor = -1;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "p:m:h")) != -1) {
+ switch (c) {
+ case 'p':
+ pid = atoi(optarg);
+ break;
+ case 'm':
+ minor = atoi(optarg);
+ break;
+ case '?':
+ goto usage;
+ case 'h':
+ tap_cli_attach_usage(stderr);
+ return 0;
+ }
+ }
+
+ if (pid == -1 || minor == -1)
+ goto usage;
+
+ return tap_ctl_attach(pid, minor);
+
+usage:
+ tap_cli_attach_usage(stderr);
+ return EINVAL;
+}
+
+static void
+tap_cli_detach_usage(FILE *stream)
+{
+ fprintf(stream, "usage: detach <-p pid> <-m minor>\n");
+}
+
+static int
+tap_cli_detach(int argc, char **argv)
+{
+ int c, pid, minor;
+
+ pid = -1;
+ minor = -1;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "p:m:h")) != -1) {
+ switch (c) {
+ case 'p':
+ pid = atoi(optarg);
+ break;
+ case 'm':
+ minor = atoi(optarg);
+ break;
+ case '?':
+ goto usage;
+ case 'h':
+ tap_cli_detach_usage(stdout);
+ return 0;
+ }
+ }
+
+ if (pid == -1 || minor == -1)
+ goto usage;
+
+ return tap_ctl_detach(pid, minor);
+
+usage:
+ tap_cli_detach_usage(stderr);
+ return EINVAL;
+}
+
+static void
+tap_cli_close_usage(FILE *stream)
+{
+ fprintf(stream, "usage: close <-p pid> <-m minor> [-f force]\n");
+}
+
+static int
+tap_cli_close(int argc, char **argv)
+{
+ int c, pid, minor, force;
+
+ pid = -1;
+ minor = -1;
+ force = 0;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "p:m:fh")) != -1) {
+ switch (c) {
+ case 'p':
+ pid = atoi(optarg);
+ break;
+ case 'm':
+ minor = atoi(optarg);
+ break;
+ case 'f':
+ force = -1;
+ break;
+ case '?':
+ goto usage;
+ case 'h':
+ tap_cli_close_usage(stdout);
+ return 0;
+ }
+ }
+
+ if (pid == -1 || minor == -1)
+ goto usage;
+
+ return tap_ctl_close(pid, minor, force);
+
+usage:
+ tap_cli_close_usage(stderr);
+ return EINVAL;
+}
+
+static void
+tap_cli_pause_usage(FILE *stream)
+{
+ fprintf(stream, "usage: pause <-p pid> <-m minor>\n");
+}
+
+static int
+tap_cli_pause(int argc, char **argv)
+{
+ int c, pid, minor;
+
+ pid = -1;
+ minor = -1;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "p:m:h")) != -1) {
+ switch (c) {
+ case 'p':
+ pid = atoi(optarg);
+ break;
+ case 'm':
+ minor = atoi(optarg);
+ break;
+ case '?':
+ goto usage;
+ case 'h':
+ tap_cli_pause_usage(stdout);
+ return 0;
+ }
+ }
+
+ if (pid == -1 || minor == -1)
+ goto usage;
+
+ return tap_ctl_pause(pid, minor);
+
+usage:
+ tap_cli_pause_usage(stderr);
+ return EINVAL;
+}
+
+static void
+tap_cli_unpause_usage(FILE *stream)
+{
+ fprintf(stream, "usage: unpause <-p pid> <-m minor> [-a args]\n");
+}
+
+int
+tap_cli_unpause(int argc, char **argv)
+{
+ const char *args;
+ int c, pid, minor;
+
+ pid = -1;
+ minor = -1;
+ args = NULL;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "p:m:a:h")) != -1) {
+ switch (c) {
+ case 'p':
+ pid = atoi(optarg);
+ break;
+ case 'm':
+ minor = atoi(optarg);
+ break;
+ case 'a':
+ args = optarg;
+ break;
+ case '?':
+ goto usage;
+ case 'h':
+ tap_cli_unpause_usage(stdout);
+ return 0;
+ }
+ }
+
+ if (pid == -1 || minor == -1)
+ goto usage;
+
+ return tap_ctl_unpause(pid, minor, args);
+
+usage:
+ tap_cli_unpause_usage(stderr);
+ return EINVAL;
+}
+
+static void
+tap_cli_major_usage(FILE *stream)
+{
+ fprintf(stream, "usage: major [-h]\n");
+}
+
+static int
+tap_cli_major(int argc, char **argv)
+{
+ int c, chr, major;
+
+ chr = 0;
+
+ while ((c = getopt(argc, argv, "bch")) != -1) {
+ switch (c) {
+ case 'b':
+ chr = 0;
+ break;
+ case 'c':
+ chr = 1;
+ break;
+ case '?':
+ goto usage;
+ case 'h':
+ tap_cli_major_usage(stdout);
+ return 0;
+ default:
+ goto usage;
+ }
+ }
+
+ if (chr)
+ major = -EINVAL;
+ else
+ major = tap_ctl_blk_major();
+
+ if (major < 0)
+ return -major;
+
+ printf("%d\n", major);
+
+ return 0;
+
+usage:
+ tap_cli_major_usage(stderr);
+ return EINVAL;
+}
+
+static void
+tap_cli_open_usage(FILE *stream)
+{
+ fprintf(stream, "usage: open <-p pid> <-m minor> <-a args>\n");
+}
+
+static int
+tap_cli_open(int argc, char **argv)
+{
+ const char *args;
+ int c, pid, minor;
+
+ pid = -1;
+ minor = -1;
+ args = NULL;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "a:m:p:h")) != -1) {
+ switch (c) {
+ case 'p':
+ pid = atoi(optarg);
+ break;
+ case 'm':
+ minor = atoi(optarg);
+ break;
+ case 'a':
+ args = optarg;
+ break;
+ case '?':
+ goto usage;
+ case 'h':
+ tap_cli_open_usage(stdout);
+ return 0;
+ }
+ }
+
+ if (pid == -1 || minor == -1 || !args)
+ goto usage;
+
+ return tap_ctl_open(pid, minor, args);
+
+usage:
+ tap_cli_open_usage(stderr);
+ return EINVAL;
+}
+
+static void
+tap_cli_check_usage(FILE *stream)
+{
+ fprintf(stream, "usage: check\n"
+ "(checks whether environment is suitable for tapdisk2)\n");
+}
+
+static int
+tap_cli_check(int argc, char **argv)
+{
+ int err;
+ const char *msg;
+
+ if (argc != 1)
+ goto usage;
+
+ err = tap_ctl_check(&msg);
+ printf("%s\n", msg);
+
+ return err;
+
+usage:
+ tap_cli_check_usage(stderr);
+ return EINVAL;
+}
+
+struct command commands[] = {
+ { .name = "list", .func = tap_cli_list },
+ { .name = "allocate", .func = tap_cli_allocate },
+ { .name = "free", .func = tap_cli_free },
+ { .name = "create", .func = tap_cli_create },
+ { .name = "destroy", .func = tap_cli_destroy },
+ { .name = "spawn", .func = tap_cli_spawn },
+ { .name = "attach", .func = tap_cli_attach },
+ { .name = "detach", .func = tap_cli_detach },
+ { .name = "open", .func = tap_cli_open },
+ { .name = "close", .func = tap_cli_close },
+ { .name = "pause", .func = tap_cli_pause },
+ { .name = "unpause", .func = tap_cli_unpause },
+ { .name = "major", .func = tap_cli_major },
+ { .name = "check", .func = tap_cli_check },
+};
+
+#define print_commands() \
+ do { \
+ int i, n; \
+ n = sizeof(commands) / sizeof(struct command); \
+ printf("COMMAND := { "); \
+ printf("%s", commands[0].name); \
+ for (i = 1; i < n; i++) \
+ printf(" | %s", commands[i].name); \
+ printf(" }\n"); \
+ } while (0)
+
+void
+help(void)
+{
+ printf("usage: tap-ctl COMMAND [OPTIONS]\n");
+ print_commands();
+ exit(0);
+}
+
+struct command *
+get_command(char *command)
+{
+ int i, n;
+
+ if (strnlen(command, 25) >= 25)
+ return NULL;
+
+ n = sizeof(commands) / sizeof (struct command);
+
+ for (i = 0; i < n; i++)
+ if (!strcmp(command, commands[i].name))
+ return &commands[i];
+
+ return NULL;
+}
+
+int
+main(int argc, char *argv[])
+{
+ char **cargv;
+ const char *msg;
+ struct command *cmd;
+ int cargc, i, cnt, ret;
+
+#ifdef CORE_DUMP
+ #include <sys/resource.h>
+ struct rlimit rlim;
+ rlim.rlim_cur = RLIM_INFINITY;
+ rlim.rlim_max = RLIM_INFINITY;
+ if (setrlimit(RLIMIT_CORE, &rlim) < 0)
+ PERROR("setrlimit failed");
+#endif
+
+ ret = 0;
+
+ if (argc < 2)
+ help();
+
+ cargc = argc - 1;
+ cmd = get_command(argv[1]);
+ if (!cmd) {
+ EPRINTF("invalid COMMAND %s", argv[1]);
+ help();
+ }
+
+ ret = tap_ctl_check(&msg);
+ if (ret) {
+ printf("%s\n", msg);
+ return ret;
+ }
+
+ cargv = malloc(sizeof(char *) * cargc);
+ if (!cargv)
+ exit(ENOMEM);
+
+ cnt = 1;
+ cargv[0] = cmd->name;
+ for (i = 1; i < cargc; i++) {
+ char *arg = argv[i + (argc - cargc)];
+
+ if (!strcmp(arg, "--debug")) {
+ tap_ctl_debug = 1;
+ continue;
+ }
+
+ cargv[cnt++] = arg;
+ }
+
+ ret = cmd->func(cnt, cargv);
+
+ free(cargv);
+
+ return (ret >= 0 ? ret : -ret);
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl.h Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __TAP_CTL_H__
+#define __TAP_CTL_H__
+
+#include <syslog.h>
+#include <errno.h>
+
+#include "tapdisk-message.h"
+
+extern int tap_ctl_debug;
+
+#ifdef TAPCTL
+#define DBG(_f, _a...) \
+ do { \
+ if (tap_ctl_debug) \
+ printf(_f, ##_a); \
+ } while (0)
+
+#define DPRINTF(_f, _a...) syslog(LOG_INFO, _f, ##_a)
+#define EPRINTF(_f, _a...) syslog(LOG_ERR, "tap-err:%s: " _f, __func__, ##_a)
+#define PERROR(_f, _a...) syslog(LOG_ERR, "tap-err:%s: " _f ": %s", __func__, ##_a, \
+ strerror(errno))
+#endif
+
+void tap_ctl_version(int *major, int *minor);
+int tap_ctl_kernel_version(int *major, int *minor);
+
+int tap_ctl_check_blktap(const char **message);
+int tap_ctl_check_version(const char **message);
+int tap_ctl_check(const char **message);
+
+int tap_ctl_connect(const char *path, int *socket);
+int tap_ctl_connect_id(int id, int *socket);
+int tap_ctl_read_message(int fd, tapdisk_message_t *message, int timeout);
+int tap_ctl_write_message(int fd, tapdisk_message_t *message, int timeout);
+int tap_ctl_send_and_receive(int fd, tapdisk_message_t *message, int timeout);
+int tap_ctl_connect_send_and_receive(int id,
+ tapdisk_message_t *message, int timeout);
+char *tap_ctl_socket_name(int id);
+
+typedef struct {
+ int id;
+ pid_t pid;
+ int minor;
+ int state;
+ char *type;
+ char *path;
+} tap_list_t;
+
+int tap_ctl_get_driver_id(const char *handle);
+
+int tap_ctl_list(tap_list_t ***list);
+void tap_ctl_free_list(tap_list_t **list);
+
+int tap_ctl_allocate(int *minor, char **devname);
+int tap_ctl_free(const int minor);
+
+int tap_ctl_create(const char *params, char **devname);
+int tap_ctl_destroy(const int id, const int minor);
+
+int tap_ctl_spawn(void);
+pid_t tap_ctl_get_pid(const int id);
+
+int tap_ctl_attach(const int id, const int minor);
+int tap_ctl_detach(const int id, const int minor);
+
+int tap_ctl_open(const int id, const int minor, const char *params);
+int tap_ctl_close(const int id, const int minor, const int force);
+
+int tap_ctl_pause(const int id, const int minor);
+int tap_ctl_unpause(const int id, const int minor, const char *params);
+
+int tap_ctl_blk_major(void);
+
+#endif
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/drivers/Makefile
--- a/tools/blktap2/drivers/Makefile Tue Jun 08 08:04:36 2010 +0100
+++ b/tools/blktap2/drivers/Makefile Tue Jun 08 08:05:09 2010 +0100
@@ -12,8 +12,7 @@ CFLAGS += -Werror -g -O0
CFLAGS += -Werror -g -O0
CFLAGS += -Wno-unused
CFLAGS += -fno-strict-aliasing
-CFLAGS += -I../lib -I../../libxc
-CFLAGS += -I../include -I../../include
+CFLAGS += -I$(BLKTAP_ROOT)/include -I$(BLKTAP_ROOT)/drivers
CFLAGS += $(CFLAGS_libxenctrl)
CFLAGS += -I $(LIBAIO_DIR)
CFLAGS += -I $(MEMSHR_DIR)
@@ -63,6 +62,7 @@ PORTABLE-OBJS-$(CONFIG_NetBSD) += blk_ne

TAP-OBJS-y := scheduler.o
TAP-OBJS-y += tapdisk-vbd.o
+TAP-OBJS-y += tapdisk-control.o
TAP-OBJS-y += tapdisk-image.o
TAP-OBJS-y += tapdisk-driver.o
TAP-OBJS-y += tapdisk-disktype.o
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/drivers/blktap2.h
--- a/tools/blktap2/drivers/blktap2.h Tue Jun 08 08:04:36 2010 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2008, XenSource Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of XenSource Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#ifndef _BLKTAP_2_H_
-#define _BLKTAP_2_H_
-
-#define MISC_MAJOR_NUMBER 10
-
-#define BLKTAP2_MAX_MESSAGE_LEN 256
-
-#define BLKTAP2_RING_MESSAGE_PAUSE 1
-#define BLKTAP2_RING_MESSAGE_RESUME 2
-#define BLKTAP2_RING_MESSAGE_CLOSE 3
-
-#define BLKTAP2_IOCTL_KICK_FE 1
-#define BLKTAP2_IOCTL_ALLOC_TAP 200
-#define BLKTAP2_IOCTL_FREE_TAP 201
-#define BLKTAP2_IOCTL_CREATE_DEVICE 202
-#define BLKTAP2_IOCTL_SET_PARAMS 203
-#define BLKTAP2_IOCTL_PAUSE 204
-#define BLKTAP2_IOCTL_REOPEN 205
-#define BLKTAP2_IOCTL_RESUME 206
-
-#define BLKTAP2_CONTROL_NAME "blktap-control"
-#define BLKTAP2_DIRECTORY "/dev/xen/blktap-2"
-#define BLKTAP2_CONTROL_DEVICE BLKTAP2_DIRECTORY"/control"
-#define BLKTAP2_RING_DEVICE BLKTAP2_DIRECTORY"/blktap"
-#define BLKTAP2_IO_DEVICE BLKTAP2_DIRECTORY"/tapdev"
-
-struct blktap2_handle {
- unsigned int ring;
- unsigned int device;
- unsigned int minor;
-};
-
-struct blktap2_params {
- char name[BLKTAP2_MAX_MESSAGE_LEN];
- unsigned long long capacity;
- unsigned long sector_size;
-};
-
-#endif
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/drivers/tapdisk-control.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/drivers/tapdisk-control.c Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,836 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include "list.h"
+#include "tapdisk.h"
+#include "blktap2.h"
+#include "blktaplib.h"
+#include "tapdisk-vbd.h"
+#include "tapdisk-utils.h"
+#include "tapdisk-server.h"
+#include "tapdisk-message.h"
+#include "tapdisk-disktype.h"
+
+struct tapdisk_control {
+ char *path;
+ int socket;
+ int event_id;
+};
+
+struct tapdisk_control_connection {
+ int socket;
+ event_id_t event_id;
+};
+
+static struct tapdisk_control td_control;
+
+static void
+tapdisk_control_initialize(void)
+{
+ td_control.socket = -1;
+ td_control.event_id = -1;
+
+ signal(SIGPIPE, SIG_IGN);
+}
+
+void
+tapdisk_control_close(void)
+{
+ if (td_control.path) {
+ unlink(td_control.path);
+ free(td_control.path);
+ td_control.path = NULL;
+ }
+
+ if (td_control.socket != -1) {
+ close(td_control.socket);
+ td_control.socket = -1;
+ }
+}
+
+static struct tapdisk_control_connection *
+tapdisk_control_allocate_connection(int fd)
+{
+ struct tapdisk_control_connection *connection;
+ size_t sz;
+
+ connection = calloc(1, sizeof(*connection));
+ if (!connection) {
+ EPRINTF("calloc");
+ return NULL;
+ }
+
+ connection->socket = fd;
+ return connection;
+}
+
+static void
+tapdisk_control_close_connection(struct tapdisk_control_connection *connection)
+{
+ tapdisk_server_unregister_event(connection->event_id);
+ close(connection->socket);
+ free(connection);
+}
+
+static int
+tapdisk_control_read_message(int fd, tapdisk_message_t *message, int timeout)
+{
+ fd_set readfds;
+ int ret, len, offset;
+ struct timeval tv, *t;
+
+ t = NULL;
+ offset = 0;
+ len = sizeof(tapdisk_message_t);
+
+ if (timeout) {
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+ t = &tv;
+ }
+
+ memset(message, 0, sizeof(tapdisk_message_t));
+
+ while (offset < len) {
+ FD_ZERO(&readfds);
+ FD_SET(fd, &readfds);
+
+ ret = select(fd + 1, &readfds, NULL, NULL, t);
+ if (ret == -1)
+ break;
+ else if (FD_ISSET(fd, &readfds)) {
+ ret = read(fd, message + offset, len - offset);
+ if (ret <= 0)
+ break;
+ offset += ret;
+ } else
+ break;
+ }
+
+ if (offset != len) {
+ EPRINTF("failure reading message (wanted %d but got %d)\n",
+ len, offset);
+ return -EIO;
+ }
+
+ DPRINTF("received '%s' message (uuid = %u)\n",
+ tapdisk_message_name(message->type), message->cookie);
+
+ return 0;
+}
+
+static int
+tapdisk_control_write_message(int fd, tapdisk_message_t *message, int timeout)
+{
+ fd_set writefds;
+ int ret, len, offset;
+ struct timeval tv, *t;
+
+ t = NULL;
+ offset = 0;
+ len = sizeof(tapdisk_message_t);
+
+ if (timeout) {
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+ t = &tv;
+ }
+
+ DPRINTF("sending '%s' message (uuid = %u)\n",
+ tapdisk_message_name(message->type), message->cookie);
+
+ while (offset < len) {
+ FD_ZERO(&writefds);
+ FD_SET(fd, &writefds);
+
+ /* we don't bother reinitializing tv. at worst, it will wait a
+ * bit more time than expected. */
+
+ ret = select(fd + 1, NULL, &writefds, NULL, t);
+ if (ret == -1)
+ break;
+ else if (FD_ISSET(fd, &writefds)) {
+ ret = write(fd, message + offset, len - offset);
+ if (ret <= 0)
+ break;
+ offset += ret;
+ } else
+ break;
+ }
+
+ if (offset != len) {
+ EPRINTF("failure writing message\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int
+tapdisk_control_validate_request(tapdisk_message_t *request)
+{
+ if (strnlen(request->u.params.path,
+ TAPDISK_MESSAGE_MAX_PATH_LENGTH) >=
+ TAPDISK_MESSAGE_MAX_PATH_LENGTH)
+ return EINVAL;
+
+ return 0;
+}
+
+static void
+tapdisk_control_list_minors(struct tapdisk_control_connection *connection,
+ tapdisk_message_t *request)
+{
+ int i;
+ td_vbd_t *vbd;
+ struct list_head *head;
+ tapdisk_message_t response;
+
+ i = 0;
+ memset(&response, 0, sizeof(response));
+
+ response.type = TAPDISK_MESSAGE_LIST_MINORS_RSP;
+ response.cookie = request->cookie;
+
+ head = tapdisk_server_get_all_vbds();
+
+ list_for_each_entry(vbd, head, next) {
+ response.u.minors.list[i++] = vbd->minor;
+ if (i >= TAPDISK_MESSAGE_MAX_MINORS) {
+ response.type = TAPDISK_MESSAGE_ERROR;
+ response.u.response.error = ERANGE;
+ break;
+ }
+ }
+
+ response.u.minors.count = i;
+ tapdisk_control_write_message(connection->socket, &response, 2);
+ tapdisk_control_close_connection(connection);
+}
+
+static void
+tapdisk_control_list(struct tapdisk_control_connection *connection,
+ tapdisk_message_t *request)
+{
+ td_vbd_t *vbd;
+ struct list_head *head;
+ tapdisk_message_t response;
+ int count, i;
+
+ memset(&response, 0, sizeof(response));
+ response.type = TAPDISK_MESSAGE_LIST_RSP;
+ response.cookie = request->cookie;
+
+ head = tapdisk_server_get_all_vbds();
+
+ count = 0;
+ list_for_each_entry(vbd, head, next)
+ count++;
+
+ list_for_each_entry(vbd, head, next) {
+ response.u.list.count = count--;
+ response.u.list.minor = vbd->minor;
+ response.u.list.state = vbd->state;
+ response.u.list.path[0] = 0;
+
+ if (!list_empty(&vbd->images)) {
+ td_image_t *image = list_entry(vbd->images.next,
+ td_image_t, next);
+ snprintf(response.u.list.path,
+ sizeof(response.u.list.path),
+ "%s:%s",
+ tapdisk_disk_types[image->type]->name,
+ image->name);
+ }
+
+ tapdisk_control_write_message(connection->socket, &response, 2);
+ }
+
+ response.u.list.count = count;
+ response.u.list.minor = -1;
+ response.u.list.path[0] = 0;
+
+ tapdisk_control_write_message(connection->socket, &response, 2);
+ tapdisk_control_close_connection(connection);
+}
+
+static void
+tapdisk_control_get_pid(struct tapdisk_control_connection *connection,
+ tapdisk_message_t *request)
+{
+ tapdisk_message_t response;
+
+ memset(&response, 0, sizeof(response));
+ response.type = TAPDISK_MESSAGE_PID_RSP;
+ response.cookie = request->cookie;
+ response.u.tapdisk_pid = getpid();
+
+ tapdisk_control_write_message(connection->socket, &response, 2);
+ tapdisk_control_close_connection(connection);
+}
+
+static void
+tapdisk_control_attach_vbd(struct tapdisk_control_connection *connection,
+ tapdisk_message_t *request)
+{
+ tapdisk_message_t response;
+ char *devname;
+ td_vbd_t *vbd;
+ struct blktap2_params params;
+ image_t image;
+ int minor, err;
+
+ /*
+ * TODO: check for max vbds per process
+ */
+
+ vbd = tapdisk_server_get_vbd(request->cookie);
+ if (vbd) {
+ err = -EEXIST;
+ goto out;
+ }
+
+ minor = request->cookie;
+ if (minor < 0) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ vbd = tapdisk_vbd_create(minor);
+ if (!vbd) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = asprintf(&devname, BLKTAP2_RING_DEVICE"%d", minor);
+ if (err == -1) {
+ err = -ENOMEM;
+ goto fail_vbd;
+ }
+
+ err = tapdisk_vbd_attach(vbd, devname, minor);
+ free(devname);
+ if (err)
+ goto fail_vbd;
+
+ tapdisk_server_add_vbd(vbd);
+
+out:
+ memset(&response, 0, sizeof(response));
+ response.type = TAPDISK_MESSAGE_ATTACH_RSP;
+ response.cookie = request->cookie;
+ response.u.response.error = -err;
+
+ tapdisk_control_write_message(connection->socket, &response, 2);
+ tapdisk_control_close_connection(connection);
+
+ return;
+
+fail_vbd:
+ tapdisk_vbd_detach(vbd);
+ free(vbd);
+ goto out;
+}
+
+
+static void
+tapdisk_control_detach_vbd(struct tapdisk_control_connection *connection,
+ tapdisk_message_t *request)
+{
+ tapdisk_message_t response;
+ td_vbd_t *vbd;
+ int err;
+
+ vbd = tapdisk_server_get_vbd(request->cookie);
+ if (!vbd) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ tapdisk_vbd_detach(vbd);
+
+ if (list_empty(&vbd->images)) {
+ tapdisk_server_remove_vbd(vbd);
+ free(vbd);
+ }
+
+ err = 0;
+out:
+ memset(&response, 0, sizeof(response));
+ response.type = TAPDISK_MESSAGE_DETACH_RSP;
+ response.cookie = request->cookie;
+ response.u.response.error = -err;
+
+ tapdisk_control_write_message(connection->socket, &response, 2);
+ tapdisk_control_close_connection(connection);
+}
+
+static void
+tapdisk_control_open_image(struct tapdisk_control_connection *connection,
+ tapdisk_message_t *request)
+{
+ int err;
+ image_t image;
+ td_vbd_t *vbd;
+ td_flag_t flags;
+ tapdisk_message_t response;
+ struct blktap2_params params;
+
+ vbd = tapdisk_server_get_vbd(request->cookie);
+ if (!vbd) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (vbd->minor == -1) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (vbd->name) {
+ err = -EALREADY;
+ goto out;
+ }
+
+ flags = 0;
+ if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_RDONLY)
+ flags |= TD_OPEN_RDONLY;
+ if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_SHARED)
+ flags |= TD_OPEN_SHAREABLE;
+ if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_ADD_CACHE)
+ flags |= TD_OPEN_ADD_CACHE;
+ if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_VHD_INDEX)
+ flags |= TD_OPEN_VHD_INDEX;
+ if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_LOG_DIRTY)
+ flags |= TD_OPEN_LOG_DIRTY;
+
+ vbd->name = strndup(request->u.params.path,
+ sizeof(request->u.params.path));
+ if (!vbd->name) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = tapdisk_vbd_parse_stack(vbd, request->u.params.path);
+ if (err)
+ goto out;
+
+ err = tapdisk_vbd_open_stack(vbd, request->u.params.storage, flags);
+ if (err)
+ goto out;
+
+ err = tapdisk_vbd_get_image_info(vbd, &image);
+ if (err)
+ goto fail_close;
+
+ params.capacity = image.size;
+ params.sector_size = image.secsize;
+
+ err = ioctl(vbd->ring.fd, BLKTAP2_IOCTL_CREATE_DEVICE, &params);
+ if (err && errno != EEXIST) {
+ err = -errno;
+ EPRINTF("create device failed: %d\n", err);
+ goto fail_close;
+ }
+
+ err = 0;
+
+out:
+ memset(&response, 0, sizeof(response));
+ response.cookie = request->cookie;
+
+ if (err) {
+ response.type = TAPDISK_MESSAGE_ERROR;
+ response.u.response.error = -err;
+ } else {
+ response.u.image.sectors = image.size;
+ response.u.image.sector_size = image.secsize;
+ response.u.image.info = image.info;
+ response.type = TAPDISK_MESSAGE_OPEN_RSP;
+ }
+
+ tapdisk_control_write_message(connection->socket, &response, 2);
+ tapdisk_control_close_connection(connection);
+
+ return;
+
+fail_close:
+ tapdisk_vbd_close_vdi(vbd);
+ free(vbd->name);
+ vbd->name = NULL;
+ goto out;
+}
+
+static void
+tapdisk_control_close_image(struct tapdisk_control_connection *connection,
+ tapdisk_message_t *request)
+{
+ tapdisk_message_t response;
+ td_vbd_t *vbd;
+ int err;
+
+ vbd = tapdisk_server_get_vbd(request->cookie);
+ if (!vbd) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (!list_empty(&vbd->pending_requests)) {
+ err = -EAGAIN;
+ goto out;
+ }
+
+ tapdisk_vbd_close_vdi(vbd);
+
+ /* NB. vbd->name free should probably belong into close_vdi,
+ but the current blktap1 reopen-stuff likely depends on a
+ lifetime extended until shutdown. */
+ free(vbd->name);
+ vbd->name = NULL;
+
+ if (vbd->minor == -1) {
+ tapdisk_server_remove_vbd(vbd);
+ tapdisk_vbd_free(vbd);
+ }
+
+ err = 0;
+out:
+ memset(&response, 0, sizeof(response));
+ response.type = TAPDISK_MESSAGE_CLOSE_RSP;
+ response.cookie = request->cookie;
+ response.u.response.error = -err;
+
+ tapdisk_control_write_message(connection->socket, &response, 2);
+ tapdisk_control_close_connection(connection);
+}
+
+static void
+tapdisk_control_pause_vbd(struct tapdisk_control_connection *connection,
+ tapdisk_message_t *request)
+{
+ int err;
+ td_vbd_t *vbd;
+ tapdisk_message_t response;
+
+ memset(&response, 0, sizeof(response));
+
+ response.type = TAPDISK_MESSAGE_PAUSE_RSP;
+
+ vbd = tapdisk_server_get_vbd(request->cookie);
+ if (!vbd) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ do {
+ err = tapdisk_vbd_pause(vbd);
+
+ if (!err || err != -EAGAIN)
+ break;
+
+ tapdisk_server_iterate();
+ } while (1);
+
+out:
+ response.cookie = request->cookie;
+ response.u.response.error = -err;
+ tapdisk_control_write_message(connection->socket, &response, 2);
+ tapdisk_control_close_connection(connection);
+}
+
+static void
+tapdisk_control_resume_vbd(struct tapdisk_control_connection *connection,
+ tapdisk_message_t *request)
+{
+ int err;
+ td_vbd_t *vbd;
+ tapdisk_message_t response;
+
+ memset(&response, 0, sizeof(response));
+
+ response.type = TAPDISK_MESSAGE_RESUME_RSP;
+
+ vbd = tapdisk_server_get_vbd(request->cookie);
+ if (!vbd) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (!td_flag_test(vbd->state, TD_VBD_PAUSED)) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (request->u.params.path[0]) {
+ free(vbd->name);
+ vbd->name = strndup(request->u.params.path,
+ sizeof(request->u.params.path));
+ if (!vbd->name) {
+ err = -ENOMEM;
+ goto out;
+ }
+ } else if (!vbd->name) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ err = tapdisk_vbd_parse_stack(vbd, vbd->name);
+ if (err)
+ goto out;
+
+ err = tapdisk_vbd_resume(vbd, NULL, -1);
+ if (err)
+ goto out;
+
+out:
+ response.cookie = request->cookie;
+ response.u.response.error = -err;
+ tapdisk_control_write_message(connection->socket, &response, 2);
+ tapdisk_control_close_connection(connection);
+}
+
+static void
+tapdisk_control_handle_request(event_id_t id, char mode, void *private)
+{
+ int err;
+ tapdisk_message_t message;
+ struct tapdisk_control_connection *connection =
+ (struct tapdisk_control_connection *)private;
+
+ if (tapdisk_control_read_message(connection->socket, &message, 2)) {
+ EPRINTF("failed to read message from %d\n", connection->socket);
+ tapdisk_control_close_connection(connection);
+ return;
+ }
+
+ err = tapdisk_control_validate_request(&message);
+ if (err)
+ goto fail;
+
+ switch (message.type) {
+ case TAPDISK_MESSAGE_PID:
+ return tapdisk_control_get_pid(connection, &message);
+ case TAPDISK_MESSAGE_LIST_MINORS:
+ return tapdisk_control_list_minors(connection, &message);
+ case TAPDISK_MESSAGE_LIST:
+ return tapdisk_control_list(connection, &message);
+ case TAPDISK_MESSAGE_ATTACH:
+ return tapdisk_control_attach_vbd(connection, &message);
+ case TAPDISK_MESSAGE_DETACH:
+ return tapdisk_control_detach_vbd(connection, &message);
+ case TAPDISK_MESSAGE_OPEN:
+ return tapdisk_control_open_image(connection, &message);
+ case TAPDISK_MESSAGE_PAUSE:
+ return tapdisk_control_pause_vbd(connection, &message);
+ case TAPDISK_MESSAGE_RESUME:
+ return tapdisk_control_resume_vbd(connection, &message);
+ case TAPDISK_MESSAGE_CLOSE:
+ return tapdisk_control_close_image(connection, &message);
+ default: {
+ tapdisk_message_t response;
+ fail:
+
+ EPRINTF("received unsupported message '%s'\n",
+ tapdisk_message_name(message.type));
+
+ memset(&response, 0, sizeof(response));
+
+ response.type = TAPDISK_MESSAGE_ERROR;
+ response.u.response.error = (err ? -err : EINVAL);
+ tapdisk_control_write_message(connection->socket, &response, 2);
+
+ tapdisk_control_close_connection(connection);
+ break;
+ }
+ }
+}
+
+static void
+tapdisk_control_accept(event_id_t id, char mode, void *private)
+{
+ int err, fd;
+ struct tapdisk_control_connection *connection;
+
+ fd = accept(td_control.socket, NULL, NULL);
+ if (fd == -1) {
+ EPRINTF("failed to accept new control connection: %d\n", errno);
+ return;
+ }
+
+ connection = tapdisk_control_allocate_connection(fd);
+ if (!connection) {
+ close(fd);
+ EPRINTF("failed to allocate new control connection\n");
+ }
+
+ err = tapdisk_server_register_event(SCHEDULER_POLL_READ_FD,
+ connection->socket, 0,
+ tapdisk_control_handle_request,
+ connection);
+ if (err == -1) {
+ close(fd);
+ free(connection);
+ EPRINTF("failed to register new control event: %d\n", err);
+ }
+
+ connection->event_id = err;
+}
+
+static int
+tapdisk_control_mkdir(const char *dir)
+{
+ int err;
+ char *ptr, *name, *start;
+
+ err = access(dir, W_OK | R_OK);
+ if (!err)
+ return 0;
+
+ name = strdup(dir);
+ if (!name)
+ return -ENOMEM;
+
+ start = name;
+
+ for (;;) {
+ ptr = strchr(start + 1, '/');
+ if (ptr)
+ *ptr = '\0';
+
+ err = mkdir(name, 0755);
+ if (err && errno != EEXIST) {
+ err = -errno;
+ EPRINTF("failed to create directory %s: %d\n",
+ name, err);
+ break;
+ }
+
+ if (!ptr)
+ break;
+ else {
+ *ptr = '/';
+ start = ptr + 1;
+ }
+ }
+
+ free(name);
+ return err;
+}
+
+static int
+tapdisk_control_create_socket(char **socket_path)
+{
+ int err, flags;
+ struct sockaddr_un saddr;
+
+ err = tapdisk_control_mkdir(BLKTAP2_CONTROL_DIR);
+ if (err) {
+ EPRINTF("failed to create directory %s: %d\n",
+ BLKTAP2_CONTROL_DIR, err);
+ return err;
+ }
+
+ err = asprintf(&td_control.path, "%s/%s%d",
+ BLKTAP2_CONTROL_DIR, BLKTAP2_CONTROL_SOCKET, getpid());
+ if (err == -1) {
+ td_control.path = NULL;
+ err = (errno ? : ENOMEM);
+ goto fail;
+ }
+
+ if (unlink(td_control.path) && errno != ENOENT) {
+ err = errno;
+ EPRINTF("failed to unlink %s: %d\n", td_control.path, errno);
+ goto fail;
+ }
+
+ td_control.socket = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (td_control.socket == -1) {
+ err = errno;
+ EPRINTF("failed to create control socket: %d\n", err);
+ goto fail;
+ }
+
+ memset(&saddr, 0, sizeof(saddr));
+ strncpy(saddr.sun_path, td_control.path, sizeof(saddr.sun_path));
+ saddr.sun_family = AF_UNIX;
+
+ err = bind(td_control.socket,
+ (const struct sockaddr *)&saddr, sizeof(saddr));
+ if (err == -1) {
+ err = errno;
+ EPRINTF("failed to bind to %s: %d\n", saddr.sun_path, err);
+ goto fail;
+ }
+
+ err = listen(td_control.socket, 10);
+ if (err == -1) {
+ err = errno;
+ EPRINTF("failed to listen: %d\n", err);
+ goto fail;
+ }
+
+ err = tapdisk_server_register_event(SCHEDULER_POLL_READ_FD,
+ td_control.socket, 0,
+ tapdisk_control_accept, NULL);
+ if (err < 0) {
+ EPRINTF("failed to add watch: %d\n", err);
+ goto fail;
+ }
+
+ td_control.event_id = err;
+ *socket_path = td_control.path;
+
+ return 0;
+
+fail:
+ tapdisk_control_close();
+ return err;
+}
+
+int
+tapdisk_control_open(char **path)
+{
+ int err;
+
+ tapdisk_control_initialize();
+
+ return tapdisk_control_create_socket(path);
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/drivers/tapdisk-control.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/drivers/tapdisk-control.h Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __TAPDISK_CONTROL_H__
+#define __TAPDISK_CONTROL_H__
+
+int tapdisk_control_open(char **path);
+void tapdisk_control_close(void);
+
+#endif
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/drivers/tapdisk-server.c
--- a/tools/blktap2/drivers/tapdisk-server.c Tue Jun 08 08:04:36 2010 +0100
+++ b/tools/blktap2/drivers/tapdisk-server.c Tue Jun 08 08:05:09 2010 +0100
@@ -63,6 +63,12 @@ tapdisk_server_get_shared_image(td_image
return NULL;
}

+struct list_head *
+tapdisk_server_get_all_vbds(void)
+{
+ return &server.vbds;
+}
+
td_vbd_t *
tapdisk_server_get_vbd(uint16_t uuid)
{
@@ -218,24 +224,29 @@ tapdisk_server_close(void)
tapdisk_server_close_aio();
}

+void
+tapdisk_server_iterate(void)
+{
+ int ret;
+
+ tapdisk_server_assert_locks();
+ tapdisk_server_set_retry_timeout();
+ tapdisk_server_check_progress();
+
+ ret = scheduler_wait_for_events(&server.scheduler);
+ if (ret < 0)
+ DBG(TLOG_WARN, "server wait returned %d\n", ret);
+
+ tapdisk_server_check_vbds();
+ tapdisk_server_submit_tiocbs();
+ tapdisk_server_kick_responses();
+}
+
static void
__tapdisk_server_run(void)
{
- int ret;
-
- while (server.run) {
- tapdisk_server_assert_locks();
- tapdisk_server_set_retry_timeout();
- tapdisk_server_check_progress();
-
- ret = scheduler_wait_for_events(&server.scheduler);
- if (ret < 0)
- DBG(TLOG_WARN, "server wait returned %d\n", ret);
-
- tapdisk_server_check_vbds();
- tapdisk_server_submit_tiocbs();
- tapdisk_server_kick_responses();
- }
+ while (server.run)
+ tapdisk_server_iterate();
}

static void
@@ -267,22 +278,50 @@ tapdisk_server_signal_handler(int signal
}

int
-tapdisk_server_initialize(void)
+tapdisk_server_init(void)
+{
+ memset(&server, 0, sizeof(server));
+ INIT_LIST_HEAD(&server.vbds);
+
+ scheduler_initialize(&server.scheduler);
+
+ return 0;
+}
+
+int
+tapdisk_server_complete(void)
{
int err;
-
- memset(&server, 0, sizeof(tapdisk_server_t));
- INIT_LIST_HEAD(&server.vbds);
-
- scheduler_initialize(&server.scheduler);

err = tapdisk_server_init_aio();
if (err)
- return err;
+ goto fail;

server.run = 1;

return 0;
+
+fail:
+ tapdisk_server_close_aio();
+ return err;
+}
+
+int
+tapdisk_server_initialize(void)
+{
+ int err;
+
+ tapdisk_server_init();
+
+ err = tapdisk_server_complete();
+ if (err)
+ goto fail;
+
+ return 0;
+
+fail:
+ tapdisk_server_close();
+ return err;
}

int
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/drivers/tapdisk-server.h
--- a/tools/blktap2/drivers/tapdisk-server.h Tue Jun 08 08:04:36 2010 +0100
+++ b/tools/blktap2/drivers/tapdisk-server.h Tue Jun 08 08:05:09 2010 +0100
@@ -28,6 +28,7 @@
#ifndef _TAPDISK_SERVER_H_
#define _TAPDISK_SERVER_H_

+#include "list.h"
#include "tapdisk-vbd.h"
#include "tapdisk-queue.h"

@@ -35,6 +36,7 @@ struct tap_disk *tapdisk_server_find_dri

td_image_t *tapdisk_server_get_shared_image(td_image_t *);

+struct list_head *tapdisk_server_get_all_vbds(void);
td_vbd_t *tapdisk_server_get_vbd(td_uuid_t);
void tapdisk_server_add_vbd(td_vbd_t *);
void tapdisk_server_remove_vbd(td_vbd_t *);
@@ -47,8 +49,11 @@ void tapdisk_server_unregister_event(eve
void tapdisk_server_unregister_event(event_id_t);
void tapdisk_server_set_max_timeout(int);

+int tapdisk_server_init(void);
int tapdisk_server_initialize(void);
+int tapdisk_server_complete(void);
int tapdisk_server_run(void);
+void tapdisk_server_iterate(void);

#define TAPDISK_TIOCBS (TAPDISK_DATA_REQUESTS + 50)

diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/drivers/tapdisk-vbd.c
--- a/tools/blktap2/drivers/tapdisk-vbd.c Tue Jun 08 08:04:36 2010 +0100
+++ b/tools/blktap2/drivers/tapdisk-vbd.c Tue Jun 08 08:05:09 2010 +0100
@@ -38,7 +38,6 @@
#include <memshr.h>
#endif

-#include "libvhd.h"
#include "tapdisk-image.h"
#include "tapdisk-driver.h"
#include "tapdisk-server.h"
@@ -93,25 +92,20 @@ tapdisk_vbd_free(td_vbd_t *vbd)
}
}

-int
-tapdisk_vbd_initialize(uint16_t uuid)
-{
+td_vbd_t*
+tapdisk_vbd_create(uint16_t uuid)
+{
+ td_vbd_t *vbd;
int i;
- td_vbd_t *vbd;
-
- vbd = tapdisk_server_get_vbd(uuid);
- if (vbd) {
- EPRINTF("duplicate vbds! %u\n", uuid);
- return -EEXIST;
- }

vbd = calloc(1, sizeof(td_vbd_t));
if (!vbd) {
EPRINTF("failed to allocate tapdisk state\n");
- return -ENOMEM;
+ return NULL;
}

vbd->uuid = uuid;
+ vbd->minor = -1;
vbd->ring.fd = -1;

/* default blktap ring completion */
@@ -134,6 +128,22 @@ tapdisk_vbd_initialize(uint16_t uuid)
for (i = 0; i < MAX_REQUESTS; i++)
tapdisk_vbd_initialize_vreq(vbd->request_list + i);

+ return vbd;
+}
+
+int
+tapdisk_vbd_initialize(uint16_t uuid)
+{
+ td_vbd_t *vbd;
+
+ vbd = tapdisk_server_get_vbd(uuid);
+ if (vbd) {
+ EPRINTF("duplicate vbds! %u\n", uuid);
+ return -EEXIST;
+ }
+
+ vbd = tapdisk_vbd_create(uuid);
+
tapdisk_server_add_vbd(vbd);

return 0;
@@ -181,6 +191,8 @@ tapdisk_vbd_close_vdi(td_vbd_t *vbd)

INIT_LIST_HEAD(&vbd->images);
td_flag_set(vbd->state, TD_VBD_CLOSED);
+
+ tapdisk_vbd_free_stack(vbd);
}

static int
@@ -646,9 +658,42 @@ tapdisk_vbd_unmap_device(td_vbd_t *vbd)
return 0;
}

+void
+tapdisk_vbd_detach(td_vbd_t *vbd)
+{
+ tapdisk_vbd_unregister_events(vbd);
+
+ tapdisk_vbd_unmap_device(vbd);
+ vbd->minor = -1;
+}
+
+
+int
+tapdisk_vbd_attach(td_vbd_t *vbd, const char *devname, int minor)
+{
+ int err;
+
+ err = tapdisk_vbd_map_device(vbd, devname);
+ if (err)
+ goto fail;
+
+ err = tapdisk_vbd_register_event_watches(vbd);
+ if (err)
+ goto fail;
+
+ vbd->minor = minor;
+
+ return 0;
+
+fail:
+ tapdisk_vbd_detach(vbd);
+
+ return err;
+}
+
int
tapdisk_vbd_open(td_vbd_t *vbd, const char *name, uint16_t type,
- uint16_t storage, const char *ring, td_flag_t flags)
+ uint16_t storage, int minor, const char *ring, td_flag_t flags)
{
int err;

@@ -656,20 +701,15 @@ tapdisk_vbd_open(td_vbd_t *vbd, const ch
if (err)
goto out;

- err = tapdisk_vbd_map_device(vbd, ring);
+ err = tapdisk_vbd_attach(vbd, ring, minor);
if (err)
goto out;

- err = tapdisk_vbd_register_event_watches(vbd);
- if (err)
- goto out;
-
return 0;

out:
+ tapdisk_vbd_detach(vbd);
tapdisk_vbd_close_vdi(vbd);
- tapdisk_vbd_unmap_device(vbd);
- tapdisk_vbd_unregister_events(vbd);
free(vbd->name);
vbd->name = NULL;
return err;
@@ -727,11 +767,9 @@ tapdisk_vbd_shutdown(td_vbd_t *vbd)
vbd->kicked);

tapdisk_vbd_close_vdi(vbd);
- tapdisk_vbd_unregister_events(vbd);
- tapdisk_vbd_unmap_device(vbd);
+ tapdisk_vbd_detach(vbd);
tapdisk_server_remove_vbd(vbd);
- free(vbd->name);
- free(vbd);
+ tapdisk_vbd_free(vbd);

tlog_print_errors();

@@ -941,17 +979,18 @@ tapdisk_vbd_resume(td_vbd_t *vbd, const
return -EINVAL;
}

- free(vbd->name);
- vbd->name = strdup(path);
- if (!vbd->name) {
- EPRINTF("copying new vbd %s name failed\n", path);
- return -EINVAL;
- }
- vbd->type = drivertype;
+ if (path) {
+ free(vbd->name);
+ vbd->name = strdup(path);
+ if (!vbd->name) {
+ EPRINTF("copying new vbd %s name failed\n", path);
+ return -EINVAL;
+ }
+ }

for (i = 0; i < TD_VBD_EIO_RETRIES; i++) {
err = __tapdisk_vbd_open_vdi(vbd, TD_OPEN_STRICT);
- if (!err)
+ if (err != -EIO)
break;

sleep(TD_VBD_EIO_SLEEP);
@@ -963,6 +1002,7 @@ tapdisk_vbd_resume(td_vbd_t *vbd, const
tapdisk_vbd_start_queue(vbd);
td_flag_clear(vbd->state, TD_VBD_PAUSED);
td_flag_clear(vbd->state, TD_VBD_PAUSE_REQUESTED);
+ tapdisk_vbd_check_state(vbd);

return 0;
}
@@ -1607,7 +1647,6 @@ tapdisk_vbd_resume_ring(td_vbd_t *vbd)
err = -ENOMEM;
goto out;
}
- vbd->type = type;

tapdisk_vbd_start_queue(vbd);

diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/drivers/tapdisk-vbd.h
--- a/tools/blktap2/drivers/tapdisk-vbd.h Tue Jun 08 08:04:36 2010 +0100
+++ b/tools/blktap2/drivers/tapdisk-vbd.h Tue Jun 08 08:05:09 2010 +0100
@@ -89,7 +89,7 @@ struct td_vbd_handle {
char *name;

td_uuid_t uuid;
- int type;
+ int minor;

struct list_head driver_stack;

@@ -168,17 +168,23 @@ tapdisk_vbd_next_image(td_image_t *image
return list_entry(image->next.next, td_image_t, next);
}

+td_vbd_t *tapdisk_vbd_create(td_uuid_t);
int tapdisk_vbd_initialize(td_uuid_t);
void tapdisk_vbd_set_callback(td_vbd_t *, td_vbd_cb_t, void *);
int tapdisk_vbd_parse_stack(td_vbd_t *vbd, const char *path);
int tapdisk_vbd_open(td_vbd_t *, const char *, uint16_t,
- uint16_t, const char *, td_flag_t);
+ uint16_t, int, const char *, td_flag_t);
int tapdisk_vbd_close(td_vbd_t *);
+void tapdisk_vbd_free(td_vbd_t *);
void tapdisk_vbd_free_stack(td_vbd_t *);

+int tapdisk_vbd_open_stack(td_vbd_t *, uint16_t, td_flag_t);
int tapdisk_vbd_open_vdi(td_vbd_t *, const char *,
uint16_t, uint16_t, td_flag_t);
void tapdisk_vbd_close_vdi(td_vbd_t *);
+
+int tapdisk_vbd_attach(td_vbd_t *, const char *, int);
+void tapdisk_vbd_detach(td_vbd_t *);

void tapdisk_vbd_forward_request(td_request_t);

diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/drivers/tapdisk2.c
--- a/tools/blktap2/drivers/tapdisk2.c Tue Jun 08 08:04:36 2010 +0100
+++ b/tools/blktap2/drivers/tapdisk2.c Tue Jun 08 08:05:09 2010 +0100
@@ -28,397 +28,37 @@
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
+#include <stdlib.h>
#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
#ifdef MEMSHR
#include <memshr.h>
#endif

#include "tapdisk.h"
-#include "blktap2.h"
-#include "tapdisk-vbd.h"
#include "tapdisk-utils.h"
#include "tapdisk-server.h"
-#include "tapdisk-disktype.h"
-
-#define TAPDISK2_VBD 0
-
-#define cprintf(_err, _f, _a...) \
- do { \
- if (child_out) { \
- fprintf(child_out, "%d: " _f, _err, ##_a); \
- fflush(child_out); \
- } \
- } while (0)
-
-#define CHILD_ERR(_err, _f, _a...) \
- do { \
- EPRINTF(_f, ##_a); \
- cprintf(_err, _f, ##_a); \
- } while (0)
-
-static int channel[2];
-static FILE *child_out;
-static struct blktap2_handle handle;
-
-static int
-tapdisk2_prepare_directory(void)
-{
- int err;
- char *ptr, *name, *start;
-
- err = access(BLKTAP2_DIRECTORY, W_OK | R_OK);
- if (!err)
- return 0;
-
- name = strdup(BLKTAP2_DIRECTORY);
- if (!name)
- return -ENOMEM;
-
- start = name;
-
- for (;;) {
- ptr = strchr(start + 1, '/');
- if (ptr)
- *ptr = '\0';
-
- err = mkdir(name, 0755);
- if (err && errno != EEXIST) {
- err = -errno;
- CHILD_ERR(err, "failed to create directory %s: %d\n",
- name, err);
- break;
- }
-
- if (!ptr)
- break;
- else {
- *ptr = '/';
- start = ptr + 1;
- }
- }
-
- free(name);
- return err;
-}
-
-static int
-tapdisk2_make_device(char *devname, int major, int minor, int perm)
-{
- int err;
- struct stat st;
-
- err = tapdisk2_prepare_directory();
- if (err)
- return err;
-
- if (!access(devname, F_OK))
- if (unlink(devname)) {
- CHILD_ERR(errno, "error unlinking %s: %d\n",
- devname, errno);
- return -errno;
- }
-
- err = mknod(devname, perm, makedev(major, minor));
- if (err) {
- CHILD_ERR(errno, "mknod %s failed: %d\n", devname, -errno);
- return -errno;
- }
-
- DPRINTF("Created %s device\n", devname);
- return 0;
-}
-
-static int
-tapdisk2_check_environment(void)
-{
- FILE *f;
- int err, minor;
- char name[256];
-
- if (!access(BLKTAP2_CONTROL_DEVICE, R_OK | W_OK))
- return 0;
-
- memset(name, 0, sizeof(name));
-
- f = fopen("/proc/misc", "r");
- if (!f) {
- CHILD_ERR(errno, "failed to open /proc/misc: %d\n", errno);
- return -errno;
- }
-
- while (fscanf(f, "%d %256s", &minor, name) == 2)
- if (!strcmp(name, BLKTAP2_CONTROL_NAME)) {
- err = tapdisk2_make_device(BLKTAP2_CONTROL_DEVICE,
- MISC_MAJOR_NUMBER,
- minor, S_IFCHR | 0600);
- goto out;
- }
-
- err = -ENOSYS;
- CHILD_ERR(err, "didn't find %s in /proc/misc\n", BLKTAP2_CONTROL_NAME);
-
-out:
- fclose(f);
- return err;
-}
-
-static void
-tapdisk2_free_device(void)
-{
- int fd, err;
-
- fd = open(BLKTAP2_CONTROL_DEVICE, O_RDONLY);
- if (fd == -1) {
- CHILD_ERR(errno, "failed to open control device: %d\n", errno);
- return;
- }
-
- err = ioctl(fd, BLKTAP2_IOCTL_FREE_TAP, handle.minor);
- close(fd);
-}
-
-static int
-tapdisk2_prepare_device(void)
-{
- char *name;
- int fd, err;
-
- fd = open(BLKTAP2_CONTROL_DEVICE, O_RDONLY);
- if (fd == -1) {
- CHILD_ERR(errno, "failed to open control device: %d\n", errno);
- return -errno;
- }
-
- err = ioctl(fd, BLKTAP2_IOCTL_ALLOC_TAP, &handle);
- close(fd);
- if (err == -1) {
- CHILD_ERR(errno, "failed to allocate new device: %d\n", errno);
- return -errno;
- }
-
- err = asprintf(&name, "%s%d", BLKTAP2_RING_DEVICE, handle.minor);
- if (err == -1) {
- err = -ENOMEM;
- goto fail;
- }
-
- err = tapdisk2_make_device(name, handle.ring,
- handle.minor, S_IFCHR | 0600);
- free(name);
- if (err) {
- CHILD_ERR(err, "creating ring device for %d failed: %d\n",
- handle.minor, err);
- goto fail;
- }
-
- err = asprintf(&name, "%s%d", BLKTAP2_IO_DEVICE, handle.minor);
- if (err == -1) {
- err = -ENOMEM;
- goto fail;
- }
-
- err = tapdisk2_make_device(name, handle.device,
- handle.minor, S_IFBLK | 0600);
- free(name);
- if (err) {
- CHILD_ERR(err, "creating IO device for %d failed: %d\n",
- handle.minor, err);
- goto fail;
- }
-
- DPRINTF("new interface: ring: %u, device: %u, minor: %u\n",
- handle.ring, handle.device, handle.minor);
-
- return 0;
-
-fail:
- tapdisk2_free_device();
- return err;
-}
-
-static int
-tapdisk2_open_device(int type, const char *path, const char *name)
-{
- int err;
- td_vbd_t *vbd;
- image_t image;
- char *devname;
- struct blktap2_params params;
-
- err = tapdisk_vbd_initialize(TAPDISK2_VBD);
- if (err)
- return err;
-
- vbd = tapdisk_server_get_vbd(TAPDISK2_VBD);
- if (!vbd) {
- err = -ENODEV;
- CHILD_ERR(err, "couldn't find vbd\n");
- return err;
- }
-
- err = asprintf(&devname, "%s%d", BLKTAP2_RING_DEVICE, handle.minor);
- if (err == -1) {
- err = -ENOMEM;
- CHILD_ERR(err, "couldn't allocate ring\n");
- return err;
- }
-
- err = tapdisk_vbd_parse_stack(vbd, name);
- if (err) {
- CHILD_ERR(err, "vbd_parse_stack failed: %d\n", err);
- return err;
- }
-
- /* TODO: clean this up */
- err = tapdisk_vbd_open(vbd, path, type,
- TAPDISK_STORAGE_TYPE_DEFAULT,
- devname, 0);
- free(devname);
- if (err) {
- CHILD_ERR(err, "vbd open failed: %d\n", err);
- return err;
- }
-
- memset(&params, 0, sizeof(params));
- tapdisk_vbd_get_image_info(vbd, &image);
-
- params.capacity = image.size;
- params.sector_size = image.secsize;
- snprintf(params.name, sizeof(params.name) - 1, "%s", name);
-
- err = ioctl(vbd->ring.fd, BLKTAP2_IOCTL_CREATE_DEVICE, &params);
- if (err) {
- err = -errno;
- CHILD_ERR(err, "create device failed: %d\n", err);
- return err;
- }
-
- return 0;
-}
-
-static int
-tapdisk2_set_child_fds(void)
-{
- int i, err;
-
- err = dup2(channel[1], STDOUT_FILENO);
- if (err == -1) {
- CHILD_ERR(errno, "failed duping pipe: %d\n", errno);
- return errno;
- }
-
- child_out = fdopen(STDOUT_FILENO, "w");
- if (!child_out) {
- CHILD_ERR(errno, "failed setting child_out: %d\n", errno);
- return errno;
- }
-
- for (i = 0; i < sysconf(_SC_OPEN_MAX); i++)
- if (i != STDOUT_FILENO)
- close(i);
-
- return 0;
-}
-
-static int
-tapdisk2_create_device(const char *params)
-{
- const char *path;
- int err, type;
-
- chdir("/");
- tapdisk_start_logging("tapdisk2");
-
- err = tapdisk2_set_child_fds();
- if (err)
- goto out;
-
- err = tapdisk2_check_environment();
- if (err)
- goto out;
-
- err = tapdisk_parse_disk_type(params, &path, &type);
- if (err)
- goto out;
-
- err = tapdisk2_prepare_device();
- if (err)
- goto out;
-
- err = tapdisk_server_initialize();
- if (err)
- goto fail;
-
- err = tapdisk2_open_device(type, path, params);
- if (err)
- goto fail;
-
- cprintf(0, "%s%d\n", BLKTAP2_IO_DEVICE, handle.minor);
- close(STDOUT_FILENO);
-
- err = tapdisk_server_run();
- if (err)
- goto fail;
-
- err = 0;
-
-out:
- tapdisk_stop_logging();
- return err;
-
-fail:
- tapdisk2_free_device();
- goto out;
-}
-
-static int
-tapdisk2_wait_for_device(void)
-{
- int err;
- char msg[1024];
- FILE *parent_in;
-
- close(channel[1]);
- parent_in = fdopen(channel[0], "r");
- if (!parent_in) {
- printf("failed to connect to child: %d\n", errno);
- return errno;
- }
-
- memset(msg, 0, sizeof(msg));
- if (fscanf(parent_in, "%d: %1023[^\n]", &err, msg) != 2) {
- printf("unrecognized child response\n");
- return EINVAL;
- }
-
- printf("%s\n", msg);
- return (err >= 0 ? err : -err);
-}
+#include "tapdisk-control.h"

static void
usage(const char *app, int err)
{
- fprintf(stderr, "usage: %s <-n file>\n", app);
+ fprintf(stderr, "usage: %s <-u uuid> <-c control socket>\n", app);
exit(err);
}

int
main(int argc, char *argv[])
{
- int c;
- char *params;
+ char *control;
+ int c, err, nodaemon;

- params = NULL;
+ control = NULL;
+ nodaemon = 0;

- while ((c = getopt(argc, argv, "n:s:h")) != -1) {
+ while ((c = getopt(argc, argv, "s:Dh")) != -1) {
switch (c) {
- case 'n':
- params = optarg;
+ case 'D':
+ nodaemon = 1;
break;
case 'h':
usage(argv[0], 0);
@@ -436,21 +76,58 @@ main(int argc, char *argv[])
}
}

- if (!params || optind != argc)
+ if (optind != argc)
usage(argv[0], EINVAL);

- if (pipe(channel) == -1) {
- printf("pipe failed: %d\n", errno);
- return errno;
+ chdir("/");
+ tapdisk_start_logging("tapdisk2");
+
+ err = tapdisk_server_init();
+ if (err) {
+ DPRINTF("failed to initialize server: %d\n", err);
+ goto out;
}

- switch (fork()) {
- case -1:
- printf("fork failed: %d\n", errno);
- return errno;
- case 0:
- return tapdisk2_create_device(params);
- default:
- return tapdisk2_wait_for_device();
+ if (!nodaemon) {
+ err = daemon(0, 1);
+ if (err) {
+ DPRINTF("failed to daemonize: %d\n", errno);
+ goto out;
+ }
}
+
+ err = tapdisk_control_open(&control);
+ if (err) {
+ DPRINTF("failed to open control socket: %d\n", err);
+ goto out;
+ }
+
+ fprintf(stdout, "%s\n", control);
+ fflush(stdout);
+
+ if (!nodaemon) {
+ int fd;
+
+ fd = open("/dev/null", O_RDWR);
+ if (fd != -1) {
+ dup2(fd, STDIN_FILENO);
+ dup2(fd, STDOUT_FILENO);
+ dup2(fd, STDERR_FILENO);
+ if (fd > 2)
+ close(fd);
+ }
+ }
+
+ err = tapdisk_server_complete();
+ if (err) {
+ DPRINTF("failed to complete server: %d\n", err);
+ goto out;
+ }
+
+ err = tapdisk_server_run();
+
+out:
+ tapdisk_control_close();
+ tapdisk_stop_logging();
+ return err;
}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/include/blktap2.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/include/blktap2.h Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _BLKTAP_2_H_
+#define _BLKTAP_2_H_
+
+#define BLKTAP2_MAX_MESSAGE_LEN 256
+
+#define BLKTAP2_RING_MESSAGE_PAUSE 1
+#define BLKTAP2_RING_MESSAGE_RESUME 2
+#define BLKTAP2_RING_MESSAGE_CLOSE 3
+
+#define BLKTAP2_IOCTL_KICK_FE 1
+#define BLKTAP2_IOCTL_ALLOC_TAP 200
+#define BLKTAP2_IOCTL_FREE_TAP 201
+#define BLKTAP2_IOCTL_CREATE_DEVICE 202
+#define BLKTAP2_IOCTL_SET_PARAMS 203
+#define BLKTAP2_IOCTL_PAUSE 204
+#define BLKTAP2_IOCTL_REOPEN 205
+#define BLKTAP2_IOCTL_RESUME 206
+
+#define BLKTAP2_SYSFS_DIR "/sys/class/blktap2"
+#define BLKTAP2_CONTROL_NAME "blktap-control"
+#define BLKTAP2_CONTROL_DIR "/var/run/"BLKTAP2_CONTROL_NAME
+#define BLKTAP2_CONTROL_SOCKET "ctl"
+#define BLKTAP2_DIRECTORY "/dev/xen/blktap-2"
+#define BLKTAP2_CONTROL_DEVICE BLKTAP2_DIRECTORY"/control"
+#define BLKTAP2_RING_DEVICE BLKTAP2_DIRECTORY"/blktap"
+#define BLKTAP2_IO_DEVICE BLKTAP2_DIRECTORY"/tapdev"
+
+struct blktap2_handle {
+ unsigned int ring;
+ unsigned int device;
+ unsigned int minor;
+};
+
+struct blktap2_params {
+ char name[BLKTAP2_MAX_MESSAGE_LEN];
+ unsigned long long capacity;
+ unsigned long sector_size;
+};
+
+#endif
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/include/tapdisk-message.h
--- a/tools/blktap2/include/tapdisk-message.h Tue Jun 08 08:04:36 2010 +0100
+++ b/tools/blktap2/include/tapdisk-message.h Tue Jun 08 08:05:09 2010 +0100
@@ -33,6 +33,9 @@
#define TAPDISK_MESSAGE_MAX_PATH_LENGTH 256
#define TAPDISK_MESSAGE_STRING_LENGTH 256

+#define TAPDISK_MESSAGE_MAX_MINORS \
+ ((TAPDISK_MESSAGE_MAX_PATH_LENGTH / sizeof(int)) - 1)
+
#define TAPDISK_MESSAGE_FLAG_SHARED 0x01
#define TAPDISK_MESSAGE_FLAG_RDONLY 0x02
#define TAPDISK_MESSAGE_FLAG_ADD_CACHE 0x04
@@ -44,10 +47,13 @@ typedef struct tapdisk_message_image
typedef struct tapdisk_message_image tapdisk_message_image_t;
typedef struct tapdisk_message_params tapdisk_message_params_t;
typedef struct tapdisk_message_string tapdisk_message_string_t;
+typedef struct tapdisk_message_response tapdisk_message_response_t;
+typedef struct tapdisk_message_minors tapdisk_message_minors_t;
+typedef struct tapdisk_message_list tapdisk_message_list_t;

struct tapdisk_message_params {
tapdisk_message_flag_t flags;
-
+
uint8_t storage;
uint32_t devnum;
uint32_t domid;
@@ -65,6 +71,23 @@ struct tapdisk_message_string {
char text[TAPDISK_MESSAGE_STRING_LENGTH];
};

+struct tapdisk_message_response {
+ int error;
+ char message[TAPDISK_MESSAGE_STRING_LENGTH];
+};
+
+struct tapdisk_message_minors {
+ int count;
+ int list[TAPDISK_MESSAGE_MAX_MINORS];
+};
+
+struct tapdisk_message_list {
+ int count;
+ int minor;
+ int state;
+ char path[TAPDISK_MESSAGE_MAX_PATH_LENGTH];
+};
+
struct tapdisk_message {
uint16_t type;
uint16_t cookie;
@@ -74,6 +97,9 @@ struct tapdisk_message {
tapdisk_message_image_t image;
tapdisk_message_params_t params;
tapdisk_message_string_t string;
+ tapdisk_message_minors_t minors;
+ tapdisk_message_response_t response;
+ tapdisk_message_list_t list;
} u;
};

@@ -82,6 +108,8 @@ enum tapdisk_message_id {
TAPDISK_MESSAGE_RUNTIME_ERROR,
TAPDISK_MESSAGE_PID,
TAPDISK_MESSAGE_PID_RSP,
+ TAPDISK_MESSAGE_ATTACH,
+ TAPDISK_MESSAGE_ATTACH_RSP,
TAPDISK_MESSAGE_OPEN,
TAPDISK_MESSAGE_OPEN_RSP,
TAPDISK_MESSAGE_PAUSE,
@@ -90,6 +118,13 @@ enum tapdisk_message_id {
TAPDISK_MESSAGE_RESUME_RSP,
TAPDISK_MESSAGE_CLOSE,
TAPDISK_MESSAGE_CLOSE_RSP,
+ TAPDISK_MESSAGE_DETACH,
+ TAPDISK_MESSAGE_DETACH_RSP,
+ TAPDISK_MESSAGE_LIST_MINORS,
+ TAPDISK_MESSAGE_LIST_MINORS_RSP,
+ TAPDISK_MESSAGE_LIST,
+ TAPDISK_MESSAGE_LIST_RSP,
+ TAPDISK_MESSAGE_FORCE_SHUTDOWN,
TAPDISK_MESSAGE_EXIT,
};

@@ -127,8 +162,35 @@ tapdisk_message_name(enum tapdisk_messag
case TAPDISK_MESSAGE_CLOSE:
return "close";

+ case TAPDISK_MESSAGE_FORCE_SHUTDOWN:
+ return "force shutdown";
+
case TAPDISK_MESSAGE_CLOSE_RSP:
return "close response";
+
+ case TAPDISK_MESSAGE_ATTACH:
+ return "attach";
+
+ case TAPDISK_MESSAGE_ATTACH_RSP:
+ return "attach response";
+
+ case TAPDISK_MESSAGE_DETACH:
+ return "detach";
+
+ case TAPDISK_MESSAGE_DETACH_RSP:
+ return "detach response";
+
+ case TAPDISK_MESSAGE_LIST_MINORS:
+ return "list minors";
+
+ case TAPDISK_MESSAGE_LIST_MINORS_RSP:
+ return "list minors response";
+
+ case TAPDISK_MESSAGE_LIST:
+ return "list";
+
+ case TAPDISK_MESSAGE_LIST_RSP:
+ return "list response";

case TAPDISK_MESSAGE_EXIT:
return "exit";

_______________________________________________
Xen-changelog mailing list
Xen-changelog@lists.xensource.com
http://lists.xensource.com/xen-changelog