From: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
To: konrad@kernel.org, xen-devel@lists.xenproject.org,
sasha.levin@oracle.com, andrew.cooper3@citrix.com,
ross.lagerwall@citrix.com, mpohlack@amazon.de
Cc: Wei Liu <wei.liu2@citrix.com>,
Stefano Stabellini <sstabellini@kernel.org>,
Ian Jackson <ian.jackson@eu.citrix.com>,
Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Subject: [PATCH v8 04/25] xen-xsplice: Tool to manipulate xsplice payloads
Date: Wed, 13 Apr 2016 17:09:35 -0400 [thread overview]
Message-ID: <1460581796-30071-5-git-send-email-konrad.wilk@oracle.com> (raw)
In-Reply-To: <1460581796-30071-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 name)
- List all the xsplice payloads loaded.
- Apply, revert, replace, or unload the payload using the
unique name.
- Do all two - upload, and apply the payload in one go (load).
Also will use the name of the file as the <name>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com>
Acked-by: Wei Liu <wei.liu2@citrix.com>
---
Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Cc: Stefano Stabellini <sstabellini@kernel.org>
Cc: Wei Liu <wei.liu2@citrix.com>
v2:
- Removed REVERTED state.
- Fixed bugs handling XSPLICE_STATUS_PROGRESS.
- Split status into state and error.
Add REPLACE action.
v3:
- Utilize the timeout and use the default one (let the hypervisor
pick it).
- Change the s/all/load and infer the <id> from name of file.
- s/id/name/
- Don't use hypercall buffer in upload_func, instead do it in libxc
- Remove the debug printk.
- Remove goto's (per Wei's review)
- Use fprintf(stderr in error paths.
- Add local variable block.
- Syntax, expand comment, and don't overwrite rc if xc_xsplice_upload failed.
v4:
- Remove LOADED state. Only have CHECKED state.
---
---
.gitignore | 1 +
tools/misc/Makefile | 4 +
tools/misc/xen-xsplice.c | 463 +++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 468 insertions(+)
create mode 100644 tools/misc/xen-xsplice.c
diff --git a/.gitignore b/.gitignore
index 20ffa2d..39eb779 100644
--- a/.gitignore
+++ b/.gitignore
@@ -182,6 +182,7 @@ tools/misc/xen_cpuperf
tools/misc/xen-cpuid
tools/misc/xen-detect
tools/misc/xen-tmem-list-parse
+tools/misc/xen-xsplice
tools/misc/xenperf
tools/misc/xenpm
tools/misc/xen-hvmctx
diff --git a/tools/misc/Makefile b/tools/misc/Makefile
index a94dad9..3a5f842 100644
--- a/tools/misc/Makefile
+++ b/tools/misc/Makefile
@@ -32,6 +32,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/
@@ -103,6 +104,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_libxenevtchn) $(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..fb9228e
--- /dev/null
+++ b/tools/misc/xen-xsplice.c
@@ -0,0 +1,463 @@
+/*
+ * Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <fcntl.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <xenctrl.h>
+#include <xenstore.h>
+
+static xc_interface *xch;
+
+void show_help(void)
+{
+ fprintf(stderr,
+ "xen-xsplice: Xsplice test tool\n"
+ "Usage: xen-xsplice <command> [args]\n"
+ " <name> An unique name of payload. Up to %d characters.\n"
+ "Commands:\n"
+ " help display this help\n"
+ " upload <name> <file> upload file <file> with <name> name\n"
+ " list list payloads uploaded.\n"
+ " apply <name> apply <name> patch.\n"
+ " revert <name> revert name <name> patch.\n"
+ " replace <name> apply <name> patch and revert all others.\n"
+ " unload <name> unload name <name> patch.\n"
+ " load <file> upload, check and apply <file>.\n"
+ " name is the <file> name\n",
+ XEN_XSPLICE_NAME_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 *state2str(unsigned int state)
+{
+#define STATE(x) [XSPLICE_STATE_##x] = #x
+ static const char *const names[] = {
+ STATE(CHECKED),
+ STATE(APPLIED),
+ };
+#undef STATE
+ if (state >= ARRAY_SIZE(names) || !names[state])
+ return "unknown";
+
+ return names[state];
+}
+
+/* This value was choosen adhoc. It could be 42 too. */
+#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 *name = 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 )
+ return rc;
+ name = malloc(sizeof(*name) * XEN_XSPLICE_NAME_SIZE * MAX_LEN);
+ if ( !name )
+ {
+ free(info);
+ return rc;
+ }
+ len = malloc(sizeof(*len) * MAX_LEN);
+ if ( !len ) {
+ free(name);
+ free(info);
+ return rc;
+ }
+
+ fprintf(stdout," ID | status\n"
+ "----------------------------------------+------------\n");
+ do {
+ done = 0;
+ /* The memset is done to catch errors. */
+ memset(info, 'A', sizeof(*info) * MAX_LEN);
+ memset(name, 'B', sizeof(*name * MAX_LEN * XEN_XSPLICE_NAME_SIZE));
+ memset(len, 'C', sizeof(*len) * MAX_LEN);
+ rc = xc_xsplice_list(xch, MAX_LEN, idx, info, name, 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 = name + (i * XEN_XSPLICE_NAME_SIZE);
+ for ( j = sz; j < XEN_XSPLICE_NAME_SIZE; j++ )
+ str[j] = '\0';
+
+ printf("%-40s| %s", str, state2str(info[i].state));
+ if ( info[i].rc )
+ printf(" (%d, %s)\n", -info[i].rc, strerror(-info[i].rc));
+ else
+ puts("");
+ }
+ idx += done;
+ } while ( left );
+
+ free(name);
+ free(info);
+ free(len);
+ return rc;
+}
+#undef MAX_LEN
+
+static int get_name(int argc, char *argv[], char *name)
+{
+ ssize_t len = strlen(argv[0]);
+ if ( len > XEN_XSPLICE_NAME_SIZE )
+ {
+ fprintf(stderr, "ID MUST be %d characters!\n", XEN_XSPLICE_NAME_SIZE);
+ errno = EINVAL;
+ return errno;
+ }
+ /* Don't want any funny strings from the stack. */
+ memset(name, 0, XEN_XSPLICE_NAME_SIZE);
+ strncpy(name, argv[0], len);
+ return 0;
+}
+
+static int upload_func(int argc, char *argv[])
+{
+ char *filename;
+ char name[XEN_XSPLICE_NAME_SIZE];
+ int fd = 0, rc;
+ struct stat buf;
+ unsigned char *fbuf;
+ ssize_t len;
+
+ if ( argc != 2 )
+ {
+ show_help();
+ return -1;
+ }
+
+ if ( get_name(argc, argv, name) )
+ 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);
+ rc = xc_xsplice_upload(xch, name, fbuf, len);
+ if ( rc )
+ fprintf(stderr, "Upload failed: %s, error: %d(%s)!\n",
+ filename, errno, strerror(errno));
+
+ if ( munmap( fbuf, len) )
+ {
+ fprintf(stderr, "Could not unmap!? error: %d(%s)!\n",
+ errno, strerror(errno));
+ if ( !rc )
+ rc = errno;
+ }
+ close(fd);
+
+ return rc;
+}
+
+/* These MUST match to the 'action_options[]' array slots. */
+enum {
+ ACTION_APPLY = 0,
+ ACTION_REVERT = 1,
+ ACTION_UNLOAD = 2,
+ ACTION_REPLACE = 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 *name, uint32_t timeout);
+ unsigned int executed; /* Has the function been called?. */
+} action_options[] = {
+ { .allow = XSPLICE_STATE_CHECKED,
+ .expected = XSPLICE_STATE_APPLIED,
+ .name = "apply",
+ .function = xc_xsplice_apply,
+ },
+ { .allow = XSPLICE_STATE_APPLIED,
+ .expected = XSPLICE_STATE_CHECKED,
+ .name = "revert",
+ .function = xc_xsplice_revert,
+ },
+ { .allow = XSPLICE_STATE_CHECKED,
+ .expected = -ENOENT,
+ .name = "unload",
+ .function = xc_xsplice_unload,
+ },
+ { .allow = XSPLICE_STATE_CHECKED,
+ .expected = XSPLICE_STATE_APPLIED,
+ .name = "replace",
+ .function = xc_xsplice_replace,
+ },
+};
+
+/* Go around 300 * 0.1 seconds = 30 seconds. */
+#define RETRIES 300
+/* aka 0.1 second */
+#define DELAY 100000
+
+int action_func(int argc, char *argv[], unsigned int idx)
+{
+ char name[XEN_XSPLICE_NAME_SIZE];
+ int rc, original_state;
+ 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_name(argc, argv, name) )
+ return EINVAL;
+
+ /* Check initial status. */
+ rc = xc_xsplice_get(xch, name, &status);
+ if ( rc )
+ {
+ fprintf(stderr, "%s failed to get status (rc=%d, %s)!\n",
+ name, -rc, strerror(-rc));
+ return -1;
+ }
+ if ( status.rc == -EAGAIN )
+ {
+ fprintf(stderr, "%s failed. Operation already in progress\n", name);
+ return -1;
+ }
+
+ if ( status.state == action_options[idx].expected )
+ {
+ printf("No action needed\n");
+ return 0;
+ }
+
+ /* Perform action. */
+ if ( action_options[idx].allow & status.state )
+ {
+ printf("Performing %s:", action_options[idx].name);
+ rc = action_options[idx].function(xch, name, 0);
+ if ( rc )
+ {
+ fprintf(stderr, "%s failed with %d(%s)\n", name, -rc, strerror(-rc));
+ return -1;
+ }
+ }
+ else
+ {
+ printf("%s: in wrong state (%s), expected (%s)\n",
+ name, state2str(status.state),
+ state2str(action_options[idx].expected));
+ return -1;
+ }
+
+ original_state = status.state;
+ do {
+ rc = xc_xsplice_get(xch, name, &status);
+ if ( rc )
+ {
+ rc = -errno;
+ break;
+ }
+
+ if ( status.state != original_state )
+ break;
+ if ( status.rc && status.rc != -EAGAIN )
+ {
+ rc = status.rc;
+ break;
+ }
+
+ printf(".");
+ fflush(stdout);
+ usleep(DELAY);
+ } while ( ++retry < RETRIES );
+
+ if ( retry >= RETRIES )
+ {
+ fprintf(stderr, "%s: Operation didn't complete after 30 seconds.\n", name);
+ return -1;
+ }
+ else
+ {
+ if ( rc == 0 )
+ rc = status.state;
+
+ if ( action_options[idx].expected == rc )
+ printf(" completed\n");
+ else if ( rc < 0 )
+ {
+ fprintf(stderr, "%s failed with %d(%s)\n", name, -rc, strerror(-rc));
+ return -1;
+ }
+ else
+ {
+ fprintf(stderr, "%s: in wrong state (%s), expected (%s)\n",
+ name, state2str(rc),
+ state2str(action_options[idx].expected));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int load_func(int argc, char *argv[])
+{
+ int rc;
+ char *new_argv[2];
+ char *path, *name, *lastdot;
+
+ if ( argc != 1 )
+ {
+ show_help();
+ return -1;
+ }
+ /* <file> */
+ new_argv[1] = argv[0];
+
+ /* Synthesize the <id> */
+ path = strdup(argv[0]);
+
+ name = basename(path);
+ lastdot = strrchr(name, '.');
+ if ( lastdot != NULL )
+ *lastdot = '\0';
+ new_argv[0] = name;
+
+ rc = upload_func(2 /* <id> <file> */, new_argv);
+ if ( rc )
+ return rc;
+
+ rc = action_func(1 /* only <id> */, new_argv, ACTION_APPLY);
+ if ( rc )
+ action_func(1, new_argv, ACTION_UNLOAD);
+
+ free(path);
+ return rc;
+}
+
+/*
+ * These are also functions in action_options that are called in case
+ * none of the ones in main_options match.
+ */
+struct {
+ const char *name;
+ int (*function)(int argc, char *argv[]);
+} main_options[] = {
+ { "help", help_func },
+ { "list", list_func },
+ { "upload", upload_func },
+ { "load", load_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;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--
2.5.0
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel
next prev parent reply other threads:[~2016-04-13 21:10 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-04-13 21:09 [PATCH v8] xSplice v1 design and implementation Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 01/25] xsplice: Design document Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 02/25] xen/xsplice: Hypervisor implementation of XEN_XSPLICE_op Konrad Rzeszutek Wilk
2016-04-20 13:18 ` Ross Lagerwall
2016-04-22 18:06 ` Konrad Rzeszutek Wilk
2016-04-25 9:03 ` Jan Beulich
2016-04-25 9:13 ` Ross Lagerwall
2016-04-13 21:09 ` [PATCH v8 03/25] libxc: Implementation of XEN_XSPLICE_op in libxc Konrad Rzeszutek Wilk
2016-04-13 21:09 ` Konrad Rzeszutek Wilk [this message]
2016-04-13 21:09 ` [PATCH v8 05/25] arm/x86: Use struct virtual_region to do bug, symbol, and (x86) exception tables lookup Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 06/25] arm/x86/vmap: Add vmalloc_xen, vfree_xen and vm_init_type Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 07/25] x86/mm: Introduce modify_xen_mappings() Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 08/25] xsplice: Add helper elf routines Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 09/25] xsplice: Implement payload loading Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 10/25] xsplice: Implement support for applying/reverting/replacing patches Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 11/25] x86/xen_hello_world.xsplice: Test payload for patching 'xen_extra_version' Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 12/25] xsplice, symbols: Implement symbol name resolution on address Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 13/25] xsplice, symbols: Implement fast symbol names -> virtual addresses lookup Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 14/25] x86, xsplice: Print payload's symbol name and payload name in backtraces Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 15/25] xsplice: Add support for bug frames Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 16/25] xsplice: Add support for exception tables Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 17/25] xsplice: Add support for alternatives Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 18/25] build_id: Provide ld-embedded build-ids Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 19/25] HYPERCALL_version_op: Add VERSION_build_id to retrieve build-id Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 20/25] libxl: info: Display build_id of the hypervisor using XEN_VERSION_build_id Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 21/25] xsplice: Print build_id in keyhandler and on bootup Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 22/25] xsplice: Stacking build-id dependency checking Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 23/25] xsplice/xen_replace_world: Test-case for XSPLICE_ACTION_REPLACE Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 24/25] xsplice: Prevent duplicate payloads from being loaded Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 25/25] MAINTAINERS/xsplice: Add myself and Ross as the maintainers Konrad Rzeszutek Wilk
2016-04-13 21:57 ` [PATCH v8] xSplice v1 design and implementation Konrad Rzeszutek Wilk
2016-04-13 22:01 ` 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=1460581796-30071-5-git-send-email-konrad.wilk@oracle.com \
--to=konrad.wilk@oracle.com \
--cc=andrew.cooper3@citrix.com \
--cc=ian.jackson@eu.citrix.com \
--cc=konrad@kernel.org \
--cc=mpohlack@amazon.de \
--cc=ross.lagerwall@citrix.com \
--cc=sasha.levin@oracle.com \
--cc=sstabellini@kernel.org \
--cc=wei.liu2@citrix.com \
--cc=xen-devel@lists.xenproject.org \
/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).