xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
From: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
To: xen-devel@lists.xenproject.org, msw@amazon.com,
	aliguori@amazon.com, amesserl@rackspace.com,
	rick.harris@rackspace.com, paul.voccio@rackspace.com,
	steven.wilson@rackspace.com, major.hayden@rackspace.com,
	josh.kearney@rackspace.com, jinsong.liu@alibaba-inc.com,
	xiantao.zxt@alibaba-inc.com, boris.ostrovsky@oracle.com,
	daniel.kiper@oracle.com, elena.ufimtseva@oracle.com,
	bob.liu@oracle.com, lars.kurth@citrix.com, hanweidong@huawei.com,
	peter.huangpeng@huawei.com, fanhenglong@huawei.com,
	liuyingdong@huawei.com, john.liuqiming@huawei.com,
	jbeulich@suse.com, andrew.cooper3@citrix.com,
	mpohlack@amazon.com, ian.campbell@citrix.com
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Subject: [PATCH v1 4/5] xen-xsplice: Tool to manipulate xsplice payloads.
Date: Wed, 16 Sep 2015 17:01:15 -0400	[thread overview]
Message-ID: <1442437276-2620-5-git-send-email-konrad.wilk@oracle.com> (raw)
In-Reply-To: <1442437276-2620-1-git-send-email-konrad.wilk@oracle.com>

A simple tool that allows an system admin to perform
basic xsplice operations:

 - Upload a xsplice file (with an unique id)
 - List all the xsplice payloads loaded.
 - Apply, revert, unload, or check the payload using the
   unique id.
 - Do all three - upload, check, and apply the
   payload in one go (--all).

Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
---
 tools/misc/Makefile      |   4 +
 tools/misc/xen-xsplice.c | 417 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 421 insertions(+)
 create mode 100644 tools/misc/xen-xsplice.c

diff --git a/tools/misc/Makefile b/tools/misc/Makefile
index c4490f3..c46873e 100644
--- a/tools/misc/Makefile
+++ b/tools/misc/Makefile
@@ -30,6 +30,7 @@ INSTALL_SBIN                   += xenlockprof
 INSTALL_SBIN                   += xenperf
 INSTALL_SBIN                   += xenpm
 INSTALL_SBIN                   += xenwatchdogd
+INSTALL_SBIN                   += xen-xsplice
 INSTALL_SBIN += $(INSTALL_SBIN-y)
 
 # Everything to be installed in a private bin/
@@ -98,6 +99,9 @@ xen-mfndump: xen-mfndump.o
 xenwatchdogd: xenwatchdogd.o
 	$(CC) $(LDFLAGS) -o $@ $< $(LDLIBS_libxenctrl) $(APPEND_LDFLAGS)
 
+xen-xsplice: xen-xsplice.o
+	$(CC) $(LDFLAGS) -o $@ $< $(LDLIBS_libxenctrl) $(APPEND_LDFLAGS)
+
 xen-lowmemd: xen-lowmemd.o
 	$(CC) $(LDFLAGS) -o $@ $< $(LDLIBS_libxenctrl) $(LDLIBS_libxenstore) $(APPEND_LDFLAGS)
 
diff --git a/tools/misc/xen-xsplice.c b/tools/misc/xen-xsplice.c
new file mode 100644
index 0000000..d8bd222
--- /dev/null
+++ b/tools/misc/xen-xsplice.c
@@ -0,0 +1,417 @@
+#include <xenctrl.h>
+#include <xenstore.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+static xc_interface *xch;
+
+void show_help(void)
+{
+    fprintf(stderr,
+            "xen-xsplice: Xsplice test tool\n"
+            "Usage: xen-xsplice <command> [args]\n"
+            " <id> An unique name of payload. Up to %d characters.\n"
+            "Commands:\n"
+            "  help                 display this help\n"
+            "  upload <id> <file>   upload file <cpuid> with <id> name\n"
+            "  list                 list payloads uploaded.\n"
+            "  apply <id>           apply <id> patch.\n"
+            "  revert <id>          revert id <id> patch.\n"
+            "  unload <id>          unload id <id> patch.\n"
+            "  check <id>           check id <id> patch.\n",
+            XEN_XSPLICE_ID_SIZE);
+}
+
+/* wrapper function */
+static int help_func(int argc, char *argv[])
+{
+    show_help();
+    return 0;
+}
+
+#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
+
+static const char *status2str(long status)
+{
+#define STATUS(x) [XSPLICE_STATUS_##x] = #x
+    static const char *const names[] = {
+            STATUS(LOADED),
+            STATUS(PROGRESS),
+            STATUS(CHECKED),
+            STATUS(APPLIED),
+            STATUS(REVERTED),
+    };
+
+    if (status >= ARRAY_SIZE(names))
+        return "unknown";
+
+    if (status < 0)
+        return "-EXX";
+
+    if (!names[status])
+        return "unknown";
+
+    return names[status];
+}
+
+#define MAX_LEN 11
+static int list_func(int argc, char *argv[])
+{
+    unsigned int idx, done, left, i;
+    xen_xsplice_status_t *info = NULL;
+    char *id = NULL;
+    uint32_t *len = NULL;
+    int rc = ENOMEM;
+
+    if ( argc )
+    {
+        show_help();
+        return -1;
+    }
+    idx = left = 0;
+    info = malloc(sizeof(*info) * MAX_LEN);
+    if ( !info )
+        goto out;
+    id = malloc(sizeof(*id) * XEN_XSPLICE_ID_SIZE * MAX_LEN);
+    if ( !id )
+        goto out;
+    len = malloc(sizeof(*len) * MAX_LEN);
+    if ( !len )
+        goto out;
+
+    fprintf(stdout," ID                                     | status\n"
+                   "----------------------------------------+------------\n");
+    do {
+        done = 0;
+        memset(info, 'A', sizeof(*info) * MAX_LEN); /* Optional. */
+        memset(id, 'i', sizeof(*id) * MAX_LEN * XEN_XSPLICE_ID_SIZE); /* Optional. */
+        memset(len, 'l', sizeof(*len) * MAX_LEN); /* Optional. */
+        rc = xc_xsplice_list(xch, MAX_LEN, idx, info, id, len, &done, &left);
+        if ( rc )
+        {
+            fprintf(stderr, "Failed to list %d/%d: %d(%s)!\n", idx, left, errno, strerror(errno));
+            break;
+        }
+        for ( i = 0; i < done; i++ )
+        {
+            unsigned int j;
+            uint32_t sz;
+            char *str;
+
+            sz = len[i];
+            str = id + (i * XEN_XSPLICE_ID_SIZE);
+            for ( j = sz; j < XEN_XSPLICE_ID_SIZE; j++ )
+                str[j] = '\0';
+
+            fprintf(stdout, "%-40s| ", str);
+            if ( info[i].status < 0 )
+                fprintf(stdout, "%s\n", strerror(info[i].status));
+            else
+                fprintf(stdout, "%s\n", status2str(info[i].status));
+        }
+        idx += done;
+    } while ( left );
+
+out:
+    free(id);
+    free(info);
+    free(len);
+    return rc;
+}
+#undef MAX_LEN
+
+static int get_id(int argc, char *argv[], char *id)
+{
+    ssize_t len = strlen(argv[0]);
+    if ( len > XEN_XSPLICE_ID_SIZE )
+    {
+        fprintf(stderr, "ID MUST be %d characters!\n", XEN_XSPLICE_ID_SIZE);
+        errno = EINVAL;
+        return errno;
+    }
+    /* Don't want any funny strings from the stack. */
+    memset(id, 0, XEN_XSPLICE_ID_SIZE);
+    strncpy(id, argv[0], len);
+    return 0;
+}
+
+static int upload_func(int argc, char *argv[])
+{
+    char *filename;
+    char id[XEN_XSPLICE_ID_SIZE];
+    int fd = 0, rc;
+    struct stat buf;
+    unsigned char *fbuf;
+    ssize_t len;
+    DECLARE_HYPERCALL_BUFFER(char, payload);
+
+    if ( argc != 2 )
+    {
+        show_help();
+        return -1;
+    }
+
+    if ( get_id(argc, argv, id) )
+        return EINVAL;
+
+    filename = argv[1];
+    fd = open(filename, O_RDONLY);
+    if ( fd < 0 )
+    {
+        fprintf(stderr, "Could not open %s, error: %d(%s)\n",
+                filename, errno, strerror(errno));
+        return errno;
+    }
+    if ( stat(filename, &buf) != 0 )
+    {
+        fprintf(stderr, "Could not get right size %s, error: %d(%s)\n",
+                filename, errno, strerror(errno));
+        close(fd);
+        return errno;
+    }
+
+    len = buf.st_size;
+    fbuf = mmap(0, len, PROT_READ, MAP_PRIVATE, fd, 0);
+    if ( fbuf == MAP_FAILED )
+    {
+        fprintf(stderr,"Could not map: %s, error: %d(%s)\n",
+                filename, errno, strerror(errno));
+        close (fd);
+        return errno;
+    }
+    printf("Uploading %s (%zu bytes)\n", filename, len);
+    payload = xc_hypercall_buffer_alloc(xch, payload, len);
+    memcpy(payload, fbuf, len);
+
+    rc = xc_xsplice_upload(xch, id, payload, len);
+    if ( rc )
+    {
+        fprintf(stderr, "Upload failed: %s, error: %d(%s)!\n",
+                filename, errno, strerror(errno));
+        goto out;
+    }
+    xc_hypercall_buffer_free(xch, payload);
+
+out:
+    if ( munmap( fbuf, len) )
+    {
+        fprintf(stderr, "Could not unmap!? error: %d(%s)!\n",
+                errno, strerror(errno));
+        rc = errno;
+    }
+    close(fd);
+
+    return rc;
+}
+
+enum {
+    ACTION_APPLY = 0,
+    ACTION_REVERT = 1,
+    ACTION_UNLOAD = 2,
+    ACTION_CHECK = 3
+};
+
+struct {
+    int allow; /* State it must be in to call function. */
+    int expected; /* The state to be in after the function. */
+    const char *name;
+    int (*function)(xc_interface *xch, char *id);
+    unsigned int executed; /* Has the function been called?. */
+} action_options[] = {
+    {   .allow = XSPLICE_STATUS_CHECKED | XSPLICE_STATUS_REVERTED,
+        .expected = XSPLICE_STATUS_APPLIED,
+        .name = "apply",
+        .function = xc_xsplice_apply,
+    },
+    {   .allow = XSPLICE_STATUS_APPLIED,
+        .expected = XSPLICE_STATUS_REVERTED,
+        .name = "revert",
+        .function = xc_xsplice_revert,
+    },
+    {   .allow = XSPLICE_STATUS_CHECKED | XSPLICE_STATUS_REVERTED | XSPLICE_STATUS_LOADED,
+        .expected = ENOENT,
+        .name = "unload",
+        .function = xc_xsplice_unload,
+    },
+    {   .allow = XSPLICE_STATUS_CHECKED | XSPLICE_STATUS_LOADED,
+        .expected = XSPLICE_STATUS_CHECKED,
+        .name = "check",
+        .function = xc_xsplice_check
+    },
+};
+
+int action_func(int argc, char *argv[], unsigned int idx)
+{
+    char id[XEN_XSPLICE_ID_SIZE];
+    int rc;
+    xen_xsplice_status_t status;
+    unsigned int retry = 0;
+
+    if ( argc != 1 )
+    {
+        show_help();
+        return -1;
+    }
+
+    if ( idx >= ARRAY_SIZE(action_options) )
+        return -1;
+
+    if ( get_id(argc, argv, id) )
+        return EINVAL;
+
+    do {
+        rc = xc_xsplice_get(xch, id, &status);
+        /* N.B. Successfull unload will return ENOENT. */
+        if ( rc )
+        {
+            rc = errno; /* rc is just -1 and we want proper EXX. */
+            break;
+        }
+
+        if ( status.status < 0 )
+        { /* We report it outside the loop. */
+            rc = status.status;
+            break;
+        }
+        if ( status.status == XSPLICE_STATUS_PROGRESS )
+        {
+            if ( !action_options[idx].executed )
+            {
+                printf("%s is in progress and we didn't initiate it!\n", id);
+                errno = EBUSY;
+                rc = -1;
+                break;
+            }
+            if ( retry++ < 30 )
+            {
+                printf(".");
+                sleep(1);
+                continue;
+            }
+            printf("%s: Waited more than 30 seconds! Bailing out.\n", id);
+            errno = EBUSY;
+            rc = -1;
+            break;
+        }
+        /* We use rc outside loop to deal with EXX type expected values. */
+        rc = status.status;
+        if ( action_options[idx].expected == rc ) /* Yeey! */
+            break;
+
+        if ( action_options[idx].allow & rc )
+        {
+            if ( action_options[idx].executed )
+            {
+                printf(" (0x%x vs 0x%x) state not reached!?\n",
+                       action_options[idx].expected, rc);
+                errno = EINVAL;
+                break;
+            }
+            printf("%s: State is 0x%x, ok are 0x%x. Commencing %s:",
+                   id, rc, action_options[idx].allow,
+                   action_options[idx].name);
+
+            rc = action_options[idx].function(xch, id);
+            if ( rc ) /* We report it outside the loop. */
+                break;
+
+            action_options[idx].executed = 1;
+            rc = 1; /* Loop again so we can display the dots. */
+        } else {
+            printf("%s: in wrong state (0x%x), expected 0x%x\n",
+                   id, rc, action_options[idx].expected);
+            errno = EINVAL;
+            rc = -1;
+            break;
+        }
+    } while ( rc > 0 );
+
+    if ( action_options[idx].expected == rc )
+    {
+            printf("completed!\n");
+            rc = 0;
+    } else
+        printf("%s failed with %d(%s)\n", id, errno, strerror(errno));
+
+    return rc;
+}
+static int all_func(int argc, char *argv[])
+{
+    int rc;
+
+    rc = upload_func(argc, argv);
+    if ( rc )
+        return rc;
+
+    rc = action_func(1 /* only id */, argv, ACTION_CHECK);
+    if ( rc )
+        goto unload;
+
+    rc = action_func(1 /* only id */, argv, ACTION_APPLY);
+    if ( rc )
+        goto unload;
+
+    return 0;
+unload:
+    action_func(argc, argv, ACTION_UNLOAD);
+    return rc;
+}
+
+struct {
+    const char *name;
+    int (*function)(int argc, char *argv[]);
+} main_options[] = {
+    { "help", help_func },
+    { "list", list_func },
+    { "upload", upload_func },
+    { "all", all_func },
+};
+
+int main(int argc, char *argv[])
+{
+    int i, j, ret;
+
+    if ( argc  <= 1 )
+    {
+        show_help();
+        return 0;
+    }
+    for ( i = 0; i < ARRAY_SIZE(main_options); i++ )
+        if (!strncmp(main_options[i].name, argv[1], strlen(argv[1])))
+            break;
+
+    if ( i == ARRAY_SIZE(main_options) )
+    {
+        for ( j = 0; j < ARRAY_SIZE(action_options); j++ )
+            if (!strncmp(action_options[j].name, argv[1], strlen(argv[1])))
+                break;
+
+        if ( j == ARRAY_SIZE(action_options) )
+        {
+            fprintf(stderr, "Unrecognised command '%s' -- try "
+                   "'xen-xsplice help'\n", argv[1]);
+            return 1;
+        }
+    } else
+        j = ARRAY_SIZE(action_options);
+
+    xch = xc_interface_open(0,0,0);
+    if ( !xch )
+    {
+        fprintf(stderr, "failed to get the handler\n");
+        return 0;
+    }
+
+    if ( i == ARRAY_SIZE(main_options) )
+        ret = action_func(argc -2, argv + 2, j);
+    else
+        ret = main_options[i].function(argc -2, argv + 2);
+
+    xc_interface_close(xch);
+
+    return !!ret;
+}
-- 
2.1.0

  parent reply	other threads:[~2015-09-16 21:01 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-09-16 21:01 [PATCH v1] xSplice initial foundation patches Konrad Rzeszutek Wilk
2015-09-16 21:01 ` [PATCH v1 1/5] xsplice: Design document Konrad Rzeszutek Wilk
2015-10-05 10:02   ` Jan Beulich
2015-10-05 10:28   ` Ross Lagerwall
2015-10-12 11:44     ` xsplice-build prototype (was [PATCH v1 1/5] xsplice: Design document.) Ross Lagerwall
2015-10-12 13:06       ` Konrad Rzeszutek Wilk
2015-10-12 14:20       ` Konrad Rzeszutek Wilk
2015-10-06 12:57   ` [PATCH v1 1/5] xsplice: Design document Ross Lagerwall
2015-10-27  8:08     ` Martin Pohlack
2015-10-27  8:45       ` Ross Lagerwall
2015-10-06 15:26   ` Jan Beulich
2015-10-26 12:01   ` Martin Pohlack
2015-10-26 12:10     ` Jan Beulich
2015-10-26 13:21     ` Ross Lagerwall
2015-10-26 13:55       ` Konrad Rzeszutek Wilk
2015-09-16 21:01 ` [PATCH v1 2/5] xen/xsplice: Hypervisor implementation of XEN_XSPLICE_op Konrad Rzeszutek Wilk
2015-10-02 15:06   ` Jan Beulich
2015-09-16 21:01 ` [PATCH v1 3/5] libxc: Implementation of XEN_XSPLICE_op in libxc Konrad Rzeszutek Wilk
2015-09-16 21:01 ` Konrad Rzeszutek Wilk [this message]
2015-09-16 21:01 ` [PATCH v1 5/5] xsplice: Use ld-embedded build-ids Konrad Rzeszutek Wilk
2015-09-16 21:41   ` Andrew Cooper
2015-09-16 21:59     ` Konrad Rzeszutek Wilk
2015-09-16 22:31       ` Andrew Cooper
2015-09-17  6:41         ` Martin Pohlack
2015-09-17  9:35           ` Andrew Cooper
2015-09-17 18:45             ` Is: Make XENVER_* use XSM, seperate the different ops in smaller security domains. Was:Re: " Konrad Rzeszutek Wilk
2015-09-18 11:40               ` Andrew Cooper
2015-09-22 13:22                 ` Konrad Rzeszutek Wilk
2015-09-22 13:33                   ` Andrew Cooper
2015-09-22 13:45                     ` Konrad Rzeszutek Wilk
2015-09-22 16:28                       ` Daniel De Graaf
2015-09-22 16:28               ` Daniel De Graaf
2015-09-25 20:18                 ` Konrad Rzeszutek Wilk
2015-10-02 15:13   ` Jan Beulich
2015-10-02 14:48 ` [PATCH v1] xSplice initial foundation patches Konrad Rzeszutek Wilk
2015-10-09 12:46   ` Konrad Rzeszutek Wilk

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1442437276-2620-5-git-send-email-konrad.wilk@oracle.com \
    --to=konrad.wilk@oracle.com \
    --cc=aliguori@amazon.com \
    --cc=amesserl@rackspace.com \
    --cc=andrew.cooper3@citrix.com \
    --cc=bob.liu@oracle.com \
    --cc=boris.ostrovsky@oracle.com \
    --cc=daniel.kiper@oracle.com \
    --cc=elena.ufimtseva@oracle.com \
    --cc=fanhenglong@huawei.com \
    --cc=hanweidong@huawei.com \
    --cc=ian.campbell@citrix.com \
    --cc=jbeulich@suse.com \
    --cc=jinsong.liu@alibaba-inc.com \
    --cc=john.liuqiming@huawei.com \
    --cc=josh.kearney@rackspace.com \
    --cc=lars.kurth@citrix.com \
    --cc=liuyingdong@huawei.com \
    --cc=major.hayden@rackspace.com \
    --cc=mpohlack@amazon.com \
    --cc=msw@amazon.com \
    --cc=paul.voccio@rackspace.com \
    --cc=peter.huangpeng@huawei.com \
    --cc=rick.harris@rackspace.com \
    --cc=steven.wilson@rackspace.com \
    --cc=xen-devel@lists.xenproject.org \
    --cc=xiantao.zxt@alibaba-inc.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).