From nobody Fri May 3 04:42:41 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 16777715071301023.5951952371871; Thu, 2 Mar 2023 07:38:27 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pXkxg-00043j-6c; Thu, 02 Mar 2023 10:35:16 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pXkxS-0003uT-H9 for qemu-devel@nongnu.org; Thu, 02 Mar 2023 10:35:07 -0500 Received: from desiato.infradead.org ([2001:8b0:10b:1:d65d:64ff:fe57:4e05]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pXkxM-0001fA-FA for qemu-devel@nongnu.org; Thu, 02 Mar 2023 10:35:01 -0500 Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by desiato.infradead.org with esmtpsa (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx3-00FL3a-2u; Thu, 02 Mar 2023 15:34:38 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx3-004uyK-2Y; Thu, 02 Mar 2023 15:34:37 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding: Content-Type:MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc: To:From:Reply-To:Content-ID:Content-Description; bh=ST1bS0bRzWP/tyEo71GSlFGlC4rrFm1ZZcHZE6bjAhs=; b=IO8rWde70SWnL/PxFFvNuS4qd4 d+0ab7T1OOtiHvUYdmGs7u1J7jUDB/ZySytfJabPbLkNO7OMPO2fgxyMpStliZeupkB01qTeH4hI+ R9toSu594vBRhdFKXvXCQg3YgTjUq+aNcWZM3G5mQI+7LdbmUAjhibKzRB2jGOrMEtI1Y8p0xbQ6A k29ITQkpYxgRvbJAlgz8RB7BULgIrH1nbH/PwiH6c72GaTY2oUZ5p4G/bKOBV6FOx8iru81x9SOy+ W5pOaFXiii03nqkiGJetOKZeK2ghkc9Krb+E9uvjuI19HFDBHUOO2EskZdYA66LQXJjOBl6Ropy4F +idEBTKg==; From: David Woodhouse To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , Stefano Stabellini , vikram.garhwal@amd.com, Anthony Perard , xen-devel@lists.xenproject.org Subject: [RFC PATCH v1 01/25] hw/xen: Add xenstore wire implementation and implementation stubs Date: Thu, 2 Mar 2023 15:34:11 +0000 Message-Id: <20230302153435.1170111-2-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230302153435.1170111-1-dwmw2@infradead.org> References: <20230302153435.1170111-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-SRS-Rewrite: SMTP reverse-path rewritten from by desiato.infradead.org. See http://www.infradead.org/rpr.html Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: none client-ip=2001:8b0:10b:1:d65d:64ff:fe57:4e05; envelope-from=BATV+9a0490e5ac528e462c30+7130+infradead.org+dwmw2@desiato.srs.infradead.org; helo=desiato.infradead.org X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1677771509169100004 From: David Woodhouse This implements the basic wire protocol for the XenStore commands, punting all the actual implementation to xs_impl_* functions which all just return errors for now. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- hw/i386/kvm/meson.build | 1 + hw/i386/kvm/trace-events | 15 + hw/i386/kvm/xen_xenstore.c | 871 +++++++++++++++++++++++++++++++++++- hw/i386/kvm/xenstore_impl.c | 117 +++++ hw/i386/kvm/xenstore_impl.h | 58 +++ 5 files changed, 1054 insertions(+), 8 deletions(-) create mode 100644 hw/i386/kvm/xenstore_impl.c create mode 100644 hw/i386/kvm/xenstore_impl.h diff --git a/hw/i386/kvm/meson.build b/hw/i386/kvm/meson.build index 82dd6ae7c6..6621ba5cd7 100644 --- a/hw/i386/kvm/meson.build +++ b/hw/i386/kvm/meson.build @@ -9,6 +9,7 @@ i386_kvm_ss.add(when: 'CONFIG_XEN_EMU', if_true: files( 'xen_evtchn.c', 'xen_gnttab.c', 'xen_xenstore.c', + 'xenstore_impl.c', )) =20 i386_ss.add_all(when: 'CONFIG_KVM', if_true: i386_kvm_ss) diff --git a/hw/i386/kvm/trace-events b/hw/i386/kvm/trace-events index b83c3eb965..e4c82de6f3 100644 --- a/hw/i386/kvm/trace-events +++ b/hw/i386/kvm/trace-events @@ -3,3 +3,18 @@ kvm_xen_unmap_pirq(int pirq, int gsi) "pirq %d gsi %d" kvm_xen_get_free_pirq(int pirq, int type) "pirq %d type %d" kvm_xen_bind_pirq(int pirq, int port) "pirq %d port %d" kvm_xen_unmask_pirq(int pirq, char *dev, int vector) "pirq %d dev %s vecto= r %d" +xenstore_error(unsigned int id, unsigned int tx_id, const char *err) "req = %u tx %u err %s" +xenstore_read(unsigned int tx_id, const char *path) "tx %u path %s" +xenstore_write(unsigned int tx_id, const char *path) "tx %u path %s" +xenstore_mkdir(unsigned int tx_id, const char *path) "tx %u path %s" +xenstore_directory(unsigned int tx_id, const char *path) "tx %u path %s" +xenstore_directory_part(unsigned int tx_id, const char *path, unsigned int= offset) "tx %u path %s offset %u" +xenstore_transaction_start(unsigned int new_tx) "new_tx %u" +xenstore_transaction_end(unsigned int tx_id, bool commit) "tx %u commit %d" +xenstore_rm(unsigned int tx_id, const char *path) "tx %u path %s" +xenstore_get_perms(unsigned int tx_id, const char *path) "tx %u path %s" +xenstore_set_perms(unsigned int tx_id, const char *path) "tx %u path %s" +xenstore_watch(const char *path, const char *token) "path %s token %s" +xenstore_unwatch(const char *path, const char *token) "path %s token %s" +xenstore_reset_watches(void) "" +xenstore_watch_event(const char *path, const char *token) "path %s token %= s" diff --git a/hw/i386/kvm/xen_xenstore.c b/hw/i386/kvm/xen_xenstore.c index 14193ef3f9..64d8f1a38f 100644 --- a/hw/i386/kvm/xen_xenstore.c +++ b/hw/i386/kvm/xen_xenstore.c @@ -28,6 +28,10 @@ #include "sysemu/kvm.h" #include "sysemu/kvm_xen.h" =20 +#include "trace.h" + +#include "xenstore_impl.h" + #include "hw/xen/interface/io/xs_wire.h" #include "hw/xen/interface/event_channel.h" =20 @@ -47,6 +51,9 @@ struct XenXenstoreState { SysBusDevice busdev; /*< public >*/ =20 + XenstoreImplState *impl; + GList *watch_events; + MemoryRegion xenstore_page; struct xenstore_domain_interface *xs; uint8_t req_data[XENSTORE_HEADER_SIZE + XENSTORE_PAYLOAD_MAX]; @@ -64,6 +71,7 @@ struct XenXenstoreState { struct XenXenstoreState *xen_xenstore_singleton; =20 static void xen_xenstore_event(void *opaque); +static void fire_watch_cb(void *opaque, const char *path, const char *toke= n); =20 static void xen_xenstore_realize(DeviceState *dev, Error **errp) { @@ -89,6 +97,8 @@ static void xen_xenstore_realize(DeviceState *dev, Error = **errp) } aio_set_fd_handler(qemu_get_aio_context(), xen_be_evtchn_fd(s->eh), tr= ue, xen_xenstore_event, NULL, NULL, NULL, s); + + s->impl =3D xs_impl_create(); } =20 static bool xen_xenstore_is_needed(void *opaque) @@ -213,20 +223,761 @@ static void reset_rsp(XenXenstoreState *s) s->rsp_offset =3D 0; } =20 +static void xs_error(XenXenstoreState *s, unsigned int id, + xs_transaction_t tx_id, int errnum) +{ + struct xsd_sockmsg *rsp =3D (struct xsd_sockmsg *)s->rsp_data; + const char *errstr =3D NULL; + + for (unsigned int i =3D 0; i < ARRAY_SIZE(xsd_errors); i++) { + struct xsd_errors *xsd_error =3D &xsd_errors[i]; + + if (xsd_error->errnum =3D=3D errnum) { + errstr =3D xsd_error->errstring; + break; + } + } + assert(errstr); + + trace_xenstore_error(id, tx_id, errstr); + + rsp->type =3D XS_ERROR; + rsp->req_id =3D id; + rsp->tx_id =3D tx_id; + rsp->len =3D (uint32_t)strlen(errstr) + 1; + + memcpy(&rsp[1], errstr, rsp->len); +} + +static void xs_ok(XenXenstoreState *s, unsigned int type, unsigned int req= _id, + xs_transaction_t tx_id) +{ + struct xsd_sockmsg *rsp =3D (struct xsd_sockmsg *)s->rsp_data; + const char *okstr =3D "OK"; + + rsp->type =3D type; + rsp->req_id =3D req_id; + rsp->tx_id =3D tx_id; + rsp->len =3D (uint32_t)strlen(okstr) + 1; + + memcpy(&rsp[1], okstr, rsp->len); +} + +/* + * The correct request and response formats are documented in xen.git: + * docs/misc/xenstore.txt. A summary is given below for convenience. + * The '|' symbol represents a NUL character. + * + * ---------- Database read, write and permissions operations ---------- + * + * READ | + * WRITE | + * Store and read the octet string at . + * WRITE creates any missing parent paths, with empty values. + * + * MKDIR | + * Ensures that the exists, by necessary by creating + * it and any missing parents with empty values. If + * or any parent already exists, its value is left unchanged. + * + * RM | + * Ensures that the does not exist, by deleting + * it and all of its children. It is not an error if does + * not exist, but it _is_ an error if 's immediate parent + * does not exist either. + * + * DIRECTORY | |* + * Gives a list of the immediate children of , as only the + * leafnames. The resulting children are each named + * /. + * + * DIRECTORY_PART | ||* + * Same as DIRECTORY, but to be used for children lists longer than + * XENSTORE_PAYLOAD_MAX. Input are and the byte offset into + * the list of children to return. Return values are the generation + * count of the node (to be used to ensure the node hasn't + * changed between two reads: being the same for multiple + * reads guarantees the node hasn't changed) and the list of child= ren + * starting at the specified of the complete list. + * + * GET_PERMS | |+ + * SET_PERMS ||+? + * is one of the following + * w write only + * r read only + * b both read and write + * n no access + * See https://wiki.xen.org/wiki/XenBus section + * `Permissions' for details of the permissions system. + * It is possible to set permissions for the special watch paths + * "@introduceDomain" and "@releaseDomain" to enable receiving tho= se + * watches in unprivileged domains. + * + * ---------- Watches ---------- + * + * WATCH ||? + * Adds a watch. + * + * When a is modified (including path creation, removal, + * contents change or permissions change) this generates an event + * on the changed . Changes made in transactions cause an + * event only if and when committed. Each occurring event is + * matched against all the watches currently set up, and each + * matching watch results in a WATCH_EVENT message (see below). + * + * The event's path matches the watch's if it is an child + * of . + * + * can be a to watch or @. In the + * latter case may have any syntax but it matches + * (according to the rules above) only the following special + * events which are invented by xenstored: + * @introduceDomain occurs on INTRODUCE + * @releaseDomain occurs on any domain crash or + * shutdown, and also on RELEASE + * and domain destruction + * events are sent to privileged callers or explicitly + * via SET_PERMS enabled domains only. + * + * When a watch is first set up it is triggered once straight + * away, with equal to . Watches may be triggered + * spuriously. The tx_id in a WATCH request is ignored. + * + * Watches are supposed to be restricted by the permissions + * system but in practice the implementation is imperfect. + * Applications should not rely on being sent a notification for + * paths that they cannot read; however, an application may rely + * on being sent a watch when a path which it _is_ able to read + * is deleted even if that leaves only a nonexistent unreadable + * parent. A notification may omitted if a node's permissions + * are changed so as to make it unreadable, in which case future + * notifications may be suppressed (and if the node is later made + * readable, some notifications may have been lost). + * + * WATCH_EVENT || + * Unsolicited `reply' generated for matching modification events + * as described above. req_id and tx_id are both 0. + * + * is the event's path, ie the actual path that was + * modified; however if the event was the recursive removal of an + * parent of , is just + * (rather than the actual path which was removed). So + * is a child of , regardless. + * + * Iff for the watch was specified as a relative pathname, + * the path will also be relative (with the same base, + * obviously). + * + * UNWATCH ||? + * + * RESET_WATCHES | + * Reset all watches and transactions of the caller. + * + * ---------- Transactions ---------- + * + * TRANSACTION_START | | + * is an opaque uint32_t allocated by xenstored + * represented as unsigned decimal. After this, transaction may + * be referenced by using (as 32-bit binary) in the + * tx_id request header field. When transaction is started whole + * db is copied; reads and writes happen on the copy. + * It is not legal to send non-0 tx_id in TRANSACTION_START. + * + * TRANSACTION_END T| + * TRANSACTION_END F| + * tx_id must refer to existing transaction. After this + * request the tx_id is no longer valid and may be reused by + * xenstore. If F, the transaction is discarded. If T, + * it is committed: if there were any other intervening writes + * then our END gets get EAGAIN. + * + * The plan is that in the future only intervening `conflicting' + * writes cause EAGAIN, meaning only writes or other commits + * which changed paths which were read or written in the + * transaction at hand. + * + */ + +static void xs_read(XenXenstoreState *s, unsigned int req_id, + xs_transaction_t tx_id, uint8_t *req_data, unsigned in= t len) +{ + const char *path =3D (const char *)req_data; + struct xsd_sockmsg *rsp =3D (struct xsd_sockmsg *)s->rsp_data; + uint8_t *rsp_data =3D (uint8_t *)&rsp[1]; + g_autoptr(GByteArray) data =3D g_byte_array_new(); + int err; + + if (len =3D=3D 0 || req_data[len - 1] !=3D '\0') { + xs_error(s, req_id, tx_id, EINVAL); + return; + } + + trace_xenstore_read(tx_id, path); + err =3D xs_impl_read(s->impl, xen_domid, tx_id, path, data); + if (err) { + xs_error(s, req_id, tx_id, err); + return; + } + + rsp->type =3D XS_READ; + rsp->req_id =3D req_id; + rsp->tx_id =3D tx_id; + rsp->len =3D 0; + + len =3D data->len; + if (len > XENSTORE_PAYLOAD_MAX) { + xs_error(s, req_id, tx_id, E2BIG); + return; + } + + memcpy(&rsp_data[rsp->len], data->data, len); + rsp->len +=3D len; +} + +static void xs_write(XenXenstoreState *s, unsigned int req_id, + xs_transaction_t tx_id, uint8_t *req_data, + unsigned int len) +{ + g_autoptr(GByteArray) data =3D g_byte_array_new(); + const char *path; + int err; + + if (len =3D=3D 0) { + xs_error(s, req_id, tx_id, EINVAL); + return; + } + + path =3D (const char *)req_data; + + while (len--) { + if (*req_data++ =3D=3D '\0') { + break; + } + if (len =3D=3D 0) { + xs_error(s, req_id, tx_id, EINVAL); + return; + } + } + + g_byte_array_append(data, req_data, len); + + trace_xenstore_write(tx_id, path); + err =3D xs_impl_write(s->impl, xen_domid, tx_id, path, data); + if (err) { + xs_error(s, req_id, tx_id, err); + return; + } + + xs_ok(s, XS_WRITE, req_id, tx_id); +} + +static void xs_mkdir(XenXenstoreState *s, unsigned int req_id, + xs_transaction_t tx_id, uint8_t *req_data, + unsigned int len) +{ + g_autoptr(GByteArray) data =3D g_byte_array_new(); + const char *path; + int err; + + if (len =3D=3D 0 || req_data[len - 1] !=3D '\0') { + xs_error(s, req_id, tx_id, EINVAL); + return; + } + + path =3D (const char *)req_data; + + trace_xenstore_mkdir(tx_id, path); + err =3D xs_impl_read(s->impl, xen_domid, tx_id, path, data); + if (err =3D=3D ENOENT) { + err =3D xs_impl_write(s->impl, xen_domid, tx_id, path, data); + } + + if (!err) { + xs_error(s, req_id, tx_id, err); + return; + } + + xs_ok(s, XS_MKDIR, req_id, tx_id); +} + +static void xs_append_strings(XenXenstoreState *s, struct xsd_sockmsg *rsp, + GList *strings, unsigned int start, bool tru= ncate) +{ + uint8_t *rsp_data =3D (uint8_t *)&rsp[1]; + GList *l; + + for (l =3D strings; l; l =3D l->next) { + size_t len =3D strlen(l->data) + 1; /* Including the NUL terminati= on */ + char *str =3D l->data; + + if (rsp->len + len > XENSTORE_PAYLOAD_MAX) { + if (truncate) { + len =3D XENSTORE_PAYLOAD_MAX - rsp->len; + if (!len) { + return; + } + } else { + xs_error(s, rsp->req_id, rsp->tx_id, E2BIG); + return; + } + } + + if (start) { + if (start >=3D len) { + start -=3D len; + continue; + } + + str +=3D start; + len -=3D start; + start =3D 0; + } + + memcpy(&rsp_data[rsp->len], str, len); + rsp->len +=3D len; + } + /* XS_DIRECTORY_PART wants an extra NUL to indicate the end */ + if (truncate && rsp->len < XENSTORE_PAYLOAD_MAX) { + rsp_data[rsp->len++] =3D '\0'; + } +} + +static void xs_directory(XenXenstoreState *s, unsigned int req_id, + xs_transaction_t tx_id, uint8_t *req_data, + unsigned int len) +{ + struct xsd_sockmsg *rsp =3D (struct xsd_sockmsg *)s->rsp_data; + GList *items =3D NULL; + const char *path; + int err; + + if (len =3D=3D 0 || req_data[len - 1] !=3D '\0') { + xs_error(s, req_id, tx_id, EINVAL); + return; + } + + path =3D (const char *)req_data; + + trace_xenstore_directory(tx_id, path); + err =3D xs_impl_directory(s->impl, xen_domid, tx_id, path, NULL, &item= s); + if (err !=3D 0) { + xs_error(s, req_id, tx_id, err); + return; + } + + rsp->type =3D XS_DIRECTORY; + rsp->req_id =3D req_id; + rsp->tx_id =3D tx_id; + rsp->len =3D 0; + + xs_append_strings(s, rsp, items, 0, false); + + g_list_free_full(items, g_free); +} + +static void xs_directory_part(XenXenstoreState *s, unsigned int req_id, + xs_transaction_t tx_id, uint8_t *req_data, + unsigned int len) +{ + const char *offset_str, *path =3D (const char *)req_data; + struct xsd_sockmsg *rsp =3D (struct xsd_sockmsg *)s->rsp_data; + char *rsp_data =3D (char *)&rsp[1]; + uint64_t gencnt =3D 0; + unsigned int offset; + GList *items =3D NULL; + int err; + + if (len =3D=3D 0) { + xs_error(s, req_id, tx_id, EINVAL); + return; + } + + while (len--) { + if (*req_data++ =3D=3D '\0') { + break; + } + if (len =3D=3D 0) { + xs_error(s, req_id, tx_id, EINVAL); + return; + } + } + + offset_str =3D (const char *)req_data; + while (len--) { + if (*req_data++ =3D=3D '\0') { + break; + } + if (len =3D=3D 0) { + xs_error(s, req_id, tx_id, EINVAL); + return; + } + } + + if (len) { + xs_error(s, req_id, tx_id, EINVAL); + return; + } + + if (qemu_strtoui(offset_str, NULL, 10, &offset) < 0) { + xs_error(s, req_id, tx_id, EINVAL); + return; + } + + trace_xenstore_directory_part(tx_id, path, offset); + err =3D xs_impl_directory(s->impl, xen_domid, tx_id, path, &gencnt, &i= tems); + if (err !=3D 0) { + xs_error(s, req_id, tx_id, err); + return; + } + + rsp->type =3D XS_DIRECTORY_PART; + rsp->req_id =3D req_id; + rsp->tx_id =3D tx_id; + rsp->len =3D snprintf(rsp_data, XENSTORE_PAYLOAD_MAX, "%" PRIu64, genc= nt) + 1; + + xs_append_strings(s, rsp, items, offset, true); + + g_list_free_full(items, g_free); +} + +static void xs_transaction_start(XenXenstoreState *s, unsigned int req_id, + xs_transaction_t tx_id, uint8_t *req_data, + unsigned int len) +{ + struct xsd_sockmsg *rsp =3D (struct xsd_sockmsg *)s->rsp_data; + char *rsp_data =3D (char *)&rsp[1]; + int err; + + if (len !=3D 1 || req_data[0] !=3D '\0') { + xs_error(s, req_id, tx_id, EINVAL); + return; + } + + rsp->type =3D XS_TRANSACTION_START; + rsp->req_id =3D req_id; + rsp->tx_id =3D tx_id; + rsp->len =3D 0; + + err =3D xs_impl_transaction_start(s->impl, xen_domid, &tx_id); + if (err) { + xs_error(s, req_id, tx_id, err); + return; + } + + trace_xenstore_transaction_start(tx_id); + + rsp->len =3D snprintf(rsp_data, XENSTORE_PAYLOAD_MAX, "%u", tx_id); + assert(rsp->len < XENSTORE_PAYLOAD_MAX); + rsp->len++; +} + +static void xs_transaction_end(XenXenstoreState *s, unsigned int req_id, + xs_transaction_t tx_id, uint8_t *req_data, + unsigned int len) +{ + bool commit; + int err; + + if (len !=3D 2 || req_data[1] !=3D '\0') { + xs_error(s, req_id, tx_id, EINVAL); + return; + } + + switch (req_data[0]) { + case 'T': + commit =3D true; + break; + case 'F': + commit =3D false; + break; + default: + xs_error(s, req_id, tx_id, EINVAL); + return; + } + + trace_xenstore_transaction_end(tx_id, commit); + err =3D xs_impl_transaction_end(s->impl, xen_domid, tx_id, commit); + if (err) { + xs_error(s, req_id, tx_id, err); + return; + } + + xs_ok(s, XS_TRANSACTION_END, req_id, tx_id); +} + +static void xs_rm(XenXenstoreState *s, unsigned int req_id, + xs_transaction_t tx_id, uint8_t *req_data, unsigned int = len) +{ + const char *path =3D (const char *)req_data; + int err; + + if (len =3D=3D 0 || req_data[len - 1] !=3D '\0') { + xs_error(s, req_id, tx_id, EINVAL); + return; + } + + trace_xenstore_rm(tx_id, path); + err =3D xs_impl_rm(s->impl, xen_domid, tx_id, path); + if (err) { + xs_error(s, req_id, tx_id, err); + return; + } + + xs_ok(s, XS_RM, req_id, tx_id); +} + +static void xs_get_perms(XenXenstoreState *s, unsigned int req_id, + xs_transaction_t tx_id, uint8_t *req_data, + unsigned int len) +{ + const char *path =3D (const char *)req_data; + struct xsd_sockmsg *rsp =3D (struct xsd_sockmsg *)s->rsp_data; + GList *perms =3D NULL; + int err; + + if (len =3D=3D 0 || req_data[len - 1] !=3D '\0') { + xs_error(s, req_id, tx_id, EINVAL); + return; + } + + trace_xenstore_get_perms(tx_id, path); + err =3D xs_impl_get_perms(s->impl, xen_domid, tx_id, path, &perms); + if (err) { + xs_error(s, req_id, tx_id, err); + return; + } + + rsp->type =3D XS_GET_PERMS; + rsp->req_id =3D req_id; + rsp->tx_id =3D tx_id; + rsp->len =3D 0; + + xs_append_strings(s, rsp, perms, 0, false); + + g_list_free_full(perms, g_free); +} + +static void xs_set_perms(XenXenstoreState *s, unsigned int req_id, + xs_transaction_t tx_id, uint8_t *req_data, + unsigned int len) +{ + const char *path =3D (const char *)req_data; + uint8_t *perm; + GList *perms =3D NULL; + int err; + + if (len =3D=3D 0) { + xs_error(s, req_id, tx_id, EINVAL); + return; + } + + while (len--) { + if (*req_data++ =3D=3D '\0') { + break; + } + if (len =3D=3D 0) { + xs_error(s, req_id, tx_id, EINVAL); + return; + } + } + + perm =3D req_data; + while (len--) { + if (*req_data++ =3D=3D '\0') { + perms =3D g_list_append(perms, perm); + perm =3D req_data; + } + } + + /* + * Note that there may be trailing garbage at the end of the buffer. + * This is explicitly permitted by the '?' at the end of the definitio= n: + * + * SET_PERMS ||+? + */ + + trace_xenstore_set_perms(tx_id, path); + err =3D xs_impl_set_perms(s->impl, xen_domid, tx_id, path, perms); + g_list_free(perms); + if (err) { + xs_error(s, req_id, tx_id, err); + return; + } + + xs_ok(s, XS_SET_PERMS, req_id, tx_id); +} + +static void xs_watch(XenXenstoreState *s, unsigned int req_id, + xs_transaction_t tx_id, uint8_t *req_data, + unsigned int len) +{ + const char *token, *path =3D (const char *)req_data; + int err; + + if (len =3D=3D 0) { + xs_error(s, req_id, tx_id, EINVAL); + return; + } + + while (len--) { + if (*req_data++ =3D=3D '\0') { + break; + } + if (len =3D=3D 0) { + xs_error(s, req_id, tx_id, EINVAL); + return; + } + } + + token =3D (const char *)req_data; + while (len--) { + if (*req_data++ =3D=3D '\0') { + break; + } + if (len =3D=3D 0) { + xs_error(s, req_id, tx_id, EINVAL); + return; + } + } + + /* + * Note that there may be trailing garbage at the end of the buffer. + * This is explicitly permitted by the '?' at the end of the definitio= n: + * + * WATCH ||? + */ + + trace_xenstore_watch(path, token); + err =3D xs_impl_watch(s->impl, xen_domid, path, token, fire_watch_cb, = s); + if (err) { + xs_error(s, req_id, tx_id, err); + return; + } + + xs_ok(s, XS_WATCH, req_id, tx_id); +} + +static void xs_unwatch(XenXenstoreState *s, unsigned int req_id, + xs_transaction_t tx_id, uint8_t *req_data, + unsigned int len) +{ + const char *token, *path =3D (const char *)req_data; + int err; + + if (len =3D=3D 0) { + xs_error(s, req_id, tx_id, EINVAL); + return; + } + + while (len--) { + if (*req_data++ =3D=3D '\0') { + break; + } + if (len =3D=3D 0) { + xs_error(s, req_id, tx_id, EINVAL); + return; + } + } + + token =3D (const char *)req_data; + while (len--) { + if (*req_data++ =3D=3D '\0') { + break; + } + if (len =3D=3D 0) { + xs_error(s, req_id, tx_id, EINVAL); + return; + } + } + + trace_xenstore_unwatch(path, token); + err =3D xs_impl_unwatch(s->impl, xen_domid, path, token, fire_watch_cb= , s); + if (err) { + xs_error(s, req_id, tx_id, err); + return; + } + + xs_ok(s, XS_UNWATCH, req_id, tx_id); +} + +static void xs_reset_watches(XenXenstoreState *s, unsigned int req_id, + xs_transaction_t tx_id, uint8_t *req_data, + unsigned int len) +{ + if (len =3D=3D 0 || req_data[len - 1] !=3D '\0') { + xs_error(s, req_id, tx_id, EINVAL); + return; + } + + trace_xenstore_reset_watches(); + xs_impl_reset_watches(s->impl, xen_domid); + + xs_ok(s, XS_RESET_WATCHES, req_id, tx_id); +} + +static void xs_priv(XenXenstoreState *s, unsigned int req_id, + xs_transaction_t tx_id, uint8_t *data, + unsigned int len) +{ + xs_error(s, req_id, tx_id, EACCES); +} + +static void xs_unimpl(XenXenstoreState *s, unsigned int req_id, + xs_transaction_t tx_id, uint8_t *data, + unsigned int len) +{ + xs_error(s, req_id, tx_id, ENOSYS); +} + +typedef void (*xs_impl)(XenXenstoreState *s, unsigned int req_id, + xs_transaction_t tx_id, uint8_t *data, + unsigned int len); + +struct xsd_req { + const char *name; + xs_impl fn; +}; +#define XSD_REQ(_type, _fn) \ + [_type] =3D { .name =3D #_type, .fn =3D _fn } + +struct xsd_req xsd_reqs[] =3D { + XSD_REQ(XS_READ, xs_read), + XSD_REQ(XS_WRITE, xs_write), + XSD_REQ(XS_MKDIR, xs_mkdir), + XSD_REQ(XS_DIRECTORY, xs_directory), + XSD_REQ(XS_DIRECTORY_PART, xs_directory_part), + XSD_REQ(XS_TRANSACTION_START, xs_transaction_start), + XSD_REQ(XS_TRANSACTION_END, xs_transaction_end), + XSD_REQ(XS_RM, xs_rm), + XSD_REQ(XS_GET_PERMS, xs_get_perms), + XSD_REQ(XS_SET_PERMS, xs_set_perms), + XSD_REQ(XS_WATCH, xs_watch), + XSD_REQ(XS_UNWATCH, xs_unwatch), + XSD_REQ(XS_CONTROL, xs_priv), + XSD_REQ(XS_INTRODUCE, xs_priv), + XSD_REQ(XS_RELEASE, xs_priv), + XSD_REQ(XS_IS_DOMAIN_INTRODUCED, xs_priv), + XSD_REQ(XS_RESUME, xs_priv), + XSD_REQ(XS_SET_TARGET, xs_priv), + XSD_REQ(XS_RESET_WATCHES, xs_reset_watches), +}; + static void process_req(XenXenstoreState *s) { struct xsd_sockmsg *req =3D (struct xsd_sockmsg *)s->req_data; - struct xsd_sockmsg *rsp =3D (struct xsd_sockmsg *)s->rsp_data; - const char enosys[] =3D "ENOSYS"; + xs_impl handler =3D NULL; =20 assert(req_pending(s)); assert(!s->rsp_pending); =20 - rsp->type =3D XS_ERROR; - rsp->req_id =3D req->req_id; - rsp->tx_id =3D req->tx_id; - rsp->len =3D sizeof(enosys); - memcpy((void *)&rsp[1], enosys, sizeof(enosys)); + if (req->type < ARRAY_SIZE(xsd_reqs)) { + handler =3D xsd_reqs[req->type].fn; + } + if (!handler) { + handler =3D &xs_unimpl; + } + + handler(s, req->req_id, req->tx_id, (uint8_t *)&req[1], req->len); =20 s->rsp_pending =3D true; reset_req(s); @@ -415,6 +1166,106 @@ static unsigned int put_rsp(XenXenstoreState *s) return copylen; } =20 +static void deliver_watch(XenXenstoreState *s, const char *path, + const char *token) +{ + struct xsd_sockmsg *rsp =3D (struct xsd_sockmsg *)s->rsp_data; + uint8_t *rsp_data =3D (uint8_t *)&rsp[1]; + unsigned int len; + + assert(!s->rsp_pending); + + trace_xenstore_watch_event(path, token); + + rsp->type =3D XS_WATCH_EVENT; + rsp->req_id =3D 0; + rsp->tx_id =3D 0; + rsp->len =3D 0; + + len =3D strlen(path); + + /* XENSTORE_ABS/REL_PATH_MAX should ensure there can be no overflow */ + assert(rsp->len + len < XENSTORE_PAYLOAD_MAX); + + memcpy(&rsp_data[rsp->len], path, len); + rsp->len +=3D len; + rsp_data[rsp->len] =3D '\0'; + rsp->len++; + + len =3D strlen(token); + /* + * It is possible for the guest to have chosen a token that will + * not fit (along with the patch) into a watch event. We have no + * choice but to drop the event if this is the case. + */ + if (rsp->len + len >=3D XENSTORE_PAYLOAD_MAX) { + return; + } + + memcpy(&rsp_data[rsp->len], token, len); + rsp->len +=3D len; + rsp_data[rsp->len] =3D '\0'; + rsp->len++; + + s->rsp_pending =3D true; +} + +struct watch_event { + char *path; + char *token; +}; + +static void queue_watch(XenXenstoreState *s, const char *path, + const char *token) +{ + struct watch_event *ev =3D g_new0(struct watch_event, 1); + + ev->path =3D g_strdup(path); + ev->token =3D g_strdup(token); + + s->watch_events =3D g_list_append(s->watch_events, ev); +} + +static void fire_watch_cb(void *opaque, const char *path, const char *toke= n) +{ + XenXenstoreState *s =3D opaque; + + assert(qemu_mutex_iothread_locked()); + + /* + * If there's a response pending, we obviously can't scribble over + * it. But if there's a request pending, it has dibs on the buffer + * too. + * + * In the common case of a watch firing due to backend activity + * when the ring was otherwise idle, we should be able to copy the + * strings directly into the rsp_data and thence the actual ring, + * without needing to perform any allocations and queue them. + */ + if (s->rsp_pending || req_pending(s)) { + queue_watch(s, path, token); + } else { + deliver_watch(s, path, token); + /* + * If the message was queued because there was already ring activi= ty, + * no need to wake the guest. But if not, we need to send the evtc= hn. + */ + xen_be_evtchn_notify(s->eh, s->be_port); + } +} + +static void process_watch_events(XenXenstoreState *s) +{ + struct watch_event *ev =3D s->watch_events->data; + + deliver_watch(s, ev->path, ev->token); + + s->watch_events =3D g_list_remove(s->watch_events, ev); + g_free(ev->path); + g_free(ev->token); + g_free(ev); +} + static void xen_xenstore_event(void *opaque) { XenXenstoreState *s =3D opaque; @@ -433,6 +1284,10 @@ static void xen_xenstore_event(void *opaque) copied_to =3D copied_from =3D 0; processed =3D false; =20 + if (!s->rsp_pending && s->watch_events) { + process_watch_events(s); + } + if (s->rsp_pending) { copied_to =3D put_rsp(s); } @@ -441,7 +1296,7 @@ static void xen_xenstore_event(void *opaque) copied_from =3D get_req(s); } =20 - if (req_pending(s) && !s->rsp_pending) { + if (req_pending(s) && !s->rsp_pending && !s->watch_events) { process_req(s); processed =3D true; } diff --git a/hw/i386/kvm/xenstore_impl.c b/hw/i386/kvm/xenstore_impl.c new file mode 100644 index 0000000000..31dbc98fe0 --- /dev/null +++ b/hw/i386/kvm/xenstore_impl.c @@ -0,0 +1,117 @@ +/* + * QEMU Xen emulation: The actual implementation of XenStore + * + * Copyright =C2=A9 2023 Amazon.com, Inc. or its affiliates. All Rights Re= served. + * + * Authors: David Woodhouse , Paul Durrant + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" + +#include "xen_xenstore.h" +#include "xenstore_impl.h" + +struct XenstoreImplState { +}; + +int xs_impl_read(XenstoreImplState *s, unsigned int dom_id, + xs_transaction_t tx_id, const char *path, GByteArray *dat= a) +{ + /* + * The data GByteArray shall exist, and will be freed by caller. + * Just g_byte_array_append() to it. + */ + return ENOENT; +} + +int xs_impl_write(XenstoreImplState *s, unsigned int dom_id, + xs_transaction_t tx_id, const char *path, GByteArray *da= ta) +{ + /* + * The data GByteArray shall exist, will be freed by caller. You are + * free to use g_byte_array_steal() and keep the data. + */ + return ENOSYS; +} + +int xs_impl_directory(XenstoreImplState *s, unsigned int dom_id, + xs_transaction_t tx_id, const char *path, + uint64_t *gencnt, GList **items) +{ + /* + * The items are (char *) to be freed by caller. Although it's consumed + * immediately so if you want to change it to (const char *) and keep + * them, go ahead and change the caller. + */ + return ENOENT; +} + +int xs_impl_transaction_start(XenstoreImplState *s, unsigned int dom_id, + xs_transaction_t *tx_id) +{ + return ENOSYS; +} + +int xs_impl_transaction_end(XenstoreImplState *s, unsigned int dom_id, + xs_transaction_t tx_id, bool commit) +{ + return ENOSYS; +} + +int xs_impl_rm(XenstoreImplState *s, unsigned int dom_id, + xs_transaction_t tx_id, const char *path) +{ + return ENOSYS; +} + +int xs_impl_get_perms(XenstoreImplState *s, unsigned int dom_id, + xs_transaction_t tx_id, const char *path, GList **pe= rms) +{ + /* + * The perms are (char *) in the wire format to be + * freed by the caller. + */ + return ENOSYS; +} + +int xs_impl_set_perms(XenstoreImplState *s, unsigned int dom_id, + xs_transaction_t tx_id, const char *path, GList *per= ms) +{ + /* + * The perms are (const char *) in the wire format. + */ + return ENOSYS; +} + +int xs_impl_watch(XenstoreImplState *s, unsigned int dom_id, const char *p= ath, + const char *token, xs_impl_watch_fn fn, void *opaque) +{ + /* + * When calling the callback @fn, note that the path should + * precisely match the relative path that the guest provided, even + * if it was a relative path which needed to be prefixed with + * /local/domain/${domid}/ + */ + return ENOSYS; +} + +int xs_impl_unwatch(XenstoreImplState *s, unsigned int dom_id, + const char *path, const char *token, + xs_impl_watch_fn fn, void *opaque) +{ + /* Remove the watch that matches all four criteria */ + return ENOSYS; +} + +int xs_impl_reset_watches(XenstoreImplState *s, unsigned int dom_id) +{ + return ENOSYS; +} + +XenstoreImplState *xs_impl_create(void) +{ + return g_new0(XenstoreImplState, 1); +} diff --git a/hw/i386/kvm/xenstore_impl.h b/hw/i386/kvm/xenstore_impl.h new file mode 100644 index 0000000000..beb7b29ab8 --- /dev/null +++ b/hw/i386/kvm/xenstore_impl.h @@ -0,0 +1,58 @@ +/* + * QEMU Xen emulation: The actual implementation of XenStore + * + * Copyright =C2=A9 2023 Amazon.com, Inc. or its affiliates. All Rights Re= served. + * + * Authors: David Woodhouse + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * See the COPYING file in the top-level directory. + */ + +#ifndef QEMU_XENSTORE_IMPL_H +#define QEMU_XENSTORE_IMPL_H + +typedef uint32_t xs_transaction_t; + +#define XBT_NULL 0 + +typedef struct XenstoreImplState XenstoreImplState; + +XenstoreImplState *xs_impl_create(void); + +/* + * These functions return *positive* error numbers. This is a little + * unconventional but it helps to keep us honest because there is + * also a very limited set of error numbers that they are permitted + * to return (those in xsd_errors). + */ + +int xs_impl_read(XenstoreImplState *s, unsigned int dom_id, + xs_transaction_t tx_id, const char *path, GByteArray *dat= a); +int xs_impl_write(XenstoreImplState *s, unsigned int dom_id, + xs_transaction_t tx_id, const char *path, GByteArray *da= ta); +int xs_impl_directory(XenstoreImplState *s, unsigned int dom_id, + xs_transaction_t tx_id, const char *path, + uint64_t *gencnt, GList **items); +int xs_impl_transaction_start(XenstoreImplState *s, unsigned int dom_id, + xs_transaction_t *tx_id); +int xs_impl_transaction_end(XenstoreImplState *s, unsigned int dom_id, + xs_transaction_t tx_id, bool commit); +int xs_impl_rm(XenstoreImplState *s, unsigned int dom_id, + xs_transaction_t tx_id, const char *path); +int xs_impl_get_perms(XenstoreImplState *s, unsigned int dom_id, + xs_transaction_t tx_id, const char *path, GList **pe= rms); +int xs_impl_set_perms(XenstoreImplState *s, unsigned int dom_id, + xs_transaction_t tx_id, const char *path, GList *per= ms); + +/* This differs from xs_watch_fn because it has the token */ +typedef void(xs_impl_watch_fn)(void *opaque, const char *path, + const char *token); +int xs_impl_watch(XenstoreImplState *s, unsigned int dom_id, const char *p= ath, + const char *token, xs_impl_watch_fn fn, void *opaque); +int xs_impl_unwatch(XenstoreImplState *s, unsigned int dom_id, + const char *path, const char *token, xs_impl_watch_fn = fn, + void *opaque); +int xs_impl_reset_watches(XenstoreImplState *s, unsigned int dom_id); + +#endif /* QEMU_XENSTORE_IMPL_H */ --=20 2.39.0 From nobody Fri May 3 04:42:41 2024 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 ARC-Seal: i=1; a=rsa-sha256; t=1677771331; cv=none; d=zohomail.com; s=zohoarc; b=j2P59vJO69kFtWWgR1q9zmsMSV8PtUiJY6PsgvEB4qhdSWVwnmFbP++28qEZXtX4U6F+NyjKKcbXwtCj0EDZfe0jvmMA/7gxpMsa61RWDftFxLOHLJNExu1ut3GsOTe5m3KXMRPx90aivh3aFELHfO3jmujRTX27b4aavSPtjms= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1677771331; h=Content-Type: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=EifP5NAedq4PsHC8d0qtGWpb3bCabAI+8eoo2m4J+qs=; b=Ef2K3/00hcjBjMDwpnZ/yDkvPdXkijUfH9u/0Cl13zxQ+QgF0jFMLdt9Fh8LuvIRQVLyHfApzWN1K5IB1ZSJa83e4dFZL8lcys7EU2to6bizhnfaaEvd5mbWOomIO/sLSW2D6pqPxNNmg3GOY1hLGdRYPUgmOAQPVVuV3PXG6Aw= 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 Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1677771331153250.57174547384568; Thu, 2 Mar 2023 07:35:31 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.505054.777624 (Exim 4.92) (envelope-from ) id 1pXkxN-0002IJ-ET; Thu, 02 Mar 2023 15:34:57 +0000 Received: by outflank-mailman (output) from mailman id 505054.777624; Thu, 02 Mar 2023 15:34:57 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxN-0002Fq-17; Thu, 02 Mar 2023 15:34:57 +0000 Received: by outflank-mailman (input) for mailman id 505054; Thu, 02 Mar 2023 15:34:55 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxL-0001Jv-5X for xen-devel@lists.xenproject.org; Thu, 02 Mar 2023 15:34:55 +0000 Received: from casper.infradead.org (casper.infradead.org [2001:8b0:10b:1236::1]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id c237a0df-b90f-11ed-96ad-2f268f93b82a; Thu, 02 Mar 2023 16:34:49 +0100 (CET) Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by casper.infradead.org with esmtpsa (Exim 4.94.2 #2 (Red Hat Linux)) id 1pXkx3-002UNC-RR; Thu, 02 Mar 2023 15:34:38 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx3-004uyO-2k; Thu, 02 Mar 2023 15:34:37 +0000 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 X-Inumbo-ID: c237a0df-b90f-11ed-96ad-2f268f93b82a DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc: To:From:Reply-To:Content-ID:Content-Description; bh=EifP5NAedq4PsHC8d0qtGWpb3bCabAI+8eoo2m4J+qs=; b=BytKT8tTGMAswV3COrA77m8Qkh UZVW52hBF8M3Wj83kGEXp0trSkzrLz0FS51MTmUGPs2H589V0BUHC4jyU/q5lpSQ12yzvt2kyo6Gz +m3/rkCjMYKzbo91ev4KY65Cr6UdQYpQt1m22UnWqWJwBAXGwcGA41g1fkw8Cngz+/zERrHsT8gUK 06tlYzpMuQ19Hkf2vjA9Cab6y5kvm98qI4giicO0RK2mzCQ0TQ52cbqFizlVYrkmjzWpuzljc/22F AHHzl5DV/OYy5SWPxC2oBg5pSeZIgJo4O1T0LL3HVEzA7dhj2ry9StnYmOe2dRWkiHemeh6iE7Moq Iy4RLNIg==; From: David Woodhouse To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , Stefano Stabellini , vikram.garhwal@amd.com, Anthony Perard , xen-devel@lists.xenproject.org Subject: [RFC PATCH v1 02/25] hw/xen: Add basic XenStore tree walk and write/read/directory support Date: Thu, 2 Mar 2023 15:34:12 +0000 Message-Id: <20230302153435.1170111-3-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230302153435.1170111-1-dwmw2@infradead.org> References: <20230302153435.1170111-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by casper.infradead.org. See http://www.infradead.org/rpr.html X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1677771331717100007 From: David Woodhouse This is a fairly simple implementation of a copy-on-write tree. The node walk function starts off at the root, with 'inplace =3D=3D true'. If it ever encounters a node with a refcount greater than one (including the root node), then that node is shared with other trees, and cannot be modified in place, so the inplace flag is cleared and we copy on write from there on down. Xenstore write has 'mkdir -p' semantics and will create the intermediate nodes if they don't already exist, so in that case we flip the inplace flag back to true as as populated the newly-created nodes. We put a copy of the absolute path into the buffer in the struct walk_op, with *two* NUL terminators at the end. As xs_node_walk() goes down the tree, it replaces the next '/' separator with a NUL so that it can use the 'child name' in place. The next recursion down then puts the '/' back and repeats the exercise for the next path element... if it doesn't hit that *second* NUL termination which indicates the true end of the path. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- hw/i386/kvm/xenstore_impl.c | 527 +++++++++++++++++++++++++++++++++++- tests/unit/meson.build | 1 + tests/unit/test-xs-node.c | 197 ++++++++++++++ 3 files changed, 718 insertions(+), 7 deletions(-) create mode 100644 tests/unit/test-xs-node.c diff --git a/hw/i386/kvm/xenstore_impl.c b/hw/i386/kvm/xenstore_impl.c index 31dbc98fe0..9e10a31bea 100644 --- a/hw/i386/kvm/xenstore_impl.c +++ b/hw/i386/kvm/xenstore_impl.c @@ -10,13 +10,470 @@ */ =20 #include "qemu/osdep.h" +#include "qom/object.h" =20 #include "xen_xenstore.h" #include "xenstore_impl.h" =20 +#include "hw/xen/interface/io/xs_wire.h" + +#define XS_MAX_WATCHES 128 +#define XS_MAX_DOMAIN_NODES 1000 +#define XS_MAX_NODE_SIZE 2048 +#define XS_MAX_TRANSACTIONS 10 +#define XS_MAX_PERMS_PER_NODE 5 + +#define XS_VALID_CHARS "abcdefghijklmnopqrstuvwxyz" \ + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ + "0123456789-/_" + +typedef struct XsNode { + uint32_t ref; + GByteArray *content; + GHashTable *children; + uint64_t gencnt; +#ifdef XS_NODE_UNIT_TEST + gchar *name; /* debug only */ +#endif +} XsNode; + struct XenstoreImplState { + XsNode *root; + unsigned int nr_nodes; }; =20 +static inline XsNode *xs_node_new(void) +{ + XsNode *n =3D g_new0(XsNode, 1); + n->ref =3D 1; + +#ifdef XS_NODE_UNIT_TEST + nr_xs_nodes++; + xs_node_list =3D g_list_prepend(xs_node_list, n); +#endif + return n; +} + +static inline XsNode *xs_node_ref(XsNode *n) +{ + /* With just 10 transactions, it can never get anywhere near this. */ + g_assert(n->ref < INT_MAX); + + g_assert(n->ref); + n->ref++; + return n; +} + +static inline void xs_node_unref(XsNode *n) +{ + if (!n) { + return; + } + g_assert(n->ref); + if (--n->ref) { + return; + } + + if (n->content) { + g_byte_array_unref(n->content); + } + if (n->children) { + g_hash_table_unref(n->children); + } +#ifdef XS_NODE_UNIT_TEST + g_free(n->name); + nr_xs_nodes--; + xs_node_list =3D g_list_remove(xs_node_list, n); +#endif + g_free(n); +} + +/* For copying from one hash table to another using g_hash_table_foreach()= */ +static void do_insert(gpointer key, gpointer value, gpointer user_data) +{ + g_hash_table_insert(user_data, g_strdup(key), xs_node_ref(value)); +} + +static XsNode *xs_node_copy(XsNode *old) +{ + XsNode *n =3D xs_node_new(); + + n->gencnt =3D old->gencnt; + if (old->children) { + n->children =3D g_hash_table_new_full(g_str_hash, g_str_equal, g_f= ree, + (GDestroyNotify)xs_node_unref); + g_hash_table_foreach(old->children, do_insert, n->children); + } + if (old && old->content) { + n->content =3D g_byte_array_ref(old->content); + } + return n; +} + +/* Returns true if it made a change to the hash table */ +static bool xs_node_add_child(XsNode *n, const char *path_elem, XsNode *ch= ild) +{ + assert(!strchr(path_elem, '/')); + + if (!child) { + assert(n->children); + return g_hash_table_remove(n->children, path_elem); + } + +#ifdef XS_NODE_UNIT_TEST + g_free(child->name); + child->name =3D g_strdup(path_elem); +#endif + if (!n->children) { + n->children =3D g_hash_table_new_full(g_str_hash, g_str_equal, g_f= ree, + (GDestroyNotify)xs_node_unref); + } + + /* + * The documentation for g_hash_table_insert() says that it "returns a + * boolean value to indicate whether the newly added value was already + * in the hash table or not." + * + * It could perhaps be clearer that returning TRUE means it wasn't, + */ + return g_hash_table_insert(n->children, g_strdup(path_elem), child); +} + +struct walk_op { + struct XenstoreImplState *s; + char path[XENSTORE_ABS_PATH_MAX + 2]; /* Two NUL terminators */ + int (*op_fn)(XsNode **n, struct walk_op *op); + void *op_opaque; + void *op_opaque2; + + unsigned int dom_id; + + /* The number of nodes which will exist in the tree if this op succeed= s. */ + unsigned int new_nr_nodes; + + /* + * This is maintained on the way *down* the walk to indicate + * whether nodes can be modified in place or whether COW is + * required. It starts off being true, as we're always going to + * replace the root node. If we walk into a shared subtree it + * becomes false. If we start *creating* new nodes for a write, + * it becomes true again. + * + * Do not use it on the way back up. + */ + bool inplace; + bool mutating; + bool create_dirs; +}; + +static int xs_node_add_content(XsNode **n, struct walk_op *op) +{ + GByteArray *data =3D op->op_opaque; + + if (op->dom_id) { + /* + * The real XenStored includes permissions and names of child nodes + * in the calculated datasize but life's too short. For a single + * tenant internal XenStore, we don't have to be quite as pedantic. + */ + if (data->len > XS_MAX_NODE_SIZE) { + return E2BIG; + } + } + /* We *are* the node to be written. Either this or a copy. */ + if (!op->inplace) { + XsNode *old =3D *n; + *n =3D xs_node_copy(old); + xs_node_unref(old); + } + + if ((*n)->content) { + g_byte_array_unref((*n)->content); + } + (*n)->content =3D g_byte_array_ref(data); + return 0; +} + +static int xs_node_get_content(XsNode **n, struct walk_op *op) +{ + GByteArray *data =3D op->op_opaque; + GByteArray *node_data; + + assert(op->inplace); + assert(*n); + + node_data =3D (*n)->content; + if (node_data) { + g_byte_array_append(data, node_data->data, node_data->len); + } + + return 0; +} + +static int node_rm_recurse(gpointer key, gpointer value, gpointer user_dat= a) +{ + struct walk_op *op =3D user_data; + XsNode *n =3D value; + bool this_inplace =3D op->inplace; + + if (n->ref !=3D 1) { + op->inplace =3D 0; + } + + if (n->children) { + g_hash_table_foreach_remove(n->children, node_rm_recurse, op); + } + op->new_nr_nodes--; + + /* + * Actually deleting the child here is just an optimisation; if we + * don't then the final unref on the topmost victim will just have + * to cascade down again repeating all the g_hash_table_foreach() + * calls. + */ + return this_inplace; +} + +static int xs_node_rm(XsNode **n, struct walk_op *op) +{ + bool this_inplace =3D op->inplace; + + /* Keep count of the nodes in the subtree which gets deleted. */ + if ((*n)->children) { + g_hash_table_foreach_remove((*n)->children, node_rm_recurse, op); + } + op->new_nr_nodes--; + + if (this_inplace) { + xs_node_unref(*n); + } + *n =3D NULL; + return 0; +} + +/* + * Passed a full reference in *n which it may free if it needs to COW. + * + * When changing the tree, the op->inplace flag indicates whether this + * node may be modified in place (i.e. it and all its parents had a + * refcount of one). If walking down the tree we find a node whose + * refcount is higher, we must clear op->inplace and COW from there + * down. Unless we are creating new nodes as scaffolding for a write + * (which works like 'mkdir -p' does). In which case those newly + * created nodes can (and must) be modified in place again. + */ +static int xs_node_walk(XsNode **n, struct walk_op *op) +{ + char *child_name =3D NULL; + size_t namelen; + XsNode *old =3D *n, *child =3D NULL; + bool stole_child =3D false; + bool this_inplace; + int err; + + namelen =3D strlen(op->path); + + /* Is there a child, or do we hit the double-NUL termination? */ + if (op->path[namelen + 1]) { + char *slash; + child_name =3D op->path + namelen + 1; + slash =3D strchr(child_name, '/'); + if (slash) { + *slash =3D '\0'; + } + op->path[namelen] =3D '/'; + } + + /* If we walk into a subtree which is shared, we must COW */ + if (op->mutating && old->ref !=3D 1) { + op->inplace =3D false; + } + + if (!child_name) { + /* This is the actual node on which the operation shall be perform= ed */ + err =3D op->op_fn(n, op); + goto out; + } + + /* op->inplace will be further modified during the recursion */ + this_inplace =3D op->inplace; + + if (old && old->children) { + child =3D g_hash_table_lookup(old->children, child_name); + /* This is a *weak* reference to 'child', owned by the hash table = */ + } + + if (child) { + xs_node_ref(child); + /* + * Now we own it too. But if we can modify inplace, that's going to + * foil the check and force it to COW. We want to be the *only* ow= ner + * so that it can be modified in place, so remove it from the hash + * table in that case. We'll add it (or its replacement) back late= r. + */ + if (op->mutating && this_inplace) { + g_hash_table_remove(old->children, child_name); + stole_child =3D true; + } + } else if (op->create_dirs) { + if (op->dom_id && op->new_nr_nodes >=3D XS_MAX_DOMAIN_NODES) { + err =3D ENOSPC; + goto out; + } + op->new_nr_nodes++; + child =3D xs_node_new(); + + /* + * If we're creating a new child, we can clearly modify it (and its + * children) in place from here on down. + */ + op->inplace =3D true; + } else { + err =3D ENOENT; + goto out; + } + + /* + * Except for the temporary child-stealing as noted, our node has not + * changed yet. We don't yet know the overall operation will complete. + */ + err =3D xs_node_walk(&child, op); + if (err || !op->mutating) { + if (stole_child) { + /* Put it back as it was. */ + g_hash_table_replace(old->children, g_strdup(child_name), chil= d); + } else { + xs_node_unref(child); + } + goto out; + } + + /* + * Now we know the operation has completed successfully and we're on + * the way back up. Make the change, substituting 'child' in the + * node at our level. + */ + if (!this_inplace) { + *n =3D xs_node_copy(old); + xs_node_unref(old); + } + + /* + * The child may be NULL here, for a remove operation. Either way, + * xs_node_add_child() will do the right thing and return a value + * indicating whether it changed the parent's hash table or not. + * + * We bump the parent gencnt if it adds a child that we *didn't* + * steal from it in the first place, or if child=3D=3DNULL and was + * thus removed (whether we stole it earlier and didn't put it + * back, or xs_node_add_child() actually removed it now). + */ + if ((xs_node_add_child(*n, child_name, child) && !stole_child) || !chi= ld) { + (*n)->gencnt++; + } + + out: + op->path[namelen] =3D '\0'; + if (!namelen) { + /* + * On completing the recursion back up the path walk and reaching = the + * top, assign the new node count if the operation was successful. + */ + if (!err && op->mutating) { + op->s->nr_nodes =3D op->new_nr_nodes; + } + } + return err; +} + +static void append_directory_item(gpointer key, gpointer value, + gpointer user_data) +{ + GList **items =3D user_data; + + *items =3D g_list_insert_sorted(*items, g_strdup(key), (GCompareFunc)s= trcmp); +} + +/* Populates items with char * names which caller must free. */ +static int xs_node_directory(XsNode **n, struct walk_op *op) +{ + GList **items =3D op->op_opaque; + + assert(op->inplace); + assert(*n); + + if ((*n)->children) { + g_hash_table_foreach((*n)->children, append_directory_item, items); + } + + if (op->op_opaque2) { + *(uint64_t *)op->op_opaque2 =3D (*n)->gencnt; + } + + return 0; +} + +static int validate_path(char *outpath, const char *userpath, + unsigned int dom_id) +{ + size_t i, pathlen =3D strlen(userpath); + + if (!pathlen || userpath[pathlen] =3D=3D '/' || strstr(userpath, "//")= ) { + return EINVAL; + } + for (i =3D 0; i < pathlen; i++) { + if (!strchr(XS_VALID_CHARS, userpath[i])) { + return EINVAL; + } + } + if (userpath[0] =3D=3D '/') { + if (pathlen > XENSTORE_ABS_PATH_MAX) { + return E2BIG; + } + memcpy(outpath, userpath, pathlen + 1); + } else { + if (pathlen > XENSTORE_REL_PATH_MAX) { + return E2BIG; + } + snprintf(outpath, XENSTORE_ABS_PATH_MAX, "/local/domain/%u/%s", do= m_id, + userpath); + } + return 0; +} + + +static int init_walk_op(XenstoreImplState *s, struct walk_op *op, + xs_transaction_t tx_id, unsigned int dom_id, + const char *path, XsNode ***rootp) +{ + int ret =3D validate_path(op->path, path, dom_id); + if (ret) { + return ret; + } + + /* + * We use *two* NUL terminators at the end of the path, as during the = walk + * we will temporarily turn each '/' into a NUL to allow us to use that + * path element for the lookup. + */ + op->path[strlen(op->path) + 1] =3D '\0'; + op->path[0] =3D '\0'; + op->inplace =3D true; + op->mutating =3D false; + op->create_dirs =3D false; + op->dom_id =3D dom_id; + op->s =3D s; + + if (tx_id =3D=3D XBT_NULL) { + *rootp =3D &s->root; + op->new_nr_nodes =3D s->nr_nodes; + } else { + return ENOENT; + } + + return 0; +} + int xs_impl_read(XenstoreImplState *s, unsigned int dom_id, xs_transaction_t tx_id, const char *path, GByteArray *dat= a) { @@ -24,7 +481,17 @@ int xs_impl_read(XenstoreImplState *s, unsigned int dom= _id, * The data GByteArray shall exist, and will be freed by caller. * Just g_byte_array_append() to it. */ - return ENOENT; + struct walk_op op; + XsNode **n; + int ret; + + ret =3D init_walk_op(s, &op, tx_id, dom_id, path, &n); + if (ret) { + return ret; + } + op.op_fn =3D xs_node_get_content; + op.op_opaque =3D data; + return xs_node_walk(n, &op); } =20 int xs_impl_write(XenstoreImplState *s, unsigned int dom_id, @@ -32,9 +499,21 @@ int xs_impl_write(XenstoreImplState *s, unsigned int do= m_id, { /* * The data GByteArray shall exist, will be freed by caller. You are - * free to use g_byte_array_steal() and keep the data. + * free to use g_byte_array_steal() and keep the data. Or just ref it. */ - return ENOSYS; + struct walk_op op; + XsNode **n; + int ret; + + ret =3D init_walk_op(s, &op, tx_id, dom_id, path, &n); + if (ret) { + return ret; + } + op.op_fn =3D xs_node_add_content; + op.op_opaque =3D data; + op.mutating =3D true; + op.create_dirs =3D true; + return xs_node_walk(n, &op); } =20 int xs_impl_directory(XenstoreImplState *s, unsigned int dom_id, @@ -46,7 +525,18 @@ int xs_impl_directory(XenstoreImplState *s, unsigned in= t dom_id, * immediately so if you want to change it to (const char *) and keep * them, go ahead and change the caller. */ - return ENOENT; + struct walk_op op; + XsNode **n; + int ret; + + ret =3D init_walk_op(s, &op, tx_id, dom_id, path, &n); + if (ret) { + return ret; + } + op.op_fn =3D xs_node_directory; + op.op_opaque =3D items; + op.op_opaque2 =3D gencnt; + return xs_node_walk(n, &op); } =20 int xs_impl_transaction_start(XenstoreImplState *s, unsigned int dom_id, @@ -64,7 +554,17 @@ int xs_impl_transaction_end(XenstoreImplState *s, unsig= ned int dom_id, int xs_impl_rm(XenstoreImplState *s, unsigned int dom_id, xs_transaction_t tx_id, const char *path) { - return ENOSYS; + struct walk_op op; + XsNode **n; + int ret; + + ret =3D init_walk_op(s, &op, tx_id, dom_id, path, &n); + if (ret) { + return ret; + } + op.op_fn =3D xs_node_rm; + op.mutating =3D true; + return xs_node_walk(n, &op); } =20 int xs_impl_get_perms(XenstoreImplState *s, unsigned int dom_id, @@ -102,16 +602,29 @@ int xs_impl_unwatch(XenstoreImplState *s, unsigned in= t dom_id, const char *path, const char *token, xs_impl_watch_fn fn, void *opaque) { - /* Remove the watch that matches all four criteria */ + /* + * When calling the callback @fn, note that the path should + * precisely match the relative path that the guest provided, even + * if it was a relative path which needed to be prefixed with + * /local/domain/${domid}/ + */ return ENOSYS; } =20 int xs_impl_reset_watches(XenstoreImplState *s, unsigned int dom_id) { + /* Remove the watch that matches all four criteria */ return ENOSYS; } =20 XenstoreImplState *xs_impl_create(void) { - return g_new0(XenstoreImplState, 1); + XenstoreImplState *s =3D g_new0(XenstoreImplState, 1); + + s->nr_nodes =3D 1; + s->root =3D xs_node_new(); +#ifdef XS_NODE_UNIT_TEST + s->root->name =3D g_strdup("/"); +#endif + return s; } diff --git a/tests/unit/meson.build b/tests/unit/meson.build index 51f453e6c4..d9c0a7eae6 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -47,6 +47,7 @@ tests =3D { 'ptimer-test': ['ptimer-test-stubs.c', meson.project_source_root() / 'hw= /core/ptimer.c'], 'test-qapi-util': [], 'test-interval-tree': [], + 'test-xs-node': [qom], } =20 if have_system or have_tools diff --git a/tests/unit/test-xs-node.c b/tests/unit/test-xs-node.c new file mode 100644 index 0000000000..c78d5bd581 --- /dev/null +++ b/tests/unit/test-xs-node.c @@ -0,0 +1,197 @@ +/* + * QEMU XenStore XsNode testing + * + * Copyright =C2=A9 2023 Amazon.com, Inc. or its affiliates. All Rights Re= served. + + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/module.h" + +static int nr_xs_nodes; +static GList *xs_node_list; + +#define XS_NODE_UNIT_TEST + +/* + * We don't need the core Xen definitions. And we *do* want to be able + * to run the unit tests even on architectures that Xen doesn't support + * (because life's too short to bother doing otherwise, and test coverage + * doesn't hurt). + */ +#define __XEN_PUBLIC_XEN_H__ + +#include "hw/i386/kvm/xenstore_impl.c" + +#define DOMID_QEMU 0 +#define DOMID_GUEST 1 + +/* This doesn't happen in qemu but we want to make valgrind happy */ +static void xs_impl_delete(XenstoreImplState *s) +{ + int err; + + err =3D xs_impl_rm(s, DOMID_QEMU, XBT_NULL, "/local"); + g_assert(!err); + g_assert(s->nr_nodes =3D=3D 1); + + xs_node_unref(s->root); + g_free(s); + + if (xs_node_list) { + GList *l; + for (l =3D xs_node_list; l; l =3D l->next) { + XsNode *n =3D l->data; + printf("Remaining node at %p name %s ref %u\n", n, n->name, + n->ref); + } + } + g_assert(!nr_xs_nodes); +} + +static int write_str(XenstoreImplState *s, unsigned int dom_id, + unsigned int tx_id, const char *path, + const char *content) +{ + GByteArray *d =3D g_byte_array_new(); + int err; + + g_byte_array_append(d, (void *)content, strlen(content)); + err =3D xs_impl_write(s, dom_id, tx_id, path, d); + g_byte_array_unref(d); + return err; +} + +static XenstoreImplState *setup(void) +{ + XenstoreImplState *s =3D xs_impl_create(); + char *abspath; + int err; + + abspath =3D g_strdup_printf("/local/domain/%u", DOMID_GUEST); + + err =3D write_str(s, DOMID_QEMU, XBT_NULL, abspath, ""); + g_assert(!err); + + g_free(abspath); + + abspath =3D g_strdup_printf("/local/domain/%u/some", DOMID_GUEST); + + err =3D write_str(s, DOMID_QEMU, XBT_NULL, abspath, ""); + g_assert(!err); + g_assert(s->nr_nodes =3D=3D 5); + + g_free(abspath); + + return s; +} + +static void test_xs_node_simple(void) +{ + GByteArray *data =3D g_byte_array_new(); + XenstoreImplState *s =3D setup(); + GList *items =3D NULL; + XsNode *old_root; + uint64_t gencnt; + int err; + + g_assert(s); + + /* Read gives ENOENT when it should */ + err =3D xs_impl_read(s, DOMID_GUEST, XBT_NULL, "foo", data); + g_assert(err =3D=3D ENOENT); + + /* Write works */ + err =3D write_str(s, DOMID_GUEST, XBT_NULL, "some/relative/path", + "something"); + g_assert(s->nr_nodes =3D=3D 7); + g_assert(!err); + + /* Read gives back what we wrote */ + err =3D xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/relative/path", d= ata); + g_assert(!err); + g_assert(data->len =3D=3D strlen("something")); + g_assert(!memcmp(data->data, "something", data->len)); + + /* Even if we use an abolute path */ + g_byte_array_set_size(data, 0); + err =3D xs_impl_read(s, DOMID_GUEST, XBT_NULL, + "/local/domain/1/some/relative/path", data); + g_assert(!err); + g_assert(data->len =3D=3D strlen("something")); + + /* Keep a copy, to force COW mode */ + old_root =3D xs_node_ref(s->root); + + /* Write works again */ + err =3D write_str(s, DOMID_GUEST, XBT_NULL, + "/local/domain/1/some/relative/path2", + "something else"); + g_assert(!err); + g_assert(s->nr_nodes =3D=3D 8); + + /* Overwrite an existing node */ + err =3D write_str(s, DOMID_GUEST, XBT_NULL, "some/relative/path", + "another thing"); + g_assert(!err); + g_assert(s->nr_nodes =3D=3D 8); + + /* We can list the two files we wrote */ + err =3D xs_impl_directory(s, DOMID_GUEST, XBT_NULL, "some/relative", &= gencnt, + &items); + g_assert(!err); + g_assert(items); + g_assert(gencnt =3D=3D 2); + g_assert(!strcmp(items->data, "path")); + g_assert(items->next); + g_assert(!strcmp(items->next->data, "path2")); + g_assert(!items->next->next); + g_list_free_full(items, g_free); + + /* Write somewhere else which already existed */ + err =3D write_str(s, DOMID_GUEST, XBT_NULL, "some/relative", "moredata= "); + g_assert(!err); + + g_byte_array_set_size(data, 0); + err =3D xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/relative", data); + g_assert(!err); + g_assert(data->len =3D=3D strlen("moredata")); + g_assert(!memcmp(data->data, "moredata", data->len)); + + /* Overwrite existing data */ + err =3D write_str(s, DOMID_GUEST, XBT_NULL, "some/relative", "otherdat= a"); + g_assert(!err); + + g_byte_array_set_size(data, 0); + err =3D xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/relative", data); + g_assert(!err); + g_assert(data->len =3D=3D strlen("otherdata")); + g_assert(!memcmp(data->data, "otherdata", data->len)); + + /* Remove the subtree */ + err =3D xs_impl_rm(s, DOMID_GUEST, XBT_NULL, "some/relative"); + g_assert(!err); + g_assert(s->nr_nodes =3D=3D 5); + + g_byte_array_set_size(data, 0); + err =3D xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/relative", data); + g_assert(err =3D=3D ENOENT); + g_byte_array_unref(data); + + xs_node_unref(old_root); + xs_impl_delete(s); +} + + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + module_call_init(MODULE_INIT_QOM); + + g_test_add_func("/xs_node/simple", test_xs_node_simple); + + return g_test_run(); +} --=20 2.39.0 From nobody Fri May 3 04:42:41 2024 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 ARC-Seal: i=1; a=rsa-sha256; t=1677771330; cv=none; d=zohomail.com; s=zohoarc; b=DXIRSW8GNDGSP0JFWSUiCr203HgQqmAC45aYIwqEhXhljCxjvAKJyNzj1H73TW695zeVrYZ+gnX010MuO+LkzLSSKiZvMAnGthJwB84Sumq9GzrPMkMsdSZzrTwAQr9tSuZXE8YuPm13c339TaXlI+tTxl+Nt+zFVxHQrTm1VPk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1677771330; 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=erWVL3FsZ/k0NITRskjF433HZz8ozg61BvoyoaGHf94=; b=jFFotfi7UrFSdiguHJDLopQOBW3cwvj/tW4HCVIFd25Z6G2idR3IeyQXJRPANy3XAVL+S0P0jGncnWOSIEZS9FkkojoN32K1h80YqEv118GoiF/SiyO0TZ+M1EX7kD93RmDDIdWZH5ISVPTyZkJu+NY9Hhitqp+iSBJEKcKp+R0= 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 Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 167777132450622.78893097758271; Thu, 2 Mar 2023 07:35:24 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.505059.777675 (Exim 4.92) (envelope-from ) id 1pXkxT-0003m1-IX; Thu, 02 Mar 2023 15:35:03 +0000 Received: by outflank-mailman (output) from mailman id 505059.777675; Thu, 02 Mar 2023 15:35:03 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxS-0003d6-G5; Thu, 02 Mar 2023 15:35:02 +0000 Received: by outflank-mailman (input) for mailman id 505059; Thu, 02 Mar 2023 15:34:58 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxN-0001Jw-Mo for xen-devel@lists.xenproject.org; Thu, 02 Mar 2023 15:34:57 +0000 Received: from casper.infradead.org (casper.infradead.org [2001:8b0:10b:1236::1]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id c2185c4b-b90f-11ed-a550-8520e6686977; Thu, 02 Mar 2023 16:34:49 +0100 (CET) Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by casper.infradead.org with esmtpsa (Exim 4.94.2 #2 (Red Hat Linux)) id 1pXkx3-002UND-TC; Thu, 02 Mar 2023 15:34:38 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx3-004uyT-2x; Thu, 02 Mar 2023 15:34:37 +0000 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 X-Inumbo-ID: c2185c4b-b90f-11ed-a550-8520e6686977 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=erWVL3FsZ/k0NITRskjF433HZz8ozg61BvoyoaGHf94=; b=DCP0WDgAi2HDlsISe89uQqbkEV dFTT20r4Tt2KoGf3KxxmLH3Q6nBAbgaozjY3u/1gxEF97GOPc7Cc5OLwve8qbv9Sk2h6rWOJKOk7M SLv7/HaPVDm1OU1hMQ7fC7nZ/wD5j4EwVRqlZMJMLlhbme6K1Ww19ynAbcu7AujbU1ShGgI8MMFCj sO0e+Vqr+GTa+IA9/XRAgtI1l6AVjAmVU1kj41DesArN+3ZpANpaOpprcLBEl6t1g4YUT2n4FcxHW AWvahBPb78oowvmx8ahIlbf8vVoBq7puDz0woEql4hmaykt32lSCQoENXMwf7JtBLdMxD+5jLgP0C k2nMH6bw==; From: David Woodhouse To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , Stefano Stabellini , vikram.garhwal@amd.com, Anthony Perard , xen-devel@lists.xenproject.org Subject: [RFC PATCH v1 03/25] hw/xen: Implement XenStore watches Date: Thu, 2 Mar 2023 15:34:13 +0000 Message-Id: <20230302153435.1170111-4-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230302153435.1170111-1-dwmw2@infradead.org> References: <20230302153435.1170111-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by casper.infradead.org. See http://www.infradead.org/rpr.html X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1677771331710100005 Content-Type: text/plain; charset="utf-8" From: David Woodhouse Starts out fairly simple: a hash table of watches based on the path. Except there can be multiple watches on the same path, so the watch ends up being a simple linked list, and the head of that list is in the hash table. Which makes removal a bit of a PITA but it's not so bad; we just special-case "I had to remove the head of the list and now I have to replace it in / remove it from the hash table". And if we don't remove the head, it's a simple linked-list operation. We do need to fire watches on *deleted* nodes, so instead of just a simple xs_node_unref() on the topmost victim, we need to recurse down and fire watches on them all. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- hw/i386/kvm/xenstore_impl.c | 253 +++++++++++++++++++++++++++++++++--- tests/unit/test-xs-node.c | 85 ++++++++++++ 2 files changed, 323 insertions(+), 15 deletions(-) diff --git a/hw/i386/kvm/xenstore_impl.c b/hw/i386/kvm/xenstore_impl.c index 9e10a31bea..2e464af93a 100644 --- a/hw/i386/kvm/xenstore_impl.c +++ b/hw/i386/kvm/xenstore_impl.c @@ -37,9 +37,20 @@ typedef struct XsNode { #endif } XsNode; =20 +typedef struct XsWatch { + struct XsWatch *next; + xs_impl_watch_fn *cb; + void *cb_opaque; + char *token; + unsigned int dom_id; + int rel_prefix; +} XsWatch; + struct XenstoreImplState { XsNode *root; unsigned int nr_nodes; + GHashTable *watches; + unsigned int nr_domu_watches; }; =20 static inline XsNode *xs_node_new(void) @@ -146,6 +157,7 @@ struct walk_op { void *op_opaque; void *op_opaque2; =20 + GList *watches; unsigned int dom_id; =20 /* The number of nodes which will exist in the tree if this op succeed= s. */ @@ -166,6 +178,35 @@ struct walk_op { bool create_dirs; }; =20 +static void fire_watches(struct walk_op *op, bool parents) +{ + GList *l =3D NULL; + XsWatch *w; + + if (!op->mutating) { + return; + } + + if (parents) { + l =3D op->watches; + } + + w =3D g_hash_table_lookup(op->s->watches, op->path); + while (w || l) { + if (!w) { + /* Fire the parent nodes from 'op' if asked to */ + w =3D l->data; + l =3D l->next; + continue; + } + + assert(strlen(op->path) > w->rel_prefix); + w->cb(w->cb_opaque, op->path + w->rel_prefix, w->token); + + w =3D w->next; + } +} + static int xs_node_add_content(XsNode **n, struct walk_op *op) { GByteArray *data =3D op->op_opaque; @@ -213,6 +254,8 @@ static int xs_node_get_content(XsNode **n, struct walk_= op *op) static int node_rm_recurse(gpointer key, gpointer value, gpointer user_dat= a) { struct walk_op *op =3D user_data; + int path_len =3D strlen(op->path); + int key_len =3D strlen(key); XsNode *n =3D value; bool this_inplace =3D op->inplace; =20 @@ -220,11 +263,22 @@ static int node_rm_recurse(gpointer key, gpointer val= ue, gpointer user_data) op->inplace =3D 0; } =20 + assert(key_len + path_len + 2 <=3D sizeof(op->path)); + op->path[path_len] =3D '/'; + memcpy(op->path + path_len + 1, key, key_len + 1); + if (n->children) { g_hash_table_foreach_remove(n->children, node_rm_recurse, op); } op->new_nr_nodes--; =20 + /* + * Fire watches on *this* node but not the parents because they are + * going to be deleted too, so the watch will fire for them anyway. + */ + fire_watches(op, false); + op->path[path_len] =3D '\0'; + /* * Actually deleting the child here is just an optimisation; if we * don't then the final unref on the topmost victim will just have @@ -238,7 +292,7 @@ static int xs_node_rm(XsNode **n, struct walk_op *op) { bool this_inplace =3D op->inplace; =20 - /* Keep count of the nodes in the subtree which gets deleted. */ + /* Fire watches for, and count, nodes in the subtree which get deleted= */ if ((*n)->children) { g_hash_table_foreach_remove((*n)->children, node_rm_recurse, op); } @@ -269,9 +323,11 @@ static int xs_node_walk(XsNode **n, struct walk_op *op) XsNode *old =3D *n, *child =3D NULL; bool stole_child =3D false; bool this_inplace; + XsWatch *watch; int err; =20 namelen =3D strlen(op->path); + watch =3D g_hash_table_lookup(op->s->watches, op->path); =20 /* Is there a child, or do we hit the double-NUL termination? */ if (op->path[namelen + 1]) { @@ -292,6 +348,9 @@ static int xs_node_walk(XsNode **n, struct walk_op *op) if (!child_name) { /* This is the actual node on which the operation shall be perform= ed */ err =3D op->op_fn(n, op); + if (!err) { + fire_watches(op, true); + } goto out; } =20 @@ -333,11 +392,24 @@ static int xs_node_walk(XsNode **n, struct walk_op *o= p) goto out; } =20 + /* + * If there's a watch on this node, add it to the list to be fired + * (with the correct full pathname for the modified node) at the end. + */ + if (watch) { + op->watches =3D g_list_append(op->watches, watch); + } + /* * Except for the temporary child-stealing as noted, our node has not * changed yet. We don't yet know the overall operation will complete. */ err =3D xs_node_walk(&child, op); + + if (watch) { + op->watches =3D g_list_remove(op->watches, watch); + } + if (err || !op->mutating) { if (stole_child) { /* Put it back as it was. */ @@ -375,6 +447,7 @@ static int xs_node_walk(XsNode **n, struct walk_op *op) out: op->path[namelen] =3D '\0'; if (!namelen) { + assert(!op->watches); /* * On completing the recursion back up the path walk and reaching = the * top, assign the new node count if the operation was successful. @@ -457,6 +530,7 @@ static int init_walk_op(XenstoreImplState *s, struct wa= lk_op *op, * path element for the lookup. */ op->path[strlen(op->path) + 1] =3D '\0'; + op->watches =3D NULL; op->path[0] =3D '\0'; op->inplace =3D true; op->mutating =3D false; @@ -589,38 +663,187 @@ int xs_impl_set_perms(XenstoreImplState *s, unsigned= int dom_id, int xs_impl_watch(XenstoreImplState *s, unsigned int dom_id, const char *p= ath, const char *token, xs_impl_watch_fn fn, void *opaque) { - /* - * When calling the callback @fn, note that the path should - * precisely match the relative path that the guest provided, even - * if it was a relative path which needed to be prefixed with - * /local/domain/${domid}/ - */ - return ENOSYS; + char abspath[XENSTORE_ABS_PATH_MAX + 1]; + XsWatch *w, *l; + int ret; + + ret =3D validate_path(abspath, path, dom_id); + if (ret) { + return ret; + } + + /* Check for duplicates */ + w =3D g_hash_table_lookup(s->watches, abspath); + while (w) { + if (!g_strcmp0(token, w->token) && opaque =3D=3D w->cb_opaque && + fn =3D=3D w->cb && dom_id =3D=3D w->dom_id) { + return EEXIST; + } + w =3D w->next; + } + + if (dom_id && s->nr_domu_watches >=3D XS_MAX_WATCHES) { + return E2BIG; + } + + w =3D g_new0(XsWatch, 1); + w->token =3D g_strdup(token); + w->cb =3D fn; + w->cb_opaque =3D opaque; + w->dom_id =3D dom_id; + w->rel_prefix =3D strlen(abspath) - strlen(path); + + l =3D g_hash_table_lookup(s->watches, abspath); + if (l) { + w->next =3D l->next; + l->next =3D w; + } else { + g_hash_table_insert(s->watches, g_strdup(abspath), w); + } + if (dom_id) { + s->nr_domu_watches++; + } + + /* A new watch should fire immediately */ + fn(opaque, path, token); + + return 0; +} + +static XsWatch *free_watch(XenstoreImplState *s, XsWatch *w) +{ + XsWatch *next =3D w->next; + + if (w->dom_id) { + assert(s->nr_domu_watches); + s->nr_domu_watches--; + } + + g_free(w->token); + g_free(w); + + return next; } =20 int xs_impl_unwatch(XenstoreImplState *s, unsigned int dom_id, const char *path, const char *token, xs_impl_watch_fn fn, void *opaque) { + char abspath[XENSTORE_ABS_PATH_MAX + 1]; + XsWatch *w, **l; + int ret; + + ret =3D validate_path(abspath, path, dom_id); + if (ret) { + return ret; + } + + w =3D g_hash_table_lookup(s->watches, abspath); + if (!w) { + return ENOENT; + } + /* - * When calling the callback @fn, note that the path should - * precisely match the relative path that the guest provided, even - * if it was a relative path which needed to be prefixed with - * /local/domain/${domid}/ + * The hash table contains the first element of a list of + * watches. Removing the first element in the list is a + * special case because we have to update the hash table to + * point to the next (or remove it if there's nothing left). */ - return ENOSYS; + if (!g_strcmp0(token, w->token) && fn =3D=3D w->cb && opaque =3D=3D w-= >cb_opaque && + dom_id =3D=3D w->dom_id) { + if (w->next) { + /* Insert the previous 'next' into the hash table */ + g_hash_table_insert(s->watches, g_strdup(abspath), w->next); + } else { + /* Nothing left; remove from hash table */ + g_hash_table_remove(s->watches, abspath); + } + free_watch(s, w); + return 0; + } + + /* + * We're all done messing with the hash table because the element + * it points to has survived the cull. Now it's just a simple + * linked list removal operation. + */ + for (l =3D &w->next; *l; l =3D &w->next) { + w =3D *l; + + if (!g_strcmp0(token, w->token) && fn =3D=3D w->cb && + opaque !=3D w->cb_opaque && dom_id =3D=3D w->dom_id) { + *l =3D free_watch(s, w); + return 0; + } + } + + return ENOENT; } =20 int xs_impl_reset_watches(XenstoreImplState *s, unsigned int dom_id) { - /* Remove the watch that matches all four criteria */ - return ENOSYS; + char **watch_paths; + guint nr_watch_paths; + guint i; + + watch_paths =3D (char **)g_hash_table_get_keys_as_array(s->watches, + &nr_watch_paths); + + for (i =3D 0; i < nr_watch_paths; i++) { + XsWatch *w1 =3D g_hash_table_lookup(s->watches, watch_paths[i]); + XsWatch *w2, *w, **l; + + /* + * w1 is the original list. The hash table has this pointer. + * w2 is the head of our newly-filtered list. + * w and l are temporary for processing. w is somewhat redundant + * with *l but makes my eyes bleed less. + */ + + w =3D w2 =3D w1; + l =3D &w; + while (w) { + if (w->dom_id =3D=3D dom_id) { + /* If we're freeing the head of the list, bump w2 */ + if (w2 =3D=3D w) { + w2 =3D w->next; + } + *l =3D free_watch(s, w); + } else { + l =3D &w->next; + } + w =3D *l; + } + /* + * If the head of the list survived the cull, we don't need to + * touch the hash table and we're done with this path. Else... + */ + if (w1 !=3D w2) { + g_hash_table_steal(s->watches, watch_paths[i]); + + /* + * It was already freed. (Don't worry, this whole thing is + * single-threaded and nobody saw it in the meantime). And + * having *stolen* it, we now own the watch_paths[i] string + * so if we don't give it back to the hash table, we need + * to free it. + */ + if (w2) { + g_hash_table_insert(s->watches, watch_paths[i], w2); + } else { + g_free(watch_paths[i]); + } + } + } + g_free(watch_paths); + return 0; } =20 XenstoreImplState *xs_impl_create(void) { XenstoreImplState *s =3D g_new0(XenstoreImplState, 1); =20 + s->watches =3D g_hash_table_new_full(g_str_hash, g_str_equal, g_free, = NULL); s->nr_nodes =3D 1; s->root =3D xs_node_new(); #ifdef XS_NODE_UNIT_TEST diff --git a/tests/unit/test-xs-node.c b/tests/unit/test-xs-node.c index c78d5bd581..19000b64b2 100644 --- a/tests/unit/test-xs-node.c +++ b/tests/unit/test-xs-node.c @@ -34,10 +34,14 @@ static void xs_impl_delete(XenstoreImplState *s) { int err; =20 + xs_impl_reset_watches(s, DOMID_GUEST); + g_assert(!s->nr_domu_watches); + err =3D xs_impl_rm(s, DOMID_QEMU, XBT_NULL, "/local"); g_assert(!err); g_assert(s->nr_nodes =3D=3D 1); =20 + g_hash_table_unref(s->watches); xs_node_unref(s->root); g_free(s); =20 @@ -65,6 +69,14 @@ static int write_str(XenstoreImplState *s, unsigned int = dom_id, return err; } =20 +static void watch_cb(void *_str, const char *path, const char *token) +{ + GString *str =3D _str; + + g_string_append(str, path); + g_string_append(str, token); +} + static XenstoreImplState *setup(void) { XenstoreImplState *s =3D xs_impl_create(); @@ -75,6 +87,7 @@ static XenstoreImplState *setup(void) =20 err =3D write_str(s, DOMID_QEMU, XBT_NULL, abspath, ""); g_assert(!err); + g_assert(s->nr_nodes =3D=3D 4); =20 g_free(abspath); =20 @@ -93,6 +106,8 @@ static void test_xs_node_simple(void) { GByteArray *data =3D g_byte_array_new(); XenstoreImplState *s =3D setup(); + GString *guest_watches =3D g_string_new(NULL); + GString *qemu_watches =3D g_string_new(NULL); GList *items =3D NULL; XsNode *old_root; uint64_t gencnt; @@ -100,6 +115,20 @@ static void test_xs_node_simple(void) =20 g_assert(s); =20 + err =3D xs_impl_watch(s, DOMID_GUEST, "some", "guestwatch", + watch_cb, guest_watches); + g_assert(!err); + g_assert(guest_watches->len =3D=3D strlen("someguestwatch")); + g_assert(!strcmp(guest_watches->str, "someguestwatch")); + g_string_truncate(guest_watches, 0); + + err =3D xs_impl_watch(s, 0, "/local/domain/1/some", "qemuwatch", + watch_cb, qemu_watches); + g_assert(!err); + g_assert(qemu_watches->len =3D=3D strlen("/local/domain/1/someqemuwatc= h")); + g_assert(!strcmp(qemu_watches->str, "/local/domain/1/someqemuwatch")); + g_string_truncate(qemu_watches, 0); + /* Read gives ENOENT when it should */ err =3D xs_impl_read(s, DOMID_GUEST, XBT_NULL, "foo", data); g_assert(err =3D=3D ENOENT); @@ -109,6 +138,14 @@ static void test_xs_node_simple(void) "something"); g_assert(s->nr_nodes =3D=3D 7); g_assert(!err); + g_assert(!strcmp(guest_watches->str, + "some/relative/pathguestwatch")); + g_assert(!strcmp(qemu_watches->str, + "/local/domain/1/some/relative/pathqemuwatch")); + + g_string_truncate(qemu_watches, 0); + g_string_truncate(guest_watches, 0); + xs_impl_reset_watches(s, 0); =20 /* Read gives back what we wrote */ err =3D xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/relative/path", d= ata); @@ -123,6 +160,8 @@ static void test_xs_node_simple(void) g_assert(!err); g_assert(data->len =3D=3D strlen("something")); =20 + g_assert(!qemu_watches->len); + g_assert(!guest_watches->len); /* Keep a copy, to force COW mode */ old_root =3D xs_node_ref(s->root); =20 @@ -132,12 +171,18 @@ static void test_xs_node_simple(void) "something else"); g_assert(!err); g_assert(s->nr_nodes =3D=3D 8); + g_assert(!qemu_watches->len); + g_assert(!strcmp(guest_watches->str, "some/relative/path2guestwatch")); + g_string_truncate(guest_watches, 0); =20 /* Overwrite an existing node */ err =3D write_str(s, DOMID_GUEST, XBT_NULL, "some/relative/path", "another thing"); g_assert(!err); g_assert(s->nr_nodes =3D=3D 8); + g_assert(!qemu_watches->len); + g_assert(!strcmp(guest_watches->str, "some/relative/pathguestwatch")); + g_string_truncate(guest_watches, 0); =20 /* We can list the two files we wrote */ err =3D xs_impl_directory(s, DOMID_GUEST, XBT_NULL, "some/relative", &= gencnt, @@ -151,9 +196,38 @@ static void test_xs_node_simple(void) g_assert(!items->next->next); g_list_free_full(items, g_free); =20 + err =3D xs_impl_unwatch(s, DOMID_GUEST, "some", "guestwatch", + watch_cb, guest_watches); + g_assert(!err); + + err =3D xs_impl_unwatch(s, DOMID_GUEST, "some", "guestwatch", + watch_cb, guest_watches); + g_assert(err =3D=3D ENOENT); + + err =3D xs_impl_watch(s, DOMID_GUEST, "some/relative/path2", "watchp2", + watch_cb, guest_watches); + g_assert(!err); + g_assert(guest_watches->len =3D=3D strlen("some/relative/path2watchp2"= )); + g_assert(!strcmp(guest_watches->str, "some/relative/path2watchp2")); + g_string_truncate(guest_watches, 0); + + err =3D xs_impl_watch(s, DOMID_GUEST, "/local/domain/1/some/relative", + "watchrel", watch_cb, guest_watches); + g_assert(!err); + g_assert(guest_watches->len =3D=3D + strlen("/local/domain/1/some/relativewatchrel")); + g_assert(!strcmp(guest_watches->str, + "/local/domain/1/some/relativewatchrel")); + g_string_truncate(guest_watches, 0); + /* Write somewhere else which already existed */ err =3D write_str(s, DOMID_GUEST, XBT_NULL, "some/relative", "moredata= "); g_assert(!err); + g_assert(s->nr_nodes =3D=3D 8); + + g_assert(!strcmp(guest_watches->str, + "/local/domain/1/some/relativewatchrel")); + g_string_truncate(guest_watches, 0); =20 g_byte_array_set_size(data, 0); err =3D xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/relative", data); @@ -164,6 +238,7 @@ static void test_xs_node_simple(void) /* Overwrite existing data */ err =3D write_str(s, DOMID_GUEST, XBT_NULL, "some/relative", "otherdat= a"); g_assert(!err); + g_string_truncate(guest_watches, 0); =20 g_byte_array_set_size(data, 0); err =3D xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/relative", data); @@ -176,11 +251,21 @@ static void test_xs_node_simple(void) g_assert(!err); g_assert(s->nr_nodes =3D=3D 5); =20 + /* Each watch fires with the least specific relevant path */ + g_assert(strstr(guest_watches->str, + "some/relative/path2watchp2")); + g_assert(strstr(guest_watches->str, + "/local/domain/1/some/relativewatchrel")); + g_string_truncate(guest_watches, 0); + g_byte_array_set_size(data, 0); err =3D xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/relative", data); g_assert(err =3D=3D ENOENT); g_byte_array_unref(data); =20 + xs_impl_reset_watches(s, DOMID_GUEST); + g_string_free(qemu_watches, true); + g_string_free(guest_watches, true); xs_node_unref(old_root); xs_impl_delete(s); } --=20 2.39.0 From nobody Fri May 3 04:42:41 2024 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 ARC-Seal: i=1; a=rsa-sha256; t=1677771333; cv=none; d=zohomail.com; s=zohoarc; b=m9Hg9enVC5+yz/dfqfyrQLSWXkZkplFOlulJWQq1G1Lb/t/YGLhyWzsM07fKfO5Vc2szqcq/tT71iZ5xjfDDwWp2ZOqfEPRIvNPADkpyWesAEYq2MCIzOxZznZnvLh2wDT++ymznmPIscArfaDY2tE3AHh8HYgYAfGH45YTUVxA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1677771333; 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=gNY1jRXkt4M+fhnisAFzyDAWz2lraNB7iybmZmnwhbA=; b=DdmvG/6PcFLmgs3pFRtJcPtCrjjmCVPXGe4a91r9fnXUDPUmxZsA8Xxwaaf9ehn/Bwi4MXGqkvrj0kdpVpAPGdymtqhIK3iv8s0j2AmYSUaaE2BGLR9oLE8ZRbvnU+lGbqJ/ucYCFkTUZDHlJ4tpLzHyilYmXajMfmeEE9+6nog= 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 Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1677771333746256.16764629482486; Thu, 2 Mar 2023 07:35:33 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.505064.777724 (Exim 4.92) (envelope-from ) id 1pXkxb-0005UY-8a; Thu, 02 Mar 2023 15:35:11 +0000 Received: by outflank-mailman (output) from mailman id 505064.777724; Thu, 02 Mar 2023 15:35:10 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxa-0005Ql-E7; Thu, 02 Mar 2023 15:35:10 +0000 Received: by outflank-mailman (input) for mailman id 505064; Thu, 02 Mar 2023 15:35:01 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxQ-0001Jw-NV for xen-devel@lists.xenproject.org; Thu, 02 Mar 2023 15:35:00 +0000 Received: from desiato.infradead.org (desiato.infradead.org [2001:8b0:10b:1:d65d:64ff:fe57:4e05]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id c49d05a4-b90f-11ed-a550-8520e6686977; Thu, 02 Mar 2023 16:34:49 +0100 (CET) Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by desiato.infradead.org with esmtpsa (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-00FL3b-0G; Thu, 02 Mar 2023 15:34:38 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx3-004uyX-38; Thu, 02 Mar 2023 15:34:37 +0000 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 X-Inumbo-ID: c49d05a4-b90f-11ed-a550-8520e6686977 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=gNY1jRXkt4M+fhnisAFzyDAWz2lraNB7iybmZmnwhbA=; b=GRyqh7DapHLe3B/pRWqdW4OS43 eIn+XARqVp00KvshV2cnL61jmlRonq5iwlxJrBirExF2US0rY7depwSF8Yd5UTakOZgffCvMm9bsS VFNt1q7bf14maCXqnYIS2gH1j2+1Wd1jGG8TeFrloEpDJPHlWLcw1SsO47qi5wL1w1sHhBl4rGOwl MUeNJiQ/D4Pe+yHFi7511Irjgf3BlpSbixgsH6pmk/r5R6hK9VAa3GCsSjV6WeKj9gaQr9/AqE8Qx QwnqAuq9chcegAbBj/OYPnfMrVN7FnK4KQPExfwlN4kmYm3E1OJCxahLdi4JP2GPqlwv+5KDzZsGh 9ud3Rf7g==; From: David Woodhouse To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , Stefano Stabellini , vikram.garhwal@amd.com, Anthony Perard , xen-devel@lists.xenproject.org Subject: [RFC PATCH v1 04/25] hw/xen: Implement XenStore transactions Date: Thu, 2 Mar 2023 15:34:14 +0000 Message-Id: <20230302153435.1170111-5-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230302153435.1170111-1-dwmw2@infradead.org> References: <20230302153435.1170111-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by desiato.infradead.org. See http://www.infradead.org/rpr.html X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1677771335655100024 Content-Type: text/plain; charset="utf-8" From: David Woodhouse Given that the whole thing supported copy on write from the beginning, transactions end up being fairly simple. On starting a transaction, just take a ref of the existing root; swap it back in on a successful commit. The main tree has a transaction ID too, and we keep a record of the last transaction ID given out. if the main tree is ever modified when it isn't the latest, it gets a new transaction ID. A commit can only succeed if the main tree hasn't moved on since it was forked. Strictly speaking, the XenStore protocol allows a transaction to succeed as long as nothing *it* read or wrote has changed in the interim, but no implementations do that; *any* change is sufficient to abort a transaction. This does not yet fire watches on the changed nodes on a commit. That bit is more fun and will come in a follow-on commit. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- hw/i386/kvm/xenstore_impl.c | 150 ++++++++++++++++++++++++++++++++++-- tests/unit/test-xs-node.c | 118 ++++++++++++++++++++++++++++ 2 files changed, 262 insertions(+), 6 deletions(-) diff --git a/hw/i386/kvm/xenstore_impl.c b/hw/i386/kvm/xenstore_impl.c index 2e464af93a..e5074ab1ec 100644 --- a/hw/i386/kvm/xenstore_impl.c +++ b/hw/i386/kvm/xenstore_impl.c @@ -46,13 +46,56 @@ typedef struct XsWatch { int rel_prefix; } XsWatch; =20 +typedef struct XsTransaction { + XsNode *root; + unsigned int nr_nodes; + unsigned int base_tx; + unsigned int tx_id; + unsigned int dom_id; +} XsTransaction; + struct XenstoreImplState { XsNode *root; unsigned int nr_nodes; GHashTable *watches; unsigned int nr_domu_watches; + GHashTable *transactions; + unsigned int nr_domu_transactions; + unsigned int root_tx; + unsigned int last_tx; }; =20 + +static void nobble_tx(gpointer key, gpointer value, gpointer user_data) +{ + unsigned int *new_tx_id =3D user_data; + XsTransaction *tx =3D value; + + if (tx->base_tx =3D=3D *new_tx_id) { + /* Transactions based on XBT_NULL will always fail */ + tx->base_tx =3D XBT_NULL; + } +} + +static inline unsigned int next_tx(struct XenstoreImplState *s) +{ + unsigned int tx_id; + + /* Find the next TX id which isn't either XBT_NULL or in use. */ + do { + tx_id =3D ++s->last_tx; + } while (tx_id =3D=3D XBT_NULL || tx_id =3D=3D s->root_tx || + g_hash_table_lookup(s->transactions, GINT_TO_POINTER(tx_id))); + + /* + * It is vanishingly unlikely, but ensure that no outstanding transact= ion + * is based on the (previous incarnation of the) newly-allocated TX id. + */ + g_hash_table_foreach(s->transactions, nobble_tx, &tx_id); + + return tx_id; +} + static inline XsNode *xs_node_new(void) { XsNode *n =3D g_new0(XsNode, 1); @@ -159,6 +202,7 @@ struct walk_op { =20 GList *watches; unsigned int dom_id; + unsigned int tx_id; =20 /* The number of nodes which will exist in the tree if this op succeed= s. */ unsigned int new_nr_nodes; @@ -176,6 +220,7 @@ struct walk_op { bool inplace; bool mutating; bool create_dirs; + bool in_transaction; }; =20 static void fire_watches(struct walk_op *op, bool parents) @@ -183,7 +228,7 @@ static void fire_watches(struct walk_op *op, bool paren= ts) GList *l =3D NULL; XsWatch *w; =20 - if (!op->mutating) { + if (!op->mutating || op->in_transaction) { return; } =20 @@ -450,10 +495,23 @@ static int xs_node_walk(XsNode **n, struct walk_op *o= p) assert(!op->watches); /* * On completing the recursion back up the path walk and reaching = the - * top, assign the new node count if the operation was successful. + * top, assign the new node count if the operation was successful.= If + * the main tree was changed, bump its tx ID so that outstanding + * transactions correctly fail. But don't bump it every time; only + * if it makes a difference. */ if (!err && op->mutating) { - op->s->nr_nodes =3D op->new_nr_nodes; + if (!op->in_transaction) { + if (op->s->root_tx !=3D op->s->last_tx) { + op->s->root_tx =3D next_tx(op->s); + } + op->s->nr_nodes =3D op->new_nr_nodes; + } else { + XsTransaction *tx =3D g_hash_table_lookup(op->s->transacti= ons, + GINT_TO_POINTER(op= ->tx_id)); + assert(tx); + tx->nr_nodes =3D op->new_nr_nodes; + } } } return err; @@ -535,14 +593,23 @@ static int init_walk_op(XenstoreImplState *s, struct = walk_op *op, op->inplace =3D true; op->mutating =3D false; op->create_dirs =3D false; + op->in_transaction =3D false; op->dom_id =3D dom_id; + op->tx_id =3D tx_id; op->s =3D s; =20 if (tx_id =3D=3D XBT_NULL) { *rootp =3D &s->root; op->new_nr_nodes =3D s->nr_nodes; } else { - return ENOENT; + XsTransaction *tx =3D g_hash_table_lookup(s->transactions, + GINT_TO_POINTER(tx_id)); + if (!tx) { + return ENOENT; + } + *rootp =3D &tx->root; + op->new_nr_nodes =3D tx->nr_nodes; + op->in_transaction =3D true; } =20 return 0; @@ -616,13 +683,71 @@ int xs_impl_directory(XenstoreImplState *s, unsigned = int dom_id, int xs_impl_transaction_start(XenstoreImplState *s, unsigned int dom_id, xs_transaction_t *tx_id) { - return ENOSYS; + XsTransaction *tx; + + if (*tx_id !=3D XBT_NULL) { + return EINVAL; + } + + if (dom_id && s->nr_domu_transactions >=3D XS_MAX_TRANSACTIONS) { + return ENOSPC; + } + + tx =3D g_new0(XsTransaction, 1); + + tx->nr_nodes =3D s->nr_nodes; + tx->tx_id =3D next_tx(s); + tx->base_tx =3D s->root_tx; + tx->root =3D xs_node_ref(s->root); + tx->dom_id =3D dom_id; + + g_hash_table_insert(s->transactions, GINT_TO_POINTER(tx->tx_id), tx); + if (dom_id) { + s->nr_domu_transactions++; + } + *tx_id =3D tx->tx_id; + return 0; +} + +static int transaction_commit(XenstoreImplState *s, XsTransaction *tx) +{ + if (s->root_tx !=3D tx->base_tx) { + return EAGAIN; + } + xs_node_unref(s->root); + s->root =3D tx->root; + tx->root =3D NULL; + s->root_tx =3D tx->tx_id; + s->nr_nodes =3D tx->nr_nodes; + + /* + * XX: Walk the new root and fire watches on any node which has a + * refcount of one (which is therefore unique to this transaction). + */ + return 0; } =20 int xs_impl_transaction_end(XenstoreImplState *s, unsigned int dom_id, xs_transaction_t tx_id, bool commit) { - return ENOSYS; + int ret =3D 0; + XsTransaction *tx =3D g_hash_table_lookup(s->transactions, + GINT_TO_POINTER(tx_id)); + + if (!tx || tx->dom_id !=3D dom_id) { + return ENOENT; + } + + if (commit) { + ret =3D transaction_commit(s, tx); + } + + g_hash_table_remove(s->transactions, GINT_TO_POINTER(tx_id)); + if (dom_id) { + assert(s->nr_domu_transactions); + s->nr_domu_transactions--; + } + return ret; } =20 int xs_impl_rm(XenstoreImplState *s, unsigned int dom_id, @@ -839,15 +964,28 @@ int xs_impl_reset_watches(XenstoreImplState *s, unsig= ned int dom_id) return 0; } =20 +static void xs_tx_free(void *_tx) +{ + XsTransaction *tx =3D _tx; + if (tx->root) { + xs_node_unref(tx->root); + } + g_free(tx); +} + XenstoreImplState *xs_impl_create(void) { XenstoreImplState *s =3D g_new0(XenstoreImplState, 1); =20 s->watches =3D g_hash_table_new_full(g_str_hash, g_str_equal, g_free, = NULL); + s->transactions =3D g_hash_table_new_full(g_direct_hash, g_direct_equa= l, + NULL, xs_tx_free); s->nr_nodes =3D 1; s->root =3D xs_node_new(); #ifdef XS_NODE_UNIT_TEST s->root->name =3D g_strdup("/"); #endif + + s->root_tx =3D s->last_tx =3D 1; return s; } diff --git a/tests/unit/test-xs-node.c b/tests/unit/test-xs-node.c index 19000b64b2..3c3654550a 100644 --- a/tests/unit/test-xs-node.c +++ b/tests/unit/test-xs-node.c @@ -42,6 +42,7 @@ static void xs_impl_delete(XenstoreImplState *s) g_assert(s->nr_nodes =3D=3D 1); =20 g_hash_table_unref(s->watches); + g_hash_table_unref(s->transactions); xs_node_unref(s->root); g_free(s); =20 @@ -271,12 +272,129 @@ static void test_xs_node_simple(void) } =20 =20 +static void do_test_xs_node_tx(bool fail, bool commit) +{ + XenstoreImplState *s =3D setup(); + GString *watches =3D g_string_new(NULL); + GByteArray *data =3D g_byte_array_new(); + unsigned int tx_id =3D XBT_NULL; + int err; + + g_assert(s); + + /* Set a watch */ + err =3D xs_impl_watch(s, DOMID_GUEST, "some", "watch", + watch_cb, watches); + g_assert(!err); + g_assert(watches->len =3D=3D strlen("somewatch")); + g_assert(!strcmp(watches->str, "somewatch")); + g_string_truncate(watches, 0); + + /* Write something */ + err =3D write_str(s, DOMID_GUEST, XBT_NULL, "some/relative/path", + "something"); + g_assert(s->nr_nodes =3D=3D 7); + g_assert(!err); + g_assert(!strcmp(watches->str, + "some/relative/pathwatch")); + g_string_truncate(watches, 0); + + /* Create a transaction */ + err =3D xs_impl_transaction_start(s, DOMID_GUEST, &tx_id); + g_assert(!err); + + if (fail) { + /* Write something else in the root */ + err =3D write_str(s, DOMID_GUEST, XBT_NULL, "some/relative/path", + "another thing"); + g_assert(!err); + g_assert(s->nr_nodes =3D=3D 7); + g_assert(!strcmp(watches->str, + "some/relative/pathwatch")); + g_string_truncate(watches, 0); + } + + g_assert(!watches->len); + + /* Perform a write in the transaction */ + err =3D write_str(s, DOMID_GUEST, tx_id, "some/relative/path", + "something else"); + g_assert(!err); + g_assert(s->nr_nodes =3D=3D 7); + g_assert(!watches->len); + + err =3D xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/relative/path", d= ata); + g_assert(!err); + if (fail) { + g_assert(data->len =3D=3D strlen("another thing")); + g_assert(!memcmp(data->data, "another thing", data->len)); + } else { + g_assert(data->len =3D=3D strlen("something")); + g_assert(!memcmp(data->data, "something", data->len)); + } + g_byte_array_set_size(data, 0); + + err =3D xs_impl_read(s, DOMID_GUEST, tx_id, "some/relative/path", data= ); + g_assert(!err); + g_assert(data->len =3D=3D strlen("something else")); + g_assert(!memcmp(data->data, "something else", data->len)); + g_byte_array_set_size(data, 0); + + /* Attempt to commit the transaction */ + err =3D xs_impl_transaction_end(s, DOMID_GUEST, tx_id, commit); + if (commit && fail) { + g_assert(err =3D=3D EAGAIN); + } else { + g_assert(!err); + } + g_assert(!watches->len); + g_assert(s->nr_nodes =3D=3D 7); + + err =3D xs_impl_unwatch(s, DOMID_GUEST, "some", "watch", + watch_cb, watches); + g_assert(!err); + + err =3D xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/relative/path", d= ata); + g_assert(!err); + if (fail) { + g_assert(data->len =3D=3D strlen("another thing")); + g_assert(!memcmp(data->data, "another thing", data->len)); + } else if (commit) { + g_assert(data->len =3D=3D strlen("something else")); + g_assert(!memcmp(data->data, "something else", data->len)); + } else { + g_assert(data->len =3D=3D strlen("something")); + g_assert(!memcmp(data->data, "something", data->len)); + } + g_byte_array_unref(data); + g_string_free(watches, true); + xs_impl_delete(s); +} + +static void test_xs_node_tx_fail(void) +{ + do_test_xs_node_tx(true, true); +} + +static void test_xs_node_tx_abort(void) +{ + do_test_xs_node_tx(false, false); + do_test_xs_node_tx(true, false); +} +static void test_xs_node_tx_succeed(void) +{ + do_test_xs_node_tx(false, true); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); module_call_init(MODULE_INIT_QOM); =20 g_test_add_func("/xs_node/simple", test_xs_node_simple); + g_test_add_func("/xs_node/tx_abort", test_xs_node_tx_abort); + g_test_add_func("/xs_node/tx_fail", test_xs_node_tx_fail); + g_test_add_func("/xs_node/tx_succeed", test_xs_node_tx_succeed); =20 return g_test_run(); } --=20 2.39.0 From nobody Fri May 3 04:42:41 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1677771532579874.921560862121; Thu, 2 Mar 2023 07:38:52 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pXkxf-00042X-8Z; Thu, 02 Mar 2023 10:35:15 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pXkxK-0003pt-Qp for qemu-devel@nongnu.org; Thu, 02 Mar 2023 10:34:57 -0500 Received: from desiato.infradead.org ([2001:8b0:10b:1:d65d:64ff:fe57:4e05]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pXkxC-0001fK-IG for qemu-devel@nongnu.org; Thu, 02 Mar 2023 10:34:54 -0500 Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by desiato.infradead.org with esmtpsa (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-00FL3c-0S; Thu, 02 Mar 2023 15:34:39 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-004uyb-06; Thu, 02 Mar 2023 15:34:38 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=/2Rzkhe6vu3EnqlxwxkKLSnLjHu/z1N676CpAY7tWpg=; b=Z8dtiQ7yWkEb1ddrgJZy0gvVmE otVXOrzfKGhO9DjOfDJv3l8Ah1QRjKdyE+b8EUcmFMREDODMrCyGnNnAS9kog4DMTXOnDW//4vZbe I5UzmmY/pqLKm33tYKjJmxfK4Mjz2f83UXZJ5J8gKwSw2rXjnF85wWXprQfkgx1lopZBO44h8b+Uj ZvTRZkjQgcyjsT40iSijXqugHcN+2yeYb4oAdJ3WA6+x+pJDC7olA1/OPhbKUHt9m9zhCD/C0feWM h+QKHC0suHjb18drhfuqf5IdFPL+zv1pS6wO6J4qQ0AiJOMM+mfoaFLbMlRvttcFQInz1fqxrlUhF /lsrJAYQ==; From: David Woodhouse To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , Stefano Stabellini , vikram.garhwal@amd.com, Anthony Perard , xen-devel@lists.xenproject.org Subject: [RFC PATCH v1 05/25] hw/xen: Watches on XenStore transactions Date: Thu, 2 Mar 2023 15:34:15 +0000 Message-Id: <20230302153435.1170111-6-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230302153435.1170111-1-dwmw2@infradead.org> References: <20230302153435.1170111-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-SRS-Rewrite: SMTP reverse-path rewritten from by desiato.infradead.org. See http://www.infradead.org/rpr.html Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: none client-ip=2001:8b0:10b:1:d65d:64ff:fe57:4e05; envelope-from=BATV+9a0490e5ac528e462c30+7130+infradead.org+dwmw2@desiato.srs.infradead.org; helo=desiato.infradead.org X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1677771533142100003 Content-Type: text/plain; charset="utf-8" From: David Woodhouse Firing watches on the nodes that still exist is relatively easy; just walk the tree and look at the nodes with refcount of one. Firing watches on *deleted* nodes is more fun. We add 'modified_in_tx' and 'deleted_in_tx' flags to each node. Nodes with those flags cannot be shared, as they will always be unique to the transaction in which they were created. When xs_node_walk would need to *create* a node as scaffolding and it encounters a deleted_in_tx node, it can resurrect it simply by clearing its deleted_in_tx flag. If that node originally had any *data*, they're gone, and the modified_in_tx flag will have been set when it was first deleted. We then attempt to send appropriate watches when the transaction is committed, properly delete the deleted_in_tx nodes, and remove the modified_in_tx flag from the others. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- hw/i386/kvm/xenstore_impl.c | 151 ++++++++++++++++++++++- tests/unit/test-xs-node.c | 231 +++++++++++++++++++++++++++++++++++- 2 files changed, 380 insertions(+), 2 deletions(-) diff --git a/hw/i386/kvm/xenstore_impl.c b/hw/i386/kvm/xenstore_impl.c index e5074ab1ec..380f8003ec 100644 --- a/hw/i386/kvm/xenstore_impl.c +++ b/hw/i386/kvm/xenstore_impl.c @@ -32,6 +32,8 @@ typedef struct XsNode { GByteArray *content; GHashTable *children; uint64_t gencnt; + bool deleted_in_tx; + bool modified_in_tx; #ifdef XS_NODE_UNIT_TEST gchar *name; /* debug only */ #endif @@ -153,6 +155,13 @@ static XsNode *xs_node_copy(XsNode *old) XsNode *n =3D xs_node_new(); =20 n->gencnt =3D old->gencnt; + +#ifdef XS_NODE_UNIT_TEST + if (n->name) { + n->name =3D g_strdup(old->name); + } +#endif + if (old->children) { n->children =3D g_hash_table_new_full(g_str_hash, g_str_equal, g_f= ree, (GDestroyNotify)xs_node_unref); @@ -221,6 +230,9 @@ struct walk_op { bool mutating; bool create_dirs; bool in_transaction; + + /* Tracking during recursion so we know which is first. */ + bool deleted_in_tx; }; =20 static void fire_watches(struct walk_op *op, bool parents) @@ -277,6 +289,9 @@ static int xs_node_add_content(XsNode **n, struct walk_= op *op) g_byte_array_unref((*n)->content); } (*n)->content =3D g_byte_array_ref(data); + if (op->tx_id !=3D XBT_NULL) { + (*n)->modified_in_tx =3D true; + } return 0; } =20 @@ -333,10 +348,62 @@ static int node_rm_recurse(gpointer key, gpointer val= ue, gpointer user_data) return this_inplace; } =20 +static XsNode *xs_node_copy_deleted(XsNode *old, struct walk_op *op); +static void copy_deleted_recurse(gpointer key, gpointer value, + gpointer user_data) +{ + struct walk_op *op =3D user_data; + GHashTable *siblings =3D op->op_opaque2; + XsNode *n =3D xs_node_copy_deleted(value, op); + + /* + * Reinsert the deleted_in_tx copy of the node into the parent's + * 'children' hash table. Having stashed it from op->op_opaque2 + * before the recursive call to xs_node_copy_deleted() scribbled + * over it. + */ + g_hash_table_insert(siblings, g_strdup(key), n); +} + +static XsNode *xs_node_copy_deleted(XsNode *old, struct walk_op *op) +{ + XsNode *n =3D xs_node_new(); + + n->gencnt =3D old->gencnt; + +#ifdef XS_NODE_UNIT_TEST + if (old->name) { + n->name =3D g_strdup(old->name); + } +#endif + + if (old->children) { + n->children =3D g_hash_table_new_full(g_str_hash, g_str_equal, g_f= ree, + (GDestroyNotify)xs_node_unref); + op->op_opaque2 =3D n->children; + g_hash_table_foreach(old->children, copy_deleted_recurse, op); + } + n->deleted_in_tx =3D true; + /* If it gets resurrected we only fire a watch if it lost its content = */ + if (old->content) { + n->modified_in_tx =3D true; + } + op->new_nr_nodes--; + return n; +} + static int xs_node_rm(XsNode **n, struct walk_op *op) { bool this_inplace =3D op->inplace; =20 + if (op->tx_id !=3D XBT_NULL) { + /* It's not trivial to do inplace handling for this one */ + XsNode *old =3D *n; + *n =3D xs_node_copy_deleted(old, op); + xs_node_unref(old); + return 0; + } + /* Fire watches for, and count, nodes in the subtree which get deleted= */ if ((*n)->children) { g_hash_table_foreach_remove((*n)->children, node_rm_recurse, op); @@ -408,6 +475,10 @@ static int xs_node_walk(XsNode **n, struct walk_op *op) } =20 if (child) { + if (child->deleted_in_tx) { + assert(child->ref =3D=3D 1); + /* Cannot actually set child->deleted_in_tx =3D false until la= ter */ + } xs_node_ref(child); /* * Now we own it too. But if we can modify inplace, that's going to @@ -475,6 +546,15 @@ static int xs_node_walk(XsNode **n, struct walk_op *op) xs_node_unref(old); } =20 + /* + * If we resurrected a deleted_in_tx node, we can mark it as no longer + * deleted now that we know the overall operation has succeeded. + */ + if (op->create_dirs && child && child->deleted_in_tx) { + op->new_nr_nodes++; + child->deleted_in_tx =3D false; + } + /* * The child may be NULL here, for a remove operation. Either way, * xs_node_add_child() will do the right thing and return a value @@ -709,8 +789,69 @@ int xs_impl_transaction_start(XenstoreImplState *s, un= signed int dom_id, return 0; } =20 +static gboolean tx_commit_walk(gpointer key, gpointer value, + gpointer user_data) +{ + struct walk_op *op =3D user_data; + int path_len =3D strlen(op->path); + int key_len =3D strlen(key); + bool fire_parents =3D true; + XsWatch *watch; + XsNode *n =3D value; + + if (n->ref !=3D 1) { + return false; + } + + if (n->deleted_in_tx) { + /* + * We first watches on our parents if we are the *first* node + * to be deleted (the topmost one). This matches the behaviour + * when deleting in the live tree. + */ + fire_parents =3D !op->deleted_in_tx; + + /* Only used on the way down so no need to clear it later */ + op->deleted_in_tx =3D true; + } + + assert(key_len + path_len + 2 <=3D sizeof(op->path)); + op->path[path_len] =3D '/'; + memcpy(op->path + path_len + 1, key, key_len + 1); + + watch =3D g_hash_table_lookup(op->s->watches, op->path); + if (watch) { + op->watches =3D g_list_append(op->watches, watch); + } + + if (n->children) { + g_hash_table_foreach_remove(n->children, tx_commit_walk, op); + } + + if (watch) { + op->watches =3D g_list_remove(op->watches, watch); + } + + /* + * Don't fire watches if this node was only copied because a + * descendent was changed. The modifieD_in_tx flag indicates the + * ones which were really changed. + */ + if (n->modified_in_tx || n->deleted_in_tx) { + fire_watches(op, fire_parents); + n->modified_in_tx =3D false; + } + op->path[path_len] =3D '\0'; + + /* Deleted nodes really do get expunged when we commit */ + return n->deleted_in_tx; +} + static int transaction_commit(XenstoreImplState *s, XsTransaction *tx) { + struct walk_op op; + XsNode **n; + if (s->root_tx !=3D tx->base_tx) { return EAGAIN; } @@ -720,10 +861,18 @@ static int transaction_commit(XenstoreImplState *s, X= sTransaction *tx) s->root_tx =3D tx->tx_id; s->nr_nodes =3D tx->nr_nodes; =20 + init_walk_op(s, &op, XBT_NULL, tx->dom_id, "/", &n); + op.deleted_in_tx =3D false; + op.mutating =3D true; + /* - * XX: Walk the new root and fire watches on any node which has a + * Walk the new root and fire watches on any node which has a * refcount of one (which is therefore unique to this transaction). */ + if (s->root->children) { + g_hash_table_foreach_remove(s->root->children, tx_commit_walk, &op= ); + } + return 0; } =20 diff --git a/tests/unit/test-xs-node.c b/tests/unit/test-xs-node.c index 3c3654550a..02c72baa62 100644 --- a/tests/unit/test-xs-node.c +++ b/tests/unit/test-xs-node.c @@ -347,7 +347,13 @@ static void do_test_xs_node_tx(bool fail, bool commit) } else { g_assert(!err); } - g_assert(!watches->len); + if (commit && !fail) { + g_assert(!strcmp(watches->str, + "some/relative/pathwatch")); + g_string_truncate(watches, 0); + } else { + g_assert(!watches->len); + } g_assert(s->nr_nodes =3D=3D 7); =20 err =3D xs_impl_unwatch(s, DOMID_GUEST, "some", "watch", @@ -386,6 +392,226 @@ static void test_xs_node_tx_succeed(void) do_test_xs_node_tx(false, true); } =20 +static void test_xs_node_tx_rm(void) +{ + XenstoreImplState *s =3D setup(); + GString *watches =3D g_string_new(NULL); + GByteArray *data =3D g_byte_array_new(); + unsigned int tx_id =3D XBT_NULL; + int err; + + g_assert(s); + + /* Set a watch */ + err =3D xs_impl_watch(s, DOMID_GUEST, "some", "watch", + watch_cb, watches); + g_assert(!err); + g_assert(watches->len =3D=3D strlen("somewatch")); + g_assert(!strcmp(watches->str, "somewatch")); + g_string_truncate(watches, 0); + + /* Write something */ + err =3D write_str(s, DOMID_GUEST, XBT_NULL, "some/deep/dark/relative/p= ath", + "something"); + g_assert(!err); + g_assert(s->nr_nodes =3D=3D 9); + g_assert(!strcmp(watches->str, + "some/deep/dark/relative/pathwatch")); + g_string_truncate(watches, 0); + + /* Create a transaction */ + err =3D xs_impl_transaction_start(s, DOMID_GUEST, &tx_id); + g_assert(!err); + + /* Delete the tree in the transaction */ + err =3D xs_impl_rm(s, DOMID_GUEST, tx_id, "some/deep/dark"); + g_assert(!err); + g_assert(s->nr_nodes =3D=3D 9); + g_assert(!watches->len); + + err =3D xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/deep/dark/relativ= e/path", + data); + g_assert(!err); + g_assert(data->len =3D=3D strlen("something")); + g_assert(!memcmp(data->data, "something", data->len)); + g_byte_array_set_size(data, 0); + + /* Commit the transaction */ + err =3D xs_impl_transaction_end(s, DOMID_GUEST, tx_id, true); + g_assert(!err); + g_assert(s->nr_nodes =3D=3D 6); + + g_assert(!strcmp(watches->str, "some/deep/darkwatch")); + g_string_truncate(watches, 0); + + /* Now the node is gone */ + err =3D xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/deep/dark/relativ= e/path", + data); + g_assert(err =3D=3D ENOENT); + g_byte_array_unref(data); + + err =3D xs_impl_unwatch(s, DOMID_GUEST, "some", "watch", + watch_cb, watches); + g_assert(!err); + + g_string_free(watches, true); + xs_impl_delete(s); +} + +static void test_xs_node_tx_resurrect(void) +{ + XenstoreImplState *s =3D setup(); + GString *watches =3D g_string_new(NULL); + GByteArray *data =3D g_byte_array_new(); + unsigned int tx_id =3D XBT_NULL; + int err; + + g_assert(s); + + /* Write something */ + err =3D write_str(s, DOMID_GUEST, XBT_NULL, "some/deep/dark/relative/p= ath", + "something"); + g_assert(!err); + g_assert(s->nr_nodes =3D=3D 9); + + /* This node will be wiped and resurrected */ + err =3D write_str(s, DOMID_GUEST, XBT_NULL, "some/deep/dark", + "foo"); + g_assert(!err); + g_assert(s->nr_nodes =3D=3D 9); + + /* Set a watch */ + err =3D xs_impl_watch(s, DOMID_GUEST, "some", "watch", + watch_cb, watches); + g_assert(!err); + g_assert(watches->len =3D=3D strlen("somewatch")); + g_assert(!strcmp(watches->str, "somewatch")); + g_string_truncate(watches, 0); + + /* Create a transaction */ + err =3D xs_impl_transaction_start(s, DOMID_GUEST, &tx_id); + g_assert(!err); + + /* Delete the tree in the transaction */ + err =3D xs_impl_rm(s, DOMID_GUEST, tx_id, "some/deep"); + g_assert(!err); + g_assert(s->nr_nodes =3D=3D 9); + g_assert(!watches->len); + + /* Resurrect part of it */ + err =3D write_str(s, DOMID_GUEST, tx_id, "some/deep/dark/different/pat= h", + "something"); + g_assert(!err); + g_assert(s->nr_nodes =3D=3D 9); + + /* Commit the transaction */ + err =3D xs_impl_transaction_end(s, DOMID_GUEST, tx_id, true); + g_assert(!err); + g_assert(s->nr_nodes =3D=3D 9); + + /* lost data */ + g_assert(strstr(watches->str, "some/deep/dark/different/pathwatch")); + /* topmost deleted */ + g_assert(strstr(watches->str, "some/deep/dark/relativewatch")); + /* lost data */ + g_assert(strstr(watches->str, "some/deep/darkwatch")); + + g_string_truncate(watches, 0); + + /* Now the node is gone */ + err =3D xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/deep/dark/relativ= e/path", + data); + g_assert(err =3D=3D ENOENT); + g_byte_array_unref(data); + + err =3D xs_impl_unwatch(s, DOMID_GUEST, "some", "watch", + watch_cb, watches); + g_assert(!err); + + g_string_free(watches, true); + xs_impl_delete(s); +} + +static void test_xs_node_tx_resurrect2(void) +{ + XenstoreImplState *s =3D setup(); + GString *watches =3D g_string_new(NULL); + GByteArray *data =3D g_byte_array_new(); + unsigned int tx_id =3D XBT_NULL; + int err; + + g_assert(s); + + /* Write something */ + err =3D write_str(s, DOMID_GUEST, XBT_NULL, "some/deep/dark/relative/p= ath", + "something"); + g_assert(!err); + g_assert(s->nr_nodes =3D=3D 9); + + /* Another node to remain shared */ + err =3D write_str(s, DOMID_GUEST, XBT_NULL, "some/place/safe", "keepme= "); + g_assert(!err); + g_assert(s->nr_nodes =3D=3D 11); + + /* This node will be wiped and resurrected */ + err =3D write_str(s, DOMID_GUEST, XBT_NULL, "some/deep/dark", + "foo"); + g_assert(!err); + g_assert(s->nr_nodes =3D=3D 11); + + /* Set a watch */ + err =3D xs_impl_watch(s, DOMID_GUEST, "some", "watch", + watch_cb, watches); + g_assert(!err); + g_assert(watches->len =3D=3D strlen("somewatch")); + g_assert(!strcmp(watches->str, "somewatch")); + g_string_truncate(watches, 0); + + /* Create a transaction */ + err =3D xs_impl_transaction_start(s, DOMID_GUEST, &tx_id); + g_assert(!err); + + /* Delete the tree in the transaction */ + err =3D xs_impl_rm(s, DOMID_GUEST, tx_id, "some/deep"); + g_assert(!err); + g_assert(s->nr_nodes =3D=3D 11); + g_assert(!watches->len); + + /* Resurrect part of it */ + err =3D write_str(s, DOMID_GUEST, tx_id, "some/deep/dark/relative/path= ", + "something"); + g_assert(!err); + g_assert(s->nr_nodes =3D=3D 11); + + /* Commit the transaction */ + err =3D xs_impl_transaction_end(s, DOMID_GUEST, tx_id, true); + g_assert(!err); + g_assert(s->nr_nodes =3D=3D 11); + + /* lost data */ + g_assert(strstr(watches->str, "some/deep/dark/relative/pathwatch")); + /* lost data */ + g_assert(strstr(watches->str, "some/deep/darkwatch")); + + g_string_truncate(watches, 0); + + /* Now the node is gone */ + err =3D xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/deep/dark/relativ= e/path", + data); + g_assert(!err); + g_assert(data->len =3D=3D strlen("something")); + g_assert(!memcmp(data->data, "something", data->len)); + + g_byte_array_unref(data); + + err =3D xs_impl_unwatch(s, DOMID_GUEST, "some", "watch", + watch_cb, watches); + g_assert(!err); + + g_string_free(watches, true); + xs_impl_delete(s); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); @@ -395,6 +621,9 @@ int main(int argc, char **argv) g_test_add_func("/xs_node/tx_abort", test_xs_node_tx_abort); g_test_add_func("/xs_node/tx_fail", test_xs_node_tx_fail); g_test_add_func("/xs_node/tx_succeed", test_xs_node_tx_succeed); + g_test_add_func("/xs_node/tx_rm", test_xs_node_tx_rm); + g_test_add_func("/xs_node/tx_resurrect", test_xs_node_tx_resurrect); + g_test_add_func("/xs_node/tx_resurrect2", test_xs_node_tx_resurrect2); =20 return g_test_run(); } --=20 2.39.0 From nobody Fri May 3 04:42:41 2024 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 ARC-Seal: i=1; a=rsa-sha256; t=1677771325; cv=none; d=zohomail.com; s=zohoarc; b=AQKuw3mx1oKdrzLQr4j4h2jZCazWWhiidbbXTR11jMLUpvAako8681E4+Q8XBPcxji1glyvBsLf31trPb2ulR91H6/UP48CzkiGyyM6BxxZwVQ1VQB5adN2tg0XPuaxCFUOHV5xLpXuRd3MhdLNT1BQECsCmV1Mce+74Ko0RjB8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1677771325; 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=gd57rl6hA1kpboJXd3u6ccGehO1OwIsGsYx1K/fGbyI=; b=P7bELkaSb29UQ7LxgBtlh2xFDCh42e2KxDzCVc5UPExOBUnB4uklyiZAq5XBgrkaSB7YoKd94UxK3tfe3fQ2yiDbBVTD0BE6lnUCTOSEdSlWdNuuc/ZYcHeH8cg1yvz5SwwiDiZ1Blbb0w+gdXsl8caLczQIHwWyP3ZoacGeHMY= 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 Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1677771319289136.84064637465053; Thu, 2 Mar 2023 07:35:19 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.505055.777631 (Exim 4.92) (envelope-from ) id 1pXkxO-0002Xr-95; Thu, 02 Mar 2023 15:34:58 +0000 Received: by outflank-mailman (output) from mailman id 505055.777631; Thu, 02 Mar 2023 15:34:58 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxN-0002Ux-UC; Thu, 02 Mar 2023 15:34:57 +0000 Received: by outflank-mailman (input) for mailman id 505055; Thu, 02 Mar 2023 15:34:56 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxL-0001Jw-MR for xen-devel@lists.xenproject.org; Thu, 02 Mar 2023 15:34:55 +0000 Received: from casper.infradead.org (casper.infradead.org [2001:8b0:10b:1236::1]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id c2222017-b90f-11ed-a550-8520e6686977; Thu, 02 Mar 2023 16:34:49 +0100 (CET) Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by casper.infradead.org with esmtpsa (Exim 4.94.2 #2 (Red Hat Linux)) id 1pXkx4-002UNE-2J; Thu, 02 Mar 2023 15:34:38 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-004uyf-0H; Thu, 02 Mar 2023 15:34:38 +0000 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 X-Inumbo-ID: c2222017-b90f-11ed-a550-8520e6686977 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=gd57rl6hA1kpboJXd3u6ccGehO1OwIsGsYx1K/fGbyI=; b=acy3mFlDAoiyeYDagf/VQnYz7z GNoFtsStCfwiNviV1/hJ0GCzeCN8C2nFIpB1rfAL1RGyDnoMIOWhThp4rS1iDkk3pK0C+Iy9+fBZT P3fyWCFcoy7M+pJGQvHuI9VYEYaGwLN8WIUFYe9Rpka7C17rKTaQNzyWIaQpPyJPpe0Fu1aPTuCpg JOkFcp22gCMbfjTXfIXv8GHPLWZ+JM7jxPAiFwqiv0Jn5IT9YcW6709gnvPeSesqAG/Hr9Fv4sE6y mTvVi/J3gqH2cWrq0Kfr9Etna1eH1lPpICFoU3C47P4SJVAxa5ibOLgHj+A5xNt8VI47tMcaqMl0o C8yFoIvA==; From: David Woodhouse To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , Stefano Stabellini , vikram.garhwal@amd.com, Anthony Perard , xen-devel@lists.xenproject.org Subject: [RFC PATCH v1 06/25] hw/xen: Implement XenStore permissions Date: Thu, 2 Mar 2023 15:34:16 +0000 Message-Id: <20230302153435.1170111-7-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230302153435.1170111-1-dwmw2@infradead.org> References: <20230302153435.1170111-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by casper.infradead.org. See http://www.infradead.org/rpr.html X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1677771325622100007 Content-Type: text/plain; charset="utf-8" From: Paul Durrant Store perms as a GList of strings, check permissions. Signed-off-by: Paul Durrant Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- hw/i386/kvm/xen_xenstore.c | 2 +- hw/i386/kvm/xenstore_impl.c | 259 +++++++++++++++++++++++++++++++++--- hw/i386/kvm/xenstore_impl.h | 8 +- tests/unit/test-xs-node.c | 27 +++- 4 files changed, 275 insertions(+), 21 deletions(-) diff --git a/hw/i386/kvm/xen_xenstore.c b/hw/i386/kvm/xen_xenstore.c index 64d8f1a38f..3b409e3817 100644 --- a/hw/i386/kvm/xen_xenstore.c +++ b/hw/i386/kvm/xen_xenstore.c @@ -98,7 +98,7 @@ static void xen_xenstore_realize(DeviceState *dev, Error = **errp) aio_set_fd_handler(qemu_get_aio_context(), xen_be_evtchn_fd(s->eh), tr= ue, xen_xenstore_event, NULL, NULL, NULL, s); =20 - s->impl =3D xs_impl_create(); + s->impl =3D xs_impl_create(xen_domid); } =20 static bool xen_xenstore_is_needed(void *opaque) diff --git a/hw/i386/kvm/xenstore_impl.c b/hw/i386/kvm/xenstore_impl.c index 380f8003ec..7988bde88f 100644 --- a/hw/i386/kvm/xenstore_impl.c +++ b/hw/i386/kvm/xenstore_impl.c @@ -12,6 +12,8 @@ #include "qemu/osdep.h" #include "qom/object.h" =20 +#include "hw/xen/xen.h" + #include "xen_xenstore.h" #include "xenstore_impl.h" =20 @@ -30,6 +32,7 @@ typedef struct XsNode { uint32_t ref; GByteArray *content; + GList *perms; GHashTable *children; uint64_t gencnt; bool deleted_in_tx; @@ -133,6 +136,9 @@ static inline void xs_node_unref(XsNode *n) if (n->content) { g_byte_array_unref(n->content); } + if (n->perms) { + g_list_free_full(n->perms, g_free); + } if (n->children) { g_hash_table_unref(n->children); } @@ -144,8 +150,51 @@ static inline void xs_node_unref(XsNode *n) g_free(n); } =20 +char *xs_perm_as_string(unsigned int perm, unsigned int domid) +{ + char letter; + + switch (perm) { + case XS_PERM_READ | XS_PERM_WRITE: + letter =3D 'b'; + break; + case XS_PERM_READ: + letter =3D 'r'; + break; + case XS_PERM_WRITE: + letter =3D 'w'; + break; + case XS_PERM_NONE: + default: + letter =3D 'n'; + break; + } + + return g_strdup_printf("%c%u", letter, domid); +} + +static gpointer do_perm_copy(gconstpointer src, gpointer user_data) +{ + return g_strdup(src); +} + +static XsNode *xs_node_create(const char *name, GList *perms) +{ + XsNode *n =3D xs_node_new(); + +#ifdef XS_NODE_UNIT_TEST + if (name) { + n->name =3D g_strdup(name); + } +#endif + + n->perms =3D g_list_copy_deep(perms, do_perm_copy, NULL); + + return n; +} + /* For copying from one hash table to another using g_hash_table_foreach()= */ -static void do_insert(gpointer key, gpointer value, gpointer user_data) +static void do_child_insert(gpointer key, gpointer value, gpointer user_da= ta) { g_hash_table_insert(user_data, g_strdup(key), xs_node_ref(value)); } @@ -162,12 +211,16 @@ static XsNode *xs_node_copy(XsNode *old) } #endif =20 + assert(old); if (old->children) { n->children =3D g_hash_table_new_full(g_str_hash, g_str_equal, g_f= ree, (GDestroyNotify)xs_node_unref); - g_hash_table_foreach(old->children, do_insert, n->children); + g_hash_table_foreach(old->children, do_child_insert, n->children); } - if (old && old->content) { + if (old->perms) { + n->perms =3D g_list_copy_deep(old->perms, do_perm_copy, NULL); + } + if (old->content) { n->content =3D g_byte_array_ref(old->content); } return n; @@ -383,6 +436,9 @@ static XsNode *xs_node_copy_deleted(XsNode *old, struct= walk_op *op) op->op_opaque2 =3D n->children; g_hash_table_foreach(old->children, copy_deleted_recurse, op); } + if (old->perms) { + n->perms =3D g_list_copy_deep(old->perms, do_perm_copy, NULL); + } n->deleted_in_tx =3D true; /* If it gets resurrected we only fire a watch if it lost its content = */ if (old->content) { @@ -417,6 +473,104 @@ static int xs_node_rm(XsNode **n, struct walk_op *op) return 0; } =20 +static int xs_node_get_perms(XsNode **n, struct walk_op *op) +{ + GList **perms =3D op->op_opaque; + + assert(op->inplace); + assert(*n); + + *perms =3D g_list_copy_deep((*n)->perms, do_perm_copy, NULL); + return 0; +} + +static void parse_perm(const char *perm, char *letter, unsigned int *dom_i= d) +{ + unsigned int n =3D sscanf(perm, "%c%u", letter, dom_id); + + assert(n =3D=3D 2); +} + +static bool can_access(unsigned int dom_id, GList *perms, const char *lett= ers) +{ + unsigned int i, n; + char perm_letter; + unsigned int perm_dom_id; + bool access; + + if (dom_id =3D=3D 0) { + return true; + } + + n =3D g_list_length(perms); + assert(n >=3D 1); + + /* + * The dom_id of the first perm is the owner, and the owner always has + * read-write access. + */ + parse_perm(g_list_nth_data(perms, 0), &perm_letter, &perm_dom_id); + if (dom_id =3D=3D perm_dom_id) { + return true; + } + + /* + * The letter of the first perm specified the default access for all o= ther + * domains. + */ + access =3D !!strchr(letters, perm_letter); + for (i =3D 1; i < n; i++) { + parse_perm(g_list_nth_data(perms, i), &perm_letter, &perm_dom_id); + if (dom_id !=3D perm_dom_id) { + continue; + } + access =3D !!strchr(letters, perm_letter); + } + + return access; +} + +static int xs_node_set_perms(XsNode **n, struct walk_op *op) +{ + GList *perms =3D op->op_opaque; + + if (op->dom_id) { + unsigned int perm_dom_id; + char perm_letter; + + /* A guest may not change permissions on nodes it does not own */ + if (!can_access(op->dom_id, (*n)->perms, "")) { + return EPERM; + } + + /* A guest may not change the owner of a node it owns. */ + parse_perm(perms->data, &perm_letter, &perm_dom_id); + if (perm_dom_id !=3D op->dom_id) { + return EPERM; + } + + if (g_list_length(perms) > XS_MAX_PERMS_PER_NODE) { + return ENOSPC; + } + } + + /* We *are* the node to be written. Either this or a copy. */ + if (!op->inplace) { + XsNode *old =3D *n; + *n =3D xs_node_copy(old); + xs_node_unref(old); + } + + if ((*n)->perms) { + g_list_free_full((*n)->perms, g_free); + } + (*n)->perms =3D g_list_copy_deep(perms, do_perm_copy, NULL); + if (op->tx_id !=3D XBT_NULL) { + (*n)->modified_in_tx =3D true; + } + return 0; +} + /* * Passed a full reference in *n which it may free if it needs to COW. * @@ -458,6 +612,13 @@ static int xs_node_walk(XsNode **n, struct walk_op *op) } =20 if (!child_name) { + const char *letters =3D op->mutating ? "wb" : "rb"; + + if (!can_access(op->dom_id, old->perms, letters)) { + err =3D EACCES; + goto out; + } + /* This is the actual node on which the operation shall be perform= ed */ err =3D op->op_fn(n, op); if (!err) { @@ -491,12 +652,20 @@ static int xs_node_walk(XsNode **n, struct walk_op *o= p) stole_child =3D true; } } else if (op->create_dirs) { + assert(op->mutating); + + if (!can_access(op->dom_id, old->perms, "wb")) { + err =3D EACCES; + goto out; + } + if (op->dom_id && op->new_nr_nodes >=3D XS_MAX_DOMAIN_NODES) { err =3D ENOSPC; goto out; } + + child =3D xs_node_create(child_name, old->perms); op->new_nr_nodes++; - child =3D xs_node_new(); =20 /* * If we're creating a new child, we can clearly modify it (and its @@ -918,20 +1087,73 @@ int xs_impl_rm(XenstoreImplState *s, unsigned int do= m_id, int xs_impl_get_perms(XenstoreImplState *s, unsigned int dom_id, xs_transaction_t tx_id, const char *path, GList **pe= rms) { - /* - * The perms are (char *) in the wire format to be - * freed by the caller. - */ - return ENOSYS; + struct walk_op op; + XsNode **n; + int ret; + + ret =3D init_walk_op(s, &op, tx_id, dom_id, path, &n); + if (ret) { + return ret; + } + op.op_fn =3D xs_node_get_perms; + op.op_opaque =3D perms; + return xs_node_walk(n, &op); +} + +static void is_valid_perm(gpointer data, gpointer user_data) +{ + char *perm =3D data; + bool *valid =3D user_data; + char letter; + unsigned int dom_id; + + if (!*valid) { + return; + } + + if (sscanf(perm, "%c%u", &letter, &dom_id) !=3D 2) { + *valid =3D false; + return; + } + + switch (letter) { + case 'n': + case 'r': + case 'w': + case 'b': + break; + + default: + *valid =3D false; + break; + } } =20 int xs_impl_set_perms(XenstoreImplState *s, unsigned int dom_id, xs_transaction_t tx_id, const char *path, GList *per= ms) { - /* - * The perms are (const char *) in the wire format. - */ - return ENOSYS; + struct walk_op op; + XsNode **n; + bool valid =3D true; + int ret; + + if (!g_list_length(perms)) { + return EINVAL; + } + + g_list_foreach(perms, is_valid_perm, &valid); + if (!valid) { + return EINVAL; + } + + ret =3D init_walk_op(s, &op, tx_id, dom_id, path, &n); + if (ret) { + return ret; + } + op.op_fn =3D xs_node_set_perms; + op.op_opaque =3D perms; + op.mutating =3D true; + return xs_node_walk(n, &op); } =20 int xs_impl_watch(XenstoreImplState *s, unsigned int dom_id, const char *p= ath, @@ -1122,18 +1344,19 @@ static void xs_tx_free(void *_tx) g_free(tx); } =20 -XenstoreImplState *xs_impl_create(void) +XenstoreImplState *xs_impl_create(unsigned int dom_id) { XenstoreImplState *s =3D g_new0(XenstoreImplState, 1); + GList *perms; =20 s->watches =3D g_hash_table_new_full(g_str_hash, g_str_equal, g_free, = NULL); s->transactions =3D g_hash_table_new_full(g_direct_hash, g_direct_equa= l, NULL, xs_tx_free); + + perms =3D g_list_append(NULL, xs_perm_as_string(XS_PERM_NONE, 0)); + s->root =3D xs_node_create("/", perms); + g_list_free_full(perms, g_free); s->nr_nodes =3D 1; - s->root =3D xs_node_new(); -#ifdef XS_NODE_UNIT_TEST - s->root->name =3D g_strdup("/"); -#endif =20 s->root_tx =3D s->last_tx =3D 1; return s; diff --git a/hw/i386/kvm/xenstore_impl.h b/hw/i386/kvm/xenstore_impl.h index beb7b29ab8..2f81251b5e 100644 --- a/hw/i386/kvm/xenstore_impl.h +++ b/hw/i386/kvm/xenstore_impl.h @@ -16,9 +16,15 @@ typedef uint32_t xs_transaction_t; =20 #define XBT_NULL 0 =20 +#define XS_PERM_NONE 0x00 +#define XS_PERM_READ 0x01 +#define XS_PERM_WRITE 0x02 + typedef struct XenstoreImplState XenstoreImplState; =20 -XenstoreImplState *xs_impl_create(void); +XenstoreImplState *xs_impl_create(unsigned int dom_id); + +char *xs_perm_as_string(unsigned int perm, unsigned int domid); =20 /* * These functions return *positive* error numbers. This is a little diff --git a/tests/unit/test-xs-node.c b/tests/unit/test-xs-node.c index 02c72baa62..2c0f89c694 100644 --- a/tests/unit/test-xs-node.c +++ b/tests/unit/test-xs-node.c @@ -80,8 +80,9 @@ static void watch_cb(void *_str, const char *path, const = char *token) =20 static XenstoreImplState *setup(void) { - XenstoreImplState *s =3D xs_impl_create(); + XenstoreImplState *s =3D xs_impl_create(DOMID_GUEST); char *abspath; + GList *perms; int err; =20 abspath =3D g_strdup_printf("/local/domain/%u", DOMID_GUEST); @@ -90,6 +91,13 @@ static XenstoreImplState *setup(void) g_assert(!err); g_assert(s->nr_nodes =3D=3D 4); =20 + perms =3D g_list_append(NULL, g_strdup_printf("n%u", DOMID_QEMU)); + perms =3D g_list_append(perms, g_strdup_printf("r%u", DOMID_GUEST)); + + err =3D xs_impl_set_perms(s, DOMID_QEMU, XBT_NULL, abspath, perms); + g_assert(!err); + + g_list_free_full(perms, g_free); g_free(abspath); =20 abspath =3D g_strdup_printf("/local/domain/%u/some", DOMID_GUEST); @@ -98,6 +106,12 @@ static XenstoreImplState *setup(void) g_assert(!err); g_assert(s->nr_nodes =3D=3D 5); =20 + perms =3D g_list_append(NULL, g_strdup_printf("n%u", DOMID_GUEST)); + + err =3D xs_impl_set_perms(s, DOMID_QEMU, XBT_NULL, abspath, perms); + g_assert(!err); + + g_list_free_full(perms, g_free); g_free(abspath); =20 return s; @@ -166,6 +180,12 @@ static void test_xs_node_simple(void) /* Keep a copy, to force COW mode */ old_root =3D xs_node_ref(s->root); =20 + /* Write somewhere we aren't allowed, in COW mode */ + err =3D write_str(s, DOMID_GUEST, XBT_NULL, "/local/domain/badplace", + "moredata"); + g_assert(err =3D=3D EACCES); + g_assert(s->nr_nodes =3D=3D 7); + /* Write works again */ err =3D write_str(s, DOMID_GUEST, XBT_NULL, "/local/domain/1/some/relative/path2", @@ -226,6 +246,11 @@ static void test_xs_node_simple(void) g_assert(!err); g_assert(s->nr_nodes =3D=3D 8); =20 + /* Write somewhere we aren't allowed */ + err =3D write_str(s, DOMID_GUEST, XBT_NULL, "/local/domain/badplace", + "moredata"); + g_assert(err =3D=3D EACCES); + g_assert(!strcmp(guest_watches->str, "/local/domain/1/some/relativewatchrel")); g_string_truncate(guest_watches, 0); --=20 2.39.0 From nobody Fri May 3 04:42:41 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1677771376829520.4199082893314; Thu, 2 Mar 2023 07:36:16 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pXkxh-00046Z-6S; Thu, 02 Mar 2023 10:35:17 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pXkxQ-0003tx-Jt for qemu-devel@nongnu.org; Thu, 02 Mar 2023 10:35:05 -0500 Received: from desiato.infradead.org ([2001:8b0:10b:1:d65d:64ff:fe57:4e05]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pXkxM-0001fD-F3 for qemu-devel@nongnu.org; Thu, 02 Mar 2023 10:35:00 -0500 Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by desiato.infradead.org with esmtpsa (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-00FL3d-0o; Thu, 02 Mar 2023 15:34:39 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-004uyj-0S; Thu, 02 Mar 2023 15:34:38 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=Ca2714vgfm18G+KeFQHG/S9JS+BdaUec2bE3wcS910w=; b=qyL9Kow45NCZ9QXvTmhTUdR7fP UZgbx0jLXWCGC2o642X5kABEQ3uxiER8SvY8ieySF2nq5ZwLsuV0bwwEM2jDfXqjtz4SY+mUfRD/A VIJEQGIuAxFEILYbPrtQLaSGOvmndf82DwEfZgt5aWNUcAAMqM/ptFjUINSB9UJXavstslaR3tu9C e16Wtac8SiRFl5/ev5mGu1N1SnUwWLW7hkiHTYS05SCNqBe5BFbQYMefdailPDkVBGuhd1nxZuZEb m71IrNCzneaP8uhfZ6LgR4Qol0eiMtv1yang1PnVab3YAvcQZfABxcnyBCo7GHEjxuyLkYydBChQ8 2i8AIudg==; From: David Woodhouse To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , Stefano Stabellini , vikram.garhwal@amd.com, Anthony Perard , xen-devel@lists.xenproject.org Subject: [RFC PATCH v1 07/25] hw/xen: Implement core serialize/deserialize methods for xenstore_impl Date: Thu, 2 Mar 2023 15:34:17 +0000 Message-Id: <20230302153435.1170111-8-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230302153435.1170111-1-dwmw2@infradead.org> References: <20230302153435.1170111-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-SRS-Rewrite: SMTP reverse-path rewritten from by desiato.infradead.org. See http://www.infradead.org/rpr.html Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: none client-ip=2001:8b0:10b:1:d65d:64ff:fe57:4e05; envelope-from=BATV+9a0490e5ac528e462c30+7130+infradead.org+dwmw2@desiato.srs.infradead.org; helo=desiato.infradead.org X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1677771377827100003 Content-Type: text/plain; charset="utf-8" From: David Woodhouse In fact I think we want to only serialize the contents of the domain's path in /local/domain/${domid} and leave the rest to be recreated? Will defer to Paul for that. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- hw/i386/kvm/xen_xenstore.c | 25 +- hw/i386/kvm/xenstore_impl.c | 574 +++++++++++++++++++++++++++++++++++- hw/i386/kvm/xenstore_impl.h | 5 + tests/unit/test-xs-node.c | 236 ++++++++++++++- 4 files changed, 824 insertions(+), 16 deletions(-) diff --git a/hw/i386/kvm/xen_xenstore.c b/hw/i386/kvm/xen_xenstore.c index 3b409e3817..1b1358ad4c 100644 --- a/hw/i386/kvm/xen_xenstore.c +++ b/hw/i386/kvm/xen_xenstore.c @@ -66,6 +66,9 @@ struct XenXenstoreState { evtchn_port_t guest_port; evtchn_port_t be_port; struct xenevtchn_handle *eh; + + uint8_t *impl_state; + uint32_t impl_state_size; }; =20 struct XenXenstoreState *xen_xenstore_singleton; @@ -109,16 +112,26 @@ static bool xen_xenstore_is_needed(void *opaque) static int xen_xenstore_pre_save(void *opaque) { XenXenstoreState *s =3D opaque; + GByteArray *save; =20 if (s->eh) { s->guest_port =3D xen_be_evtchn_get_guest_port(s->eh); } + + g_free(s->impl_state); + save =3D xs_impl_serialize(s->impl); + s->impl_state =3D save->data; + s->impl_state_size =3D save->len; + g_byte_array_free(save, false); + return 0; } =20 static int xen_xenstore_post_load(void *opaque, int ver) { XenXenstoreState *s =3D opaque; + GByteArray *save; + int ret; =20 /* * As qemu/dom0, rebind to the guest's port. The Windows drivers may @@ -135,7 +148,13 @@ static int xen_xenstore_post_load(void *opaque, int ve= r) } s->be_port =3D be_port; } - return 0; + + save =3D g_byte_array_new_take(s->impl_state, s->impl_state_size); + s->impl_state =3D NULL; + s->impl_state_size =3D 0; + + ret =3D xs_impl_deserialize(s->impl, save, xen_domid, fire_watch_cb, s= ); + return ret; } =20 static const VMStateDescription xen_xenstore_vmstate =3D { @@ -155,6 +174,10 @@ static const VMStateDescription xen_xenstore_vmstate = =3D { VMSTATE_BOOL(rsp_pending, XenXenstoreState), VMSTATE_UINT32(guest_port, XenXenstoreState), VMSTATE_BOOL(fatal_error, XenXenstoreState), + VMSTATE_UINT32(impl_state_size, XenXenstoreState), + VMSTATE_VARRAY_UINT32_ALLOC(impl_state, XenXenstoreState, + impl_state_size, 0, + vmstate_info_uint8, uint8_t), VMSTATE_END_OF_LIST() } }; diff --git a/hw/i386/kvm/xenstore_impl.c b/hw/i386/kvm/xenstore_impl.c index 7988bde88f..82e7ae06f5 100644 --- a/hw/i386/kvm/xenstore_impl.c +++ b/hw/i386/kvm/xenstore_impl.c @@ -37,6 +37,7 @@ typedef struct XsNode { uint64_t gencnt; bool deleted_in_tx; bool modified_in_tx; + unsigned int serialized_tx; #ifdef XS_NODE_UNIT_TEST gchar *name; /* debug only */ #endif @@ -68,6 +69,7 @@ struct XenstoreImplState { unsigned int nr_domu_transactions; unsigned int root_tx; unsigned int last_tx; + bool serialized; }; =20 =20 @@ -1156,8 +1158,10 @@ int xs_impl_set_perms(XenstoreImplState *s, unsigned= int dom_id, return xs_node_walk(n, &op); } =20 -int xs_impl_watch(XenstoreImplState *s, unsigned int dom_id, const char *p= ath, - const char *token, xs_impl_watch_fn fn, void *opaque) +static int do_xs_impl_watch(XenstoreImplState *s, unsigned int dom_id, + const char *path, const char *token, + xs_impl_watch_fn fn, void *opaque) + { char abspath[XENSTORE_ABS_PATH_MAX + 1]; XsWatch *w, *l; @@ -1200,12 +1204,22 @@ int xs_impl_watch(XenstoreImplState *s, unsigned in= t dom_id, const char *path, s->nr_domu_watches++; } =20 - /* A new watch should fire immediately */ - fn(opaque, path, token); - return 0; } =20 +int xs_impl_watch(XenstoreImplState *s, unsigned int dom_id, const char *p= ath, + const char *token, xs_impl_watch_fn fn, void *opaque) +{ + int ret =3D do_xs_impl_watch(s, dom_id, path, token, fn, opaque); + + if (!ret) { + /* A new watch should fire immediately */ + fn(opaque, path, token); + } + + return ret; +} + static XsWatch *free_watch(XenstoreImplState *s, XsWatch *w) { XsWatch *next =3D w->next; @@ -1361,3 +1375,553 @@ XenstoreImplState *xs_impl_create(unsigned int dom_= id) s->root_tx =3D s->last_tx =3D 1; return s; } + + +static void clear_serialized_tx(gpointer key, gpointer value, gpointer opa= que) +{ + XsNode *n =3D value; + + n->serialized_tx =3D XBT_NULL; + if (n->children) { + g_hash_table_foreach(n->children, clear_serialized_tx, NULL); + } +} + +static void clear_tx_serialized_tx(gpointer key, gpointer value, + gpointer opaque) +{ + XsTransaction *t =3D value; + + clear_serialized_tx(NULL, t->root, NULL); +} + +static void write_be32(GByteArray *save, uint32_t val) +{ + uint32_t be =3D htonl(val); + g_byte_array_append(save, (void *)&be, sizeof(be)); +} + + +struct save_state { + GByteArray *bytes; + unsigned int tx_id; +}; + +#define MODIFIED_IN_TX (1U << 0) +#define DELETED_IN_TX (1U << 1) +#define NODE_REF (1U << 2) + +static void save_node(gpointer key, gpointer value, gpointer opaque) +{ + struct save_state *ss =3D opaque; + XsNode *n =3D value; + char *name =3D key; + uint8_t flag =3D 0; + + /* Child nodes (i.e. anything but the root) have a name */ + if (name) { + g_byte_array_append(ss->bytes, key, strlen(key) + 1); + } + + /* + * If we already wrote this node, refer to the previous copy. + * There's no rename/move in XenStore, so all we need to find + * it is the tx_id of the transation in which it exists. Which + * may be the root tx. + */ + if (n->serialized_tx !=3D XBT_NULL) { + flag =3D NODE_REF; + g_byte_array_append(ss->bytes, &flag, 1); + write_be32(ss->bytes, n->serialized_tx); + } else { + GList *l; + n->serialized_tx =3D ss->tx_id; + + if (n->modified_in_tx) { + flag |=3D MODIFIED_IN_TX; + } + if (n->deleted_in_tx) { + flag |=3D DELETED_IN_TX; + } + g_byte_array_append(ss->bytes, &flag, 1); + + if (n->content) { + write_be32(ss->bytes, n->content->len); + g_byte_array_append(ss->bytes, n->content->data, n->content->l= en); + } else { + write_be32(ss->bytes, 0); + } + + for (l =3D n->perms; l; l =3D l->next) { + g_byte_array_append(ss->bytes, l->data, strlen(l->data) + 1); + } + /* NUL termination after perms */ + g_byte_array_append(ss->bytes, (void *)"", 1); + + if (n->children) { + g_hash_table_foreach(n->children, save_node, ss); + } + /* NUL termination after children (child name is NUL) */ + g_byte_array_append(ss->bytes, (void *)"", 1); + } +} + +static void save_tree(struct save_state *ss, uint32_t tx_id, XsNode *root) +{ + write_be32(ss->bytes, tx_id); + ss->tx_id =3D tx_id; + save_node(NULL, root, ss); +} + +static void save_tx(gpointer key, gpointer value, gpointer opaque) +{ + uint32_t tx_id =3D GPOINTER_TO_INT(key); + struct save_state *ss =3D opaque; + XsTransaction *n =3D value; + + write_be32(ss->bytes, n->base_tx); + write_be32(ss->bytes, n->dom_id); + + save_tree(ss, tx_id, n->root); +} + +static void save_watch(gpointer key, gpointer value, gpointer opaque) +{ + struct save_state *ss =3D opaque; + XsWatch *w =3D value; + + /* We only save the *guest* watches. */ + if (w->dom_id) { + gpointer relpath =3D key + w->rel_prefix; + g_byte_array_append(ss->bytes, relpath, strlen(relpath) + 1); + g_byte_array_append(ss->bytes, (void *)w->token, strlen(w->token) = + 1); + } +} + +GByteArray *xs_impl_serialize(XenstoreImplState *s) +{ + struct save_state ss; + + ss.bytes =3D g_byte_array_new(); + + /* + * node =3D flags [ real_node / node_ref ] + * flags =3D uint8_t (MODIFIED_IN_TX | DELETED_IN_TX | NODE_REF) + * node_ref =3D tx_id (in which the original version of this node ex= ists) + * real_node =3D content perms child* NUL + * content =3D len data + * len =3D uint32_t + * data =3D uint8_t{len} + * perms =3D perm* NUL + * perm =3D asciiz + * child =3D name node + * name =3D asciiz + * + * tree =3D tx_id node + * tx_id =3D uint32_t + * + * transaction =3D base_tx_id dom_id tree + * base_tx_id =3D uint32_t + * dom_id =3D uint32_t + * + * tx_list =3D tree transaction* XBT_NULL + * + * watch =3D path token + * path =3D asciiz + * token =3D asciiz + * + * watch_list =3D watch* NUL + * + * xs_serialize_stream =3D last_tx tx_list watch_list + * last_tx =3D uint32_t + */ + + /* Clear serialized_tx in every node. */ + if (s->serialized) { + clear_serialized_tx(NULL, s->root, NULL); + g_hash_table_foreach(s->transactions, clear_tx_serialized_tx, NULL= ); + } + + s->serialized =3D true; + + write_be32(ss.bytes, s->last_tx); + save_tree(&ss, s->root_tx, s->root); + g_hash_table_foreach(s->transactions, save_tx, &ss); + + write_be32(ss.bytes, XBT_NULL); + + g_hash_table_foreach(s->watches, save_watch, &ss); + g_byte_array_append(ss.bytes, (void *)"", 1); + + return ss.bytes; +} + +struct unsave_state { + char path[XENSTORE_ABS_PATH_MAX + 1]; + XenstoreImplState *s; + GByteArray *bytes; + uint8_t *d; + size_t l; + bool root_walk; +}; + +static int consume_be32(struct unsave_state *us, unsigned int *val) +{ + uint32_t d; + + if (us->l < sizeof(d)) { + return -EINVAL; + } + memcpy(&d, us->d, sizeof(d)); + *val =3D ntohl(d); + us->d +=3D sizeof(d); + us->l -=3D sizeof(d); + return 0; +} + +static int consume_string(struct unsave_state *us, char **str, size_t *len) +{ + size_t l; + + if (!us->l) { + return -EINVAL; + } + + l =3D strnlen((void *)us->d, us->l); + if (l =3D=3D us->l) { + return -EINVAL; + } + + if (str) { + *str =3D (void *)us->d; + } + if (len) { + *len =3D l; + } + + us->d +=3D l + 1; + us->l -=3D l + 1; + return 0; +} + +static XsNode *lookup_node(XsNode *n, char *path) +{ + char *slash =3D strchr(path, '/'); + XsNode *child; + + if (path[0] =3D=3D '\0') { + return n; + } + + if (slash) { + *slash =3D '\0'; + } + + if (!n->children) { + return NULL; + } + child =3D g_hash_table_lookup(n->children, path); + if (!slash) { + return child; + } + + *slash =3D '/'; + if (!child) { + return NULL; + } + return lookup_node(child, slash + 1); +} + +static XsNode *lookup_tx_node(struct unsave_state *us, unsigned int tx_id) +{ + XsTransaction *t; + if (tx_id =3D=3D us->s->root_tx) { + return lookup_node(us->s->root, us->path + 1); + } + + t =3D g_hash_table_lookup(us->s->transactions, GINT_TO_POINTER(tx_id)); + if (!t) { + return NULL; + } + g_assert(t->root); + return lookup_node(t->root, us->path + 1); +} + +static void count_child_nodes(gpointer key, gpointer value, gpointer user_= data) +{ + unsigned int *nr_nodes =3D user_data; + XsNode *n =3D value; + + (*nr_nodes)++; + + if (n->children) { + g_hash_table_foreach(n->children, count_child_nodes, nr_nodes); + } +} + +static int consume_node(struct unsave_state *us, XsNode **nodep, + unsigned int *nr_nodes) +{ + XsNode *n =3D NULL; + uint8_t flags; + int ret; + + if (us->l < 1) { + return -EINVAL; + } + flags =3D us->d[0]; + us->d++; + us->l--; + + if (flags =3D=3D NODE_REF) { + unsigned int tx; + + ret =3D consume_be32(us, &tx); + if (ret) { + return ret; + } + + n =3D lookup_tx_node(us, tx); + if (!n) { + return -EINVAL; + } + n->ref++; + if (n->children) { + g_hash_table_foreach(n->children, count_child_nodes, nr_nodes); + } + } else { + uint32_t datalen; + + if (flags & ~(DELETED_IN_TX | MODIFIED_IN_TX)) { + return -EINVAL; + } + n =3D xs_node_new(); + + if (flags & DELETED_IN_TX) { + n->deleted_in_tx =3D true; + } + if (flags & MODIFIED_IN_TX) { + n->modified_in_tx =3D true; + } + ret =3D consume_be32(us, &datalen); + if (ret) { + xs_node_unref(n); + return -EINVAL; + } + if (datalen) { + if (datalen > us->l) { + xs_node_unref(n); + return -EINVAL; + } + + GByteArray *node_data =3D g_byte_array_new(); + g_byte_array_append(node_data, us->d, datalen); + us->d +=3D datalen; + us->l -=3D datalen; + n->content =3D node_data; + + if (us->root_walk) { + n->modified_in_tx =3D true; + } + } + while (1) { + char *perm =3D NULL; + size_t permlen =3D 0; + + ret =3D consume_string(us, &perm, &permlen); + if (ret) { + xs_node_unref(n); + return ret; + } + + if (!permlen) { + break; + } + + n->perms =3D g_list_append(n->perms, g_strdup(perm)); + } + + /* Now children */ + while (1) { + size_t childlen; + char *childname; + char *pathend; + XsNode *child =3D NULL; + + ret =3D consume_string(us, &childname, &childlen); + if (ret) { + xs_node_unref(n); + return ret; + } + + if (!childlen) { + break; + } + + pathend =3D us->path + strlen(us->path); + strncat(us->path, "/", sizeof(us->path) - 1); + strncat(us->path, childname, sizeof(us->path) - 1); + + ret =3D consume_node(us, &child, nr_nodes); + *pathend =3D '\0'; + if (ret) { + xs_node_unref(n); + return ret; + } + g_assert(child); + xs_node_add_child(n, childname, child); + } + + /* + * If the node has no data and no children we still want to fire + * a watch on it. + */ + if (us->root_walk && !n->children) { + n->modified_in_tx =3D true; + } + } + + if (!n->deleted_in_tx) { + (*nr_nodes)++; + } + + *nodep =3D n; + return 0; +} + +static int consume_tree(struct unsave_state *us, XsTransaction *t) +{ + int ret; + + ret =3D consume_be32(us, &t->tx_id); + if (ret) { + return ret; + } + + if (t->tx_id > us->s->last_tx) { + return -EINVAL; + } + + us->path[0] =3D '\0'; + + return consume_node(us, &t->root, &t->nr_nodes); +} + +int xs_impl_deserialize(XenstoreImplState *s, GByteArray *bytes, + unsigned int dom_id, xs_impl_watch_fn watch_fn, + void *watch_opaque) +{ + struct unsave_state us; + XsTransaction base_t =3D { 0 }; + int ret; + + us.s =3D s; + us.bytes =3D bytes; + us.d =3D bytes->data; + us.l =3D bytes->len; + + xs_impl_reset_watches(s, dom_id); + g_hash_table_remove_all(s->transactions); + + xs_node_unref(s->root); + s->root =3D NULL; + s->root_tx =3D s->last_tx =3D XBT_NULL; + + ret =3D consume_be32(&us, &s->last_tx); + if (ret) { + return ret; + } + + /* + * Consume the base tree into a transaction so that watches can be + * fired as we commit it. By setting us.root_walk we cause the nodes + * to be marked as 'modified_in_tx' as they are created, so that the + * watches are triggered on them. + */ + base_t.dom_id =3D dom_id; + base_t.base_tx =3D XBT_NULL; + us.root_walk =3D true; + ret =3D consume_tree(&us, &base_t); + if (ret) { + return ret; + } + us.root_walk =3D false; + + /* + * Commit the transaction now while the refcount on all nodes is 1. + * Note that we haven't yet reinstated the *guest* watches but that's + * OK because we don't want the guest to see any changes. Even any + * backend nodes which get recreated should be *precisely* as they + * were before the migration. Back ends may have been instantiated + * already, and will see the frontend magically blink into existence + * now (well, from the aio_bh which fires the watches). It's their + * responsibility to rebuild everything precisely as it was before. + */ + ret =3D transaction_commit(s, &base_t); + if (ret) { + return ret; + } + + while (1) { + unsigned int base_tx; + XsTransaction *t; + + ret =3D consume_be32(&us, &base_tx); + if (ret) { + return ret; + } + if (base_tx =3D=3D XBT_NULL) { + break; + } + + t =3D g_new0(XsTransaction, 1); + t->base_tx =3D base_tx; + + ret =3D consume_be32(&us, &t->dom_id); + if (!ret) { + ret =3D consume_tree(&us, t); + } + if (ret) { + g_free(t); + return ret; + } + g_assert(t->root); + if (t->dom_id) { + s->nr_domu_transactions++; + } + g_hash_table_insert(s->transactions, GINT_TO_POINTER(t->tx_id), t); + } + + while (1) { + char *path, *token; + size_t pathlen, toklen; + + ret =3D consume_string(&us, &path, &pathlen); + if (ret) { + return ret; + } + if (!pathlen) { + break; + } + + ret =3D consume_string(&us, &token, &toklen); + if (ret) { + return ret; + } + + if (!watch_fn) { + continue; + } + + ret =3D do_xs_impl_watch(s, dom_id, path, token, watch_fn, watch_o= paque); + if (ret) { + return ret; + } + } + + if (us.l) { + return -EINVAL; + } + + return 0; +} diff --git a/hw/i386/kvm/xenstore_impl.h b/hw/i386/kvm/xenstore_impl.h index 2f81251b5e..bbe2391e2e 100644 --- a/hw/i386/kvm/xenstore_impl.h +++ b/hw/i386/kvm/xenstore_impl.h @@ -61,4 +61,9 @@ int xs_impl_unwatch(XenstoreImplState *s, unsigned int do= m_id, void *opaque); int xs_impl_reset_watches(XenstoreImplState *s, unsigned int dom_id); =20 +GByteArray *xs_impl_serialize(XenstoreImplState *s); +int xs_impl_deserialize(XenstoreImplState *s, GByteArray *bytes, + unsigned int dom_id, xs_impl_watch_fn watch_fn, + void *watch_opaque); + #endif /* QEMU_XENSTORE_IMPL_H */ diff --git a/tests/unit/test-xs-node.c b/tests/unit/test-xs-node.c index 2c0f89c694..fda6a047d0 100644 --- a/tests/unit/test-xs-node.c +++ b/tests/unit/test-xs-node.c @@ -29,8 +29,32 @@ static GList *xs_node_list; #define DOMID_QEMU 0 #define DOMID_GUEST 1 =20 +static void dump_ref(const char *name, XsNode *n, int indent) +{ + int i; + + if (!indent && name) { + printf("%s:\n", name); + } + + for (i =3D 0; i < indent; i++) { + printf(" "); + } + + printf("->%p(%d, '%s'): '%.*s'%s%s\n", n, n->ref, n->name, + (int)(n->content ? n->content->len : strlen("")), + n->content ? (char *)n->content->data : "", + n->modified_in_tx ? " MODIFIED" : "", + n->deleted_in_tx ? " DELETED" : ""); + + if (n->children) { + g_hash_table_foreach(n->children, (void *)dump_ref, + GINT_TO_POINTER(indent + 2)); + } +} + /* This doesn't happen in qemu but we want to make valgrind happy */ -static void xs_impl_delete(XenstoreImplState *s) +static void xs_impl_delete(XenstoreImplState *s, bool last) { int err; =20 @@ -46,6 +70,10 @@ static void xs_impl_delete(XenstoreImplState *s) xs_node_unref(s->root); g_free(s); =20 + if (!last) { + return; + } + if (xs_node_list) { GList *l; for (l =3D xs_node_list; l; l =3D l->next) { @@ -57,6 +85,137 @@ static void xs_impl_delete(XenstoreImplState *s) g_assert(!nr_xs_nodes); } =20 +struct compare_walk { + char path[XENSTORE_ABS_PATH_MAX + 1]; + XsNode *parent_2; + bool compare_ok; +}; + + +static bool compare_perms(GList *p1, GList *p2) +{ + while (p1) { + if (!p2 || g_strcmp0(p1->data, p2->data)) { + return false; + } + p1 =3D p1->next; + p2 =3D p2->next; + } + return (p2 =3D=3D NULL); +} + +static bool compare_content(GByteArray *c1, GByteArray *c2) +{ + size_t len1 =3D 0, len2 =3D 0; + + if (c1) { + len1 =3D c1->len; + } + if (c2) { + len2 =3D c2->len; + } + if (len1 !=3D len2) { + return false; + } + + if (!len1) { + return true; + } + + return !memcmp(c1->data, c2->data, len1); +} + +static void compare_child(gpointer, gpointer, gpointer); + +static void compare_nodes(struct compare_walk *cw, XsNode *n1, XsNode *n2) +{ + int nr_children1 =3D 0, nr_children2 =3D 0; + + if (n1->children) { + nr_children1 =3D g_hash_table_size(n1->children); + } + if (n2->children) { + nr_children2 =3D g_hash_table_size(n2->children); + } + + if (n1->ref !=3D n2->ref || + n1->deleted_in_tx !=3D n2->deleted_in_tx || + n1->modified_in_tx !=3D n2->modified_in_tx || + !compare_perms(n1->perms, n2->perms) || + !compare_content(n1->content, n2->content) || + nr_children1 !=3D nr_children2) { + cw->compare_ok =3D false; + printf("Compare failure on '%s'\n", cw->path); + } + + if (nr_children1) { + XsNode *oldparent =3D cw->parent_2; + cw->parent_2 =3D n2; + g_hash_table_foreach(n1->children, compare_child, cw); + + cw->parent_2 =3D oldparent; + } +} + +static void compare_child(gpointer key, gpointer val, gpointer opaque) +{ + struct compare_walk *cw =3D opaque; + char *childname =3D key; + XsNode *child1 =3D val; + XsNode *child2 =3D g_hash_table_lookup(cw->parent_2->children, childna= me); + int pathlen =3D strlen(cw->path); + + if (!child2) { + cw->compare_ok =3D false; + printf("Child '%s' does not exist under '%s'\n", childname, cw->pa= th); + return; + } + + strncat(cw->path, "/", sizeof(cw->path) - 1); + strncat(cw->path, childname, sizeof(cw->path) - 1); + + compare_nodes(cw, child1, child2); + cw->path[pathlen] =3D '\0'; +} + +static bool compare_trees(XsNode *n1, XsNode *n2) +{ + struct compare_walk cw; + + cw.path[0] =3D '\0'; + cw.parent_2 =3D n2; + cw.compare_ok =3D true; + + if (!n1 || !n2) { + return false; + } + + compare_nodes(&cw, n1, n2); + return cw.compare_ok; +} + +static void compare_tx(gpointer key, gpointer val, gpointer opaque) +{ + XenstoreImplState *s2 =3D opaque; + XsTransaction *t1 =3D val, *t2; + unsigned int tx_id =3D GPOINTER_TO_INT(key); + + t2 =3D g_hash_table_lookup(s2->transactions, key); + g_assert(t2); + + g_assert(t1->tx_id =3D=3D tx_id); + g_assert(t2->tx_id =3D=3D tx_id); + g_assert(t1->base_tx =3D=3D t2->base_tx); + g_assert(t1->dom_id =3D=3D t2->dom_id); + if (!compare_trees(t1->root, t2->root)) { + printf("Comparison failure in TX %u after serdes:\n", tx_id); + dump_ref("Original", t1->root, 0); + dump_ref("Deserialised", t2->root, 0); + g_assert(0); + } + g_assert(t1->nr_nodes =3D=3D t2->nr_nodes); +} + static int write_str(XenstoreImplState *s, unsigned int dom_id, unsigned int tx_id, const char *path, const char *content) @@ -78,6 +237,40 @@ static void watch_cb(void *_str, const char *path, cons= t char *token) g_string_append(str, token); } =20 +static void check_serdes(XenstoreImplState *s) +{ + XenstoreImplState *s2 =3D xs_impl_create(DOMID_GUEST); + GByteArray *bytes =3D xs_impl_serialize(s); + int nr_transactions1, nr_transactions2; + int ret; + + ret =3D xs_impl_deserialize(s2, bytes, DOMID_GUEST, watch_cb, NULL); + g_assert(!ret); + + g_byte_array_unref(bytes); + + g_assert(s->last_tx =3D=3D s2->last_tx); + g_assert(s->root_tx =3D=3D s2->root_tx); + + if (!compare_trees(s->root, s2->root)) { + printf("Comparison failure in main tree after serdes:\n"); + dump_ref("Original", s->root, 0); + dump_ref("Deserialised", s2->root, 0); + g_assert(0); + } + + nr_transactions1 =3D g_hash_table_size(s->transactions); + nr_transactions2 =3D g_hash_table_size(s2->transactions); + g_assert(nr_transactions1 =3D=3D nr_transactions2); + + g_hash_table_foreach(s->transactions, compare_tx, s2); + + g_assert(s->nr_domu_watches =3D=3D s2->nr_domu_watches); + g_assert(s->nr_domu_transactions =3D=3D s2->nr_domu_transactions); + g_assert(s->nr_nodes =3D=3D s2->nr_nodes); + xs_impl_delete(s2, false); +} + static XenstoreImplState *setup(void) { XenstoreImplState *s =3D xs_impl_create(DOMID_GUEST); @@ -293,7 +486,7 @@ static void test_xs_node_simple(void) g_string_free(qemu_watches, true); g_string_free(guest_watches, true); xs_node_unref(old_root); - xs_impl_delete(s); + xs_impl_delete(s, true); } =20 =20 @@ -365,6 +558,8 @@ static void do_test_xs_node_tx(bool fail, bool commit) g_assert(!memcmp(data->data, "something else", data->len)); g_byte_array_set_size(data, 0); =20 + check_serdes(s); + /* Attempt to commit the transaction */ err =3D xs_impl_transaction_end(s, DOMID_GUEST, tx_id, commit); if (commit && fail) { @@ -381,6 +576,8 @@ static void do_test_xs_node_tx(bool fail, bool commit) } g_assert(s->nr_nodes =3D=3D 7); =20 + check_serdes(s); + err =3D xs_impl_unwatch(s, DOMID_GUEST, "some", "watch", watch_cb, watches); g_assert(!err); @@ -399,7 +596,7 @@ static void do_test_xs_node_tx(bool fail, bool commit) } g_byte_array_unref(data); g_string_free(watches, true); - xs_impl_delete(s); + xs_impl_delete(s, true); } =20 static void test_xs_node_tx_fail(void) @@ -461,6 +658,8 @@ static void test_xs_node_tx_rm(void) g_assert(!memcmp(data->data, "something", data->len)); g_byte_array_set_size(data, 0); =20 + check_serdes(s); + /* Commit the transaction */ err =3D xs_impl_transaction_end(s, DOMID_GUEST, tx_id, true); g_assert(!err); @@ -480,7 +679,7 @@ static void test_xs_node_tx_rm(void) g_assert(!err); =20 g_string_free(watches, true); - xs_impl_delete(s); + xs_impl_delete(s, true); } =20 static void test_xs_node_tx_resurrect(void) @@ -499,11 +698,16 @@ static void test_xs_node_tx_resurrect(void) g_assert(!err); g_assert(s->nr_nodes =3D=3D 9); =20 + /* Another node to remain shared */ + err =3D write_str(s, DOMID_GUEST, XBT_NULL, "some/place/safe", "keepme= "); + g_assert(!err); + g_assert(s->nr_nodes =3D=3D 11); + /* This node will be wiped and resurrected */ err =3D write_str(s, DOMID_GUEST, XBT_NULL, "some/deep/dark", "foo"); g_assert(!err); - g_assert(s->nr_nodes =3D=3D 9); + g_assert(s->nr_nodes =3D=3D 11); =20 /* Set a watch */ err =3D xs_impl_watch(s, DOMID_GUEST, "some", "watch", @@ -520,19 +724,23 @@ static void test_xs_node_tx_resurrect(void) /* Delete the tree in the transaction */ err =3D xs_impl_rm(s, DOMID_GUEST, tx_id, "some/deep"); g_assert(!err); - g_assert(s->nr_nodes =3D=3D 9); + g_assert(s->nr_nodes =3D=3D 11); g_assert(!watches->len); =20 /* Resurrect part of it */ err =3D write_str(s, DOMID_GUEST, tx_id, "some/deep/dark/different/pat= h", "something"); g_assert(!err); - g_assert(s->nr_nodes =3D=3D 9); + g_assert(s->nr_nodes =3D=3D 11); + + check_serdes(s); =20 /* Commit the transaction */ err =3D xs_impl_transaction_end(s, DOMID_GUEST, tx_id, true); g_assert(!err); - g_assert(s->nr_nodes =3D=3D 9); + g_assert(s->nr_nodes =3D=3D 11); + + check_serdes(s); =20 /* lost data */ g_assert(strstr(watches->str, "some/deep/dark/different/pathwatch")); @@ -549,12 +757,14 @@ static void test_xs_node_tx_resurrect(void) g_assert(err =3D=3D ENOENT); g_byte_array_unref(data); =20 + check_serdes(s); + err =3D xs_impl_unwatch(s, DOMID_GUEST, "some", "watch", watch_cb, watches); g_assert(!err); =20 g_string_free(watches, true); - xs_impl_delete(s); + xs_impl_delete(s, true); } =20 static void test_xs_node_tx_resurrect2(void) @@ -608,11 +818,15 @@ static void test_xs_node_tx_resurrect2(void) g_assert(!err); g_assert(s->nr_nodes =3D=3D 11); =20 + check_serdes(s); + /* Commit the transaction */ err =3D xs_impl_transaction_end(s, DOMID_GUEST, tx_id, true); g_assert(!err); g_assert(s->nr_nodes =3D=3D 11); =20 + check_serdes(s); + /* lost data */ g_assert(strstr(watches->str, "some/deep/dark/relative/pathwatch")); /* lost data */ @@ -629,12 +843,14 @@ static void test_xs_node_tx_resurrect2(void) =20 g_byte_array_unref(data); =20 + check_serdes(s); + err =3D xs_impl_unwatch(s, DOMID_GUEST, "some", "watch", watch_cb, watches); g_assert(!err); =20 g_string_free(watches, true); - xs_impl_delete(s); + xs_impl_delete(s, true); } =20 int main(int argc, char **argv) --=20 2.39.0 From nobody Fri May 3 04:42:41 2024 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 ARC-Seal: i=1; a=rsa-sha256; t=1677771331; cv=none; d=zohomail.com; s=zohoarc; b=hdOYAnfk55m0xpV1frhFWM6SZmTQdCET9kxOVlWu7LHOJfOpWpdyLIA7A7kP+RPTDwZi9lX3qvk56cTUegYQF6kjn04HPRH7DxSSEaGyS0wmb5lU6m7ourkOa0IpKhRzkS1IAZm3wsYN86jX3Pf8b94HZKUOAvmveRSfDtW3ofw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1677771331; 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=CiL9BoVIR8kjLuSX6JDQTr7KEneQW3tf2NeAtIBuItk=; b=j07D++sVx+GtQai6hu+40eDwP3cQkAYg6vHP7csjjoU0I+6no/kfS+nHnZPMxEjmgkBLeMZprPnZ5L3iX1VxLEmG7LyKKG4QOd8sxt0w5FnfkcpxZ+KoVHeBrnHUl6433t2KFMplk5WaJt+/aiGWNkxZy3Rt4dJpvl85LyUcWY4= 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 Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1677771331719475.05999099194275; Thu, 2 Mar 2023 07:35:31 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.505051.777599 (Exim 4.92) (envelope-from ) id 1pXkxL-0001ig-LW; Thu, 02 Mar 2023 15:34:55 +0000 Received: by outflank-mailman (output) from mailman id 505051.777599; Thu, 02 Mar 2023 15:34:55 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxL-0001dE-Ay; Thu, 02 Mar 2023 15:34:55 +0000 Received: by outflank-mailman (input) for mailman id 505051; Thu, 02 Mar 2023 15:34:53 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxJ-0001Jw-Q2 for xen-devel@lists.xenproject.org; Thu, 02 Mar 2023 15:34:53 +0000 Received: from casper.infradead.org (casper.infradead.org [2001:8b0:10b:1236::1]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id c2137f89-b90f-11ed-a550-8520e6686977; Thu, 02 Mar 2023 16:34:49 +0100 (CET) Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by casper.infradead.org with esmtpsa (Exim 4.94.2 #2 (Red Hat Linux)) id 1pXkx4-002UNG-6D; Thu, 02 Mar 2023 15:34:38 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-004uyn-0c; Thu, 02 Mar 2023 15:34:38 +0000 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 X-Inumbo-ID: c2137f89-b90f-11ed-a550-8520e6686977 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=CiL9BoVIR8kjLuSX6JDQTr7KEneQW3tf2NeAtIBuItk=; b=tgdtvoyyO6EkUx17MYdIZ0BC9v +wdjiO/YftXiwsYf+hXfDk6NgeLX1UioTSk+oTsvWRln8Y4UpzIb9ox5+6Il7d2/8PS3tr0lyn4Sb TEUktrIAaojfPt4Ays0rukS2gPFFe9iBizcg7kAVjGGnL4Ylnk15Y5hXWI2eHJvKcatermggwrH6W zNh5SyVCIkKqaWPNt3t+OZbJUMBIreqLpd8NceeKzmK43/vzVha/JU7H96T4HswEBWpdvA7F0F6d9 tKxdaXLhxwgJSOuYj7ZiUlq0NKCxKQtDHHzimMEhUKFC9kZxwTIGlq9QRnU7vfSqxxQGpFjXIvl5j bhw4V3Nw==; From: David Woodhouse To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , Stefano Stabellini , vikram.garhwal@amd.com, Anthony Perard , xen-devel@lists.xenproject.org Subject: [RFC PATCH v1 08/25] hw/xen: Create initial XenStore nodes Date: Thu, 2 Mar 2023 15:34:18 +0000 Message-Id: <20230302153435.1170111-9-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230302153435.1170111-1-dwmw2@infradead.org> References: <20230302153435.1170111-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by casper.infradead.org. See http://www.infradead.org/rpr.html X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1677771333616100019 Content-Type: text/plain; charset="utf-8" From: Paul Durrant Signed-off-by: Paul Durrant Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- hw/i386/kvm/xen_xenstore.c | 70 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/hw/i386/kvm/xen_xenstore.c b/hw/i386/kvm/xen_xenstore.c index 1b1358ad4c..5a8e38aae7 100644 --- a/hw/i386/kvm/xen_xenstore.c +++ b/hw/i386/kvm/xen_xenstore.c @@ -76,9 +76,39 @@ struct XenXenstoreState *xen_xenstore_singleton; static void xen_xenstore_event(void *opaque); static void fire_watch_cb(void *opaque, const char *path, const char *toke= n); =20 +static void G_GNUC_PRINTF (4, 5) relpath_printf(XenXenstoreState *s, + GList *perms, + const char *relpath, + const char *fmt, ...) +{ + gchar *abspath; + gchar *value; + va_list args; + GByteArray *data; + int err; + + abspath =3D g_strdup_printf("/local/domain/%u/%s", xen_domid, relpath); + va_start(args, fmt); + value =3D g_strdup_vprintf(fmt, args); + va_end(args); + + data =3D g_byte_array_new_take((void *)value, strlen(value)); + + err =3D xs_impl_write(s->impl, DOMID_QEMU, XBT_NULL, abspath, data); + assert(!err); + + g_byte_array_unref(data); + + err =3D xs_impl_set_perms(s->impl, DOMID_QEMU, XBT_NULL, abspath, perm= s); + assert(!err); + + g_free(abspath); +} + static void xen_xenstore_realize(DeviceState *dev, Error **errp) { XenXenstoreState *s =3D XEN_XENSTORE(dev); + GList *perms; =20 if (xen_mode !=3D XEN_EMULATE) { error_setg(errp, "Xen xenstore support is for Xen emulation"); @@ -102,6 +132,46 @@ static void xen_xenstore_realize(DeviceState *dev, Err= or **errp) xen_xenstore_event, NULL, NULL, NULL, s); =20 s->impl =3D xs_impl_create(xen_domid); + + /* Populate the default nodes */ + + /* Nodes owned by 'dom0' but readable by the guest */ + perms =3D g_list_append(NULL, xs_perm_as_string(XS_PERM_NONE, DOMID_QE= MU)); + perms =3D g_list_append(perms, xs_perm_as_string(XS_PERM_READ, xen_dom= id)); + + relpath_printf(s, perms, "", "%s", ""); + + relpath_printf(s, perms, "domid", "%u", xen_domid); + + relpath_printf(s, perms, "control/platform-feature-xs_reset_watches", = "%u", 1); + relpath_printf(s, perms, "control/platform-feature-multiprocessor-susp= end", "%u", 1); + + relpath_printf(s, perms, "platform/acpi", "%u", 1); + relpath_printf(s, perms, "platform/acpi_s3", "%u", 1); + relpath_printf(s, perms, "platform/acpi_s4", "%u", 1); + relpath_printf(s, perms, "platform/acpi_laptop_slate", "%u", 0); + + g_list_free_full(perms, g_free); + + /* Nodes owned by the guest */ + perms =3D g_list_append(NULL, xs_perm_as_string(XS_PERM_NONE, xen_domi= d)); + + relpath_printf(s, perms, "attr", "%s", ""); + + relpath_printf(s, perms, "control/shutdown", "%s", ""); + relpath_printf(s, perms, "control/feature-poweroff", "%u", 1); + relpath_printf(s, perms, "control/feature-reboot", "%u", 1); + relpath_printf(s, perms, "control/feature-suspend", "%u", 1); + relpath_printf(s, perms, "control/feature-s3", "%u", 1); + relpath_printf(s, perms, "control/feature-s4", "%u", 1); + + relpath_printf(s, perms, "data", "%s", ""); + relpath_printf(s, perms, "device", "%s", ""); + relpath_printf(s, perms, "drivers", "%s", ""); + relpath_printf(s, perms, "error", "%s", ""); + relpath_printf(s, perms, "feature", "%s", ""); + + g_list_free_full(perms, g_free); } =20 static bool xen_xenstore_is_needed(void *opaque) --=20 2.39.0 From nobody Fri May 3 04:42:41 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 167777132522492.52674984063151; Thu, 2 Mar 2023 07:35:25 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pXkxX-0003tj-7x; Thu, 02 Mar 2023 10:35:07 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pXkxG-0003n3-Uw for qemu-devel@nongnu.org; Thu, 02 Mar 2023 10:34:51 -0500 Received: from casper.infradead.org ([2001:8b0:10b:1236::1]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pXkxB-0001f4-4C for qemu-devel@nongnu.org; Thu, 02 Mar 2023 10:34:50 -0500 Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by casper.infradead.org with esmtpsa (Exim 4.94.2 #2 (Red Hat Linux)) id 1pXkx4-002UNH-7f; Thu, 02 Mar 2023 15:34:38 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-004uyr-0n; Thu, 02 Mar 2023 15:34:38 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc: To:From:Reply-To:Content-ID:Content-Description; bh=CXnndV9W56vuz0SiAw6xRBw1OTFLio1HX3v+4EPY8fI=; b=Dn4/ri5U0VbbtEfqAUnCLW2rRq WrZXITu1AtW99YGWUOzmDJYdQ1eifD3klsft2hL7tavIIfWSMBxZUdA0XODt9Q54AUnSSediWpCWW CtEZyzXh1ZQXPXRIv7ApF8BOIFWjPFu+FsQvNDc0Ug83/P2oMmghvMiC59b206H4bWwmExaN4GsnP 502qkV4Xu8FPHg+U4MB15lB66wy5G7u0J+fDA03+OgXTIeRKn2DPfbQbWUxPh4OTcvbooxK9F29N0 WQJOIKjAuj8kSWZKsyDpw08DROeJtO0D/fldxa0YNd6NjWvgezpLZ0pbli93vzJhLlpVMltKh5oZe 6kHEY/Mg==; From: David Woodhouse To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , Stefano Stabellini , vikram.garhwal@amd.com, Anthony Perard , xen-devel@lists.xenproject.org Subject: [RFC PATCH v1 09/25] hw/xen: Add evtchn operations to allow redirection to internal emulation Date: Thu, 2 Mar 2023 15:34:19 +0000 Message-Id: <20230302153435.1170111-10-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230302153435.1170111-1-dwmw2@infradead.org> References: <20230302153435.1170111-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-SRS-Rewrite: SMTP reverse-path rewritten from by casper.infradead.org. See http://www.infradead.org/rpr.html Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: none client-ip=2001:8b0:10b:1236::1; envelope-from=BATV+a1ad97f05afd282148df+7130+infradead.org+dwmw2@casper.srs.infradead.org; helo=casper.infradead.org X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1677771331694100003 From: David Woodhouse The existing implementation calling into the real libxenevtchn moves to a new file hw/xen/xen-operations.c, and is called via a function table which in a subsequent commit will also be able to invoke the emulated event channel support. Signed-off-by: David Woodhouse Signed-off-by: Paul Durrant Reviewed-by: Paul Durrant --- hw/9pfs/xen-9p-backend.c | 24 +++--- hw/i386/xen/xen-hvm.c | 27 ++++--- hw/xen/meson.build | 1 + hw/xen/xen-bus.c | 22 +++--- hw/xen/xen-legacy-backend.c | 8 +- hw/xen/xen-operations.c | 71 +++++++++++++++++ hw/xen/xen_pvdev.c | 12 +-- include/hw/xen/xen-bus.h | 1 + include/hw/xen/xen-legacy-backend.h | 1 + include/hw/xen/xen_backend_ops.h | 118 ++++++++++++++++++++++++++++ include/hw/xen/xen_common.h | 12 --- include/hw/xen/xen_pvdev.h | 1 + softmmu/globals.c | 1 + 13 files changed, 242 insertions(+), 57 deletions(-) create mode 100644 hw/xen/xen-operations.c create mode 100644 include/hw/xen/xen_backend_ops.h diff --git a/hw/9pfs/xen-9p-backend.c b/hw/9pfs/xen-9p-backend.c index 65c4979c3c..864bdaf952 100644 --- a/hw/9pfs/xen-9p-backend.c +++ b/hw/9pfs/xen-9p-backend.c @@ -241,7 +241,7 @@ static void xen_9pfs_push_and_notify(V9fsPDU *pdu) xen_wmb(); =20 ring->inprogress =3D false; - xenevtchn_notify(ring->evtchndev, ring->local_port); + qemu_xen_evtchn_notify(ring->evtchndev, ring->local_port); =20 qemu_bh_schedule(ring->bh); } @@ -324,8 +324,8 @@ static void xen_9pfs_evtchn_event(void *opaque) Xen9pfsRing *ring =3D opaque; evtchn_port_t port; =20 - port =3D xenevtchn_pending(ring->evtchndev); - xenevtchn_unmask(ring->evtchndev, port); + port =3D qemu_xen_evtchn_pending(ring->evtchndev); + qemu_xen_evtchn_unmask(ring->evtchndev, port); =20 qemu_bh_schedule(ring->bh); } @@ -337,10 +337,10 @@ static void xen_9pfs_disconnect(struct XenLegacyDevic= e *xendev) =20 for (i =3D 0; i < xen_9pdev->num_rings; i++) { if (xen_9pdev->rings[i].evtchndev !=3D NULL) { - qemu_set_fd_handler(xenevtchn_fd(xen_9pdev->rings[i].evtchndev= ), - NULL, NULL, NULL); - xenevtchn_unbind(xen_9pdev->rings[i].evtchndev, - xen_9pdev->rings[i].local_port); + qemu_set_fd_handler(qemu_xen_evtchn_fd(xen_9pdev->rings[i].evt= chndev), + NULL, NULL, NULL); + qemu_xen_evtchn_unbind(xen_9pdev->rings[i].evtchndev, + xen_9pdev->rings[i].local_port); xen_9pdev->rings[i].evtchndev =3D NULL; } } @@ -447,12 +447,12 @@ static int xen_9pfs_connect(struct XenLegacyDevice *x= endev) xen_9pdev->rings[i].inprogress =3D false; =20 =20 - xen_9pdev->rings[i].evtchndev =3D xenevtchn_open(NULL, 0); + xen_9pdev->rings[i].evtchndev =3D qemu_xen_evtchn_open(); if (xen_9pdev->rings[i].evtchndev =3D=3D NULL) { goto out; } - qemu_set_cloexec(xenevtchn_fd(xen_9pdev->rings[i].evtchndev)); - xen_9pdev->rings[i].local_port =3D xenevtchn_bind_interdomain + qemu_set_cloexec(qemu_xen_evtchn_fd(xen_9pdev->rings[i].evtchndev)= ); + xen_9pdev->rings[i].local_port =3D qemu_xen_evtchn_bind_interdomain (xen_9pdev->rings[i].evtchndev, xendev->dom, xen_9pdev->rings[i].evtchn); @@ -463,8 +463,8 @@ static int xen_9pfs_connect(struct XenLegacyDevice *xen= dev) goto out; } xen_pv_printf(xendev, 2, "bind evtchn port %d\n", xendev->local_po= rt); - qemu_set_fd_handler(xenevtchn_fd(xen_9pdev->rings[i].evtchndev), - xen_9pfs_evtchn_event, NULL, &xen_9pdev->rings[i]); + qemu_set_fd_handler(qemu_xen_evtchn_fd(xen_9pdev->rings[i].evtchnd= ev), + xen_9pfs_evtchn_event, NULL, &xen_9pdev->rings= [i]); } =20 xen_9pdev->security_model =3D xenstore_read_be_str(xendev, "security_m= odel"); diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c index e5a1dd19f4..cb1d24f592 100644 --- a/hw/i386/xen/xen-hvm.c +++ b/hw/i386/xen/xen-hvm.c @@ -761,7 +761,7 @@ static ioreq_t *cpu_get_ioreq(XenIOState *state) int i; evtchn_port_t port; =20 - port =3D xenevtchn_pending(state->xce_handle); + port =3D qemu_xen_evtchn_pending(state->xce_handle); if (port =3D=3D state->bufioreq_local_port) { timer_mod(state->buffered_io_timer, BUFFER_IO_MAX_DELAY + qemu_clock_get_ms(QEMU_CLOCK_REALTIM= E)); @@ -780,7 +780,7 @@ static ioreq_t *cpu_get_ioreq(XenIOState *state) } =20 /* unmask the wanted port again */ - xenevtchn_unmask(state->xce_handle, port); + qemu_xen_evtchn_unmask(state->xce_handle, port); =20 /* get the io packet from shared memory */ state->send_vcpu =3D i; @@ -1147,7 +1147,7 @@ static void handle_buffered_io(void *opaque) BUFFER_IO_MAX_DELAY + qemu_clock_get_ms(QEMU_CLOCK_REALTIM= E)); } else { timer_del(state->buffered_io_timer); - xenevtchn_unmask(state->xce_handle, state->bufioreq_local_port); + qemu_xen_evtchn_unmask(state->xce_handle, state->bufioreq_local_po= rt); } } =20 @@ -1196,8 +1196,8 @@ static void cpu_handle_ioreq(void *opaque) } =20 req->state =3D STATE_IORESP_READY; - xenevtchn_notify(state->xce_handle, - state->ioreq_local_port[state->send_vcpu]); + qemu_xen_evtchn_notify(state->xce_handle, + state->ioreq_local_port[state->send_vcpu]); } } =20 @@ -1206,7 +1206,7 @@ static void xen_main_loop_prepare(XenIOState *state) int evtchn_fd =3D -1; =20 if (state->xce_handle !=3D NULL) { - evtchn_fd =3D xenevtchn_fd(state->xce_handle); + evtchn_fd =3D qemu_xen_evtchn_fd(state->xce_handle); } =20 state->buffered_io_timer =3D timer_new_ms(QEMU_CLOCK_REALTIME, handle_= buffered_io, @@ -1249,7 +1249,7 @@ static void xen_exit_notifier(Notifier *n, void *data) xenforeignmemory_unmap_resource(xen_fmem, state->fres); } =20 - xenevtchn_close(state->xce_handle); + qemu_xen_evtchn_close(state->xce_handle); xs_daemon_close(state->xenstore); } =20 @@ -1397,9 +1397,11 @@ void xen_hvm_init_pc(PCMachineState *pcms, MemoryReg= ion **ram_memory) xen_pfn_t ioreq_pfn; XenIOState *state; =20 + setup_xen_backend_ops(); + state =3D g_new0(XenIOState, 1); =20 - state->xce_handle =3D xenevtchn_open(NULL, 0); + state->xce_handle =3D qemu_xen_evtchn_open(); if (state->xce_handle =3D=3D NULL) { perror("xen: event channel open"); goto err; @@ -1463,8 +1465,9 @@ void xen_hvm_init_pc(PCMachineState *pcms, MemoryRegi= on **ram_memory) =20 /* FIXME: how about if we overflow the page here? */ for (i =3D 0; i < max_cpus; i++) { - rc =3D xenevtchn_bind_interdomain(state->xce_handle, xen_domid, - xen_vcpu_eport(state->shared_page,= i)); + rc =3D qemu_xen_evtchn_bind_interdomain(state->xce_handle, xen_dom= id, + xen_vcpu_eport(state->shared= _page, + i)); if (rc =3D=3D -1) { error_report("shared evtchn %d bind error %d", i, errno); goto err; @@ -1472,8 +1475,8 @@ void xen_hvm_init_pc(PCMachineState *pcms, MemoryRegi= on **ram_memory) state->ioreq_local_port[i] =3D rc; } =20 - rc =3D xenevtchn_bind_interdomain(state->xce_handle, xen_domid, - state->bufioreq_remote_port); + rc =3D qemu_xen_evtchn_bind_interdomain(state->xce_handle, xen_domid, + state->bufioreq_remote_port); if (rc =3D=3D -1) { error_report("buffered evtchn bind error %d", errno); goto err; diff --git a/hw/xen/meson.build b/hw/xen/meson.build index ae0ace3046..f195bbd25c 100644 --- a/hw/xen/meson.build +++ b/hw/xen/meson.build @@ -5,6 +5,7 @@ softmmu_ss.add(when: ['CONFIG_XEN', xen], if_true: files( 'xen-legacy-backend.c', 'xen_devconfig.c', 'xen_pvdev.c', + 'xen-operations.c', )) =20 xen_specific_ss =3D ss.source_set() diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c index df3f6b9ae0..d0b1ae93da 100644 --- a/hw/xen/xen-bus.c +++ b/hw/xen/xen-bus.c @@ -1095,12 +1095,12 @@ static bool xen_device_poll(void *opaque) static void xen_device_event(void *opaque) { XenEventChannel *channel =3D opaque; - unsigned long port =3D xenevtchn_pending(channel->xeh); + unsigned long port =3D qemu_xen_evtchn_pending(channel->xeh); =20 if (port =3D=3D channel->local_port) { xen_device_poll(channel); =20 - xenevtchn_unmask(channel->xeh, port); + qemu_xen_evtchn_unmask(channel->xeh, port); } } =20 @@ -1115,11 +1115,11 @@ void xen_device_set_event_channel_context(XenDevice= *xendev, } =20 if (channel->ctx) - aio_set_fd_handler(channel->ctx, xenevtchn_fd(channel->xeh), true, + aio_set_fd_handler(channel->ctx, qemu_xen_evtchn_fd(channel->xeh),= true, NULL, NULL, NULL, NULL, NULL); =20 channel->ctx =3D ctx; - aio_set_fd_handler(channel->ctx, xenevtchn_fd(channel->xeh), true, + aio_set_fd_handler(channel->ctx, qemu_xen_evtchn_fd(channel->xeh), tru= e, xen_device_event, NULL, xen_device_poll, NULL, chan= nel); } =20 @@ -1131,13 +1131,13 @@ XenEventChannel *xen_device_bind_event_channel(XenD= evice *xendev, XenEventChannel *channel =3D g_new0(XenEventChannel, 1); xenevtchn_port_or_error_t local_port; =20 - channel->xeh =3D xenevtchn_open(NULL, 0); + channel->xeh =3D qemu_xen_evtchn_open(); if (!channel->xeh) { error_setg_errno(errp, errno, "failed xenevtchn_open"); goto fail; } =20 - local_port =3D xenevtchn_bind_interdomain(channel->xeh, + local_port =3D qemu_xen_evtchn_bind_interdomain(channel->xeh, xendev->frontend_id, port); if (local_port < 0) { @@ -1160,7 +1160,7 @@ XenEventChannel *xen_device_bind_event_channel(XenDev= ice *xendev, =20 fail: if (channel->xeh) { - xenevtchn_close(channel->xeh); + qemu_xen_evtchn_close(channel->xeh); } =20 g_free(channel); @@ -1177,7 +1177,7 @@ void xen_device_notify_event_channel(XenDevice *xende= v, return; } =20 - if (xenevtchn_notify(channel->xeh, channel->local_port) < 0) { + if (qemu_xen_evtchn_notify(channel->xeh, channel->local_port) < 0) { error_setg_errno(errp, errno, "xenevtchn_notify failed"); } } @@ -1193,14 +1193,14 @@ void xen_device_unbind_event_channel(XenDevice *xen= dev, =20 QLIST_REMOVE(channel, list); =20 - aio_set_fd_handler(channel->ctx, xenevtchn_fd(channel->xeh), true, + aio_set_fd_handler(channel->ctx, qemu_xen_evtchn_fd(channel->xeh), tru= e, NULL, NULL, NULL, NULL, NULL); =20 - if (xenevtchn_unbind(channel->xeh, channel->local_port) < 0) { + if (qemu_xen_evtchn_unbind(channel->xeh, channel->local_port) < 0) { error_setg_errno(errp, errno, "xenevtchn_unbind failed"); } =20 - xenevtchn_close(channel->xeh); + qemu_xen_evtchn_close(channel->xeh); g_free(channel); } =20 diff --git a/hw/xen/xen-legacy-backend.c b/hw/xen/xen-legacy-backend.c index afba71f6eb..9ce3dc204b 100644 --- a/hw/xen/xen-legacy-backend.c +++ b/hw/xen/xen-legacy-backend.c @@ -294,13 +294,13 @@ static struct XenLegacyDevice *xen_be_get_xendev(cons= t char *type, int dom, xendev->debug =3D debug; xendev->local_port =3D -1; =20 - xendev->evtchndev =3D xenevtchn_open(NULL, 0); + xendev->evtchndev =3D qemu_xen_evtchn_open(); if (xendev->evtchndev =3D=3D NULL) { xen_pv_printf(NULL, 0, "can't open evtchn device\n"); qdev_unplug(DEVICE(xendev), NULL); return NULL; } - qemu_set_cloexec(xenevtchn_fd(xendev->evtchndev)); + qemu_set_cloexec(qemu_xen_evtchn_fd(xendev->evtchndev)); =20 xen_pv_insert_xendev(xendev); =20 @@ -751,14 +751,14 @@ int xen_be_bind_evtchn(struct XenLegacyDevice *xendev) if (xendev->local_port !=3D -1) { return 0; } - xendev->local_port =3D xenevtchn_bind_interdomain + xendev->local_port =3D qemu_xen_evtchn_bind_interdomain (xendev->evtchndev, xendev->dom, xendev->remote_port); if (xendev->local_port =3D=3D -1) { xen_pv_printf(xendev, 0, "xenevtchn_bind_interdomain failed\n"); return -1; } xen_pv_printf(xendev, 2, "bind evtchn port %d\n", xendev->local_port); - qemu_set_fd_handler(xenevtchn_fd(xendev->evtchndev), + qemu_set_fd_handler(qemu_xen_evtchn_fd(xendev->evtchndev), xen_pv_evtchn_event, NULL, xendev); return 0; } diff --git a/hw/xen/xen-operations.c b/hw/xen/xen-operations.c new file mode 100644 index 0000000000..1a959d89e8 --- /dev/null +++ b/hw/xen/xen-operations.c @@ -0,0 +1,71 @@ +/* + * QEMU Xen backend support: Operations for true Xen + * + * Copyright =C2=A9 2022 Amazon.com, Inc. or its affiliates. All Rights Re= served. + * + * Authors: David Woodhouse + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" + +#include "hw/xen/xen_backend_ops.h" +#include "hw/xen/xen_common.h" + +/* + * If we have new enough libxenctrl then we do not want/need these compat + * interfaces, despite what the user supplied cflags might say. They + * must be undefined before including xenctrl.h + */ +#undef XC_WANT_COMPAT_EVTCHN_API + +#include + +/* + * We don't support Xen prior to 4.2.0. + */ + +/* Xen 4.2 through 4.6 */ +#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 40701 + +typedef xc_evtchn xenevtchn_handle; +typedef evtchn_port_or_error_t xenevtchn_port_or_error_t; + +#define xenevtchn_open(l, f) xc_evtchn_open(l, f); +#define xenevtchn_close(h) xc_evtchn_close(h) +#define xenevtchn_fd(h) xc_evtchn_fd(h) +#define xenevtchn_pending(h) xc_evtchn_pending(h) +#define xenevtchn_notify(h, p) xc_evtchn_notify(h, p) +#define xenevtchn_bind_interdomain(h, d, p) xc_evtchn_bind_interdomain(h, = d, p) +#define xenevtchn_unmask(h, p) xc_evtchn_unmask(h, p) +#define xenevtchn_unbind(h, p) xc_evtchn_unbind(h, p) + +#else /* CONFIG_XEN_CTRL_INTERFACE_VERSION >=3D 40701 */ + +#include + +#endif + +static xenevtchn_handle *libxenevtchn_backend_open(void) +{ + return xenevtchn_open(NULL, 0); +} + +struct evtchn_backend_ops libxenevtchn_backend_ops =3D { + .open =3D libxenevtchn_backend_open, + .close =3D xenevtchn_close, + .bind_interdomain =3D xenevtchn_bind_interdomain, + .unbind =3D xenevtchn_unbind, + .get_fd =3D xenevtchn_fd, + .notify =3D xenevtchn_notify, + .unmask =3D xenevtchn_unmask, + .pending =3D xenevtchn_pending, +}; + +void setup_xen_backend_ops(void) +{ + xen_evtchn_ops =3D &libxenevtchn_backend_ops; +} diff --git a/hw/xen/xen_pvdev.c b/hw/xen/xen_pvdev.c index 1a5177b354..86a2c8e567 100644 --- a/hw/xen/xen_pvdev.c +++ b/hw/xen/xen_pvdev.c @@ -238,14 +238,14 @@ void xen_pv_evtchn_event(void *opaque) struct XenLegacyDevice *xendev =3D opaque; evtchn_port_t port; =20 - port =3D xenevtchn_pending(xendev->evtchndev); + port =3D qemu_xen_evtchn_pending(xendev->evtchndev); if (port !=3D xendev->local_port) { xen_pv_printf(xendev, 0, "xenevtchn_pending returned %d (expected %d)\n", port, xendev->local_port); return; } - xenevtchn_unmask(xendev->evtchndev, port); + qemu_xen_evtchn_unmask(xendev->evtchndev, port); =20 if (xendev->ops->event) { xendev->ops->event(xendev); @@ -257,15 +257,15 @@ void xen_pv_unbind_evtchn(struct XenLegacyDevice *xen= dev) if (xendev->local_port =3D=3D -1) { return; } - qemu_set_fd_handler(xenevtchn_fd(xendev->evtchndev), NULL, NULL, NULL); - xenevtchn_unbind(xendev->evtchndev, xendev->local_port); + qemu_set_fd_handler(qemu_xen_evtchn_fd(xendev->evtchndev), NULL, NULL,= NULL); + qemu_xen_evtchn_unbind(xendev->evtchndev, xendev->local_port); xen_pv_printf(xendev, 2, "unbind evtchn port %d\n", xendev->local_port= ); xendev->local_port =3D -1; } =20 int xen_pv_send_notify(struct XenLegacyDevice *xendev) { - return xenevtchn_notify(xendev->evtchndev, xendev->local_port); + return qemu_xen_evtchn_notify(xendev->evtchndev, xendev->local_port); } =20 /* ------------------------------------------------------------- */ @@ -306,7 +306,7 @@ void xen_pv_del_xendev(struct XenLegacyDevice *xendev) } =20 if (xendev->evtchndev !=3D NULL) { - xenevtchn_close(xendev->evtchndev); + qemu_xen_evtchn_close(xendev->evtchndev); } if (xendev->gnttabdev !=3D NULL) { xengnttab_close(xendev->gnttabdev); diff --git a/include/hw/xen/xen-bus.h b/include/hw/xen/xen-bus.h index 4d966a2dbb..e21b83796e 100644 --- a/include/hw/xen/xen-bus.h +++ b/include/hw/xen/xen-bus.h @@ -8,6 +8,7 @@ #ifndef HW_XEN_BUS_H #define HW_XEN_BUS_H =20 +#include "hw/xen/xen_backend_ops.h" #include "hw/xen/xen_common.h" #include "hw/sysbus.h" #include "qemu/notify.h" diff --git a/include/hw/xen/xen-legacy-backend.h b/include/hw/xen/xen-legac= y-backend.h index e31cd3a068..06985b1f03 100644 --- a/include/hw/xen/xen-legacy-backend.h +++ b/include/hw/xen/xen-legacy-backend.h @@ -2,6 +2,7 @@ #define HW_XEN_LEGACY_BACKEND_H =20 #include "hw/xen/xen_common.h" +#include "hw/xen/xen_backend_ops.h" #include "hw/xen/xen_pvdev.h" #include "net/net.h" #include "qom/object.h" diff --git a/include/hw/xen/xen_backend_ops.h b/include/hw/xen/xen_backend_= ops.h new file mode 100644 index 0000000000..9605456e81 --- /dev/null +++ b/include/hw/xen/xen_backend_ops.h @@ -0,0 +1,118 @@ +/* + * QEMU Xen backend support + * + * Copyright =C2=A9 2022 Amazon.com, Inc. or its affiliates. All Rights Re= served. + * + * Authors: David Woodhouse + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * See the COPYING file in the top-level directory. + */ + +#ifndef QEMU_XEN_BACKEND_OPS_H +#define QEMU_XEN_BACKEND_OPS_H + +/* + * For the time being, these operations map fairly closely to the API of + * the actual Xen libraries, e.g. libxenevtchn. As we complete the migrati= on + * from XenLegacyDevice back ends to the new XenDevice model, they may + * evolve to slightly higher-level APIs. + * + * The internal emulations do not emulate the Xen APIs entirely faithfully; + * only enough to be used by the Xen backend devices. For example, only one + * event channel can be bound to each handle, since that's sufficient for + * the device support (only the true Xen HVM backend uses more). And the + * behaviour of unmask() and pending() is different too because the device + * backends don't care. + */ + +typedef struct xenevtchn_handle xenevtchn_handle; +typedef int xenevtchn_port_or_error_t; +typedef uint32_t evtchn_port_t; + +struct evtchn_backend_ops { + xenevtchn_handle *(*open)(void); + int (*bind_interdomain)(xenevtchn_handle *xc, uint32_t domid, + evtchn_port_t guest_port); + int (*unbind)(xenevtchn_handle *xc, evtchn_port_t port); + int (*close)(struct xenevtchn_handle *xc); + int (*get_fd)(struct xenevtchn_handle *xc); + int (*notify)(struct xenevtchn_handle *xc, evtchn_port_t port); + int (*unmask)(struct xenevtchn_handle *xc, evtchn_port_t port); + int (*pending)(struct xenevtchn_handle *xc); +}; + +extern struct evtchn_backend_ops *xen_evtchn_ops; + +static inline xenevtchn_handle *qemu_xen_evtchn_open(void) +{ + if (!xen_evtchn_ops) { + return NULL; + } + return xen_evtchn_ops->open(); +} + +static inline int qemu_xen_evtchn_bind_interdomain(xenevtchn_handle *xc, + uint32_t domid, + evtchn_port_t guest_por= t) +{ + if (!xen_evtchn_ops) { + return -ENOSYS; + } + return xen_evtchn_ops->bind_interdomain(xc, domid, guest_port); +} + +static inline int qemu_xen_evtchn_unbind(xenevtchn_handle *xc, + evtchn_port_t port) +{ + if (!xen_evtchn_ops) { + return -ENOSYS; + } + return xen_evtchn_ops->unbind(xc, port); +} + +static inline int qemu_xen_evtchn_close(xenevtchn_handle *xc) +{ + if (!xen_evtchn_ops) { + return -ENOSYS; + } + return xen_evtchn_ops->close(xc); +} + +static inline int qemu_xen_evtchn_fd(xenevtchn_handle *xc) +{ + if (!xen_evtchn_ops) { + return -ENOSYS; + } + return xen_evtchn_ops->get_fd(xc); +} + +static inline int qemu_xen_evtchn_notify(xenevtchn_handle *xc, + evtchn_port_t port) +{ + if (!xen_evtchn_ops) { + return -ENOSYS; + } + return xen_evtchn_ops->notify(xc, port); +} + +static inline int qemu_xen_evtchn_unmask(xenevtchn_handle *xc, + evtchn_port_t port) +{ + if (!xen_evtchn_ops) { + return -ENOSYS; + } + return xen_evtchn_ops->unmask(xc, port); +} + +static inline int qemu_xen_evtchn_pending(xenevtchn_handle *xc) +{ + if (!xen_evtchn_ops) { + return -ENOSYS; + } + return xen_evtchn_ops->pending(xc); +} + +void setup_xen_backend_ops(void); + +#endif /* QEMU_XEN_BACKEND_OPS_H */ diff --git a/include/hw/xen/xen_common.h b/include/hw/xen/xen_common.h index 9a13a756ae..34abd0a772 100644 --- a/include/hw/xen/xen_common.h +++ b/include/hw/xen/xen_common.h @@ -28,18 +28,7 @@ extern xc_interface *xen_xc; #if CONFIG_XEN_CTRL_INTERFACE_VERSION < 40701 =20 typedef xc_interface xenforeignmemory_handle; -typedef xc_evtchn xenevtchn_handle; typedef xc_gnttab xengnttab_handle; -typedef evtchn_port_or_error_t xenevtchn_port_or_error_t; - -#define xenevtchn_open(l, f) xc_evtchn_open(l, f); -#define xenevtchn_close(h) xc_evtchn_close(h) -#define xenevtchn_fd(h) xc_evtchn_fd(h) -#define xenevtchn_pending(h) xc_evtchn_pending(h) -#define xenevtchn_notify(h, p) xc_evtchn_notify(h, p) -#define xenevtchn_bind_interdomain(h, d, p) xc_evtchn_bind_interdomain(h, = d, p) -#define xenevtchn_unmask(h, p) xc_evtchn_unmask(h, p) -#define xenevtchn_unbind(h, p) xc_evtchn_unbind(h, p) =20 #define xengnttab_open(l, f) xc_gnttab_open(l, f) #define xengnttab_close(h) xc_gnttab_close(h) @@ -69,7 +58,6 @@ static inline void *xenforeignmemory_map(xc_interface *h,= uint32_t dom, =20 #else /* CONFIG_XEN_CTRL_INTERFACE_VERSION >=3D 40701 */ =20 -#include #include #include =20 diff --git a/include/hw/xen/xen_pvdev.h b/include/hw/xen/xen_pvdev.h index 7cd4bc2b82..9c27b14764 100644 --- a/include/hw/xen/xen_pvdev.h +++ b/include/hw/xen/xen_pvdev.h @@ -1,6 +1,7 @@ #ifndef QEMU_HW_XEN_PVDEV_H #define QEMU_HW_XEN_PVDEV_H =20 +#include "hw/xen/xen_backend_ops.h" #include "hw/xen/xen_common.h" /* ------------------------------------------------------------- */ =20 diff --git a/softmmu/globals.c b/softmmu/globals.c index 0a4405614e..eb62739be1 100644 --- a/softmmu/globals.c +++ b/softmmu/globals.c @@ -65,3 +65,4 @@ bool qemu_uuid_set; uint32_t xen_domid; enum xen_mode xen_mode =3D XEN_DISABLED; bool xen_domid_restrict; +struct evtchn_backend_ops *xen_evtchn_ops; --=20 2.39.0 From nobody Fri May 3 04:42:41 2024 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 ARC-Seal: i=1; a=rsa-sha256; t=1677771337; cv=none; d=zohomail.com; s=zohoarc; b=R7wtyHbeTBl/87pD61lPDIrBOQNiGGHwwzTsO8IqLLPPPCMGSuqJH3yVPxIaYLNC5mnoHaRkNxlTVQGoYxwvfAFA/VGV/o9FP7b3mCldZK+X4bBhHKqtchCIMuYv13NkPWTl0sGSr1ef8ehE9fqEawA0fn/zuphyjVkw4km/s9M= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1677771337; 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=9ZgYwkDmHdUTNn7NpOvT11cK4T0wTI/32/sDSKDPebo=; b=J1ILrMz6xk7kGsyzmdJ727ETYEnwLFTReU53GrFUGSUt0SV+qxOpMnwzP4QyuSzSAVFM/syZGfYqHpIu5fdzGW1jItjMWftXtuoGkbegw409IyODSLjLEoo6OVtSIODw/qydXKkLXBUsAAPsTF9IObQAbXbKOOOiXxditCrUH24= 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 Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1677771337328549.9956429919487; Thu, 2 Mar 2023 07:35:37 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.505062.777703 (Exim 4.92) (envelope-from ) id 1pXkxX-0004gF-Jz; Thu, 02 Mar 2023 15:35:07 +0000 Received: by outflank-mailman (output) from mailman id 505062.777703; Thu, 02 Mar 2023 15:35:07 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxW-0004Zd-K4; Thu, 02 Mar 2023 15:35:06 +0000 Received: by outflank-mailman (input) for mailman id 505062; Thu, 02 Mar 2023 15:34:59 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxP-0001Jv-5x for xen-devel@lists.xenproject.org; Thu, 02 Mar 2023 15:34:59 +0000 Received: from desiato.infradead.org (desiato.infradead.org [2001:8b0:10b:1:d65d:64ff:fe57:4e05]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id c2ce6d02-b90f-11ed-96ad-2f268f93b82a; Thu, 02 Mar 2023 16:34:49 +0100 (CET) Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by desiato.infradead.org with esmtpsa (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-00FL3h-1J; Thu, 02 Mar 2023 15:34:39 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-004uyv-0y; Thu, 02 Mar 2023 15:34:38 +0000 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 X-Inumbo-ID: c2ce6d02-b90f-11ed-96ad-2f268f93b82a DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=9ZgYwkDmHdUTNn7NpOvT11cK4T0wTI/32/sDSKDPebo=; b=e+PfC71rTBVEii8yyVkbh/t56H +829LbM5c3AOktaXOdD1q5NguavsYOlIjTr6rqGbsoxAJIt97tD+7ZtVYEMlyNFprMB1Ae5DHOdK6 1LdO7mgC1+qhnFjUVqDV/uwfebOXub1iavhFK+C6O/rSfypZM9WabK+tYkDkVgU3X7wBC/ZYIIXar AGvUUziKVsGWV9bfdC15Nk30WTJGzE/nGxZh601/E3eRz8xiRJ7XLeuw/3qAehEmR8ltOtcvSZleo vmPHP3Gn6cKDi0vaziNrMFBJD2fTKYjMBAFJ6nR0h42esHxxpk9YsAb3Z674NfeljO+ZmWaVMGNli RGdrseoQ==; From: David Woodhouse To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , Stefano Stabellini , vikram.garhwal@amd.com, Anthony Perard , xen-devel@lists.xenproject.org Subject: [RFC PATCH v1 10/25] hw/xen: Add gnttab operations to allow redirection to internal emulation Date: Thu, 2 Mar 2023 15:34:20 +0000 Message-Id: <20230302153435.1170111-11-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230302153435.1170111-1-dwmw2@infradead.org> References: <20230302153435.1170111-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by desiato.infradead.org. See http://www.infradead.org/rpr.html X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1677771339768100001 Content-Type: text/plain; charset="utf-8" From: David Woodhouse Move the existing code using libxengnttab to xen-operations.c and allow the operations to be redirected so that we can add emulation of grant table mapping for backend drivers. In emulation, mapping more than one grant ref to be virtually contiguous would be fairly difficult. The best way to do it might be to make the ram_block mappings actually backed by a file (shmem or a deleted file, perhaps) so that we can have multiple *shared* mappings of it. But that would be fairly intrusive. Making the backend drivers cope with page *lists* instead of expecting the mapping to be contiguous is also non-trivial, since some structures would actually *cross* page boundaries (e.g. the 32-bit blkif responses which are 12 bytes). So for now, we'll support only single-page mappings in emulation. Add a XEN_GNTTAB_OP_FEATURE_MAP_MULTIPLE flag to indicate that the native Xen implementation *does* support multi-page maps, and a helper function to query it. Signed-off-by: David Woodhouse Signed-off-by: Paul Durrant Reviewed-by: Paul Durrant --- hw/xen/xen-bus.c | 112 ++------------------ hw/xen/xen-legacy-backend.c | 125 ++-------------------- hw/xen/xen-operations.c | 157 ++++++++++++++++++++++++++++ hw/xen/xen_pvdev.c | 2 +- include/hw/xen/xen-bus.h | 3 +- include/hw/xen/xen-legacy-backend.h | 13 +-- include/hw/xen/xen_backend_ops.h | 100 ++++++++++++++++++ include/hw/xen/xen_common.h | 39 ------- softmmu/globals.c | 1 + 9 files changed, 280 insertions(+), 272 deletions(-) diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c index d0b1ae93da..b247e86f28 100644 --- a/hw/xen/xen-bus.c +++ b/hw/xen/xen-bus.c @@ -947,7 +947,7 @@ static void xen_device_frontend_destroy(XenDevice *xend= ev) void xen_device_set_max_grant_refs(XenDevice *xendev, unsigned int nr_refs, Error **errp) { - if (xengnttab_set_max_grants(xendev->xgth, nr_refs)) { + if (qemu_xen_gnttab_set_max_grants(xendev->xgth, nr_refs)) { error_setg_errno(errp, errno, "xengnttab_set_max_grants failed"); } } @@ -956,9 +956,8 @@ void *xen_device_map_grant_refs(XenDevice *xendev, uint= 32_t *refs, unsigned int nr_refs, int prot, Error **errp) { - void *map =3D xengnttab_map_domain_grant_refs(xendev->xgth, nr_refs, - xendev->frontend_id, refs, - prot); + void *map =3D qemu_xen_gnttab_map_refs(xendev->xgth, nr_refs, + xendev->frontend_id, refs, prot); =20 if (!map) { error_setg_errno(errp, errno, @@ -971,109 +970,17 @@ void *xen_device_map_grant_refs(XenDevice *xendev, u= int32_t *refs, void xen_device_unmap_grant_refs(XenDevice *xendev, void *map, unsigned int nr_refs, Error **errp) { - if (xengnttab_unmap(xendev->xgth, map, nr_refs)) { + if (qemu_xen_gnttab_unmap(xendev->xgth, map, nr_refs)) { error_setg_errno(errp, errno, "xengnttab_unmap failed"); } } =20 -static void compat_copy_grant_refs(XenDevice *xendev, bool to_domain, - XenDeviceGrantCopySegment segs[], - unsigned int nr_segs, Error **errp) -{ - uint32_t *refs =3D g_new(uint32_t, nr_segs); - int prot =3D to_domain ? PROT_WRITE : PROT_READ; - void *map; - unsigned int i; - - for (i =3D 0; i < nr_segs; i++) { - XenDeviceGrantCopySegment *seg =3D &segs[i]; - - refs[i] =3D to_domain ? seg->dest.foreign.ref : - seg->source.foreign.ref; - } - - map =3D xengnttab_map_domain_grant_refs(xendev->xgth, nr_segs, - xendev->frontend_id, refs, - prot); - if (!map) { - error_setg_errno(errp, errno, - "xengnttab_map_domain_grant_refs failed"); - goto done; - } - - for (i =3D 0; i < nr_segs; i++) { - XenDeviceGrantCopySegment *seg =3D &segs[i]; - void *page =3D map + (i * XC_PAGE_SIZE); - - if (to_domain) { - memcpy(page + seg->dest.foreign.offset, seg->source.virt, - seg->len); - } else { - memcpy(seg->dest.virt, page + seg->source.foreign.offset, - seg->len); - } - } - - if (xengnttab_unmap(xendev->xgth, map, nr_segs)) { - error_setg_errno(errp, errno, "xengnttab_unmap failed"); - } - -done: - g_free(refs); -} - void xen_device_copy_grant_refs(XenDevice *xendev, bool to_domain, XenDeviceGrantCopySegment segs[], unsigned int nr_segs, Error **errp) { - xengnttab_grant_copy_segment_t *xengnttab_segs; - unsigned int i; - - if (!xendev->feature_grant_copy) { - compat_copy_grant_refs(xendev, to_domain, segs, nr_segs, errp); - return; - } - - xengnttab_segs =3D g_new0(xengnttab_grant_copy_segment_t, nr_segs); - - for (i =3D 0; i < nr_segs; i++) { - XenDeviceGrantCopySegment *seg =3D &segs[i]; - xengnttab_grant_copy_segment_t *xengnttab_seg =3D &xengnttab_segs[= i]; - - if (to_domain) { - xengnttab_seg->flags =3D GNTCOPY_dest_gref; - xengnttab_seg->dest.foreign.domid =3D xendev->frontend_id; - xengnttab_seg->dest.foreign.ref =3D seg->dest.foreign.ref; - xengnttab_seg->dest.foreign.offset =3D seg->dest.foreign.offse= t; - xengnttab_seg->source.virt =3D seg->source.virt; - } else { - xengnttab_seg->flags =3D GNTCOPY_source_gref; - xengnttab_seg->source.foreign.domid =3D xendev->frontend_id; - xengnttab_seg->source.foreign.ref =3D seg->source.foreign.ref; - xengnttab_seg->source.foreign.offset =3D - seg->source.foreign.offset; - xengnttab_seg->dest.virt =3D seg->dest.virt; - } - - xengnttab_seg->len =3D seg->len; - } - - if (xengnttab_grant_copy(xendev->xgth, nr_segs, xengnttab_segs)) { - error_setg_errno(errp, errno, "xengnttab_grant_copy failed"); - goto done; - } - - for (i =3D 0; i < nr_segs; i++) { - xengnttab_grant_copy_segment_t *xengnttab_seg =3D &xengnttab_segs[= i]; - - if (xengnttab_seg->status !=3D GNTST_okay) { - error_setg(errp, "xengnttab_grant_copy seg[%u] failed", i); - break; - } - } - -done: - g_free(xengnttab_segs); + qemu_xen_gnttab_grant_copy(xendev->xgth, to_domain, xendev->frontend_i= d, + (XenGrantCopySegment *)segs, nr_segs, errp); } =20 struct XenEventChannel { @@ -1235,7 +1142,7 @@ static void xen_device_unrealize(DeviceState *dev) xen_device_backend_destroy(xendev); =20 if (xendev->xgth) { - xengnttab_close(xendev->xgth); + qemu_xen_gnttab_close(xendev->xgth); xendev->xgth =3D NULL; } =20 @@ -1298,15 +1205,12 @@ static void xen_device_realize(DeviceState *dev, Er= ror **errp) =20 xendev->watch_list =3D watch_list_create(xendev->xsh); =20 - xendev->xgth =3D xengnttab_open(NULL, 0); + xendev->xgth =3D qemu_xen_gnttab_open(); if (!xendev->xgth) { error_setg_errno(errp, errno, "failed xengnttab_open"); goto unrealize; } =20 - xendev->feature_grant_copy =3D - (xengnttab_grant_copy(xendev->xgth, 0, NULL) =3D=3D 0); - xen_device_backend_create(xendev, errp); if (*errp) { goto unrealize; diff --git a/hw/xen/xen-legacy-backend.c b/hw/xen/xen-legacy-backend.c index 9ce3dc204b..1e9a28f263 100644 --- a/hw/xen/xen-legacy-backend.c +++ b/hw/xen/xen-legacy-backend.c @@ -43,7 +43,6 @@ struct xs_handle *xenstore; const char *xen_protocol; =20 /* private */ -static bool xen_feature_grant_copy; static int debug; =20 int xenstore_write_be_str(struct XenLegacyDevice *xendev, const char *node, @@ -113,7 +112,7 @@ void xen_be_set_max_grant_refs(struct XenLegacyDevice *= xendev, { assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV); =20 - if (xengnttab_set_max_grants(xendev->gnttabdev, nr_refs)) { + if (qemu_xen_gnttab_set_max_grants(xendev->gnttabdev, nr_refs)) { xen_pv_printf(xendev, 0, "xengnttab_set_max_grants failed: %s\n", strerror(errno)); } @@ -126,8 +125,8 @@ void *xen_be_map_grant_refs(struct XenLegacyDevice *xen= dev, uint32_t *refs, =20 assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV); =20 - ptr =3D xengnttab_map_domain_grant_refs(xendev->gnttabdev, nr_refs, - xen_domid, refs, prot); + ptr =3D qemu_xen_gnttab_map_refs(xendev->gnttabdev, nr_refs, xen_domid= , refs, + prot); if (!ptr) { xen_pv_printf(xendev, 0, "xengnttab_map_domain_grant_refs failed: %s\n", @@ -142,119 +141,27 @@ void xen_be_unmap_grant_refs(struct XenLegacyDevice = *xendev, void *ptr, { assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV); =20 - if (xengnttab_unmap(xendev->gnttabdev, ptr, nr_refs)) { + if (qemu_xen_gnttab_unmap(xendev->gnttabdev, ptr, nr_refs)) { xen_pv_printf(xendev, 0, "xengnttab_unmap failed: %s\n", strerror(errno)); } } =20 -static int compat_copy_grant_refs(struct XenLegacyDevice *xendev, - bool to_domain, - XenGrantCopySegment segs[], - unsigned int nr_segs) -{ - uint32_t *refs =3D g_new(uint32_t, nr_segs); - int prot =3D to_domain ? PROT_WRITE : PROT_READ; - void *pages; - unsigned int i; - - for (i =3D 0; i < nr_segs; i++) { - XenGrantCopySegment *seg =3D &segs[i]; - - refs[i] =3D to_domain ? - seg->dest.foreign.ref : seg->source.foreign.ref; - } - - pages =3D xengnttab_map_domain_grant_refs(xendev->gnttabdev, nr_segs, - xen_domid, refs, prot); - if (!pages) { - xen_pv_printf(xendev, 0, - "xengnttab_map_domain_grant_refs failed: %s\n", - strerror(errno)); - g_free(refs); - return -1; - } - - for (i =3D 0; i < nr_segs; i++) { - XenGrantCopySegment *seg =3D &segs[i]; - void *page =3D pages + (i * XC_PAGE_SIZE); - - if (to_domain) { - memcpy(page + seg->dest.foreign.offset, seg->source.virt, - seg->len); - } else { - memcpy(seg->dest.virt, page + seg->source.foreign.offset, - seg->len); - } - } - - if (xengnttab_unmap(xendev->gnttabdev, pages, nr_segs)) { - xen_pv_printf(xendev, 0, "xengnttab_unmap failed: %s\n", - strerror(errno)); - } - - g_free(refs); - return 0; -} - int xen_be_copy_grant_refs(struct XenLegacyDevice *xendev, bool to_domain, XenGrantCopySegment segs[], unsigned int nr_segs) { - xengnttab_grant_copy_segment_t *xengnttab_segs; - unsigned int i; int rc; =20 assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV); =20 - if (!xen_feature_grant_copy) { - return compat_copy_grant_refs(xendev, to_domain, segs, nr_segs); - } - - xengnttab_segs =3D g_new0(xengnttab_grant_copy_segment_t, nr_segs); - - for (i =3D 0; i < nr_segs; i++) { - XenGrantCopySegment *seg =3D &segs[i]; - xengnttab_grant_copy_segment_t *xengnttab_seg =3D &xengnttab_segs[= i]; - - if (to_domain) { - xengnttab_seg->flags =3D GNTCOPY_dest_gref; - xengnttab_seg->dest.foreign.domid =3D xen_domid; - xengnttab_seg->dest.foreign.ref =3D seg->dest.foreign.ref; - xengnttab_seg->dest.foreign.offset =3D seg->dest.foreign.offse= t; - xengnttab_seg->source.virt =3D seg->source.virt; - } else { - xengnttab_seg->flags =3D GNTCOPY_source_gref; - xengnttab_seg->source.foreign.domid =3D xen_domid; - xengnttab_seg->source.foreign.ref =3D seg->source.foreign.ref; - xengnttab_seg->source.foreign.offset =3D - seg->source.foreign.offset; - xengnttab_seg->dest.virt =3D seg->dest.virt; - } - - xengnttab_seg->len =3D seg->len; - } - - rc =3D xengnttab_grant_copy(xendev->gnttabdev, nr_segs, xengnttab_segs= ); - + rc =3D qemu_xen_gnttab_grant_copy(xendev->gnttabdev, to_domain, xen_do= mid, + segs, nr_segs, NULL); if (rc) { - xen_pv_printf(xendev, 0, "xengnttab_copy failed: %s\n", - strerror(errno)); - } - - for (i =3D 0; i < nr_segs; i++) { - xengnttab_grant_copy_segment_t *xengnttab_seg =3D - &xengnttab_segs[i]; - - if (xengnttab_seg->status !=3D GNTST_okay) { - xen_pv_printf(xendev, 0, "segment[%u] status: %d\n", i, - xengnttab_seg->status); - rc =3D -1; - } + xen_pv_printf(xendev, 0, "xengnttab_grant_copy failed: %s\n", + strerror(-rc)); } - - g_free(xengnttab_segs); return rc; } =20 @@ -466,7 +373,7 @@ static int xen_be_try_initialise(struct XenLegacyDevice= *xendev) } =20 if (xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV) { - xendev->gnttabdev =3D xengnttab_open(NULL, 0); + xendev->gnttabdev =3D qemu_xen_gnttab_open(); if (xendev->gnttabdev =3D=3D NULL) { xen_pv_printf(NULL, 0, "can't open gnttab device\n"); return -1; @@ -524,7 +431,7 @@ static void xen_be_disconnect(struct XenLegacyDevice *x= endev, xendev->ops->disconnect(xendev); } if (xendev->gnttabdev) { - xengnttab_close(xendev->gnttabdev); + qemu_xen_gnttab_close(xendev->gnttabdev); xendev->gnttabdev =3D NULL; } if (xendev->be_state !=3D state) { @@ -687,8 +594,6 @@ static void xen_set_dynamic_sysbus(void) =20 void xen_be_init(void) { - xengnttab_handle *gnttabdev; - xenstore =3D xs_daemon_open(); if (!xenstore) { xen_pv_printf(NULL, 0, "can't connect to xenstored\n"); @@ -697,19 +602,11 @@ void xen_be_init(void) =20 qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL); =20 - if (xen_xc =3D=3D NULL || xen_fmem =3D=3D NULL) { + if (xen_evtchn_ops =3D=3D NULL || xen_gnttab_ops =3D=3D NULL) { xen_pv_printf(NULL, 0, "Xen operations not set up\n"); exit(1); } =20 - gnttabdev =3D xengnttab_open(NULL, 0); - if (gnttabdev !=3D NULL) { - if (xengnttab_grant_copy(gnttabdev, 0, NULL) =3D=3D 0) { - xen_feature_grant_copy =3D true; - } - xengnttab_close(gnttabdev); - } - xen_sysdev =3D qdev_new(TYPE_XENSYSDEV); sysbus_realize_and_unref(SYS_BUS_DEVICE(xen_sysdev), &error_fatal); xen_sysbus =3D qbus_new(TYPE_XENSYSBUS, xen_sysdev, "xen-sysbus"); diff --git a/hw/xen/xen-operations.c b/hw/xen/xen-operations.c index 1a959d89e8..eb5fb0a59f 100644 --- a/hw/xen/xen-operations.c +++ b/hw/xen/xen-operations.c @@ -21,6 +21,7 @@ * must be undefined before including xenctrl.h */ #undef XC_WANT_COMPAT_EVTCHN_API +#undef XC_WANT_COMPAT_GNTTAB_API =20 #include =20 @@ -43,12 +44,141 @@ typedef evtchn_port_or_error_t xenevtchn_port_or_error= _t; #define xenevtchn_unmask(h, p) xc_evtchn_unmask(h, p) #define xenevtchn_unbind(h, p) xc_evtchn_unbind(h, p) =20 +typedef xc_gnttab xengnttab_handle; + +#define xengnttab_open(l, f) xc_gnttab_open(l, f) +#define xengnttab_close(h) xc_gnttab_close(h) +#define xengnttab_set_max_grants(h, n) xc_gnttab_set_max_grants(h, n) +#define xengnttab_map_grant_ref(h, d, r, p) xc_gnttab_map_grant_ref(h, d, = r, p) +#define xengnttab_unmap(h, a, n) xc_gnttab_munmap(h, a, n) +#define xengnttab_map_grant_refs(h, c, d, r, p) \ + xc_gnttab_map_grant_refs(h, c, d, r, p) +#define xengnttab_map_domain_grant_refs(h, c, d, r, p) \ + xc_gnttab_map_domain_grant_refs(h, c, d, r, p) + #else /* CONFIG_XEN_CTRL_INTERFACE_VERSION >=3D 40701 */ =20 #include +#include =20 #endif =20 +/* Xen before 4.8 */ + +static int libxengnttab_fallback_grant_copy(xengnttab_handle *xgt, + bool to_domain, uint32_t domid, + XenGrantCopySegment segs[], + unsigned int nr_segs, Error **= errp) +{ + uint32_t *refs =3D g_new(uint32_t, nr_segs); + int prot =3D to_domain ? PROT_WRITE : PROT_READ; + void *map; + unsigned int i; + int rc =3D 0; + + for (i =3D 0; i < nr_segs; i++) { + XenGrantCopySegment *seg =3D &segs[i]; + + refs[i] =3D to_domain ? seg->dest.foreign.ref : + seg->source.foreign.ref; + } + map =3D xengnttab_map_domain_grant_refs(xgt, nr_segs, domid, refs, pro= t); + if (!map) { + if (errp) { + error_setg_errno(errp, errno, + "xengnttab_map_domain_grant_refs failed"); + } + rc =3D -errno; + goto done; + } + + for (i =3D 0; i < nr_segs; i++) { + XenGrantCopySegment *seg =3D &segs[i]; + void *page =3D map + (i * XEN_PAGE_SIZE); + + if (to_domain) { + memcpy(page + seg->dest.foreign.offset, seg->source.virt, + seg->len); + } else { + memcpy(seg->dest.virt, page + seg->source.foreign.offset, + seg->len); + } + } + + if (xengnttab_unmap(xgt, map, nr_segs)) { + if (errp) { + error_setg_errno(errp, errno, "xengnttab_unmap failed"); + } + rc =3D -errno; + } + +done: + g_free(refs); + return rc; +} + +#if CONFIG_XEN_CTRL_INTERFACE_VERSION >=3D 40800 + +static int libxengnttab_backend_grant_copy(xengnttab_handle *xgt, + bool to_domain, uint32_t domid, + XenGrantCopySegment *segs, + uint32_t nr_segs, Error **errp) +{ + xengnttab_grant_copy_segment_t *xengnttab_segs; + unsigned int i; + int rc; + + xengnttab_segs =3D g_new0(xengnttab_grant_copy_segment_t, nr_segs); + + for (i =3D 0; i < nr_segs; i++) { + XenGrantCopySegment *seg =3D &segs[i]; + xengnttab_grant_copy_segment_t *xengnttab_seg =3D &xengnttab_segs[= i]; + + if (to_domain) { + xengnttab_seg->flags =3D GNTCOPY_dest_gref; + xengnttab_seg->dest.foreign.domid =3D domid; + xengnttab_seg->dest.foreign.ref =3D seg->dest.foreign.ref; + xengnttab_seg->dest.foreign.offset =3D seg->dest.foreign.offse= t; + xengnttab_seg->source.virt =3D seg->source.virt; + } else { + xengnttab_seg->flags =3D GNTCOPY_source_gref; + xengnttab_seg->source.foreign.domid =3D domid; + xengnttab_seg->source.foreign.ref =3D seg->source.foreign.ref; + xengnttab_seg->source.foreign.offset =3D + seg->source.foreign.offset; + xengnttab_seg->dest.virt =3D seg->dest.virt; + } + + xengnttab_seg->len =3D seg->len; + } + + if (xengnttab_grant_copy(xgt, nr_segs, xengnttab_segs)) { + if (errp) { + error_setg_errno(errp, errno, "xengnttab_grant_copy failed"); + } + rc =3D -errno; + goto done; + } + + rc =3D 0; + for (i =3D 0; i < nr_segs; i++) { + xengnttab_grant_copy_segment_t *xengnttab_seg =3D &xengnttab_segs[= i]; + + if (xengnttab_seg->status !=3D GNTST_okay) { + if (errp) { + error_setg(errp, "xengnttab_grant_copy seg[%u] failed", i); + } + rc =3D -EIO; + break; + } + } + +done: + g_free(xengnttab_segs); + return rc; +} +#endif + static xenevtchn_handle *libxenevtchn_backend_open(void) { return xenevtchn_open(NULL, 0); @@ -65,7 +195,34 @@ struct evtchn_backend_ops libxenevtchn_backend_ops =3D { .pending =3D xenevtchn_pending, }; =20 +static xengnttab_handle *libxengnttab_backend_open(void) +{ + return xengnttab_open(NULL, 0); +} + + +static struct gnttab_backend_ops libxengnttab_backend_ops =3D { + .features =3D XEN_GNTTAB_OP_FEATURE_MAP_MULTIPLE, + .open =3D libxengnttab_backend_open, + .close =3D xengnttab_close, + .grant_copy =3D libxengnttab_fallback_grant_copy, + .set_max_grants =3D xengnttab_set_max_grants, + .map_refs =3D xengnttab_map_domain_grant_refs, + .unmap =3D xengnttab_unmap, +}; + void setup_xen_backend_ops(void) { +#if CONFIG_XEN_CTRL_INTERFACE_VERSION >=3D 40800 + xengnttab_handle *xgt =3D xengnttab_open(NULL, 0); + + if (xgt) { + if (xengnttab_grant_copy(xgt, 0, NULL) =3D=3D 0) { + xen_gnttab_ops->grant_copy =3D libxengnttab_backend_grant_copy; + } + xengnttab_close(xgt); + } +#endif xen_evtchn_ops =3D &libxenevtchn_backend_ops; + xen_gnttab_ops =3D &libxengnttab_backend_ops; } diff --git a/hw/xen/xen_pvdev.c b/hw/xen/xen_pvdev.c index 86a2c8e567..d8582cc74c 100644 --- a/hw/xen/xen_pvdev.c +++ b/hw/xen/xen_pvdev.c @@ -309,7 +309,7 @@ void xen_pv_del_xendev(struct XenLegacyDevice *xendev) qemu_xen_evtchn_close(xendev->evtchndev); } if (xendev->gnttabdev !=3D NULL) { - xengnttab_close(xendev->gnttabdev); + qemu_xen_gnttab_close(xendev->gnttabdev); } =20 QTAILQ_REMOVE(&xendevs, xendev, next); diff --git a/include/hw/xen/xen-bus.h b/include/hw/xen/xen-bus.h index e21b83796e..72d71d1eb7 100644 --- a/include/hw/xen/xen-bus.h +++ b/include/hw/xen/xen-bus.h @@ -9,7 +9,7 @@ #define HW_XEN_BUS_H =20 #include "hw/xen/xen_backend_ops.h" -#include "hw/xen/xen_common.h" +#include "hw/xen/interface/io/xenbus.h" #include "hw/sysbus.h" #include "qemu/notify.h" #include "qom/object.h" @@ -33,7 +33,6 @@ struct XenDevice { bool backend_online; XenWatch *backend_online_watch; xengnttab_handle *xgth; - bool feature_grant_copy; bool inactive; QLIST_HEAD(, XenEventChannel) event_channels; QLIST_ENTRY(XenDevice) list; diff --git a/include/hw/xen/xen-legacy-backend.h b/include/hw/xen/xen-legac= y-backend.h index 06985b1f03..eaf79cd221 100644 --- a/include/hw/xen/xen-legacy-backend.h +++ b/include/hw/xen/xen-legacy-backend.h @@ -1,8 +1,8 @@ #ifndef HW_XEN_LEGACY_BACKEND_H #define HW_XEN_LEGACY_BACKEND_H =20 -#include "hw/xen/xen_common.h" #include "hw/xen/xen_backend_ops.h" +#include "hw/xen/interface/io/xenbus.h" #include "hw/xen/xen_pvdev.h" #include "net/net.h" #include "qom/object.h" @@ -54,17 +54,6 @@ void *xen_be_map_grant_refs(struct XenLegacyDevice *xend= ev, uint32_t *refs, void xen_be_unmap_grant_refs(struct XenLegacyDevice *xendev, void *ptr, unsigned int nr_refs); =20 -typedef struct XenGrantCopySegment { - union { - void *virt; - struct { - uint32_t ref; - off_t offset; - } foreign; - } source, dest; - size_t len; -} XenGrantCopySegment; - int xen_be_copy_grant_refs(struct XenLegacyDevice *xendev, bool to_domain, XenGrantCopySegment segs[], unsigned int nr_segs); diff --git a/include/hw/xen/xen_backend_ops.h b/include/hw/xen/xen_backend_= ops.h index 9605456e81..bb3333ab00 100644 --- a/include/hw/xen/xen_backend_ops.h +++ b/include/hw/xen/xen_backend_ops.h @@ -29,6 +29,12 @@ typedef struct xenevtchn_handle xenevtchn_handle; typedef int xenevtchn_port_or_error_t; typedef uint32_t evtchn_port_t; +typedef uint16_t domid_t; +typedef uint32_t grant_ref_t; + +#define XEN_PAGE_SHIFT 12 +#define XEN_PAGE_SIZE (1UL << XEN_PAGE_SHIFT) +#define XEN_PAGE_MASK (~(XEN_PAGE_SIZE - 1)) =20 struct evtchn_backend_ops { xenevtchn_handle *(*open)(void); @@ -113,6 +119,100 @@ static inline int qemu_xen_evtchn_pending(xenevtchn_h= andle *xc) return xen_evtchn_ops->pending(xc); } =20 +typedef struct xengntdev_handle xengnttab_handle; + +typedef struct XenGrantCopySegment { + union { + void *virt; + struct { + uint32_t ref; + off_t offset; + } foreign; + } source, dest; + size_t len; +} XenGrantCopySegment; + +#define XEN_GNTTAB_OP_FEATURE_MAP_MULTIPLE (1U << 0) + +struct gnttab_backend_ops { + uint32_t features; + xengnttab_handle *(*open)(void); + int (*close)(xengnttab_handle *xgt); + int (*grant_copy)(xengnttab_handle *xgt, bool to_domain, uint32_t domi= d, + XenGrantCopySegment *segs, uint32_t nr_segs, + Error **errp); + int (*set_max_grants)(xengnttab_handle *xgt, uint32_t nr_grants); + void *(*map_refs)(xengnttab_handle *xgt, uint32_t count, uint32_t domi= d, + uint32_t *refs, int prot); + int (*unmap)(xengnttab_handle *xgt, void *start_address, uint32_t coun= t); +}; + +extern struct gnttab_backend_ops *xen_gnttab_ops; + +static inline bool qemu_xen_gnttab_can_map_multi(void) +{ + return xen_gnttab_ops && + !!(xen_gnttab_ops->features & XEN_GNTTAB_OP_FEATURE_MAP_MULTIPLE); +} + +static inline xengnttab_handle *qemu_xen_gnttab_open(void) +{ + if (!xen_gnttab_ops) { + return NULL; + } + return xen_gnttab_ops->open(); +} + +static inline int qemu_xen_gnttab_close(xengnttab_handle *xgt) +{ + if (!xen_gnttab_ops) { + return -ENOSYS; + } + return xen_gnttab_ops->close(xgt); +} + +static inline int qemu_xen_gnttab_grant_copy(xengnttab_handle *xgt, + bool to_domain, uint32_t domi= d, + XenGrantCopySegment *segs, + uint32_t nr_segs, Error **err= p) +{ + if (!xen_gnttab_ops) { + return -ENOSYS; + } + + return xen_gnttab_ops->grant_copy(xgt, to_domain, domid, segs, nr_segs, + errp); +} + +static inline int qemu_xen_gnttab_set_max_grants(xengnttab_handle *xgt, + uint32_t nr_grants) +{ + if (!xen_gnttab_ops) { + return -ENOSYS; + } + return xen_gnttab_ops->set_max_grants(xgt, nr_grants); +} + +static inline void *qemu_xen_gnttab_map_refs(xengnttab_handle *xgt, + uint32_t count, uint32_t domi= d, + uint32_t *refs, int prot) +{ + if (!xen_gnttab_ops) { + return NULL; + } + return xen_gnttab_ops->map_refs(xgt, count, domid, refs, prot); +} + +static inline int qemu_xen_gnttab_unmap(xengnttab_handle *xgt, + void *start_address, + uint32_t count) +{ + if (!xen_gnttab_ops) { + return -ENOSYS; + } + return xen_gnttab_ops->unmap(xgt, start_address, count); +} + void setup_xen_backend_ops(void); =20 #endif /* QEMU_XEN_BACKEND_OPS_H */ diff --git a/include/hw/xen/xen_common.h b/include/hw/xen/xen_common.h index 34abd0a772..d4d10d3ff1 100644 --- a/include/hw/xen/xen_common.h +++ b/include/hw/xen/xen_common.h @@ -28,17 +28,6 @@ extern xc_interface *xen_xc; #if CONFIG_XEN_CTRL_INTERFACE_VERSION < 40701 =20 typedef xc_interface xenforeignmemory_handle; -typedef xc_gnttab xengnttab_handle; - -#define xengnttab_open(l, f) xc_gnttab_open(l, f) -#define xengnttab_close(h) xc_gnttab_close(h) -#define xengnttab_set_max_grants(h, n) xc_gnttab_set_max_grants(h, n) -#define xengnttab_map_grant_ref(h, d, r, p) xc_gnttab_map_grant_ref(h, d, = r, p) -#define xengnttab_unmap(h, a, n) xc_gnttab_munmap(h, a, n) -#define xengnttab_map_grant_refs(h, c, d, r, p) \ - xc_gnttab_map_grant_refs(h, c, d, r, p) -#define xengnttab_map_domain_grant_refs(h, c, d, r, p) \ - xc_gnttab_map_domain_grant_refs(h, c, d, r, p) =20 #define xenforeignmemory_open(l, f) xen_xc #define xenforeignmemory_close(h) @@ -58,7 +47,6 @@ static inline void *xenforeignmemory_map(xc_interface *h,= uint32_t dom, =20 #else /* CONFIG_XEN_CTRL_INTERFACE_VERSION >=3D 40701 */ =20 -#include #include =20 #endif @@ -648,31 +636,4 @@ static inline int xen_set_ioreq_server_state(domid_t d= om, =20 #endif =20 -/* Xen before 4.8 */ - -#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 40800 - -struct xengnttab_grant_copy_segment { - union xengnttab_copy_ptr { - void *virt; - struct { - uint32_t ref; - uint16_t offset; - uint16_t domid; - } foreign; - } source, dest; - uint16_t len; - uint16_t flags; - int16_t status; -}; - -typedef struct xengnttab_grant_copy_segment xengnttab_grant_copy_segment_t; - -static inline int xengnttab_grant_copy(xengnttab_handle *xgt, uint32_t cou= nt, - xengnttab_grant_copy_segment_t *seg= s) -{ - return -ENOSYS; -} -#endif - #endif /* QEMU_HW_XEN_COMMON_H */ diff --git a/softmmu/globals.c b/softmmu/globals.c index eb62739be1..23bb27f0f6 100644 --- a/softmmu/globals.c +++ b/softmmu/globals.c @@ -66,3 +66,4 @@ uint32_t xen_domid; enum xen_mode xen_mode =3D XEN_DISABLED; bool xen_domid_restrict; struct evtchn_backend_ops *xen_evtchn_ops; +struct gnttab_backend_ops *xen_gnttab_ops; --=20 2.39.0 From nobody Fri May 3 04:42:41 2024 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 ARC-Seal: i=1; a=rsa-sha256; t=1677771331; cv=none; d=zohomail.com; s=zohoarc; b=TUmLv52LFRUb1HxzPHOZyJw/C5S1EVuFVgKWyyKWKWuo4u6pRwQnX4/bNeYxuDxJc47dqvqy+155pz0d1MibJS7NQpkbEn3NbTbAHZxX0O06XTZOB8vNVPNHCMMR52ajXTMJxaaTzfptmPsrGIIPdTFKfrB4odVY9iOWSiaqiUc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1677771331; 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=NF8xN9k5qsj8llf3yVbtIw6AiA0womeXOrSieif4acs=; b=irqgIHuslCwfLA967Ir+lK9YwHHxbp+rosHSFECRD+OFmmpVLUSCpxVkxTvZM+jVz6cCrdPuGFz5v81TG3CxcSoYxlMuD9BWblj+d54hJjlSfCKbFqH8d5TMQZ0Zlh0A5rKQBAu7/rxupwZr8P97wtpdIXog+ihnaF/zLg6Jvz4= 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 Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1677771331640763.4187200538639; Thu, 2 Mar 2023 07:35:31 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.505060.777684 (Exim 4.92) (envelope-from ) id 1pXkxV-00047X-33; Thu, 02 Mar 2023 15:35:05 +0000 Received: by outflank-mailman (output) from mailman id 505060.777684; Thu, 02 Mar 2023 15:35:04 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxU-00043g-EW; Thu, 02 Mar 2023 15:35:04 +0000 Received: by outflank-mailman (input) for mailman id 505060; Thu, 02 Mar 2023 15:34:58 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxO-0001Jv-5m for xen-devel@lists.xenproject.org; Thu, 02 Mar 2023 15:34:58 +0000 Received: from casper.infradead.org (casper.infradead.org [2001:8b0:10b:1236::1]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id c263863f-b90f-11ed-96ad-2f268f93b82a; Thu, 02 Mar 2023 16:34:49 +0100 (CET) Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by casper.infradead.org with esmtpsa (Exim 4.94.2 #2 (Red Hat Linux)) id 1pXkx4-002UNI-Ax; Thu, 02 Mar 2023 15:34:38 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-004uyz-18; Thu, 02 Mar 2023 15:34:38 +0000 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 X-Inumbo-ID: c263863f-b90f-11ed-96ad-2f268f93b82a DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=NF8xN9k5qsj8llf3yVbtIw6AiA0womeXOrSieif4acs=; b=cUA7Lvw0yCJuWXSkIWQA5xO/xU Oi0tHoBTGkTy0ikl27dE7lIj+pLnQsIXy2aPk8GHf/8P6QyEaLRtXsCQ5Wztsruq7+fRMIPkInvid BhmWYmiNrX78XsgufP3qVCbduJfDZnim6W1zVR9V8Wfmw/VG1oJrRoh1PUlM/r6Hp+G62mybpghc7 a8a7VW3IfgxIBcXBUsZ+Qyjd/iEcWuoKDr7AwRrFBR7DRB9SuvWx6lnvLe5SrB6THBkKal1wOvUwv h0Bs0RxEp/SQ2jbKEd6YwoRvmiAWSkdzE0EEf6ov2BVNwEYQq5NBZN/fSFsZw7QPTTKvriSAOH6M6 Rg5fMqgQ==; From: David Woodhouse To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , Stefano Stabellini , vikram.garhwal@amd.com, Anthony Perard , xen-devel@lists.xenproject.org Subject: [RFC PATCH v1 11/25] hw/xen: Pass grant ref to gnttab unmap operation Date: Thu, 2 Mar 2023 15:34:21 +0000 Message-Id: <20230302153435.1170111-12-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230302153435.1170111-1-dwmw2@infradead.org> References: <20230302153435.1170111-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by casper.infradead.org. See http://www.infradead.org/rpr.html X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1677771333605100017 Content-Type: text/plain; charset="utf-8" From: David Woodhouse The previous commit introduced redirectable gnttab operations fairly much like-for-like, with the exception of the extra arguments to the ->open() call which were always NULL/0 anyway. This *changes* the arguments to the ->unmap() operation to include the original ref# that was mapped. Under real Xen it isn't necessary; all we need to do from QEMU is munmap(), then the kernel will release the grant, and Xen does the tracking/refcounting for the guest. When we have emulated grant tables though, we need to do all that for ourselves. So let's have the back ends keep track of what they mapped and pass it in to the ->unmap() method for us. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- hw/9pfs/xen-9p-backend.c | 7 ++++--- hw/block/dataplane/xen-block.c | 1 + hw/char/xen_console.c | 2 +- hw/net/xen_nic.c | 13 ++++++++----- hw/usb/xen-usb.c | 21 ++++++++++++++++----- hw/xen/xen-bus.c | 4 ++-- hw/xen/xen-legacy-backend.c | 4 ++-- hw/xen/xen-operations.c | 9 ++++++++- include/hw/xen/xen-bus.h | 2 +- include/hw/xen/xen-legacy-backend.h | 6 +++--- include/hw/xen/xen_backend_ops.h | 7 ++++--- 11 files changed, 50 insertions(+), 26 deletions(-) diff --git a/hw/9pfs/xen-9p-backend.c b/hw/9pfs/xen-9p-backend.c index 864bdaf952..d8bb0e847c 100644 --- a/hw/9pfs/xen-9p-backend.c +++ b/hw/9pfs/xen-9p-backend.c @@ -359,12 +359,13 @@ static int xen_9pfs_free(struct XenLegacyDevice *xend= ev) if (xen_9pdev->rings[i].data !=3D NULL) { xen_be_unmap_grant_refs(&xen_9pdev->xendev, xen_9pdev->rings[i].data, + xen_9pdev->rings[i].intf->ref, (1 << xen_9pdev->rings[i].ring_order)); } if (xen_9pdev->rings[i].intf !=3D NULL) { - xen_be_unmap_grant_refs(&xen_9pdev->xendev, - xen_9pdev->rings[i].intf, - 1); + xen_be_unmap_grant_ref(&xen_9pdev->xendev, + xen_9pdev->rings[i].intf, + xen_9pdev->rings[i].ref); } if (xen_9pdev->rings[i].bh !=3D NULL) { qemu_bh_delete(xen_9pdev->rings[i].bh); diff --git a/hw/block/dataplane/xen-block.c b/hw/block/dataplane/xen-block.c index 2785b9e849..e55b713002 100644 --- a/hw/block/dataplane/xen-block.c +++ b/hw/block/dataplane/xen-block.c @@ -705,6 +705,7 @@ void xen_block_dataplane_stop(XenBlockDataPlane *datapl= ane) Error *local_err =3D NULL; =20 xen_device_unmap_grant_refs(xendev, dataplane->sring, + dataplane->ring_ref, dataplane->nr_ring_ref, &local_err); dataplane->sring =3D NULL; =20 diff --git a/hw/char/xen_console.c b/hw/char/xen_console.c index 63153dfde4..19ad6c946a 100644 --- a/hw/char/xen_console.c +++ b/hw/char/xen_console.c @@ -271,7 +271,7 @@ static void con_disconnect(struct XenLegacyDevice *xend= ev) if (!xendev->dev) { xenforeignmemory_unmap(xen_fmem, con->sring, 1); } else { - xen_be_unmap_grant_ref(xendev, con->sring); + xen_be_unmap_grant_ref(xendev, con->sring, con->ring_ref); } con->sring =3D NULL; } diff --git a/hw/net/xen_nic.c b/hw/net/xen_nic.c index 7d92c2d022..166d03787d 100644 --- a/hw/net/xen_nic.c +++ b/hw/net/xen_nic.c @@ -181,7 +181,7 @@ static void net_tx_packets(struct XenNetDev *netdev) qemu_send_packet(qemu_get_queue(netdev->nic), page + txreq.offset, txreq.size); } - xen_be_unmap_grant_ref(&netdev->xendev, page); + xen_be_unmap_grant_ref(&netdev->xendev, page, txreq.gref); net_tx_response(netdev, &txreq, NETIF_RSP_OKAY); } if (!netdev->tx_work) { @@ -261,7 +261,7 @@ static ssize_t net_rx_packet(NetClientState *nc, const = uint8_t *buf, size_t size return -1; } memcpy(page + NET_IP_ALIGN, buf, size); - xen_be_unmap_grant_ref(&netdev->xendev, page); + xen_be_unmap_grant_ref(&netdev->xendev, page, rxreq.gref); net_rx_response(netdev, &rxreq, NETIF_RSP_OKAY, NET_IP_ALIGN, size, 0); =20 return size; @@ -343,7 +343,8 @@ static int net_connect(struct XenLegacyDevice *xendev) netdev->rx_ring_ref, PROT_READ | PROT_WRITE); if (!netdev->rxs) { - xen_be_unmap_grant_ref(&netdev->xendev, netdev->txs); + xen_be_unmap_grant_ref(&netdev->xendev, netdev->txs, + netdev->tx_ring_ref); netdev->txs =3D NULL; return -1; } @@ -368,11 +369,13 @@ static void net_disconnect(struct XenLegacyDevice *xe= ndev) xen_pv_unbind_evtchn(&netdev->xendev); =20 if (netdev->txs) { - xen_be_unmap_grant_ref(&netdev->xendev, netdev->txs); + xen_be_unmap_grant_ref(&netdev->xendev, netdev->txs, + netdev->tx_ring_ref); netdev->txs =3D NULL; } if (netdev->rxs) { - xen_be_unmap_grant_ref(&netdev->xendev, netdev->rxs); + xen_be_unmap_grant_ref(&netdev->xendev, netdev->rxs, + netdev->rx_ring_ref); netdev->rxs =3D NULL; } } diff --git a/hw/usb/xen-usb.c b/hw/usb/xen-usb.c index 0f7369e7ed..a770a64cb4 100644 --- a/hw/usb/xen-usb.c +++ b/hw/usb/xen-usb.c @@ -101,6 +101,8 @@ struct usbback_hotplug { struct usbback_info { struct XenLegacyDevice xendev; /* must be first */ USBBus bus; + uint32_t urb_ring_ref; + uint32_t conn_ring_ref; void *urb_sring; void *conn_sring; struct usbif_urb_back_ring urb_ring; @@ -277,10 +279,11 @@ static int usbback_init_packet(struct usbback_req *us= bback_req) static void usbback_do_response(struct usbback_req *usbback_req, int32_t s= tatus, int32_t actual_length, int32_t error_count) { + uint32_t ref[USBIF_MAX_SEGMENTS_PER_REQUEST]; struct usbback_info *usbif; struct usbif_urb_response *res; struct XenLegacyDevice *xendev; - unsigned int notify; + unsigned int notify, i; =20 usbif =3D usbback_req->usbif; xendev =3D &usbif->xendev; @@ -293,13 +296,19 @@ static void usbback_do_response(struct usbback_req *u= sbback_req, int32_t status, } =20 if (usbback_req->buffer) { - xen_be_unmap_grant_refs(xendev, usbback_req->buffer, + for (i =3D 0; i < usbback_req->nr_buffer_segs; i++) { + ref[i] =3D usbback_req->req.seg[i].gref; + } + xen_be_unmap_grant_refs(xendev, usbback_req->buffer, ref, usbback_req->nr_buffer_segs); usbback_req->buffer =3D NULL; } =20 if (usbback_req->isoc_buffer) { - xen_be_unmap_grant_refs(xendev, usbback_req->isoc_buffer, + for (i =3D 0; i < usbback_req->nr_extra_segs; i++) { + ref[i] =3D usbback_req->req.seg[i + usbback_req->req.nr_buffer= _segs].gref; + } + xen_be_unmap_grant_refs(xendev, usbback_req->isoc_buffer, ref, usbback_req->nr_extra_segs); usbback_req->isoc_buffer =3D NULL; } @@ -832,11 +841,11 @@ static void usbback_disconnect(struct XenLegacyDevice= *xendev) xen_pv_unbind_evtchn(xendev); =20 if (usbif->urb_sring) { - xen_be_unmap_grant_ref(xendev, usbif->urb_sring); + xen_be_unmap_grant_ref(xendev, usbif->urb_sring, usbif->urb_ring_r= ef); usbif->urb_sring =3D NULL; } if (usbif->conn_sring) { - xen_be_unmap_grant_ref(xendev, usbif->conn_sring); + xen_be_unmap_grant_ref(xendev, usbif->conn_sring, usbif->conn_ring= _ref); usbif->conn_sring =3D NULL; } =20 @@ -889,6 +898,8 @@ static int usbback_connect(struct XenLegacyDevice *xend= ev) return -1; } =20 + usbif->urb_ring_ref =3D urb_ring_ref; + usbif->conn_ring_ref =3D conn_ring_ref; urb_sring =3D usbif->urb_sring; conn_sring =3D usbif->conn_sring; BACK_RING_INIT(&usbif->urb_ring, urb_sring, XC_PAGE_SIZE); diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c index b247e86f28..aee6a8c9b0 100644 --- a/hw/xen/xen-bus.c +++ b/hw/xen/xen-bus.c @@ -967,10 +967,10 @@ void *xen_device_map_grant_refs(XenDevice *xendev, ui= nt32_t *refs, return map; } =20 -void xen_device_unmap_grant_refs(XenDevice *xendev, void *map, +void xen_device_unmap_grant_refs(XenDevice *xendev, void *map, uint32_t *r= efs, unsigned int nr_refs, Error **errp) { - if (qemu_xen_gnttab_unmap(xendev->xgth, map, nr_refs)) { + if (qemu_xen_gnttab_unmap(xendev->xgth, map, refs, nr_refs)) { error_setg_errno(errp, errno, "xengnttab_unmap failed"); } } diff --git a/hw/xen/xen-legacy-backend.c b/hw/xen/xen-legacy-backend.c index 1e9a28f263..a48a25aeb5 100644 --- a/hw/xen/xen-legacy-backend.c +++ b/hw/xen/xen-legacy-backend.c @@ -137,11 +137,11 @@ void *xen_be_map_grant_refs(struct XenLegacyDevice *x= endev, uint32_t *refs, } =20 void xen_be_unmap_grant_refs(struct XenLegacyDevice *xendev, void *ptr, - unsigned int nr_refs) + uint32_t *refs, unsigned int nr_refs) { assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV); =20 - if (qemu_xen_gnttab_unmap(xendev->gnttabdev, ptr, nr_refs)) { + if (qemu_xen_gnttab_unmap(xendev->gnttabdev, ptr, refs, nr_refs)) { xen_pv_printf(xendev, 0, "xengnttab_unmap failed: %s\n", strerror(errno)); } diff --git a/hw/xen/xen-operations.c b/hw/xen/xen-operations.c index eb5fb0a59f..73dabac8e5 100644 --- a/hw/xen/xen-operations.c +++ b/hw/xen/xen-operations.c @@ -200,6 +200,13 @@ static xengnttab_handle *libxengnttab_backend_open(voi= d) return xengnttab_open(NULL, 0); } =20 +static int libxengnttab_backend_unmap(xengnttab_handle *xgt, + void *start_address, uint32_t *refs, + uint32_t count) +{ + return xengnttab_unmap(xgt, start_address, count); +} + =20 static struct gnttab_backend_ops libxengnttab_backend_ops =3D { .features =3D XEN_GNTTAB_OP_FEATURE_MAP_MULTIPLE, @@ -208,7 +215,7 @@ static struct gnttab_backend_ops libxengnttab_backend_o= ps =3D { .grant_copy =3D libxengnttab_fallback_grant_copy, .set_max_grants =3D xengnttab_set_max_grants, .map_refs =3D xengnttab_map_domain_grant_refs, - .unmap =3D xengnttab_unmap, + .unmap =3D libxengnttab_backend_unmap, }; =20 void setup_xen_backend_ops(void) diff --git a/include/hw/xen/xen-bus.h b/include/hw/xen/xen-bus.h index 72d71d1eb7..5a90e79d53 100644 --- a/include/hw/xen/xen-bus.h +++ b/include/hw/xen/xen-bus.h @@ -102,7 +102,7 @@ void xen_device_set_max_grant_refs(XenDevice *xendev, u= nsigned int nr_refs, void *xen_device_map_grant_refs(XenDevice *xendev, uint32_t *refs, unsigned int nr_refs, int prot, Error **errp); -void xen_device_unmap_grant_refs(XenDevice *xendev, void *map, +void xen_device_unmap_grant_refs(XenDevice *xendev, void *map, uint32_t *r= efs, unsigned int nr_refs, Error **errp); =20 typedef struct XenDeviceGrantCopySegment { diff --git a/include/hw/xen/xen-legacy-backend.h b/include/hw/xen/xen-legac= y-backend.h index eaf79cd221..ab28583267 100644 --- a/include/hw/xen/xen-legacy-backend.h +++ b/include/hw/xen/xen-legacy-backend.h @@ -52,7 +52,7 @@ void xen_be_set_max_grant_refs(struct XenLegacyDevice *xe= ndev, void *xen_be_map_grant_refs(struct XenLegacyDevice *xendev, uint32_t *refs, unsigned int nr_refs, int prot); void xen_be_unmap_grant_refs(struct XenLegacyDevice *xendev, void *ptr, - unsigned int nr_refs); + uint32_t *refs, unsigned int nr_refs); =20 int xen_be_copy_grant_refs(struct XenLegacyDevice *xendev, bool to_domain, XenGrantCopySegment segs[], @@ -65,9 +65,9 @@ static inline void *xen_be_map_grant_ref(struct XenLegacy= Device *xendev, } =20 static inline void xen_be_unmap_grant_ref(struct XenLegacyDevice *xendev, - void *ptr) + void *ptr, uint32_t ref) { - return xen_be_unmap_grant_refs(xendev, ptr, 1); + return xen_be_unmap_grant_refs(xendev, ptr, &ref, 1); } =20 /* actual backend drivers */ diff --git a/include/hw/xen/xen_backend_ops.h b/include/hw/xen/xen_backend_= ops.h index bb3333ab00..6f9d8e2c62 100644 --- a/include/hw/xen/xen_backend_ops.h +++ b/include/hw/xen/xen_backend_ops.h @@ -144,7 +144,8 @@ struct gnttab_backend_ops { int (*set_max_grants)(xengnttab_handle *xgt, uint32_t nr_grants); void *(*map_refs)(xengnttab_handle *xgt, uint32_t count, uint32_t domi= d, uint32_t *refs, int prot); - int (*unmap)(xengnttab_handle *xgt, void *start_address, uint32_t coun= t); + int (*unmap)(xengnttab_handle *xgt, void *start_address, uint32_t *ref= s, + uint32_t count); }; =20 extern struct gnttab_backend_ops *xen_gnttab_ops; @@ -204,13 +205,13 @@ static inline void *qemu_xen_gnttab_map_refs(xengntta= b_handle *xgt, } =20 static inline int qemu_xen_gnttab_unmap(xengnttab_handle *xgt, - void *start_address, + void *start_address, uint32_t *ref= s, uint32_t count) { if (!xen_gnttab_ops) { return -ENOSYS; } - return xen_gnttab_ops->unmap(xgt, start_address, count); + return xen_gnttab_ops->unmap(xgt, start_address, refs, count); } =20 void setup_xen_backend_ops(void); --=20 2.39.0 From nobody Fri May 3 04:42:41 2024 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 ARC-Seal: i=1; a=rsa-sha256; t=1677771331; cv=none; d=zohomail.com; s=zohoarc; b=mXiNXWhQV79gxK1C8GqualS1KtaMFCVSWdnkF5lphmgBQ69gUiCNSwGdIP/o5+eKimbyBaBLTxTOsESlPuXqGeLssr+A2lIfoana8dTeSqJRKs5XfjM7fx/kkkYu62vunI9nRwi+1+9RoXYP1MiURCc4gYgud09ElyGwBmG/IA4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1677771331; 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=5roE0YB+d8rwQAkUuNGzRtMIdxxHP+hz32oiYI6yf7w=; b=fea6gayg/uLXQ00x9L9l23lYQJmJsXIYf3Dd2EKWRZ1VfSIG9tR+DfDuxW8wuQqfHEmOQqF83iBZKoTgY2ciq4ho4DFjWAYTkr/5uyDFMWNEsYZIkbRUA4oQtbDwtenJn92XAtG7p98Ago285yE3u81uVl0enm3g/uaz0noYcdU= 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 Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1677771331089117.43482776512633; Thu, 2 Mar 2023 07:35:31 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.505052.777605 (Exim 4.92) (envelope-from ) id 1pXkxM-0001sZ-0f; Thu, 02 Mar 2023 15:34:56 +0000 Received: by outflank-mailman (output) from mailman id 505052.777605; Thu, 02 Mar 2023 15:34:55 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxL-0001pG-Px; Thu, 02 Mar 2023 15:34:55 +0000 Received: by outflank-mailman (input) for mailman id 505052; Thu, 02 Mar 2023 15:34:54 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxK-0001Jv-5T for xen-devel@lists.xenproject.org; Thu, 02 Mar 2023 15:34:54 +0000 Received: from desiato.infradead.org (desiato.infradead.org [2001:8b0:10b:1:d65d:64ff:fe57:4e05]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id c2cd18b0-b90f-11ed-96ad-2f268f93b82a; Thu, 02 Mar 2023 16:34:49 +0100 (CET) Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by desiato.infradead.org with esmtpsa (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-00FL3i-1h; Thu, 02 Mar 2023 15:34:39 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-004uz3-1J; Thu, 02 Mar 2023 15:34:38 +0000 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 X-Inumbo-ID: c2cd18b0-b90f-11ed-96ad-2f268f93b82a DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=5roE0YB+d8rwQAkUuNGzRtMIdxxHP+hz32oiYI6yf7w=; b=ZMiL3mxSXiO+MHU/FiBVWoME3R Ko8a+F95bX2y7tnmyGdEXww1EHQVtXKhZhpvb53UzDhaNdyAizxp6zbLhC/cr4n+P61sgFp0AdPaj D6wZ7McMkUylocJagzgdfPt1R9h/nElYoVS1F0u/ecX/c670vQGs7wE25vMaa1lRHilGn7juoT7al YK6prpJLu6NRRZMv9TA4DJDt8kzN+Qs2L/Mn90lvZtfxjLTmU2uUtnst/V/xbcF21ooQAXcUjEtLp 9K9WdnAR+WDmKcQFNQ6Nz4l2yptOdA5bSIQhIjtk0HZBTCEpPNniyRWjtyd/dsNmg0oQib7SFidI7 be11QR6Q==; From: David Woodhouse To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , Stefano Stabellini , vikram.garhwal@amd.com, Anthony Perard , xen-devel@lists.xenproject.org Subject: [RFC PATCH v1 12/25] hw/xen: Add foreignmem operations to allow redirection to internal emulation Date: Thu, 2 Mar 2023 15:34:22 +0000 Message-Id: <20230302153435.1170111-13-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230302153435.1170111-1-dwmw2@infradead.org> References: <20230302153435.1170111-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by desiato.infradead.org. See http://www.infradead.org/rpr.html X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1677771331716100006 Content-Type: text/plain; charset="utf-8" From: David Woodhouse Signed-off-by: David Woodhouse Signed-off-by: Paul Durrant Reviewed-by: Paul Durrant --- hw/char/xen_console.c | 8 +++--- hw/display/xenfb.c | 20 +++++++------- hw/xen/xen-operations.c | 45 ++++++++++++++++++++++++++++++++ include/hw/xen/xen_backend_ops.h | 26 ++++++++++++++++++ include/hw/xen/xen_common.h | 13 --------- softmmu/globals.c | 1 + tests/unit/test-xs-node.c | 1 + 7 files changed, 88 insertions(+), 26 deletions(-) diff --git a/hw/char/xen_console.c b/hw/char/xen_console.c index 19ad6c946a..e9cef3e1ef 100644 --- a/hw/char/xen_console.c +++ b/hw/char/xen_console.c @@ -237,9 +237,9 @@ static int con_initialise(struct XenLegacyDevice *xende= v) =20 if (!xendev->dev) { xen_pfn_t mfn =3D con->ring_ref; - con->sring =3D xenforeignmemory_map(xen_fmem, con->xendev.dom, - PROT_READ | PROT_WRITE, - 1, &mfn, NULL); + con->sring =3D qemu_xen_foreignmem_map(con->xendev.dom, NULL, + PROT_READ | PROT_WRITE, + 1, &mfn, NULL); } else { con->sring =3D xen_be_map_grant_ref(xendev, con->ring_ref, PROT_READ | PROT_WRITE); @@ -269,7 +269,7 @@ static void con_disconnect(struct XenLegacyDevice *xend= ev) =20 if (con->sring) { if (!xendev->dev) { - xenforeignmemory_unmap(xen_fmem, con->sring, 1); + qemu_xen_foreignmem_unmap(con->sring, 1); } else { xen_be_unmap_grant_ref(xendev, con->sring, con->ring_ref); } diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c index 260eb38a76..2c4016fcbd 100644 --- a/hw/display/xenfb.c +++ b/hw/display/xenfb.c @@ -98,8 +98,9 @@ static int common_bind(struct common *c) if (xenstore_read_fe_int(&c->xendev, "event-channel", &c->xendev.remot= e_port) =3D=3D -1) return -1; =20 - c->page =3D xenforeignmemory_map(xen_fmem, c->xendev.dom, - PROT_READ | PROT_WRITE, 1, &mfn, NULL); + c->page =3D qemu_xen_foreignmem_map(c->xendev.dom, NULL, + PROT_READ | PROT_WRITE, 1, &mfn, + NULL); if (c->page =3D=3D NULL) return -1; =20 @@ -115,7 +116,7 @@ static void common_unbind(struct common *c) { xen_pv_unbind_evtchn(&c->xendev); if (c->page) { - xenforeignmemory_unmap(xen_fmem, c->page, 1); + qemu_xen_foreignmem_unmap(c->page, 1); c->page =3D NULL; } } @@ -500,15 +501,16 @@ static int xenfb_map_fb(struct XenFB *xenfb) fbmfns =3D g_new0(xen_pfn_t, xenfb->fbpages); =20 xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd); - map =3D xenforeignmemory_map(xen_fmem, xenfb->c.xendev.dom, - PROT_READ, n_fbdirs, pgmfns, NULL); + map =3D qemu_xen_foreignmem_map(xenfb->c.xendev.dom, NULL, PROT_READ, + n_fbdirs, pgmfns, NULL); if (map =3D=3D NULL) goto out; xenfb_copy_mfns(mode, xenfb->fbpages, fbmfns, map); - xenforeignmemory_unmap(xen_fmem, map, n_fbdirs); + qemu_xen_foreignmem_unmap(map, n_fbdirs); =20 - xenfb->pixels =3D xenforeignmemory_map(xen_fmem, xenfb->c.xendev.dom, - PROT_READ, xenfb->fbpages, fbmfns, NULL); + xenfb->pixels =3D qemu_xen_foreignmem_map(xenfb->c.xendev.dom, NULL, + PROT_READ, xenfb->fbpages, + fbmfns, NULL); if (xenfb->pixels =3D=3D NULL) goto out; =20 @@ -927,7 +929,7 @@ static void fb_disconnect(struct XenLegacyDevice *xende= v) * Replacing the framebuffer with anonymous shared memory * instead. This releases the guest pages and keeps qemu happy. */ - xenforeignmemory_unmap(xen_fmem, fb->pixels, fb->fbpages); + qemu_xen_foreignmem_unmap(fb->pixels, fb->fbpages); fb->pixels =3D mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); diff --git a/hw/xen/xen-operations.c b/hw/xen/xen-operations.c index 73dabac8e5..61e56a7abe 100644 --- a/hw/xen/xen-operations.c +++ b/hw/xen/xen-operations.c @@ -22,6 +22,7 @@ */ #undef XC_WANT_COMPAT_EVTCHN_API #undef XC_WANT_COMPAT_GNTTAB_API +#undef XC_WANT_COMPAT_MAP_FOREIGN_API =20 #include =20 @@ -56,10 +57,13 @@ typedef xc_gnttab xengnttab_handle; #define xengnttab_map_domain_grant_refs(h, c, d, r, p) \ xc_gnttab_map_domain_grant_refs(h, c, d, r, p) =20 +typedef xc_interface xenforeignmemory_handle; + #else /* CONFIG_XEN_CTRL_INTERFACE_VERSION >=3D 40701 */ =20 #include #include +#include =20 #endif =20 @@ -218,6 +222,46 @@ static struct gnttab_backend_ops libxengnttab_backend_= ops =3D { .unmap =3D libxengnttab_backend_unmap, }; =20 +#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 40701 + +static void *libxenforeignmem_backend_map(uint32_t dom, void *addr, int pr= ot, + size_t pages, xfn_pfn_t *pfns, + int *errs) +{ + if (errs) { + return xc_map_foreign_bulk(xen_xc, dom, prot, pfns, errs, pages); + } else { + return xc_map_foreign_pages(xen_xc, dom, prot, pfns, pages); + } +} + +static int libxenforeignmem_backend_unmap(void *addr, size_t pages) +{ + return munmap(addr, pages * XC_PAGE_SIZE); +} + +#else /* CONFIG_XEN_CTRL_INTERFACE_VERSION >=3D 40701 */ + +static void *libxenforeignmem_backend_map(uint32_t dom, void *addr, int pr= ot, + size_t pages, xen_pfn_t *pfns, + int *errs) +{ + return xenforeignmemory_map2(xen_fmem, dom, addr, prot, 0, pages, pfns, + errs); +} + +static int libxenforeignmem_backend_unmap(void *addr, size_t pages) +{ + return xenforeignmemory_unmap(xen_fmem, addr, pages); +} + +#endif + +struct foreignmem_backend_ops libxenforeignmem_backend_ops =3D { + .map =3D libxenforeignmem_backend_map, + .unmap =3D libxenforeignmem_backend_unmap, +}; + void setup_xen_backend_ops(void) { #if CONFIG_XEN_CTRL_INTERFACE_VERSION >=3D 40800 @@ -232,4 +276,5 @@ void setup_xen_backend_ops(void) #endif xen_evtchn_ops =3D &libxenevtchn_backend_ops; xen_gnttab_ops =3D &libxengnttab_backend_ops; + xen_foreignmem_ops =3D &libxenforeignmem_backend_ops; } diff --git a/include/hw/xen/xen_backend_ops.h b/include/hw/xen/xen_backend_= ops.h index 6f9d8e2c62..0dff06bbde 100644 --- a/include/hw/xen/xen_backend_ops.h +++ b/include/hw/xen/xen_backend_ops.h @@ -214,6 +214,32 @@ static inline int qemu_xen_gnttab_unmap(xengnttab_hand= le *xgt, return xen_gnttab_ops->unmap(xgt, start_address, refs, count); } =20 +struct foreignmem_backend_ops { + void *(*map)(uint32_t dom, void *addr, int prot, size_t pages, + xen_pfn_t *pfns, int *errs); + int (*unmap)(void *addr, size_t pages); +}; + +extern struct foreignmem_backend_ops *xen_foreignmem_ops; + +static inline void *qemu_xen_foreignmem_map(uint32_t dom, void *addr, int = prot, + size_t pages, xen_pfn_t *pfns, + int *errs) +{ + if (!xen_foreignmem_ops) { + return NULL; + } + return xen_foreignmem_ops->map(dom, addr, prot, pages, pfns, errs); +} + +static inline int qemu_xen_foreignmem_unmap(void *addr, size_t pages) +{ + if (!xen_foreignmem_ops) { + return -ENOSYS; + } + return xen_foreignmem_ops->unmap(addr, pages); +} + void setup_xen_backend_ops(void); =20 #endif /* QEMU_XEN_BACKEND_OPS_H */ diff --git a/include/hw/xen/xen_common.h b/include/hw/xen/xen_common.h index d4d10d3ff1..632ce617cc 100644 --- a/include/hw/xen/xen_common.h +++ b/include/hw/xen/xen_common.h @@ -32,19 +32,6 @@ typedef xc_interface xenforeignmemory_handle; #define xenforeignmemory_open(l, f) xen_xc #define xenforeignmemory_close(h) =20 -static inline void *xenforeignmemory_map(xc_interface *h, uint32_t dom, - int prot, size_t pages, - const xen_pfn_t arr[/*pages*/], - int err[/*pages*/]) -{ - if (err) - return xc_map_foreign_bulk(h, dom, prot, arr, err, pages); - else - return xc_map_foreign_pages(h, dom, prot, arr, pages); -} - -#define xenforeignmemory_unmap(h, p, s) munmap(p, s * XC_PAGE_SIZE) - #else /* CONFIG_XEN_CTRL_INTERFACE_VERSION >=3D 40701 */ =20 #include diff --git a/softmmu/globals.c b/softmmu/globals.c index 23bb27f0f6..dda32986f7 100644 --- a/softmmu/globals.c +++ b/softmmu/globals.c @@ -67,3 +67,4 @@ enum xen_mode xen_mode =3D XEN_DISABLED; bool xen_domid_restrict; struct evtchn_backend_ops *xen_evtchn_ops; struct gnttab_backend_ops *xen_gnttab_ops; +struct foreignmem_backend_ops *xen_foreignmem_ops; diff --git a/tests/unit/test-xs-node.c b/tests/unit/test-xs-node.c index fda6a047d0..b80d10ff98 100644 --- a/tests/unit/test-xs-node.c +++ b/tests/unit/test-xs-node.c @@ -23,6 +23,7 @@ static GList *xs_node_list; * doesn't hurt). */ #define __XEN_PUBLIC_XEN_H__ +typedef unsigned long xen_pfn_t; =20 #include "hw/i386/kvm/xenstore_impl.c" =20 --=20 2.39.0 From nobody Fri May 3 04:42:41 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1677771472982955.9514279515264; Thu, 2 Mar 2023 07:37:52 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pXkxr-0004Kv-P7; Thu, 02 Mar 2023 10:35:27 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pXkxS-0003uS-H8 for qemu-devel@nongnu.org; Thu, 02 Mar 2023 10:35:05 -0500 Received: from desiato.infradead.org ([2001:8b0:10b:1:d65d:64ff:fe57:4e05]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pXkxM-0001fC-FE for qemu-devel@nongnu.org; Thu, 02 Mar 2023 10:35:01 -0500 Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by desiato.infradead.org with esmtpsa (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-00FL3j-1r; Thu, 02 Mar 2023 15:34:39 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-004uz7-1V; Thu, 02 Mar 2023 15:34:38 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=7OYcuGk/WJovN4Fv5UgZ+akMCJx0VuuFqOz3t8MFOl8=; b=A96C9T3klBaf5y8FERbIaq1p8B qcL0vvjHV+7WOWbLN9X9idp393Or1KRbJV4/6HVfrxbDC84my8Sp2kOzXZ4Sf+Y/RBTb5w1wqjRmN gfOm4D29deFFwaQfXuSuMhoKbTHG7oEyOp3oN4VVyFhphBjYfsZvis7GWVXEHSiMqHvYKsLQ0DXdL t6EnmDvTGL34joq5CtT97KoaC4l+z7FvI3ZhUQMTbEJf2IX8eXLcW297XJFVP2drzns2ANi4cXAEX hJqX55yaOpGtaSL84/HdHiokTLszF7xaVKnQSGCEwQVDFLBdySo8b8yiXd5cidUso2LG/0hx1oi1s dl+0tSZw==; From: David Woodhouse To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , Stefano Stabellini , vikram.garhwal@amd.com, Anthony Perard , xen-devel@lists.xenproject.org Subject: [RFC PATCH v1 13/25] hw/xen: Add xenstore operations to allow redirection to internal emulation Date: Thu, 2 Mar 2023 15:34:23 +0000 Message-Id: <20230302153435.1170111-14-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230302153435.1170111-1-dwmw2@infradead.org> References: <20230302153435.1170111-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-SRS-Rewrite: SMTP reverse-path rewritten from by desiato.infradead.org. See http://www.infradead.org/rpr.html Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: none client-ip=2001:8b0:10b:1:d65d:64ff:fe57:4e05; envelope-from=BATV+9a0490e5ac528e462c30+7130+infradead.org+dwmw2@desiato.srs.infradead.org; helo=desiato.infradead.org X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1677771474901100005 Content-Type: text/plain; charset="utf-8" From: Paul Durrant Signed-off-by: Paul Durrant Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- accel/xen/xen-all.c | 11 +- hw/char/xen_console.c | 2 +- hw/i386/kvm/xen_xenstore.c | 3 - hw/i386/kvm/xenstore_impl.h | 8 +- hw/xen/xen-bus-helper.c | 62 +++---- hw/xen/xen-bus.c | 261 ++++------------------------ hw/xen/xen-legacy-backend.c | 119 +++++++------ hw/xen/xen-operations.c | 198 +++++++++++++++++++++ hw/xen/xen_devconfig.c | 4 +- hw/xen/xen_pt_graphics.c | 1 - hw/xen/xen_pvdev.c | 49 +----- include/hw/xen/xen-bus-helper.h | 26 +-- include/hw/xen/xen-bus.h | 17 +- include/hw/xen/xen-legacy-backend.h | 6 +- include/hw/xen/xen_backend_ops.h | 163 +++++++++++++++++ include/hw/xen/xen_common.h | 1 - include/hw/xen/xen_pvdev.h | 2 +- softmmu/globals.c | 1 + 18 files changed, 525 insertions(+), 409 deletions(-) diff --git a/accel/xen/xen-all.c b/accel/xen/xen-all.c index e85e4aeba5..425216230f 100644 --- a/accel/xen/xen-all.c +++ b/accel/xen/xen-all.c @@ -90,12 +90,15 @@ void xenstore_store_pv_console_info(int i, Chardev *chr) } =20 =20 -static void xenstore_record_dm_state(struct xs_handle *xs, const char *sta= te) +static void xenstore_record_dm_state(const char *state) { + struct xs_handle *xs; char path[50]; =20 + /* We now have everything we need to set the xenstore entry. */ + xs =3D xs_open(0); if (xs =3D=3D NULL) { - error_report("xenstore connection not initialized"); + fprintf(stderr, "Could not contact XenStore\n"); exit(1); } =20 @@ -109,6 +112,8 @@ static void xenstore_record_dm_state(struct xs_handle *= xs, const char *state) error_report("error recording dm state"); exit(1); } + + xs_close(xs); } =20 =20 @@ -117,7 +122,7 @@ static void xen_change_state_handler(void *opaque, bool= running, { if (running) { /* record state running */ - xenstore_record_dm_state(xenstore, "running"); + xenstore_record_dm_state("running"); } } =20 diff --git a/hw/char/xen_console.c b/hw/char/xen_console.c index e9cef3e1ef..ad8638a86d 100644 --- a/hw/char/xen_console.c +++ b/hw/char/xen_console.c @@ -181,7 +181,7 @@ static int con_init(struct XenLegacyDevice *xendev) const char *output; =20 /* setup */ - dom =3D xs_get_domain_path(xenstore, con->xendev.dom); + dom =3D qemu_xen_xs_get_domain_path(xenstore, con->xendev.dom); if (!xendev->dev) { snprintf(con->console, sizeof(con->console), "%s/console", dom); } else { diff --git a/hw/i386/kvm/xen_xenstore.c b/hw/i386/kvm/xen_xenstore.c index 5a8e38aae7..bab40d1a04 100644 --- a/hw/i386/kvm/xen_xenstore.c +++ b/hw/i386/kvm/xen_xenstore.c @@ -38,9 +38,6 @@ #define TYPE_XEN_XENSTORE "xen-xenstore" OBJECT_DECLARE_SIMPLE_TYPE(XenXenstoreState, XEN_XENSTORE) =20 -#define XEN_PAGE_SHIFT 12 -#define XEN_PAGE_SIZE (1ULL << XEN_PAGE_SHIFT) - #define ENTRIES_PER_FRAME_V1 (XEN_PAGE_SIZE / sizeof(grant_entry_v1_t)) #define ENTRIES_PER_FRAME_V2 (XEN_PAGE_SIZE / sizeof(grant_entry_v2_t)) =20 diff --git a/hw/i386/kvm/xenstore_impl.h b/hw/i386/kvm/xenstore_impl.h index bbe2391e2e..0df2a91aae 100644 --- a/hw/i386/kvm/xenstore_impl.h +++ b/hw/i386/kvm/xenstore_impl.h @@ -12,13 +12,7 @@ #ifndef QEMU_XENSTORE_IMPL_H #define QEMU_XENSTORE_IMPL_H =20 -typedef uint32_t xs_transaction_t; - -#define XBT_NULL 0 - -#define XS_PERM_NONE 0x00 -#define XS_PERM_READ 0x01 -#define XS_PERM_WRITE 0x02 +#include "hw/xen/xen_backend_ops.h" =20 typedef struct XenstoreImplState XenstoreImplState; =20 diff --git a/hw/xen/xen-bus-helper.c b/hw/xen/xen-bus-helper.c index 5a1e12b374..b2b2cc9c5d 100644 --- a/hw/xen/xen-bus-helper.c +++ b/hw/xen/xen-bus-helper.c @@ -10,6 +10,7 @@ #include "hw/xen/xen-bus.h" #include "hw/xen/xen-bus-helper.h" #include "qapi/error.h" +#include "trace.h" =20 #include =20 @@ -46,34 +47,28 @@ const char *xs_strstate(enum xenbus_state state) return "INVALID"; } =20 -void xs_node_create(struct xs_handle *xsh, xs_transaction_t tid, - const char *node, struct xs_permissions perms[], - unsigned int nr_perms, Error **errp) +void xs_node_create(struct qemu_xs_handle *h, xs_transaction_t tid, + const char *node, unsigned int owner, unsigned int dom= id, + unsigned int perms, Error **errp) { trace_xs_node_create(node); =20 - if (!xs_write(xsh, tid, node, "", 0)) { + if (!qemu_xen_xs_create(h, tid, owner, domid, perms, node)) { error_setg_errno(errp, errno, "failed to create node '%s'", node); - return; - } - - if (!xs_set_permissions(xsh, tid, node, perms, nr_perms)) { - error_setg_errno(errp, errno, "failed to set node '%s' permissions= ", - node); } } =20 -void xs_node_destroy(struct xs_handle *xsh, xs_transaction_t tid, +void xs_node_destroy(struct qemu_xs_handle *h, xs_transaction_t tid, const char *node, Error **errp) { trace_xs_node_destroy(node); =20 - if (!xs_rm(xsh, tid, node)) { + if (!qemu_xen_xs_destroy(h, tid, node)) { error_setg_errno(errp, errno, "failed to destroy node '%s'", node); } } =20 -void xs_node_vprintf(struct xs_handle *xsh, xs_transaction_t tid, +void xs_node_vprintf(struct qemu_xs_handle *h, xs_transaction_t tid, const char *node, const char *key, Error **errp, const char *fmt, va_list ap) { @@ -86,7 +81,7 @@ void xs_node_vprintf(struct xs_handle *xsh, xs_transactio= n_t tid, =20 trace_xs_node_vprintf(path, value); =20 - if (!xs_write(xsh, tid, path, value, len)) { + if (!qemu_xen_xs_write(h, tid, path, value, len)) { error_setg_errno(errp, errno, "failed to write '%s' to '%s'", value, path); } @@ -95,18 +90,18 @@ void xs_node_vprintf(struct xs_handle *xsh, xs_transact= ion_t tid, g_free(path); } =20 -void xs_node_printf(struct xs_handle *xsh, xs_transaction_t tid, +void xs_node_printf(struct qemu_xs_handle *h, xs_transaction_t tid, const char *node, const char *key, Error **errp, const char *fmt, ...) { va_list ap; =20 va_start(ap, fmt); - xs_node_vprintf(xsh, tid, node, key, errp, fmt, ap); + xs_node_vprintf(h, tid, node, key, errp, fmt, ap); va_end(ap); } =20 -int xs_node_vscanf(struct xs_handle *xsh, xs_transaction_t tid, +int xs_node_vscanf(struct qemu_xs_handle *h, xs_transaction_t tid, const char *node, const char *key, Error **errp, const char *fmt, va_list ap) { @@ -115,7 +110,7 @@ int xs_node_vscanf(struct xs_handle *xsh, xs_transacti= on_t tid, =20 path =3D (strlen(node) !=3D 0) ? g_strdup_printf("%s/%s", node, key) : g_strdup(key); - value =3D xs_read(xsh, tid, path, NULL); + value =3D qemu_xen_xs_read(h, tid, path, NULL); =20 trace_xs_node_vscanf(path, value); =20 @@ -133,7 +128,7 @@ int xs_node_vscanf(struct xs_handle *xsh, xs_transacti= on_t tid, return rc; } =20 -int xs_node_scanf(struct xs_handle *xsh, xs_transaction_t tid, +int xs_node_scanf(struct qemu_xs_handle *h, xs_transaction_t tid, const char *node, const char *key, Error **errp, const char *fmt, ...) { @@ -141,42 +136,35 @@ int xs_node_scanf(struct xs_handle *xsh, xs_transact= ion_t tid, int rc; =20 va_start(ap, fmt); - rc =3D xs_node_vscanf(xsh, tid, node, key, errp, fmt, ap); + rc =3D xs_node_vscanf(h, tid, node, key, errp, fmt, ap); va_end(ap); =20 return rc; } =20 -void xs_node_watch(struct xs_handle *xsh, const char *node, const char *ke= y, - char *token, Error **errp) +struct qemu_xs_watch *xs_node_watch(struct qemu_xs_handle *h, const char *= node, + const char *key, xs_watch_fn fn, + void *opaque, Error **errp) { char *path; + struct qemu_xs_watch *w; =20 path =3D (strlen(node) !=3D 0) ? g_strdup_printf("%s/%s", node, key) : g_strdup(key); =20 trace_xs_node_watch(path); =20 - if (!xs_watch(xsh, path, token)) { + w =3D qemu_xen_xs_watch(h, path, fn, opaque); + if (!w) { error_setg_errno(errp, errno, "failed to watch node '%s'", path); } =20 g_free(path); + + return w; } =20 -void xs_node_unwatch(struct xs_handle *xsh, const char *node, - const char *key, const char *token, Error **errp) +void xs_node_unwatch(struct qemu_xs_handle *h, struct qemu_xs_watch *w) { - char *path; - - path =3D (strlen(node) !=3D 0) ? g_strdup_printf("%s/%s", node, key) : - g_strdup(key); - - trace_xs_node_unwatch(path); - - if (!xs_unwatch(xsh, path, token)) { - error_setg_errno(errp, errno, "failed to unwatch node '%s'", path); - } - - g_free(path); + qemu_xen_xs_unwatch(h, w); } diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c index aee6a8c9b0..9fe54967d4 100644 --- a/hw/xen/xen-bus.c +++ b/hw/xen/xen-bus.c @@ -62,7 +62,7 @@ static void xen_device_unplug(XenDevice *xendev, Error **= errp) =20 /* Mimic the way the Xen toolstack does an unplug */ again: - tid =3D xs_transaction_start(xenbus->xsh); + tid =3D qemu_xen_xs_transaction_start(xenbus->xsh); if (tid =3D=3D XBT_NULL) { error_setg_errno(errp, errno, "failed xs_transaction_start"); return; @@ -80,7 +80,7 @@ again: goto abort; } =20 - if (!xs_transaction_end(xenbus->xsh, tid, false)) { + if (!qemu_xen_xs_transaction_end(xenbus->xsh, tid, false)) { if (errno =3D=3D EAGAIN) { goto again; } @@ -95,7 +95,7 @@ abort: * We only abort if there is already a failure so ignore any error * from ending the transaction. */ - xs_transaction_end(xenbus->xsh, tid, true); + qemu_xen_xs_transaction_end(xenbus->xsh, tid, true); } =20 static void xen_bus_print_dev(Monitor *mon, DeviceState *dev, int indent) @@ -111,143 +111,6 @@ static char *xen_bus_get_dev_path(DeviceState *dev) return xen_device_get_backend_path(XEN_DEVICE(dev)); } =20 -struct XenWatch { - char *node, *key; - char *token; - XenWatchHandler handler; - void *opaque; - Notifier notifier; -}; - -static void watch_notify(Notifier *n, void *data) -{ - XenWatch *watch =3D container_of(n, XenWatch, notifier); - const char *token =3D data; - - if (!strcmp(watch->token, token)) { - watch->handler(watch->opaque); - } -} - -static XenWatch *new_watch(const char *node, const char *key, - XenWatchHandler handler, void *opaque) -{ - XenWatch *watch =3D g_new0(XenWatch, 1); - QemuUUID uuid; - - qemu_uuid_generate(&uuid); - - watch->token =3D qemu_uuid_unparse_strdup(&uuid); - watch->node =3D g_strdup(node); - watch->key =3D g_strdup(key); - watch->handler =3D handler; - watch->opaque =3D opaque; - watch->notifier.notify =3D watch_notify; - - return watch; -} - -static void free_watch(XenWatch *watch) -{ - g_free(watch->token); - g_free(watch->key); - g_free(watch->node); - - g_free(watch); -} - -struct XenWatchList { - struct xs_handle *xsh; - NotifierList notifiers; -}; - -static void watch_list_event(void *opaque) -{ - XenWatchList *watch_list =3D opaque; - char **v; - const char *token; - - v =3D xs_check_watch(watch_list->xsh); - if (!v) { - return; - } - - token =3D v[XS_WATCH_TOKEN]; - - notifier_list_notify(&watch_list->notifiers, (void *)token); - - free(v); -} - -static XenWatchList *watch_list_create(struct xs_handle *xsh) -{ - XenWatchList *watch_list =3D g_new0(XenWatchList, 1); - - g_assert(xsh); - - watch_list->xsh =3D xsh; - notifier_list_init(&watch_list->notifiers); - qemu_set_fd_handler(xs_fileno(watch_list->xsh), watch_list_event, NULL, - watch_list); - - return watch_list; -} - -static void watch_list_destroy(XenWatchList *watch_list) -{ - g_assert(notifier_list_empty(&watch_list->notifiers)); - qemu_set_fd_handler(xs_fileno(watch_list->xsh), NULL, NULL, NULL); - g_free(watch_list); -} - -static XenWatch *watch_list_add(XenWatchList *watch_list, const char *node, - const char *key, XenWatchHandler handler, - void *opaque, Error **errp) -{ - ERRP_GUARD(); - XenWatch *watch =3D new_watch(node, key, handler, opaque); - - notifier_list_add(&watch_list->notifiers, &watch->notifier); - - xs_node_watch(watch_list->xsh, node, key, watch->token, errp); - if (*errp) { - notifier_remove(&watch->notifier); - free_watch(watch); - - return NULL; - } - - return watch; -} - -static void watch_list_remove(XenWatchList *watch_list, XenWatch *watch, - Error **errp) -{ - xs_node_unwatch(watch_list->xsh, watch->node, watch->key, watch->token, - errp); - - notifier_remove(&watch->notifier); - free_watch(watch); -} - -static XenWatch *xen_bus_add_watch(XenBus *xenbus, const char *node, - const char *key, XenWatchHandler handle= r, - Error **errp) -{ - trace_xen_bus_add_watch(node, key); - - return watch_list_add(xenbus->watch_list, node, key, handler, xenbus, - errp); -} - -static void xen_bus_remove_watch(XenBus *xenbus, XenWatch *watch, - Error **errp) -{ - trace_xen_bus_remove_watch(watch->node, watch->key); - - watch_list_remove(xenbus->watch_list, watch, errp); -} - static void xen_bus_backend_create(XenBus *xenbus, const char *type, const char *name, char *path, Error **errp) @@ -261,15 +124,15 @@ static void xen_bus_backend_create(XenBus *xenbus, co= nst char *type, trace_xen_bus_backend_create(type, path); =20 again: - tid =3D xs_transaction_start(xenbus->xsh); + tid =3D qemu_xen_xs_transaction_start(xenbus->xsh); if (tid =3D=3D XBT_NULL) { error_setg(errp, "failed xs_transaction_start"); return; } =20 - key =3D xs_directory(xenbus->xsh, tid, path, &n); + key =3D qemu_xen_xs_directory(xenbus->xsh, tid, path, &n); if (!key) { - if (!xs_transaction_end(xenbus->xsh, tid, true)) { + if (!qemu_xen_xs_transaction_end(xenbus->xsh, tid, true)) { error_setg_errno(errp, errno, "failed xs_transaction_end"); } return; @@ -300,7 +163,7 @@ again: =20 free(key); =20 - if (!xs_transaction_end(xenbus->xsh, tid, false)) { + if (!qemu_xen_xs_transaction_end(xenbus->xsh, tid, false)) { qobject_unref(opts); =20 if (errno =3D=3D EAGAIN) { @@ -327,7 +190,7 @@ static void xen_bus_type_enumerate(XenBus *xenbus, cons= t char *type) =20 trace_xen_bus_type_enumerate(type); =20 - backend =3D xs_directory(xenbus->xsh, XBT_NULL, domain_path, &n); + backend =3D qemu_xen_xs_directory(xenbus->xsh, XBT_NULL, domain_path, = &n); if (!backend) { goto out; } @@ -372,7 +235,7 @@ static void xen_bus_enumerate(XenBus *xenbus) =20 trace_xen_bus_enumerate(); =20 - type =3D xs_directory(xenbus->xsh, XBT_NULL, "backend", &n); + type =3D qemu_xen_xs_directory(xenbus->xsh, XBT_NULL, "backend", &n); if (!type) { return; } @@ -415,7 +278,7 @@ static void xen_bus_cleanup(XenBus *xenbus) } } =20 -static void xen_bus_backend_changed(void *opaque) +static void xen_bus_backend_changed(void *opaque, const char *path) { XenBus *xenbus =3D opaque; =20 @@ -434,7 +297,7 @@ static void xen_bus_unrealize(BusState *bus) =20 for (i =3D 0; i < xenbus->backend_types; i++) { if (xenbus->backend_watch[i]) { - xen_bus_remove_watch(xenbus, xenbus->backend_watch[i], NUL= L); + xs_node_unwatch(xenbus->xsh, xenbus->backend_watch[i]); } } =20 @@ -442,13 +305,8 @@ static void xen_bus_unrealize(BusState *bus) xenbus->backend_watch =3D NULL; } =20 - if (xenbus->watch_list) { - watch_list_destroy(xenbus->watch_list); - xenbus->watch_list =3D NULL; - } - if (xenbus->xsh) { - xs_close(xenbus->xsh); + qemu_xen_xs_close(xenbus->xsh); } } =20 @@ -463,7 +321,7 @@ static void xen_bus_realize(BusState *bus, Error **errp) =20 trace_xen_bus_realize(); =20 - xenbus->xsh =3D xs_open(0); + xenbus->xsh =3D qemu_xen_xs_open(); if (!xenbus->xsh) { error_setg_errno(errp, errno, "failed xs_open"); goto fail; @@ -476,19 +334,18 @@ static void xen_bus_realize(BusState *bus, Error **er= rp) xenbus->backend_id =3D 0; /* Assume lack of node means dom0 */ } =20 - xenbus->watch_list =3D watch_list_create(xenbus->xsh); - module_call_init(MODULE_INIT_XEN_BACKEND); =20 type =3D xen_backend_get_types(&xenbus->backend_types); - xenbus->backend_watch =3D g_new(XenWatch *, xenbus->backend_types); + xenbus->backend_watch =3D g_new(struct qemu_xs_watch *, + xenbus->backend_types); =20 for (i =3D 0; i < xenbus->backend_types; i++) { char *node =3D g_strdup_printf("backend/%s", type[i]); =20 xenbus->backend_watch[i] =3D - xen_bus_add_watch(xenbus, node, key, xen_bus_backend_changed, - &local_err); + xs_node_watch(xenbus->xsh, node, key, xen_bus_backend_changed, + xenbus, &local_err); if (local_err) { /* This need not be treated as a hard error so don't propagate= */ error_reportf_err(local_err, @@ -631,7 +488,7 @@ static bool xen_device_frontend_is_active(XenDevice *xe= ndev) } } =20 -static void xen_device_backend_changed(void *opaque) +static void xen_device_backend_changed(void *opaque, const char *path) { XenDevice *xendev =3D opaque; const char *type =3D object_get_typename(OBJECT(xendev)); @@ -685,66 +542,35 @@ static void xen_device_backend_changed(void *opaque) } } =20 -static XenWatch *xen_device_add_watch(XenDevice *xendev, const char *node, - const char *key, - XenWatchHandler handler, - Error **errp) -{ - const char *type =3D object_get_typename(OBJECT(xendev)); - - trace_xen_device_add_watch(type, xendev->name, node, key); - - return watch_list_add(xendev->watch_list, node, key, handler, xendev, - errp); -} - -static void xen_device_remove_watch(XenDevice *xendev, XenWatch *watch, - Error **errp) -{ - const char *type =3D object_get_typename(OBJECT(xendev)); - - trace_xen_device_remove_watch(type, xendev->name, watch->node, - watch->key); - - watch_list_remove(xendev->watch_list, watch, errp); -} - - static void xen_device_backend_create(XenDevice *xendev, Error **errp) { ERRP_GUARD(); XenBus *xenbus =3D XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); - struct xs_permissions perms[2]; =20 xendev->backend_path =3D xen_device_get_backend_path(xendev); =20 - perms[0].id =3D xenbus->backend_id; - perms[0].perms =3D XS_PERM_NONE; - perms[1].id =3D xendev->frontend_id; - perms[1].perms =3D XS_PERM_READ; - g_assert(xenbus->xsh); =20 - xs_node_create(xenbus->xsh, XBT_NULL, xendev->backend_path, perms, - ARRAY_SIZE(perms), errp); + xs_node_create(xenbus->xsh, XBT_NULL, xendev->backend_path, + xenbus->backend_id, xendev->frontend_id, XS_PERM_READ, = errp); if (*errp) { error_prepend(errp, "failed to create backend: "); return; } =20 xendev->backend_state_watch =3D - xen_device_add_watch(xendev, xendev->backend_path, - "state", xen_device_backend_changed, - errp); + xs_node_watch(xendev->xsh, xendev->backend_path, + "state", xen_device_backend_changed, xendev, + errp); if (*errp) { error_prepend(errp, "failed to watch backend state: "); return; } =20 xendev->backend_online_watch =3D - xen_device_add_watch(xendev, xendev->backend_path, - "online", xen_device_backend_changed, - errp); + xs_node_watch(xendev->xsh, xendev->backend_path, + "online", xen_device_backend_changed, xendev, + errp); if (*errp) { error_prepend(errp, "failed to watch backend online: "); return; @@ -757,12 +583,12 @@ static void xen_device_backend_destroy(XenDevice *xen= dev) Error *local_err =3D NULL; =20 if (xendev->backend_online_watch) { - xen_device_remove_watch(xendev, xendev->backend_online_watch, NULL= ); + xs_node_unwatch(xendev->xsh, xendev->backend_online_watch); xendev->backend_online_watch =3D NULL; } =20 if (xendev->backend_state_watch) { - xen_device_remove_watch(xendev, xendev->backend_state_watch, NULL); + xs_node_unwatch(xendev->xsh, xendev->backend_state_watch); xendev->backend_state_watch =3D NULL; } =20 @@ -837,7 +663,7 @@ static void xen_device_frontend_set_state(XenDevice *xe= ndev, } } =20 -static void xen_device_frontend_changed(void *opaque) +static void xen_device_frontend_changed(void *opaque, const char *path) { XenDevice *xendev =3D opaque; XenDeviceClass *xendev_class =3D XEN_DEVICE_GET_CLASS(xendev); @@ -885,7 +711,6 @@ static void xen_device_frontend_create(XenDevice *xende= v, Error **errp) { ERRP_GUARD(); XenBus *xenbus =3D XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); - struct xs_permissions perms[2]; =20 xendev->frontend_path =3D xen_device_get_frontend_path(xendev); =20 @@ -894,15 +719,11 @@ static void xen_device_frontend_create(XenDevice *xen= dev, Error **errp) * toolstack. */ if (!xen_device_frontend_exists(xendev)) { - perms[0].id =3D xendev->frontend_id; - perms[0].perms =3D XS_PERM_NONE; - perms[1].id =3D xenbus->backend_id; - perms[1].perms =3D XS_PERM_READ | XS_PERM_WRITE; - g_assert(xenbus->xsh); =20 - xs_node_create(xenbus->xsh, XBT_NULL, xendev->frontend_path, perms, - ARRAY_SIZE(perms), errp); + xs_node_create(xenbus->xsh, XBT_NULL, xendev->frontend_path, + xendev->frontend_id, xenbus->backend_id, + XS_PERM_READ | XS_PERM_WRITE, errp); if (*errp) { error_prepend(errp, "failed to create frontend: "); return; @@ -910,8 +731,8 @@ static void xen_device_frontend_create(XenDevice *xende= v, Error **errp) } =20 xendev->frontend_state_watch =3D - xen_device_add_watch(xendev, xendev->frontend_path, "state", - xen_device_frontend_changed, errp); + xs_node_watch(xendev->xsh, xendev->frontend_path, "state", + xen_device_frontend_changed, xendev, errp); if (*errp) { error_prepend(errp, "failed to watch frontend state: "); } @@ -923,8 +744,7 @@ static void xen_device_frontend_destroy(XenDevice *xend= ev) Error *local_err =3D NULL; =20 if (xendev->frontend_state_watch) { - xen_device_remove_watch(xendev, xendev->frontend_state_watch, - NULL); + xs_node_unwatch(xendev->xsh, xendev->frontend_state_watch); xendev->frontend_state_watch =3D NULL; } =20 @@ -1146,13 +966,8 @@ static void xen_device_unrealize(DeviceState *dev) xendev->xgth =3D NULL; } =20 - if (xendev->watch_list) { - watch_list_destroy(xendev->watch_list); - xendev->watch_list =3D NULL; - } - if (xendev->xsh) { - xs_close(xendev->xsh); + qemu_xen_xs_close(xendev->xsh); xendev->xsh =3D NULL; } =20 @@ -1197,14 +1012,12 @@ static void xen_device_realize(DeviceState *dev, Er= ror **errp) =20 trace_xen_device_realize(type, xendev->name); =20 - xendev->xsh =3D xs_open(0); + xendev->xsh =3D qemu_xen_xs_open(); if (!xendev->xsh) { error_setg_errno(errp, errno, "failed xs_open"); goto unrealize; } =20 - xendev->watch_list =3D watch_list_create(xendev->xsh); - xendev->xgth =3D qemu_xen_gnttab_open(); if (!xendev->xgth) { error_setg_errno(errp, errno, "failed xengnttab_open"); diff --git a/hw/xen/xen-legacy-backend.c b/hw/xen/xen-legacy-backend.c index a48a25aeb5..4ded3cec23 100644 --- a/hw/xen/xen-legacy-backend.c +++ b/hw/xen/xen-legacy-backend.c @@ -39,7 +39,7 @@ BusState *xen_sysbus; /* ------------------------------------------------------------- */ =20 /* public */ -struct xs_handle *xenstore; +struct qemu_xs_handle *xenstore; const char *xen_protocol; =20 /* private */ @@ -274,6 +274,25 @@ static void xen_be_frontend_changed(struct XenLegacyDe= vice *xendev, } } =20 +static void xenstore_update_fe(void *opaque, const char *watch) +{ + struct XenLegacyDevice *xendev =3D opaque; + const char *node; + unsigned int len; + + len =3D strlen(xendev->fe); + if (strncmp(xendev->fe, watch, len) !=3D 0) { + return; + } + if (watch[len] !=3D '/') { + return; + } + node =3D watch + len + 1; + + xen_be_frontend_changed(xendev, node); + xen_be_check_state(xendev); +} + /* ------------------------------------------------------------- */ /* Check for possible state transitions and perform them. */ =20 @@ -287,7 +306,6 @@ static void xen_be_frontend_changed(struct XenLegacyDev= ice *xendev, */ static int xen_be_try_setup(struct XenLegacyDevice *xendev) { - char token[XEN_BUFSIZE]; int be_state; =20 if (xenstore_read_be_int(xendev, "state", &be_state) =3D=3D -1) { @@ -308,8 +326,9 @@ static int xen_be_try_setup(struct XenLegacyDevice *xen= dev) } =20 /* setup frontend watch */ - snprintf(token, sizeof(token), "fe:%p", xendev); - if (!xs_watch(xenstore, xendev->fe, token)) { + xendev->watch =3D qemu_xen_xs_watch(xenstore, xendev->fe, xenstore_upd= ate_fe, + xendev); + if (!xendev->watch) { xen_pv_printf(xendev, 0, "watching frontend path (%s) failed\n", xendev->fe); return -1; @@ -498,46 +517,20 @@ void xen_be_check_state(struct XenLegacyDevice *xende= v) =20 /* ------------------------------------------------------------- */ =20 -static int xenstore_scan(const char *type, int dom, struct XenDevOps *ops) -{ - struct XenLegacyDevice *xendev; - char path[XEN_BUFSIZE], token[XEN_BUFSIZE]; - char **dev =3D NULL; - unsigned int cdev, j; - - /* setup watch */ - snprintf(token, sizeof(token), "be:%p:%d:%p", type, dom, ops); - snprintf(path, sizeof(path), "backend/%s/%d", type, dom); - if (!xs_watch(xenstore, path, token)) { - xen_pv_printf(NULL, 0, "xen be: watching backend path (%s) failed\= n", - path); - return -1; - } - - /* look for backends */ - dev =3D xs_directory(xenstore, 0, path, &cdev); - if (!dev) { - return 0; - } - for (j =3D 0; j < cdev; j++) { - xendev =3D xen_be_get_xendev(type, dom, atoi(dev[j]), ops); - if (xendev =3D=3D NULL) { - continue; - } - xen_be_check_state(xendev); - } - free(dev); - return 0; -} +struct xenstore_be { + const char *type; + int dom; + struct XenDevOps *ops; +}; =20 -void xenstore_update_be(char *watch, char *type, int dom, - struct XenDevOps *ops) +static void xenstore_update_be(void *opaque, const char *watch) { + struct xenstore_be *be =3D opaque; struct XenLegacyDevice *xendev; char path[XEN_BUFSIZE], *bepath; unsigned int len, dev; =20 - len =3D snprintf(path, sizeof(path), "backend/%s/%d", type, dom); + len =3D snprintf(path, sizeof(path), "backend/%s/%d", be->type, be->do= m); if (strncmp(path, watch, len) !=3D 0) { return; } @@ -551,9 +544,9 @@ void xenstore_update_be(char *watch, char *type, int do= m, return; } =20 - xendev =3D xen_be_get_xendev(type, dom, dev, ops); + xendev =3D xen_be_get_xendev(be->type, be->dom, dev, be->ops); if (xendev !=3D NULL) { - bepath =3D xs_read(xenstore, 0, xendev->be, &len); + bepath =3D qemu_xen_xs_read(xenstore, 0, xendev->be, &len); if (bepath =3D=3D NULL) { xen_pv_del_xendev(xendev); } else { @@ -564,23 +557,41 @@ void xenstore_update_be(char *watch, char *type, int = dom, } } =20 -void xenstore_update_fe(char *watch, struct XenLegacyDevice *xendev) +static int xenstore_scan(const char *type, int dom, struct XenDevOps *ops) { - char *node; - unsigned int len; + struct XenLegacyDevice *xendev; + char path[XEN_BUFSIZE]; + struct xenstore_be *be =3D g_new0(struct xenstore_be, 1); + char **dev =3D NULL; + unsigned int cdev, j; =20 - len =3D strlen(xendev->fe); - if (strncmp(xendev->fe, watch, len) !=3D 0) { - return; - } - if (watch[len] !=3D '/') { - return; + /* setup watch */ + be->type =3D type; + be->dom =3D dom; + be->ops =3D ops; + snprintf(path, sizeof(path), "backend/%s/%d", type, dom); + if (!qemu_xen_xs_watch(xenstore, path, xenstore_update_be, be)) { + xen_pv_printf(NULL, 0, "xen be: watching backend path (%s) failed\= n", + path); + return -1; } - node =3D watch + len + 1; =20 - xen_be_frontend_changed(xendev, node); - xen_be_check_state(xendev); + /* look for backends */ + dev =3D qemu_xen_xs_directory(xenstore, 0, path, &cdev); + if (!dev) { + return 0; + } + for (j =3D 0; j < cdev; j++) { + xendev =3D xen_be_get_xendev(type, dom, atoi(dev[j]), ops); + if (xendev =3D=3D NULL) { + continue; + } + xen_be_check_state(xendev); + } + free(dev); + return 0; } + /* -------------------------------------------------------------------- */ =20 static void xen_set_dynamic_sysbus(void) @@ -594,14 +605,12 @@ static void xen_set_dynamic_sysbus(void) =20 void xen_be_init(void) { - xenstore =3D xs_daemon_open(); + xenstore =3D qemu_xen_xs_open(); if (!xenstore) { xen_pv_printf(NULL, 0, "can't connect to xenstored\n"); exit(1); } =20 - qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL); - if (xen_evtchn_ops =3D=3D NULL || xen_gnttab_ops =3D=3D NULL) { xen_pv_printf(NULL, 0, "Xen operations not set up\n"); exit(1); diff --git a/hw/xen/xen-operations.c b/hw/xen/xen-operations.c index 61e56a7abe..80c8fbede6 100644 --- a/hw/xen/xen-operations.c +++ b/hw/xen/xen-operations.c @@ -10,6 +10,7 @@ */ =20 #include "qemu/osdep.h" +#include "qemu/uuid.h" #include "qapi/error.h" =20 #include "hw/xen/xen_backend_ops.h" @@ -262,6 +263,202 @@ struct foreignmem_backend_ops libxenforeignmem_backen= d_ops =3D { .unmap =3D libxenforeignmem_backend_unmap, }; =20 +struct qemu_xs_handle { + struct xs_handle *xsh; + NotifierList notifiers; +}; + +static void watch_event(void *opaque) +{ + struct qemu_xs_handle *h =3D opaque; + + for (;;) { + char **v =3D xs_check_watch(h->xsh); + + if (!v) { + break; + } + + notifier_list_notify(&h->notifiers, v); + free(v); + } +} + +static struct qemu_xs_handle *libxenstore_open(void) +{ + struct xs_handle *xsh =3D xs_open(0); + struct qemu_xs_handle *h =3D g_new0(struct qemu_xs_handle, 1); + + if (!xsh) { + return NULL; + } + + h =3D g_new0(struct qemu_xs_handle, 1); + h->xsh =3D xsh; + + notifier_list_init(&h->notifiers); + qemu_set_fd_handler(xs_fileno(h->xsh), watch_event, NULL, h); + + return h; +} + +static void libxenstore_close(struct qemu_xs_handle *h) +{ + g_assert(notifier_list_empty(&h->notifiers)); + qemu_set_fd_handler(xs_fileno(h->xsh), NULL, NULL, NULL); + xs_close(h->xsh); + g_free(h); +} + +static char *libxenstore_get_domain_path(struct qemu_xs_handle *h, + unsigned int domid) +{ + return xs_get_domain_path(h->xsh, domid); +} + +static char **libxenstore_directory(struct qemu_xs_handle *h, + xs_transaction_t t, const char *path, + unsigned int *num) +{ + return xs_directory(h->xsh, t, path, num); +} + +static void *libxenstore_read(struct qemu_xs_handle *h, xs_transaction_t t, + const char *path, unsigned int *len) +{ + return xs_read(h->xsh, t, path, len); +} + +static bool libxenstore_write(struct qemu_xs_handle *h, xs_transaction_t t, + const char *path, const void *data, + unsigned int len) +{ + return xs_write(h->xsh, t, path, data, len); +} + +static bool libxenstore_create(struct qemu_xs_handle *h, xs_transaction_t = t, + unsigned int owner, unsigned int domid, + unsigned int perms, const char *path) +{ + struct xs_permissions perms_list[] =3D { + { + .id =3D owner, + .perms =3D XS_PERM_NONE, + }, + { + .id =3D domid, + .perms =3D perms, + }, + }; + + if (!xs_mkdir(h->xsh, t, path)) { + return false; + } + + return xs_set_permissions(h->xsh, t, path, perms_list, + ARRAY_SIZE(perms_list)); +} + +static bool libxenstore_destroy(struct qemu_xs_handle *h, xs_transaction_t= t, + const char *path) +{ + return xs_rm(h->xsh, t, path); +} + +struct qemu_xs_watch { + char *path; + char *token; + xs_watch_fn fn; + void *opaque; + Notifier notifier; +}; + +static void watch_notify(Notifier *n, void *data) +{ + struct qemu_xs_watch *w =3D container_of(n, struct qemu_xs_watch, noti= fier); + const char **v =3D data; + + if (!strcmp(w->token, v[XS_WATCH_TOKEN])) { + w->fn(w->opaque, v[XS_WATCH_PATH]); + } +} + +static struct qemu_xs_watch *new_watch(const char *path, xs_watch_fn fn, + void *opaque) +{ + struct qemu_xs_watch *w =3D g_new0(struct qemu_xs_watch, 1); + QemuUUID uuid; + + qemu_uuid_generate(&uuid); + + w->token =3D qemu_uuid_unparse_strdup(&uuid); + w->path =3D g_strdup(path); + w->fn =3D fn; + w->opaque =3D opaque; + w->notifier.notify =3D watch_notify; + + return w; +} + +static void free_watch(struct qemu_xs_watch *w) +{ + g_free(w->token); + g_free(w->path); + + g_free(w); +} + +static struct qemu_xs_watch *libxenstore_watch(struct qemu_xs_handle *h, + const char *path, xs_watch_= fn fn, + void *opaque) +{ + struct qemu_xs_watch *w =3D new_watch(path, fn, opaque); + + notifier_list_add(&h->notifiers, &w->notifier); + + if (!xs_watch(h->xsh, path, w->token)) { + notifier_remove(&w->notifier); + free_watch(w); + return NULL; + } + + return w; +} + +static void libxenstore_unwatch(struct qemu_xs_handle *h, + struct qemu_xs_watch *w) +{ + xs_unwatch(h->xsh, w->path, w->token); + notifier_remove(&w->notifier); + free_watch(w); +} + +static xs_transaction_t libxenstore_transaction_start(struct qemu_xs_handl= e *h) +{ + return xs_transaction_start(h->xsh); +} + +static bool libxenstore_transaction_end(struct qemu_xs_handle *h, + xs_transaction_t t, bool abort) +{ + return xs_transaction_end(h->xsh, t, abort); +} + +struct xenstore_backend_ops libxenstore_backend_ops =3D { + .open =3D libxenstore_open, + .close =3D libxenstore_close, + .get_domain_path =3D libxenstore_get_domain_path, + .directory =3D libxenstore_directory, + .read =3D libxenstore_read, + .write =3D libxenstore_write, + .create =3D libxenstore_create, + .destroy =3D libxenstore_destroy, + .watch =3D libxenstore_watch, + .unwatch =3D libxenstore_unwatch, + .transaction_start =3D libxenstore_transaction_start, + .transaction_end =3D libxenstore_transaction_end, +}; + void setup_xen_backend_ops(void) { #if CONFIG_XEN_CTRL_INTERFACE_VERSION >=3D 40800 @@ -277,4 +474,5 @@ void setup_xen_backend_ops(void) xen_evtchn_ops =3D &libxenevtchn_backend_ops; xen_gnttab_ops =3D &libxengnttab_backend_ops; xen_foreignmem_ops =3D &libxenforeignmem_backend_ops; + xen_xenstore_ops =3D &libxenstore_backend_ops; } diff --git a/hw/xen/xen_devconfig.c b/hw/xen/xen_devconfig.c index 46ee4a7f02..9b7304e544 100644 --- a/hw/xen/xen_devconfig.c +++ b/hw/xen/xen_devconfig.c @@ -11,11 +11,11 @@ static int xen_config_dev_dirs(const char *ftype, const= char *btype, int vdev, { char *dom; =20 - dom =3D xs_get_domain_path(xenstore, xen_domid); + dom =3D qemu_xen_xs_get_domain_path(xenstore, xen_domid); snprintf(fe, len, "%s/device/%s/%d", dom, ftype, vdev); free(dom); =20 - dom =3D xs_get_domain_path(xenstore, 0); + dom =3D qemu_xen_xs_get_domain_path(xenstore, 0); snprintf(be, len, "%s/backend/%s/%d/%d", dom, btype, xen_domid, vdev); free(dom); =20 diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c index f303f67c9c..0aed3bb6fd 100644 --- a/hw/xen/xen_pt_graphics.c +++ b/hw/xen/xen_pt_graphics.c @@ -5,7 +5,6 @@ #include "qapi/error.h" #include "xen_pt.h" #include "xen-host-pci-device.h" -#include "hw/xen/xen-legacy-backend.h" =20 static unsigned long igd_guest_opregion; static unsigned long igd_host_opregion; diff --git a/hw/xen/xen_pvdev.c b/hw/xen/xen_pvdev.c index d8582cc74c..be1504b82c 100644 --- a/hw/xen/xen_pvdev.c +++ b/hw/xen/xen_pvdev.c @@ -54,31 +54,17 @@ void xen_config_cleanup(void) struct xs_dirs *d; =20 QTAILQ_FOREACH(d, &xs_cleanup, list) { - xs_rm(xenstore, 0, d->xs_dir); + qemu_xen_xs_destroy(xenstore, 0, d->xs_dir); } } =20 int xenstore_mkdir(char *path, int p) { - struct xs_permissions perms[2] =3D { - { - .id =3D 0, /* set owner: dom0 */ - }, { - .id =3D xen_domid, - .perms =3D p, - } - }; - - if (!xs_mkdir(xenstore, 0, path)) { + if (!qemu_xen_xs_create(xenstore, 0, 0, xen_domid, p, path)) { xen_pv_printf(NULL, 0, "xs_mkdir %s: failed\n", path); return -1; } xenstore_cleanup_dir(g_strdup(path)); - - if (!xs_set_permissions(xenstore, 0, path, perms, 2)) { - xen_pv_printf(NULL, 0, "xs_set_permissions %s: failed\n", path); - return -1; - } return 0; } =20 @@ -87,7 +73,7 @@ int xenstore_write_str(const char *base, const char *node= , const char *val) char abspath[XEN_BUFSIZE]; =20 snprintf(abspath, sizeof(abspath), "%s/%s", base, node); - if (!xs_write(xenstore, 0, abspath, val, strlen(val))) { + if (!qemu_xen_xs_write(xenstore, 0, abspath, val, strlen(val))) { return -1; } return 0; @@ -100,7 +86,7 @@ char *xenstore_read_str(const char *base, const char *no= de) char *str, *ret =3D NULL; =20 snprintf(abspath, sizeof(abspath), "%s/%s", base, node); - str =3D xs_read(xenstore, 0, abspath, &len); + str =3D qemu_xen_xs_read(xenstore, 0, abspath, &len); if (str !=3D NULL) { /* move to qemu-allocated memory to make sure * callers can savely g_free() stuff. */ @@ -152,29 +138,6 @@ int xenstore_read_uint64(const char *base, const char = *node, uint64_t *uval) return rc; } =20 -void xenstore_update(void *unused) -{ - char **vec =3D NULL; - intptr_t type, ops, ptr; - unsigned int dom, count; - - vec =3D xs_read_watch(xenstore, &count); - if (vec =3D=3D NULL) { - goto cleanup; - } - - if (sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR, - &type, &dom, &ops) =3D=3D 3) { - xenstore_update_be(vec[XS_WATCH_PATH], (void *)type, dom, (void*)o= ps); - } - if (sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr) =3D=3D 1) { - xenstore_update_fe(vec[XS_WATCH_PATH], (void *)ptr); - } - -cleanup: - free(vec); -} - const char *xenbus_strstate(enum xenbus_state state) { static const char *const name[] =3D { @@ -299,9 +262,7 @@ void xen_pv_del_xendev(struct XenLegacyDevice *xendev) } =20 if (xendev->fe) { - char token[XEN_BUFSIZE]; - snprintf(token, sizeof(token), "fe:%p", xendev); - xs_unwatch(xenstore, xendev->fe, token); + qemu_xen_xs_unwatch(xenstore, xendev->watch); g_free(xendev->fe); } =20 diff --git a/include/hw/xen/xen-bus-helper.h b/include/hw/xen/xen-bus-helpe= r.h index 8782f30550..d8dcc2f010 100644 --- a/include/hw/xen/xen-bus-helper.h +++ b/include/hw/xen/xen-bus-helper.h @@ -8,40 +8,40 @@ #ifndef HW_XEN_BUS_HELPER_H #define HW_XEN_BUS_HELPER_H =20 -#include "hw/xen/xen_common.h" +#include "hw/xen/xen_backend_ops.h" =20 const char *xs_strstate(enum xenbus_state state); =20 -void xs_node_create(struct xs_handle *xsh, xs_transaction_t tid, - const char *node, struct xs_permissions perms[], - unsigned int nr_perms, Error **errp); -void xs_node_destroy(struct xs_handle *xsh, xs_transaction_t tid, +void xs_node_create(struct qemu_xs_handle *h, xs_transaction_t tid, + const char *node, unsigned int owner, unsigned int dom= id, + unsigned int perms, Error **errp); +void xs_node_destroy(struct qemu_xs_handle *h, xs_transaction_t tid, const char *node, Error **errp); =20 /* Write to node/key unless node is empty, in which case write to key */ -void xs_node_vprintf(struct xs_handle *xsh, xs_transaction_t tid, +void xs_node_vprintf(struct qemu_xs_handle *h, xs_transaction_t tid, const char *node, const char *key, Error **errp, const char *fmt, va_list ap) G_GNUC_PRINTF(6, 0); -void xs_node_printf(struct xs_handle *xsh, xs_transaction_t tid, +void xs_node_printf(struct qemu_xs_handle *h, xs_transaction_t tid, const char *node, const char *key, Error **errp, const char *fmt, ...) G_GNUC_PRINTF(6, 7); =20 /* Read from node/key unless node is empty, in which case read from key */ -int xs_node_vscanf(struct xs_handle *xsh, xs_transaction_t tid, +int xs_node_vscanf(struct qemu_xs_handle *h, xs_transaction_t tid, const char *node, const char *key, Error **errp, const char *fmt, va_list ap) G_GNUC_SCANF(6, 0); -int xs_node_scanf(struct xs_handle *xsh, xs_transaction_t tid, +int xs_node_scanf(struct qemu_xs_handle *h, xs_transaction_t tid, const char *node, const char *key, Error **errp, const char *fmt, ...) G_GNUC_SCANF(6, 7); =20 /* Watch node/key unless node is empty, in which case watch key */ -void xs_node_watch(struct xs_handle *xsh, const char *node, const char *ke= y, - char *token, Error **errp); -void xs_node_unwatch(struct xs_handle *xsh, const char *node, const char *= key, - const char *token, Error **errp); +struct qemu_xs_watch *xs_node_watch(struct qemu_xs_handle *h, const char *= node, + const char *key, xs_watch_fn fn, + void *opaque, Error **errp); +void xs_node_unwatch(struct qemu_xs_handle *h, struct qemu_xs_watch *w); =20 #endif /* HW_XEN_BUS_HELPER_H */ diff --git a/include/hw/xen/xen-bus.h b/include/hw/xen/xen-bus.h index 5a90e79d53..f435898164 100644 --- a/include/hw/xen/xen-bus.h +++ b/include/hw/xen/xen-bus.h @@ -9,29 +9,23 @@ #define HW_XEN_BUS_H =20 #include "hw/xen/xen_backend_ops.h" -#include "hw/xen/interface/io/xenbus.h" #include "hw/sysbus.h" #include "qemu/notify.h" #include "qom/object.h" =20 -typedef void (*XenWatchHandler)(void *opaque); - -typedef struct XenWatchList XenWatchList; -typedef struct XenWatch XenWatch; typedef struct XenEventChannel XenEventChannel; =20 struct XenDevice { DeviceState qdev; domid_t frontend_id; char *name; - struct xs_handle *xsh; - XenWatchList *watch_list; + struct qemu_xs_handle *xsh; char *backend_path, *frontend_path; enum xenbus_state backend_state, frontend_state; Notifier exit; - XenWatch *backend_state_watch, *frontend_state_watch; + struct qemu_xs_watch *backend_state_watch, *frontend_state_watch; bool backend_online; - XenWatch *backend_online_watch; + struct qemu_xs_watch *backend_online_watch; xengnttab_handle *xgth; bool inactive; QLIST_HEAD(, XenEventChannel) event_channels; @@ -64,10 +58,9 @@ OBJECT_DECLARE_TYPE(XenDevice, XenDeviceClass, XEN_DEVIC= E) struct XenBus { BusState qbus; domid_t backend_id; - struct xs_handle *xsh; - XenWatchList *watch_list; + struct qemu_xs_handle *xsh; unsigned int backend_types; - XenWatch **backend_watch; + struct qemu_xs_watch **backend_watch; QLIST_HEAD(, XenDevice) inactive_devices; }; =20 diff --git a/include/hw/xen/xen-legacy-backend.h b/include/hw/xen/xen-legac= y-backend.h index ab28583267..6c307c5f2c 100644 --- a/include/hw/xen/xen-legacy-backend.h +++ b/include/hw/xen/xen-legacy-backend.h @@ -2,7 +2,6 @@ #define HW_XEN_LEGACY_BACKEND_H =20 #include "hw/xen/xen_backend_ops.h" -#include "hw/xen/interface/io/xenbus.h" #include "hw/xen/xen_pvdev.h" #include "net/net.h" #include "qom/object.h" @@ -16,7 +15,7 @@ DECLARE_INSTANCE_CHECKER(XenLegacyDevice, XENBACKEND, TYPE_XENBACKEND) =20 /* variables */ -extern struct xs_handle *xenstore; +extern struct qemu_xs_handle *xenstore; extern const char *xen_protocol; extern DeviceState *xen_sysdev; extern BusState *xen_sysbus; @@ -31,9 +30,6 @@ int xenstore_write_be_int64(struct XenLegacyDevice *xende= v, const char *node, char *xenstore_read_be_str(struct XenLegacyDevice *xendev, const char *nod= e); int xenstore_read_be_int(struct XenLegacyDevice *xendev, const char *node, int *ival); -void xenstore_update_fe(char *watch, struct XenLegacyDevice *xendev); -void xenstore_update_be(char *watch, char *type, int dom, - struct XenDevOps *ops); char *xenstore_read_fe_str(struct XenLegacyDevice *xendev, const char *nod= e); int xenstore_read_fe_int(struct XenLegacyDevice *xendev, const char *node, int *ival); diff --git a/include/hw/xen/xen_backend_ops.h b/include/hw/xen/xen_backend_= ops.h index 0dff06bbde..90cca85f52 100644 --- a/include/hw/xen/xen_backend_ops.h +++ b/include/hw/xen/xen_backend_ops.h @@ -12,6 +12,10 @@ #ifndef QEMU_XEN_BACKEND_OPS_H #define QEMU_XEN_BACKEND_OPS_H =20 +#include "hw/xen/xen.h" +#include "hw/xen/interface/xen.h" +#include "hw/xen/interface/io/xenbus.h" + /* * For the time being, these operations map fairly closely to the API of * the actual Xen libraries, e.g. libxenevtchn. As we complete the migrati= on @@ -36,6 +40,16 @@ typedef uint32_t grant_ref_t; #define XEN_PAGE_SIZE (1UL << XEN_PAGE_SHIFT) #define XEN_PAGE_MASK (~(XEN_PAGE_SIZE - 1)) =20 +#ifndef xen_rmb +#define xen_rmb() smp_rmb() +#endif +#ifndef xen_wmb +#define xen_wmb() smp_wmb() +#endif +#ifndef xen_mb +#define xen_mb() smp_mb() +#endif + struct evtchn_backend_ops { xenevtchn_handle *(*open)(void); int (*bind_interdomain)(xenevtchn_handle *xc, uint32_t domid, @@ -240,6 +254,155 @@ static inline int qemu_xen_foreignmem_unmap(void *add= r, size_t pages) return xen_foreignmem_ops->unmap(addr, pages); } =20 +typedef void (*xs_watch_fn)(void *opaque, const char *path); + +struct qemu_xs_handle; +struct qemu_xs_watch; +typedef uint32_t xs_transaction_t; + +#define XBT_NULL 0 + +#define XS_PERM_NONE 0x00 +#define XS_PERM_READ 0x01 +#define XS_PERM_WRITE 0x02 + +struct xenstore_backend_ops { + struct qemu_xs_handle *(*open)(void); + void (*close)(struct qemu_xs_handle *h); + char *(*get_domain_path)(struct qemu_xs_handle *h, unsigned int domid); + char **(*directory)(struct qemu_xs_handle *h, xs_transaction_t t, + const char *path, unsigned int *num); + void *(*read)(struct qemu_xs_handle *h, xs_transaction_t t, + const char *path, unsigned int *len); + bool (*write)(struct qemu_xs_handle *h, xs_transaction_t t, + const char *path, const void *data, unsigned int len); + bool (*create)(struct qemu_xs_handle *h, xs_transaction_t t, + unsigned int owner, unsigned int domid, + unsigned int perms, const char *path); + bool (*destroy)(struct qemu_xs_handle *h, xs_transaction_t t, + const char *path); + struct qemu_xs_watch *(*watch)(struct qemu_xs_handle *h, const char *p= ath, + xs_watch_fn fn, void *opaque); + void (*unwatch)(struct qemu_xs_handle *h, struct qemu_xs_watch *w); + xs_transaction_t (*transaction_start)(struct qemu_xs_handle *h); + bool (*transaction_end)(struct qemu_xs_handle *h, xs_transaction_t t, + bool abort); +}; + +extern struct xenstore_backend_ops *xen_xenstore_ops; + +static inline struct qemu_xs_handle *qemu_xen_xs_open(void) +{ + if (!xen_xenstore_ops) { + return NULL; + } + return xen_xenstore_ops->open(); +} + +static inline void qemu_xen_xs_close(struct qemu_xs_handle *h) +{ + if (!xen_xenstore_ops) { + return; + } + xen_xenstore_ops->close(h); +} + +static inline char *qemu_xen_xs_get_domain_path(struct qemu_xs_handle *h, + unsigned int domid) +{ + if (!xen_xenstore_ops) { + return NULL; + } + return xen_xenstore_ops->get_domain_path(h, domid); +} + +static inline char **qemu_xen_xs_directory(struct qemu_xs_handle *h, + xs_transaction_t t, const char = *path, + unsigned int *num) +{ + if (!xen_xenstore_ops) { + return NULL; + } + return xen_xenstore_ops->directory(h, t, path, num); +} + +static inline void *qemu_xen_xs_read(struct qemu_xs_handle *h, + xs_transaction_t t, const char *path, + unsigned int *len) +{ + if (!xen_xenstore_ops) { + return NULL; + } + return xen_xenstore_ops->read(h, t, path, len); +} + +static inline bool qemu_xen_xs_write(struct qemu_xs_handle *h, + xs_transaction_t t, const char *path, + const void *data, unsigned int len) +{ + if (!xen_xenstore_ops) { + return false; + } + return xen_xenstore_ops->write(h, t, path, data, len); +} + +static inline bool qemu_xen_xs_create(struct qemu_xs_handle *h, + xs_transaction_t t, unsigned int own= er, + unsigned int domid, unsigned int per= ms, + const char *path) +{ + if (!xen_xenstore_ops) { + return false; + } + return xen_xenstore_ops->create(h, t, owner, domid, perms, path); +} + +static inline bool qemu_xen_xs_destroy(struct qemu_xs_handle *h, + xs_transaction_t t, const char *pat= h) +{ + if (!xen_xenstore_ops) { + return false; + } + return xen_xenstore_ops->destroy(h, t, path); +} + +static inline struct qemu_xs_watch *qemu_xen_xs_watch(struct qemu_xs_handl= e *h, + const char *path, + xs_watch_fn fn, + void *opaque) +{ + if (!xen_xenstore_ops) { + return NULL; + } + return xen_xenstore_ops->watch(h, path, fn, opaque); +} + +static inline void qemu_xen_xs_unwatch(struct qemu_xs_handle *h, + struct qemu_xs_watch *w) +{ + if (!xen_xenstore_ops) { + return; + } + xen_xenstore_ops->unwatch(h, w); +} + +static inline xs_transaction_t qemu_xen_xs_transaction_start(struct qemu_x= s_handle *h) +{ + if (!xen_xenstore_ops) { + return XBT_NULL; + } + return xen_xenstore_ops->transaction_start(h); +} + +static inline bool qemu_xen_xs_transaction_end(struct qemu_xs_handle *h, + xs_transaction_t t, bool ab= ort) +{ + if (!xen_xenstore_ops) { + return false; + } + return xen_xenstore_ops->transaction_end(h, t, abort); +} + void setup_xen_backend_ops(void); =20 #endif /* QEMU_XEN_BACKEND_OPS_H */ diff --git a/include/hw/xen/xen_common.h b/include/hw/xen/xen_common.h index 632ce617cc..7edcf3eb25 100644 --- a/include/hw/xen/xen_common.h +++ b/include/hw/xen/xen_common.h @@ -12,7 +12,6 @@ =20 #include #include -#include "hw/xen/interface/io/xenbus.h" =20 #include "hw/xen/xen.h" #include "hw/pci/pci_device.h" diff --git a/include/hw/xen/xen_pvdev.h b/include/hw/xen/xen_pvdev.h index 9c27b14764..d8eea353b8 100644 --- a/include/hw/xen/xen_pvdev.h +++ b/include/hw/xen/xen_pvdev.h @@ -39,6 +39,7 @@ struct XenLegacyDevice { char name[64]; int debug; =20 + struct qemu_xs_watch *watch; enum xenbus_state be_state; enum xenbus_state fe_state; int online; @@ -64,7 +65,6 @@ int xenstore_write_int64(const char *base, const char *no= de, int64_t ival); char *xenstore_read_str(const char *base, const char *node); int xenstore_read_int(const char *base, const char *node, int *ival); int xenstore_read_uint64(const char *base, const char *node, uint64_t *uva= l); -void xenstore_update(void *unused); =20 const char *xenbus_strstate(enum xenbus_state state); =20 diff --git a/softmmu/globals.c b/softmmu/globals.c index dda32986f7..39678aa8c5 100644 --- a/softmmu/globals.c +++ b/softmmu/globals.c @@ -68,3 +68,4 @@ bool xen_domid_restrict; struct evtchn_backend_ops *xen_evtchn_ops; struct gnttab_backend_ops *xen_gnttab_ops; struct foreignmem_backend_ops *xen_foreignmem_ops; +struct xenstore_backend_ops *xen_xenstore_ops; --=20 2.39.0 From nobody Fri May 3 04:42:41 2024 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 ARC-Seal: i=1; a=rsa-sha256; t=1677771331; cv=none; d=zohomail.com; s=zohoarc; b=T4Mxa2Y/IKDGbDIqayn8sw6z+Gb6Q796LBbvAMBENF6KjAXTv4hj3PPZaY7ssK6NFONpjtyLBIkvLrXXZJAwpdjr0laGOuzAODwwqBCDSrOiwWFzUrWAS/w0AHJzDui0MoW0gyKi0nfzB0nXCHgm8NZY0timaV29lHgvz1lm2Dw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1677771331; 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=hO9boeY37hI66edoKGp/We1ozdCgGmP7lbWXFd91Vmg=; b=OlF2AVixVxgDSJ2utFoDkieMrfPxcu+tQ71w531ngXpfQ3DksLUtNjFwtJOFUgVeaWKhALEiOaipePpgOVCSB+3GU/xM5Jd+A8C0DyFJmS5obfvZTIGL1Mpso6py9Va1Wk8Pp7FTLXGhtWBEB8H/MzFdsPosTbRRfjOZN775neo= 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 Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1677771331046351.6357499567712; Thu, 2 Mar 2023 07:35:31 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.505050.777592 (Exim 4.92) (envelope-from ) id 1pXkxL-0001Y9-At; Thu, 02 Mar 2023 15:34:55 +0000 Received: by outflank-mailman (output) from mailman id 505050.777592; Thu, 02 Mar 2023 15:34:55 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxL-0001XE-0P; Thu, 02 Mar 2023 15:34:55 +0000 Received: by outflank-mailman (input) for mailman id 505050; Thu, 02 Mar 2023 15:34:53 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxJ-0001Jw-0C for xen-devel@lists.xenproject.org; Thu, 02 Mar 2023 15:34:53 +0000 Received: from casper.infradead.org (casper.infradead.org [2001:8b0:10b:1236::1]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id c2002737-b90f-11ed-a550-8520e6686977; Thu, 02 Mar 2023 16:34:49 +0100 (CET) Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by casper.infradead.org with esmtpsa (Exim 4.94.2 #2 (Red Hat Linux)) id 1pXkx4-002UNL-GG; Thu, 02 Mar 2023 15:34:39 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-004uzB-1f; Thu, 02 Mar 2023 15:34:38 +0000 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 X-Inumbo-ID: c2002737-b90f-11ed-a550-8520e6686977 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=hO9boeY37hI66edoKGp/We1ozdCgGmP7lbWXFd91Vmg=; b=XEw5/n84HVx/f6TpZQyopNgrJO jGzibgq8/nq92uNWAx2ml1yf0nb7kz9OG+jPVpu0zp+J+dCmFYpnnGtmtr43ouNrSDdku+iQXkFWJ BCI2FPJ2rh+NiRKrjSsSc10InnYmPq5EFD3Ou8R8SlkzBviIaehalog7XLvfoL0zmG8JffYffUhfT YRkIeFB8kgo1kAKwcRP8OkWIhea4tMbxuf8JEAcglYjWXT3Dc8uUOrq9QVVXHOb5BufSXXVGV+9W7 4gXnSSHgOsMPb0f6ODCoqsZ9aB6BeBipEeIU7Finm1wZHN7wBqZPyWrJuOrq4YI8FGnZ/KB+eW5AD GITmZOlA==; From: David Woodhouse To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , Stefano Stabellini , vikram.garhwal@amd.com, Anthony Perard , xen-devel@lists.xenproject.org Subject: [RFC PATCH v1 14/25] hw/xen: Move xenstore_store_pv_console_info to xen_console.c Date: Thu, 2 Mar 2023 15:34:24 +0000 Message-Id: <20230302153435.1170111-15-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230302153435.1170111-1-dwmw2@infradead.org> References: <20230302153435.1170111-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by casper.infradead.org. See http://www.infradead.org/rpr.html X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1677771331701100004 Content-Type: text/plain; charset="utf-8" From: David Woodhouse There's no need for this to be in the Xen accel code, and as we want to use the Xen console support with KVM-emulated Xen we'll want to have a platform-agnostic version of it. Make it use GString to build up the path while we're at it. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- accel/xen/xen-all.c | 61 ------------------------------------------- hw/char/xen_console.c | 45 +++++++++++++++++++++++++++++-- include/hw/xen/xen.h | 2 -- 3 files changed, 43 insertions(+), 65 deletions(-) diff --git a/accel/xen/xen-all.c b/accel/xen/xen-all.c index 425216230f..2d51c41e40 100644 --- a/accel/xen/xen-all.c +++ b/accel/xen/xen-all.c @@ -29,67 +29,6 @@ xc_interface *xen_xc; xenforeignmemory_handle *xen_fmem; xendevicemodel_handle *xen_dmod; =20 -static int store_dev_info(int domid, Chardev *cs, const char *string) -{ - struct xs_handle *xs =3D NULL; - char *path =3D NULL; - char *newpath =3D NULL; - char *pts =3D NULL; - int ret =3D -1; - - /* Only continue if we're talking to a pty. */ - if (!CHARDEV_IS_PTY(cs)) { - return 0; - } - pts =3D cs->filename + 4; - - /* We now have everything we need to set the xenstore entry. */ - xs =3D xs_open(0); - if (xs =3D=3D NULL) { - fprintf(stderr, "Could not contact XenStore\n"); - goto out; - } - - path =3D xs_get_domain_path(xs, domid); - if (path =3D=3D NULL) { - fprintf(stderr, "xs_get_domain_path() error\n"); - goto out; - } - newpath =3D realloc(path, (strlen(path) + strlen(string) + - strlen("/tty") + 1)); - if (newpath =3D=3D NULL) { - fprintf(stderr, "realloc error\n"); - goto out; - } - path =3D newpath; - - strcat(path, string); - strcat(path, "/tty"); - if (!xs_write(xs, XBT_NULL, path, pts, strlen(pts))) { - fprintf(stderr, "xs_write for '%s' fail", string); - goto out; - } - ret =3D 0; - -out: - free(path); - xs_close(xs); - - return ret; -} - -void xenstore_store_pv_console_info(int i, Chardev *chr) -{ - if (i =3D=3D 0) { - store_dev_info(xen_domid, chr, "/console"); - } else { - char buf[32]; - snprintf(buf, sizeof(buf), "/device/console/%d", i); - store_dev_info(xen_domid, chr, buf); - } -} - - static void xenstore_record_dm_state(const char *state) { struct xs_handle *xs; diff --git a/hw/char/xen_console.c b/hw/char/xen_console.c index ad8638a86d..c7a19c0e7c 100644 --- a/hw/char/xen_console.c +++ b/hw/char/xen_console.c @@ -173,6 +173,48 @@ static void xencons_send(struct XenConsole *con) =20 /* -------------------------------------------------------------------- */ =20 +static int store_con_info(struct XenConsole *con) +{ + Chardev *cs =3D qemu_chr_fe_get_driver(&con->chr); + char *pts =3D NULL; + char *dom_path; + GString *path; + int ret =3D -1; + + /* Only continue if we're talking to a pty. */ + if (!CHARDEV_IS_PTY(cs)) { + return 0; + } + pts =3D cs->filename + 4; + + dom_path =3D qemu_xen_xs_get_domain_path(xenstore, xen_domid); + if (!dom_path) { + return 0; + } + + path =3D g_string_new(dom_path); + free(dom_path); + + if (con->xendev.dev) { + g_string_append_printf(path, "/device/console/%d", con->xendev.dev= ); + } else { + g_string_append(path, "/console"); + } + g_string_append(path, "/tty"); + + if (xenstore_write_str(con->console, path->str, pts)) { + fprintf(stderr, "xenstore_write_str for '%s' fail", path->str); + goto out; + } + ret =3D 0; + +out: + g_string_free(path, true); + free(path); + + return ret; +} + static int con_init(struct XenLegacyDevice *xendev) { struct XenConsole *con =3D container_of(xendev, struct XenConsole, xen= dev); @@ -215,8 +257,7 @@ static int con_init(struct XenLegacyDevice *xendev) &error_abort); } =20 - xenstore_store_pv_console_info(con->xendev.dev, - qemu_chr_fe_get_driver(&con->chr)); + store_con_info(con); =20 out: g_free(type); diff --git a/include/hw/xen/xen.h b/include/hw/xen/xen.h index 03983939f9..56b1c2a827 100644 --- a/include/hw/xen/xen.h +++ b/include/hw/xen/xen.h @@ -39,8 +39,6 @@ int xen_is_pirq_msi(uint32_t msi_data); =20 qemu_irq *xen_interrupt_controller_init(void); =20 -void xenstore_store_pv_console_info(int i, Chardev *chr); - void xen_register_framebuffer(struct MemoryRegion *mr); =20 #endif /* QEMU_HW_XEN_H */ --=20 2.39.0 From nobody Fri May 3 04:42:41 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1677771341468254.87465497944925; Thu, 2 Mar 2023 07:35:41 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pXkxJ-0003oE-JM; Thu, 02 Mar 2023 10:34:53 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pXkxG-0003mq-2R for qemu-devel@nongnu.org; Thu, 02 Mar 2023 10:34:50 -0500 Received: from casper.infradead.org ([2001:8b0:10b:1236::1]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pXkxB-0001f1-4B for qemu-devel@nongnu.org; Thu, 02 Mar 2023 10:34:49 -0500 Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by casper.infradead.org with esmtpsa (Exim 4.94.2 #2 (Red Hat Linux)) id 1pXkx4-002UNM-I1; Thu, 02 Mar 2023 15:34:39 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-004uzF-1p; Thu, 02 Mar 2023 15:34:38 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=NsStsbU/wrYzcT7pqD6BfZJ/9CY8QxWSUO7MAruBqXQ=; b=SVOthX9RI/7oAIXMFIA0zNaRPr UvaAcMmuLtQcin9lHMzeMeGPWpqcB4ypj6KWx9bdn7eBtBYK4+Ex0tvX2vrd0zuDQUMkU69LQ2SAV dzUYdCMQSjsmZr7cpMg2trM6ZMw8nGG0M9zI0UXhyHkfrmAbOQQbxIQ+feJnk3V5SRmDKR6uAF+6D y5/roN1G3IYdY3REGr1BIUfu72Vb3r6TfppOKKFMRufu8I9494Vjj/ETN5DAGTdaSti7Vkk0WbWN/ /XnSMg1dvMMuMX5Mh7mUO/B0eyMuHP/OEBSYDH33O6gVMVKSXsqlAFCZ5bpUUPZ2fo3/ly2um1W2k lVkCg1Bw==; From: David Woodhouse To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , Stefano Stabellini , vikram.garhwal@amd.com, Anthony Perard , xen-devel@lists.xenproject.org Subject: [RFC PATCH v1 15/25] hw/xen: Use XEN_PAGE_SIZE in PV backend drivers Date: Thu, 2 Mar 2023 15:34:25 +0000 Message-Id: <20230302153435.1170111-16-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230302153435.1170111-1-dwmw2@infradead.org> References: <20230302153435.1170111-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-SRS-Rewrite: SMTP reverse-path rewritten from by casper.infradead.org. See http://www.infradead.org/rpr.html Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: none client-ip=2001:8b0:10b:1236::1; envelope-from=BATV+a1ad97f05afd282148df+7130+infradead.org+dwmw2@casper.srs.infradead.org; helo=casper.infradead.org X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1677771343777100003 Content-Type: text/plain; charset="utf-8" From: David Woodhouse XC_PAGE_SIZE comes from the actual Xen libraries, while XEN_PAGE_SIZE is provided by QEMU itself in xen_backend_ops.h. For backends which may be built for emulation mode, use the latter. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- hw/block/dataplane/xen-block.c | 8 ++++---- hw/display/xenfb.c | 12 ++++++------ hw/net/xen_nic.c | 12 ++++++------ hw/usb/xen-usb.c | 8 ++++---- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/hw/block/dataplane/xen-block.c b/hw/block/dataplane/xen-block.c index e55b713002..8322a1de82 100644 --- a/hw/block/dataplane/xen-block.c +++ b/hw/block/dataplane/xen-block.c @@ -101,9 +101,9 @@ static XenBlockRequest *xen_block_start_request(XenBloc= kDataPlane *dataplane) * re-use requests, allocate the memory once here. It will be freed * xen_block_dataplane_destroy() when the request list is freed. */ - request->buf =3D qemu_memalign(XC_PAGE_SIZE, + request->buf =3D qemu_memalign(XEN_PAGE_SIZE, BLKIF_MAX_SEGMENTS_PER_REQUEST * - XC_PAGE_SIZE); + XEN_PAGE_SIZE); dataplane->requests_total++; qemu_iovec_init(&request->v, 1); } else { @@ -185,7 +185,7 @@ static int xen_block_parse_request(XenBlockRequest *req= uest) goto err; } if (request->req.seg[i].last_sect * dataplane->sector_size >=3D - XC_PAGE_SIZE) { + XEN_PAGE_SIZE) { error_report("error: page crossing"); goto err; } @@ -740,7 +740,7 @@ void xen_block_dataplane_start(XenBlockDataPlane *datap= lane, =20 dataplane->protocol =3D protocol; =20 - ring_size =3D XC_PAGE_SIZE * dataplane->nr_ring_ref; + ring_size =3D XEN_PAGE_SIZE * dataplane->nr_ring_ref; switch (dataplane->protocol) { case BLKIF_PROTOCOL_NATIVE: { diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c index 2c4016fcbd..0074a9b6f8 100644 --- a/hw/display/xenfb.c +++ b/hw/display/xenfb.c @@ -489,13 +489,13 @@ static int xenfb_map_fb(struct XenFB *xenfb) } =20 if (xenfb->pixels) { - munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE); + munmap(xenfb->pixels, xenfb->fbpages * XEN_PAGE_SIZE); xenfb->pixels =3D NULL; } =20 - xenfb->fbpages =3D DIV_ROUND_UP(xenfb->fb_len, XC_PAGE_SIZE); + xenfb->fbpages =3D DIV_ROUND_UP(xenfb->fb_len, XEN_PAGE_SIZE); n_fbdirs =3D xenfb->fbpages * mode / 8; - n_fbdirs =3D DIV_ROUND_UP(n_fbdirs, XC_PAGE_SIZE); + n_fbdirs =3D DIV_ROUND_UP(n_fbdirs, XEN_PAGE_SIZE); =20 pgmfns =3D g_new0(xen_pfn_t, n_fbdirs); fbmfns =3D g_new0(xen_pfn_t, xenfb->fbpages); @@ -528,8 +528,8 @@ static int xenfb_configure_fb(struct XenFB *xenfb, size= _t fb_len_lim, { size_t mfn_sz =3D sizeof_field(struct xenfb_page, pd[0]); size_t pd_len =3D sizeof_field(struct xenfb_page, pd) / mfn_sz; - size_t fb_pages =3D pd_len * XC_PAGE_SIZE / mfn_sz; - size_t fb_len_max =3D fb_pages * XC_PAGE_SIZE; + size_t fb_pages =3D pd_len * XEN_PAGE_SIZE / mfn_sz; + size_t fb_len_max =3D fb_pages * XEN_PAGE_SIZE; int max_width, max_height; =20 if (fb_len_lim > fb_len_max) { @@ -930,7 +930,7 @@ static void fb_disconnect(struct XenLegacyDevice *xende= v) * instead. This releases the guest pages and keeps qemu happy. */ qemu_xen_foreignmem_unmap(fb->pixels, fb->fbpages); - fb->pixels =3D mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE, + fb->pixels =3D mmap(fb->pixels, fb->fbpages * XEN_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); if (fb->pixels =3D=3D MAP_FAILED) { diff --git a/hw/net/xen_nic.c b/hw/net/xen_nic.c index 166d03787d..9bbf6599fc 100644 --- a/hw/net/xen_nic.c +++ b/hw/net/xen_nic.c @@ -145,7 +145,7 @@ static void net_tx_packets(struct XenNetDev *netdev) continue; } =20 - if ((txreq.offset + txreq.size) > XC_PAGE_SIZE) { + if ((txreq.offset + txreq.size) > XEN_PAGE_SIZE) { xen_pv_printf(&netdev->xendev, 0, "error: page crossing\n"= ); net_tx_error(netdev, &txreq, rc); continue; @@ -171,7 +171,7 @@ static void net_tx_packets(struct XenNetDev *netdev) if (txreq.flags & NETTXF_csum_blank) { /* have read-only mapping -> can't fill checksum in-place = */ if (!tmpbuf) { - tmpbuf =3D g_malloc(XC_PAGE_SIZE); + tmpbuf =3D g_malloc(XEN_PAGE_SIZE); } memcpy(tmpbuf, page + txreq.offset, txreq.size); net_checksum_calculate(tmpbuf, txreq.size, CSUM_ALL); @@ -243,9 +243,9 @@ static ssize_t net_rx_packet(NetClientState *nc, const = uint8_t *buf, size_t size if (rc =3D=3D rp || RING_REQUEST_CONS_OVERFLOW(&netdev->rx_ring, rc)) { return 0; } - if (size > XC_PAGE_SIZE - NET_IP_ALIGN) { + if (size > XEN_PAGE_SIZE - NET_IP_ALIGN) { xen_pv_printf(&netdev->xendev, 0, "packet too big (%lu > %ld)", - (unsigned long)size, XC_PAGE_SIZE - NET_IP_ALIGN); + (unsigned long)size, XEN_PAGE_SIZE - NET_IP_ALIGN); return -1; } =20 @@ -348,8 +348,8 @@ static int net_connect(struct XenLegacyDevice *xendev) netdev->txs =3D NULL; return -1; } - BACK_RING_INIT(&netdev->tx_ring, netdev->txs, XC_PAGE_SIZE); - BACK_RING_INIT(&netdev->rx_ring, netdev->rxs, XC_PAGE_SIZE); + BACK_RING_INIT(&netdev->tx_ring, netdev->txs, XEN_PAGE_SIZE); + BACK_RING_INIT(&netdev->rx_ring, netdev->rxs, XEN_PAGE_SIZE); =20 xen_be_bind_evtchn(&netdev->xendev); =20 diff --git a/hw/usb/xen-usb.c b/hw/usb/xen-usb.c index a770a64cb4..66cb3f7c24 100644 --- a/hw/usb/xen-usb.c +++ b/hw/usb/xen-usb.c @@ -161,7 +161,7 @@ static int usbback_gnttab_map(struct usbback_req *usbba= ck_req) =20 for (i =3D 0; i < nr_segs; i++) { if ((unsigned)usbback_req->req.seg[i].offset + - (unsigned)usbback_req->req.seg[i].length > XC_PAGE_SIZE) { + (unsigned)usbback_req->req.seg[i].length > XEN_PAGE_SIZE) { xen_pv_printf(xendev, 0, "segment crosses page boundary\n"); return -EINVAL; } @@ -185,7 +185,7 @@ static int usbback_gnttab_map(struct usbback_req *usbba= ck_req) =20 for (i =3D 0; i < usbback_req->nr_buffer_segs; i++) { seg =3D usbback_req->req.seg + i; - addr =3D usbback_req->buffer + i * XC_PAGE_SIZE + seg->offset; + addr =3D usbback_req->buffer + i * XEN_PAGE_SIZE + seg->offset; qemu_iovec_add(&usbback_req->packet.iov, addr, seg->length); } } @@ -902,8 +902,8 @@ static int usbback_connect(struct XenLegacyDevice *xend= ev) usbif->conn_ring_ref =3D conn_ring_ref; urb_sring =3D usbif->urb_sring; conn_sring =3D usbif->conn_sring; - BACK_RING_INIT(&usbif->urb_ring, urb_sring, XC_PAGE_SIZE); - BACK_RING_INIT(&usbif->conn_ring, conn_sring, XC_PAGE_SIZE); + BACK_RING_INIT(&usbif->urb_ring, urb_sring, XEN_PAGE_SIZE); + BACK_RING_INIT(&usbif->conn_ring, conn_sring, XEN_PAGE_SIZE); =20 xen_be_bind_evtchn(xendev); =20 --=20 2.39.0 From nobody Fri May 3 04:42:41 2024 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 ARC-Seal: i=1; a=rsa-sha256; t=1677771331; cv=none; d=zohomail.com; s=zohoarc; b=LS3EOEyiFnRm5ve0b2yOCfy7fBIsB+YdIrXoowJTQzf2CmnuLj/Ff7WJGYr3O8Wyjp7h1HSvZ3Qrx2nbRaiYsd7HaWtbiOWZZ4FgHG9A/Z3ZCsqOwlnMCBWvaCg4Vaej13csvC5LkbWa4svo/hy8C6blyhCKKfP4SSKcB7aWkKI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1677771331; 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=n8LLYMrAYAzp3JCDi83tNu3v9ZoLlZOiuyoSpRezh9U=; b=llVZKYjEIdZw8ept9Uob4DU2DoCsJ2F+T/OWMo+PsiWW9DqNUdmc7oapzvXXyj0bW90kXnniHGDLjquOcvdlbY8y6rL2rJA//LTcYrBop/8sf7jRYX+2Jgu30L63XNyoy+naoJNca74JSdhANG2DXevdp6PTqdgMeSGvNuwwtz8= 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 Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1677771331115440.98380373116686; Thu, 2 Mar 2023 07:35:31 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.505056.777642 (Exim 4.92) (envelope-from ) id 1pXkxP-0002k4-5Q; Thu, 02 Mar 2023 15:34:59 +0000 Received: by outflank-mailman (output) from mailman id 505056.777642; Thu, 02 Mar 2023 15:34:59 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxO-0002h9-M0; Thu, 02 Mar 2023 15:34:58 +0000 Received: by outflank-mailman (input) for mailman id 505056; Thu, 02 Mar 2023 15:34:56 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxM-0001Jv-5b for xen-devel@lists.xenproject.org; Thu, 02 Mar 2023 15:34:56 +0000 Received: from desiato.infradead.org (desiato.infradead.org [2001:8b0:10b:1:d65d:64ff:fe57:4e05]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id c2cf51aa-b90f-11ed-96ad-2f268f93b82a; Thu, 02 Mar 2023 16:34:49 +0100 (CET) Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by desiato.infradead.org with esmtpsa (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-00FL3k-2L; Thu, 02 Mar 2023 15:34:41 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-004uzJ-1z; Thu, 02 Mar 2023 15:34:38 +0000 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 X-Inumbo-ID: c2cf51aa-b90f-11ed-96ad-2f268f93b82a DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=n8LLYMrAYAzp3JCDi83tNu3v9ZoLlZOiuyoSpRezh9U=; b=hbNt5x2HZSwFDzDoMeCTo7KHqy hvUNdOYMbYAvX1tdmAeimolbpy8c0iQ4O6rivnIrLKZCuoPZOSBpksukOo598V0UFGtf8011+G5DE G2tOuvaiUEKdQmZSPGYzBO8Ewd1XAVdvWhdjtFf/jGxl0SnDV03hUUsVyPN0Zo4AZzgBugN9az7Gc 7ZGVXFjDSqzfXAqYXHDVBz6PfA18iLoydLUWAQO9d84Q5FbHU/5yJ9xQPTWFk974Rh4dqD3u6euqy 9Z3OQ6YyHTfkajon+fO/fH5STM2GcoRo6pEhA5xKAyVhi1Zh9+cGcep+hrIeD0xoYxU1r8pvxjq+i btkx84Jg==; From: David Woodhouse To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , Stefano Stabellini , vikram.garhwal@amd.com, Anthony Perard , xen-devel@lists.xenproject.org Subject: [RFC PATCH v1 16/25] hw/xen: Rename xen_common.h to xen_native.h Date: Thu, 2 Mar 2023 15:34:26 +0000 Message-Id: <20230302153435.1170111-17-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230302153435.1170111-1-dwmw2@infradead.org> References: <20230302153435.1170111-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by desiato.infradead.org. See http://www.infradead.org/rpr.html X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1677771331719100008 Content-Type: text/plain; charset="utf-8" From: David Woodhouse This header is now only for native Xen code, not PV backends that may be used in Xen emulation. Since the toolstack libraries may depend on the specific version of Xen headers that they pull in (and will set the __XEN_TOOLS__ macro to enable internal definitions that they depend on), the rule is that xen_native.h (and thus the toolstack library headers) must be included *before* any of the headers in include/hw/xen/interface. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- accel/xen/xen-all.c | 1 + hw/9pfs/xen-9p-backend.c | 1 + hw/block/dataplane/xen-block.c | 3 ++- hw/block/xen-block.c | 1 - hw/i386/pc_piix.c | 4 ++-- hw/i386/xen/xen-hvm.c | 11 +++++----- hw/i386/xen/xen-mapcache.c | 2 +- hw/i386/xen/xen_platform.c | 7 +++--- hw/xen/trace-events | 2 +- hw/xen/xen-operations.c | 2 +- hw/xen/xen_pt.c | 2 +- hw/xen/xen_pt.h | 2 +- hw/xen/xen_pt_config_init.c | 2 +- hw/xen/xen_pt_msi.c | 4 ++-- include/hw/xen/xen.h | 22 ++++++++++++------- include/hw/xen/{xen_common.h =3D> xen_native.h} | 10 ++++++--- include/hw/xen/xen_pvdev.h | 3 ++- 17 files changed, 47 insertions(+), 32 deletions(-) rename include/hw/xen/{xen_common.h =3D> xen_native.h} (98%) diff --git a/accel/xen/xen-all.c b/accel/xen/xen-all.c index 2d51c41e40..00221e23c5 100644 --- a/accel/xen/xen-all.c +++ b/accel/xen/xen-all.c @@ -12,6 +12,7 @@ #include "qemu/error-report.h" #include "qemu/module.h" #include "qapi/error.h" +#include "hw/xen/xen_native.h" #include "hw/xen/xen-legacy-backend.h" #include "hw/xen/xen_pt.h" #include "chardev/char.h" diff --git a/hw/9pfs/xen-9p-backend.c b/hw/9pfs/xen-9p-backend.c index d8bb0e847c..74f3a05f88 100644 --- a/hw/9pfs/xen-9p-backend.c +++ b/hw/9pfs/xen-9p-backend.c @@ -22,6 +22,7 @@ #include "qemu/config-file.h" #include "qemu/main-loop.h" #include "qemu/option.h" +#include "qemu/iov.h" #include "fsdev/qemu-fsdev.h" =20 #define VERSIONS "1" diff --git a/hw/block/dataplane/xen-block.c b/hw/block/dataplane/xen-block.c index 8322a1de82..734da42ea7 100644 --- a/hw/block/dataplane/xen-block.c +++ b/hw/block/dataplane/xen-block.c @@ -23,8 +23,9 @@ #include "qemu/main-loop.h" #include "qemu/memalign.h" #include "qapi/error.h" -#include "hw/xen/xen_common.h" +#include "hw/xen/xen.h" #include "hw/block/xen_blkif.h" +#include "hw/xen/interface/io/ring.h" #include "sysemu/block-backend.h" #include "sysemu/iothread.h" #include "xen-block.h" diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c index 345b284d70..87299615e3 100644 --- a/hw/block/xen-block.c +++ b/hw/block/xen-block.c @@ -19,7 +19,6 @@ #include "qapi/qmp/qdict.h" #include "qapi/qmp/qstring.h" #include "qom/object_interfaces.h" -#include "hw/xen/xen_common.h" #include "hw/block/xen_blkif.h" #include "hw/qdev-properties.h" #include "hw/xen/xen-block.h" diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 126b6c11df..e0f768b664 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -47,8 +47,6 @@ #include "hw/kvm/clock.h" #include "hw/sysbus.h" #include "hw/i2c/smbus_eeprom.h" -#include "hw/xen/xen-x86.h" -#include "hw/xen/xen.h" #include "exec/memory.h" #include "hw/acpi/acpi.h" #include "hw/acpi/piix4.h" @@ -60,6 +58,8 @@ #include #include "hw/xen/xen_pt.h" #endif +#include "hw/xen/xen-x86.h" +#include "hw/xen/xen.h" #include "migration/global_state.h" #include "migration/misc.h" #include "sysemu/numa.h" diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c index cb1d24f592..56641a550e 100644 --- a/hw/i386/xen/xen-hvm.c +++ b/hw/i386/xen/xen-hvm.c @@ -18,7 +18,7 @@ #include "hw/irq.h" #include "hw/hw.h" #include "hw/i386/apic-msidef.h" -#include "hw/xen/xen_common.h" +#include "hw/xen/xen_native.h" #include "hw/xen/xen-legacy-backend.h" #include "hw/xen/xen-bus.h" #include "hw/xen/xen-x86.h" @@ -52,10 +52,11 @@ static bool xen_in_migration; =20 /* Compatibility with older version */ =20 -/* This allows QEMU to build on a system that has Xen 4.5 or earlier - * installed. This here (not in hw/xen/xen_common.h) because xen/hvm/iore= q.h - * needs to be included before this block and hw/xen/xen_common.h needs to - * be included before xen/hvm/ioreq.h +/* + * This allows QEMU to build on a system that has Xen 4.5 or earlier insta= lled. + * This is here (not in hw/xen/xen_native.h) because xen/hvm/ioreq.h needs= to + * be included before this block and hw/xen/xen_native.h needs to be inclu= ded + * before xen/hvm/ioreq.h */ #ifndef IOREQ_TYPE_VMWARE_PORT #define IOREQ_TYPE_VMWARE_PORT 3 diff --git a/hw/i386/xen/xen-mapcache.c b/hw/i386/xen/xen-mapcache.c index 1d0879d234..f7d974677d 100644 --- a/hw/i386/xen/xen-mapcache.c +++ b/hw/i386/xen/xen-mapcache.c @@ -14,7 +14,7 @@ =20 #include =20 -#include "hw/xen/xen-legacy-backend.h" +#include "hw/xen/xen_native.h" #include "qemu/bitmap.h" =20 #include "sysemu/runstate.h" diff --git a/hw/i386/xen/xen_platform.c b/hw/i386/xen/xen_platform.c index 539f7da374..57f1d742c1 100644 --- a/hw/i386/xen/xen_platform.c +++ b/hw/i386/xen/xen_platform.c @@ -28,7 +28,6 @@ #include "hw/ide/pci.h" #include "hw/pci/pci.h" #include "migration/vmstate.h" -#include "hw/xen/xen.h" #include "net/net.h" #include "trace.h" #include "sysemu/xen.h" @@ -38,10 +37,12 @@ #include "qom/object.h" =20 #ifdef CONFIG_XEN -#include "hw/xen/xen_common.h" -#include "hw/xen/xen-legacy-backend.h" +#include "hw/xen/xen_native.h" #endif =20 +/* The rule is that xen_native.h must come first */ +#include "hw/xen/xen.h" + //#define DEBUG_PLATFORM =20 #ifdef DEBUG_PLATFORM diff --git a/hw/xen/trace-events b/hw/xen/trace-events index 3da3fd8348..55c9e1df68 100644 --- a/hw/xen/trace-events +++ b/hw/xen/trace-events @@ -1,6 +1,6 @@ # See docs/devel/tracing.rst for syntax documentation. =20 -# ../../include/hw/xen/xen_common.h +# ../../include/hw/xen/xen_native.h xen_default_ioreq_server(void) "" xen_ioreq_server_create(uint32_t id) "id: %u" xen_ioreq_server_destroy(uint32_t id) "id: %u" diff --git a/hw/xen/xen-operations.c b/hw/xen/xen-operations.c index 80c8fbede6..2b229f722f 100644 --- a/hw/xen/xen-operations.c +++ b/hw/xen/xen-operations.c @@ -13,8 +13,8 @@ #include "qemu/uuid.h" #include "qapi/error.h" =20 +#include "hw/xen/xen_native.h" #include "hw/xen/xen_backend_ops.h" -#include "hw/xen/xen_common.h" =20 /* * If we have new enough libxenctrl then we do not want/need these compat diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index 8db0532632..b705aff724 100644 --- a/hw/xen/xen_pt.c +++ b/hw/xen/xen_pt.c @@ -59,9 +59,9 @@ #include "hw/pci/pci.h" #include "hw/qdev-properties.h" #include "hw/qdev-properties-system.h" +#include "xen_pt.h" #include "hw/xen/xen.h" #include "hw/xen/xen-legacy-backend.h" -#include "xen_pt.h" #include "qemu/range.h" =20 static bool has_igd_gfx_passthru; diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h index cf10fc7bbf..27fc7bb585 100644 --- a/hw/xen/xen_pt.h +++ b/hw/xen/xen_pt.h @@ -1,7 +1,7 @@ #ifndef XEN_PT_H #define XEN_PT_H =20 -#include "hw/xen/xen_common.h" +#include "hw/xen/xen_native.h" #include "xen-host-pci-device.h" #include "qom/object.h" =20 diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c index cde898b744..0cd9fbd22c 100644 --- a/hw/xen/xen_pt_config_init.c +++ b/hw/xen/xen_pt_config_init.c @@ -15,8 +15,8 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/timer.h" -#include "hw/xen/xen-legacy-backend.h" #include "xen_pt.h" +#include "hw/xen/xen-legacy-backend.h" =20 #define XEN_PT_MERGE_VALUE(value, data, val_mask) \ (((value) & (val_mask)) | ((data) & ~(val_mask))) diff --git a/hw/xen/xen_pt_msi.c b/hw/xen/xen_pt_msi.c index b71563f98a..09cca4eecb 100644 --- a/hw/xen/xen_pt_msi.c +++ b/hw/xen/xen_pt_msi.c @@ -11,9 +11,9 @@ =20 #include "qemu/osdep.h" =20 -#include "hw/xen/xen-legacy-backend.h" -#include "xen_pt.h" #include "hw/i386/apic-msidef.h" +#include "xen_pt.h" +#include "hw/xen/xen-legacy-backend.h" =20 =20 #define XEN_PT_AUTO_ASSIGN -1 diff --git a/include/hw/xen/xen.h b/include/hw/xen/xen.h index 56b1c2a827..2bd8ec742d 100644 --- a/include/hw/xen/xen.h +++ b/include/hw/xen/xen.h @@ -8,15 +8,21 @@ #define QEMU_HW_XEN_H =20 /* - * As a temporary measure while the headers are being untangled, define - * __XEN_TOOLS__ here before any Xen headers are included. Otherwise, if - * the Xen toolstack library headers are later included, they will find - * some of the "internal" definitions missing and the build will fail. In - * later commits, we'll end up with a rule that the native libraries have - * to be included first, which will ensure that the libraries get the - * version of Xen libraries that they expect. + * C files using Xen toolstack libraries will have included those headers + * already via xen_native.h, and having __XEM_TOOLS__ defined will have + * automatically set __XEN_INTERFACE_VERSION__ to the latest supported + * by the *system* Xen headers which were transitively included. + * + * C files which are part of the internal emulation, and which did not + * include xen_native.h, may need this defined so that the Xen headers + * imported to include/hw/xen/interface/ will expose the appropriate API + * version. + * + * This is why there's a rule that xen_native.h must be included first. */ -#define __XEN_TOOLS__ 1 +#ifndef __XEN_INTERFACE_VERSION__ +#define __XEN_INTERFACE_VERSION__ 0x00040e00 +#endif =20 #include "exec/cpu-common.h" =20 diff --git a/include/hw/xen/xen_common.h b/include/hw/xen/xen_native.h similarity index 98% rename from include/hw/xen/xen_common.h rename to include/hw/xen/xen_native.h index 7edcf3eb25..6bcc83baf9 100644 --- a/include/hw/xen/xen_common.h +++ b/include/hw/xen/xen_native.h @@ -1,5 +1,9 @@ -#ifndef QEMU_HW_XEN_COMMON_H -#define QEMU_HW_XEN_COMMON_H +#ifndef QEMU_HW_XEN_NATIVE_H +#define QEMU_HW_XEN_NATIVE_H + +#ifdef __XEN_INTERFACE_VERSION__ +#error In Xen native files, include xen_native.h before other Xen headers +#endif =20 /* * If we have new enough libxenctrl then we do not want/need these compat @@ -622,4 +626,4 @@ static inline int xen_set_ioreq_server_state(domid_t do= m, =20 #endif =20 -#endif /* QEMU_HW_XEN_COMMON_H */ +#endif /* QEMU_HW_XEN_NATIVE_H */ diff --git a/include/hw/xen/xen_pvdev.h b/include/hw/xen/xen_pvdev.h index d8eea353b8..ddad4b9f36 100644 --- a/include/hw/xen/xen_pvdev.h +++ b/include/hw/xen/xen_pvdev.h @@ -1,8 +1,9 @@ #ifndef QEMU_HW_XEN_PVDEV_H #define QEMU_HW_XEN_PVDEV_H =20 +#include "hw/qdev-core.h" #include "hw/xen/xen_backend_ops.h" -#include "hw/xen/xen_common.h" + /* ------------------------------------------------------------- */ =20 #define XEN_BUFSIZE 1024 --=20 2.39.0 From nobody Fri May 3 04:42:41 2024 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 ARC-Seal: i=1; a=rsa-sha256; t=1677771319; cv=none; d=zohomail.com; s=zohoarc; b=Wxa7AXOjkEEPfOdtU4PteJVaONIcZDL57gptFvUHecMMzKPzRB4KSGSHI/b0Ph57PYqDVmDA7sOwq9FgMDk8JsRx1XUlT/TuU7CVg9VjpF/hvYtDsbt/J1hommph8SC0JPCWE045B25EPtDPpNoijpJGz3KuTcOf31UjLxOFhwI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1677771319; 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=chJB4LTr6zPMlbhOF6PfeBpSzwoNMPhcrFtbZG5ajq4=; b=myPrJzLedhUGPofCJNW/s4R9q24V8F3e6CUijujIajfU3TDdkwvdPT2rVd32+sazM3LLG3ga/6ygfKqAVnTvNYP7hpPdw+gh4i/rLZwgokh6gJYKbtSDMm7fFrBuoWJMsnQ3T4udL0VEjjO/54Gg1DWbpVtHwwM3k7a/RTaScHo= 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 Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1677771319610678.2980423559854; Thu, 2 Mar 2023 07:35:19 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.505057.777655 (Exim 4.92) (envelope-from ) id 1pXkxQ-0003CV-LK; Thu, 02 Mar 2023 15:35:00 +0000 Received: by outflank-mailman (output) from mailman id 505057.777655; Thu, 02 Mar 2023 15:35:00 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxQ-000398-5m; Thu, 02 Mar 2023 15:35:00 +0000 Received: by outflank-mailman (input) for mailman id 505057; Thu, 02 Mar 2023 15:34:57 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxM-0001Jw-Md for xen-devel@lists.xenproject.org; Thu, 02 Mar 2023 15:34:56 +0000 Received: from desiato.infradead.org (desiato.infradead.org [2001:8b0:10b:1:d65d:64ff:fe57:4e05]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id c2b4ac21-b90f-11ed-a550-8520e6686977; Thu, 02 Mar 2023 16:34:49 +0100 (CET) Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by desiato.infradead.org with esmtpsa (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-00FL3l-2U; Thu, 02 Mar 2023 15:34:39 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-004uzN-29; Thu, 02 Mar 2023 15:34:38 +0000 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 X-Inumbo-ID: c2b4ac21-b90f-11ed-a550-8520e6686977 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=chJB4LTr6zPMlbhOF6PfeBpSzwoNMPhcrFtbZG5ajq4=; b=ZNnYEgUAD8ML+7lcO6KjFLOkLJ iM1JOIPzKMyquJ9dpU2yVBq3u2zQi5N5QABGgIIk8HZtsKsBjJVT0e3Kf10ocN3ijXaaVl8nXWWRW K0G32lZuLLuP7CZwsoYzA+/mSscBGHUTsmGb+JFNpgem/zot1rFVPEefZh0eF1P0Tv2mRTdlJoBb/ +oudgciQKCWJNcxTTd1NsaVVVDKGfV6+aR3gTGw7QB1X2GxySRI+XgotRIi1x+PKFPeS5pqVfrCTa 2GWoZdqPCjFBnCWeqivNzjkt3vYqzYkZJprNnyjFGOFruyZ+XqtY1IG11rx/TTUTuD93sgEBkkDTj k2UndtgA==; From: David Woodhouse To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , Stefano Stabellini , vikram.garhwal@amd.com, Anthony Perard , xen-devel@lists.xenproject.org Subject: [RFC PATCH v1 17/25] hw/xen: Build PV backend drivers for CONFIG_XEN_BUS Date: Thu, 2 Mar 2023 15:34:27 +0000 Message-Id: <20230302153435.1170111-18-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230302153435.1170111-1-dwmw2@infradead.org> References: <20230302153435.1170111-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by desiato.infradead.org. See http://www.infradead.org/rpr.html X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1677771321523100003 Content-Type: text/plain; charset="utf-8" From: David Woodhouse Now that we have the redirectable Xen backend operations we can build the PV backends even without the Xen libraries. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- hw/9pfs/meson.build | 2 +- hw/block/dataplane/meson.build | 2 +- hw/block/meson.build | 2 +- hw/char/meson.build | 2 +- hw/display/meson.build | 2 +- hw/usb/meson.build | 2 +- hw/xen/meson.build | 5 ++++- 7 files changed, 10 insertions(+), 7 deletions(-) diff --git a/hw/9pfs/meson.build b/hw/9pfs/meson.build index 12443b6ad5..fd37b7a02d 100644 --- a/hw/9pfs/meson.build +++ b/hw/9pfs/meson.build @@ -15,7 +15,7 @@ fs_ss.add(files( )) fs_ss.add(when: 'CONFIG_LINUX', if_true: files('9p-util-linux.c')) fs_ss.add(when: 'CONFIG_DARWIN', if_true: files('9p-util-darwin.c')) -fs_ss.add(when: 'CONFIG_XEN', if_true: files('xen-9p-backend.c')) +fs_ss.add(when: 'CONFIG_XEN_BUS', if_true: files('xen-9p-backend.c')) softmmu_ss.add_all(when: 'CONFIG_FSDEV_9P', if_true: fs_ss) =20 specific_ss.add(when: 'CONFIG_VIRTIO_9P', if_true: files('virtio-9p-device= .c')) diff --git a/hw/block/dataplane/meson.build b/hw/block/dataplane/meson.build index 12c6a264f1..78d7ac1a11 100644 --- a/hw/block/dataplane/meson.build +++ b/hw/block/dataplane/meson.build @@ -1,2 +1,2 @@ specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c')) -specific_ss.add(when: 'CONFIG_XEN', if_true: files('xen-block.c')) +specific_ss.add(when: 'CONFIG_XEN_BUS', if_true: files('xen-block.c')) diff --git a/hw/block/meson.build b/hw/block/meson.build index b434d5654c..cc2a75cc50 100644 --- a/hw/block/meson.build +++ b/hw/block/meson.build @@ -14,7 +14,7 @@ softmmu_ss.add(when: 'CONFIG_PFLASH_CFI02', if_true: file= s('pflash_cfi02.c')) softmmu_ss.add(when: 'CONFIG_SSI_M25P80', if_true: files('m25p80.c')) softmmu_ss.add(when: 'CONFIG_SSI_M25P80', if_true: files('m25p80_sfdp.c')) softmmu_ss.add(when: 'CONFIG_SWIM', if_true: files('swim.c')) -softmmu_ss.add(when: 'CONFIG_XEN', if_true: files('xen-block.c')) +softmmu_ss.add(when: 'CONFIG_XEN_BUS', if_true: files('xen-block.c')) softmmu_ss.add(when: 'CONFIG_TC58128', if_true: files('tc58128.c')) =20 specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c', = 'virtio-blk-common.c')) diff --git a/hw/char/meson.build b/hw/char/meson.build index 7b594f51b8..e02c60dd54 100644 --- a/hw/char/meson.build +++ b/hw/char/meson.build @@ -18,7 +18,7 @@ softmmu_ss.add(when: 'CONFIG_SERIAL_PCI', if_true: files(= 'serial-pci.c')) softmmu_ss.add(when: 'CONFIG_SERIAL_PCI_MULTI', if_true: files('serial-pci= -multi.c')) softmmu_ss.add(when: 'CONFIG_SHAKTI_UART', if_true: files('shakti_uart.c')) softmmu_ss.add(when: 'CONFIG_VIRTIO_SERIAL', if_true: files('virtio-consol= e.c')) -softmmu_ss.add(when: 'CONFIG_XEN', if_true: files('xen_console.c')) +softmmu_ss.add(when: 'CONFIG_XEN_BUS', if_true: files('xen_console.c')) softmmu_ss.add(when: 'CONFIG_XILINX', if_true: files('xilinx_uartlite.c')) =20 softmmu_ss.add(when: 'CONFIG_AVR_USART', if_true: files('avr_usart.c')) diff --git a/hw/display/meson.build b/hw/display/meson.build index f470179122..4191694380 100644 --- a/hw/display/meson.build +++ b/hw/display/meson.build @@ -14,7 +14,7 @@ softmmu_ss.add(when: 'CONFIG_PL110', if_true: files('pl11= 0.c')) softmmu_ss.add(when: 'CONFIG_SII9022', if_true: files('sii9022.c')) softmmu_ss.add(when: 'CONFIG_SSD0303', if_true: files('ssd0303.c')) softmmu_ss.add(when: 'CONFIG_SSD0323', if_true: files('ssd0323.c')) -softmmu_ss.add(when: 'CONFIG_XEN', if_true: files('xenfb.c')) +softmmu_ss.add(when: 'CONFIG_XEN_BUS', if_true: files('xenfb.c')) =20 softmmu_ss.add(when: 'CONFIG_VGA_PCI', if_true: files('vga-pci.c')) softmmu_ss.add(when: 'CONFIG_VGA_ISA', if_true: files('vga-isa.c')) diff --git a/hw/usb/meson.build b/hw/usb/meson.build index bdf34cbd3e..599dc24f0d 100644 --- a/hw/usb/meson.build +++ b/hw/usb/meson.build @@ -84,6 +84,6 @@ if libusb.found() hw_usb_modules +=3D {'host': usbhost_ss} endif =20 -softmmu_ss.add(when: ['CONFIG_USB', 'CONFIG_XEN', libusb], if_true: files(= 'xen-usb.c')) +softmmu_ss.add(when: ['CONFIG_USB', 'CONFIG_XEN_BUS', libusb], if_true: fi= les('xen-usb.c')) =20 modules +=3D { 'hw-usb': hw_usb_modules } diff --git a/hw/xen/meson.build b/hw/xen/meson.build index f195bbd25c..19c6aabc7c 100644 --- a/hw/xen/meson.build +++ b/hw/xen/meson.build @@ -1,10 +1,13 @@ -softmmu_ss.add(when: ['CONFIG_XEN', xen], if_true: files( +softmmu_ss.add(when: ['CONFIG_XEN_BUS'], if_true: files( 'xen-backend.c', 'xen-bus-helper.c', 'xen-bus.c', 'xen-legacy-backend.c', 'xen_devconfig.c', 'xen_pvdev.c', +)) + +softmmu_ss.add(when: ['CONFIG_XEN', xen], if_true: files( 'xen-operations.c', )) =20 --=20 2.39.0 From nobody Fri May 3 04:42:41 2024 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 ARC-Seal: i=1; a=rsa-sha256; t=1677771321; cv=none; d=zohomail.com; s=zohoarc; b=VC1AHScSi5jGJ5fQ+Y30FcsSJ+6PJ7RAod2eiW52XpvKyo/CDAg3YszPWavzxzXycBITH1a7pOH7XSU9qcj8pZ8TzduuwoYSdYpxR1OJECKCubkvHUUq6b8u9Cdu9jgnSBz+lIbBi5EzvBJmPVkwKXOd8Ia/0r6Soh09MdSyAp4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1677771321; 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=FnClZ8IFan30fx5D6PHOfap2YeZdQXUEp+XrOHw7NWs=; b=HNXlnmLQ3IHZf7OZuMDs4qa51vjXzAtOkmCyNyriXhGdjFAYQg/K1xBx6ZEWyvuPmTg3nTtM1wm19Rv/5XEhV7cJOg9Qw/8FdQPhLBgvkX9BO4MHAyFPTD553MLcNDfjYhFa4WwLLqcx6EeQvEFLiMtqyNS4whJQPvRDXu6MkJ0= 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 Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1677771317816780.6795065111496; Thu, 2 Mar 2023 07:35:17 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.505048.777576 (Exim 4.92) (envelope-from ) id 1pXkxK-0001MV-Is; Thu, 02 Mar 2023 15:34:54 +0000 Received: by outflank-mailman (output) from mailman id 505048.777576; Thu, 02 Mar 2023 15:34:54 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxK-0001L1-F6; Thu, 02 Mar 2023 15:34:54 +0000 Received: by outflank-mailman (input) for mailman id 505048; Thu, 02 Mar 2023 15:34:53 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxJ-0001Jv-17 for xen-devel@lists.xenproject.org; Thu, 02 Mar 2023 15:34:53 +0000 Received: from desiato.infradead.org (desiato.infradead.org [2001:8b0:10b:1:d65d:64ff:fe57:4e05]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id c43a7735-b90f-11ed-96ad-2f268f93b82a; Thu, 02 Mar 2023 16:34:49 +0100 (CET) Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by desiato.infradead.org with esmtpsa (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-00FL3m-2e; Thu, 02 Mar 2023 15:34:40 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-004uzR-2J; Thu, 02 Mar 2023 15:34:38 +0000 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 X-Inumbo-ID: c43a7735-b90f-11ed-96ad-2f268f93b82a DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=FnClZ8IFan30fx5D6PHOfap2YeZdQXUEp+XrOHw7NWs=; b=VVkNvJQsV79cgt8bzx+l0ClT+G Wiyz5BhL24D12/QkaDakc0ALlSx1i2qok2apG76LwYNEM1pPgmDb1NfTSlVj7wZkqVtHQVBqpujPV K1mLrO+C4airr6O55gGcgarHdCX04k4Bsl7YQxlVfXtD4xKx+Jia60goBVqSVetR+CatCGqWNXsPc Hkh2FB4jcKSnEwt9c7+CYwLFfwoNISbAUmAKkfx1ZpxeJe/41myBDmH/5c+nMtk3LX5v20ijD+P3c fb+EEZ7t4gvEtKdroZBJtbhl42Mqx90Tx1WL+utNfz9glZ4m/cq0szzCSXECcHVSYePfkl7xeKlYy t8AX++Ww==; From: David Woodhouse To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , Stefano Stabellini , vikram.garhwal@amd.com, Anthony Perard , xen-devel@lists.xenproject.org Subject: [RFC PATCH v1 18/25] hw/xen: Avoid crash when backend watch fires too early Date: Thu, 2 Mar 2023 15:34:28 +0000 Message-Id: <20230302153435.1170111-19-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230302153435.1170111-1-dwmw2@infradead.org> References: <20230302153435.1170111-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by desiato.infradead.org. See http://www.infradead.org/rpr.html X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1677771323777100005 Content-Type: text/plain; charset="utf-8" From: Paul Durrant The xen-block code ends up calling aio_poll() through blkconf_geometry(), which means we see watch events during the indirect call to xendev_class->realize() in xen_device_realize(). Unfortunately this call is made before populating the initial frontend and backend device nodes in xenstore and hence xen_block_frontend_changed() (which is called from a watch event) fails to read the frontend's 'state' node, and hence believes the device is being torn down. This in-turn sets the backend state to XenbusStateClosed and causes the device to be deleted before it is fully set up, leading to the crash. By simply moving the call to xendev_class->realize() after the initial xenstore nodes are populated, this sorry state of affairs is avoided. Reported-by: David Woodhouse Signed-off-by: Paul Durrant Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- hw/xen/xen-bus.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c index 9fe54967d4..c59850b1de 100644 --- a/hw/xen/xen-bus.c +++ b/hw/xen/xen-bus.c @@ -1034,13 +1034,6 @@ static void xen_device_realize(DeviceState *dev, Err= or **errp) goto unrealize; } =20 - if (xendev_class->realize) { - xendev_class->realize(xendev, errp); - if (*errp) { - goto unrealize; - } - } - xen_device_backend_printf(xendev, "frontend", "%s", xendev->frontend_path); xen_device_backend_printf(xendev, "frontend-id", "%u", @@ -1059,6 +1052,13 @@ static void xen_device_realize(DeviceState *dev, Err= or **errp) xen_device_frontend_set_state(xendev, XenbusStateInitialising, tru= e); } =20 + if (xendev_class->realize) { + xendev_class->realize(xendev, errp); + if (*errp) { + goto unrealize; + } + } + xendev->exit.notify =3D xen_device_exit; qemu_add_exit_notifier(&xendev->exit); return; --=20 2.39.0 From nobody Fri May 3 04:42:41 2024 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 ARC-Seal: i=1; a=rsa-sha256; t=1677771330; cv=none; d=zohomail.com; s=zohoarc; b=M5zYxo6wmb5rpynMl5NQz041bNcxiUJNi1EHqoZDVUh/vbnQaNNyw4PEuL1647AY7eUgfS2JcULpEPBlQt/n0p7rDt2uhD6hGq6RPJfJaQySeYfdXVBWUAjokrA9b/Vqm1xzce+3Kuvsvt03NSZ2KxhpqQmhidnAA5mL5L8GBXA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1677771330; 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=7HuQae7CBMvNWNUtKmsp3irMJUgtZo+bY0Gg/sxTvcA=; b=mzfJwvgOO1aDHpk6bkOUjq3SMhu9dn5CKrFy1nJdOcdk0ch/8tXO4cdqp14vIu/UZEyUv2vqc3tp9QDUBUhtXPdvZ7MHhps7PGD1TMjAva8+rO+X7yOBgyz8d9FjnIAXIArTYFTGmJEtb1N6IJGdIzFY+3kPqIfGiuG6Nu+zmW8= 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 Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1677771329869774.6400449234916; Thu, 2 Mar 2023 07:35:29 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.505049.777583 (Exim 4.92) (envelope-from ) id 1pXkxK-0001SD-Tp; Thu, 02 Mar 2023 15:34:54 +0000 Received: by outflank-mailman (output) from mailman id 505049.777583; Thu, 02 Mar 2023 15:34:54 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxK-0001Ri-OD; Thu, 02 Mar 2023 15:34:54 +0000 Received: by outflank-mailman (input) for mailman id 505049; Thu, 02 Mar 2023 15:34:53 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxJ-0001Jv-8F for xen-devel@lists.xenproject.org; Thu, 02 Mar 2023 15:34:53 +0000 Received: from desiato.infradead.org (desiato.infradead.org [2001:8b0:10b:1:d65d:64ff:fe57:4e05]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id c2cdbef2-b90f-11ed-96ad-2f268f93b82a; Thu, 02 Mar 2023 16:34:49 +0100 (CET) Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by desiato.infradead.org with esmtpsa (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-00FL3n-2o; Thu, 02 Mar 2023 15:34:40 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-004uzW-2S; Thu, 02 Mar 2023 15:34:38 +0000 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 X-Inumbo-ID: c2cdbef2-b90f-11ed-96ad-2f268f93b82a DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=7HuQae7CBMvNWNUtKmsp3irMJUgtZo+bY0Gg/sxTvcA=; b=dq8AgLqqnaLPtRWcENWM2cS34S VPG6QR36tiZ4IOJIl0WR5V140YJiSV4QwUoMXWjQyPcG8gmcMFdqz1bC9CEY9jbPh2WHAPw/ucBhm oM5fK7TlM8bdPU3fRvBsq+nMkLRvvLB/dH3AaAvQKW5WaIRw5OUlj8kvCwKojnlO2HKmcNRn143qM 0uwwkElqhMVAy1aetnMgnlnmrGE2KR2hViX+Ee56aT3ouBn9iCrBS05fxonTB8AVe2TmyMuz8OS6+ UeVLolZ2i4CLzzk1CtUbzuHZB0zIkPT+bqYEMfBVyJVAn66km008aM1dnhq2FS/bFH9hrsUv5RLUt n31ldh3Q==; From: David Woodhouse To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , Stefano Stabellini , vikram.garhwal@amd.com, Anthony Perard , xen-devel@lists.xenproject.org Subject: [RFC PATCH v1 19/25] hw/xen: Only advertise ring-page-order for xen-block if gnttab supports it Date: Thu, 2 Mar 2023 15:34:29 +0000 Message-Id: <20230302153435.1170111-20-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230302153435.1170111-1-dwmw2@infradead.org> References: <20230302153435.1170111-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by desiato.infradead.org. See http://www.infradead.org/rpr.html X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1677771331677100001 Content-Type: text/plain; charset="utf-8" From: David Woodhouse Whem emulating Xen, multi-page grants are distinctly non-trivial and we have elected not to support them for the time being. Don't advertise them to the guest. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- hw/block/xen-block.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c index 87299615e3..f5a744589d 100644 --- a/hw/block/xen-block.c +++ b/hw/block/xen-block.c @@ -83,7 +83,8 @@ static void xen_block_connect(XenDevice *xendev, Error **= errp) g_free(ring_ref); return; } - } else if (order <=3D blockdev->props.max_ring_page_order) { + } else if (qemu_xen_gnttab_can_map_multi() && + order <=3D blockdev->props.max_ring_page_order) { unsigned int i; =20 nr_ring_ref =3D 1 << order; @@ -255,8 +256,12 @@ static void xen_block_realize(XenDevice *xendev, Error= **errp) } =20 xen_device_backend_printf(xendev, "feature-flush-cache", "%u", 1); - xen_device_backend_printf(xendev, "max-ring-page-order", "%u", - blockdev->props.max_ring_page_order); + + if (qemu_xen_gnttab_can_map_multi()) { + xen_device_backend_printf(xendev, "max-ring-page-order", "%u", + blockdev->props.max_ring_page_order); + } + xen_device_backend_printf(xendev, "info", "%u", blockdev->info); =20 xen_device_frontend_printf(xendev, "virtual-device", "%lu", --=20 2.39.0 From nobody Fri May 3 04:42:41 2024 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 ARC-Seal: i=1; a=rsa-sha256; t=1677771330; cv=none; d=zohomail.com; s=zohoarc; b=NyZGwah/2p2BjcURM6AhplhZWtuyZWfVJBDmwsZ6EtythLOG5u/pJrrnRlArhhb/oXtyrp/RvsBN0Db6rHLo1EV5qHfBuFA18uXtNGpCj6uWrEMfxnDNgM8nqS+taMaOAZh5YIeAEcO9RGQYDC3pyeoWnESqW/QehBtXXfeaqcc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1677771330; 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=YlCfg83tKKXeKZ+xSZwkLL5PykObe3vQTOvEbi/RER8=; b=PHB33BdD9kp3x3UBYT3oHaidgfVgOtDWCuXpO7sdsI2Tuu3CZty/gALWxCzSI9sNy6I+FUmr9Aq0kl2OflF5dMXmIofX2Fy2L2TiETUE2ElPikRcjVPCranSoH7fAD0MH3Dnd6wE7+Tv3eyopV1doGaZP3r3KDnj70LXqNwkNr8= 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 Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1677771330305823.9443180207439; Thu, 2 Mar 2023 07:35:30 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.505047.777573 (Exim 4.92) (envelope-from ) id 1pXkxK-0001KT-D1; Thu, 02 Mar 2023 15:34:54 +0000 Received: by outflank-mailman (output) from mailman id 505047.777573; Thu, 02 Mar 2023 15:34:54 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxK-0001KM-87; Thu, 02 Mar 2023 15:34:54 +0000 Received: by outflank-mailman (input) for mailman id 505047; Thu, 02 Mar 2023 15:34:52 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxH-0001Jv-Rt for xen-devel@lists.xenproject.org; Thu, 02 Mar 2023 15:34:52 +0000 Received: from desiato.infradead.org (desiato.infradead.org [2001:8b0:10b:1:d65d:64ff:fe57:4e05]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id c40c7173-b90f-11ed-96ad-2f268f93b82a; Thu, 02 Mar 2023 16:34:49 +0100 (CET) Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by desiato.infradead.org with esmtpsa (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-00FL3p-2y; Thu, 02 Mar 2023 15:34:44 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-004uzb-2c; Thu, 02 Mar 2023 15:34:38 +0000 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 X-Inumbo-ID: c40c7173-b90f-11ed-96ad-2f268f93b82a DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=YlCfg83tKKXeKZ+xSZwkLL5PykObe3vQTOvEbi/RER8=; b=DiDdTZUfWBP8v/oc6s9Gc9aXNS DmyqgfC2P9B45IlIUhm2YWvDQPvHiiZMs/BQ89SxeyJSf5E2HTlj+ZCzcRLDa0/a8FcOF7iLVyAsr azJp1I8YoM3OeYPl25JZTvu502Qzn+fbod4+skxoIEbpuN/1J63rVR3AM6QHzcZ6C0ew0Bi3bDLiZ NgndzJqcMVw4VoCQT6RZfpUmBEixeCCy4YqtPMnkFoxfig4gTTDy3kCz02zrewows2QJy5Rnq/NO/ 2bzEUzX4V06JKvYJAVxYK0SX7k/mMvXK7NlLKPp9M5QOQRefoDNpjLAVnzAzJtdOT/V8H9wOYf48f /OS0Gfyw==; From: David Woodhouse To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , Stefano Stabellini , vikram.garhwal@amd.com, Anthony Perard , xen-devel@lists.xenproject.org Subject: [RFC PATCH v1 20/25] hw/xen: Hook up emulated implementation for event channel operations Date: Thu, 2 Mar 2023 15:34:30 +0000 Message-Id: <20230302153435.1170111-21-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230302153435.1170111-1-dwmw2@infradead.org> References: <20230302153435.1170111-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by desiato.infradead.org. See http://www.infradead.org/rpr.html X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1677771331682100002 Content-Type: text/plain; charset="utf-8" From: David Woodhouse We provided the backend-facing evtchn functions very early on as part of the core Xen platform support, since things like timers and xenstore need to use them. By what may or may not be an astonishing coincidence, those functions just *happen* all to have exactly the right function prototypes to slot into the evtchn_backend_ops table and be called by the PV backends. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- hw/i386/kvm/xen_evtchn.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/hw/i386/kvm/xen_evtchn.c b/hw/i386/kvm/xen_evtchn.c index 886fbf6b3b..98a7b85047 100644 --- a/hw/i386/kvm/xen_evtchn.c +++ b/hw/i386/kvm/xen_evtchn.c @@ -34,6 +34,7 @@ #include "hw/pci/msi.h" #include "hw/pci/msix.h" #include "hw/irq.h" +#include "hw/xen/xen_backend_ops.h" =20 #include "xen_evtchn.h" #include "xen_overlay.h" @@ -278,6 +279,17 @@ static const TypeInfo xen_evtchn_info =3D { .class_init =3D xen_evtchn_class_init, }; =20 +static struct evtchn_backend_ops emu_evtchn_backend_ops =3D { + .open =3D xen_be_evtchn_open, + .bind_interdomain =3D xen_be_evtchn_bind_interdomain, + .unbind =3D xen_be_evtchn_unbind, + .close =3D xen_be_evtchn_close, + .get_fd =3D xen_be_evtchn_fd, + .notify =3D xen_be_evtchn_notify, + .unmask =3D xen_be_evtchn_unmask, + .pending =3D xen_be_evtchn_pending, +}; + static void gsi_assert_bh(void *opaque) { struct vcpu_info *vi =3D kvm_xen_get_vcpu_info_hva(0); @@ -318,6 +330,9 @@ void xen_evtchn_create(void) s->nr_pirq_inuse_words =3D DIV_ROUND_UP(s->nr_pirqs, 64); s->pirq_inuse_bitmap =3D g_new0(uint64_t, s->nr_pirq_inuse_words); s->pirq =3D g_new0(struct pirq_info, s->nr_pirqs); + + /* Set event channel functions for backend drivers to use */ + xen_evtchn_ops =3D &emu_evtchn_backend_ops; } =20 void xen_evtchn_connect_gsis(qemu_irq *system_gsis) --=20 2.39.0 From nobody Fri May 3 04:42:41 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1677771473131661.5342775508698; Thu, 2 Mar 2023 07:37:53 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pXkxk-0004AJ-8N; Thu, 02 Mar 2023 10:35:20 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pXkxJ-0003oU-BA for qemu-devel@nongnu.org; Thu, 02 Mar 2023 10:34:53 -0500 Received: from desiato.infradead.org ([2001:8b0:10b:1:d65d:64ff:fe57:4e05]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pXkxC-0001fF-L2 for qemu-devel@nongnu.org; Thu, 02 Mar 2023 10:34:53 -0500 Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by desiato.infradead.org with esmtpsa (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-00FL3q-38; Thu, 02 Mar 2023 15:34:41 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-004uzf-2m; Thu, 02 Mar 2023 15:34:38 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=0AyQpPd/CdJCn44zjL9zdzWbeQRuI8mbYBEGeaZNf0g=; b=GF1UkXMJYKnkrymMgC583SbMEm wi/RLc1fkxJFaBIQUCwaUFjYF2yZU2z+RO3ZF2IWAC3iEIrDOWp0vTWkACYd9YF8xkniJvq0z0sGc E2paSgXsFJQgBVYKCjkWQSA4WJASVkOCNKlm0q7hYbRKelXXzZKo++wdkuD6kiW8Xe0qXhU1XRKmZ Iu5CVfBGk1hmpMjZD+3lQqrOA2/XAjERtZx2P49eiIpgzsr2L64aRWkOtvvWx95kmOI15zwMuz/uv Rp4XaWEieFRXvGTnCkU/NV467N9WUKnz4EQYw7f9b3HB13Y0zaND1SB5WOVaPkm3HJJqgmcLMAPB9 R5cpngRQ==; From: David Woodhouse To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , Stefano Stabellini , vikram.garhwal@amd.com, Anthony Perard , xen-devel@lists.xenproject.org Subject: [RFC PATCH v1 21/25] hw/xen: Add emulated implementation of grant table operations Date: Thu, 2 Mar 2023 15:34:31 +0000 Message-Id: <20230302153435.1170111-22-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230302153435.1170111-1-dwmw2@infradead.org> References: <20230302153435.1170111-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-SRS-Rewrite: SMTP reverse-path rewritten from by desiato.infradead.org. See http://www.infradead.org/rpr.html Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: none client-ip=2001:8b0:10b:1:d65d:64ff:fe57:4e05; envelope-from=BATV+9a0490e5ac528e462c30+7130+infradead.org+dwmw2@desiato.srs.infradead.org; helo=desiato.infradead.org X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1677771474909100006 Content-Type: text/plain; charset="utf-8" From: David Woodhouse This is limited to mapping a single grant at a time, because under Xen the pages are mapped *contiguously* into qemu's address space, and that's very hard to do when those pages actually come from anonymous mappings in qemu in the first place. Eventually perhaps we can look at using shared mappings of actual objects for system RAM, and then we can make new mappings of the same backing store (be it deleted files, shmem, whatever). But for now let's stick to a page at a time. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- hw/i386/kvm/xen_gnttab.c | 299 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 296 insertions(+), 3 deletions(-) diff --git a/hw/i386/kvm/xen_gnttab.c b/hw/i386/kvm/xen_gnttab.c index 1e691ded32..2bf91d36c0 100644 --- a/hw/i386/kvm/xen_gnttab.c +++ b/hw/i386/kvm/xen_gnttab.c @@ -22,6 +22,7 @@ =20 #include "hw/sysbus.h" #include "hw/xen/xen.h" +#include "hw/xen/xen_backend_ops.h" #include "xen_overlay.h" #include "xen_gnttab.h" =20 @@ -34,11 +35,10 @@ #define TYPE_XEN_GNTTAB "xen-gnttab" OBJECT_DECLARE_SIMPLE_TYPE(XenGnttabState, XEN_GNTTAB) =20 -#define XEN_PAGE_SHIFT 12 -#define XEN_PAGE_SIZE (1ULL << XEN_PAGE_SHIFT) - #define ENTRIES_PER_FRAME_V1 (XEN_PAGE_SIZE / sizeof(grant_entry_v1_t)) =20 +static struct gnttab_backend_ops emu_gnttab_backend_ops; + struct XenGnttabState { /*< private >*/ SysBusDevice busdev; @@ -57,6 +57,8 @@ struct XenGnttabState { MemoryRegion gnt_frames; MemoryRegion *gnt_aliases; uint64_t *gnt_frame_gpas; + + uint8_t *map_track; }; =20 struct XenGnttabState *xen_gnttab_singleton; @@ -88,9 +90,15 @@ static void xen_gnttab_realize(DeviceState *dev, Error *= *errp) s->gnt_frame_gpas[i] =3D INVALID_GPA; } =20 + s->entries.v1[GNTTAB_RESERVED_XENSTORE].flags =3D GTF_permit_access; + s->entries.v1[GNTTAB_RESERVED_XENSTORE].frame =3D XEN_SPECIAL_PFN(XENS= TORE); qemu_mutex_init(&s->gnt_lock); =20 xen_gnttab_singleton =3D s; + + s->map_track =3D g_new0(uint8_t, s->max_frames * ENTRIES_PER_FRAME_V1); + + xen_gnttab_ops =3D &emu_gnttab_backend_ops; } =20 static int xen_gnttab_post_load(void *opaque, int version_id) @@ -230,3 +238,288 @@ int xen_gnttab_query_size_op(struct gnttab_query_size= *size) size->max_nr_frames =3D s->max_frames; return 0; } + +/* Track per-open refs, to allow close() to clean up. */ +struct active_ref { + MemoryRegionSection mrs; + void *virtaddr; + uint32_t refcnt; + int prot; +}; + +static void gnt_unref(XenGnttabState *s, grant_ref_t ref, + MemoryRegionSection *mrs, int prot) +{ + if (mrs && mrs->mr) { + if (prot & PROT_WRITE) { + memory_region_set_dirty(mrs->mr, mrs->offset_within_region, + XEN_PAGE_SIZE); + } + memory_region_unref(mrs->mr); + mrs->mr =3D NULL; + } + assert(s->map_track[ref] !=3D 0); + + if (--s->map_track[ref] =3D=3D 0) { + grant_entry_v1_t *gnt_p =3D &s->entries.v1[ref]; + qatomic_and(&gnt_p->flags, (uint16_t)~(GTF_reading | GTF_writing)); + } +} + +static uint64_t gnt_ref(XenGnttabState *s, grant_ref_t ref, int prot) +{ + uint16_t mask =3D GTF_type_mask | GTF_sub_page; + grant_entry_v1_t gnt, *gnt_p; + int retries =3D 0; + + if (ref >=3D s->max_frames * ENTRIES_PER_FRAME_V1 || + s->map_track[ref] =3D=3D UINT8_MAX) { + return INVALID_GPA; + } + + if (prot & PROT_WRITE) { + mask |=3D GTF_readonly; + } + + gnt_p =3D &s->entries.v1[ref]; + + /* + * The guest can legitimately be changing the GTF_readonly flag. Allow + * that, but don't let a malicious guest cause a livelock. + */ + for (retries =3D 0; retries < 5; retries++) { + uint16_t new_flags; + + /* Read the entry before an atomic operation on its flags */ + gnt =3D *(volatile grant_entry_v1_t *)gnt_p; + + if ((gnt.flags & mask) !=3D GTF_permit_access || + gnt.domid !=3D DOMID_QEMU) { + return INVALID_GPA; + } + + new_flags =3D gnt.flags | GTF_reading; + if (prot & PROT_WRITE) { + new_flags |=3D GTF_writing; + } + + if (qatomic_cmpxchg(&gnt_p->flags, gnt.flags, new_flags) =3D=3D gn= t.flags) { + return (uint64_t)gnt.frame << XEN_PAGE_SHIFT; + } + } + + return INVALID_GPA; +} + +struct xengntdev_handle { + GHashTable *active_maps; +}; + +static int xen_be_gnttab_set_max_grants(struct xengntdev_handle *xgt, + uint32_t nr_grants) +{ + return 0; +} + +static void *xen_be_gnttab_map_refs(struct xengntdev_handle *xgt, + uint32_t count, uint32_t domid, + uint32_t *refs, int prot) +{ + XenGnttabState *s =3D xen_gnttab_singleton; + struct active_ref *act; + + if (!s) { + errno =3D ENOTSUP; + return NULL; + } + + if (domid !=3D xen_domid) { + errno =3D EINVAL; + return NULL; + } + + if (!count || count > 4096) { + errno =3D EINVAL; + return NULL; + } + + /* + * Making a contiguous mapping from potentially discontiguous grant + * references would be... distinctly non-trivial. We don't support it. + * Even changing the API to return an array of pointers, one per page, + * wouldn't be simple to use in PV backends because some structures + * actually cross page boundaries (e.g. 32-bit blkif_response ring + * entries are 12 bytes). + */ + if (count !=3D 1) { + errno =3D EINVAL; + return NULL; + } + + QEMU_LOCK_GUARD(&s->gnt_lock); + + act =3D g_hash_table_lookup(xgt->active_maps, GINT_TO_POINTER(refs[0])= ); + if (act) { + if ((prot & PROT_WRITE) && !(act->prot & PROT_WRITE)) { + if (gnt_ref(s, refs[0], prot) =3D=3D INVALID_GPA) { + return NULL; + } + act->prot |=3D PROT_WRITE; + } + act->refcnt++; + } else { + uint64_t gpa =3D gnt_ref(s, refs[0], prot); + if (gpa =3D=3D INVALID_GPA) { + errno =3D EINVAL; + return NULL; + } + + act =3D g_new0(struct active_ref, 1); + act->prot =3D prot; + act->refcnt =3D 1; + act->mrs =3D memory_region_find(get_system_memory(), gpa, XEN_PAGE= _SIZE); + + if (act->mrs.mr && + !int128_lt(act->mrs.size, int128_make64(XEN_PAGE_SIZE)) && + memory_region_get_ram_addr(act->mrs.mr) !=3D RAM_ADDR_INVALID)= { + act->virtaddr =3D qemu_map_ram_ptr(act->mrs.mr->ram_block, + act->mrs.offset_within_region= ); + } + if (!act->virtaddr) { + gnt_unref(s, refs[0], &act->mrs, 0); + g_free(act); + errno =3D EINVAL; + return NULL; + } + + s->map_track[refs[0]]++; + g_hash_table_insert(xgt->active_maps, GINT_TO_POINTER(refs[0]), ac= t); + } + + return act->virtaddr; +} + +static gboolean do_unmap(gpointer key, gpointer value, gpointer user_data) +{ + XenGnttabState *s =3D user_data; + grant_ref_t gref =3D GPOINTER_TO_INT(key); + struct active_ref *act =3D value; + + gnt_unref(s, gref, &act->mrs, act->prot); + g_free(act); + return true; +} + +static int xen_be_gnttab_unmap(struct xengntdev_handle *xgt, + void *start_address, uint32_t *refs, + uint32_t count) +{ + XenGnttabState *s =3D xen_gnttab_singleton; + struct active_ref *act; + + if (!s) { + return -ENOTSUP; + } + + if (count !=3D 1) { + return -EINVAL; + } + + QEMU_LOCK_GUARD(&s->gnt_lock); + + act =3D g_hash_table_lookup(xgt->active_maps, GINT_TO_POINTER(refs[0])= ); + if (!act) { + return -ENOENT; + } + + if (act->virtaddr !=3D start_address) { + return -EINVAL; + } + + if (!--act->refcnt) { + do_unmap(GINT_TO_POINTER(refs[0]), act, s); + g_hash_table_remove(xgt->active_maps, GINT_TO_POINTER(refs[0])); + } + + return 0; +} + +/* + * This looks a bit like the one for true Xen in xen-operations.c but + * in emulation we don't support multi-page mappings. And under Xen we + * *want* the multi-page mappings so we have fewer bounces through the + * kernel and the hypervisor. So the code paths end up being similar, + * but different. + */ +static int xen_be_gnttab_copy(struct xengntdev_handle *xgt, bool to_domain, + uint32_t domid, XenGrantCopySegment *segs, + uint32_t nr_segs, Error **errp) +{ + int prot =3D to_domain ? PROT_WRITE : PROT_READ; + unsigned int i; + + for (i =3D 0; i < nr_segs; i++) { + XenGrantCopySegment *seg =3D &segs[i]; + void *page; + uint32_t ref =3D to_domain ? seg->dest.foreign.ref : + seg->source.foreign.ref; + + page =3D xen_be_gnttab_map_refs(xgt, 1, domid, &ref, prot); + if (!page) { + if (errp) { + error_setg_errno(errp, errno, + "xen_be_gnttab_map_refs failed"); + } + return -errno; + } + + if (to_domain) { + memcpy(page + seg->dest.foreign.offset, seg->source.virt, + seg->len); + } else { + memcpy(seg->dest.virt, page + seg->source.foreign.offset, + seg->len); + } + + if (xen_be_gnttab_unmap(xgt, page, &ref, 1)) { + if (errp) { + error_setg_errno(errp, errno, "xen_be_gnttab_unmap failed"= ); + } + return -errno; + } + } + + return 0; +} + +static struct xengntdev_handle *xen_be_gnttab_open(void) +{ + struct xengntdev_handle *xgt =3D g_new0(struct xengntdev_handle, 1); + + xgt->active_maps =3D g_hash_table_new(g_direct_hash, g_direct_equal); + return xgt; +} + +static int xen_be_gnttab_close(struct xengntdev_handle *xgt) +{ + XenGnttabState *s =3D xen_gnttab_singleton; + + if (!s) { + return -ENOTSUP; + } + + g_hash_table_foreach_remove(xgt->active_maps, do_unmap, s); + g_hash_table_destroy(xgt->active_maps); + g_free(xgt); + return 0; +} + +static struct gnttab_backend_ops emu_gnttab_backend_ops =3D { + .open =3D xen_be_gnttab_open, + .close =3D xen_be_gnttab_close, + .grant_copy =3D xen_be_gnttab_copy, + .set_max_grants =3D xen_be_gnttab_set_max_grants, + .map_refs =3D xen_be_gnttab_map_refs, + .unmap =3D xen_be_gnttab_unmap, +}; + --=20 2.39.0 From nobody Fri May 3 04:42:41 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1677771438630785.2555359391176; Thu, 2 Mar 2023 07:37:18 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pXkxn-0004D2-Hu; Thu, 02 Mar 2023 10:35:24 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pXkxI-0003oC-Rg for qemu-devel@nongnu.org; Thu, 02 Mar 2023 10:34:52 -0500 Received: from desiato.infradead.org ([2001:8b0:10b:1:d65d:64ff:fe57:4e05]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pXkxC-0001f9-Iw for qemu-devel@nongnu.org; Thu, 02 Mar 2023 10:34:52 -0500 Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by desiato.infradead.org with esmtpsa (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx5-00FL3r-07; Thu, 02 Mar 2023 15:34:41 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-004uzk-2x; Thu, 02 Mar 2023 15:34:38 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=GIy/mr/P0dU4lKy5osmGAuO163GgHpykyx4+8Dxy3J8=; b=psZYAy7hv1vPQkhNzx5j+j6PHj aUyGV4bYYciEJOkFzCEJhMbOARGxDslIEJw4j6rxUHi9qpYkgFnxvxXqk03Pp+ElrcJlqwIbw+kjg 0RXL1heQljsalhW8cGZyUm5iCD4ShOcWcXuuPNF4VhSVDPNv4zLroaiJOyTgIwDKcEMURGOw8VKyK GsT8GvlhpqTuky3/UE+sacR11dim6D8pDQtAmaXf5qZxu4Zs/zJAPFF28d6emV39xcadQbJdnnXyE aZsTR+Ey1CRyZYzmWD7AnOg1oliBGmpQ3E7GMXZvW/AiYUQS3GKoL1fMm0WGxCRfjqHGGj7IrPXNt PTJwgqWw==; From: David Woodhouse To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , Stefano Stabellini , vikram.garhwal@amd.com, Anthony Perard , xen-devel@lists.xenproject.org Subject: [RFC PATCH v1 22/25] hw/xen: Add emulated implementation of XenStore operations Date: Thu, 2 Mar 2023 15:34:32 +0000 Message-Id: <20230302153435.1170111-23-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230302153435.1170111-1-dwmw2@infradead.org> References: <20230302153435.1170111-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-SRS-Rewrite: SMTP reverse-path rewritten from by desiato.infradead.org. See http://www.infradead.org/rpr.html Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: none client-ip=2001:8b0:10b:1:d65d:64ff:fe57:4e05; envelope-from=BATV+9a0490e5ac528e462c30+7130+infradead.org+dwmw2@desiato.srs.infradead.org; helo=desiato.infradead.org X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1677771440807100010 Content-Type: text/plain; charset="utf-8" From: David Woodhouse Now that we have an internal implementation of XenStore, we can populate the xenstore_backend_ops to allow PV backends to talk to it. Watches can't be processed with immediate callbacks because that would call back into XenBus code recursively. Defer them to a QEMUBH to be run as appropriate from the main loop. We use a QEMUBH per XS handle, and it walks all the watches (there shouldn't be many per handle) to fire any which have pending events. We *could* have done it differently but this allows us to use the same struct watch_event as we have for the guest side, and keeps things relatively simple. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- hw/i386/kvm/xen_xenstore.c | 273 ++++++++++++++++++++++++++++++++++++- 1 file changed, 269 insertions(+), 4 deletions(-) diff --git a/hw/i386/kvm/xen_xenstore.c b/hw/i386/kvm/xen_xenstore.c index bab40d1a04..028f80499e 100644 --- a/hw/i386/kvm/xen_xenstore.c +++ b/hw/i386/kvm/xen_xenstore.c @@ -49,7 +49,7 @@ struct XenXenstoreState { /*< public >*/ =20 XenstoreImplState *impl; - GList *watch_events; + GList *watch_events; /* for the guest */ =20 MemoryRegion xenstore_page; struct xenstore_domain_interface *xs; @@ -73,6 +73,8 @@ struct XenXenstoreState *xen_xenstore_singleton; static void xen_xenstore_event(void *opaque); static void fire_watch_cb(void *opaque, const char *path, const char *toke= n); =20 +static struct xenstore_backend_ops emu_xenstore_backend_ops; + static void G_GNUC_PRINTF (4, 5) relpath_printf(XenXenstoreState *s, GList *perms, const char *relpath, @@ -169,6 +171,8 @@ static void xen_xenstore_realize(DeviceState *dev, Erro= r **errp) relpath_printf(s, perms, "feature", "%s", ""); =20 g_list_free_full(perms, g_free); + + xen_xenstore_ops =3D &emu_xenstore_backend_ops; } =20 static bool xen_xenstore_is_needed(void *opaque) @@ -1305,6 +1309,15 @@ struct watch_event { char *token; }; =20 +static void free_watch_event(struct watch_event *ev) +{ + if (ev) { + g_free(ev->path); + g_free(ev->token); + g_free(ev); + } +} + static void queue_watch(XenXenstoreState *s, const char *path, const char *token) { @@ -1351,9 +1364,7 @@ static void process_watch_events(XenXenstoreState *s) deliver_watch(s, ev->path, ev->token); =20 s->watch_events =3D g_list_remove(s->watch_events, ev); - g_free(ev->path); - g_free(ev->token); - g_free(ev); + free_watch_event(ev); } =20 static void xen_xenstore_event(void *opaque) @@ -1443,3 +1454,257 @@ int xen_xenstore_reset(void) =20 return 0; } + +struct qemu_xs_handle { + XenstoreImplState *impl; + GList *watches; + QEMUBH *watch_bh; +}; + +struct qemu_xs_watch { + struct qemu_xs_handle *h; + char *path; + xs_watch_fn fn; + void *opaque; + GList *events; +}; + +static char *xs_be_get_domain_path(struct qemu_xs_handle *h, unsigned int = domid) +{ + return g_strdup_printf("/local/domain/%u", domid); +} + +static char **xs_be_directory(struct qemu_xs_handle *h, xs_transaction_t t, + const char *path, unsigned int *num) +{ + GList *items =3D NULL, *l; + unsigned int i =3D 0; + char **items_ret; + int err; + + err =3D xs_impl_directory(h->impl, DOMID_QEMU, t, path, NULL, &items); + if (err) { + errno =3D err; + return NULL; + } + + items_ret =3D g_new0(char *, g_list_length(items) + 1); + *num =3D 0; + for (l =3D items; l; l =3D l->next) { + items_ret[i++] =3D l->data; + (*num)++; + } + g_list_free(items); + return items_ret; +} + +static void *xs_be_read(struct qemu_xs_handle *h, xs_transaction_t t, + const char *path, unsigned int *len) +{ + GByteArray *data =3D g_byte_array_new(); + bool free_segment =3D false; + int err; + + err =3D xs_impl_read(h->impl, DOMID_QEMU, t, path, data); + if (err) { + free_segment =3D true; + errno =3D err; + } else { + if (len) { + *len =3D data->len; + } + /* The xen-bus-helper code expects to get NUL terminated string! */ + g_byte_array_append(data, (void *)"", 1); + } + + return g_byte_array_free(data, free_segment); +} + +static bool xs_be_write(struct qemu_xs_handle *h, xs_transaction_t t, + const char *path, const void *data, unsigned int l= en) +{ + GByteArray *gdata =3D g_byte_array_new(); + int err; + + g_byte_array_append(gdata, data, len); + err =3D xs_impl_write(h->impl, DOMID_QEMU, t, path, gdata); + g_byte_array_unref(gdata); + if (err) { + errno =3D err; + return false; + } + return true; +} + +static bool xs_be_create(struct qemu_xs_handle *h, xs_transaction_t t, + unsigned int owner, unsigned int domid, + unsigned int perms, const char *path) +{ + g_autoptr(GByteArray) data =3D g_byte_array_new(); + GList *perms_list =3D NULL; + int err; + + /* mkdir does this */ + err =3D xs_impl_read(h->impl, DOMID_QEMU, t, path, data); + if (err =3D=3D ENOENT) { + err =3D xs_impl_write(h->impl, DOMID_QEMU, t, path, data); + } + if (err) { + errno =3D err; + return false; + } + + perms_list =3D g_list_append(perms_list, + xs_perm_as_string(XS_PERM_NONE, owner)); + perms_list =3D g_list_append(perms_list, + xs_perm_as_string(perms, domid)); + + err =3D xs_impl_set_perms(h->impl, DOMID_QEMU, t, path, perms_list); + g_list_free_full(perms_list, g_free); + if (err) { + errno =3D err; + return false; + } + return true; +} + +static bool xs_be_destroy(struct qemu_xs_handle *h, xs_transaction_t t, + const char *path) +{ + int err =3D xs_impl_rm(h->impl, DOMID_QEMU, t, path); + if (err) { + errno =3D err; + return false; + } + return true; +} + +static void be_watch_bh(void *_h) +{ + struct qemu_xs_handle *h =3D _h; + GList *l; + + for (l =3D h->watches; l; l =3D l->next) { + struct qemu_xs_watch *w =3D l->data; + + while (w->events) { + struct watch_event *ev =3D w->events->data; + + w->fn(w->opaque, ev->path); + + w->events =3D g_list_remove(w->events, ev); + free_watch_event(ev); + } + } +} + +static void xs_be_watch_cb(void *opaque, const char *path, const char *tok= en) +{ + struct watch_event *ev =3D g_new0(struct watch_event, 1); + struct qemu_xs_watch *w =3D opaque; + + /* We don't care about the token */ + ev->path =3D g_strdup(path); + w->events =3D g_list_append(w->events, ev); + + qemu_bh_schedule(w->h->watch_bh); +} + +static struct qemu_xs_watch *xs_be_watch(struct qemu_xs_handle *h, + const char *path, xs_watch_fn fn, + void *opaque) +{ + struct qemu_xs_watch *w =3D g_new0(struct qemu_xs_watch, 1); + int err; + + w->h =3D h; + w->fn =3D fn; + w->opaque =3D opaque; + + err =3D xs_impl_watch(h->impl, DOMID_QEMU, path, NULL, xs_be_watch_cb,= w); + if (err) { + errno =3D err; + g_free(w); + return NULL; + } + + w->path =3D g_strdup(path); + h->watches =3D g_list_append(h->watches, w); + return w; +} + +static void xs_be_unwatch(struct qemu_xs_handle *h, struct qemu_xs_watch *= w) +{ + xs_impl_unwatch(h->impl, DOMID_QEMU, w->path, NULL, xs_be_watch_cb, w); + + h->watches =3D g_list_remove(h->watches, w); + g_list_free_full(w->events, (GDestroyNotify)free_watch_event); + g_free(w->path); + g_free(w); +} + +static xs_transaction_t xs_be_transaction_start(struct qemu_xs_handle *h) +{ + unsigned int new_tx =3D XBT_NULL; + int err =3D xs_impl_transaction_start(h->impl, DOMID_QEMU, &new_tx); + if (err) { + errno =3D err; + return XBT_NULL; + } + return new_tx; +} + +static bool xs_be_transaction_end(struct qemu_xs_handle *h, xs_transaction= _t t, + bool abort) +{ + int err =3D xs_impl_transaction_end(h->impl, DOMID_QEMU, t, !abort); + if (err) { + errno =3D err; + return false; + } + return true; +} + +static struct qemu_xs_handle *xs_be_open(void) +{ + XenXenstoreState *s =3D xen_xenstore_singleton; + struct qemu_xs_handle *h; + + if (!s && !s->impl) { + errno =3D -ENOSYS; + return NULL; + } + + h =3D g_new0(struct qemu_xs_handle, 1); + h->impl =3D s->impl; + + h->watch_bh =3D aio_bh_new(qemu_get_aio_context(), be_watch_bh, h); + + return h; +} + +static void xs_be_close(struct qemu_xs_handle *h) +{ + while (h->watches) { + struct qemu_xs_watch *w =3D h->watches->data; + xs_be_unwatch(h, w); + } + + qemu_bh_delete(h->watch_bh); + g_free(h); +} + +static struct xenstore_backend_ops emu_xenstore_backend_ops =3D { + .open =3D xs_be_open, + .close =3D xs_be_close, + .get_domain_path =3D xs_be_get_domain_path, + .directory =3D xs_be_directory, + .read =3D xs_be_read, + .write =3D xs_be_write, + .create =3D xs_be_create, + .destroy =3D xs_be_destroy, + .watch =3D xs_be_watch, + .unwatch =3D xs_be_unwatch, + .transaction_start =3D xs_be_transaction_start, + .transaction_end =3D xs_be_transaction_end, +}; --=20 2.39.0 From nobody Fri May 3 04:42:41 2024 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 ARC-Seal: i=1; a=rsa-sha256; t=1677771333; cv=none; d=zohomail.com; s=zohoarc; b=fGu7j2q3FHInRhWUH34FXIDmiRx2nBXJgzYdd2N537+aZOCTW5qvR4AD+IEoHtxvmOW0PuDc8CB0i+u9ukInz/xkK6tNSRwP1mHf5Ogr0f1sZpKL2VMGHcB3iEeSWhIHzP/kLCPy4xbzM80j4QZq+gq/0mLk6y0sVImXLlT4azQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1677771333; 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=7gK7dvxz5pclX0MnciBP6zR++gp8k+vbHhIgn8vIfXk=; b=CeH7xvMhUCYjz9mmIqtZz5l6vwWgtD8uEDbqwxAMdUvMra0dWtcBu0yZJ663ocujeYoEcyMzZ9N/55duxMevAHGR0NJVkwC/z54JHI2hLFbPt7It6cB9z/TE5wFRwenhUXl8v/N0shFnFvqm/m4nORJbUS3WGrt+k+Ae89OBoVA= 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 Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1677771333864714.1453672643606; Thu, 2 Mar 2023 07:35:33 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.505058.777664 (Exim 4.92) (envelope-from ) id 1pXkxR-0003QU-Ek; Thu, 02 Mar 2023 15:35:01 +0000 Received: by outflank-mailman (output) from mailman id 505058.777664; Thu, 02 Mar 2023 15:35:01 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxR-0003Nk-0L; Thu, 02 Mar 2023 15:35:01 +0000 Received: by outflank-mailman (input) for mailman id 505058; Thu, 02 Mar 2023 15:34:57 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pXkxN-0001Jv-5e for xen-devel@lists.xenproject.org; Thu, 02 Mar 2023 15:34:57 +0000 Received: from desiato.infradead.org (desiato.infradead.org [2001:8b0:10b:1:d65d:64ff:fe57:4e05]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id c2d1fed5-b90f-11ed-96ad-2f268f93b82a; Thu, 02 Mar 2023 16:34:49 +0100 (CET) Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by desiato.infradead.org with esmtpsa (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx5-00FL3s-0L; Thu, 02 Mar 2023 15:34:42 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-004uzq-38; Thu, 02 Mar 2023 15:34:38 +0000 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 X-Inumbo-ID: c2d1fed5-b90f-11ed-96ad-2f268f93b82a DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=7gK7dvxz5pclX0MnciBP6zR++gp8k+vbHhIgn8vIfXk=; b=S4wCJdfuWRVgYPx9kKLk0xA+ko e7ZB09+Rs2KKJZoF7A2nmmbx4uXvWmZO8R/FlyeezVVODqEnTf3UGYROuP6Ln2PAMwseYTN+2ylze WIfvuHbVTq++w7YQm5Vbz/zeKfYK1n4sx2f5k04ZVAHmCRLfGQwoOYxPP1YEA3GydmIPPuBaH8GNB fGb6PBC9kgdipKoQRH374/cqIfbNOBYuXtA8yjW1vqiPTLpcrzZiC75A0JNifqzBbPAFr9ljsFUdh KEDDSRCDfn/eyuwne1D+npgC4VoXBRwdD1DixUj1yJ7RIQ1iNcFzRd/3NfjLSX4lq+9xdEeh/ExL5 gpA4JCLQ==; From: David Woodhouse To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , Stefano Stabellini , vikram.garhwal@amd.com, Anthony Perard , xen-devel@lists.xenproject.org Subject: [RFC PATCH v1 23/25] hw/xen: Map guest XENSTORE_PFN grant in emulated Xenstore Date: Thu, 2 Mar 2023 15:34:33 +0000 Message-Id: <20230302153435.1170111-24-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230302153435.1170111-1-dwmw2@infradead.org> References: <20230302153435.1170111-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by desiato.infradead.org. See http://www.infradead.org/rpr.html X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1677771335648100023 Content-Type: text/plain; charset="utf-8" From: David Woodhouse Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- hw/i386/kvm/xen_xenstore.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/hw/i386/kvm/xen_xenstore.c b/hw/i386/kvm/xen_xenstore.c index 028f80499e..f9b7387024 100644 --- a/hw/i386/kvm/xen_xenstore.c +++ b/hw/i386/kvm/xen_xenstore.c @@ -21,6 +21,7 @@ =20 #include "hw/sysbus.h" #include "hw/xen/xen.h" +#include "hw/xen/xen_backend_ops.h" #include "xen_overlay.h" #include "xen_evtchn.h" #include "xen_xenstore.h" @@ -34,6 +35,7 @@ =20 #include "hw/xen/interface/io/xs_wire.h" #include "hw/xen/interface/event_channel.h" +#include "hw/xen/interface/grant_table.h" =20 #define TYPE_XEN_XENSTORE "xen-xenstore" OBJECT_DECLARE_SIMPLE_TYPE(XenXenstoreState, XEN_XENSTORE) @@ -66,6 +68,9 @@ struct XenXenstoreState { =20 uint8_t *impl_state; uint32_t impl_state_size; + + struct xengntdev_handle *gt; + void *granted_xs; }; =20 struct XenXenstoreState *xen_xenstore_singleton; @@ -1452,6 +1457,17 @@ int xen_xenstore_reset(void) } s->be_port =3D err; =20 + /* + * We don't actually access the guest's page through the grant, because + * this isn't real Xen, and we can just use the page we gave it in the + * first place. Map the grant anyway, mostly for cosmetic purposes so + * it *looks* like it's in use in the guest-visible grant table. + */ + s->gt =3D qemu_xen_gnttab_open(); + uint32_t xs_gntref =3D GNTTAB_RESERVED_XENSTORE; + s->granted_xs =3D qemu_xen_gnttab_map_refs(s->gt, 1, xen_domid, &xs_gn= tref, + PROT_READ | PROT_WRITE); + return 0; } =20 --=20 2.39.0 From nobody Fri May 3 04:42:41 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1677771391400596.7491136325551; Thu, 2 Mar 2023 07:36:31 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pXkxd-00042K-QI; Thu, 02 Mar 2023 10:35:13 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pXkxI-0003nf-3f for qemu-devel@nongnu.org; Thu, 02 Mar 2023 10:34:52 -0500 Received: from desiato.infradead.org ([2001:8b0:10b:1:d65d:64ff:fe57:4e05]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pXkxC-0001gd-Jg for qemu-devel@nongnu.org; Thu, 02 Mar 2023 10:34:51 -0500 Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by desiato.infradead.org with esmtpsa (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx5-00FL3t-0S; Thu, 02 Mar 2023 15:34:44 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx5-004uzv-05; Thu, 02 Mar 2023 15:34:39 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=/GQrGB9GrgC+Q8b54vxISRJa7cHPlcTCAZI1cxqx0gk=; b=KNpoc56AxdyqwqODe7tIRm+WTq ZEo+mZzWlDOYx/REo4Hh7sRTsD1jg/4V8jUUb0D7jNd1l/FQbJeU7KhEDOoBNrgCOTNyYbS2fMQ5n Tmj/FP+EhTdaQCFycvw5u94GedSXnkgUa7ZGoWFnS0K3DajVLi6Ue03zvWWIrAviihKYS4YKrZ1bF a1kiuQbPO3zbVNpGJvE1p9vCHDUdELVwEBK3lOB8OtsztLuGBlQeISaQXvvQv8WRajcxynUx7mJEf fZ9S+ivqVptAXDVfvB40RffQpuomI1R13Dcsbp0QcNrHactvz6T+u2THro41Ixw/TXCHnN+6O1E/A IxTXd0Fg==; From: David Woodhouse To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , Stefano Stabellini , vikram.garhwal@amd.com, Anthony Perard , xen-devel@lists.xenproject.org Subject: [RFC PATCH v1 24/25] hw/xen: Implement soft reset for emulated gnttab Date: Thu, 2 Mar 2023 15:34:34 +0000 Message-Id: <20230302153435.1170111-25-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230302153435.1170111-1-dwmw2@infradead.org> References: <20230302153435.1170111-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-SRS-Rewrite: SMTP reverse-path rewritten from by desiato.infradead.org. See http://www.infradead.org/rpr.html Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: none client-ip=2001:8b0:10b:1:d65d:64ff:fe57:4e05; envelope-from=BATV+9a0490e5ac528e462c30+7130+infradead.org+dwmw2@desiato.srs.infradead.org; helo=desiato.infradead.org X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1677771391863100002 Content-Type: text/plain; charset="utf-8" From: David Woodhouse This is only part of it; we will also need to get the PV back end drivers to tear down their own mappings (or do it for them, but they kind of need to stop using the pointers too). Some more work on the actual PV back ends and xen-bus code is going to be needed to really make soft reset and migration fully functional, and this part is the basis for that. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- hw/i386/kvm/xen_gnttab.c | 26 ++++++++++++++++++++++++-- hw/i386/kvm/xen_gnttab.h | 1 + target/i386/kvm/xen-emu.c | 5 +++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/hw/i386/kvm/xen_gnttab.c b/hw/i386/kvm/xen_gnttab.c index 2bf91d36c0..21c30e3659 100644 --- a/hw/i386/kvm/xen_gnttab.c +++ b/hw/i386/kvm/xen_gnttab.c @@ -72,13 +72,11 @@ static void xen_gnttab_realize(DeviceState *dev, Error = **errp) error_setg(errp, "Xen grant table support is for Xen emulation"); return; } - s->nr_frames =3D 0; s->max_frames =3D kvm_xen_get_gnttab_max_frames(); memory_region_init_ram(&s->gnt_frames, OBJECT(dev), "xen:grant_table", XEN_PAGE_SIZE * s->max_frames, &error_abort); memory_region_set_enabled(&s->gnt_frames, true); s->entries.v1 =3D memory_region_get_ram_ptr(&s->gnt_frames); - memset(s->entries.v1, 0, XEN_PAGE_SIZE * s->max_frames); =20 /* Create individual page-sizes aliases for overlays */ s->gnt_aliases =3D (void *)g_new0(MemoryRegion, s->max_frames); @@ -90,8 +88,11 @@ static void xen_gnttab_realize(DeviceState *dev, Error *= *errp) s->gnt_frame_gpas[i] =3D INVALID_GPA; } =20 + s->nr_frames =3D 0; + memset(s->entries.v1, 0, XEN_PAGE_SIZE * s->max_frames); s->entries.v1[GNTTAB_RESERVED_XENSTORE].flags =3D GTF_permit_access; s->entries.v1[GNTTAB_RESERVED_XENSTORE].frame =3D XEN_SPECIAL_PFN(XENS= TORE); + qemu_mutex_init(&s->gnt_lock); =20 xen_gnttab_singleton =3D s; @@ -523,3 +524,24 @@ static struct gnttab_backend_ops emu_gnttab_backend_op= s =3D { .unmap =3D xen_be_gnttab_unmap, }; =20 +int xen_gnttab_reset(void) +{ + XenGnttabState *s =3D xen_gnttab_singleton; + + if (!s) { + return -ENOTSUP; + } + + QEMU_LOCK_GUARD(&s->gnt_lock); + + s->nr_frames =3D 0; + + memset(s->entries.v1, 0, XEN_PAGE_SIZE * s->max_frames); + + s->entries.v1[GNTTAB_RESERVED_XENSTORE].flags =3D GTF_permit_access; + s->entries.v1[GNTTAB_RESERVED_XENSTORE].frame =3D XEN_SPECIAL_PFN(XENS= TORE); + + memset(s->map_track, 0, s->max_frames * ENTRIES_PER_FRAME_V1); + + return 0; +} diff --git a/hw/i386/kvm/xen_gnttab.h b/hw/i386/kvm/xen_gnttab.h index 3bdbe96191..ee215239b0 100644 --- a/hw/i386/kvm/xen_gnttab.h +++ b/hw/i386/kvm/xen_gnttab.h @@ -13,6 +13,7 @@ #define QEMU_XEN_GNTTAB_H =20 void xen_gnttab_create(void); +int xen_gnttab_reset(void); int xen_gnttab_map_page(uint64_t idx, uint64_t gfn); =20 struct gnttab_set_version; diff --git a/target/i386/kvm/xen-emu.c b/target/i386/kvm/xen-emu.c index bad3131d08..0bb6c601c9 100644 --- a/target/i386/kvm/xen-emu.c +++ b/target/i386/kvm/xen-emu.c @@ -1406,6 +1406,11 @@ int kvm_xen_soft_reset(void) return err; } =20 + err =3D xen_gnttab_reset(); + if (err) { + return err; + } + err =3D xen_xenstore_reset(); if (err) { return err; --=20 2.39.0 From nobody Fri May 3 04:42:41 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1677771358297657.056343302191; Thu, 2 Mar 2023 07:35:58 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pXkxq-0004KV-KM; Thu, 02 Mar 2023 10:35:26 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pXkxQ-0003ty-Js for qemu-devel@nongnu.org; Thu, 02 Mar 2023 10:35:05 -0500 Received: from desiato.infradead.org ([2001:8b0:10b:1:d65d:64ff:fe57:4e05]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pXkxN-0001gr-7T for qemu-devel@nongnu.org; Thu, 02 Mar 2023 10:35:00 -0500 Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by desiato.infradead.org with esmtpsa (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx5-00FL3u-0c; Thu, 02 Mar 2023 15:34:45 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx5-004uzz-0H; Thu, 02 Mar 2023 15:34:39 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=T2ES46G+W4wfRtbGgYULh0xnoiw027E1Epehblpp/UU=; b=Q6PRP+Ok4Y/LWFg5GT2Lo6owKb 6PzF3X/WY+wW19Qd6c5e2Ldj/TWoSmau5OeSFhd7wqiP14jiannTxtt4NsAXCNdD8DEQ2Q4vjt77f c1C7dV9Inqty2v6QOkHysCYsI8AoxZcPBSMIwPhZe13LBja6uDKcNlJpjq3lqQom9f29rGMQY5aBb aqwxKMzs4Z15CTvBJmfZWP9bJkeJecSW+v0Ou5CXvmaRMfdChC/4WPTs4/ZQDesOVK+L1NAezIqyO lCziKQDGt0ar2rUjdRS4MZstN/4FWKHH/BXG61f9T4ujzOCpzjHTD6q3SQMU89n8J8GEDM7cn6ePo I7hERoTw==; From: David Woodhouse To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , Stefano Stabellini , vikram.garhwal@amd.com, Anthony Perard , xen-devel@lists.xenproject.org Subject: [RFC PATCH v1 25/25] i386/xen: Initialize Xen backends from pc_basic_device_init() for emulation Date: Thu, 2 Mar 2023 15:34:35 +0000 Message-Id: <20230302153435.1170111-26-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230302153435.1170111-1-dwmw2@infradead.org> References: <20230302153435.1170111-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-SRS-Rewrite: SMTP reverse-path rewritten from by desiato.infradead.org. See http://www.infradead.org/rpr.html Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: none client-ip=2001:8b0:10b:1:d65d:64ff:fe57:4e05; envelope-from=BATV+9a0490e5ac528e462c30+7130+infradead.org+dwmw2@desiato.srs.infradead.org; helo=desiato.infradead.org X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1677771359698100015 Content-Type: text/plain; charset="utf-8" From: David Woodhouse Now that all the work is done to enable the PV backends to work without actual Xen, instantiate the bus from pc_basic_device_init() for emulated mode. This allows us finally to launch an emulated Xen guest with PV disk. qemu-system-x86_64 -serial mon:stdio -M q35 -cpu host -display none \ -m 1G -smp 2 -accel kvm,xen-version=3D0x4000a,kernel-irqchip=3Dsplit \ -kernel bzImage -append "console=3DttyS0 root=3D/dev/xvda1" \ -drive file=3D/var/lib/libvirt/images/fedora28.qcow2,if=3Dnone,id=3Ddi= sk \ -device xen-disk,drive=3Ddisk,vdev=3Dxvda If we use -M pc instead of q35, we can even add an IDE disk and boot a guest image normally through grub. But q35 gives us AHCI and that isn't unplugged by the Xen magic, so the guests ends up seeing "both" disks. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- hw/i386/pc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index fd17ce7a94..3fe028c86c 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -102,6 +102,11 @@ #include "trace.h" #include CONFIG_DEVICES =20 +#ifdef CONFIG_XEN_EMU +#include "hw/xen/xen-legacy-backend.h" +#include "hw/xen/xen-bus.h" +#endif + /* * Helper for setting model-id for CPU models that changed model-id * depending on QEMU versions up to QEMU 2.4. @@ -1318,6 +1323,8 @@ void pc_basic_device_init(struct PCMachineState *pcms, if (pcms->bus) { pci_create_simple(pcms->bus, -1, "xen-platform"); } + xen_bus_init(); + xen_be_init(); } #endif =20 --=20 2.39.0 From nobody Fri May 3 04:42:41 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1678206153344240.83730698581417; Tue, 7 Mar 2023 08:22:33 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pZa4g-0000zF-AI; Tue, 07 Mar 2023 11:22:02 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pZa4e-0000pb-6C for qemu-devel@nongnu.org; Tue, 07 Mar 2023 11:22:00 -0500 Received: from casper.infradead.org ([2001:8b0:10b:1236::1]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pZa4c-000799-2d for qemu-devel@nongnu.org; Tue, 07 Mar 2023 11:21:59 -0500 Received: from [2001:8b0:10b:5:640c:634b:db90:9c87] (helo=u3832b3a9db3152.ant.amazon.com) by casper.infradead.org with esmtpsa (Exim 4.94.2 #2 (Red Hat Linux)) id 1pZa4X-006YTQ-7M; Tue, 07 Mar 2023 16:21:53 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=MIME-Version:Content-Type:References: In-Reply-To:Date:Cc:To:From:Subject:Message-ID:Sender:Reply-To: Content-Transfer-Encoding:Content-ID:Content-Description; bh=hkgLMeScvQtXNmP8vLk5y3isKa3UBGhTjKl2IDsGIMk=; b=dpHhUxt6v9QZSravsSg0UVcvhC hG1q2ZJdiKnkWM1MFaEGbH39kbqQ2cqNJAfBjV1/kwTAKdH8qLgWfODSS0/+6bsEbxSDrb+sgLoAw jEP4pImJoF8V29yfQ9V7Fsz54g5y39VVLV1NcYLq3V4JN8fg9F7T4/GKCgExGIqnWUHPXZH4mU3pH 7rDTre8QfgjAb1gQjZzZ+4JIFCtaVsb3rId/xFRRiaCO6rTO9bvmFq5ylG7qy9b/e8S48dskLc+wy U2TNnMJUjddAjnI0aZrJklZd1GoNAWYJ2EHjPaZxeHB52DIiLHX0jqQ1dbehsHEvPJsa1p45DJm4V rc2DEdLw==; Message-ID: <945564aa2d51aa6cd6f9b179981ca3ded5c94190.camel@infradead.org> Subject: [RFC PATCH v1 26/25] MAINTAINERS: Add entry for Xen on KVM emulation From: David Woodhouse To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , Stefano Stabellini , vikram.garhwal@amd.com, Anthony Perard , xen-devel@lists.xenproject.org Date: Tue, 07 Mar 2023 16:21:52 +0000 In-Reply-To: <20230302153435.1170111-1-dwmw2@infradead.org> References: <20230302153435.1170111-1-dwmw2@infradead.org> Content-Type: multipart/signed; micalg="sha-256"; protocol="application/pkcs7-signature"; boundary="=-RnOalRUiVwy89vS9fhar" User-Agent: Evolution 3.44.4-0ubuntu1 MIME-Version: 1.0 X-SRS-Rewrite: SMTP reverse-path rewritten from by casper.infradead.org. See http://www.infradead.org/rpr.html Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: none client-ip=2001:8b0:10b:1236::1; envelope-from=BATV+9298a7250c90fe94fbb7+7135+infradead.org+dwmw2@casper.srs.infradead.org; helo=casper.infradead.org X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-Zoho-Virus-Status: 1 X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1678206153675100001 --=-RnOalRUiVwy89vS9fhar Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: David Woodhouse Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- MAINTAINERS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index da29661b37..76b705e467 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -443,6 +443,15 @@ F: target/i386/kvm/ F: target/i386/sev* F: scripts/kvm/vmxcap =20 +Xen emulation on X86 KVM CPUs +M: David Woodhouse +M: Paul Durrant +S: Supported +F: include/sysemu/kvm_xen.h +F: target/i386/kvm/xen* +F: hw/i386/kvm/xen* +F: tests/avocado/xen_guest.py + Guest CPU Cores (other accelerators) ------------------------------------ Overall --=20 2.34.1 --=-RnOalRUiVwy89vS9fhar Content-Type: application/pkcs7-signature; name="smime.p7s" Content-Disposition: attachment; filename="smime.p7s" Content-Transfer-Encoding: base64 MIAGCSqGSIb3DQEHAqCAMIACAQExDzANBglghkgBZQMEAgEFADCABgkqhkiG9w0BBwEAAKCCEkQw ggYQMIID+KADAgECAhBNlCwQ1DvglAnFgS06KwZPMA0GCSqGSIb3DQEBDAUAMIGIMQswCQYDVQQG EwJVUzETMBEGA1UECBMKTmV3IEplcnNleTEUMBIGA1UEBxMLSmVyc2V5IENpdHkxHjAcBgNVBAoT FVRoZSBVU0VSVFJVU1QgTmV0d29yazEuMCwGA1UEAxMlVVNFUlRydXN0IFJTQSBDZXJ0aWZpY2F0 aW9uIEF1dGhvcml0eTAeFw0xODExMDIwMDAwMDBaFw0zMDEyMzEyMzU5NTlaMIGWMQswCQYDVQQG EwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRgwFgYD VQQKEw9TZWN0aWdvIExpbWl0ZWQxPjA8BgNVBAMTNVNlY3RpZ28gUlNBIENsaWVudCBBdXRoZW50 aWNhdGlvbiBhbmQgU2VjdXJlIEVtYWlsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAyjztlApB/975Rrno1jvm2pK/KxBOqhq8gr2+JhwpKirSzZxQgT9tlC7zl6hn1fXjSo5MqXUf ItMltrMaXqcESJuK8dtK56NCSrq4iDKaKq9NxOXFmqXX2zN8HHGjQ2b2Xv0v1L5Nk1MQPKA19xeW QcpGEGFUUd0kN+oHox+L9aV1rjfNiCj3bJk6kJaOPabPi2503nn/ITX5e8WfPnGw4VuZ79Khj1YB rf24k5Ee1sLTHsLtpiK9OjG4iQRBdq6Z/TlVx/hGAez5h36bBJMxqdHLpdwIUkTqT8se3ed0PewD ch/8kHPo5fZl5u1B0ecpq/sDN/5sCG52Ds+QU5O5EwIDAQABo4IBZDCCAWAwHwYDVR0jBBgwFoAU U3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFAnA8vwL2pTbX/4r36iZQs/J4K0AMA4GA1Ud DwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF BQcDBDARBgNVHSAECjAIMAYGBFUdIAAwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2Vy dHJ1c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUF BwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJT QUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMA0G CSqGSIb3DQEBDAUAA4ICAQBBRHUAqznCFfXejpVtMnFojADdF9d6HBA4kMjjsb0XMZHztuOCtKF+ xswhh2GqkW5JQrM8zVlU+A2VP72Ky2nlRA1GwmIPgou74TZ/XTarHG8zdMSgaDrkVYzz1g3nIVO9 IHk96VwsacIvBF8JfqIs+8aWH2PfSUrNxP6Ys7U0sZYx4rXD6+cqFq/ZW5BUfClN/rhk2ddQXyn7 kkmka2RQb9d90nmNHdgKrwfQ49mQ2hWQNDkJJIXwKjYA6VUR/fZUFeCUisdDe/0ABLTI+jheXUV1 eoYV7lNwNBKpeHdNuO6Aacb533JlfeUHxvBz9OfYWUiXu09sMAviM11Q0DuMZ5760CdO2VnpsXP4 KxaYIhvqPqUMWqRdWyn7crItNkZeroXaecG03i3mM7dkiPaCkgocBg0EBYsbZDZ8bsG3a08LwEsL 1Ygz3SBsyECa0waq4hOf/Z85F2w2ZpXfP+w8q4ifwO90SGZZV+HR/Jh6rEaVPDRF/CEGVqR1hiuQ OZ1YL5ezMTX0ZSLwrymUE0pwi/KDaiYB15uswgeIAcA6JzPFf9pLkAFFWs1QNyN++niFhsM47qod x/PL+5jR87myx5uYdBEQkkDc+lKB1Wct6ucXqm2EmsaQ0M95QjTmy+rDWjkDYdw3Ms6mSWE3Bn7i 5ZgtwCLXgAIe5W8mybM2JzCCBhQwggT8oAMCAQICEQDGvhmWZ0DEAx0oURL6O6l+MA0GCSqGSIb3 DQEBCwUAMIGWMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD VQQHEwdTYWxmb3JkMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxPjA8BgNVBAMTNVNlY3RpZ28g UlNBIENsaWVudCBBdXRoZW50aWNhdGlvbiBhbmQgU2VjdXJlIEVtYWlsIENBMB4XDTIyMDEwNzAw MDAwMFoXDTI1MDEwNjIzNTk1OVowJDEiMCAGCSqGSIb3DQEJARYTZHdtdzJAaW5mcmFkZWFkLm9y ZzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQ3GpC2bomUqk+91wLYBzDMcCj5C9m6 oZaHwvmIdXftOgTbCJXADo6G9T7BBAebw2JV38EINgKpy/ZHh7htyAkWYVoFsFPrwHounto8xTsy SSePMiPlmIdQ10BcVSXMUJ3Juu16GlWOnAMJY2oYfEzmE7uT9YgcBqKCo65pTFmOnR/VVbjJk4K2 xE34GC2nAdUQkPFuyaFisicc6HRMOYXPuF0DuwITEKnjxgNjP+qDrh0db7PAjO1D4d5ftfrsf+kd RR4gKVGSk8Tz2WwvtLAroJM4nXjNPIBJNT4w/FWWc/5qPHJy2U+eITZ5LLE5s45mX2oPFknWqxBo bQZ8a9dsZ3dSPZBvE9ZrmtFLrVrN4eo1jsXgAp1+p7bkfqd3BgBEmfsYWlBXO8rVXfvPgLs32VdV NZxb/CDWPqBsiYv0Hv3HPsz07j5b+/cVoWqyHDKzkaVbxfq/7auNVRmPB3v5SWEsH8xi4Bez2V9U KxfYCnqsjp8RaC2/khxKt0A552Eaxnz/4ly/2C7wkwTQnBmdlFYhAflWKQ03Ufiu8t3iBE3VJbc2 5oMrglj7TRZrmKq3CkbFnX0fyulB+kHimrt6PIWn7kgyl9aelIl6vtbhMA+l0nfrsORMa4kobqQ5 C5rveVgmcIad67EDa+UqEKy/GltUwlSh6xy+TrK1tzDvAgMBAAGjggHMMIIByDAfBgNVHSMEGDAW gBQJwPL8C9qU21/+K9+omULPyeCtADAdBgNVHQ4EFgQUzMeDMcimo0oz8o1R1Nver3ZVpSkwDgYD VR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYwFAYIKwYBBQUHAwQGCCsGAQUFBwMC MEAGA1UdIAQ5MDcwNQYMKwYBBAGyMQECAQEBMCUwIwYIKwYBBQUHAgEWF2h0dHBzOi8vc2VjdGln by5jb20vQ1BTMFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9jcmwuc2VjdGlnby5jb20vU2VjdGln b1JTQUNsaWVudEF1dGhlbnRpY2F0aW9uYW5kU2VjdXJlRW1haWxDQS5jcmwwgYoGCCsGAQUFBwEB BH4wfDBVBggrBgEFBQcwAoZJaHR0cDovL2NydC5zZWN0aWdvLmNvbS9TZWN0aWdvUlNBQ2xpZW50 QXV0aGVudGljYXRpb25hbmRTZWN1cmVFbWFpbENBLmNydDAjBggrBgEFBQcwAYYXaHR0cDovL29j c3Auc2VjdGlnby5jb20wHgYDVR0RBBcwFYETZHdtdzJAaW5mcmFkZWFkLm9yZzANBgkqhkiG9w0B AQsFAAOCAQEAyW6MUir5dm495teKqAQjDJwuFCi35h4xgnQvQ/fzPXmtR9t54rpmI2TfyvcKgOXp qa7BGXNFfh1JsqexVkIqZP9uWB2J+uVMD+XZEs/KYNNX2PvIlSPrzIB4Z2wyIGQpaPLlYflrrVFK v9CjT2zdqvy2maK7HKOQRt3BiJbVG5lRiwbbygldcALEV9ChWFfgSXvrWDZspnU3Gjw/rMHrGnql Htlyebp3pf3fSS9kzQ1FVtVIDrL6eqhTwJxe+pXSMMqFiN0whpBtXdyDjzBtQTaZJ7zTT/vlehc/ tDuqZwGHm/YJy883Ll+GP3NvOkgaRGWEuYWJJ6hFCkXYjyR9IzCCBhQwggT8oAMCAQICEQDGvhmW Z0DEAx0oURL6O6l+MA0GCSqGSIb3DQEBCwUAMIGWMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0 ZWQxPjA8BgNVBAMTNVNlY3RpZ28gUlNBIENsaWVudCBBdXRoZW50aWNhdGlvbiBhbmQgU2VjdXJl IEVtYWlsIENBMB4XDTIyMDEwNzAwMDAwMFoXDTI1MDEwNjIzNTk1OVowJDEiMCAGCSqGSIb3DQEJ ARYTZHdtdzJAaW5mcmFkZWFkLm9yZzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQ3 GpC2bomUqk+91wLYBzDMcCj5C9m6oZaHwvmIdXftOgTbCJXADo6G9T7BBAebw2JV38EINgKpy/ZH h7htyAkWYVoFsFPrwHounto8xTsySSePMiPlmIdQ10BcVSXMUJ3Juu16GlWOnAMJY2oYfEzmE7uT 9YgcBqKCo65pTFmOnR/VVbjJk4K2xE34GC2nAdUQkPFuyaFisicc6HRMOYXPuF0DuwITEKnjxgNj P+qDrh0db7PAjO1D4d5ftfrsf+kdRR4gKVGSk8Tz2WwvtLAroJM4nXjNPIBJNT4w/FWWc/5qPHJy 2U+eITZ5LLE5s45mX2oPFknWqxBobQZ8a9dsZ3dSPZBvE9ZrmtFLrVrN4eo1jsXgAp1+p7bkfqd3 BgBEmfsYWlBXO8rVXfvPgLs32VdVNZxb/CDWPqBsiYv0Hv3HPsz07j5b+/cVoWqyHDKzkaVbxfq/ 7auNVRmPB3v5SWEsH8xi4Bez2V9UKxfYCnqsjp8RaC2/khxKt0A552Eaxnz/4ly/2C7wkwTQnBmd lFYhAflWKQ03Ufiu8t3iBE3VJbc25oMrglj7TRZrmKq3CkbFnX0fyulB+kHimrt6PIWn7kgyl9ae lIl6vtbhMA+l0nfrsORMa4kobqQ5C5rveVgmcIad67EDa+UqEKy/GltUwlSh6xy+TrK1tzDvAgMB AAGjggHMMIIByDAfBgNVHSMEGDAWgBQJwPL8C9qU21/+K9+omULPyeCtADAdBgNVHQ4EFgQUzMeD Mcimo0oz8o1R1Nver3ZVpSkwDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYw FAYIKwYBBQUHAwQGCCsGAQUFBwMCMEAGA1UdIAQ5MDcwNQYMKwYBBAGyMQECAQEBMCUwIwYIKwYB BQUHAgEWF2h0dHBzOi8vc2VjdGlnby5jb20vQ1BTMFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9j cmwuc2VjdGlnby5jb20vU2VjdGlnb1JTQUNsaWVudEF1dGhlbnRpY2F0aW9uYW5kU2VjdXJlRW1h aWxDQS5jcmwwgYoGCCsGAQUFBwEBBH4wfDBVBggrBgEFBQcwAoZJaHR0cDovL2NydC5zZWN0aWdv LmNvbS9TZWN0aWdvUlNBQ2xpZW50QXV0aGVudGljYXRpb25hbmRTZWN1cmVFbWFpbENBLmNydDAj BggrBgEFBQcwAYYXaHR0cDovL29jc3Auc2VjdGlnby5jb20wHgYDVR0RBBcwFYETZHdtdzJAaW5m cmFkZWFkLm9yZzANBgkqhkiG9w0BAQsFAAOCAQEAyW6MUir5dm495teKqAQjDJwuFCi35h4xgnQv Q/fzPXmtR9t54rpmI2TfyvcKgOXpqa7BGXNFfh1JsqexVkIqZP9uWB2J+uVMD+XZEs/KYNNX2PvI lSPrzIB4Z2wyIGQpaPLlYflrrVFKv9CjT2zdqvy2maK7HKOQRt3BiJbVG5lRiwbbygldcALEV9Ch WFfgSXvrWDZspnU3Gjw/rMHrGnqlHtlyebp3pf3fSS9kzQ1FVtVIDrL6eqhTwJxe+pXSMMqFiN0w hpBtXdyDjzBtQTaZJ7zTT/vlehc/tDuqZwGHm/YJy883Ll+GP3NvOkgaRGWEuYWJJ6hFCkXYjyR9 IzGCBMcwggTDAgEBMIGsMIGWMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVz dGVyMRAwDgYDVQQHEwdTYWxmb3JkMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxPjA8BgNVBAMT NVNlY3RpZ28gUlNBIENsaWVudCBBdXRoZW50aWNhdGlvbiBhbmQgU2VjdXJlIEVtYWlsIENBAhEA xr4ZlmdAxAMdKFES+jupfjANBglghkgBZQMEAgEFAKCCAeswGAYJKoZIhvcNAQkDMQsGCSqGSIb3 DQEHATAcBgkqhkiG9w0BCQUxDxcNMjMwMzA3MTYyMTUyWjAvBgkqhkiG9w0BCQQxIgQgZzQeIAhc 7QQgDi03bxYniNvKTrFfHIOILJ/7Hkuz5CEwgb0GCSsGAQQBgjcQBDGBrzCBrDCBljELMAkGA1UE BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYG A1UEChMPU2VjdGlnbyBMaW1pdGVkMT4wPAYDVQQDEzVTZWN0aWdvIFJTQSBDbGllbnQgQXV0aGVu dGljYXRpb24gYW5kIFNlY3VyZSBFbWFpbCBDQQIRAMa+GZZnQMQDHShREvo7qX4wgb8GCyqGSIb3 DQEJEAILMYGvoIGsMIGWMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVy MRAwDgYDVQQHEwdTYWxmb3JkMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxPjA8BgNVBAMTNVNl Y3RpZ28gUlNBIENsaWVudCBBdXRoZW50aWNhdGlvbiBhbmQgU2VjdXJlIEVtYWlsIENBAhEAxr4Z lmdAxAMdKFES+jupfjANBgkqhkiG9w0BAQEFAASCAgBVepFemNwm0FU05xxDEsdUZauRarZdG4+2 RSoP8lC7x/ZDddIfd4vh77lpEJz1DghzBxrNYqPpPS3DiKdSW2fs2aI/eOUnkqEnmNrdRh3cCB6L pcpHU7PFRKv9ZL2KxLlYnYvt+72XDin79sjN2AkyBINRmn6dYyDJySqJ8/eYZuF6bwP6SOwwnPXw lOGbeCGXm8yLRz+P4ILxDVWBTk+Rd+UPo0qWSvRcjKoHIrOl2/pMl3ETEVCAlOTsbHtkeg756fdZ 1ov6F3Hwieh+Pxt0HN75iVJSdu1MEb0TrwWp5OHByz70BuwQEPyyenvTpGYKU4qTjlYRuizb2gXu Z1jIk0lacuHj2YRCbmZmACjcirSEg+ZsehvpEaD8bnOrUlfG5cSACuqGznDNYcCvtwOHF+MoRuLo TbxSK2hs+iyGEOodmeAz3hByUA5zQC+O/h3WuAvoMDhpJ1vF9dRFvW3XvIHDk7u592144C8wFbxo H2bdlgXAIHXw95tHdqax81hAd7vF6FUdpMTG9jrXCJDTpQ9Y7GPAmHDMX5SqisCiXyAvIWGi6yYx g5B7D334JvUL1LsTs29fJDgN0arJB2sMhBK581LkPX6E9vL3VuJRQpi9AJSrS/ZDn4Aei0qJKCoI eToYG0vPo0Lmrenw6Xtyxis+STb8c6XQ3Lkwa4f9bwAAAAAAAA== --=-RnOalRUiVwy89vS9fhar-- From nobody Fri May 3 04:42:41 2024 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=fail; 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 Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1678206202410367.04706431169177; Tue, 7 Mar 2023 08:23:22 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.507589.781289 (Exim 4.92) (envelope-from ) id 1pZa5a-00043h-DV; Tue, 07 Mar 2023 16:22:58 +0000 Received: by outflank-mailman (output) from mailman id 507589.781289; Tue, 07 Mar 2023 16:22:58 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pZa5a-00043a-AO; Tue, 07 Mar 2023 16:22:58 +0000 Received: by outflank-mailman (input) for mailman id 507589; Tue, 07 Mar 2023 16:22:57 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pZa5Z-0003Ki-Js for xen-devel@lists.xenproject.org; Tue, 07 Mar 2023 16:22:57 +0000 Received: from casper.infradead.org (casper.infradead.org [2001:8b0:10b:1236::1]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id 4f48674d-bd04-11ed-a550-8520e6686977; Tue, 07 Mar 2023 17:22:55 +0100 (CET) Received: from [2001:8b0:10b:5:640c:634b:db90:9c87] (helo=u3832b3a9db3152.ant.amazon.com) by casper.infradead.org with esmtpsa (Exim 4.94.2 #2 (Red Hat Linux)) id 1pZa5Q-006YZ0-3p; Tue, 07 Mar 2023 16:22:48 +0000 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: 4f48674d-bd04-11ed-a550-8520e6686977 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=MIME-Version:Content-Type:References: In-Reply-To:Date:Cc:To:From:Subject:Message-ID:Sender:Reply-To: Content-Transfer-Encoding:Content-ID:Content-Description; bh=nNhyhMhwfXBKddqL0/8UN9Xo0T2a9NXo9/sjONe8BOk=; b=thidL2pmJz3CPwZNpsw2A/39vX nuzNNcWhl2EV/b8yasNrtUlJLkdb0o1wrf8/c3a+3qSmY8jf3+qD8sfCNnXFAgYZOU6+7MP5WEUAl IDVOo+3839P0hFOi//7y/oNSAR42KpkUyej39+4iD0d6cGbOQ7y3UuS4pa6W/z0uyWPDhJfAvOSRp FigLqDsM3HhC54qRAhD5Tds0KfcEYwabPnialtxNISyfExZeNYvoZE3RpcAvESds+uud8rUTdKdYk DwAL+ZzLqT4qyhxS3L34es/tYyk+XjtEylHMcGIHDblFlg26DOgNKMBGzWHZSe3WFEKI7d8GWLCVI XFq9X8kg==; Message-ID: <1de346bcc550da15f43c9efe05cb98ea57260df2.camel@infradead.org> Subject: [RFC PATCH v1 27/25] docs: Update Xen-on-KVM documentation for PV disk support From: David Woodhouse To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , Stefano Stabellini , vikram.garhwal@amd.com, Anthony Perard , xen-devel@lists.xenproject.org Date: Tue, 07 Mar 2023 16:22:47 +0000 In-Reply-To: <20230302153435.1170111-1-dwmw2@infradead.org> References: <20230302153435.1170111-1-dwmw2@infradead.org> Content-Type: multipart/signed; micalg="sha-256"; protocol="application/pkcs7-signature"; boundary="=-hMr61SxQiFbEJlG4AHmT" User-Agent: Evolution 3.44.4-0ubuntu1 MIME-Version: 1.0 X-SRS-Rewrite: SMTP reverse-path rewritten from by casper.infradead.org. See http://www.infradead.org/rpr.html X-Zoho-Virus-Status: 1 X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1678206204055100001 --=-hMr61SxQiFbEJlG4AHmT Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: David Woodhouse Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- docs/system/i386/xen.rst | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/docs/system/i386/xen.rst b/docs/system/i386/xen.rst index a00523b492..f06765e88c 100644 --- a/docs/system/i386/xen.rst +++ b/docs/system/i386/xen.rst @@ -9,6 +9,8 @@ KVM has support for hosting Xen guests, intercepting Xen hy= percalls and event channel (Xen PV interrupt) delivery. This allows guests which expect to be run under Xen to be hosted in QEMU under Linux/KVM instead. =20 +Using the split irqchip is mandatory for Xen support. + Setup ----- =20 @@ -17,14 +19,14 @@ accelerator, for example for Xen 4.10: =20 .. parsed-literal:: =20 - |qemu_system| --accel kvm,xen-version=3D0x4000a + |qemu_system| --accel kvm,xen-version=3D0x4000a,kernel-irqchip=3Dsplit =20 Additionally, virtual APIC support can be advertised to the guest through = the ``xen-vapic`` CPU flag: =20 .. parsed-literal:: =20 - |qemu_system| --accel kvm,xen-version=3D0x4000a --cpu host,+xen_vapic + |qemu_system| --accel kvm,xen-version=3D0x4000a,kernel-irqchip=3Dsplit -= -cpu host,+xen_vapic =20 When Xen support is enabled, QEMU changes hypervisor identification (CPUID 0x40000000..0x4000000A) to Xen. The KVM identification and features are not @@ -33,11 +35,25 @@ moves to leaves 0x40000100..0x4000010A. =20 The Xen platform device is enabled automatically for a Xen guest. This all= ows a guest to unplug all emulated devices, in order to use Xen PV block and n= etwork -drivers instead. Note that until the Xen PV device back ends are enabled t= o work -with Xen mode in QEMU, that is unlikely to cause significant joy. Linux gu= ests -can be dissuaded from this by adding 'xen_emul_unplug=3Dnever' on their co= mmand -line, and it can also be noted that AHCI disk controllers are exempt from = being -unplugged, as are passthrough VFIO PCI devices. +drivers instead. Under Xen, the boot disk is typically available both via = IDE +emulation, and as a PV block device. Guest bootloaders typically use IDE t= o load +the guest kernel, which then unplugs the IDE and continues with the Xen PV= block +device. + +This configuration can be achieved as follows + +.. parsed-literal:: + + |qemu_system| -M pc --accel kvm,xen-version=3D0x4000a,kernel-irqchip=3Ds= plit \\ + -drive file=3D${GUEST_IMAGE},if=3Dnone,id=3Ddisk,file.locking=3Doff= -device xen-disk,drive=3Ddisk,vdev=3Dxvda \\ + -drive file=3D${GUEST_IMAGE},index=3D2,media=3Ddisk,file.locking=3D= off,if=3Dide + +It is necessary to use the pc machine type, as the q35 machine uses AHCI i= nstead +of legacy IDE, and AHCI disks are not unplugged through the Xen PV unplug +mechanism. + +VirtIO devices can also be used; Linux guests may need to be dissuaded from +umplugging them by adding 'xen_emul_unplug=3Dnever' on their command line. =20 Properties ---------- --=20 2.34.1 --=-hMr61SxQiFbEJlG4AHmT Content-Type: application/pkcs7-signature; name="smime.p7s" Content-Disposition: attachment; filename="smime.p7s" Content-Transfer-Encoding: base64 MIAGCSqGSIb3DQEHAqCAMIACAQExDzANBglghkgBZQMEAgEFADCABgkqhkiG9w0BBwEAAKCCEkQw ggYQMIID+KADAgECAhBNlCwQ1DvglAnFgS06KwZPMA0GCSqGSIb3DQEBDAUAMIGIMQswCQYDVQQG EwJVUzETMBEGA1UECBMKTmV3IEplcnNleTEUMBIGA1UEBxMLSmVyc2V5IENpdHkxHjAcBgNVBAoT FVRoZSBVU0VSVFJVU1QgTmV0d29yazEuMCwGA1UEAxMlVVNFUlRydXN0IFJTQSBDZXJ0aWZpY2F0 aW9uIEF1dGhvcml0eTAeFw0xODExMDIwMDAwMDBaFw0zMDEyMzEyMzU5NTlaMIGWMQswCQYDVQQG EwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRgwFgYD VQQKEw9TZWN0aWdvIExpbWl0ZWQxPjA8BgNVBAMTNVNlY3RpZ28gUlNBIENsaWVudCBBdXRoZW50 aWNhdGlvbiBhbmQgU2VjdXJlIEVtYWlsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAyjztlApB/975Rrno1jvm2pK/KxBOqhq8gr2+JhwpKirSzZxQgT9tlC7zl6hn1fXjSo5MqXUf ItMltrMaXqcESJuK8dtK56NCSrq4iDKaKq9NxOXFmqXX2zN8HHGjQ2b2Xv0v1L5Nk1MQPKA19xeW QcpGEGFUUd0kN+oHox+L9aV1rjfNiCj3bJk6kJaOPabPi2503nn/ITX5e8WfPnGw4VuZ79Khj1YB rf24k5Ee1sLTHsLtpiK9OjG4iQRBdq6Z/TlVx/hGAez5h36bBJMxqdHLpdwIUkTqT8se3ed0PewD ch/8kHPo5fZl5u1B0ecpq/sDN/5sCG52Ds+QU5O5EwIDAQABo4IBZDCCAWAwHwYDVR0jBBgwFoAU U3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFAnA8vwL2pTbX/4r36iZQs/J4K0AMA4GA1Ud DwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF BQcDBDARBgNVHSAECjAIMAYGBFUdIAAwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2Vy dHJ1c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUF BwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJT QUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMA0G CSqGSIb3DQEBDAUAA4ICAQBBRHUAqznCFfXejpVtMnFojADdF9d6HBA4kMjjsb0XMZHztuOCtKF+ xswhh2GqkW5JQrM8zVlU+A2VP72Ky2nlRA1GwmIPgou74TZ/XTarHG8zdMSgaDrkVYzz1g3nIVO9 IHk96VwsacIvBF8JfqIs+8aWH2PfSUrNxP6Ys7U0sZYx4rXD6+cqFq/ZW5BUfClN/rhk2ddQXyn7 kkmka2RQb9d90nmNHdgKrwfQ49mQ2hWQNDkJJIXwKjYA6VUR/fZUFeCUisdDe/0ABLTI+jheXUV1 eoYV7lNwNBKpeHdNuO6Aacb533JlfeUHxvBz9OfYWUiXu09sMAviM11Q0DuMZ5760CdO2VnpsXP4 KxaYIhvqPqUMWqRdWyn7crItNkZeroXaecG03i3mM7dkiPaCkgocBg0EBYsbZDZ8bsG3a08LwEsL 1Ygz3SBsyECa0waq4hOf/Z85F2w2ZpXfP+w8q4ifwO90SGZZV+HR/Jh6rEaVPDRF/CEGVqR1hiuQ OZ1YL5ezMTX0ZSLwrymUE0pwi/KDaiYB15uswgeIAcA6JzPFf9pLkAFFWs1QNyN++niFhsM47qod x/PL+5jR87myx5uYdBEQkkDc+lKB1Wct6ucXqm2EmsaQ0M95QjTmy+rDWjkDYdw3Ms6mSWE3Bn7i 5ZgtwCLXgAIe5W8mybM2JzCCBhQwggT8oAMCAQICEQDGvhmWZ0DEAx0oURL6O6l+MA0GCSqGSIb3 DQEBCwUAMIGWMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD VQQHEwdTYWxmb3JkMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxPjA8BgNVBAMTNVNlY3RpZ28g UlNBIENsaWVudCBBdXRoZW50aWNhdGlvbiBhbmQgU2VjdXJlIEVtYWlsIENBMB4XDTIyMDEwNzAw MDAwMFoXDTI1MDEwNjIzNTk1OVowJDEiMCAGCSqGSIb3DQEJARYTZHdtdzJAaW5mcmFkZWFkLm9y ZzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQ3GpC2bomUqk+91wLYBzDMcCj5C9m6 oZaHwvmIdXftOgTbCJXADo6G9T7BBAebw2JV38EINgKpy/ZHh7htyAkWYVoFsFPrwHounto8xTsy SSePMiPlmIdQ10BcVSXMUJ3Juu16GlWOnAMJY2oYfEzmE7uT9YgcBqKCo65pTFmOnR/VVbjJk4K2 xE34GC2nAdUQkPFuyaFisicc6HRMOYXPuF0DuwITEKnjxgNjP+qDrh0db7PAjO1D4d5ftfrsf+kd RR4gKVGSk8Tz2WwvtLAroJM4nXjNPIBJNT4w/FWWc/5qPHJy2U+eITZ5LLE5s45mX2oPFknWqxBo bQZ8a9dsZ3dSPZBvE9ZrmtFLrVrN4eo1jsXgAp1+p7bkfqd3BgBEmfsYWlBXO8rVXfvPgLs32VdV NZxb/CDWPqBsiYv0Hv3HPsz07j5b+/cVoWqyHDKzkaVbxfq/7auNVRmPB3v5SWEsH8xi4Bez2V9U KxfYCnqsjp8RaC2/khxKt0A552Eaxnz/4ly/2C7wkwTQnBmdlFYhAflWKQ03Ufiu8t3iBE3VJbc2 5oMrglj7TRZrmKq3CkbFnX0fyulB+kHimrt6PIWn7kgyl9aelIl6vtbhMA+l0nfrsORMa4kobqQ5 C5rveVgmcIad67EDa+UqEKy/GltUwlSh6xy+TrK1tzDvAgMBAAGjggHMMIIByDAfBgNVHSMEGDAW gBQJwPL8C9qU21/+K9+omULPyeCtADAdBgNVHQ4EFgQUzMeDMcimo0oz8o1R1Nver3ZVpSkwDgYD VR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYwFAYIKwYBBQUHAwQGCCsGAQUFBwMC MEAGA1UdIAQ5MDcwNQYMKwYBBAGyMQECAQEBMCUwIwYIKwYBBQUHAgEWF2h0dHBzOi8vc2VjdGln by5jb20vQ1BTMFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9jcmwuc2VjdGlnby5jb20vU2VjdGln b1JTQUNsaWVudEF1dGhlbnRpY2F0aW9uYW5kU2VjdXJlRW1haWxDQS5jcmwwgYoGCCsGAQUFBwEB BH4wfDBVBggrBgEFBQcwAoZJaHR0cDovL2NydC5zZWN0aWdvLmNvbS9TZWN0aWdvUlNBQ2xpZW50 QXV0aGVudGljYXRpb25hbmRTZWN1cmVFbWFpbENBLmNydDAjBggrBgEFBQcwAYYXaHR0cDovL29j c3Auc2VjdGlnby5jb20wHgYDVR0RBBcwFYETZHdtdzJAaW5mcmFkZWFkLm9yZzANBgkqhkiG9w0B AQsFAAOCAQEAyW6MUir5dm495teKqAQjDJwuFCi35h4xgnQvQ/fzPXmtR9t54rpmI2TfyvcKgOXp qa7BGXNFfh1JsqexVkIqZP9uWB2J+uVMD+XZEs/KYNNX2PvIlSPrzIB4Z2wyIGQpaPLlYflrrVFK v9CjT2zdqvy2maK7HKOQRt3BiJbVG5lRiwbbygldcALEV9ChWFfgSXvrWDZspnU3Gjw/rMHrGnql Htlyebp3pf3fSS9kzQ1FVtVIDrL6eqhTwJxe+pXSMMqFiN0whpBtXdyDjzBtQTaZJ7zTT/vlehc/ tDuqZwGHm/YJy883Ll+GP3NvOkgaRGWEuYWJJ6hFCkXYjyR9IzCCBhQwggT8oAMCAQICEQDGvhmW Z0DEAx0oURL6O6l+MA0GCSqGSIb3DQEBCwUAMIGWMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0 ZWQxPjA8BgNVBAMTNVNlY3RpZ28gUlNBIENsaWVudCBBdXRoZW50aWNhdGlvbiBhbmQgU2VjdXJl IEVtYWlsIENBMB4XDTIyMDEwNzAwMDAwMFoXDTI1MDEwNjIzNTk1OVowJDEiMCAGCSqGSIb3DQEJ ARYTZHdtdzJAaW5mcmFkZWFkLm9yZzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQ3 GpC2bomUqk+91wLYBzDMcCj5C9m6oZaHwvmIdXftOgTbCJXADo6G9T7BBAebw2JV38EINgKpy/ZH h7htyAkWYVoFsFPrwHounto8xTsySSePMiPlmIdQ10BcVSXMUJ3Juu16GlWOnAMJY2oYfEzmE7uT 9YgcBqKCo65pTFmOnR/VVbjJk4K2xE34GC2nAdUQkPFuyaFisicc6HRMOYXPuF0DuwITEKnjxgNj P+qDrh0db7PAjO1D4d5ftfrsf+kdRR4gKVGSk8Tz2WwvtLAroJM4nXjNPIBJNT4w/FWWc/5qPHJy 2U+eITZ5LLE5s45mX2oPFknWqxBobQZ8a9dsZ3dSPZBvE9ZrmtFLrVrN4eo1jsXgAp1+p7bkfqd3 BgBEmfsYWlBXO8rVXfvPgLs32VdVNZxb/CDWPqBsiYv0Hv3HPsz07j5b+/cVoWqyHDKzkaVbxfq/ 7auNVRmPB3v5SWEsH8xi4Bez2V9UKxfYCnqsjp8RaC2/khxKt0A552Eaxnz/4ly/2C7wkwTQnBmd lFYhAflWKQ03Ufiu8t3iBE3VJbc25oMrglj7TRZrmKq3CkbFnX0fyulB+kHimrt6PIWn7kgyl9ae lIl6vtbhMA+l0nfrsORMa4kobqQ5C5rveVgmcIad67EDa+UqEKy/GltUwlSh6xy+TrK1tzDvAgMB AAGjggHMMIIByDAfBgNVHSMEGDAWgBQJwPL8C9qU21/+K9+omULPyeCtADAdBgNVHQ4EFgQUzMeD Mcimo0oz8o1R1Nver3ZVpSkwDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYw FAYIKwYBBQUHAwQGCCsGAQUFBwMCMEAGA1UdIAQ5MDcwNQYMKwYBBAGyMQECAQEBMCUwIwYIKwYB BQUHAgEWF2h0dHBzOi8vc2VjdGlnby5jb20vQ1BTMFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9j cmwuc2VjdGlnby5jb20vU2VjdGlnb1JTQUNsaWVudEF1dGhlbnRpY2F0aW9uYW5kU2VjdXJlRW1h aWxDQS5jcmwwgYoGCCsGAQUFBwEBBH4wfDBVBggrBgEFBQcwAoZJaHR0cDovL2NydC5zZWN0aWdv LmNvbS9TZWN0aWdvUlNBQ2xpZW50QXV0aGVudGljYXRpb25hbmRTZWN1cmVFbWFpbENBLmNydDAj BggrBgEFBQcwAYYXaHR0cDovL29jc3Auc2VjdGlnby5jb20wHgYDVR0RBBcwFYETZHdtdzJAaW5m cmFkZWFkLm9yZzANBgkqhkiG9w0BAQsFAAOCAQEAyW6MUir5dm495teKqAQjDJwuFCi35h4xgnQv Q/fzPXmtR9t54rpmI2TfyvcKgOXpqa7BGXNFfh1JsqexVkIqZP9uWB2J+uVMD+XZEs/KYNNX2PvI lSPrzIB4Z2wyIGQpaPLlYflrrVFKv9CjT2zdqvy2maK7HKOQRt3BiJbVG5lRiwbbygldcALEV9Ch WFfgSXvrWDZspnU3Gjw/rMHrGnqlHtlyebp3pf3fSS9kzQ1FVtVIDrL6eqhTwJxe+pXSMMqFiN0w hpBtXdyDjzBtQTaZJ7zTT/vlehc/tDuqZwGHm/YJy883Ll+GP3NvOkgaRGWEuYWJJ6hFCkXYjyR9 IzGCBMcwggTDAgEBMIGsMIGWMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVz dGVyMRAwDgYDVQQHEwdTYWxmb3JkMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxPjA8BgNVBAMT NVNlY3RpZ28gUlNBIENsaWVudCBBdXRoZW50aWNhdGlvbiBhbmQgU2VjdXJlIEVtYWlsIENBAhEA xr4ZlmdAxAMdKFES+jupfjANBglghkgBZQMEAgEFAKCCAeswGAYJKoZIhvcNAQkDMQsGCSqGSIb3 DQEHATAcBgkqhkiG9w0BCQUxDxcNMjMwMzA3MTYyMjQ3WjAvBgkqhkiG9w0BCQQxIgQg2H3ZM2Q9 3rfKG9QoaBNr2GIOtU55IqxM3ing4YmPNcAwgb0GCSsGAQQBgjcQBDGBrzCBrDCBljELMAkGA1UE BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYG A1UEChMPU2VjdGlnbyBMaW1pdGVkMT4wPAYDVQQDEzVTZWN0aWdvIFJTQSBDbGllbnQgQXV0aGVu dGljYXRpb24gYW5kIFNlY3VyZSBFbWFpbCBDQQIRAMa+GZZnQMQDHShREvo7qX4wgb8GCyqGSIb3 DQEJEAILMYGvoIGsMIGWMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVy MRAwDgYDVQQHEwdTYWxmb3JkMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxPjA8BgNVBAMTNVNl Y3RpZ28gUlNBIENsaWVudCBBdXRoZW50aWNhdGlvbiBhbmQgU2VjdXJlIEVtYWlsIENBAhEAxr4Z lmdAxAMdKFES+jupfjANBgkqhkiG9w0BAQEFAASCAgAh+vEWnRVDD4GADfb+4rZXQ96Ttzo+zyk2 UxO5O9jFh/dN95Y5CvXSkAfPdNoaySvYgYVFNhefUHEhGWCNMq+8MknAM+CJA46o1inuQ6jHNXuh jWayY+jT7v9yIKaAfifKZfpXmvIanlhLq5xCTCCSlYGEatXm3fXqWp9dbG45XPbpHBKvlsHaB9Sz FNa3lWgYUeWSIR04HWSLcs3eO/2BwEEXU7cJH4ROeedvluF/J8cG/INqYape05Jr3753UhAzquTC jIZBJc5aqNxi5WXJfCpBs5/h68G+F6O02uZOrDwWWpeBke2ffT3SbpGIshXurBIYgB7NiOsTYugl vGiVYJW77IGPs/n21oQY4QLl67MgLEz9MKKhSGGvz8ls03dgaUlhHHoNFwVIjkIh/lC5NuZihwo9 BSOJqA40XAhWaMUdvA9SXDOPkctF7EIekkWB0QJxT9EkRm/40kXHuteUX8eoJSY3dwh2rS+5Yz5e WWbhr9OG2eiMitgCjySPzYW4z0ajqeYss9gc7xUKveDDIKO0pyV663nt8oBmssxOONhfDx+DJ2vy BtPh81WD3gKN+1nI5g0tmj3fHbc1AWfu9ioHSxwA0Zt6v59WTlINc3RQC/WnHJUFYDkmH2yvuqm2 vHsssIEoZI+MQAxIFV/8SibG97X8u2FtZF2RPO+6hAAAAAAAAA== --=-hMr61SxQiFbEJlG4AHmT--