From nobody Sat May 18 22:31:26 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 1676540827642129.6431567811486; Thu, 16 Feb 2023 01:47:07 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pSapP-0000V6-2y; Thu, 16 Feb 2023 04:45: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 1pSap4-00009S-HF for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:45:02 -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 1pSaoy-0006LB-5f for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:45:02 -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 1pSao2-00AEEu-10; Thu, 16 Feb 2023 09:44:44 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pSaoi-0090BE-1V; Thu, 16 Feb 2023 09:44:40 +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=o6VRuYNucgV7HKFoom+PQYxq9jyb5QygRTZEE7yOiaI=; b=F3JSPM85ipOo+IYCz5CD4ZhxjR dLyIx3IBHE9uBZyQiyAzu5rvGlEDOxtX0IlU7HfVsg67XDQ3K0jJyBm3w7DTQQdJkcgFN61th/iJu A2DhpFOsl+Hf/Ex8vKsY7BMnkEYNUqt1+y2R5ZodDsA9IIvYK1m0wAepeMrBz4tI+MKqfGSiI5HEK Jaus2cpY+IJDuoHU80ir+RjqgkAyWfWQzGuL2wcf6kkFJJHv+j4WReJi0umznZdoGGDJuDiE3fpPW zeJqaK8qbNs0RrroTABShHGFO5AufVwyd1T9kFj80MQm/JALcltaycFI5+OkblVkLwgp0BLaWJ2r8 8s5EI3wA==; From: David Woodhouse To: Peter Maydell , qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Juan Quintela , "Dr . David Alan Gilbert" , Claudio Fontana , Julien Grall , "Michael S. Tsirkin" , Marcel Apfelbaum , armbru@redhat.com, Stefano Stabellini , vikram.garhwal@amd.com Subject: [RFC PATCH v11bis 01/26] hw/xen: Add xenstore wire implementation and implementation stubs Date: Thu, 16 Feb 2023 09:44:11 +0000 Message-Id: <20230216094436.2144978-2-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230216094436.2144978-1-dwmw2@infradead.org> References: <20230216094436.2144978-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+96e41a9b2a2966255e0b+7116+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: 1676540828276100003 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 --- hw/i386/kvm/meson.build | 1 + hw/i386/kvm/trace-events | 15 + hw/i386/kvm/xen_xenstore.c | 869 +++++++++++++++++++++++++++++++++++- hw/i386/kvm/xenstore_impl.c | 117 +++++ hw/i386/kvm/xenstore_impl.h | 58 +++ 5 files changed, 1051 insertions(+), 9 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..7917167e89 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, size_t offse= t) "tx %u path %s offset %zu" +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 2388842d15..78c887ab29 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) @@ -209,20 +219,757 @@ 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, size_t start, bool truncate) +{ + 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; + size_t 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; + } + + offset =3D strtoull(offset_str, NULL, 10); + 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); + 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); @@ -382,6 +1129,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; @@ -400,13 +1247,17 @@ 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); =20 if (!req_pending(s)) 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 Sat May 18 22:31:26 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 1676540787301353.7413575211003; Thu, 16 Feb 2023 01:46:27 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pSapO-0000UL-9i; Thu, 16 Feb 2023 04:45:23 -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 1pSap1-00005X-MT for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:44:59 -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 1pSaoy-0006LD-84 for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:44:59 -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 1pSao2-00AEEv-1A; Thu, 16 Feb 2023 09:44:44 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pSaoi-0090BH-1i; Thu, 16 Feb 2023 09:44:40 +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=datHZGJ32TDzWmhHHrb4QFGfIsfT6P4qRH8j9cl1hbk=; b=bnAPoYQcODey+5Vcg1a9o4z8xN Vk952em5bmnfg5GiXsKIBWjY/v0qQXg5Xy/gr8yDxoGFRD1Vq6txj3DE2QD8CGgTBbnyuKr+tA43d x7wAyW8yruhbRIbf/B5OFLyw+2XnWYvGlyjjaMrRC7Mjx6g0Wi83C+CWgT+L/mk/LmV2DLO0etoDs kO5yPFBRN1vTTpv9U5x5FxnESMBgvfHTMmN9z6K1uiB71PRGl4cK82SsE/s7olIU36fKsvZmpZg5i ox8Ive9ydBFPIMBs4Dai8H6dA2RO1GZPAWpbaI+bOkyFQjjLJ/l5cohMa2uEYUCh8WDX7z8jD3Gw1 IZAApgbw==; From: David Woodhouse To: Peter Maydell , qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Juan Quintela , "Dr . David Alan Gilbert" , Claudio Fontana , Julien Grall , "Michael S. Tsirkin" , Marcel Apfelbaum , armbru@redhat.com, Stefano Stabellini , vikram.garhwal@amd.com Subject: [RFC PATCH v11bis 02/26] hw/xen: Add basic XenStore tree walk and write/read/directory support Date: Thu, 16 Feb 2023 09:44:12 +0000 Message-Id: <20230216094436.2144978-3-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230216094436.2144978-1-dwmw2@infradead.org> References: <20230216094436.2144978-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+96e41a9b2a2966255e0b+7116+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: 1676540788076100003 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 --- hw/i386/kvm/xenstore_impl.c | 440 +++++++++++++++++++++++++++++++++++- tests/unit/meson.build | 1 + tests/unit/test-xs-node.c | 177 +++++++++++++++ 3 files changed, 611 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..520883d172 100644 --- a/hw/i386/kvm/xenstore_impl.c +++ b/hw/i386/kvm/xenstore_impl.c @@ -10,13 +10,384 @@ */ =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 TYPE_XS_NODE "xs-node" + +typedef struct XsNode { + uint32_t ref; + GByteArray *content; + GHashTable *children; + uint64_t gencnt; +#ifdef XS_NODE_UNIT_TEST + gchar *name; /* debug only */ +#endif +} XsNode; + +#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 + struct XenstoreImplState { + XsNode *root; +}; + +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; + + /* + * 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; }; =20 +static int xs_node_add_content(XsNode **n, struct walk_op *op) +{ + /* 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(op->op_opaque); + 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 xs_node_rm(XsNode **n, struct walk_op *op) +{ + bool this_inplace =3D op->inplace; + + 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) { + 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'; + 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 init_walk_op(XenstoreImplState *s, struct walk_op *op, + xs_transaction_t tx_id, unsigned int dom_id, + const char *path, XsNode ***rootp) +{ + if (path[0] =3D=3D '/') { + if (strlen(path) > XENSTORE_ABS_PATH_MAX) { + return E2BIG; + } + snprintf(op->path, sizeof(op->path), "%s", path); + } else { + if (strlen(path) > XENSTORE_REL_PATH_MAX) { + return E2BIG; + } + snprintf(op->path, sizeof(op->path), "/local/domain/%u/%s", dom_id, + path); + } + /* + * 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; + } 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 +395,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 +413,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 +439,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 +468,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 +516,28 @@ 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->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 ffa444f432..ee54b3c3eb 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -48,6 +48,7 @@ tests =3D { 'test-qapi-util': [], 'test-smp-parse': [qom, meson.project_source_root() / 'hw/core/machine-s= mp.c'], '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..07b8f0ba51 --- /dev/null +++ b/tests/unit/test-xs-node.c @@ -0,0 +1,177 @@ +/* + * 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 +#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) +{ + 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_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(!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); + + /* Overwrite an existing node */ + err =3D write_str(s, DOMID_GUEST, XBT_NULL, "some/relative/path", + "another thing"); + g_assert(!err); + + /* 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_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 Sat May 18 22:31:26 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 1676540793879350.0495898245538; Thu, 16 Feb 2023 01:46:33 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pSap8-0000Ac-Pw; Thu, 16 Feb 2023 04:45:06 -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 1pSap2-00007P-PJ for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:45:00 -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 1pSaoy-0006LA-6I for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:45: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 1pSao2-00AEEw-1N; Thu, 16 Feb 2023 09:44:44 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pSaoi-0090BM-1v; Thu, 16 Feb 2023 09:44:40 +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=w3VV1AeqTmNEzpD2Gof9YjiIkZBpbVHvGh10w/AT8BU=; b=jkBC/B4GrRQG+f8OgqH5Sk/Tkv lPoR6N4Zkpg6xP813ShEkGk9C1jH5iVoyUULLHlXok+JvxFdMe5ul4Knn65xtwdNQg4Idcg6YfWp+ Z3A6eFTnjkwnLV0u9uOWUzYk2dJrR5UoeBNKp7hJtlLDBJNuzo8MiNuyHofEXjQkpvPhIcgiQ+bpq CVX346zboUaqhQTQl91SFeEMARaIPqS4+F7Qfc7KxzmcTR23RjuWzyYZzmhgsbgI6ow0SWmtTNbFO 2YlY9/dUC2M6vAaR9/Ov7NdmwHcQ5liUROsy3OPltwgsxuUN+a0s3iYcQ4ftPVE65KWXtYp0tYRGU O7CkQFNw==; From: David Woodhouse To: Peter Maydell , qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Juan Quintela , "Dr . David Alan Gilbert" , Claudio Fontana , Julien Grall , "Michael S. Tsirkin" , Marcel Apfelbaum , armbru@redhat.com, Stefano Stabellini , vikram.garhwal@amd.com Subject: [RFC PATCH v11bis 03/26] hw/xen: Implement XenStore watches Date: Thu, 16 Feb 2023 09:44:13 +0000 Message-Id: <20230216094436.2144978-4-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230216094436.2144978-1-dwmw2@infradead.org> References: <20230216094436.2144978-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+96e41a9b2a2966255e0b+7116+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: 1676540796082100007 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 --- hw/i386/kvm/xenstore_impl.c | 294 +++++++++++++++++++++++++++++++++--- tests/unit/test-xs-node.c | 80 ++++++++++ 2 files changed, 355 insertions(+), 19 deletions(-) diff --git a/hw/i386/kvm/xenstore_impl.c b/hw/i386/kvm/xenstore_impl.c index 520883d172..e7bbe3deee 100644 --- a/hw/i386/kvm/xenstore_impl.c +++ b/hw/i386/kvm/xenstore_impl.c @@ -19,6 +19,12 @@ =20 #define TYPE_XS_NODE "xs-node" =20 +#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 + typedef struct XsNode { uint32_t ref; GByteArray *content; @@ -29,14 +35,18 @@ typedef struct XsNode { #endif } XsNode; =20 -#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 +typedef struct XsWatch { + struct XsWatch *next; + xs_impl_watch_fn *cb; + void *cb_opaque; + char *token; + unsigned int dom_id; + int rel_prefix; +} XsWatch; =20 struct XenstoreImplState { XsNode *root; + GHashTable *watches; }; =20 static inline XsNode *xs_node_new(void) @@ -143,6 +153,7 @@ struct walk_op { void *op_opaque; void *op_opaque2; =20 + GList *watches; unsigned int dom_id; =20 /* @@ -160,6 +171,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) { /* We *are* the node to be written. Either this or a copy. */ @@ -192,10 +232,51 @@ static int xs_node_get_content(XsNode **n, struct wal= k_op *op) return 0; } =20 +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; + + if (n->ref !=3D 1) { + op->inplace =3D 0; + } + + 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); + } + /* + * 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 + * 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; =20 + /* Fire watches for any node in the subtree which gets deleted. */ + if ((*n)->children) { + g_hash_table_foreach_remove((*n)->children, node_rm_recurse, op); + } + if (this_inplace) { xs_node_unref(*n); } @@ -221,9 +302,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]) { @@ -244,6 +327,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 @@ -279,11 +365,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. */ @@ -320,6 +419,9 @@ static int xs_node_walk(XsNode **n, struct walk_op *op) =20 out: op->path[namelen] =3D '\0'; + if (!namelen) { + assert(!op->watches); + } return err; } =20 @@ -372,6 +474,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; @@ -503,38 +606,191 @@ 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; + const char *effective_path; + char *fullpath =3D NULL; /* Allocated copy */ + XsWatch *w, *l; + + if (path[0] =3D=3D '/') { + if (strlen(path) > XENSTORE_ABS_PATH_MAX) { + return E2BIG; + } + effective_path =3D path; + } else { + if (strlen(path) > XENSTORE_REL_PATH_MAX) { + return E2BIG; + } + effective_path =3D fullpath =3D g_strdup_printf("/local/domain/%u/= %s", + dom_id, path); + } + + 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(effective_path) - strlen(path); + + l =3D g_hash_table_lookup(s->watches, effective_path); + if (l) { + w->next =3D l->next; + l->next =3D w; + } else { + if (!fullpath) { + fullpath =3D g_strdup(path); + } + g_hash_table_insert(s->watches, fullpath, w); + fullpath =3D NULL; /* Don't free; hash owns it */ + } + g_free(fullpath); + fn(opaque, path, token); + return 0; +} + +static XsWatch *free_watch(XsWatch *w) +{ + XsWatch *next =3D w->next; + + 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) { + const char *effective_path; + char *fullpath =3D NULL; /* Allocated copy */ + XsWatch *w, **l; + + if (path[0] =3D=3D '/') { + if (strlen(path) > XENSTORE_ABS_PATH_MAX) { + return E2BIG; + } + effective_path =3D path; + } else { + if (strlen(path) > XENSTORE_REL_PATH_MAX) { + return E2BIG; + } + effective_path =3D fullpath =3D g_strdup_printf("/local/domain/%u/= %s", + dom_id, path); + } + + w =3D g_hash_table_lookup(s->watches, effective_path); + if (!w) { + g_free(fullpath); + 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 */ + if (!fullpath) { + fullpath =3D g_strdup(path); + } + g_hash_table_insert(s->watches, fullpath, w->next); + fullpath =3D NULL; + } else { + /* Nothing left; remove from hash table */ + g_hash_table_remove(s->watches, effective_path); + g_free(fullpath); + } + free_watch(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. + */ + g_free(fullpath); + + 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(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(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->root =3D xs_node_new(); #ifdef XS_NODE_UNIT_TEST s->root->name =3D g_strdup("/"); diff --git a/tests/unit/test-xs-node.c b/tests/unit/test-xs-node.c index 07b8f0ba51..fb7f12aaa1 100644 --- a/tests/unit/test-xs-node.c +++ b/tests/unit/test-xs-node.c @@ -23,6 +23,7 @@ static GList *xs_node_list; /* This doesn't happen in qemu but we want to make valgrind happy */ static void xs_impl_delete(XenstoreImplState *s) { + g_hash_table_unref(s->watches); xs_node_unref(s->root); g_free(s); =20 @@ -50,6 +51,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(); @@ -77,6 +86,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; @@ -84,6 +95,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); @@ -92,6 +117,14 @@ static void test_xs_node_simple(void) err =3D write_str(s, DOMID_GUEST, XBT_NULL, "some/relative/path", "something"); 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); @@ -106,6 +139,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 @@ -114,11 +149,17 @@ static void test_xs_node_simple(void) "/local/domain/1/some/relative/path2", "something else"); g_assert(!err); + 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(!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, @@ -132,10 +173,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); =20 + g_assert(!strcmp(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); @@ -145,6 +214,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); @@ -156,11 +226,21 @@ static void test_xs_node_simple(void) err =3D xs_impl_rm(s, DOMID_GUEST, XBT_NULL, "some/relative"); g_assert(!err); =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 Sat May 18 22:31:26 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 1676540753812692.40990361051; Thu, 16 Feb 2023 01:45:53 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pSap2-00005o-3Y; Thu, 16 Feb 2023 04:45:00 -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 1pSap0-0008QU-Eh for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:44:58 -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 1pSaoy-0006J1-EG for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:44:58 -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 1pSaoi-008Ib5-Lj; Thu, 16 Feb 2023 09:44:41 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pSaoi-0090BR-27; Thu, 16 Feb 2023 09:44:40 +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=p3X5Bi/TPU0hl/md0jjwrz2d3jqx/aPMrDo6CxjQGfs=; b=kIah8Es07lz6r1Q7XsMnM5YCkg itG0k+8ZBdAFqfSb0cbhvVnqdS88aaW6G0T82lK3sxffEyPCFLrpYUuwXK4DazQ93PQ/aBfjY2jDQ wqxpgrgjWX1yJDGDCXp/Yy/qs4dZ2s6QHcPBhSHINZu+2DF6NtgDHW643Rk9E8EcecSLIu+HeneGG ZMKpgP/+taHzQmmSYwObjhfzrPY8Zd/CZq1sJrC88JwEMHJ65UUe/ttnfkymwtc7AWPZGPafbbz96 X9fDAySOwmCq4k9le2PPwuq38AZGjby3k0D0S7QPYryK7SaFDK40DS4XyWcmaqkFW63i0QxSJU8+W ImVtTFyw==; From: David Woodhouse To: Peter Maydell , qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Juan Quintela , "Dr . David Alan Gilbert" , Claudio Fontana , Julien Grall , "Michael S. Tsirkin" , Marcel Apfelbaum , armbru@redhat.com, Stefano Stabellini , vikram.garhwal@amd.com Subject: [RFC PATCH v11bis 04/26] hw/xen: Implement XenStore transactions Date: Thu, 16 Feb 2023 09:44:14 +0000 Message-Id: <20230216094436.2144978-5-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230216094436.2144978-1-dwmw2@infradead.org> References: <20230216094436.2144978-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+33d3adc5578b079b0cf9+7116+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: 1676540755958100003 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 --- hw/i386/kvm/xenstore_impl.c | 99 +++++++++++++++++++++++++++++++++++-- tests/unit/test-xs-node.c | 97 ++++++++++++++++++++++++++++++++++++ 2 files changed, 192 insertions(+), 4 deletions(-) diff --git a/hw/i386/kvm/xenstore_impl.c b/hw/i386/kvm/xenstore_impl.c index e7bbe3deee..692622f706 100644 --- a/hw/i386/kvm/xenstore_impl.c +++ b/hw/i386/kvm/xenstore_impl.c @@ -44,9 +44,19 @@ typedef struct XsWatch { int rel_prefix; } XsWatch; =20 +typedef struct XsTransaction { + XsNode *root; + unsigned int base_tx; + unsigned int tx_id; + unsigned int dom_id; +} XsTransaction; + struct XenstoreImplState { XsNode *root; GHashTable *watches; + GHashTable *transactions; + unsigned int root_tx; + unsigned int last_tx; }; =20 static inline XsNode *xs_node_new(void) @@ -169,6 +179,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) @@ -176,7 +187,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 @@ -421,6 +432,16 @@ static int xs_node_walk(XsNode **n, struct walk_op *op) op->path[namelen] =3D '\0'; if (!namelen) { assert(!op->watches); + /* + * 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->in_transaction) { + if (op->s->root_tx !=3D op->s->last_tx) { + op->s->root_tx =3D ++op->s->last_tx; + } + } } return err; } @@ -479,13 +500,20 @@ 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->s =3D s; =20 if (tx_id =3D=3D XBT_NULL) { *rootp =3D &s->root; } 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->in_transaction =3D true; } =20 return 0; @@ -559,13 +587,65 @@ 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; + } + + tx =3D g_new0(XsTransaction, 1); + + tx->tx_id =3D ++s->last_tx; + 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); + *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; + + /* + * 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; + + if (commit) { + XsTransaction *tx =3D g_hash_table_lookup(s->transactions, + GINT_TO_POINTER(tx_id)); + if (!tx || tx->dom_id !=3D dom_id) { + return ENOENT; + } + + ret =3D transaction_commit(s, tx); + /* + * It *is* in the hash table still, so g_hash_table_remove() will + * return true and we'll return ret; + */ + } + + if (g_hash_table_remove(s->transactions, GINT_TO_POINTER(tx_id))) { + return ret; + } else { + return ENOENT; + } } =20 int xs_impl_rm(XenstoreImplState *s, unsigned int dom_id, @@ -786,11 +866,22 @@ 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->root =3D xs_node_new(); #ifdef XS_NODE_UNIT_TEST s->root->name =3D g_strdup("/"); diff --git a/tests/unit/test-xs-node.c b/tests/unit/test-xs-node.c index fb7f12aaa1..d51677584f 100644 --- a/tests/unit/test-xs-node.c +++ b/tests/unit/test-xs-node.c @@ -23,6 +23,7 @@ static GList *xs_node_list; /* This doesn't happen in qemu but we want to make valgrind happy */ static void xs_impl_delete(XenstoreImplState *s) { + g_hash_table_unref(s->transactions); g_hash_table_unref(s->watches); xs_node_unref(s->root); g_free(s); @@ -246,12 +247,108 @@ 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(!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(!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(!watches->len); + + /* The transaction should fail */ + 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); + + 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 Sat May 18 22:31:26 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 1676540898730757.8772141083837; Thu, 16 Feb 2023 01:48:18 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pSapt-0001OU-6T; Thu, 16 Feb 2023 04:45: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 1pSap6-0000AI-Lx for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:45:06 -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 1pSaoy-0006LN-C6 for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:45:03 -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 1pSao2-00AEEx-1m; Thu, 16 Feb 2023 09:44:44 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pSaoi-0090BV-2K; Thu, 16 Feb 2023 09:44:40 +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=/sHKcuBGlgmdgFz2DkCWF7DBipYEByc+6pq3YnO5EyY=; b=W9tXG7ml3MdKDa6lcjcgB3W05Q 6csXv4w3VkhsPgfg8rlbPbydBQv+VNs74pCe+oMPSVYSZvwEEPZMXO/n9Jgunrkzc3uu53gfrwdkW TR5wcPNBtHnmipZp0w85SPb6M87eh2j5kiQB5RTNhobZCeNL4zOLBaGWHFNHhkBiNkvEfqHSQiGVC bFT72XO43cbd6YjPjYBnvayBAi+RqC4BTJvnYH3tpS+oFBvsM3EF+YLl/jYSNCki/zedOWBBZiqGw kahWbuX9fIaH6bYI4Wg34JJBpJR7MJlVNHWyFq7gzNNKmNjkjUSfw6P19Ro0u4eSDQ7VzTe6H5Pdy j9FUQnew==; From: David Woodhouse To: Peter Maydell , qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Juan Quintela , "Dr . David Alan Gilbert" , Claudio Fontana , Julien Grall , "Michael S. Tsirkin" , Marcel Apfelbaum , armbru@redhat.com, Stefano Stabellini , vikram.garhwal@amd.com Subject: [RFC PATCH v11bis 05/26] hw/xen: Watches on XenStore transactions Date: Thu, 16 Feb 2023 09:44:15 +0000 Message-Id: <20230216094436.2144978-6-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230216094436.2144978-1-dwmw2@infradead.org> References: <20230216094436.2144978-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+96e41a9b2a2966255e0b+7116+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: 1676540900774100011 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 --- hw/i386/kvm/xenstore_impl.c | 133 ++++++++++++++++++++++++++++++++- tests/unit/test-xs-node.c | 142 +++++++++++++++++++++++++++++++++++- 2 files changed, 272 insertions(+), 3 deletions(-) diff --git a/hw/i386/kvm/xenstore_impl.c b/hw/i386/kvm/xenstore_impl.c index 692622f706..2f9e1ff51b 100644 --- a/hw/i386/kvm/xenstore_impl.c +++ b/hw/i386/kvm/xenstore_impl.c @@ -30,6 +30,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 @@ -116,6 +118,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); @@ -165,6 +174,7 @@ struct walk_op { =20 GList *watches; unsigned int dom_id; + unsigned int tx_id; =20 /* * This is maintained on the way *down* the walk to indicate @@ -180,6 +190,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) @@ -224,6 +237,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(op->op_opaque); + if (op->tx_id !=3D XBT_NULL) { + (*n)->modified_in_tx =3D true; + } return 0; } =20 @@ -279,10 +295,51 @@ 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); +static void copy_deleted_recurse(gpointer key, gpointer value, + gpointer user_data) +{ + XsNode *n =3D xs_node_copy_deleted(value); + g_hash_table_insert(user_data, g_strdup(key), n); +} + +static XsNode *xs_node_copy_deleted(XsNode *old) +{ + 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); + g_hash_table_foreach(old->children, copy_deleted_recurse, n->child= ren); + } + 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; + } + 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); + xs_node_unref(old); + return 0; + } + /* Fire watches for any node in the subtree which gets deleted. */ if ((*n)->children) { g_hash_table_foreach_remove((*n)->children, node_rm_recurse, op); @@ -353,6 +410,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); + child->deleted_in_tx =3D false; + } xs_node_ref(child); /* * Now we own it too. But if we can modify inplace, that's going to @@ -502,6 +563,7 @@ static int init_walk_op(XenstoreImplState *s, struct wa= lk_op *op, 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) { @@ -605,8 +667,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; } @@ -615,10 +738,18 @@ static int transaction_commit(XenstoreImplState *s, X= sTransaction *tx) tx->root =3D NULL; s->root_tx =3D tx->tx_id; =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 d51677584f..307855e014 100644 --- a/tests/unit/test-xs-node.c +++ b/tests/unit/test-xs-node.c @@ -295,14 +295,21 @@ static void do_test_xs_node_tx(bool fail, bool commit) g_assert(!err); g_assert(!watches->len); =20 - /* The transaction should fail */ + /* 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); + + if (commit && !fail) { + g_assert(!strcmp(watches->str, + "some/relative/pathwatch")); + g_string_truncate(watches, 0); + } else { + g_assert(!watches->len); + } =20 err =3D xs_impl_unwatch(s, DOMID_GUEST, "some", "watch", watch_cb, watches); @@ -340,6 +347,135 @@ 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(!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(!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(!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); + + /* This node will be wiped and resurrected */ + err =3D write_str(s, DOMID_GUEST, XBT_NULL, "some/deep/dark", + "foo"); + g_assert(!err); + + /* 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(!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); + + /* Commit the transaction */ + err =3D xs_impl_transaction_end(s, DOMID_GUEST, tx_id, true); + g_assert(!err); + + g_assert(!strcmp(watches->str, + "some/deep/dark/different/pathwatch" /* lost data */ + "some/deep/dark/relativewatch" /* topmost deleted */ + "some/deep/darkwatch" /* lost data */)); + 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); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); @@ -349,6 +485,8 @@ 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); =20 return g_test_run(); } --=20 2.39.0 From nobody Sat May 18 22:31:26 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 1676540864991474.8709770908731; Thu, 16 Feb 2023 01:47:44 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pSap6-00009p-HO; Thu, 16 Feb 2023 04:45:04 -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 1pSap2-00006l-DX for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:45:00 -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 1pSaoy-0006LC-8I for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:45: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 1pSao2-00AEEy-1y; Thu, 16 Feb 2023 09:44:43 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pSaoi-0090BZ-2X; Thu, 16 Feb 2023 09:44:40 +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=9UsvJgIz8DVqSezPGGR/YvCsP+Pc4Gsb73K7iHYZp9s=; b=oNVw33DP7RK+dodExGvN0KycMx 1YD9hu2kLxHYCpo5THVBtozCTPsHJFl9wFdQP8rKW2W3S/wDnczDLsslOaCO9YERQOflEjUKq024u VIPFyeA7oO1Wy/wypD73m0vBZJDevfgJXQjHqrjZfHeX94S1/fh2QbIruO8XrQVKOsBNMB35atd+x BUWo2BX5PCTJBjk9LcEQnl8JBK3Vj66r2TgbXVMkHWjIzH2du1wWtzooktZADSrsFYwh3PWUjJQ7v 5cE8R3QsuxdUgiTkhs/GMEj8NOUUqdPUIIM/gX1GfxjnojAaWPHt0znN/LRGgNec1tRj8p073Svoj ShXYfmug==; From: David Woodhouse To: Peter Maydell , qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Juan Quintela , "Dr . David Alan Gilbert" , Claudio Fontana , Julien Grall , "Michael S. Tsirkin" , Marcel Apfelbaum , armbru@redhat.com, Stefano Stabellini , vikram.garhwal@amd.com Subject: [RFC PATCH v11bis 06/26] xenstore perms WIP Date: Thu, 16 Feb 2023 09:44:16 +0000 Message-Id: <20230216094436.2144978-7-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230216094436.2144978-1-dwmw2@infradead.org> References: <20230216094436.2144978-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+96e41a9b2a2966255e0b+7116+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: 1676540866465100001 Content-Type: text/plain; charset="utf-8" From: Paul Durrant Store perms as a GList of strings, check permissions. No unit tests yet. Signed-off-by: Paul Durrant Signed-off-by: David Woodhoues --- hw/i386/kvm/xen_xenstore.c | 2 +- hw/i386/kvm/xenstore_impl.c | 239 +++++++++++++++++++++++++++++++++--- hw/i386/kvm/xenstore_impl.h | 8 +- tests/unit/test-xs-node.c | 24 +++- 4 files changed, 252 insertions(+), 21 deletions(-) diff --git a/hw/i386/kvm/xen_xenstore.c b/hw/i386/kvm/xen_xenstore.c index 78c887ab29..90f3bb8946 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 2f9e1ff51b..e6c6a2200e 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 @@ -28,6 +30,7 @@ typedef struct XsNode { uint32_t ref; GByteArray *content; + GList *perms; GHashTable *children; uint64_t gencnt; bool deleted_in_tx; @@ -96,6 +99,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); } @@ -107,8 +113,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)); } @@ -125,12 +174,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->perms) { + n->perms =3D g_list_copy_deep(old->perms, do_perm_copy, NULL); } - if (old && old->content) { + if (old->content) { n->content =3D g_byte_array_ref(old->content); } return n; @@ -320,6 +373,9 @@ static XsNode *xs_node_copy_deleted(XsNode *old) (GDestroyNotify)xs_node_unref); g_hash_table_foreach(old->children, copy_deleted_recurse, n->child= ren); } + 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) { @@ -352,6 +408,84 @@ 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 int xs_node_set_perms(XsNode **n, struct walk_op *op) +{ + GList *perms =3D op->op_opaque; + + /* 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; +} + +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; +} + /* * Passed a full reference in *n which it may free if it needs to COW. * @@ -393,6 +527,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) { @@ -426,7 +567,14 @@ static int xs_node_walk(XsNode **n, struct walk_op *op) stole_child =3D true; } } else if (op->create_dirs) { - child =3D xs_node_new(); + assert(op->mutating); + + if (!can_access(op->dom_id, old->perms, "wb")) { + err =3D EACCES; + goto out; + } + + child =3D xs_node_create(child_name, old->perms); /* * If we're creating a new child, we can clearly modify it (and its * children) in place from here on down. @@ -798,20 +946,73 @@ int xs_impl_rm(XenstoreImplState *s, unsigned int dom= _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, @@ -1006,16 +1207,18 @@ 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); - s->root =3D xs_node_new(); -#ifdef XS_NODE_UNIT_TEST - s->root->name =3D g_strdup("/"); -#endif + + 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); + 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 307855e014..55f07aa217 100644 --- a/tests/unit/test-xs-node.c +++ b/tests/unit/test-xs-node.c @@ -62,8 +62,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); @@ -71,6 +72,13 @@ static XenstoreImplState *setup(void) err =3D write_str(s, DOMID_QEMU, XBT_NULL, abspath, ""); g_assert(!err); =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); @@ -78,6 +86,12 @@ static XenstoreImplState *setup(void) err =3D write_str(s, DOMID_QEMU, XBT_NULL, abspath, ""); g_assert(!err); =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; @@ -145,6 +159,10 @@ 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); + /* Write works again */ err =3D write_str(s, DOMID_GUEST, XBT_NULL, "/local/domain/1/some/relative/path2", @@ -202,6 +220,10 @@ static void test_xs_node_simple(void) err =3D write_str(s, DOMID_GUEST, XBT_NULL, "some/relative", "moredata= "); g_assert(!err); =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 Sat May 18 22:31:26 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 167654090207250.6190795957217; Thu, 16 Feb 2023 01:48:22 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pSaqO-0003DJ-KG; Thu, 16 Feb 2023 04:46: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 1pSapD-0000Jw-BM for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:45:11 -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 1pSap8-0006LO-EI for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:45:10 -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 1pSao2-00AEEz-2E; Thu, 16 Feb 2023 09:44:44 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pSaoi-0090Bd-2k; Thu, 16 Feb 2023 09:44:40 +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=PbKLZxaTZ5hEwltWRkgYbdXu+V2RxVtTO0dpvaEF5jI=; b=c2JbHyDu7cAdAHjwLGGXcvmNY+ T00ydKRP06dkfYM7Zej2/Q/VSC/Y8bl0eJ6+ecHsINj6Q4LNGjGrkYcs2nzzGJZxZGM/n+cW5rTia t8JSzUXcmdI/kHfGA0ecHhzzg4+luMn4nGfN41Mx7YvzeNaiPqQtsBptmBJajsfn7MqAug0jnSnNY M9aI/qSeyR9aMS/Go03DR8G74LmcIC7nBbzBDTI+y7g+W1OgO5zzyEO5TToAjI5lFtPhRjwGZwx2S mnndjuAxA+SFk1Ue8alxaxReSWYzAlKg47zruD66wbTah01ONr9LgYUh2nCkCvTVGpmRIPzcepwys qnTmJv6w==; From: David Woodhouse To: Peter Maydell , qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Juan Quintela , "Dr . David Alan Gilbert" , Claudio Fontana , Julien Grall , "Michael S. Tsirkin" , Marcel Apfelbaum , armbru@redhat.com, Stefano Stabellini , vikram.garhwal@amd.com Subject: [RFC PATCH v11bis 07/26] hw/xen: Implement core serialize/deserialize methods for xenstore_impl Date: Thu, 16 Feb 2023 09:44:17 +0000 Message-Id: <20230216094436.2144978-8-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230216094436.2144978-1-dwmw2@infradead.org> References: <20230216094436.2144978-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+96e41a9b2a2966255e0b+7116+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: 1676540902784100013 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 --- hw/i386/kvm/xen_xenstore.c | 25 +- hw/i386/kvm/xenstore_impl.c | 530 ++++++++++++++++++++++++++++++++++++ hw/i386/kvm/xenstore_impl.h | 5 + tests/unit/test-xs-node.c | 213 ++++++++++++++- 4 files changed, 767 insertions(+), 6 deletions(-) diff --git a/hw/i386/kvm/xen_xenstore.c b/hw/i386/kvm/xen_xenstore.c index 90f3bb8946..d15eea76c4 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 @@ -134,7 +147,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 { @@ -152,6 +171,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 e6c6a2200e..6744e99e4e 100644 --- a/hw/i386/kvm/xenstore_impl.c +++ b/hw/i386/kvm/xenstore_impl.c @@ -35,6 +35,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 @@ -62,6 +63,7 @@ struct XenstoreImplState { GHashTable *transactions; unsigned int root_tx; unsigned int last_tx; + bool serialized; }; =20 static inline XsNode *xs_node_new(void) @@ -1220,5 +1222,533 @@ XenstoreImplState *xs_impl_create(unsigned int dom_= id) s->root =3D xs_node_create("/", perms); g_list_free_full(perms, g_free); =20 + 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) { + g_byte_array_append(ss->bytes, key, strlen(key) + 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 int consume_node(struct unsave_state *us, XsNode **nodep) +{ + 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++; + } 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); + *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; + } + } + + *nodep =3D n; + return 0; +} + +static int consume_tree(struct unsave_state *us, unsigned int *tx_id, + XsNode **root) +{ + int ret; + + ret =3D consume_be32(us, tx_id); + if (ret) { + return ret; + } + + if (*tx_id > us->s->last_tx) { + return -EINVAL; + } + + us->path[0] =3D '\0'; + + return consume_node(us, root); +} + +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.tx_id, &base_t.root); + 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->tx_id, &t->root); + } + if (ret) { + g_free(t); + return ret; + } + g_assert(t->root); + 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 xs_impl_watch(s, dom_id, path, token, watch_fn, watch_opaq= ue); + 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 55f07aa217..c845d4ecd9 100644 --- a/tests/unit/test-xs-node.c +++ b/tests/unit/test-xs-node.c @@ -20,14 +20,42 @@ 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) { g_hash_table_unref(s->transactions); g_hash_table_unref(s->watches); 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) { @@ -39,6 +67,167 @@ 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); + } +} + +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, NULL, 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); + + xs_impl_delete(s2, false); +} + static int write_str(XenstoreImplState *s, unsigned int dom_id, unsigned int tx_id, const char *path, const char *content) @@ -265,7 +454,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 @@ -317,6 +506,8 @@ static void do_test_xs_node_tx(bool fail, bool commit) g_assert(!err); g_assert(!watches->len); =20 + check_serdes(s); + /* Attempt to commit the transaction */ err =3D xs_impl_transaction_end(s, DOMID_GUEST, tx_id, commit); if (commit && fail) { @@ -333,6 +524,8 @@ static void do_test_xs_node_tx(bool fail, bool commit) g_assert(!watches->len); } =20 + check_serdes(s); + err =3D xs_impl_unwatch(s, DOMID_GUEST, "some", "watch", watch_cb, watches); g_assert(!err); @@ -351,7 +544,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) @@ -411,6 +604,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); @@ -429,7 +624,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) @@ -447,6 +642,10 @@ static void test_xs_node_tx_resurrect(void) "something"); g_assert(!err); =20 + /* Another node to remain shared */ + err =3D write_str(s, DOMID_GUEST, XBT_NULL, "some/place/safe", "keepme= "); + g_assert(!err); + /* This node will be wiped and resurrected */ err =3D write_str(s, DOMID_GUEST, XBT_NULL, "some/deep/dark", "foo"); @@ -474,6 +673,8 @@ static void test_xs_node_tx_resurrect(void) "something"); g_assert(!err); =20 + check_serdes(s); + /* Commit the transaction */ err =3D xs_impl_transaction_end(s, DOMID_GUEST, tx_id, true); g_assert(!err); @@ -490,12 +691,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 int main(int argc, char **argv) --=20 2.39.0 From nobody Sat May 18 22:31:26 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 1676540877766775.7668928501141; Thu, 16 Feb 2023 01:47:57 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pSapD-0000Eg-Lg; Thu, 16 Feb 2023 04:45:11 -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 1pSap4-00009U-Ih for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:45:02 -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 1pSaoy-0006LP-C1 for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:45:02 -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 1pSao2-00AEF0-2O; Thu, 16 Feb 2023 09:44:44 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pSaoi-0090Bh-2w; Thu, 16 Feb 2023 09:44:40 +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=WGMgm2xP5OFveuzNv5BqlZwn6gD0y4xm/+xNLbXDQdI=; b=b/2R0ue0ve40sNlOSe+6nuEHxS ahIuy4iQ15h3yy/jATRzThOqLj66IZnGfbli3zuuHcGG6wWtlIVnkPgKYQ/OllKMcZaGoGeP2iub8 oPxSXUjONOJx+4wFulC80+To9iSo19Ke0Mo4lpqWl2z8iSRB5WBIV2GJmekYShu0zPpdjva6Uy8o+ phx4GCbrvcs9zjgX7BWKauk3biO4RPFqfWUMQFbCxo5BpeSGGO4/JDI4iKyHp5sfCPd8J6hCgPxFS CuqzkDlsMp+TTdfYRMKW6JGQIu1TN8aMPS3KMMBQEGWhpg0YBKrtLZ+rWsnyTLupWXHjTl64/70fG UVeD8//w==; From: David Woodhouse To: Peter Maydell , qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Juan Quintela , "Dr . David Alan Gilbert" , Claudio Fontana , Julien Grall , "Michael S. Tsirkin" , Marcel Apfelbaum , armbru@redhat.com, Stefano Stabellini , vikram.garhwal@amd.com Subject: [RFC PATCH v11bis 08/26] hw/xen: Create initial XenStore nodes Date: Thu, 16 Feb 2023 09:44:18 +0000 Message-Id: <20230216094436.2144978-9-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230216094436.2144978-1-dwmw2@infradead.org> References: <20230216094436.2144978-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+96e41a9b2a2966255e0b+7116+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: 1676540878476100003 Content-Type: text/plain; charset="utf-8" From: Paul Durrant Signed-off-by: Paul Durrant Signed-off-by: David Woodhouse --- 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 d15eea76c4..ff39137846 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 Sat May 18 22:31:26 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 1676540919266739.3016548251993; Thu, 16 Feb 2023 01:48:39 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pSapu-0001gA-Vr; Thu, 16 Feb 2023 04:45:55 -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 1pSapD-0000K0-BM for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:45:11 -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 1pSap8-0006LE-EL for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:45:10 -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 1pSao2-00AEF1-2b; Thu, 16 Feb 2023 09:44:44 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pSaoi-0090Bl-39; Thu, 16 Feb 2023 09:44:40 +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=LbXcJwRm4fYkP6XsB2Pt0dnz0wmfqGCKU/brq1q2Wno=; b=U9Pv6Ae/MG48JkyvE6JwgEPW0e ZeX57adbQ0ZRP0GmXjXQfcvFKaAXI2y15XvJsz7scXsEeozkfLBxpCn7cRhYLy7ZfNbp7NuJxxiQI c93ASBIJnos+syZKWRfZLwIimX9mrG2UtwTR6Un+aoEQ1lGsVFLfh9tq5TPnvMb00nlHsG300TL45 AmsQqf/KZm7cjj3q6DRTK5nJ+trabRmkhAflYoSrHsJ6VV5td0sE3/Gf/C81bcNVRu/Je5AIuctjJ Z+xUJFZaRNReUejp0NLrqXTemcniC0ECi4sv8rgvEMnBsX8OkyjgXyyC5IhjejWyjwuWYJDMv3mOI ifkn6uPw==; From: David Woodhouse To: Peter Maydell , qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Juan Quintela , "Dr . David Alan Gilbert" , Claudio Fontana , Julien Grall , "Michael S. Tsirkin" , Marcel Apfelbaum , armbru@redhat.com, Stefano Stabellini , vikram.garhwal@amd.com Subject: [RFC PATCH v11bis 09/26] hw/xen: Add evtchn operations to allow redirection to internal emulation Date: Thu, 16 Feb 2023 09:44:19 +0000 Message-Id: <20230216094436.2144978-10-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230216094436.2144978-1-dwmw2@infradead.org> References: <20230216094436.2144978-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+96e41a9b2a2966255e0b+7116+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, T_FILL_THIS_FORM_SHORT=0.01 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: 1676540920966100003 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 --- hw/9pfs/xen-9p-backend.c | 24 +++--- hw/xen/meson.build | 1 + hw/xen/xen-bus.c | 22 +++--- hw/xen/xen-hvm-common.c | 27 ++++--- 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-hvm-common.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 + 14 files changed, 243 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/xen/meson.build b/hw/xen/meson.build index 008e036d63..02b9118b7f 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-hvm-common.c b/hw/xen/xen-hvm-common.c index 077c8dae5b..0a3ffbf955 100644 --- a/hw/xen/xen-hvm-common.c +++ b/hw/xen/xen-hvm-common.c @@ -194,7 +194,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)); @@ -213,7 +213,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; @@ -534,7 +534,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 @@ -583,8 +583,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 @@ -593,7 +593,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, @@ -636,7 +636,7 @@ 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 @@ -814,8 +814,9 @@ static void xen_do_ioreq_register(XenIOState *state, =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; @@ -823,8 +824,8 @@ static void xen_do_ioreq_register(XenIOState *state, 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; @@ -862,7 +863,9 @@ void xen_register_ioreq(XenIOState *state, unsigned int= max_cpus, { int rc; =20 - state->xce_handle =3D xenevtchn_open(NULL, 0); + setup_xen_backend_ops(); + + state->xce_handle =3D qemu_xen_evtchn_open(); if (state->xce_handle =3D=3D NULL) { error_report("xen: event channel open failed with error %d", errno= ); goto err; diff --git a/hw/xen/xen-legacy-backend.c b/hw/xen/xen-legacy-backend.c index 085fd31ef7..23e8a6fbd8 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 @@ -763,14 +763,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-hvm-common.h b/include/hw/xen/xen-hvm-commo= n.h index 2979f84ee2..c0b354e591 100644 --- a/include/hw/xen/xen-hvm-common.h +++ b/include/hw/xen/xen-hvm-common.h @@ -7,6 +7,7 @@ #include "cpu.h" #include "hw/pci/pci.h" #include "hw/hw.h" +#include "hw/xen/xen_backend_ops.h" #include "hw/xen/xen_common.h" #include "sysemu/runstate.h" #include "sysemu/sysemu.h" diff --git a/include/hw/xen/xen-legacy-backend.h b/include/hw/xen/xen-legac= y-backend.h index be281e1f38..0ef9b772ac 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 9ec69582b3..36bd4d92dc 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 Sat May 18 22:31:26 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 1676540896573848.2613566533806; Thu, 16 Feb 2023 01:48:16 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pSapt-0001OW-5e; Thu, 16 Feb 2023 04:45: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 1pSapD-0000L2-SP for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:45:11 -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 1pSap8-0006LM-EN for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:45:11 -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 1pSao2-00AEF2-2p; Thu, 16 Feb 2023 09:44:44 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pSaoj-0090Bp-09; Thu, 16 Feb 2023 09:44:41 +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=RJv2RNm4nlaIuytnALifP+ghN+EnMGD+HDzz0HEx38A=; b=Wbw/fD5MH8VwnwlL9U1+QRLtfN m9J7fCzOJtvSsXu6vM2C2oer4GKiLfUfyrLNdGE2QAcg9R9q8SlbQlN8bJpTpVUdFtgJuZTKC1UV8 1Rx5i/LPGWHcTAZzFBnqEvmVzwSxaQvJK+NcLSuNSz+RQwwgjLb5N/3cJCyJ3roYI9ZtmL+WN5vIj xzrUPFHNGWiBwmwB8ACFPa5GizEdOnG0riWWYYmcLgrw31+3O2iUrDRamkfoFZbWnZntz+qjq5Jwo liP/yh6SPCP0pTkMNPa4aMSZyyGGe3n+QG6vsy/4ANpgn++1BUbE71wXz4lKgWGtkmXeIVrzHnd9G Oph/xCsA==; From: David Woodhouse To: Peter Maydell , qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Juan Quintela , "Dr . David Alan Gilbert" , Claudio Fontana , Julien Grall , "Michael S. Tsirkin" , Marcel Apfelbaum , armbru@redhat.com, Stefano Stabellini , vikram.garhwal@amd.com Subject: [RFC PATCH v11bis 10/26] hw/xen: Add gnttab operations to allow redirection to internal emulation Date: Thu, 16 Feb 2023 09:44:20 +0000 Message-Id: <20230216094436.2144978-11-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230216094436.2144978-1-dwmw2@infradead.org> References: <20230216094436.2144978-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+96e41a9b2a2966255e0b+7116+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: 1676540898715100004 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 --- 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 | 99 ++++++++++++++++++ include/hw/xen/xen_common.h | 39 ------- softmmu/globals.c | 1 + 9 files changed, 279 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 23e8a6fbd8..88d2ae3f0a 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) { @@ -678,8 +585,6 @@ void xenstore_update_fe(char *watch, struct XenLegacyDe= vice *xendev) =20 int 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"); @@ -688,19 +593,11 @@ int 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) { /* Check if xen_init() have been called */ goto err; } =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 0ef9b772ac..01c12952b7 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" @@ -55,17 +55,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..d27151f92f 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,99 @@ static inline int qemu_xen_evtchn_pending(xenevtchn_ha= ndle *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, ui= nt32_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 domid, uint32_t *ref= s, + 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 36bd4d92dc..75704d147b 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 @@ -651,31 +639,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 Sat May 18 22:31:26 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 1676540828555494.4225744158333; Thu, 16 Feb 2023 01:47:08 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pSaps-0001LA-Kz; Thu, 16 Feb 2023 04:45:52 -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 1pSapD-0000Ja-AE for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:45:11 -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 1pSap8-0006LI-HC for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:45:10 -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 1pSao2-00AEF3-32; Thu, 16 Feb 2023 09:44:44 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pSaoj-0090Bu-0M; Thu, 16 Feb 2023 09:44:41 +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=mUZ0ShI9ugOIEyxl5xnr/9Ilt2JDQfHlfbgsKdLQCQQ=; b=VswAGCrblHATsBj5pAt8NC+2hw /IF4hQ6f9HBlX5P9ev/TVe6J7CX0Zc0SwcVyU+bdrEl79nyqWUALMTkPJ7G3mWfyJnxc1uboVNgqY mht0Shew2irTg7te6+/mPgUrCeb9w0lGHGvZHuD9ZKEkTRmoNJxYciSMv2kVd/NlW6FycJvB3WC/l sLu7CROP8STtOIQ9eVdAGdFxbICoqo6BOqmnjHSZw4TMWjEZts+/QkxYNDkii794he6wTRwAtUzm7 vBa3C8xSHCRDC0woGDtbD7y3d6eHCRuQj37jOw48YdxL9JydiThUMhTfROTHvs7IT6eQb8lq/V0nw muUtlMDA==; From: David Woodhouse To: Peter Maydell , qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Juan Quintela , "Dr . David Alan Gilbert" , Claudio Fontana , Julien Grall , "Michael S. Tsirkin" , Marcel Apfelbaum , armbru@redhat.com, Stefano Stabellini , vikram.garhwal@amd.com Subject: [RFC PATCH v11bis 11/26] hw/xen: Pass grant ref to gnttab unmap operation Date: Thu, 16 Feb 2023 09:44:21 +0000 Message-Id: <20230216094436.2144978-12-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230216094436.2144978-1-dwmw2@infradead.org> References: <20230216094436.2144978-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+96e41a9b2a2966255e0b+7116+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: 1676540830251100007 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 --- 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 88d2ae3f0a..047463d89c 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 01c12952b7..ea84a9246f 100644 --- a/include/hw/xen/xen-legacy-backend.h +++ b/include/hw/xen/xen-legacy-backend.h @@ -53,7 +53,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[], @@ -66,9 +66,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 d27151f92f..c55914d03e 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; @@ -203,13 +204,13 @@ static inline void *qemu_xen_gnttab_map_refs(xengntta= b_handle *xgt, uint32_t cou } =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 Sat May 18 22:31:26 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 1676540840089982.9591540042069; Thu, 16 Feb 2023 01:47:20 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pSaq1-0002DV-EI; Thu, 16 Feb 2023 04:46:01 -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 1pSapA-0000Cs-Ui for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:45:09 -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 1pSap8-0006LG-EH for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:45:08 -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 1pSao3-00AEF4-02; Thu, 16 Feb 2023 09:44:44 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pSaoj-0090By-0Z; Thu, 16 Feb 2023 09:44:41 +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=g12hH72Gux6Wb9MJIaMp9aPh1ujjDcGsGREoMlaAyBg=; b=eMIW0Cq0aPFg6DbLQnxj58cGK+ +ujvosZr3TB4PL18eRUkNwFBDfVgubpMASAzwuCVwOWdU77Zl3YC9Y0NMzv9Fjj7pN57vUH0+DDkd Sju0TcpaYXNyOSwmJ6RStGNFPOAGYLZwwVBd0NLgtgeJL0xEP5MtM35DG3m6gl7vJEOGHF661YRxr 1gLzNVA7qKdl2CRIgD7xVOjqSyZFSxmVWUSVb09nncUborD8wNcA7khrcwxLT261wQsWGOjL51S3u xyVmOW7VuTI7b8NK2nbKAMM1BIBY2DkFFyQ3sYjjocgmiS5AZm7PoGbGLfhj/2vmUe7xZGYELy+lO 81Yh14ww==; From: David Woodhouse To: Peter Maydell , qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Juan Quintela , "Dr . David Alan Gilbert" , Claudio Fontana , Julien Grall , "Michael S. Tsirkin" , Marcel Apfelbaum , armbru@redhat.com, Stefano Stabellini , vikram.garhwal@amd.com Subject: [RFC PATCH v11bis 12/26] hw/xen: Add foreignmem operations to allow redirection to internal emulation Date: Thu, 16 Feb 2023 09:44:22 +0000 Message-Id: <20230216094436.2144978-13-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230216094436.2144978-1-dwmw2@infradead.org> References: <20230216094436.2144978-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+96e41a9b2a2966255e0b+7116+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: 1676540840347100005 Content-Type: text/plain; charset="utf-8" From: David Woodhouse Signed-off-by: David Woodhouse Signed-off-by: Paul Durrant --- hw/char/xen_console.c | 8 ++-- hw/display/xenfb.c | 20 +++++----- hw/xen/xen-operations.c | 63 ++++++++++++++++++++++++++++++++ include/hw/xen/xen_backend_ops.h | 26 +++++++++++++ include/hw/xen/xen_common.h | 13 ------- softmmu/globals.c | 1 + 6 files changed, 105 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..4c6b305cc4 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,64 @@ 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, + uint64_t *pfns, int *errs) +{ + if (errs) + return xc_map_foreign_bulk(xen_xc, dom, prot, arr, err, pages); + else + return xc_map_foreign_pages(xen_xc, dom, prot, arr, 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, + uint64_t *pfns, int *errs) +{ + xen_pfn_t *xen_pfns; + void *ptr =3D NULL; + + if (sizeof(pfns[0]) =3D=3D sizeof(xen_pfn_t)) { + xen_pfns =3D (xen_pfn_t *)pfns; + } else { + int i; + xen_pfns =3D g_new0(xen_pfn_t, pages); + for (i =3D 0; i < pages; i++) { + xen_pfns[i] =3D pfns[i]; + if (xen_pfns[i] !=3D pfns[i]) { + goto out; + } + } + } + ptr =3D xenforeignmemory_map2(xen_fmem, dom, addr, prot, 0, pages, xen= _pfns, errs); + out: + if ((void *)xen_pfns !=3D (void *)pfns) { + g_free(xen_pfns); + } + return ptr; +} + +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 +294,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 c55914d03e..ca52e8f188 100644 --- a/include/hw/xen/xen_backend_ops.h +++ b/include/hw/xen/xen_backend_ops.h @@ -213,6 +213,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, + uint64_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, + uint64_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 75704d147b..4e3cdb35d8 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; --=20 2.39.0 From nobody Sat May 18 22:31:26 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 1676540838703978.472070534117; Thu, 16 Feb 2023 01:47:18 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pSapr-00010P-23; Thu, 16 Feb 2023 04:45:51 -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 1pSap6-0000AH-O5 for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:45:06 -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 1pSaoy-0006LJ-6d for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:45:03 -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 1pSao3-00AEF5-0G; Thu, 16 Feb 2023 09:44:45 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pSaoj-0090C2-0n; Thu, 16 Feb 2023 09:44:41 +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=07KFE1uNPx3OFgdJSOAuqFAQGFnWux7DJeIba1iRFcY=; b=bkQpesQwX/mvYzIMYMd96V+S0P 3R784hGKqbpxdcI5wXXRlG+T3i8NhdxuaPln7nzZ+TlgBLxpYlLrdX1hdLPr0Psj/itNj675noZAv wsqWmbR8RVM8fE21Dpasm+p84x+PZLxk/fdLCHEv4Kmmt84fOxxwo7cN9LkPLt1NDNGbLGLwqLN37 uOvN5CF9Rp7zs0PBXv5gxmEM4xa+XMI7NafoC0wL1zlBinO/u2HrD0DYa11sFRX62Bgvati9syWuB Snj/XcfrojbcAJCg9aEmjaqwamaaq0KcKGUt+6VVzVzzfURQn+MHZTvj6QU4iWh8mfEzzbG5Alf+T Or5lxmsg==; From: David Woodhouse To: Peter Maydell , qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Juan Quintela , "Dr . David Alan Gilbert" , Claudio Fontana , Julien Grall , "Michael S. Tsirkin" , Marcel Apfelbaum , armbru@redhat.com, Stefano Stabellini , vikram.garhwal@amd.com Subject: [RFC PATCH v11bis 13/26] hw/xen: Add xenstore operations to allow redirection to internal emulation Date: Thu, 16 Feb 2023 09:44:23 +0000 Message-Id: <20230216094436.2144978-14-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230216094436.2144978-1-dwmw2@infradead.org> References: <20230216094436.2144978-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+96e41a9b2a2966255e0b+7116+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: 1676540840448100007 Content-Type: text/plain; charset="utf-8" From: Paul Durrant Signed-off-by: Paul Durrant Signed-off-by: David Woodhouse --- 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 | 61 +++---- hw/xen/xen-bus.c | 258 ++++------------------------ hw/xen/xen-legacy-backend.c | 121 +++++++------ hw/xen/xen-operations.c | 189 ++++++++++++++++++++ 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 | 25 ++- include/hw/xen/xen-bus.h | 17 +- include/hw/xen/xen-legacy-backend.h | 6 +- include/hw/xen/xen_backend_ops.h | 155 +++++++++++++++++ include/hw/xen/xen_common.h | 1 - include/hw/xen/xen_pvdev.h | 2 +- softmmu/globals.c | 1 + 18 files changed, 503 insertions(+), 411 deletions(-) diff --git a/accel/xen/xen-all.c b/accel/xen/xen-all.c index 2329556595..6df7b4ff34 100644 --- a/accel/xen/xen-all.c +++ b/accel/xen/xen-all.c @@ -100,12 +100,15 @@ void xenstore_store_pv_console_info(int i, Chardev *c= hr) } =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 @@ -119,6 +122,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 @@ -127,7 +132,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 ff39137846..57cd18a7c9 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..db1e64e0fb 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,34 @@ 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..e8d9adeb3e 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,16 @@ 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->backen= d_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 +486,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 +540,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->ba= ckend_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 +581,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 +661,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 +709,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 +717,10 @@ 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, xende= v->frontend_id, + xenbus->backend_id, XS_PERM_READ | XS_PERM_WRITE, e= rrp); if (*errp) { error_prepend(errp, "failed to create frontend: "); return; @@ -910,8 +728,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 +741,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 +963,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 +1009,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 047463d89c..96d0941a7c 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,8 @@ 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 +516,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 +543,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,35 +556,51 @@ 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 int 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"); return -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) { /* Check if xen_init() have been called */ goto err; @@ -606,8 +614,7 @@ int xen_be_init(void) return 0; =20 err: - qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL); - xs_daemon_close(xenstore); + qemu_xen_xs_close(xenstore); xenstore =3D NULL; =20 return -1; diff --git a/hw/xen/xen-operations.c b/hw/xen/xen-operations.c index 4c6b305cc4..b2b76c63af 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" @@ -280,6 +281,193 @@ 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, unsigne= d int domid) +{ + return xs_get_domain_path(h->xsh, domid); +} + +static char **libxenstore_directory(struct qemu_xs_handle *h, xs_transacti= on_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(perm= s_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, v= oid *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, c= onst char *path, + xs_watch_fn fn, void *opaqu= e) +{ + 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_w= atch *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_trans= action_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 @@ -295,4 +483,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..c5b083e4ab 100644 --- a/include/hw/xen/xen-bus-helper.h +++ b/include/hw/xen/xen-bus-helper.h @@ -8,40 +8,39 @@ #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 ea84a9246f..6c2ae709f5 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 ca52e8f188..b479682ac5 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, @@ -239,6 +253,147 @@ 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_tr= ansaction_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_transact= ion_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_transact= ion_t t, + const char *path, const void *data, u= nsigned 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_transac= tion_t t, + unsigned int owner, unsigned int dom= id, + unsigned int perms, 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_transa= ction_t t, + const char *path) +{ + 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 qe= mu_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, x= s_transaction_t t, + bool abort) +{ + 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 4e3cdb35d8..cb32b36a12 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 Sat May 18 22:31:26 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 1676540852418340.0639453388152; Thu, 16 Feb 2023 01:47:32 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pSaov-00088k-W2; Thu, 16 Feb 2023 04:44:54 -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 1pSaot-000856-Rv for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:44: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 1pSaoo-0006Iu-JV for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:44:51 -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 1pSaoj-008Ib9-AQ; Thu, 16 Feb 2023 09:44:41 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pSaoj-0090C6-10; Thu, 16 Feb 2023 09:44:41 +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=tGT0gg20u507g6Dy2KPZBK5266IKAD22cDGTR6BCVXc=; b=nPiocR1oBQkWreJojvQXBJ9Lz/ e7QhDuDIXM+EkZ1CoE2Y7zhHMThtfIpcj3KGKIlx7xSfhcgGMZKjFyE1mmXmh424v6JvVlLyNV3NL uQHAHsJhcaT7qF5vc5iQsIUVWy2sEjSC+mfqSSWYvh/6DNi23XoV69UwrEu5F/VcMIizY6mijn9o8 GApsMqlCq1CaUyF70OIf8Hd5JFLovs3okJIk7Cn8lGuXOU3Y8d+74Vz3bJLDg8aZZwbyLuh5mtJqL rUhgjnSvyR/i+dNP0cVWz7pYJE1EUpBBcKLZNVpLp6v+wBJ4/5EzU3vLKxqar5I0KLWNekmzBdIS1 Lhqrd6Tg==; From: David Woodhouse To: Peter Maydell , qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Juan Quintela , "Dr . David Alan Gilbert" , Claudio Fontana , Julien Grall , "Michael S. Tsirkin" , Marcel Apfelbaum , armbru@redhat.com, Stefano Stabellini , vikram.garhwal@amd.com Subject: [RFC PATCH v11bis 14/26] hw/xen: Move xenstore_store_pv_console_info to xen_console.c Date: Thu, 16 Feb 2023 09:44:24 +0000 Message-Id: <20230216094436.2144978-15-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230216094436.2144978-1-dwmw2@infradead.org> References: <20230216094436.2144978-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+33d3adc5578b079b0cf9+7116+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: 1676540854359100005 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 --- 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 6df7b4ff34..514bc9eea4 100644 --- a/accel/xen/xen-all.c +++ b/accel/xen/xen-all.c @@ -39,67 +39,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 b3873c581b..fcc6c5b522 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 Sat May 18 22:31:26 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 1676540845611134.0031883749209; Thu, 16 Feb 2023 01:47:25 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pSaow-0008Cu-Lo; Thu, 16 Feb 2023 04:44:54 -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 1pSaot-000852-Rm for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:44: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 1pSaoo-0006J2-Lx for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:44:51 -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 1pSaoj-008IbA-CK; Thu, 16 Feb 2023 09:44:41 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pSaoj-0090CB-1C; Thu, 16 Feb 2023 09:44:41 +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=S42qlvexkxlBH5q1Cv7fJbdsj1 QZJUsrCT9trdEfJuwMHR5AhhlfGOQwecGg+GzoIdQ5Xsw6t05YgCWjJgdas1+9z/BfGMPWA6NdAE1 q6Y7YWVVic4qyndfJaZqTtvStDbQt/orfdUfLn17+YpGwU2lZ/WeNA//txlOTRcymyAEXEDpjvTYJ 8x9LrDyL5h7MhF59Ck47/iNEXMsibRMMI6aAzXYzt1Gj3DkOuzib/r41gWBHKesra9VWNmhIBjXbX IHTJVvkwyc98M1NJKm7EMnktl3xC1qXr1iq5hGjemBd4yEHjQh53+Ajz3gVg+n8uDsY49TfmFrzKq sF94Fh2A==; From: David Woodhouse To: Peter Maydell , qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Juan Quintela , "Dr . David Alan Gilbert" , Claudio Fontana , Julien Grall , "Michael S. Tsirkin" , Marcel Apfelbaum , armbru@redhat.com, Stefano Stabellini , vikram.garhwal@amd.com Subject: [RFC PATCH v11bis 15/26] hw/xen: Use XEN_PAGE_SIZE in PV backend drivers Date: Thu, 16 Feb 2023 09:44:25 +0000 Message-Id: <20230216094436.2144978-16-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230216094436.2144978-1-dwmw2@infradead.org> References: <20230216094436.2144978-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+33d3adc5578b079b0cf9+7116+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: 1676540846337100003 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 --- 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 Sat May 18 22:31:26 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 1676540768083560.0878587345957; Thu, 16 Feb 2023 01:46:08 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pSapm-0000a4-P0; Thu, 16 Feb 2023 04:45:49 -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 1pSap3-000096-U8 for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:45:02 -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 1pSaoy-0006LH-5f for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:45: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 1pSao3-00AEF6-0s; Thu, 16 Feb 2023 09:44:44 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pSaoj-0090CF-1P; Thu, 16 Feb 2023 09:44:41 +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=R/q3iDuqVhCg5KamG1/gaK6121rVqYNALR95nOvFIIM=; b=oLgGixB9KUrFrtUZ+phnCDm1Oo J83xXMlgkhuKynPxSJUc/VNKIm01d6v8xE0hOSQohVtcyCNnurPuxPLqQRp0QxYxJgr/HAP0sCH6V xcEsYxX1zSNA1fD4bps37UzOSsZWNKlpBVdJOItmz8uS7Ly52ov0y/qm+eXTNYBwMvJGD2CVYNsG2 /qm2f55lLu4sB92EnlG1GUv5oEHAZ7MjGOQY+WDoZEuCMqYpN0EYqz2lglZ9fzbFnXUzIHhKwf2uf lfimF/CrZrZTA5fSCGA8CrOf/9m6m4pdzE0fTUVtlO0QU/gDEuXFh5f2Qo2vlsmfeMKRs/v4/ST/l Yg8l29pQ==; From: David Woodhouse To: Peter Maydell , qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Juan Quintela , "Dr . David Alan Gilbert" , Claudio Fontana , Julien Grall , "Michael S. Tsirkin" , Marcel Apfelbaum , armbru@redhat.com, Stefano Stabellini , vikram.garhwal@amd.com Subject: [RFC PATCH v11bis 16/26] hw/xen: Rename xen_common.h to xen_native.h Date: Thu, 16 Feb 2023 09:44:26 +0000 Message-Id: <20230216094436.2144978-17-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230216094436.2144978-1-dwmw2@infradead.org> References: <20230216094436.2144978-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+96e41a9b2a2966255e0b+7116+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: 1676540770293100003 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 --- 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 | 8 +++---- hw/i386/xen/xen_platform.c | 7 +++--- hw/xen/trace-events | 2 +- hw/xen/xen-mapcache.c | 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-hvm-common.h | 2 +- include/hw/xen/xen.h | 22 ++++++++++++------- include/hw/xen/{xen_common.h =3D> xen_native.h} | 10 ++++++--- include/hw/xen/xen_pvdev.h | 3 ++- 18 files changed, 46 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 514bc9eea4..fcdc8364bf 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 df64dd8dcc..4a4825e81d 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -46,8 +46,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" @@ -59,6 +57,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 4219308caf..98f1836708 100644 --- a/hw/i386/xen/xen-hvm.c +++ b/hw/i386/xen/xen-hvm.c @@ -30,10 +30,10 @@ 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_platform.c b/hw/i386/xen/xen_platform.c index 319049d80c..dfa1379ec9 100644 --- a/hw/i386/xen/xen_platform.c +++ b/hw/i386/xen/xen_platform.c @@ -29,7 +29,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" @@ -39,10 +38,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 02ca1183da..67a6c41926 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-mapcache.c b/hw/xen/xen-mapcache.c index 1d0879d234..f7d974677d 100644 --- a/hw/xen/xen-mapcache.c +++ b/hw/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/xen/xen-operations.c b/hw/xen/xen-operations.c index b2b76c63af..352153c974 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-hvm-common.h b/include/hw/xen/xen-hvm-commo= n.h index c0b354e591..aeb12e1408 100644 --- a/include/hw/xen/xen-hvm-common.h +++ b/include/hw/xen/xen-hvm-common.h @@ -7,8 +7,8 @@ #include "cpu.h" #include "hw/pci/pci.h" #include "hw/hw.h" +#include "hw/xen/xen_native.h" #include "hw/xen/xen_backend_ops.h" -#include "hw/xen/xen_common.h" #include "sysemu/runstate.h" #include "sysemu/sysemu.h" #include "sysemu/xen.h" diff --git a/include/hw/xen/xen.h b/include/hw/xen/xen.h index fcc6c5b522..fe73990db7 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 cb32b36a12..8b01b071e5 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 @@ -625,4 +629,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 Sat May 18 22:31:26 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 1676540922731708.5942192286989; Thu, 16 Feb 2023 01:48:42 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pSaox-0008EW-03; Thu, 16 Feb 2023 04:44:55 -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 1pSaot-00085W-V0 for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:44: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 1pSaoo-0006Iv-Ky for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:44:51 -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 1pSaoj-008IbB-GX; Thu, 16 Feb 2023 09:44:42 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pSaoj-0090CJ-1b; Thu, 16 Feb 2023 09:44:41 +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=tbphZeDYd2J9cuSKfYpX0flwoj0wo+iHN0GjOE24anQ=; b=tmyLenqT0jsGv0vTrHxmr51aKi 0cBR9X85OUI3KLYH2fqkKwzCfXV+oHOPpxQCPFu0ZZLhf1NqItJCEgIqHaRF3yyCR2JQQfv3C3faO CyFd4s92sFpUhVZDHFB3PK2Q9G/m0vTKP61h81SXRfqQX5EBmqGSfw7K4OIxCSzFLmbfb07uhnGcA sEMCSN6j5aCnijfehT5y/oZ+/HvODs71/QDDvOuL1fYqgUOdFVTY/CgysdbO0aveI/ZK9y5Kuvggj lmNDK5blIQihue2kUxoY6Ci/HZby4iwLtJZIV2cZGG8vFyoF+Dt92b3KdiN4YCampXszifPy0pvPF JdoqwxoQ==; From: David Woodhouse To: Peter Maydell , qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Juan Quintela , "Dr . David Alan Gilbert" , Claudio Fontana , Julien Grall , "Michael S. Tsirkin" , Marcel Apfelbaum , armbru@redhat.com, Stefano Stabellini , vikram.garhwal@amd.com Subject: [RFC PATCH v11bis 17/26] hw/xen: Build PV backend drivers for CONFIG_XEN_BUS Date: Thu, 16 Feb 2023 09:44:27 +0000 Message-Id: <20230216094436.2144978-18-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230216094436.2144978-1-dwmw2@infradead.org> References: <20230216094436.2144978-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+33d3adc5578b079b0cf9+7116+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: 1676540924859100003 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 --- 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 02b9118b7f..afd20754a1 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 Sat May 18 22:31:26 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 1676540897882638.7085943793018; Thu, 16 Feb 2023 01:48:17 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pSaot-000851-NY; Thu, 16 Feb 2023 04:44:51 -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 1pSaos-00083F-3F for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:44: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 1pSaoo-0006J4-Ln for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:44: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 1pSaoj-008IbC-Ih; Thu, 16 Feb 2023 09:44:42 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pSaoj-0090CN-1o; Thu, 16 Feb 2023 09:44:41 +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=Brn84Bd/KTpVkrNFiD99D3sEym3orojn0xO+CrA41rM=; b=sVlbls3DctqUW0WKOXOG87z350 BT3IYr7mDcr1jzEw+/3FYvLvqXm54+U+FdRzdA9PsPWM990ln7gwpjpM4HEEooGRLJeXO+O55G1I+ wkWF2F1cMzl9Q53rthLVAv0y2f3X7FGe/qiBeRcIjCAALq1iD/IPA7akF51l0APFwn+FR7ZoAfHDz lwSaiiFDC42uMWNs7dqCaI0NLlw9ajm0u8+/wDXKxpi4jfD+MXrlRn3XnB5NA2MYOcHJ5uK/UAf28 SvFsZH0dVaVdit1CIB19o1heatRHlXHq85epwnhwfHD6ZEtESgJC7pI0EdLRxChvRaPUqKO6x333z qR5QuqfQ==; From: David Woodhouse To: Peter Maydell , qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Juan Quintela , "Dr . David Alan Gilbert" , Claudio Fontana , Julien Grall , "Michael S. Tsirkin" , Marcel Apfelbaum , armbru@redhat.com, Stefano Stabellini , vikram.garhwal@amd.com Subject: [RFC PATCH v11bis 18/26] hw/xen: Avoid crash when backend watch fires too early Date: Thu, 16 Feb 2023 09:44:28 +0000 Message-Id: <20230216094436.2144978-19-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230216094436.2144978-1-dwmw2@infradead.org> References: <20230216094436.2144978-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+33d3adc5578b079b0cf9+7116+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: 1676540898692100003 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 --- 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 e8d9adeb3e..83121c5a43 100644 --- a/hw/xen/xen-bus.c +++ b/hw/xen/xen-bus.c @@ -1031,13 +1031,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", @@ -1056,6 +1049,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 Sat May 18 22:31:26 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 167654079470164.62840948141513; Thu, 16 Feb 2023 01:46:34 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pSaou-00085r-BS; Thu, 16 Feb 2023 04:44:52 -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 1pSaot-00084w-Fu for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:44: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 1pSaoo-0006Iy-Jk for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:44:51 -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 1pSaoj-008IbD-KZ; Thu, 16 Feb 2023 09:44:42 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pSaoj-0090CR-20; Thu, 16 Feb 2023 09:44:41 +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=7HuQae7CBMvNWNUtKmsp3irMJUgtZo+bY0Gg/sxTvcA=; b=a5b8MNtkYYwoOEl0SY9W9ePfHV xVzFLEJEFUQPSLjRBsMEYAMCy6bF6TDrwpFEe50y/NSf6tApvEmpTzjDCHT9vM1g37cksG845r93m vpop8ao73xhi0dSM881rjHLVJr9Pms3Eih4bNfDFVsetRxmJhGLBvDIN2fKwXEzGr0pWweC0slh0e FUVKBIIStB51mZPpevt1h2TNv3eU4pAdYHxTD9NGFc+Lc6suesxHpJhizBI1AM3ZKnHp9j28ccyB+ AxC3K+DLUsOmYhm/WRWNl0+HGtf7A+ZeE19CwNEuZ3cxJM4AHI8ou7pKHUJ7P9Hoc1JeWX9eED0Jh 4tWh5bzQ==; From: David Woodhouse To: Peter Maydell , qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Juan Quintela , "Dr . David Alan Gilbert" , Claudio Fontana , Julien Grall , "Michael S. Tsirkin" , Marcel Apfelbaum , armbru@redhat.com, Stefano Stabellini , vikram.garhwal@amd.com Subject: [RFC PATCH v11bis 19/26] hw/xen: Only advertise ring-page-order for xen-block if gnttab supports it Date: Thu, 16 Feb 2023 09:44:29 +0000 Message-Id: <20230216094436.2144978-20-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230216094436.2144978-1-dwmw2@infradead.org> References: <20230216094436.2144978-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+33d3adc5578b079b0cf9+7116+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: 1676540796022100005 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 --- 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 Sat May 18 22:31:26 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 1676540840089136.22093860695736; Thu, 16 Feb 2023 01:47:20 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pSapv-0001jP-Fg; Thu, 16 Feb 2023 04:45:55 -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 1pSapA-0000BB-DN for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:45:08 -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 1pSap8-0006LL-HM for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:45:08 -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 1pSao3-00AEF7-1f; Thu, 16 Feb 2023 09:44:44 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pSaoj-0090CW-2C; Thu, 16 Feb 2023 09:44:41 +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=xLkkRlpHG9JKYJBXjvVOkKqNbVuiZaxxdPWmCFIY5qE=; b=oeQZu6Q7LX3/GPKRMJO1+mfk8k qLdMsOvUqQ2mwMYOaEDMaWQSuNeaJSaCjtwW/OHCMxG8g35Npj+nudqgIyf/jP7mW7NvhnXRaa/JT D2ToFiyEQ97Azgh4LMiINhx7ye6tlvQ2Io07apZF/IqAqQYN6VjwXDqEnAdmEo2LfgUmk7Ns+1gBY FYjTyovg2JOf1yM4Uz79P6LHxA/zQ8d3gYO9rtIbHtHN4A0aVGpkDm92law8cotSjHM64d+U4fAYc tc4+a98lxci08oh3Sm2S5NxfxQeHWiCOLNepY4wgl3/07sOnhtIvNuNB9dV5iCbSvxrgk3IdlBEgW XQL+bzsA==; From: David Woodhouse To: Peter Maydell , qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Juan Quintela , "Dr . David Alan Gilbert" , Claudio Fontana , Julien Grall , "Michael S. Tsirkin" , Marcel Apfelbaum , armbru@redhat.com, Stefano Stabellini , vikram.garhwal@amd.com Subject: [RFC PATCH v11bis 20/26] hw/xen: Hook up emulated implementation for event channel operations Date: Thu, 16 Feb 2023 09:44:30 +0000 Message-Id: <20230216094436.2144978-21-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230216094436.2144978-1-dwmw2@infradead.org> References: <20230216094436.2144978-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+96e41a9b2a2966255e0b+7116+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: 1676540840303100003 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 --- 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 3f60461e5c..4442e3ab06 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 Sat May 18 22:31:26 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 1676540820500158.33336713813594; Thu, 16 Feb 2023 01:47:00 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pSaov-00087D-F9; Thu, 16 Feb 2023 04:44: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 1pSaos-00083w-Kd for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:44: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 1pSaoo-0006Iz-KJ for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:44: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 1pSaoj-008IbE-Of; Thu, 16 Feb 2023 09:44:42 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pSaoj-0090Ca-2P; Thu, 16 Feb 2023 09:44:41 +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=VnV5oMqi4bXEEfCU/NZ8KaoiNRmx4hQo5PA94pNnkcU=; b=N4bqDZ80+wRqEoe1CatUwS+6O2 dvQqV4rBerwZaV0JobDjU1gC14kj9v6YO0sJjELH/20RGWS34iX8IbczZBJSq92Nj8i+7PDD8l56l yxFAQDXf46MYo3ONeTWNX6EaVtQBdOgAJtdvMWSSPWAQiodqoYDqo2P+A4GkwZK6OCvglhmxu4hW8 mUrCeVVjfBPKkKBbUj4Ezb2ud5hpQC9Got+2BoWJMwOaFgkMoKVqSwSNYoqtdYkbPAHxHOCbQzgdT a2lJ6+JR+Gsjvc7dbnCslRQ1SHJVLgiGLwRHYQ1Zy5Vu0LL3UxvpWpLgWne4/vtV6gEpNbawVwVZl HBzVJklQ==; From: David Woodhouse To: Peter Maydell , qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Juan Quintela , "Dr . David Alan Gilbert" , Claudio Fontana , Julien Grall , "Michael S. Tsirkin" , Marcel Apfelbaum , armbru@redhat.com, Stefano Stabellini , vikram.garhwal@amd.com Subject: [RFC PATCH v11bis 21/26] hw/xen: Add emulated implementation of grant table operations Date: Thu, 16 Feb 2023 09:44:31 +0000 Message-Id: <20230216094436.2144978-22-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230216094436.2144978-1-dwmw2@infradead.org> References: <20230216094436.2144978-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+33d3adc5578b079b0cf9+7116+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: 1676540822152100007 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 --- hw/i386/kvm/xen_gnttab.c | 294 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 291 insertions(+), 3 deletions(-) diff --git a/hw/i386/kvm/xen_gnttab.c b/hw/i386/kvm/xen_gnttab.c index 1e691ded32..5bd99eaf17 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,283 @@ 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, ~(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; + volatile grant_entry_v1_t *gnt_p; + grant_entry_v1_t gnt; + 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; + gnt =3D *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 pr= ot) +{ + 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 || act->mrs.size < XEN_PAGE_SIZE || + memory_region_get_ram_addr(act->mrs.mr) =3D=3D RAM_ADDR_INVALI= D || + !(act->virtaddr =3D qemu_map_ram_ptr(act->mrs.mr->ram_block, + act->mrs.offset_within_regi= on))) { + 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 Sat May 18 22:31:26 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 1676540853480425.4849272906249; Thu, 16 Feb 2023 01:47:33 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pSapr-00010O-3l; Thu, 16 Feb 2023 04:45:51 -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 1pSap4-00009V-Kl for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:45:02 -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 1pSaoy-0006LF-6X for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:45:02 -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 1pSao3-00AEF8-22; Thu, 16 Feb 2023 09:44:44 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pSaoj-0090Ce-2b; Thu, 16 Feb 2023 09:44:41 +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=ugMRYpOENcLNDnJ7psPeBdrXquDv6QhcfrVsn04tLNM=; b=TubUwkPCALe7b7TN46veOUNIyW /t+cNj1n3RdC5DzfmIMf5yHnOin08AhZp7AFSaJ40gZNkv4HVW04d+AWLWRTSURbojs3ZXg02eSIa 9Y4xmLKd9a8jmj83cPwv5IrJXMn3rE6k2Pjv8Um0TCvr39HUCfjkrO17rkl7yGL2+tD5Xjxfh+uCE NdBLsfr7qAeq/sPhxLzHThJ8VyxOQC+SUB4YqXYTFqC2fJBD8ye8HrQdV5QzaqGT8olULmG/sapZQ lBkNTxJoU6LrHUAEFzJTjuR8c1k8ETGHpK5WfHMjFjF0RTUuvYpkbP5BYBy/X3VAdLZJ8rW+M/Zcj bulonxSw==; From: David Woodhouse To: Peter Maydell , qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Juan Quintela , "Dr . David Alan Gilbert" , Claudio Fontana , Julien Grall , "Michael S. Tsirkin" , Marcel Apfelbaum , armbru@redhat.com, Stefano Stabellini , vikram.garhwal@amd.com Subject: [RFC PATCH v11bis 22/26] hw/xen: Add emulated implementation of XenStore operations Date: Thu, 16 Feb 2023 09:44:32 +0000 Message-Id: <20230216094436.2144978-23-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230216094436.2144978-1-dwmw2@infradead.org> References: <20230216094436.2144978-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+96e41a9b2a2966255e0b+7116+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: 1676540854405100006 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 --- 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 57cd18a7c9..74729cbb63 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) @@ -1268,6 +1272,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) { @@ -1314,9 +1327,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) @@ -1404,3 +1415,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 Sat May 18 22:31:26 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 1676540740875960.5697933491832; Thu, 16 Feb 2023 01:45:40 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pSaos-00083N-Fm; Thu, 16 Feb 2023 04:44:50 -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 1pSaoq-00081s-P6 for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:44:49 -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 1pSaoo-0006Iw-K2 for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:44:48 -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 1pSaoj-008IbG-SO; Thu, 16 Feb 2023 09:44:42 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pSaoj-0090Ci-2o; Thu, 16 Feb 2023 09:44:41 +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=QyNeWaB4dDnqjyYiPRBYMMBedUv4wTrX+rvq6VHxarA=; b=g+ySgIj10Wlbn6QnxAl/CqCb+O Iba8ff7P7uhQlf0dAWM6rnlZOQ1GO19jcNykQJxSpLG8qtoRS9AgUvNl6YzwH2gE8fvlifs/pDHVy Ef5ZKy15Q+Cm/atwAC+c9ns3PhuTJeZtuYXfW4KZ67J98hhLeM8Xki07/X+YebBFVxBA2QyOb4cDh jR5TtGssBiVwZYCRiSzpevbo4sQt9nWkT8TEHVzvLvSkoBmhl6zTrBqCkO8/lI+kNcakOwA7IOcc2 lYqhGXoADMOVxVPXAMcBBWmceSvdUPPA2AvLBLmkhTXUrOiTuquvcEuhNUPMheDYD6UOWp6qd3Ts3 QmGIUP0g==; From: David Woodhouse To: Peter Maydell , qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Juan Quintela , "Dr . David Alan Gilbert" , Claudio Fontana , Julien Grall , "Michael S. Tsirkin" , Marcel Apfelbaum , armbru@redhat.com, Stefano Stabellini , vikram.garhwal@amd.com Subject: [RFC PATCH v11bis 23/26] hw/xen: Map guest XENSTORE_PFN grant in emulated Xenstore Date: Thu, 16 Feb 2023 09:44:33 +0000 Message-Id: <20230216094436.2144978-24-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230216094436.2144978-1-dwmw2@infradead.org> References: <20230216094436.2144978-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+33d3adc5578b079b0cf9+7116+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: 1676540741836100003 Content-Type: text/plain; charset="utf-8" From: David Woodhouse Signed-off-by: David Woodhouse --- 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 74729cbb63..a58c89b555 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; @@ -1413,6 +1418,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_gntref, PROT_READ|PROT_WR= ITE); + return 0; } =20 --=20 2.39.0 From nobody Sat May 18 22:31:26 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 1676540790190369.02933129117105; Thu, 16 Feb 2023 01:46:30 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pSaou-000865-Jg; Thu, 16 Feb 2023 04:44:52 -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 1pSaoq-00081u-Q3 for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:44:49 -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 1pSaoo-0006J3-Jf for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:44:48 -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 1pSaoj-008IbI-UV; Thu, 16 Feb 2023 09:44:42 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pSaoj-0090Cm-31; Thu, 16 Feb 2023 09:44:41 +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=Am7P9DiYTIJnr+YtbTgvJ67LnHE09jjxnbAUAsxMMXs=; b=EcZUmcMNuOLPSGh2ml9Y8cHVgV evZTKn5xC5a1LMIqYhOYA3Ix/CRIRNrRDSCgnvOTayKoLVSW/xYUW+385qksYeJMgWvasQ/glWUxY 99q1yF42ndkUPGTa+q/wEymz3D4qrKEeLNoXS2hIsArFbEcny+4ONWy+fT5iUg3FUk6FNH+i/mPvV YAOocmNoFVpR1CZMPGQ5sXj/r8f/43TH1D0qlmDuyhQUwUAoPaJCRRgg+nKLHS3fv7/8BgvCIGrNg E/qlg9ZaTxaAvQjbQQkt/SBqqhmiiog/jgV4Jclu3f6eD2Lu28jl2aD3qJtV8QZSd4EnN2LtztOm5 2apevZsw==; From: David Woodhouse To: Peter Maydell , qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Juan Quintela , "Dr . David Alan Gilbert" , Claudio Fontana , Julien Grall , "Michael S. Tsirkin" , Marcel Apfelbaum , armbru@redhat.com, Stefano Stabellini , vikram.garhwal@amd.com Subject: [RFC PATCH v11bis 24/26] hw/xen: Implement soft reset for emulated gnttab Date: Thu, 16 Feb 2023 09:44:34 +0000 Message-Id: <20230216094436.2144978-25-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230216094436.2144978-1-dwmw2@infradead.org> References: <20230216094436.2144978-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+33d3adc5578b079b0cf9+7116+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: 1676540792007100003 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 --- 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 5bd99eaf17..16230f8581 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; @@ -518,3 +519,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 ef77f64e75..705de0ebb1 100644 --- a/target/i386/kvm/xen-emu.c +++ b/target/i386/kvm/xen-emu.c @@ -1384,6 +1384,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 Sat May 18 22:31:26 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 167654071666320.27101078053738; Thu, 16 Feb 2023 01:45:16 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pSaoz-0008Jp-5D; Thu, 16 Feb 2023 04:44:57 -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 1pSaou-00085g-34 for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:44:52 -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 1pSaoo-0006Ix-Ku for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:44:51 -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 1pSaok-008IbJ-0O; Thu, 16 Feb 2023 09:44:42 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pSaoj-0090Cq-3D; Thu, 16 Feb 2023 09:44:42 +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=1fVTFj0bYzICeuIXvuNLzGQ/h9sPn+k7vgman+UIV1A=; b=sJ0Xw9zX+oznKQ/wqvzr9F9uQX RjqxVHcVHD4tb+mpczvxHop1d6nEo61f3GCMT1jV5ZguDMptgEClWBJDmVx/gHJ7RNjcvCC6MvAxb Qs0h5HF7FRwexgwGrboi3LAF7nPqGh6qkAvuaGsE4R+z+ob3zWu58Sc/v0u9YBhWx/dXhj0mjWXKu 6XJo3SpW/a0oHvUDYKOR0Pxb8BzbxZcP9qBryykZ9ySxMhQ17BsqGPsmOQJI2DZSPB0TCqUCxvuHI 2F75+tM0cpfOx/DX7oZ5Czg3l2hFGz9aFRRoDYpPdIqwCbU7cPZQVV3alPNLDkDKg3c9t5v1qFir8 thQyKvbg==; From: David Woodhouse To: Peter Maydell , qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Juan Quintela , "Dr . David Alan Gilbert" , Claudio Fontana , Julien Grall , "Michael S. Tsirkin" , Marcel Apfelbaum , armbru@redhat.com, Stefano Stabellini , vikram.garhwal@amd.com Subject: [RFC PATCH v11bis 25/26] hw/xen: Subsume xen_be_register_common() into xen_be_init() Date: Thu, 16 Feb 2023 09:44:35 +0000 Message-Id: <20230216094436.2144978-26-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230216094436.2144978-1-dwmw2@infradead.org> References: <20230216094436.2144978-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+33d3adc5578b079b0cf9+7116+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: 1676540718015100001 Content-Type: text/plain; charset="utf-8" From: David Woodhouse Every caller of xen_be_init() checks and exits on error, then calls xen_be_register_common(). Just make xen_be_init() abort for itself and return void, and register the common devices too. Signed-off-by: David Woodhouse --- hw/xen/xen-hvm-common.c | 18 +--------- hw/xen/xen-legacy-backend.c | 55 ++++++++++++----------------- hw/xenpv/xen_machine_pv.c | 6 +--- include/hw/xen/xen-legacy-backend.h | 3 +- 4 files changed, 25 insertions(+), 57 deletions(-) diff --git a/hw/xen/xen-hvm-common.c b/hw/xen/xen-hvm-common.c index 0a3ffbf955..44679116ce 100644 --- a/hw/xen/xen-hvm-common.c +++ b/hw/xen/xen-hvm-common.c @@ -765,22 +765,6 @@ void xen_shutdown_fatal_error(const char *fmt, ...) qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_ERROR); } =20 -static void xen_register_backend(XenIOState *state) -{ - /* Initialize backend core & drivers */ - if (xen_be_init() !=3D 0) { - error_report("xen backend core setup failed"); - goto err; - } - xen_be_register_common(); - - return; - -err: - error_report("xen hardware virtual machine backend registration failed= "); - exit(1); -} - static void xen_do_ioreq_register(XenIOState *state, unsigned int max_cpus, MemoryListener xen_memory_liste= ner) @@ -886,7 +870,7 @@ void xen_register_ioreq(XenIOState *state, unsigned int= max_cpus, =20 xen_bus_init(); =20 - xen_register_backend(state); + xen_be_init(); =20 return; =20 diff --git a/hw/xen/xen-legacy-backend.c b/hw/xen/xen-legacy-backend.c index 96d0941a7c..d6ad190062 100644 --- a/hw/xen/xen-legacy-backend.c +++ b/hw/xen/xen-legacy-backend.c @@ -593,17 +593,26 @@ static int xenstore_scan(const char *type, int dom, s= truct XenDevOps *ops) =20 /* -------------------------------------------------------------------- */ =20 -int xen_be_init(void) +static void xen_set_dynamic_sysbus(void) +{ + Object *machine =3D qdev_get_machine(); + ObjectClass *oc =3D object_get_class(machine); + MachineClass *mc =3D MACHINE_CLASS(oc); + + machine_class_allow_dynamic_sysbus_dev(mc, TYPE_XENSYSDEV); +} + +void xen_be_init(void) { xenstore =3D qemu_xen_xs_open(); if (!xenstore) { xen_pv_printf(NULL, 0, "can't connect to xenstored\n"); - return -1; + exit(1); } =20 if (xen_evtchn_ops =3D=3D NULL || xen_gnttab_ops =3D=3D NULL) { - /* Check if xen_init() have been called */ - goto err; + xen_pv_printf(NULL, 0, "Xen operations not set up\n"); + exit(1); } =20 xen_sysdev =3D qdev_new(TYPE_XENSYSDEV); @@ -611,22 +620,16 @@ int xen_be_init(void) xen_sysbus =3D qbus_new(TYPE_XENSYSBUS, xen_sysdev, "xen-sysbus"); qbus_set_bus_hotplug_handler(xen_sysbus); =20 - return 0; - -err: - qemu_xen_xs_close(xenstore); - xenstore =3D NULL; - - return -1; -} - -static void xen_set_dynamic_sysbus(void) -{ - Object *machine =3D qdev_get_machine(); - ObjectClass *oc =3D object_get_class(machine); - MachineClass *mc =3D MACHINE_CLASS(oc); + xen_set_dynamic_sysbus(); =20 - machine_class_allow_dynamic_sysbus_dev(mc, TYPE_XENSYSDEV); + xen_be_register("console", &xen_console_ops); + xen_be_register("vkbd", &xen_kbdmouse_ops); +#ifdef CONFIG_VIRTFS + xen_be_register("9pfs", &xen_9pfs_ops); +#endif +#ifdef CONFIG_USB_LIBUSB + xen_be_register("qusb", &xen_usb_ops); +#endif } =20 int xen_be_register(const char *type, struct XenDevOps *ops) @@ -648,20 +651,6 @@ int xen_be_register(const char *type, struct XenDevOps= *ops) return xenstore_scan(type, xen_domid, ops); } =20 -void xen_be_register_common(void) -{ - xen_set_dynamic_sysbus(); - - xen_be_register("console", &xen_console_ops); - xen_be_register("vkbd", &xen_kbdmouse_ops); -#ifdef CONFIG_VIRTFS - xen_be_register("9pfs", &xen_9pfs_ops); -#endif -#ifdef CONFIG_USB_LIBUSB - xen_be_register("qusb", &xen_usb_ops); -#endif -} - int xen_be_bind_evtchn(struct XenLegacyDevice *xendev) { if (xendev->local_port !=3D -1) { diff --git a/hw/xenpv/xen_machine_pv.c b/hw/xenpv/xen_machine_pv.c index 20c9611d71..2e759d0619 100644 --- a/hw/xenpv/xen_machine_pv.c +++ b/hw/xenpv/xen_machine_pv.c @@ -36,10 +36,7 @@ static void xen_init_pv(MachineState *machine) int i; =20 /* Initialize backend core & drivers */ - if (xen_be_init() !=3D 0) { - error_report("%s: xen backend core setup failed", __func__); - exit(1); - } + xen_be_init(); =20 switch (xen_mode) { case XEN_ATTACH: @@ -55,7 +52,6 @@ static void xen_init_pv(MachineState *machine) break; } =20 - xen_be_register_common(); xen_be_register("vfb", &xen_framebuffer_ops); xen_be_register("qnic", &xen_netdev_ops); =20 diff --git a/include/hw/xen/xen-legacy-backend.h b/include/hw/xen/xen-legac= y-backend.h index 6c2ae709f5..6c307c5f2c 100644 --- a/include/hw/xen/xen-legacy-backend.h +++ b/include/hw/xen/xen-legacy-backend.h @@ -39,8 +39,7 @@ int xenstore_read_fe_uint64(struct XenLegacyDevice *xende= v, const char *node, void xen_be_check_state(struct XenLegacyDevice *xendev); =20 /* xen backend driver bits */ -int xen_be_init(void); -void xen_be_register_common(void); +void xen_be_init(void); int xen_be_register(const char *type, struct XenDevOps *ops); int xen_be_set_state(struct XenLegacyDevice *xendev, enum xenbus_state sta= te); int xen_be_bind_evtchn(struct XenLegacyDevice *xendev); --=20 2.39.0 From nobody Sat May 18 22:31:26 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 1676540820894602.8773170759649; Thu, 16 Feb 2023 01:47:00 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pSap3-00007t-Hf; Thu, 16 Feb 2023 04:45:01 -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 1pSap1-00005V-Km for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:44:59 -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 1pSaoy-0006LK-85 for qemu-devel@nongnu.org; Thu, 16 Feb 2023 04:44:59 -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 1pSao3-00AEF9-2s; Thu, 16 Feb 2023 09:44:44 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pSaok-0090Cw-0C; Thu, 16 Feb 2023 09:44:42 +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=a+qZtg1Rqx19i6OtP3yYmF7RzpIlILXUOwzZY45PjeE=; b=NL6R73+BCDPR8wtyK057V7CzLW 6L2zawNql4OLvdB10DF1RRnTJ8mHpxqZjSAn2MhH/EuaqEzOx5TkB+ha3yS4qiI1+PkPLC88qnAvi lSQDIQZf79pg0sBfIq5Xm7RsrYKK1+VR5/alkrUpytvsUA/QP0tYdKxZpTyy4lBIj3Zv9cmcWLpyd fPoDGPkxpvhtK+c3m5Kadyxc1h67LM+4yLyzeynUKc3hlQfxdtIToU74fDiSdsHRi+KixlSfaj4+D /MDVdDJeWCT8vX8SivNpU72MKQO0VkV20v+A8bA0X5WQIi8SFX1V2J0/afM06dg2uK70ejSIX5rn/ FFqwXBjw==; From: David Woodhouse To: Peter Maydell , qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Juan Quintela , "Dr . David Alan Gilbert" , Claudio Fontana , Julien Grall , "Michael S. Tsirkin" , Marcel Apfelbaum , armbru@redhat.com, Stefano Stabellini , vikram.garhwal@amd.com Subject: [RFC PATCH v11bis 26/26] i386/xen: Initialize Xen backends from pc_basic_device_init() for emulation Date: Thu, 16 Feb 2023 09:44:36 +0000 Message-Id: <20230216094436.2144978-27-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230216094436.2144978-1-dwmw2@infradead.org> References: <20230216094436.2144978-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+96e41a9b2a2966255e0b+7116+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: 1676540822110100005 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 --- hw/i386/pc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 5ec3518b9e..d464f171fa 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. @@ -1316,6 +1321,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