tools/xenstore: add live update command to xenstore-control

Add the "live-update" command to xenstore-control enabling updating
xenstored to a new version in a running Xen system.

With -c <arg> it is possible to pass a different command line to the
new instance of xenstored. This will replace the command line used
for the invocation of the just running xenstored instance.

The running xenstored (or xenstore-stubdom) needs to support live
updating, of course.

For now just add a small dummy handler to C xenstore denying any
live update action.

Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Paul Durrant <paul@xen.org>
Reviewed-by: Julien Grall <jgrall@amazon.com>
Acked-by: Wei Liu <wl@xen.org>
This commit is contained in:
Juergen Gross committed 2021-01-21 17:29:44 +01:00
1 parent 7104017a13
commit 7f97193e6a
4 files changed
+370 -17

No files matched your search

+21
View File
@@ -317,6 +317,27 @@ CONTROL <command>|[<parameters>|]
Current commands are:
check
checks xenstored innards
live-update|<params>|+
perform a live-update of the Xenstore daemon, only to
be used via xenstore-control command.
<params> are implementation specific and are used for
different steps of the live-update processing. Currently
supported <params> are:
-f <file> specify new daemon binary
-b <size> specify size of new stubdom binary
-d <chunk-size> <binary-chunk> transfer chunk of new
stubdom binary
-c <pars> specify new command line to use
-s [-t <sec>] [-F] start live update process (-t specifies
timeout in seconds to wait for active transactions
to finish, default is 60 seconds; -F will force
live update to happen even with running transactions
after timeout elapsed)
-a abort live update handling
All sub-options will return "OK" in case of success or an
error string in case of failure. -s can return "BUSY" in case
of an active transaction, a retry of -s can be done in that
case.
log|on
turn xenstore logging on
log|off
+2 -1
View File
@@ -11,6 +11,7 @@ CFLAGS += -include $(XEN_ROOT)/tools/config.h
CFLAGS += -I./include
CFLAGS += $(CFLAGS_libxenevtchn)
CFLAGS += $(CFLAGS_libxenctrl)
CFLAGS += $(CFLAGS_libxenguest)
CFLAGS += $(CFLAGS_libxentoolcore)
CFLAGS += -DXEN_LIB_STORED="\"$(XEN_LIB_STORED)\""
CFLAGS += -DXEN_RUN_STORED="\"$(XEN_RUN_STORED)\""
@@ -81,7 +82,7 @@ xenstore: xenstore_client.o
$(CC) $< $(LDFLAGS) $(LDLIBS_libxenstore) $(LDLIBS_libxentoolcore) $(SOCKET_LIBS) -o $@ $(APPEND_LDFLAGS)
xenstore-control: xenstore_control.o
$(CC) $< $(LDFLAGS) $(LDLIBS_libxenstore) $(LDLIBS_libxentoolcore) $(SOCKET_LIBS) -o $@ $(APPEND_LDFLAGS)
$(CC) $< $(LDFLAGS) $(LDLIBS_libxenstore) $(LDLIBS_libxenctrl) $(LDLIBS_libxenguest) $(LDLIBS_libxentoolcore) $(SOCKET_LIBS) -o $@ $(APPEND_LDFLAGS)
xs_tdb_dump: xs_tdb_dump.o utils.o tdb.o talloc.o
$(CC) $^ $(LDFLAGS) -o $@ $(APPEND_LDFLAGS)
+317 -16
View File
@@ -1,9 +1,312 @@
#define _GNU_SOURCE
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <xenctrl.h>
#include <xenguest.h>
#include "xenstore.h"
/* Add a string plus terminating 0 byte to buf, returning new len. */
static int add_to_buf(char **buf, const char *val, int len)
{
int vallen = strlen(val) + 1;
if (len < 0)
return -1;
*buf = realloc(*buf, len + vallen);
if (!*buf)
return -1;
strcpy(*buf + len, val);
return len + vallen;
}
static int live_update_start(struct xs_handle *xsh, bool force, unsigned int to)
{
int len = 0;
char *buf = NULL, *ret;
time_t time_start;
if (asprintf(&ret, "%u", to) < 0)
return 1;
len = add_to_buf(&buf, "-s", len);
len = add_to_buf(&buf, "-t", len);
len = add_to_buf(&buf, ret, len);
free(ret);
if (force)
len = add_to_buf(&buf, "-F", len);
if (len < 0)
return 1;
for (time_start = time(NULL); time(NULL) - time_start < to;) {
ret = xs_control_command(xsh, "live-update", buf, len);
if (!ret)
goto err;
if (strcmp(ret, "BUSY"))
break;
sleep(1);
}
if (strcmp(ret, "OK"))
goto err;
free(buf);
free(ret);
return 0;
err:
fprintf(stderr, "Starting live update failed:\n%s\n",
ret ? : strerror(errno));
free(buf);
free(ret);
return 3;
}
static int live_update_cmdline(struct xs_handle *xsh, const char *cmdline)
{
int len = 0, rc = 0;
char *buf = NULL, *ret;
len = add_to_buf(&buf, "-c", len);
len = add_to_buf(&buf, cmdline, len);
if (len < 0)
return 1;
ret = xs_control_command(xsh, "live-update", buf, len);
free(buf);
if (!ret || strcmp(ret, "OK")) {
fprintf(stderr, "Setting update binary failed:\n%s\n",
ret ? : strerror(errno));
rc = 3;
}
free(ret);
return rc;
}
static int send_kernel_blob(struct xs_handle *xsh, const char *binary)
{
int rc = 0, len = 0;
xc_interface *xch;
struct xc_dom_image *dom;
char *ret, *buf = NULL;
size_t off, sz;
#define BLOB_CHUNK_SZ 2048
xch = xc_interface_open(NULL, NULL, 0);
if (!xch) {
fprintf(stderr, "xc_interface_open() failed\n");
return 1;
}
dom = xc_dom_allocate(xch, NULL, NULL);
if (!dom) {
rc = 1;
goto out_close;
}
rc = xc_dom_kernel_file(dom, binary);
if (rc) {
rc = 1;
goto out_rel;
}
if (asprintf(&ret, "%zu", dom->kernel_size) < 0) {
rc = 1;
goto out_rel;
}
len = add_to_buf(&buf, "-b", len);
len = add_to_buf(&buf, ret, len);
free(ret);
if (len < 0) {
rc = 1;
goto out_rel;
}
ret = xs_control_command(xsh, "live-update", buf, len);
free(buf);
if (!ret || strcmp(ret, "OK")) {
fprintf(stderr, "Starting live update failed:\n%s\n",
ret ? : strerror(errno));
rc = 3;
}
free(ret);
if (rc)
goto out_rel;
/* buf capable to hold "-d" <1..2048> BLOB_CHUNK_SZ and a terminating 0. */
buf = malloc(3 + 5 + BLOB_CHUNK_SZ + 1);
if (!buf) {
rc = 1;
goto out_rel;
}
strcpy(buf, "-d");
sz = BLOB_CHUNK_SZ;
for (off = 0; off < dom->kernel_size; off += BLOB_CHUNK_SZ) {
if (dom->kernel_size - off < BLOB_CHUNK_SZ)
sz = dom->kernel_size - off;
sprintf(buf + 3, "%zu", sz);
len = 3 + strlen(buf + 3) + 1;
memcpy(buf + len, dom->kernel_blob + off, sz);
buf[len + sz] = 0;
len += sz + 1;
ret = xs_control_command(xsh, "live-update", buf, len);
if (!ret || strcmp(ret, "OK")) {
fprintf(stderr, "Transfer of new binary failed:\n%s\n",
ret ? : strerror(errno));
rc = 3;
free(ret);
break;
}
free(ret);
}
free(buf);
out_rel:
xc_dom_release(dom);
out_close:
xc_interface_close(xch);
return rc;
}
/*
* Live update of Xenstore stubdom
*
* Sequence of actions:
* 1. transfer new stubdom binary
* a) specify size
* b) transfer unpacked binary in chunks
* 2. transfer new cmdline (optional)
* 3. start update (includes flags)
*/
static int live_update_stubdom(struct xs_handle *xsh, const char *binary,
const char *cmdline, bool force, unsigned int to)
{
int rc;
rc = send_kernel_blob(xsh, binary);
if (rc)
goto abort;
if (cmdline) {
rc = live_update_cmdline(xsh, cmdline);
if (rc)
goto abort;
}
rc = live_update_start(xsh, force, to);
if (rc)
goto abort;
return 0;
abort:
xs_control_command(xsh, "live-update", "-a", 3);
return rc;
}
/*
* Live update of Xenstore daemon
*
* Sequence of actions:
* 1. transfer new binary filename
* 2. transfer new cmdline (optional)
* 3. start update (includes flags)
*/
static int live_update_daemon(struct xs_handle *xsh, const char *binary,
const char *cmdline, bool force, unsigned int to)
{
int len = 0, rc;
char *buf = NULL, *ret;
len = add_to_buf(&buf, "-f", len);
len = add_to_buf(&buf, binary, len);
if (len < 0)
return 1;
ret = xs_control_command(xsh, "live-update", buf, len);
free(buf);
if (!ret || strcmp(ret, "OK")) {
fprintf(stderr, "Setting update binary failed:\n%s\n",
ret ? : strerror(errno));
free(ret);
return 3;
}
free(ret);
if (cmdline) {
rc = live_update_cmdline(xsh, cmdline);
if (rc)
goto abort;
}
rc = live_update_start(xsh, force, to);
if (rc)
goto abort;
return 0;
abort:
xs_control_command(xsh, "live-update", "-a", 3);
return rc;
}
static int live_update(struct xs_handle *xsh, int argc, char **argv)
{
int rc = 0;
unsigned int i, to = 60;
char *binary = NULL, *cmdline = NULL, *val;
bool force = false;
for (i = 0; i < argc; i++) {
if (!strcmp(argv[i], "-c")) {
i++;
if (i == argc) {
fprintf(stderr, "Missing command line value\n");
rc = 2;
goto out;
}
cmdline = argv[i];
} else if (!strcmp(argv[i], "-t")) {
i++;
if (i == argc) {
fprintf(stderr, "Missing timeout value\n");
rc = 2;
goto out;
}
to = atoi(argv[i]);
} else if (!strcmp(argv[i], "-F"))
force = true;
else
binary = argv[i];
}
if (!binary) {
fprintf(stderr, "Missing binary specification\n");
rc = 2;
goto out;
}
val = xs_read(xsh, XBT_NULL, "/tool/xenstored/domid", &i);
if (val)
rc = live_update_stubdom(xsh, binary, cmdline, force, to);
else
rc = live_update_daemon(xsh, binary, cmdline, force, to);
free(val);
out:
return rc;
}
int main(int argc, char **argv)
{
@@ -20,22 +323,6 @@ int main(int argc, char **argv)
goto out;
}
for (p = 2; p < argc; p++)
len += strlen(argv[p]) + 1;
if (len) {
par = malloc(len);
if (!par) {
fprintf(stderr, "Allocation error.\n");
rc = 1;
goto out;
}
len = 0;
for (p = 2; p < argc; p++) {
memcpy(par + len, argv[p], strlen(argv[p]) + 1);
len += strlen(argv[p]) + 1;
}
}
xsh = xs_open(0);
if (xsh == NULL) {
fprintf(stderr, "Failed to contact Xenstored.\n");
@@ -43,6 +330,19 @@ int main(int argc, char **argv)
goto out;
}
if (!strcmp(argv[1], "live-update")) {
rc = live_update(xsh, argc - 2, argv + 2);
goto out_close;
}
for (p = 2; p < argc; p++)
len = add_to_buf(&par, argv[p], len);
if (len < 0) {
fprintf(stderr, "Allocation error.\n");
rc = 1;
goto out_close;
}
ret = xs_control_command(xsh, argv[1], par, len);
if (!ret) {
rc = 3;
@@ -59,6 +359,7 @@ int main(int argc, char **argv)
} else if (strlen(ret) > 0)
printf("%s\n", ret);
out_close:
xs_close(xsh);
out:
+30
View File
@@ -149,11 +149,41 @@ static int do_control_print(void *ctx, struct connection *conn,
return 0;
}
static int do_control_lu(void *ctx, struct connection *conn,
char **vec, int num)
{
const char *resp;
resp = talloc_strdup(ctx, "NYI");
send_reply(conn, XS_CONTROL, resp, strlen(resp) + 1);
return 0;
}
static int do_control_help(void *, struct connection *, char **, int);
static struct cmd_s cmds[] = {
{ "check", do_control_check, "" },
{ "log", do_control_log, "on|off" },
/*
* The parameters are those of the xenstore-control utility!
* Depending on environment (Mini-OS or daemon) the live-update
* sequence is split into several sub-operations:
* 1. Specification of new binary
* daemon: -f <filename>
* Mini-OS: -b <binary-size>
* -d <size> <data-bytes> (multiple of those)
* 2. New command-line (optional): -c <cmdline>
* 3. Start of update: -s [-F] [-t <timeout>]
* Any sub-operation needs to respond with the string "OK" in case
* of success, any other response indicates failure.
* A started live-update sequence can be aborted via "-a" (not
* needed in case of failure for the first or last live-update
* sub-operation).
*/
{ "live-update", do_control_lu,
"[-c <cmdline>] [-F] [-t <timeout>] <file>\n"
" Default timeout is 60 seconds.", 4 },
#ifdef __MINIOS__
{ "memreport", do_control_memreport, "" },
#else
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.