]> xenbits.xensource.com Git - people/dstodden/blktap.git/commitdiff
CP-1760: tap-ctl stats -- sample tapdisk object state.
authorDaniel Stodden <daniel.stodden@citrix.com>
Tue, 17 Aug 2010 08:56:29 +0000 (01:56 -0700)
committerDaniel Stodden <daniel.stodden@citrix.com>
Tue, 17 Aug 2010 08:56:29 +0000 (01:56 -0700)
Marshals vbd/image/driver state into JSON object trees.

18 files changed:
control/Makefile
control/tap-ctl-ipc.c
control/tap-ctl-stats.c [new file with mode: 0644]
control/tap-ctl.c
control/tap-ctl.h
drivers/Makefile
drivers/block-aio.c
drivers/tapdisk-control.c
drivers/tapdisk-driver.c
drivers/tapdisk-driver.h
drivers/tapdisk-image.c
drivers/tapdisk-image.h
drivers/tapdisk-stats.c [new file with mode: 0644]
drivers/tapdisk-stats.h [new file with mode: 0644]
drivers/tapdisk-vbd.c
drivers/tapdisk-vbd.h
drivers/tapdisk.h
include/tapdisk-message.h

index 4751ba7af8d29697c10328ff492be492da7892bc..2d954eadc6dc0746119e39ed61344fb34e869e93 100644 (file)
@@ -28,6 +28,7 @@ CTL_OBJS  += tap-ctl-pause.o
 CTL_OBJS  += tap-ctl-unpause.o
 CTL_OBJS  += tap-ctl-major.o
 CTL_OBJS  += tap-ctl-check.o
+CTL_OBJS  += tap-ctl-stats.o
 
 CTL_PICS  = $(patsubst %.o,%.opic,$(CTL_OBJS))
 
index c3183297d4ff084742c481138d0e0c9f7f9813a6..f7f67c4aa2a3a2932948f0e28b1b0c330c08a996 100644 (file)
 int tap_ctl_debug = 0;
 
 int
-tap_ctl_read_message(int fd, tapdisk_message_t *message,
-                    struct timeval *timeout)
+tap_ctl_read_raw(int fd, void *buf, size_t size, struct timeval *timeout)
 {
        fd_set readfds;
-       int ret, len, offset;
-
-       offset = 0;
-       len    = sizeof(tapdisk_message_t);
+       size_t offset = 0;
+       int ret;
 
-       memset(message, 0, sizeof(tapdisk_message_t));
-
-       while (offset < len) {
+       while (offset < size) {
                FD_ZERO(&readfds);
                FD_SET(fd, &readfds);
 
@@ -61,7 +56,7 @@ tap_ctl_read_message(int fd, tapdisk_message_t *message,
                if (ret == -1)
                        break;
                else if (FD_ISSET(fd, &readfds)) {
-                       ret = read(fd, message + offset, len - offset);
+                       ret = read(fd, buf + offset, size - offset);
                        if (ret <= 0)
                                break;
                        offset += ret;
@@ -69,11 +64,25 @@ tap_ctl_read_message(int fd, tapdisk_message_t *message,
                        break;
        }
 
-       if (offset != len) {
-               EPRINTF("failure reading message\n");
+       if (offset != size) {
+               EPRINTF("failure reading data %zd/%zd\n", offset, size);
                return -EIO;
        }
 
+       return 0;
+}
+
+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);
 
diff --git a/control/tap-ctl-stats.c b/control/tap-ctl-stats.c
new file mode 100644 (file)
index 0000000..6fe250e
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2010, Citrix 
+ * 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 <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#include "tap-ctl.h"
+
+int
+_tap_ctl_stats_connect_and_send(pid_t pid, int minor)
+{
+       struct timeval timeout = { .tv_sec = 10, .tv_usec = 0 };
+       tapdisk_message_t message;
+       int sfd, err;
+       size_t len;
+
+       err = tap_ctl_connect_id(pid, &sfd);
+       if (err)
+               return err;
+
+       memset(&message, 0, sizeof(message));
+       message.type   = TAPDISK_MESSAGE_STATS;
+       message.cookie = minor;
+
+       err = tap_ctl_write_message(sfd, &message, &timeout);
+       if (err)
+               return err;
+
+       return sfd;
+}
+
+ssize_t
+tap_ctl_stats(pid_t pid, int minor, char *buf, size_t size)
+{
+       tapdisk_message_t message;
+       int sfd, err;
+       size_t len;
+
+       sfd = _tap_ctl_stats_connect_and_send(pid, minor);
+       if (sfd < 0)
+               return sfd;
+
+       err = tap_ctl_read_message(sfd, &message, NULL);
+       if (err)
+               return err;
+
+       len= message.u.info.length;
+       if (len < 0) {
+               err = len;
+               goto out;
+       }
+       if (size < len + 1)
+               len = size - 1;
+
+       err = tap_ctl_read_raw(sfd, buf, len, NULL);
+       if (err)
+               goto out;
+
+       buf[len] = 0;
+
+out:
+       close(sfd);
+       return err;
+}
+
+int
+tap_ctl_stats_fwrite(pid_t pid, int minor, FILE *stream)
+{
+       tapdisk_message_t message;
+       int sfd = -1, prot, flags, err;
+       size_t len, bufsz;
+       char *buf = MAP_FAILED;
+
+       prot  = PROT_READ|PROT_WRITE;
+       flags = MAP_ANONYMOUS|MAP_PRIVATE;
+       bufsz = sysconf(_SC_PAGE_SIZE);
+
+       buf = mmap(NULL, bufsz, prot, flags, -1, 0);
+       if (buf == MAP_FAILED) {
+               buf = NULL;
+               err = -ENOMEM;
+               goto out;
+       }
+
+       sfd = _tap_ctl_stats_connect_and_send(pid, minor);
+       if (sfd < 0) {
+               err = sfd;
+               goto out;
+       }
+
+       err = tap_ctl_read_message(sfd, &message, NULL);
+       if (err)
+               goto out;
+
+       len = message.u.info.length;
+       err = len;
+       if (len < 0)
+               goto out;
+
+       while (len) {
+               fd_set rfds;
+               size_t in, out;
+               int n;
+
+               FD_ZERO(&rfds);
+               FD_SET(sfd, &rfds);
+
+               n = select(sfd + 1, &rfds, NULL, NULL, NULL);
+               err = n;
+               if (n < 0)
+                       goto out;
+
+               in = read(sfd, buf, bufsz);
+               err = in;
+               if (in <= 0)
+                       goto out;
+
+               len -= in;
+
+               out = fwrite(buf, in, 1, stream);
+               if (out != in) {
+                       err = -errno;
+                       goto out;
+               }
+       }
+
+out:
+       if (sfd >= 0)
+               close(sfd);
+       if (buf != MAP_FAILED)
+               munmap(buf, bufsz);
+
+       return err;
+}
index 83f89bbd66564af82c2a99eaaacee854c508ed69..91368aa224920cbf247f2eedd55768538a6d689e 100644 (file)
@@ -760,6 +760,54 @@ usage:
        return EINVAL;
 }
 
+static void
+tap_cli_stats_usage(FILE *stream)
+{
+       fprintf(stream, "usage: info <-p pid> <-m minor>\n");
+}
+
+static int
+tap_cli_stats(int argc, char **argv)
+{
+       pid_t pid;
+       int c, minor, err;
+
+       pid     = -1;
+       minor   = -1;
+
+       optind = 0;
+       while ((c = getopt(argc, argv, "p:m:h")) != -1) {
+               switch (c) {
+               case 'p':
+                       pid = atoi(optarg);
+                       break;
+               case 'm':
+                       minor = atoi(optarg);
+                       break;
+               case '?':
+                       goto usage;
+               case 'h':
+                       tap_cli_stats_usage(stdout);
+                       return 0;
+               }
+       }
+
+       if (pid == -1 || minor == -1)
+               goto usage;
+
+       err = tap_ctl_stats_fwrite(pid, minor, stdout);
+       if (err)
+               return err;
+
+       fprintf(stdout, "\n");
+
+       return 0;
+
+usage:
+       tap_cli_stats_usage(stderr);
+       return EINVAL;
+}
+
 static void
 tap_cli_check_usage(FILE *stream)
 {
@@ -799,6 +847,7 @@ struct command commands[] = {
        { .name = "close",        .func = tap_cli_close         },
        { .name = "pause",        .func = tap_cli_pause         },
        { .name = "unpause",      .func = tap_cli_unpause       },
+       { .name = "stats",        .func = tap_cli_stats         },
        { .name = "major",        .func = tap_cli_major         },
        { .name = "check",        .func = tap_cli_check         },
 };
index 630364e29261cfc72731d59ae6e9b4e67f09d384..b381a16a07d9a6c8be4e7dc08e84b0d36f0691b1 100644 (file)
@@ -57,6 +57,7 @@ int tap_ctl_check(const char **message);
 
 int tap_ctl_connect(const char *path, int *socket);
 int tap_ctl_connect_id(int id, int *socket);
+int tap_ctl_read_raw(int fd, void *buf, size_t sz, struct timeval *timeout);
 int tap_ctl_read_message(int fd, tapdisk_message_t *message,
                         struct timeval *timeout);
 int tap_ctl_write_message(int fd, tapdisk_message_t *message,
@@ -112,6 +113,9 @@ int tap_ctl_close(const int id, const int minor, const int force,
 int tap_ctl_pause(const int id, const int minor, struct timeval *timeout);
 int tap_ctl_unpause(const int id, const int minor, const char *params);
 
+ssize_t tap_ctl_stats(pid_t pid, int minor, char *buf, size_t size);
+int tap_ctl_stats_fwrite(pid_t pid, int minor, FILE *out);
+
 int tap_ctl_blk_major(void);
 
 #endif
index 47ff47ae95826cece018a802334b850f3c429254..e01e8efee2e2e10268ba7f378ba10c8884dab9d7 100644 (file)
@@ -52,6 +52,7 @@ TAP-OBJS  += tapdisk-log.o
 TAP-OBJS  += tapdisk-utils.o
 TAP-OBJS  += tapdisk-disktype.o
 TAP-OBJS  += tapdisk-syslog.o
+TAP-OBJS  += tapdisk-stats.o
 TAP-OBJS  += io-optimize.o
 TAP-OBJS  += lock.o
 
index 8708dad8d96103fffc905aa1f431aff3ed12334c..1dda2ed21bc3ed77e6f6162dab620ec61a224d1a 100644 (file)
@@ -260,6 +260,19 @@ int tdaio_validate_parent(td_driver_t *driver,
        return -EINVAL;
 }
 
+void tdaio_stats(td_driver_t *driver, td_stats_t *st)
+{
+       struct tdaio_state *prv = (struct tdaio_state *)driver->data;
+       int n_pending;
+
+       n_pending = MAX_AIO_REQS - prv->aio_free_count;
+
+       tapdisk_stats_field(st, "reqs", "{");
+       tapdisk_stats_field(st, "max", "lu", MAX_AIO_REQS);
+       tapdisk_stats_field(st, "pending", "d", n_pending);
+       tapdisk_stats_leave(st, '}');
+}
+
 struct tap_disk tapdisk_aio = {
        .disk_type          = "tapdisk_aio",
        .flags              = 0,
@@ -271,4 +284,5 @@ struct tap_disk tapdisk_aio = {
        .td_get_parent_id   = tdaio_get_parent_id,
        .td_validate_parent = tdaio_validate_parent,
        .td_debug           = NULL,
+       .td_stats           = tdaio_stats,
 };
index 3f337192b0e57bf0af3699c7914cfffeb3f846d9..71cfe7b8bbd3fe3d9753779f7e6d59a832dce8c3 100644 (file)
@@ -48,6 +48,7 @@
 #include "tapdisk-server.h"
 #include "tapdisk-message.h"
 #include "tapdisk-disktype.h"
+#include "tapdisk-stats.h"
 #include "tapdisk-control.h"
 
 #define TD_CTL_MAX_CONNECTIONS  10
@@ -90,13 +91,13 @@ struct tapdisk_ctl_conn {
                int             busy;
        } in;
 
-       struct tapdisk_message_info *info;
+       struct tapdisk_control_info *info;
 };
 
 #define TAPDISK_MSG_REENTER    (1<<0) /* non-blocking, idempotent */
 #define TAPDISK_MSG_VERBOSE    (1<<1) /* tell syslog about it */
 
-struct tapdisk_message_info {
+struct tapdisk_control_info {
        void (*handler)(struct tapdisk_ctl_conn *, tapdisk_message_t *);
        int flags;
 };
@@ -905,7 +906,53 @@ out:
        tapdisk_control_write_message(conn, &response);
 }
 
-struct tapdisk_message_info message_infos[] = {
+static void
+tapdisk_control_stats(struct tapdisk_ctl_conn *conn,
+                     tapdisk_message_t *request)
+{
+       tapdisk_message_t response;
+       td_stats_t _st, *st = &_st;
+       td_vbd_t *vbd;
+       size_t rv;
+
+       tapdisk_stats_init(st,
+                          conn->out.buf + sizeof(response),
+                          conn->out.bufsz - sizeof(response));
+
+       if (request->cookie != (uint16_t)-1) {
+
+               vbd = tapdisk_server_get_vbd(request->cookie);
+               if (!vbd) {
+                       rv = -ENODEV;
+                       goto out;
+               }
+
+               tapdisk_vbd_stats(vbd, st);
+
+       } else {
+               struct list_head *list = tapdisk_server_get_all_vbds();
+
+               tapdisk_stats_enter(st, '[');
+
+               list_for_each_entry(vbd, list, next)
+                       tapdisk_vbd_stats(vbd, st);
+
+               tapdisk_stats_leave(st, ']');
+       }
+
+       rv = tapdisk_stats_length(st);
+out:
+       memset(&response, 0, sizeof(response));
+       response.type = TAPDISK_MESSAGE_STATS_RSP;
+       response.cookie = request->cookie;
+       response.u.info.length = rv;
+
+       tapdisk_control_write_message(conn, &response);
+       if (rv > 0)
+               conn->out.prod += rv;
+}
+
+struct tapdisk_control_info message_infos[] = {
        [TAPDISK_MESSAGE_PID] = {
                .handler = tapdisk_control_get_pid,
                .flags   = TAPDISK_MSG_REENTER,
@@ -938,6 +985,10 @@ struct tapdisk_message_info message_infos[] = {
                .handler = tapdisk_control_close_image,
                .flags   = TAPDISK_MSG_VERBOSE,
        },
+       [TAPDISK_MESSAGE_STATS] = {
+               .handler = tapdisk_control_stats,
+               .flags   = TAPDISK_MSG_VERBOSE,
+       },
 };
 
 
@@ -947,7 +998,7 @@ tapdisk_control_handle_request(event_id_t id, char mode, void *private)
        int err, len, excl;
        tapdisk_message_t message, response;
        struct tapdisk_ctl_conn *conn = private;
-       struct tapdisk_message_info *info;
+       struct tapdisk_control_info *info;
 
        err = tapdisk_control_read_message(conn->fd, &message, 2);
        if (err)
index aa1ed15f40ad6a96676f132c9a02bb08b70ff006..00717bd6752f9701a92b40e6f07a83f7a0a89961 100644 (file)
  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+
 #include <stdlib.h>
+#include <stdio.h>
 
 #include "tapdisk-driver.h"
 #include "tapdisk-server.h"
 #include "tapdisk-disktype.h"
+#include "tapdisk-stats.h"
 
 td_driver_t *
 tapdisk_driver_allocate(int type, char *name, td_flag_t flags, int storage)
@@ -99,3 +102,17 @@ tapdisk_driver_debug(td_driver_t *driver)
        if (driver->ops->td_debug)
                driver->ops->td_debug(driver);
 }
+
+void
+tapdisk_driver_stats(td_driver_t *driver, td_stats_t *st)
+{
+       tapdisk_stats_field(st, "type", "d", driver->type);
+
+       if (driver->ops->td_stats) {
+               tapdisk_stats_field(st, "status", "{");
+               driver->ops->td_stats(driver, st);
+               tapdisk_stats_leave(st, '}');
+       } else
+               tapdisk_stats_field(st, "status", NULL);
+
+}
index 42de05db1d620dde11d6a165a4df28113e7cd893..62b5ae1efe2765ece46f4730a208b16d31dbfd40 100644 (file)
@@ -59,4 +59,6 @@ void tapdisk_driver_queue_tiocb(td_driver_t *, struct tiocb *);
 
 void tapdisk_driver_debug(td_driver_t *);
 
+void tapdisk_driver_stats(td_driver_t *, td_stats_t *);
+
 #endif
index 96ebd4b6435d6d9e9c0dd9a408554f2c4eee29bf..19e308434a245c41db93a963bc8ffed518c83cec 100644 (file)
 #include <errno.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <stdio.h>
 
 #include "tapdisk-image.h"
 #include "tapdisk-driver.h"
 #include "tapdisk-server.h"
+#include "tapdisk-stats.h"
 
 #define ERR(_err, _f, _a...) tlog_error(_err, _f, ##_a)
 
@@ -158,3 +160,16 @@ fail:
            req->operation, req->sector_number + total);
        return -EINVAL;
 }
+
+void
+tapdisk_image_stats(td_image_t *image, td_stats_t *st)
+{
+       tapdisk_stats_enter(st, '{');
+       tapdisk_stats_field(st, "name", "s", image->name);
+
+       tapdisk_stats_field(st, "driver", "{");
+       tapdisk_driver_stats(image->driver, st);
+       tapdisk_stats_leave(st, '}');
+
+       tapdisk_stats_leave(st, '}');
+}
index 8779dff8b766fa43e6b9e1c046111b7dc8a75c83..508305c0a02c92cc6e53d6c513e8b674902e9dd2 100644 (file)
@@ -51,5 +51,6 @@ void tapdisk_image_free(td_image_t *);
 
 int tapdisk_image_check_td_request(td_image_t *, td_request_t);
 int tapdisk_image_check_ring_request(td_image_t *, blkif_request_t *);
+void tapdisk_image_stats(td_image_t *, td_stats_t *);
 
 #endif
diff --git a/drivers/tapdisk-stats.c b/drivers/tapdisk-stats.c
new file mode 100644 (file)
index 0000000..40a8049
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2010, Citrix Systems, 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 <stdarg.h>
+
+#include "tapdisk-stats.h"
+
+static void
+tapdisk_stats_vsprintf(td_stats_t *st,
+                     const char *fmt, va_list ap)
+{
+       st->pos += vsnprintf(st->pos, st->buf + st->size - st->pos, fmt, ap);
+}
+
+static void __attribute__((format (printf, 2, 3)))
+tapdisk_stats_sprintf(td_stats_t *st,
+                    const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       tapdisk_stats_vsprintf(st, fmt, ap);
+       va_end(ap);
+}
+
+
+static inline void
+__tapdisk_stats_enter(td_stats_t *st, char t)
+{
+       tapdisk_stats_sprintf(st, "%c ", t);
+
+       st->depth++;
+       st->n_elem[st->depth] = 0;
+}
+
+void
+tapdisk_stats_enter(td_stats_t *st, char t)
+{
+       int n_elem;
+
+       n_elem = st->n_elem[st->depth];
+       if (n_elem > 0)
+               tapdisk_stats_sprintf(st, ", ");
+       st->n_elem[st->depth]++;
+
+       __tapdisk_stats_enter(st, t);
+}
+
+
+void
+tapdisk_stats_leave(td_stats_t *st, char t)
+{
+       st->depth--;
+
+       tapdisk_stats_sprintf(st, " %c", t);
+}
+
+void
+tapdisk_stats_field(td_stats_t *st, const char *key, const char *conv, ...)
+{
+       va_list ap;
+       int n_elem;
+       char fmt[32], t;
+
+       n_elem = st->n_elem[st->depth]++;
+       if (n_elem > 0)
+               tapdisk_stats_sprintf(st, ", ");
+
+       tapdisk_stats_sprintf(st, "\"%s\": ", key);
+
+       if (!conv) {
+               tapdisk_stats_sprintf(st, "null");
+               return;
+       }
+
+       t = conv[0];
+       switch (t) {
+       case 's':
+               va_start(ap, conv);
+               tapdisk_stats_vsprintf(st, "\"%s\"", ap);
+               va_end(ap);
+               break;
+
+       case '[':
+       case '{':
+               __tapdisk_stats_enter(st, t);
+               break;
+
+       default:
+               sprintf(fmt, "%%%s", conv);
+
+               va_start(ap, conv);
+               tapdisk_stats_vsprintf(st, fmt, ap);
+               va_end(ap);
+               break;
+       }
+}
diff --git a/drivers/tapdisk-stats.h b/drivers/tapdisk-stats.h
new file mode 100644 (file)
index 0000000..cf41aa7
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2010, Citrix Systems, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of XenSource Inc. nor the names of its contributors
+ *       may be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TAPDISK_STATS_H_
+#define _TAPDISK_STATS_H_
+
+#include <string.h>
+
+#define TD_INFO_MAX_DEPTH 8
+
+struct tapdisk_stats_ctx {
+       void           *pos;
+
+       void           *buf;
+       size_t          size;
+
+       int             n_elem[TD_INFO_MAX_DEPTH];
+       int             depth;
+};
+
+typedef struct tapdisk_stats_ctx td_stats_t;
+
+static inline void
+tapdisk_stats_init(td_stats_t *st, char *buf, size_t size)
+{
+       memset(st, 0, sizeof(*st));
+
+       st->pos  = buf;
+       st->buf  = buf;
+       st->size = size;
+}
+
+static inline size_t
+tapdisk_stats_length(td_stats_t *st)
+{
+       return st->pos - st->buf;
+}
+
+void tapdisk_stats_enter(td_stats_t *st, char t);
+void tapdisk_stats_leave(td_stats_t *st, char t);
+void tapdisk_stats_field(td_stats_t *st, const char *key, const char *conv, ...);
+
+#endif /* _TAPDISK_STATS_H_ */
index 7bbf2551988caa2883565a975ee824d018697acf..7c9e3e812560b4cd4f98361b657a0b44f74e06b1 100644 (file)
@@ -45,6 +45,7 @@
 #include "tapdisk-vbd.h"
 #include "tapdisk-disktype.h"
 #include "tapdisk-interface.h"
+#include "tapdisk-stats.h"
 
 #include "blktap2.h"
 
@@ -2160,3 +2161,22 @@ tapdisk_vbd_ring_event(event_id_t id, char mode, void *private)
        /* vbd may be destroyed after this call */
        tapdisk_vbd_check_ring_message(vbd);
 }
+
+void
+tapdisk_vbd_stats(td_vbd_t *vbd, td_stats_t *st)
+{
+       td_image_t *image, *next;
+
+       tapdisk_stats_enter(st, '{');
+       tapdisk_stats_field(st, "name", "s", vbd->name);
+       tapdisk_stats_field(st, "minor", "d", vbd->minor);
+
+       tapdisk_stats_field(st, "image", "[");
+
+       tapdisk_vbd_for_each_image(vbd, image, next)
+               tapdisk_image_stats(image, st);
+
+       tapdisk_stats_leave(st, ']');
+
+       tapdisk_stats_leave(st, '}');
+}
index 2b7bdc630a32802b2223c5d32f0f8a67e49cdf28..1109d078034a3036d4f6832c471e51dba5cdb5c1 100644 (file)
@@ -207,5 +207,6 @@ int tapdisk_vbd_kick(td_vbd_t *);
 void tapdisk_vbd_check_state(td_vbd_t *);
 void tapdisk_vbd_check_progress(td_vbd_t *);
 void tapdisk_vbd_debug(td_vbd_t *);
+void tapdisk_vbd_stats(td_vbd_t *, td_stats_t *);
 
 #endif
index cce2f262c5aba09ef20aa3642ee8e602a4615857..743f30d8860d92e11465c9148fc0987710753d0f 100644 (file)
@@ -63,6 +63,7 @@
 #include "blktaplib.h"
 #include "tapdisk-log.h"
 #include "tapdisk-utils.h"
+#include "tapdisk-stats.h"
 
 #define MAX_SEGMENTS_PER_REQ         11
 #define SECTOR_SHIFT                 9
@@ -154,6 +155,7 @@ struct tap_disk {
        void (*td_queue_read)        (td_driver_t *, td_request_t);
        void (*td_queue_write)       (td_driver_t *, td_request_t);
        void (*td_debug)             (td_driver_t *);
+       void (*td_stats)             (td_driver_t *, td_stats_t *);
 };
 
 void td_panic(void);
index cd21b76ab5af283ede8403d005f78f56a286497d..bc17271d8984584599344a13ee01f4c74db57aee 100644 (file)
@@ -54,6 +54,7 @@ typedef struct tapdisk_message_string    tapdisk_message_string_t;
 typedef struct tapdisk_message_response  tapdisk_message_response_t;
 typedef struct tapdisk_message_minors    tapdisk_message_minors_t;
 typedef struct tapdisk_message_list      tapdisk_message_list_t;
+typedef struct tapdisk_message_stat      tapdisk_message_stat_t;
 
 struct tapdisk_message_params {
        tapdisk_message_flag_t           flags;
@@ -93,6 +94,13 @@ struct tapdisk_message_list {
        char                             path[TAPDISK_MESSAGE_MAX_PATH_LENGTH];
 };
 
+struct tapdisk_message_stat {
+       uint16_t                         type;
+       uint16_t                         cookie;
+       size_t                           length;
+};
+
+
 struct tapdisk_message {
        uint16_t                         type;
        uint16_t                         cookie;
@@ -105,6 +113,7 @@ struct tapdisk_message {
                tapdisk_message_minors_t minors;
                tapdisk_message_response_t response;
                tapdisk_message_list_t   list;
+               tapdisk_message_stat_t   info;
        } u;
 };
 
@@ -129,6 +138,8 @@ enum tapdisk_message_id {
        TAPDISK_MESSAGE_LIST_MINORS_RSP,
        TAPDISK_MESSAGE_LIST,
        TAPDISK_MESSAGE_LIST_RSP,
+       TAPDISK_MESSAGE_STATS,
+       TAPDISK_MESSAGE_STATS_RSP,
        TAPDISK_MESSAGE_FORCE_SHUTDOWN,
        TAPDISK_MESSAGE_EXIT,
 };
@@ -199,6 +210,12 @@ tapdisk_message_name(enum tapdisk_message_id id)
        case TAPDISK_MESSAGE_LIST_RSP:
                return "list response";
 
+       case TAPDISK_MESSAGE_STATS:
+               return "stats";
+
+       case TAPDISK_MESSAGE_STATS_RSP:
+               return "stats response";
+
        case TAPDISK_MESSAGE_EXIT:
                return "exit";