[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v1 4/5] xen-xsplice: Tool to manipulate xsplice payloads.
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@xxxxxxxxxx> --- 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 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |