aboutsummaryrefslogtreecommitdiffstats
path: root/tools/blktap2/drivers
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2010-06-08 08:05:09 +0100
committerKeir Fraser <keir.fraser@citrix.com>2010-06-08 08:05:09 +0100
commit4b1af8b188ccf532742ed5f2a49f480d9a702333 (patch)
treea34e14bc4e972f3ec7af5870b6a7ed634cd3282b /tools/blktap2/drivers
parentc6913b5aaf48107f7bb9fb4e01c7f74c863b3713 (diff)
downloadxen-4b1af8b188ccf532742ed5f2a49f480d9a702333.tar.gz
xen-4b1af8b188ccf532742ed5f2a49f480d9a702333.tar.bz2
xen-4b1af8b188ccf532742ed5f2a49f480d9a702333.zip
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>
Diffstat (limited to 'tools/blktap2/drivers')
-rw-r--r--tools/blktap2/drivers/Makefile4
-rw-r--r--tools/blktap2/drivers/tapdisk-control.c836
-rw-r--r--tools/blktap2/drivers/tapdisk-control.h (renamed from tools/blktap2/drivers/blktap2.h)39
-rw-r--r--tools/blktap2/drivers/tapdisk-server.c75
-rw-r--r--tools/blktap2/drivers/tapdisk-server.h5
-rw-r--r--tools/blktap2/drivers/tapdisk-vbd.c101
-rw-r--r--tools/blktap2/drivers/tapdisk-vbd.h10
-rw-r--r--tools/blktap2/drivers/tapdisk2.c441
8 files changed, 1041 insertions, 470 deletions
diff --git a/tools/blktap2/drivers/Makefile b/tools/blktap2/drivers/Makefile
index 88d3a8c8b5..446c8c6fb7 100644
--- a/tools/blktap2/drivers/Makefile
+++ b/tools/blktap2/drivers/Makefile
@@ -12,8 +12,7 @@ INST_DIR = $(SBINDIR)
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_netbsd.o
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 --git a/tools/blktap2/drivers/tapdisk-control.c b/tools/blktap2/drivers/tapdisk-control.c
new file mode 100644
index 0000000000..a48c11301e
--- /dev/null
+++ b/tools/blktap2/drivers/tapdisk-control.c
@@ -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 --git a/tools/blktap2/drivers/blktap2.h b/tools/blktap2/drivers/tapdisk-control.h
index 38350d2fad..10c18112f3 100644
--- a/tools/blktap2/drivers/blktap2.h
+++ b/tools/blktap2/drivers/tapdisk-control.h
@@ -25,42 +25,11 @@
* 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
+#ifndef __TAPDISK_CONTROL_H__
+#define __TAPDISK_CONTROL_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_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;
-};
+int tapdisk_control_open(char **path);
+void tapdisk_control_close(void);
#endif
diff --git a/tools/blktap2/drivers/tapdisk-server.c b/tools/blktap2/drivers/tapdisk-server.c
index 73e9717815..eecde3d23f 100644
--- a/tools/blktap2/drivers/tapdisk-server.c
+++ b/tools/blktap2/drivers/tapdisk-server.c
@@ -63,6 +63,12 @@ tapdisk_server_get_shared_image(td_image_t *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();
}
-static void
-__tapdisk_server_run(void)
+void
+tapdisk_server_iterate(void)
{
int ret;
- while (server.run) {
- tapdisk_server_assert_locks();
- tapdisk_server_set_retry_timeout();
- tapdisk_server_check_progress();
+ 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);
+ 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();
- }
+ tapdisk_server_check_vbds();
+ tapdisk_server_submit_tiocbs();
+ tapdisk_server_kick_responses();
+}
+
+static void
+__tapdisk_server_run(void)
+{
+ 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)
{
- int err;
-
- memset(&server, 0, sizeof(tapdisk_server_t));
+ memset(&server, 0, sizeof(server));
INIT_LIST_HEAD(&server.vbds);
scheduler_initialize(&server.scheduler);
+ return 0;
+}
+
+int
+tapdisk_server_complete(void)
+{
+ int err;
+
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 --git a/tools/blktap2/drivers/tapdisk-server.h b/tools/blktap2/drivers/tapdisk-server.h
index f401b049b2..d9c1a03bb5 100644
--- a/tools/blktap2/drivers/tapdisk-server.h
+++ b/tools/blktap2/drivers/tapdisk-server.h
@@ -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_driver_interface(int);
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 @@ event_id_t tapdisk_server_register_event(char, int, int, event_cb_t, void *);
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 --git a/tools/blktap2/drivers/tapdisk-vbd.c b/tools/blktap2/drivers/tapdisk-vbd.c
index f39fdadb1a..e6d18594ce 100644
--- a/tools/blktap2/drivers/tapdisk-vbd.c
+++ b/tools/blktap2/drivers/tapdisk-vbd.c
@@ -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)
{
- int i;
td_vbd_t *vbd;
-
- vbd = tapdisk_server_get_vbd(uuid);
- if (vbd) {
- EPRINTF("duplicate vbds! %u\n", uuid);
- return -EEXIST;
- }
+ int i;
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,30 +658,58 @@ 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_open(td_vbd_t *vbd, const char *name, uint16_t type,
- uint16_t storage, const char *ring, td_flag_t flags)
+tapdisk_vbd_attach(td_vbd_t *vbd, const char *devname, int minor)
{
int err;
- err = tapdisk_vbd_open_stack(vbd, storage, flags);
+ err = tapdisk_vbd_map_device(vbd, devname);
if (err)
- goto out;
+ goto fail;
- err = tapdisk_vbd_map_device(vbd, ring);
+ 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, int minor, const char *ring, td_flag_t flags)
+{
+ int err;
+
+ err = tapdisk_vbd_open_stack(vbd, storage, flags);
if (err)
goto out;
- err = tapdisk_vbd_register_event_watches(vbd);
+ err = tapdisk_vbd_attach(vbd, ring, minor);
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 char *path, uint16_t drivertype)
return -EINVAL;
}
- free(vbd->name);
- vbd->name = strdup(path);
- if (!vbd->name) {
- EPRINTF("copying new vbd %s name failed\n", path);
- return -EINVAL;
+ if (path) {
+ free(vbd->name);
+ vbd->name = strdup(path);
+ if (!vbd->name) {
+ EPRINTF("copying new vbd %s name failed\n", path);
+ return -EINVAL;
+ }
}
- vbd->type = drivertype;
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 char *path, uint16_t drivertype)
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 --git a/tools/blktap2/drivers/tapdisk-vbd.h b/tools/blktap2/drivers/tapdisk-vbd.h
index 0fea53e4f9..be084b2e03 100644
--- a/tools/blktap2/drivers/tapdisk-vbd.h
+++ b/tools/blktap2/drivers/tapdisk-vbd.h
@@ -89,7 +89,7 @@ struct td_vbd_handle {
char *name;
td_uuid_t uuid;
- int type;
+ int minor;
struct list_head driver_stack;
@@ -168,18 +168,24 @@ 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);
int tapdisk_vbd_get_image_info(td_vbd_t *, image_t *);
diff --git a/tools/blktap2/drivers/tapdisk2.c b/tools/blktap2/drivers/tapdisk2.c
index 0eb10cb5e5..d30f73984a 100644
--- a/tools/blktap2/drivers/tapdisk2.c
+++ b/tools/blktap2/drivers/tapdisk2.c
@@ -28,397 +28,37 @@
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
-#include <unistd.h>
#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
+#include <unistd.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;
+ }
+
+ 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);
+ }
}
- 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();
+ 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;
}