From nobody Mon Feb 9 08:55:20 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass(p=quarantine dis=none) header.from=suse.com ARC-Seal: i=1; a=rsa-sha256; t=1608050221; cv=none; d=zohomail.com; s=zohoarc; b=lSjv6ytKSCR8Se1mueho/T3HsKaWEPJ6AZhAh9ejA3dQtFZFTty/7BsDVCbDJJ3C4XnlASt9UOGkYrEzf4aOr7F2ycLgAjDNgwDTQ3FBWT00H5id95Y9fdwpZ8/uVm3ZnOkPdDT5DV2Ayh4GwkntWIxw9oFGK5jvFZnVeGbQ4RQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1608050221; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=Pqaa2EAISfoqMQYdGvAptWd4x6dr6DKrqL0LaEJ013g=; b=DB6N42sUSk4e0DNolpia3XHfJ5X73w+XZOKrB0I0jv6qANVyVT9F8abAvQZNAYaI74IdqnzGHRrokBd0GcDYW9m13SdEKbYYQ3ld7bDLM3i2/bIYRhZ3l5h1k7BO3sfLtXA1Fdy7cMD+Aq3HgwIm/yOawNW3LmZzAx7YzcOakAk= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass header.from= (p=quarantine dis=none) header.from= Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1608050221499758.6124740060889; Tue, 15 Dec 2020 08:37:01 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.54557.94978 (Exim 4.92) (envelope-from ) id 1kpDJb-00074I-DL; Tue, 15 Dec 2020 16:36:43 +0000 Received: by outflank-mailman (output) from mailman id 54557.94978; Tue, 15 Dec 2020 16:36:43 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1kpDJb-00073m-11; Tue, 15 Dec 2020 16:36:43 +0000 Received: by outflank-mailman (input) for mailman id 54557; Tue, 15 Dec 2020 16:36:41 +0000 Received: from all-amaz-eas1.inumbo.com ([34.197.232.57] helo=us1-amaz-eas2.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1kpDJZ-00066M-Hy for xen-devel@lists.xenproject.org; Tue, 15 Dec 2020 16:36:41 +0000 Received: from mx2.suse.de (unknown [195.135.220.15]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id edb30b2c-898a-4786-a166-5a33fabf2be1; Tue, 15 Dec 2020 16:36:11 +0000 (UTC) Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id F269CAF73; Tue, 15 Dec 2020 16:36:08 +0000 (UTC) X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: edb30b2c-898a-4786-a166-5a33fabf2be1 X-Virus-Scanned: by amavisd-new at test-mx.suse.de DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1608050169; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Pqaa2EAISfoqMQYdGvAptWd4x6dr6DKrqL0LaEJ013g=; b=DvLlmnlO946ltBwXIbxkN5+QAUTA1nV9fl8ji2mxnxtW3FUSU67Y/rfR7kgIk/jJq8BQQf EkQBTUr++toDfK6MKVxRqoL/04i0qDACbBk8XjVKoR+VkC5k2L5ocESV91eNPHv8PO8Oi1 RlFinGRUo0e3mazFPD6fUMHulqGrKJM= From: Juergen Gross To: xen-devel@lists.xenproject.org Cc: Juergen Gross , Andrew Cooper , George Dunlap , Ian Jackson , Jan Beulich , Julien Grall , Stefano Stabellini , Wei Liu , Paul Durrant , Julien Grall Subject: [PATCH v10 06/25] tools/xenstore: add live update command to xenstore-control Date: Tue, 15 Dec 2020 17:35:44 +0100 Message-Id: <20201215163603.21700-7-jgross@suse.com> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20201215163603.21700-1-jgross@suse.com> References: <20201215163603.21700-1-jgross@suse.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @suse.com) Content-Type: text/plain; charset="utf-8" Add the "live-update" command to xenstore-control enabling updating xenstored to a new version in a running Xen system. With -c 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 Reviewed-by: Paul Durrant Reviewed-by: Julien Grall --- V2: - add 0 byte after kernel chunk - add comment regrading add_to_buf() semantics (Pawel Wieczorkiewicz) - use %u for unsigned in format (Pawel Wieczorkiewicz) - explain buffer size better (Pawel Wieczorkiewicz) - add loop around "-s" option for client side retry in case of timeout V3: - add live-update command to docs/misc/xenstore.txt (Paul Durrant) - fix indent (Paul Durrant) V4: - made several parameters const (Julien Grall) - added more details to xenstore.txt (Julien Grall) V5: - set old_binary to NULL initially (Paul Durrant) V6: - use strerror(errno) in error message (Julien Grall) V10: - make binary specification mandatory (Andrew Cooper) Signed-off-by: Juergen Gross --- docs/misc/xenstore.txt | 21 ++ tools/xenstore/Makefile | 3 +- tools/xenstore/xenstore_control.c | 332 +++++++++++++++++++++++++++-- tools/xenstore/xenstored_control.c | 30 +++ 4 files changed, 369 insertions(+), 17 deletions(-) diff --git a/docs/misc/xenstore.txt b/docs/misc/xenstore.txt index 2081f20f55..1480742330 100644 --- a/docs/misc/xenstore.txt +++ b/docs/misc/xenstore.txt @@ -317,6 +317,27 @@ CONTROL |[|] Current commands are: check checks xenstored innards + live-update||+ + perform a live-update of the Xenstore daemon, only to + be used via xenstore-control command. + are implementation specific and are used for + different steps of the live-update processing. Currently + supported are: + -f specify new daemon binary + -b specify size of new stubdom binary + -d transfer chunk of new + stubdom binary + -c specify new command line to use + -s [-t ] [-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 diff --git a/tools/xenstore/Makefile b/tools/xenstore/Makefile index 9a0f0d012d..ab89e22d3a 100644 --- a/tools/xenstore/Makefile +++ b/tools/xenstore/Makefile @@ -11,6 +11,7 @@ CFLAGS +=3D -include $(XEN_ROOT)/tools/config.h CFLAGS +=3D -I./include CFLAGS +=3D $(CFLAGS_libxenevtchn) CFLAGS +=3D $(CFLAGS_libxenctrl) +CFLAGS +=3D $(CFLAGS_libxenguest) CFLAGS +=3D $(CFLAGS_libxentoolcore) CFLAGS +=3D -DXEN_LIB_STORED=3D"\"$(XEN_LIB_STORED)\"" CFLAGS +=3D -DXEN_RUN_STORED=3D"\"$(XEN_RUN_STORED)\"" @@ -81,7 +82,7 @@ xenstore: xenstore_client.o $(CC) $< $(LDFLAGS) $(LDLIBS_libxenstore) $(LDLIBS_libxentoolcore) $(SOCK= ET_LIBS) -o $@ $(APPEND_LDFLAGS) =20 xenstore-control: xenstore_control.o - $(CC) $< $(LDFLAGS) $(LDLIBS_libxenstore) $(LDLIBS_libxentoolcore) $(SOCK= ET_LIBS) -o $@ $(APPEND_LDFLAGS) + $(CC) $< $(LDFLAGS) $(LDLIBS_libxenstore) $(LDLIBS_libxenctrl) $(LDLIBS_l= ibxenguest) $(LDLIBS_libxentoolcore) $(SOCKET_LIBS) -o $@ $(APPEND_LDFLAGS) =20 xs_tdb_dump: xs_tdb_dump.o utils.o tdb.o talloc.o $(CC) $^ $(LDFLAGS) -o $@ $(APPEND_LDFLAGS) diff --git a/tools/xenstore/xenstore_control.c b/tools/xenstore/xenstore_co= ntrol.c index afa04495a7..5ca015a07d 100644 --- a/tools/xenstore/xenstore_control.c +++ b/tools/xenstore/xenstore_control.c @@ -1,9 +1,311 @@ +#define _GNU_SOURCE +#include #include #include #include +#include +#include +#include =20 #include "xenstore.h" =20 +/* 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 =3D strlen(val) + 1; + + if (len < 0) + return -1; + + *buf =3D 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 i= nt to) +{ + int len =3D 0; + char *buf =3D NULL, *ret; + time_t time_start; + + if (asprintf(&ret, "%u", to) < 0) + return 1; + len =3D add_to_buf(&buf, "-s", len); + len =3D add_to_buf(&buf, "-t", len); + len =3D add_to_buf(&buf, ret, len); + free(ret); + if (force) + len =3D add_to_buf(&buf, "-F", len); + if (len < 0) + return 1; + + for (time_start =3D time(NULL); time(NULL) - time_start < to;) { + ret =3D xs_control_command(xsh, "live-update", buf, len); + if (!ret) + goto err; + if (strcmp(ret, "BUSY")) + break; + } + + 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 =3D 0, rc =3D 0; + char *buf =3D NULL, *ret; + + len =3D add_to_buf(&buf, "-c", len); + len =3D add_to_buf(&buf, cmdline, len); + if (len < 0) + return 1; + + ret =3D 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 =3D 3; + } + free(ret); + + return rc; +} + +static int send_kernel_blob(struct xs_handle *xsh, const char *binary) +{ + int rc =3D 0, len =3D 0; + xc_interface *xch; + struct xc_dom_image *dom; + char *ret, *buf =3D NULL; + size_t off, sz; +#define BLOB_CHUNK_SZ 2048 + + xch =3D xc_interface_open(NULL, NULL, 0); + if (!xch) { + fprintf(stderr, "xc_interface_open() failed\n"); + return 1; + } + + dom =3D xc_dom_allocate(xch, NULL, NULL); + if (!dom) { + rc =3D 1; + goto out_close; + } + + rc =3D xc_dom_kernel_file(dom, binary); + if (rc) { + rc =3D 1; + goto out_rel; + } + + if (asprintf(&ret, "%zu", dom->kernel_size) < 0) { + rc =3D 1; + goto out_rel; + } + len =3D add_to_buf(&buf, "-b", len); + len =3D add_to_buf(&buf, ret, len); + free(ret); + if (len < 0) { + rc =3D 1; + goto out_rel; + } + ret =3D 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 =3D 3; + } + free(ret); + if (rc) + goto out_rel; + + /* buf capable to hold "-d" <1..2048> BLOB_CHUNK_SZ and a terminating = 0. */ + buf =3D malloc(3 + 5 + BLOB_CHUNK_SZ + 1); + if (!buf) { + rc =3D 1; + goto out_rel; + } + + strcpy(buf, "-d"); + sz =3D BLOB_CHUNK_SZ; + for (off =3D 0; off < dom->kernel_size; off +=3D BLOB_CHUNK_SZ) { + if (dom->kernel_size - off < BLOB_CHUNK_SZ) + sz =3D dom->kernel_size - off; + sprintf(buf + 3, "%zu", sz); + len =3D 3 + strlen(buf + 3) + 1; + memcpy(buf + len, dom->kernel_blob + off, sz); + buf[len + sz] =3D 0; + len +=3D sz + 1; + ret =3D 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 =3D 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 i= nt to) +{ + int rc; + + rc =3D send_kernel_blob(xsh, binary); + if (rc) + goto abort; + + if (cmdline) { + rc =3D live_update_cmdline(xsh, cmdline); + if (rc) + goto abort; + } + + rc =3D 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 in= t to) +{ + int len =3D 0, rc; + char *buf =3D NULL, *ret; + + len =3D add_to_buf(&buf, "-f", len); + len =3D add_to_buf(&buf, binary, len); + if (len < 0) + return 1; + ret =3D 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 =3D live_update_cmdline(xsh, cmdline); + if (rc) + goto abort; + } + + rc =3D 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 =3D 0; + unsigned int i, to =3D 60; + char *binary =3D NULL, *cmdline =3D NULL, *val; + bool force =3D false; + + for (i =3D 0; i < argc; i++) { + if (!strcmp(argv[i], "-c")) { + i++; + if (i =3D=3D argc) { + fprintf(stderr, "Missing command line value\n"); + rc =3D 2; + goto out; + } + cmdline =3D argv[i]; + } else if (!strcmp(argv[i], "-t")) { + i++; + if (i =3D=3D argc) { + fprintf(stderr, "Missing timeout value\n"); + rc =3D 2; + goto out; + } + to =3D atoi(argv[i]); + } else if (!strcmp(argv[i], "-F")) + force =3D true; + else + binary =3D argv[i]; + } + + if (!binary) { + fprintf(stderr, "Missing binary specification\n"); + rc =3D 2; + goto out; + } + + val =3D xs_read(xsh, XBT_NULL, "/tool/xenstored/domid", &i); + if (val) + rc =3D live_update_stubdom(xsh, binary, cmdline, force, to); + else + rc =3D live_update_daemon(xsh, binary, cmdline, force, to); + + free(val); + + out: + return rc; +} =20 int main(int argc, char **argv) { @@ -20,22 +322,6 @@ int main(int argc, char **argv) goto out; } =20 - for (p =3D 2; p < argc; p++) - len +=3D strlen(argv[p]) + 1; - if (len) { - par =3D malloc(len); - if (!par) { - fprintf(stderr, "Allocation error.\n"); - rc =3D 1; - goto out; - } - len =3D 0; - for (p =3D 2; p < argc; p++) { - memcpy(par + len, argv[p], strlen(argv[p]) + 1); - len +=3D strlen(argv[p]) + 1; - } - } - xsh =3D xs_open(0); if (xsh =3D=3D NULL) { fprintf(stderr, "Failed to contact Xenstored.\n"); @@ -43,6 +329,19 @@ int main(int argc, char **argv) goto out; } =20 + if (!strcmp(argv[1], "live-update")) { + rc =3D live_update(xsh, argc - 2, argv + 2); + goto out_close; + } + + for (p =3D 2; p < argc; p++) + len =3D add_to_buf(&par, argv[p], len); + if (len < 0) { + fprintf(stderr, "Allocation error.\n"); + rc =3D 1; + goto out_close; + } + ret =3D xs_control_command(xsh, argv[1], par, len); if (!ret) { rc =3D 3; @@ -59,6 +358,7 @@ int main(int argc, char **argv) } else if (strlen(ret) > 0) printf("%s\n", ret); =20 + out_close: xs_close(xsh); =20 out: diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_= control.c index 8d29db8270..00fda5acdb 100644 --- a/tools/xenstore/xenstored_control.c +++ b/tools/xenstore/xenstored_control.c @@ -149,11 +149,41 @@ static int do_control_print(void *ctx, struct connect= ion *conn, return 0; } =20 +static int do_control_lu(void *ctx, struct connection *conn, + char **vec, int num) +{ + const char *resp; + + resp =3D 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); =20 static struct cmd_s cmds[] =3D { { "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 + * Mini-OS: -b + * -d (multiple of those) + * 2. New command-line (optional): -c + * 3. Start of update: -s [-F] [-t ] + * 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 ] [-F] [-t ] \n" + " Default timeout is 60 seconds.", 4 }, #ifdef __MINIOS__ { "memreport", do_control_memreport, "" }, #else --=20 2.26.2