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

[Xen-devel] [PATCH 07 of 15 v4] blktap3/libblktapctl: Introduce tapdisk message exchange functionality



This patch introduces file conrol/tap-ctl-ipc.c, where the functionality of
talking to a tapdisk process is implemented. This file is imported from the
existing blktap2 implementation, with most changes coming from blktap2 living
in github.

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

---
Changed since v2:
  * Check for unexpected response in tap_ctl_send_and_receive.
  * If the message has been served but an error occurred, the error in the
    message is returned by the function in order to simplify error
    checking/handling by the caller.

Changed since v3:
  * Removed wrong way of checking for errors in order to provide more verbose
    logging, as not all messages contain an error field.

diff --git a/tools/blktap3/control/tap-ctl-ipc.c 
b/tools/blktap3/control/tap-ctl-ipc.c
new file mode 100644
--- /dev/null
+++ b/tools/blktap3/control/tap-ctl-ipc.c
@@ -0,0 +1,256 @@
+/*
+ * 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 <fcntl.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <assert.h>
+
+#include "tap-ctl.h"
+#include "blktap3.h"
+
+int tap_ctl_debug = 0;
+
+int
+tap_ctl_read_raw(int fd, void *buf, size_t size, struct timeval *timeout)
+{
+       fd_set readfds;
+       size_t offset = 0;
+       int ret;
+
+       while (offset < size) {
+               FD_ZERO(&readfds);
+               FD_SET(fd, &readfds);
+
+               ret = select(fd + 1, &readfds, NULL, NULL, timeout);
+               if (ret == -1)
+                       break;
+               else if (FD_ISSET(fd, &readfds)) {
+                       ret = read(fd, buf + offset, size - offset);
+                       if (ret <= 0)
+                               break;
+                       offset += ret;
+               } else
+                       break;
+       }
+
+       if (offset != size) {
+               EPRINTF("failure reading data %zd/%zd\n", offset, size);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+int
+tap_ctl_write_message(int fd, tapdisk_message_t * message,
+                                         struct timeval *timeout)
+{
+       fd_set writefds;
+       int ret, len, offset;
+
+       offset = 0;
+       len    = sizeof(tapdisk_message_t);
+
+       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, timeout);
+               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(const int sfd, tapdisk_message_t * const message,
+                                                struct timeval *timeout)
+{
+       int err;
+       td_msg_id_t msg_type;
+
+       assert(message);
+
+       msg_type = message->type;
+
+       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) {
+               /*
+                * TODO If there are messages for which a response is not 
required
+                * and failure to receive a reply is expected, this print is 
bogus.
+                */
+               EPRINTF("failed to receive '%s' message\n",
+                       tapdisk_message_name(message->type));
+               return err;
+       }
+
+    if (tapdisk_message_is_rsp_paired(msg_type)) {
+               if (message->type - msg_type != 1) {
+                       err = EINVAL;
+                       EPRINTF("invalid response '%s' to message '%s'\n",
+                                       tapdisk_message_name(message->type),
+                                       tapdisk_message_name(msg_type));
+               }
+        else
+            err = 0;
+       }
+
+       return err;
+}
+
+char *
+tap_ctl_socket_name(int id)
+{
+       char *name;
+
+       if (asprintf(&name, "%s/%s%d",
+                                BLKTAP3_CONTROL_DIR, BLKTAP3_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,
+                                                                struct timeval 
*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;
+}
+
+int
+tap_ctl_read_message(int fd, tapdisk_message_t * message,
+                                        struct timeval *timeout)
+{
+       size_t size = sizeof(tapdisk_message_t);
+       int err;
+
+       err = tap_ctl_read_raw(fd, message, size, timeout);
+       if (err)
+               return err;
+
+       DBG("received '%s' message (uuid = %u)\n",
+               tapdisk_message_name(message->type), message->cookie);
+
+       return 0;
+}

_______________________________________________
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®.