[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 08 of 21 RESEND] blktap3/drivers: Introduce handling of control commands



This patch copies the functionality of handling control commands from blktap2,
with changes coming from blktap2.5. Also, it contains the following
blktap3-related changes:
  * Replaced the minor number with type:/path/to/file or /path/to/file,
    depending on the occasion.
  * Removed VBD.attach/detach message handlers.
And the following optimisations/clean-up:
  * Removed the unused uuid member from struct tapdisk_control.
  * Simplified message handling: all message handler functions accept the
    response as an argument and the caller of these functions initialises this
    response and handles errors.

Signed-off-by: Thanos Makatos <thanos.makatos@xxxxxxxxxx>

diff --git a/tools/blktap2/drivers/tapdisk-control.c 
b/tools/blktap3/drivers/tapdisk-control.c
copy from tools/blktap2/drivers/tapdisk-control.c
copy to tools/blktap3/drivers/tapdisk-control.c
--- a/tools/blktap2/drivers/tapdisk-control.c
+++ b/tools/blktap3/drivers/tapdisk-control.c
@@ -25,6 +25,7 @@
  * 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>
@@ -37,42 +38,350 @@
 #include <sys/types.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
+#include <sys/mman.h>
+#include <sys/select.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"
+#include "tapdisk-stats.h"
+#include "tapdisk-control.h"
+#include "sring/td-blkif.h"
+
+#define TD_CTL_MAX_CONNECTIONS  10
+#define TD_CTL_SOCK_BACKLOG     32
+#define TD_CTL_RECV_TIMEOUT     10
+#define TD_CTL_SEND_TIMEOUT     10
+#define TD_CTL_SEND_BUFSZ       ((size_t)4096)
+
+#define DBG(_f, _a...)             tlog_syslog(LOG_DEBUG, "%s:%d " _f, \
+        __FILE__, __LINE__, ##_a)
+#define ERR(err, _f, _a...)        tlog_error(err, "%s:%d " _f, __FILE__, \
+    __LINE__, ##_a)
+
+#define ASSERT(_p)                                                     \
+       if (!(_p)) {                                                    \
+               EPRINTF("%s:%d: FAILED ASSERTION: '%s'\n",              \
+                       __FILE__, __LINE__, #_p);                       \
+               td_panic();                                             \
+       }
+
+#define WARN_ON(_p)                                                    \
+       if (_p) {                                                       \
+               EPRINTF("%s:%d: WARNING: '%s'\n",                       \
+                       __FILE__, __LINE__, #_p);                       \
+       }
+
+struct tapdisk_ctl_conn {
+    int fd;
+
+    struct {
+        void *buf;
+        size_t bufsz;
+        int event_id;
+        int done;
+
+        void *prod;
+        void *cons;
+    } out;
+
+    struct {
+        int event_id;
+        int busy;
+    } in;
+
+    struct tapdisk_control_info *info;
+};
+
+#define TAPDISK_MSG_REENTER    (1<<0)   /* non-blocking, idempotent */
+#define TAPDISK_MSG_VERBOSE    (1<<1)   /* tell syslog about it */
+#define TAPDISK_MSG_VERBOSE_ERROR (1<<2)    /* tell syslog about it, with 
errors */
+
+struct tapdisk_control_info {
+    int (*handler) (struct tapdisk_ctl_conn *, tapdisk_message_t *,
+            tapdisk_message_t * const);
+    int flags;
+};
 
 struct tapdisk_control {
        char              *path;
        int                socket;
        int                event_id;
-};
+    int busy;
 
-struct tapdisk_control_connection {
-       int                socket;
-       event_id_t         event_id;
+    int n_conn;
+    struct tapdisk_ctl_conn __conn[TD_CTL_MAX_CONNECTIONS];
+    struct tapdisk_ctl_conn *conn[TD_CTL_MAX_CONNECTIONS];
 };
 
 static struct tapdisk_control td_control;
 
+static inline size_t page_align(size_t size)
+{
+    size_t page_size = sysconf(_SC_PAGE_SIZE);
+    return (size + page_size - 1) & ~(page_size - 1);
+}
+
+static void tapdisk_ctl_conn_uninit(struct tapdisk_ctl_conn *conn)
+{
+    if (conn->out.buf) {
+        munmap(conn->out.buf, conn->out.bufsz);
+        conn->out.buf = NULL;
+    }
+}
+
+static int
+tapdisk_ctl_conn_init(struct tapdisk_ctl_conn *conn, size_t bufsz)
+{
+    int prot, flags, err;
+
+    memset(conn, 0, sizeof(*conn));
+    conn->out.event_id = -1;
+    conn->in.event_id = -1;
+
+    prot = PROT_READ | PROT_WRITE;
+    flags = MAP_ANONYMOUS | MAP_PRIVATE;
+
+    conn->out.buf = mmap(NULL, bufsz, prot, flags, -1, 0);
+    if (conn->out.buf == MAP_FAILED) {
+        conn->out.buf = NULL;
+        err = -ENOMEM;
+        goto fail;
+    }
+    conn->out.bufsz = page_align(bufsz);
+
+    return 0;
+
+  fail:
+    tapdisk_ctl_conn_uninit(conn);
+    return err;
+}
+
+static int tapdisk_ctl_conn_connected(struct tapdisk_ctl_conn *conn)
+{
+    return conn->fd >= 1;
+}
+
+static void tapdisk_ctl_conn_free(struct tapdisk_ctl_conn *conn)
+{
+    struct tapdisk_ctl_conn *prev, *next;
+    int i;
+
+    i = --td_control.n_conn;
+    /* NB. bubble the freed connection off the active list. */
+    prev = conn;
+    do {
+        ASSERT(i >= 0);
+        next = td_control.conn[i];
+        td_control.conn[i] = prev;
+        prev = next;
+        i--;
+    } while (next != conn);
+}
+
+static void tapdisk_ctl_conn_close(struct tapdisk_ctl_conn *conn)
+{
+    if (conn->out.event_id >= 0) {
+        tapdisk_server_unregister_event(conn->out.event_id);
+        conn->out.event_id = -1;
+    }
+
+    if (conn->fd >= 0) {
+        close(conn->fd);
+        conn->fd = -1;
+
+        tapdisk_ctl_conn_free(conn);
+        tapdisk_server_mask_event(td_control.event_id, 0);
+    }
+}
+
+static void tapdisk_ctl_conn_mask_out(struct tapdisk_ctl_conn *conn)
+{
+    tapdisk_server_mask_event(conn->out.event_id, 1);
+}
+
+static void tapdisk_ctl_conn_unmask_out(struct tapdisk_ctl_conn *conn)
+{
+    tapdisk_server_mask_event(conn->out.event_id, 0);
+}
+
+static ssize_t tapdisk_ctl_conn_send_buf(struct tapdisk_ctl_conn *conn)
+{
+    ssize_t size;
+
+    size = conn->out.prod - conn->out.cons;
+    if (!size)
+        return 0;
+
+    size = send(conn->fd, conn->out.cons, size, MSG_DONTWAIT);
+    if (size < 0)
+        return -errno;
+
+    conn->out.cons += size;
+
+    return size;
+}
+
 static void
-tapdisk_control_initialize(void)
+tapdisk_ctl_conn_send_event(event_id_t id __attribute__((unused)), char mode,
+        void *private)
 {
+    struct tapdisk_ctl_conn *conn = private;
+    ssize_t rv;
+
+    do {
+        rv = tapdisk_ctl_conn_send_buf(conn);
+    } while (rv > 0);
+
+    if (rv == -EAGAIN)
+        return;
+
+    if (rv < 0)
+        ERR(rv, "failure sending message at offset %td/%td\n",
+            conn->out.cons - conn->out.buf,
+            conn->out.prod - conn->out.buf);
+
+    if (rv || conn->out.done || mode & SCHEDULER_POLL_TIMEOUT)
+        tapdisk_ctl_conn_close(conn);
+    else
+        tapdisk_ctl_conn_mask_out(conn);
+}
+
+/*
+ * NB. the control interface is still not properly integrated into the
+ * server, therefore neither the scheduler. After the last close, the
+ * server will exit but we still have a pending close response in the
+ * output buffer.
+ */
+static void tapdisk_ctl_conn_drain(struct tapdisk_ctl_conn *conn)
+{
+    struct timeval tv = {.tv_sec = TD_CTL_SEND_TIMEOUT,
+        .tv_usec = 0
+    };
+    fd_set wfds;
+    int n, mode;
+
+    ASSERT(conn->out.done);
+    ASSERT(conn->fd >= 0);
+
+    while (tapdisk_ctl_conn_connected(conn)) {
+        FD_ZERO(&wfds);
+        FD_SET(conn->fd, &wfds);
+
+        n = select(conn->fd + 1, NULL, &wfds, NULL, &tv);
+        if (n < 0)
+            break;
+
+        if (n)
+            mode = SCHEDULER_POLL_WRITE_FD;
+        else
+            mode = SCHEDULER_POLL_TIMEOUT;
+
+        tapdisk_ctl_conn_send_event(conn->out.event_id, mode, conn);
+    }
+}
+
+
+struct tapdisk_ctl_conn *tapdisk_ctl_conn_open(int fd)
+{
+    struct tapdisk_ctl_conn *conn;
+
+    if (td_control.n_conn >= TD_CTL_MAX_CONNECTIONS)
+        return NULL;
+
+    conn = td_control.conn[td_control.n_conn++];
+
+    conn->out.event_id =
+        tapdisk_server_register_event(SCHEDULER_POLL_WRITE_FD,
+                                      fd, TD_CTL_SEND_TIMEOUT,
+                                      tapdisk_ctl_conn_send_event, conn);
+    if (conn->out.event_id < 0)
+        return NULL;
+
+    conn->fd = fd;
+    conn->out.prod = conn->out.buf;
+    conn->out.cons = conn->out.buf;
+
+    tapdisk_ctl_conn_mask_out(conn);
+
+    if (td_control.n_conn >= TD_CTL_MAX_CONNECTIONS)
+        tapdisk_server_mask_event(td_control.event_id, 1);
+
+    return conn;
+}
+
+static size_t
+tapdisk_ctl_conn_write(struct tapdisk_ctl_conn *conn, void *buf,
+                       size_t size)
+{
+    size_t rest;
+
+    rest = conn->out.buf + conn->out.bufsz - conn->out.prod;
+    if (rest < size)
+        size = rest;
+    if (!size)
+        return 0;
+
+    memcpy(conn->out.prod, buf, size);
+    conn->out.prod += size;
+    tapdisk_ctl_conn_unmask_out(conn);
+
+    return size;
+}
+
+static void tapdisk_ctl_conn_release(struct tapdisk_ctl_conn *conn)
+{
+    conn->out.done = 1;
+
+    if (conn->out.prod == conn->out.cons)
+        tapdisk_ctl_conn_close(conn);
+}
+
+static void tapdisk_control_initialize(void)
+{
+    struct tapdisk_ctl_conn *conn;
+    int i;
+
        td_control.socket   = -1;
        td_control.event_id = -1;
 
        signal(SIGPIPE, SIG_IGN);
+
+    for (i = 0; i < TD_CTL_MAX_CONNECTIONS; i++) {
+        conn = &td_control.__conn[i];
+        tapdisk_ctl_conn_init(conn, TD_CTL_SEND_BUFSZ);
+        td_control.conn[i] = conn;
 }
 
-void
-tapdisk_control_close(void)
+    td_control.n_conn = 0;
+
+    DPRINTF("tapdisk-control: init, %d x %zuk buffers\n",
+            TD_CTL_MAX_CONNECTIONS, TD_CTL_SEND_BUFSZ >> 10);
+}
+
+void tapdisk_control_close(void)
 {
+    struct tapdisk_ctl_conn *conn;
+    int i;
+
+    DPRINTF("tapdisk-control: draining %d connections\n",
+            td_control.n_conn);
+
+    while (td_control.n_conn) {
+        conn = td_control.conn[td_control.n_conn - 1];
+        tapdisk_ctl_conn_drain(conn);
+    }
+
+    for (i = 0; i < TD_CTL_MAX_CONNECTIONS; i++) {
+        conn = &td_control.__conn[i];
+        tapdisk_ctl_conn_uninit(conn);
+    }
+
+    DPRINTF("tapdisk-control: done\n");
+
        if (td_control.path) {
                unlink(td_control.path);
                free(td_control.path);
@@ -85,40 +394,41 @@ tapdisk_control_close(void)
        }
 }
 
-static struct tapdisk_control_connection *
-tapdisk_control_allocate_connection(int fd)
+static void
+tapdisk_control_release_connection(struct tapdisk_ctl_conn *conn)
 {
-       struct tapdisk_control_connection *connection;
-       size_t sz;
-
-       connection = calloc(1, sizeof(*connection));
-       if (!connection) {
-               EPRINTF("calloc");
-               return NULL;
+    if (conn->in.event_id) {
+        tapdisk_server_unregister_event(conn->in.event_id);
+        conn->in.event_id = -1;
        }
 
-       connection->socket = fd;
-       return connection;
+    tapdisk_ctl_conn_release(conn);
 }
 
 static void
-tapdisk_control_close_connection(struct tapdisk_control_connection *connection)
+tapdisk_control_close_connection(struct tapdisk_ctl_conn *conn)
 {
-       tapdisk_server_unregister_event(connection->event_id);
-       close(connection->socket);
-       free(connection);
+    tapdisk_control_release_connection(conn);
+
+    if (tapdisk_ctl_conn_connected(conn))
+        /* NB. best effort for write/close sequences. */
+        tapdisk_ctl_conn_send_buf(conn);
+
+    tapdisk_ctl_conn_close(conn);
 }
 
+
 static int
-tapdisk_control_read_message(int fd, tapdisk_message_t *message, int timeout)
+tapdisk_control_read_message(int fd, tapdisk_message_t * message,
+                             int timeout)
 {
+    const int len = sizeof(tapdisk_message_t);
        fd_set readfds;
-       int ret, len, offset;
+    int ret, offset, err = 0;
        struct timeval tv, *t;
 
        t      = NULL;
        offset = 0;
-       len    = sizeof(tapdisk_message_t);
 
        if (timeout) {
                tv.tv_sec  = timeout;
@@ -144,67 +454,31 @@ tapdisk_control_read_message(int fd, tap
                        break;
        }
 
-       if (offset != len) {
-               EPRINTF("failure reading message (wanted %d but got %d)\n",
-                       len, offset);
-               return -EIO;
-       }
+    if (ret < 0)
+        err = -errno;
+    else if (offset != len)
+        err = -EIO;
+    if (err)
+        ERR(err, "failure reading message at offset %d/%d\n", offset, len);
 
-       DPRINTF("received '%s' message (uuid = %u)\n",
-               tapdisk_message_name(message->type), message->cookie);
 
-       return 0;
+    return err;
 }
 
-static int
-tapdisk_control_write_message(int fd, tapdisk_message_t *message, int timeout)
+static void
+tapdisk_control_write_message(struct tapdisk_ctl_conn *conn,
+                              tapdisk_message_t * message)
 {
-       fd_set writefds;
-       int ret, len, offset;
-       struct timeval tv, *t;
+    size_t size = sizeof(*message), count;
 
-       t      = NULL;
-       offset = 0;
-       len    = sizeof(tapdisk_message_t);
+    if (conn->info->flags & TAPDISK_MSG_VERBOSE)
+        DBG("sending '%s' message\n", tapdisk_message_name(message->type));
 
-       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;
+    count = tapdisk_ctl_conn_write(conn, message, size);
+    WARN_ON(count != size);
 }
 
-static int
-tapdisk_control_validate_request(tapdisk_message_t *request)
+static int tapdisk_control_validate_request(tapdisk_message_t * request)
 {
        if (strnlen(request->u.params.path,
                    TAPDISK_MESSAGE_MAX_PATH_LENGTH) >=
@@ -214,8 +488,10 @@ tapdisk_control_validate_request(tapdisk
        return 0;
 }
 
+/* XXX Commented out in blktap2.5. */
+#if 0
 static void
-tapdisk_control_list_minors(struct tapdisk_control_connection *connection,
+tapdisk_control_list_minors(struct tapdisk_ctl_conn *conn,
                            tapdisk_message_t *request)
 {
        int i;
@@ -232,7 +508,11 @@ tapdisk_control_list_minors(struct tapdi
        head = tapdisk_server_get_all_vbds();
 
        list_for_each_entry(vbd, head, next) {
-               response.u.minors.list[i++] = vbd->minor;
+        td_blktap_t *tap = vbd->tap;
+        if (!tap)
+            continue;
+
+        response.u.minors.list[i++] = tap->minor;
                if (i >= TAPDISK_MESSAGE_MAX_MINORS) {
                        response.type = TAPDISK_MESSAGE_ERROR;
                        response.u.response.error = ERANGE;
@@ -241,194 +521,101 @@ tapdisk_control_list_minors(struct tapdi
        }
 
        response.u.minors.count = i;
-       tapdisk_control_write_message(connection->socket, &response, 2);
-       tapdisk_control_close_connection(connection);
+    tapdisk_ctl_conn_write(conn, &response, 2);
 }
+#endif
 
-static void
-tapdisk_control_list(struct tapdisk_control_connection *connection,
-                    tapdisk_message_t *request)
+static int
+tapdisk_control_list(struct tapdisk_ctl_conn *conn,
+                    tapdisk_message_t *request, tapdisk_message_t * const 
response)
 {
        td_vbd_t *vbd;
-       struct list_head *head;
-       tapdisk_message_t response;
-       int count, i;
+    struct tqh_td_vbd_handle *head;
+    int count;
 
-       memset(&response, 0, sizeof(response));
-       response.type = TAPDISK_MESSAGE_LIST_RSP;
-       response.cookie = request->cookie;
+    assert(conn);
+    assert(request);
+    assert(response);
+
+       response->type = TAPDISK_MESSAGE_LIST_RSP;
 
        head = tapdisk_server_get_all_vbds();
 
+    /*
+     * Count all the VBDs.
+     * TODO avoid this by maintaining this number?
+     */
        count = 0;
-       list_for_each_entry(vbd, head, next)
+    TAILQ_FOREACH(vbd, head, entry)
                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;
+    TAILQ_FOREACH(vbd, head, entry) {
+               response->u.list.count   = count--;
+               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);
-               }
+        if (vbd->name)
+            strncpy(response->u.list.path, vbd->name,
+                    sizeof(response->u.list.path));
 
-               tapdisk_control_write_message(connection->socket, &response, 2);
+        tapdisk_control_write_message(conn, response);
        }
 
-       response.u.list.count   = count;
-       response.u.list.minor   = -1;
-       response.u.list.path[0] = 0;
+       response->u.list.count   = count;
+       response->u.list.path[0] = 0;
 
-       tapdisk_control_write_message(connection->socket, &response, 2);
-       tapdisk_control_close_connection(connection);
+    return 0;
 }
 
-static void
-tapdisk_control_get_pid(struct tapdisk_control_connection *connection,
-                       tapdisk_message_t *request)
+static int
+tapdisk_control_get_pid(struct tapdisk_ctl_conn *conn __attribute__((unused)),
+                       tapdisk_message_t *request __attribute__((unused)),
+            tapdisk_message_t * const response)
 {
-       tapdisk_message_t response;
+    assert(response);
 
-       memset(&response, 0, sizeof(response));
-       response.type = TAPDISK_MESSAGE_PID_RSP;
-       response.cookie = request->cookie;
-       response.u.tapdisk_pid = getpid();
+       response->type = TAPDISK_MESSAGE_PID_RSP;
+       response->u.tapdisk_pid = getpid();
 
-       tapdisk_control_write_message(connection->socket, &response, 2);
-       tapdisk_control_close_connection(connection);
+    return 0;
 }
 
-static void
-tapdisk_control_attach_vbd(struct tapdisk_control_connection *connection,
-                          tapdisk_message_t *request)
+static int
+tapdisk_control_open_image(
+        struct tapdisk_ctl_conn *conn __attribute__((unused)),
+        tapdisk_message_t *request, tapdisk_message_t * const response)
 {
-       tapdisk_message_t response;
-       char *devname;
+       int err;
        td_vbd_t *vbd;
-       struct blktap2_params params;
-       image_t image;
-       int minor, err;
+       td_flag_t flags;
+    td_disk_info_t info;
+    int prt_path_len;
+    char * prt_path;
 
-       /*
-        * TODO: check for max vbds per process
-        */
+    assert(request);
+    assert(response);
 
-       vbd = tapdisk_server_get_vbd(request->cookie);
-       if (vbd) {
-               err = -EEXIST;
-               goto out;
-       }
+    /* TODO Check whether the image is already open by another VBD? */
+    prt_path_len = strnlen(request->u.params.prt_path,
+            TAPDISK_MESSAGE_MAX_PATH_LENGTH);
+    if (unlikely(prt_path_len == TAPDISK_MESSAGE_MAX_PATH_LENGTH)) {
+        err = -EINVAL;
+        goto out;
+    } else if (prt_path_len == 0)
+        prt_path = NULL;
+    else
+        prt_path = request->u.params.prt_path;
 
-       minor = request->cookie;
-       if (minor < 0) {
-               err = -EINVAL;
-               goto out;
-       }
-
-       vbd = tapdisk_vbd_create(minor);
+    vbd = tapdisk_vbd_create();
        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;
-
+    /* TODO Add after everything has been initialised? */
        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;
-       }
-
+    /* TODO check for unsupported flags */
        flags = 0;
        if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_RDONLY)
                flags |= TD_OPEN_RDONLY;
@@ -440,83 +627,92 @@ tapdisk_control_open_image(struct tapdis
                flags |= TD_OPEN_VHD_INDEX;
        if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_LOG_DIRTY)
                flags |= TD_OPEN_LOG_DIRTY;
+    if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_ADD_LCACHE)
+        flags |= TD_OPEN_LOCAL_CACHE;
+    if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_REUSE_PRT)
+        flags |= TD_OPEN_REUSE_PARENT;
+    if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_STANDBY)
+        flags |= TD_OPEN_STANDBY;
+    if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_SECONDARY) {
+        char *name = strdup(request->u.params.secondary);
+        if (!name) {
+            err = -errno;
+                   goto out;
+       }
+        vbd->secondary_name = name;
+        flags |= TD_OPEN_SECONDARY;
+    }
 
-       vbd->name = strndup(request->u.params.path,
-                           sizeof(request->u.params.path));
-       if (!vbd->name) {
-               err = -ENOMEM;
+    err = tapdisk_vbd_open_vdi(vbd, request->u.params.path, flags, prt_path);
+    if (err) {
+        EPRINTF("failed to open VDI: %s\n", strerror(-err));
                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;
-       strncpy(params.name, vbd->name, BLKTAP2_MAX_MESSAGE_LEN);
-
-       err = ioctl(vbd->ring.fd, BLKTAP2_IOCTL_CREATE_DEVICE, &params);
-       if (err && errno != EEXIST) {
-               err = -errno;
-               EPRINTF("create device failed: %d\n", err);
+    err = tapdisk_vbd_get_disk_info(vbd, &info);
+    if (err) {
+        EPRINTF("failed to get disk info: %s\n", strerror(-err));
                goto fail_close;
        }
 
        err = 0;
 
 out:
-       memset(&response, 0, sizeof(response));
-       response.cookie = request->cookie;
+    if (!err) {
+        response->u.image.sectors = info.size;
+        response->u.image.sector_size = info.sector_size;
+        response->u.image.info = info.info;
+        response->type = TAPDISK_MESSAGE_OPEN_RSP;
+    }
 
-       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;
+       return err;
 
 fail_close:
        tapdisk_vbd_close_vdi(vbd);
-       free(vbd->name);
-       vbd->name = NULL;
+
+    if (vbd->name) {
+        free(vbd->name);
+        vbd->name = NULL;
+    }
+
        goto out;
 }
 
-static void
-tapdisk_control_close_image(struct tapdisk_control_connection *connection,
-                           tapdisk_message_t *request)
+static int
+tapdisk_control_close_image(struct tapdisk_ctl_conn *conn,
+        tapdisk_message_t *request, tapdisk_message_t * const response)
 {
-       tapdisk_message_t response;
        td_vbd_t *vbd;
-       int err;
+       int err = 0;
+    int len;
 
-       vbd = tapdisk_server_get_vbd(request->cookie);
+    assert(conn);
+    assert(request);
+    assert(response);
+
+    len = strnlen(request->u.string.text, TAPDISK_MESSAGE_STRING_LENGTH);
+    if (len < 1) {
+        err = -EINVAL;
+        goto out;
+    }
+    if (len >= TAPDISK_MESSAGE_STRING_LENGTH) {
+        err = -ENAMETOOLONG;
+        goto out;
+    }
+
+       vbd = tapdisk_server_get_vbd(request->u.string.text);
        if (!vbd) {
-               err = -EINVAL;
+        EPRINTF("no VBD \'%s\'", request->u.string.text);
+        err = -ENODEV;
                goto out;
        }
 
-       if (!list_empty(&vbd->pending_requests)) {
-               err = -EAGAIN;
-               goto out;
-       }
+    /* TODO How do we make sure that new requests won't enter the ring?
+     * I assume we have disconnected from the ring before? If yes, then
+     * make sure we check this. */
+
+    while (!TAILQ_EMPTY(&vbd->pending_requests))
+        tapdisk_server_iterate();
 
        tapdisk_vbd_close_vdi(vbd);
 
@@ -526,35 +722,45 @@ tapdisk_control_close_image(struct tapdi
        free(vbd->name);
        vbd->name = NULL;
 
-       if (vbd->minor == -1) {
-               tapdisk_server_remove_vbd(vbd);
-               tapdisk_vbd_free(vbd);
+    tapdisk_server_remove_vbd(vbd);
+
+out:
+    if (!err) {
+        response->type = TAPDISK_MESSAGE_CLOSE_RSP;
+        response->u.response.error = -err;
        }
 
-       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);
+    return err;
 }
 
-static void
-tapdisk_control_pause_vbd(struct tapdisk_control_connection *connection,
-                         tapdisk_message_t *request)
+static int
+tapdisk_control_pause_vbd(struct tapdisk_ctl_conn *conn,
+                         tapdisk_message_t *request, tapdisk_message_t * const 
response)
 {
        int err;
        td_vbd_t *vbd;
-       tapdisk_message_t response;
+    int len;
 
-       memset(&response, 0, sizeof(response));
+    assert(conn);
+    assert(request);
+    assert(response);
 
-       response.type = TAPDISK_MESSAGE_PAUSE_RSP;
+    len = strnlen(request->u.string.text, TAPDISK_MESSAGE_STRING_LENGTH);
 
-       vbd = tapdisk_server_get_vbd(request->cookie);
+    /* TODO boilerplate */
+    if (len < 1) {
+        err = -EINVAL;
+        goto out;
+    }
+    if (len >= TAPDISK_MESSAGE_STRING_LENGTH) {
+        err = -ENAMETOOLONG;
+        goto out;
+    }
+
+       response->type = TAPDISK_MESSAGE_PAUSE_RSP;
+
+    /* TODO Need to fix this in control/tap-ctl-pause.c */
+       vbd = tapdisk_server_get_vbd(request->u.string.text);
        if (!vbd) {
                err = -EINVAL;
                goto out;
@@ -567,155 +773,429 @@ tapdisk_control_pause_vbd(struct tapdisk
                        break;
 
                tapdisk_server_iterate();
-       } while (1);
+
+    } while (conn->fd >= 0);
 
 out:
-       response.cookie = request->cookie;
-       response.u.response.error = -err;
-       tapdisk_control_write_message(connection->socket, &response, 2);
-       tapdisk_control_close_connection(connection);
+    if (!err)
+        /* TODO useless? */
+       response->u.response.error = -err;
+    return err;
 }
 
-static void
-tapdisk_control_resume_vbd(struct tapdisk_control_connection *connection,
-                          tapdisk_message_t *request)
+static int
+tapdisk_control_resume_vbd(
+        struct tapdisk_ctl_conn *conn __attribute__((unused)),
+        tapdisk_message_t *request, tapdisk_message_t * const response)
 {
        int err;
        td_vbd_t *vbd;
-       tapdisk_message_t response;
+    const char *desc = NULL;
+    int len;
 
-       memset(&response, 0, sizeof(response));
+    assert(request);
+    assert(response);
 
-       response.type = TAPDISK_MESSAGE_RESUME_RSP;
+    len = strnlen(request->u.string.text, TAPDISK_MESSAGE_STRING_LENGTH);
 
-       vbd = tapdisk_server_get_vbd(request->cookie);
+    /* TODO boilerplate */
+    if (len < 1) {
+        err = -EINVAL;
+        goto out;
+    }
+    if (len >= TAPDISK_MESSAGE_STRING_LENGTH) {
+        err = -ENAMETOOLONG;
+        goto out;
+    }
+
+       response->type = TAPDISK_MESSAGE_RESUME_RSP;
+
+    /* TODO Need to fix this in control/tap-ctl-pause.c */
+       vbd = tapdisk_server_get_vbd(request->u.string.text);
        if (!vbd) {
                err = -EINVAL;
                goto out;
        }
 
-       if (!td_flag_test(vbd->state, TD_VBD_PAUSED)) {
-               err = -EINVAL;
-               goto out;
+    /* TODO What's this path? */
+    if (request->u.params.path[0])
+        desc = request->u.params.path;
+
+    err = tapdisk_vbd_resume(vbd, desc);
+out:
+    if (!err)
+        /* TODO useless? */
+        response->u.response.error = -err;
+    return err;
+}
+
+static int
+tapdisk_control_stats(struct tapdisk_ctl_conn *conn __attribute__((unused)),
+        tapdisk_message_t * request, tapdisk_message_t * const response)
+{
+    td_stats_t _st, *st = &_st;
+    td_vbd_t *vbd;
+    size_t rv = 0;
+    int err = 0;
+    int len;
+
+    assert(request);
+    assert(response);
+
+    len = strnlen(request->u.string.text, TAPDISK_MESSAGE_STRING_LENGTH);
+
+    tapdisk_stats_init(st,
+                       conn->out.buf + sizeof(*response),
+                       conn->out.bufsz - sizeof(*response));
+    if (len > 1) {
+        if (len >= TAPDISK_MESSAGE_STRING_LENGTH) {
+            err = -ENAMETOOLONG;
+            goto out;
+        }
+
+        vbd = tapdisk_server_get_vbd(request->u.string.text);
+        if (!vbd) {
+            err = -ENODEV;
+                       goto out;
+               }
+
+        tapdisk_vbd_stats(vbd, st);
+
+    } else {
+        struct tqh_td_vbd_handle *list = tapdisk_server_get_all_vbds();
+
+        tapdisk_stats_enter(st, '[');
+
+        TAILQ_FOREACH(vbd, list, entry)
+            tapdisk_vbd_stats(vbd, st);
+
+        tapdisk_stats_leave(st, ']');
        }
 
-       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;
+    rv = tapdisk_stats_length(st);
+out:
+    if (!err) {
+        response->type = TAPDISK_MESSAGE_STATS_RSP;
+        response->u.info.length = rv;
+    }
+
+    /* TODO Should only be executed if err == 0? */
+    if (rv > 0)
+        conn->out.prod += rv;
+
+    return err;
+}
+
+/**
+ * Message handler executed for TAPDISK_MESSAGE_XENBLKIF_CONNECT.
+ *
+ * This is the entry point for connecting the tapdisk to the shared ring. It
+ * also sets up the necessary structures/descriptors (TODO explain).
+ */
+static int
+tapdisk_control_xenblkif_connect(
+        struct tapdisk_ctl_conn *conn __attribute__((unused)),
+        tapdisk_message_t *request, tapdisk_message_t * const response)
+{
+    /*
+     * Get the block interface parameters (domain ID, device ID, etc.).
+     */
+    tapdisk_message_blkif_t *blkif;
+
+    td_vbd_t *vbd;
+    const char *pool;
+    size_t len;
+    int err;
+
+    assert(request);
+    assert(response);
+
+    len = strnlen(request->u.string.text, TAPDISK_MESSAGE_STRING_LENGTH);
+    /* TODO boilerplate */
+    if (len < 1) {
+        err = -EINVAL;
+        goto out;
+    }
+    if (len >= TAPDISK_MESSAGE_STRING_LENGTH) {
+        err = -ENAMETOOLONG;
+        goto out;
+    }
+
+    vbd = tapdisk_server_get_vbd(request->u.blkif.params);
+    if (!vbd) {
+        err = -ENODEV;
                goto out;
+    }
+
+    blkif = &request->u.blkif;
+    len = strnlen(blkif->pool, sizeof(blkif->pool));
+    if (!len)
+        pool = NULL;
+    else if (len >= sizeof(blkif->pool)) {
+        err = -EINVAL;
+               goto out;
+    } else
+        pool = blkif->pool;
+
+    DPRINTF("connecting VBD domid=%d, devid=%d, pool %s, evt %d\n",
+            blkif->domid, blkif->devid, pool, blkif->port);
+
+    err = tapdisk_xenblkif_connect(blkif->domid, blkif->devid, blkif->gref,
+            blkif->order, blkif->port, blkif->proto, pool, vbd);
+out:
+    if (!err) {
+        response->type = TAPDISK_MESSAGE_XENBLKIF_CONNECT_RSP;
+        /* TODO Useless? */
+           response->u.response.error = -err;
+    }
+    return err;
+}
+
+static int
+tapdisk_control_xenblkif_disconnect(
+        struct tapdisk_ctl_conn *conn __attribute__((unused)),
+        tapdisk_message_t * request, tapdisk_message_t * const response)
+{
+    tapdisk_message_blkif_t *blkif;
+       int err;
+
+    assert(request);
+    assert(response);
+
+    blkif = &request->u.blkif;
+
+    DPRINTF("disconnecting VBD domid=%d, devid=%d\n", blkif->domid,
+            blkif->devid);
+
+    err = tapdisk_xenblkif_disconnect(blkif->domid, blkif->devid);
+
+    if (!err) {
+        response->type = TAPDISK_MESSAGE_XENBLKIF_DISCONNECT_RSP;
+        /* TODO Useless? */
+        response->u.response.error = -err;
+    }
+    return err;
+}
+
+static int
+tapdisk_control_disk_info(
+        struct tapdisk_ctl_conn *conn __attribute__((unused)),
+        tapdisk_message_t * request, tapdisk_message_t * const response)
+{
+    tapdisk_message_image_t *image;
+    int err;
+    td_vbd_t *vbd;
+    td_disk_info_t info;
+    int len;
+
+    assert(request);
+    assert(response);
+
+    image = &response->u.image;
+    len = strnlen(request->u.string.text, TAPDISK_MESSAGE_STRING_LENGTH);
+
+    /* TODO boilerplate */
+    if (len < 1) {
+        err = -EINVAL;
+        goto out;
+    }
+    if (len >= TAPDISK_MESSAGE_STRING_LENGTH) {
+        err = -ENAMETOOLONG;
+        goto out;
+    }
+
+    DPRINTF("getting info vbd %s\n", request->u.string.text);
+
+    vbd = tapdisk_server_get_vbd(request->u.string.text);
+    if (!vbd) {
+        err = -ENODEV;
+        goto out;
        }
 
-       err = tapdisk_vbd_parse_stack(vbd, vbd->name);
-       if (err)
-               goto out;
+    err = tapdisk_vbd_get_disk_info(vbd, &info);
+    if (err) {
+        EPRINTF("tapdisk_vbd_get_disk_info failed %d\n", err);
+        goto out;
+    }
 
-       err = tapdisk_vbd_resume(vbd, NULL, -1);
-       if (err)
-               goto out;
-
+    EPRINTF("got disk info: %ld %d\n", info.sector_size, err);
 out:
-       response.cookie = request->cookie;
-       response.u.response.error = -err;
-       tapdisk_control_write_message(connection->socket, &response, 2);
-       tapdisk_control_close_connection(connection);
+    if (!err) {
+        response->type = TAPDISK_MESSAGE_DISK_INFO_RSP;
+        image->sectors = info.size;
+        image->sector_size = info.sector_size;
+        image->info = info.info;
+    }
+    return err;
 }
 
-static void
-tapdisk_control_handle_request(event_id_t id, char mode, void *private)
+struct tapdisk_control_info message_infos[] = {
+    [TAPDISK_MESSAGE_PID] = {
+                             .handler = tapdisk_control_get_pid,
+                             .flags = TAPDISK_MSG_REENTER,
+                             },
+    [TAPDISK_MESSAGE_LIST] = {
+                              .handler = tapdisk_control_list,
+                              .flags = TAPDISK_MSG_REENTER,
+                              },
+    [TAPDISK_MESSAGE_OPEN] = {
+                              .handler = tapdisk_control_open_image,
+                              .flags = TAPDISK_MSG_VERBOSE,
+                              },
+    [TAPDISK_MESSAGE_PAUSE] = {
+                               .handler = tapdisk_control_pause_vbd,
+                               .flags = TAPDISK_MSG_VERBOSE,
+                               },
+    [TAPDISK_MESSAGE_RESUME] = {
+                                .handler = tapdisk_control_resume_vbd,
+                                .flags = TAPDISK_MSG_VERBOSE,
+                                },
+    [TAPDISK_MESSAGE_CLOSE] = {
+                               .handler = tapdisk_control_close_image,
+                               .flags = TAPDISK_MSG_VERBOSE,
+                               },
+    [TAPDISK_MESSAGE_STATS] = {
+                               .handler = tapdisk_control_stats,
+                               .flags = TAPDISK_MSG_REENTER,
+                               },
+    [TAPDISK_MESSAGE_XENBLKIF_CONNECT] = {
+                                          .handler =
+                                          tapdisk_control_xenblkif_connect,
+                                          .flags =
+                                          TAPDISK_MSG_VERBOSE |
+                                          TAPDISK_MSG_VERBOSE_ERROR,
+                                          },
+    [TAPDISK_MESSAGE_XENBLKIF_DISCONNECT] = {
+                                             .handler =
+                                             
tapdisk_control_xenblkif_disconnect,
+                                             .flags = TAPDISK_MSG_VERBOSE
+                                             || TAPDISK_MSG_VERBOSE_ERROR,
+                                             },
+    [TAPDISK_MESSAGE_DISK_INFO] = {
+                                   .handler = tapdisk_control_disk_info,
+                                   .flags =
+                                   TAPDISK_MSG_VERBOSE |
+                                   TAPDISK_MSG_VERBOSE_ERROR,
+                                   },
+};
+
+
+static void tapdisk_control_handle_request(
+        event_id_t id __attribute__((unused)),
+        char mode __attribute__((unused)), void *private)
 {
-       int err;
-       tapdisk_message_t message;
-       struct tapdisk_control_connection *connection =
-               (struct tapdisk_control_connection *)private;
+    int err, excl;
+    tapdisk_message_t message, response;
+    struct tapdisk_ctl_conn *conn = private;
+    struct tapdisk_control_info *info;
 
-       if (tapdisk_control_read_message(connection->socket, &message, 2)) {
-               EPRINTF("failed to read message from %d\n", connection->socket);
-               tapdisk_control_close_connection(connection);
+    err = tapdisk_control_read_message(conn->fd, &message, 2);
+    if (err)
+        goto close;
+
+    if (conn->in.busy)
+        goto busy;
+
+       err = tapdisk_control_validate_request(&message);
+       if (err)
+        goto invalid;
+
+    if (message.type > TAPDISK_MESSAGE_EXIT)
+        goto invalid;
+
+    info = &message_infos[message.type];
+
+    if (!info->handler)
+        goto invalid;
+
+    if (info->flags & TAPDISK_MSG_VERBOSE)
+        DBG("received '%s' message\n",
+            tapdisk_message_name(message.type));
+
+    excl = !(info->flags & TAPDISK_MSG_REENTER);
+    if (excl) {
+        if (td_control.busy)
+            goto busy;
+
+        td_control.busy = 1;
+    }
+    conn->in.busy = 1;
+    conn->info = info;
+
+       memset(&response, 0, sizeof(response));
+
+    err = info->handler(conn, &message, &response);
+    if (err) {
+        response.type = TAPDISK_MESSAGE_ERROR;
+        response.u.response.error = -err;
+    }
+    tapdisk_control_write_message(conn, &response);
+
+    conn->in.busy = 0;
+    if (excl)
+        td_control.busy = 0;
+
+    tapdisk_control_release_connection(conn);
+    return;
+
+  error:
+    memset(&response, 0, sizeof(response));
+               response.type = TAPDISK_MESSAGE_ERROR;
+               response.u.response.error = (err ? -err : EINVAL);
+    tapdisk_control_write_message(conn, &response);
+
+  close:
+    tapdisk_control_close_connection(conn);
+    return;
+
+  busy:
+    err = -EBUSY;
+    ERR(err, "rejecting message '%s' while busy\n",
+        tapdisk_message_name(message.type));
+    goto error;
+
+  invalid:
+    err = -EINVAL;
+    ERR(err, "rejecting unsupported message '%s'\n",
+        tapdisk_message_name(message.type));
+    goto error;
+}
+
+static void tapdisk_control_accept(event_id_t id __attribute__((unused)),
+        char mode __attribute__((unused)),
+        void *private __attribute__((unused)))
+{
+       int err, fd;
+    struct tapdisk_ctl_conn *conn;
+
+       fd = accept(td_control.socket, NULL, NULL);
+       if (fd == -1) {
+        ERR(-errno, "failed to accept new control connection: %d\n",
+            errno);
                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) {
+    conn = tapdisk_ctl_conn_open(fd);
+    if (!conn) {
                close(fd);
-               EPRINTF("failed to allocate new control connection\n");
+        ERR(-ENOMEM, "failed to allocate new control connection\n");
+        return;
        }
 
        err = tapdisk_server_register_event(SCHEDULER_POLL_READ_FD,
-                                           connection->socket, 0,
+                                        conn->fd, TD_CTL_RECV_TIMEOUT,
                                            tapdisk_control_handle_request,
-                                           connection);
+                                        conn);
        if (err == -1) {
-               close(fd);
-               free(connection);
-               EPRINTF("failed to register new control event: %d\n", err);
+        tapdisk_control_close_connection(conn);
+        ERR(err, "failed to register new control event\n");
+        return;
        }
 
-       connection->event_id = err;
+    conn->in.event_id = err;
 }
 
-static int
-tapdisk_control_mkdir(const char *dir)
+static int tapdisk_control_mkdir(const char *dir)
 {
        int err;
        char *ptr, *name, *start;
@@ -738,8 +1218,7 @@ tapdisk_control_mkdir(const char *dir)
                err = mkdir(name, 0755);
                if (err && errno != EEXIST) {
                        err = -errno;
-                       EPRINTF("failed to create directory %s: %d\n",
-                                 name, err);
+            EPRINTF("failed to create directory %s: %d\n", name, err);
                        break;
                }
 
@@ -755,21 +1234,20 @@ tapdisk_control_mkdir(const char *dir)
        return err;
 }
 
-static int
-tapdisk_control_create_socket(char **socket_path)
+static int tapdisk_control_create_socket(char **socket_path)
 {
-       int err, flags;
        struct sockaddr_un saddr;
+    int err;
 
-       err = tapdisk_control_mkdir(BLKTAP2_CONTROL_DIR);
+    err = tapdisk_control_mkdir(BLKTAP3_CONTROL_DIR);
        if (err) {
                EPRINTF("failed to create directory %s: %d\n",
-                       BLKTAP2_CONTROL_DIR, err);
+                BLKTAP3_CONTROL_DIR, err);
                return err;
        }
 
        err = asprintf(&td_control.path, "%s/%s%d",
-                      BLKTAP2_CONTROL_DIR, BLKTAP2_CONTROL_SOCKET, getpid());
+                   BLKTAP3_CONTROL_DIR, BLKTAP3_CONTROL_SOCKET, getpid());
        if (err == -1) {
                td_control.path = NULL;
                err = (errno ? : ENOMEM);
@@ -801,7 +1279,7 @@ tapdisk_control_create_socket(char **soc
                goto fail;
        }
 
-       err = listen(td_control.socket, 10);
+    err = listen(td_control.socket, TD_CTL_SOCK_BACKLOG);
        if (err == -1) {
                err = errno;
                EPRINTF("failed to listen: %d\n", err);
@@ -826,11 +1304,8 @@ fail:
        return err;
 }
 
-int
-tapdisk_control_open(char **path)
+int tapdisk_control_open(char **path)
 {
-       int err;
-
        tapdisk_control_initialize();
 
        return tapdisk_control_create_socket(path);
diff --git a/tools/blktap2/drivers/tapdisk-control.h 
b/tools/blktap3/drivers/tapdisk-control.h
copy from tools/blktap2/drivers/tapdisk-control.h
copy to tools/blktap3/drivers/tapdisk-control.h

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.