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

[Xen-devel] [PATCH 6 of 7 v4] blktap3/tapback: Introduce the tapback daemon



This patch introduces the core of the tapback daemon, the user space daemon
that acts as a device's back-end, essentially most of blkback in user space.
Similar to blkback, the daemon monitors XenStore for device creation/removal
requests and front-end state changes, and acts in response to them
(communicates to the front-end necessary information, switches the back-end's
state etc.). The daemon creates/destroys tapdisk processes as needed.

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

---
Changed since v1:
  * minor code clean up

Changed since v2:
  * Introduce function XenbusState2str for printing XenbusStates in a more
    human-friendly way.
  * Don't print the log identify if the tapback is run in non-daemon mode, in
    order to make debug output more concise.

Changed since v3:
  * Remove some debug print as they spam the output.
  * Use function abs() to report errors as some error codes are negated.
  * Create the control socket.

diff --git a/tools/blktap3/tapback/tapback.c b/tools/blktap3/tapback/tapback.c
new file mode 100644
--- /dev/null
+++ b/tools/blktap3/tapback/tapback.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2012      Citrix Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+ * USA.
+ *
+ * This file contains the core of the tapback daemon, the user space daemon
+ * that acts as a device's back-end.
+ */
+
+/*
+ * TODO Some of these includes may be useless.
+ * TODO Replace hard-coding strings with defines/const string.
+ */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <syslog.h>
+
+#include "blktap3.h"
+#include "stdio.h" /* TODO tap-ctl.h needs to include stdio.h */
+#include "tap-ctl.h"
+#include "tapback.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <signal.h>
+
+void tapback_log(int prio, const char *fmt, ...);
+void (*tapback_vlog) (int prio, const char *fmt, va_list ap);
+
+struct _blktap3_daemon blktap3_daemon;
+
+char *XenbusState2str(const XenbusState xbs)
+{
+    static char * const str[] = {
+        [XenbusStateUnknown] = "unknown",
+        [XenbusStateInitialising] = "initialising",
+        [XenbusStateInitWait] = "init wait",
+        [XenbusStateInitialised] = "initialised",
+        [XenbusStateConnected] = "connected",
+        [XenbusStateClosing] = "closing",
+        [XenbusStateClosed] = "closed",
+        [XenbusStateReconfiguring] = "reconfiguring",
+        [XenbusStateReconfigured] = "reconfigured"
+    };
+    return str[xbs];
+}
+
+/**
+ * Read changes that occurred on the "backend/<backend name>" XenStore path
+ * or one of the front-end paths and act accordingly.
+ */
+static inline void
+tapback_read_watch(void)
+{
+    char **watch = NULL, *path = NULL, *token = NULL;
+    unsigned int n = 0;
+    int err = 0, _abort = 0;
+
+    /* read the change */
+    watch = xs_read_watch(blktap3_daemon.xs, &n);
+    path = watch[XS_WATCH_PATH];
+    token = watch[XS_WATCH_TOKEN];
+
+    /*
+     * TODO Put the body of "again:" into a loop instead of using goto.
+     */
+again:
+    if (!(blktap3_daemon.xst = xs_transaction_start(blktap3_daemon.xs))) {
+        WARN("error starting transaction\n");
+        goto fail;
+    }
+
+    /*
+     * The token indicates which XenStore watch triggered, the front-end one or
+     * the back-end one.
+     */
+    if (!strcmp(token, BLKTAP3_FRONTEND_TOKEN)) {
+        err = tapback_backend_handle_otherend_watch(path);
+    } else if (!strcmp(token, BLKTAP3_BACKEND_TOKEN)) {
+        err = tapback_backend_handle_backend_watch(path);
+    } else {
+        WARN("invalid token \'%s\'\n", token);
+        err = EINVAL;
+    }
+
+    _abort = !!err;
+    if (_abort)
+        /* TODO Some functions return +err, others -err */
+        DBG("aborting transaction: %s\n", strerror(abs(err)));
+
+    err = xs_transaction_end(blktap3_daemon.xs, blktap3_daemon.xst, _abort);
+    blktap3_daemon.xst = 0;
+    if (!err) {
+        err = -errno;
+        /*
+         * This is OK according to xs_transaction_end's semantics.
+         */
+        if (EAGAIN == errno)
+            goto again;
+        DBG("error ending transaction: %s\n", strerror(err));
+    }
+
+fail:
+    free(watch);
+    return;
+}
+
+static void
+tapback_backend_destroy(void)
+{
+    int err;
+
+    if (blktap3_daemon.xs) {
+        xs_daemon_close(blktap3_daemon.xs);
+        blktap3_daemon.xs = NULL;
+    }
+
+    err = unlink(TAPBACK_CTL_SOCK_PATH);
+    if (err == -1 && errno != ENOENT) {
+        err = errno;
+        WARN("failed to remove %s: %s\n", TAPBACK_CTL_SOCK_PATH, 
strerror(err));
+    }
+}
+
+static void
+signal_cb(int signum) {
+
+    assert(signum == SIGINT || signum == SIGTERM);
+
+    /* TODO Check whether there are active VBDs? */
+    tapback_backend_destroy();
+    exit(0);
+}
+
+/**
+ * Initializes the back-end descriptor. There is one back-end per tapback
+ * process. Also, it initiates a watch to XenStore on backend/<backend name>.
+ *
+ * @returns 0 on success, an error code otherwise
+ */
+static inline int
+tapback_backend_create(void)
+{
+    int err;
+    struct sockaddr_un local;
+    int len;
+
+    TAILQ_INIT(&blktap3_daemon.devices);
+    blktap3_daemon.xst = XBT_NULL;
+    blktap3_daemon.ctrl_sock = -1;
+
+    if (!(blktap3_daemon.xs = xs_daemon_open())) {
+        err = EINVAL;
+        goto fail;
+    }
+
+    /*
+     * Watch the back-end.
+     */
+    if (!xs_watch(blktap3_daemon.xs, BLKTAP3_BACKEND_PATH,
+                BLKTAP3_BACKEND_TOKEN)) {
+        err = errno;
+        goto fail;
+    }
+
+    if (SIG_ERR == signal(SIGINT, signal_cb) ||
+            SIG_ERR == signal(SIGTERM, signal_cb)) {
+        WARN("failed to register signal handlers\n");
+        err = EINVAL;
+        goto fail;
+    }
+
+    /*
+     * Create the control socket.
+     * XXX We don't listen for connections as we don't yet support any control
+     * commands.
+     */
+    blktap3_daemon.ctrl_sock = socket(AF_UNIX, SOCK_STREAM, 0);
+    if (blktap3_daemon.ctrl_sock == -1) {
+        err = errno;
+        WARN("failed to create control socket: %s\n", strerror(errno));
+        goto fail;
+    }
+    local.sun_family = AF_UNIX;
+    strcpy(local.sun_path, TAPBACK_CTL_SOCK_PATH);
+    err = unlink(local.sun_path);
+    if (err && errno != ENOENT) {
+        err = errno;
+        WARN("failed to remove %s: %s\n", local.sun_path, strerror(err));
+        goto fail;
+    }
+    len = strlen(local.sun_path) + sizeof(local.sun_family);
+    err = bind(blktap3_daemon.ctrl_sock, (struct sockaddr *)&local, len);
+    if (err == -1) {
+        err = errno;
+        WARN("failed to bind to %s: %s\n", local.sun_path, strerror(err));
+        goto fail;
+    }
+
+    return 0;
+
+fail:
+       tapback_backend_destroy();
+
+    return err;
+}
+
+/**
+ * Runs the daemon.
+ *
+ * Watches backend/<backend name> and the front-end devices.
+ */
+static inline int
+tapback_backend_run(void)
+{
+    const int fd = xs_fileno(blktap3_daemon.xs);
+       int err;
+
+    do {
+        fd_set rfds;
+        int nfds = 0;
+
+        FD_ZERO(&rfds);
+        FD_SET(fd, &rfds);
+
+        /* poll the fd for changes in the XenStore path we're interested in */
+        if ((nfds = select(fd + 1, &rfds, NULL, NULL, NULL)) < 0) {
+            perror("error monitoring XenStore");
+            err = -errno;
+            break;
+        }
+
+        if (FD_ISSET(fd, &rfds))
+            tapback_read_watch();
+        DBG("--\n");
+    } while (1);
+
+    return err;
+}
+
+static char *blkback_ident = NULL;
+
+static void
+blkback_vlog_fprintf(const int prio, const char * const fmt, va_list ap)
+{
+    static const char *strprio[] = {
+        [LOG_DEBUG] = "DBG",
+        [LOG_INFO] = "INF",
+        [LOG_WARNING] = "WRN"
+    };
+
+    assert(LOG_DEBUG == prio || LOG_INFO == prio || LOG_WARNING == prio);
+    assert(strprio[prio]);
+
+    fprintf(stderr, "%s[%s] ", blkback_ident, strprio[prio]);
+    vfprintf(stderr, fmt, ap);
+}
+
+/**
+ * Print tapback's usage instructions.
+ */
+static void
+usage(FILE * const stream, const char * const prog)
+{
+    assert(stream);
+    assert(prog);
+
+    fprintf(stream,
+            "usage: %s\n"
+            "\t[-D|--debug]\n"
+                       "\t[-h|--help]\n", prog);
+}
+
+int main(int argc, char **argv)
+{
+    const char *prog = NULL;
+    int opt_debug = 0;
+    int err = 0;
+
+    prog = basename(argv[0]);
+
+    opt_debug = 0;
+
+    do {
+        const struct option longopts[] = {
+            {"help", 0, NULL, 'h'},
+            {"debug", 0, NULL, 'D'},
+        };
+        int c;
+
+        c = getopt_long(argc, argv, "h:D", longopts, NULL);
+        if (c < 0)
+            break;
+
+        switch (c) {
+        case 'h':
+            usage(stdout, prog);
+            return 0;
+        case 'D':
+            opt_debug = 1;
+            break;
+        case '?':
+            goto usage;
+        }
+    } while (1);
+
+    if (opt_debug) {
+        blkback_ident = "";
+        tapback_vlog = blkback_vlog_fprintf;
+    }
+    else {
+        blkback_ident = BLKTAP3_BACKEND_TOKEN;
+        openlog(blkback_ident, 0, LOG_DAEMON);
+    }
+
+    if (!opt_debug) {
+        if ((err = daemon(0, 0))) {
+            err = -errno;
+            goto fail;
+        }
+    }
+
+       if ((err = tapback_backend_create())) {
+        WARN("error creating blkback: %s\n", strerror(err));
+        goto fail;
+    }
+
+    err = tapback_backend_run();
+
+    tapback_backend_destroy();
+
+fail:
+    return err ? -err : 0;
+
+usage:
+    usage(stderr, prog);
+    return 1;
+}

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