From nobody Tue Feb 10 12:58:41 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1677771438630785.2555359391176; Thu, 2 Mar 2023 07:37:18 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pXkxn-0004D2-Hu; Thu, 02 Mar 2023 10:35:24 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pXkxI-0003oC-Rg for qemu-devel@nongnu.org; Thu, 02 Mar 2023 10:34:52 -0500 Received: from desiato.infradead.org ([2001:8b0:10b:1:d65d:64ff:fe57:4e05]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pXkxC-0001f9-Iw for qemu-devel@nongnu.org; Thu, 02 Mar 2023 10:34:52 -0500 Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by desiato.infradead.org with esmtpsa (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx5-00FL3r-07; Thu, 02 Mar 2023 15:34:41 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pXkx4-004uzk-2x; Thu, 02 Mar 2023 15:34:38 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=GIy/mr/P0dU4lKy5osmGAuO163GgHpykyx4+8Dxy3J8=; b=psZYAy7hv1vPQkhNzx5j+j6PHj aUyGV4bYYciEJOkFzCEJhMbOARGxDslIEJw4j6rxUHi9qpYkgFnxvxXqk03Pp+ElrcJlqwIbw+kjg 0RXL1heQljsalhW8cGZyUm5iCD4ShOcWcXuuPNF4VhSVDPNv4zLroaiJOyTgIwDKcEMURGOw8VKyK GsT8GvlhpqTuky3/UE+sacR11dim6D8pDQtAmaXf5qZxu4Zs/zJAPFF28d6emV39xcadQbJdnnXyE aZsTR+Ey1CRyZYzmWD7AnOg1oliBGmpQ3E7GMXZvW/AiYUQS3GKoL1fMm0WGxCRfjqHGGj7IrPXNt PTJwgqWw==; From: David Woodhouse To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Paul Durrant , Joao Martins , Ankur Arora , Stefano Stabellini , vikram.garhwal@amd.com, Anthony Perard , xen-devel@lists.xenproject.org Subject: [RFC PATCH v1 22/25] hw/xen: Add emulated implementation of XenStore operations Date: Thu, 2 Mar 2023 15:34:32 +0000 Message-Id: <20230302153435.1170111-23-dwmw2@infradead.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230302153435.1170111-1-dwmw2@infradead.org> References: <20230302153435.1170111-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-SRS-Rewrite: SMTP reverse-path rewritten from by desiato.infradead.org. See http://www.infradead.org/rpr.html Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: none client-ip=2001:8b0:10b:1:d65d:64ff:fe57:4e05; envelope-from=BATV+9a0490e5ac528e462c30+7130+infradead.org+dwmw2@desiato.srs.infradead.org; helo=desiato.infradead.org X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1677771440807100010 Content-Type: text/plain; charset="utf-8" From: David Woodhouse Now that we have an internal implementation of XenStore, we can populate the xenstore_backend_ops to allow PV backends to talk to it. Watches can't be processed with immediate callbacks because that would call back into XenBus code recursively. Defer them to a QEMUBH to be run as appropriate from the main loop. We use a QEMUBH per XS handle, and it walks all the watches (there shouldn't be many per handle) to fire any which have pending events. We *could* have done it differently but this allows us to use the same struct watch_event as we have for the guest side, and keeps things relatively simple. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- hw/i386/kvm/xen_xenstore.c | 273 ++++++++++++++++++++++++++++++++++++- 1 file changed, 269 insertions(+), 4 deletions(-) diff --git a/hw/i386/kvm/xen_xenstore.c b/hw/i386/kvm/xen_xenstore.c index bab40d1a04..028f80499e 100644 --- a/hw/i386/kvm/xen_xenstore.c +++ b/hw/i386/kvm/xen_xenstore.c @@ -49,7 +49,7 @@ struct XenXenstoreState { /*< public >*/ =20 XenstoreImplState *impl; - GList *watch_events; + GList *watch_events; /* for the guest */ =20 MemoryRegion xenstore_page; struct xenstore_domain_interface *xs; @@ -73,6 +73,8 @@ struct XenXenstoreState *xen_xenstore_singleton; static void xen_xenstore_event(void *opaque); static void fire_watch_cb(void *opaque, const char *path, const char *toke= n); =20 +static struct xenstore_backend_ops emu_xenstore_backend_ops; + static void G_GNUC_PRINTF (4, 5) relpath_printf(XenXenstoreState *s, GList *perms, const char *relpath, @@ -169,6 +171,8 @@ static void xen_xenstore_realize(DeviceState *dev, Erro= r **errp) relpath_printf(s, perms, "feature", "%s", ""); =20 g_list_free_full(perms, g_free); + + xen_xenstore_ops =3D &emu_xenstore_backend_ops; } =20 static bool xen_xenstore_is_needed(void *opaque) @@ -1305,6 +1309,15 @@ struct watch_event { char *token; }; =20 +static void free_watch_event(struct watch_event *ev) +{ + if (ev) { + g_free(ev->path); + g_free(ev->token); + g_free(ev); + } +} + static void queue_watch(XenXenstoreState *s, const char *path, const char *token) { @@ -1351,9 +1364,7 @@ static void process_watch_events(XenXenstoreState *s) deliver_watch(s, ev->path, ev->token); =20 s->watch_events =3D g_list_remove(s->watch_events, ev); - g_free(ev->path); - g_free(ev->token); - g_free(ev); + free_watch_event(ev); } =20 static void xen_xenstore_event(void *opaque) @@ -1443,3 +1454,257 @@ int xen_xenstore_reset(void) =20 return 0; } + +struct qemu_xs_handle { + XenstoreImplState *impl; + GList *watches; + QEMUBH *watch_bh; +}; + +struct qemu_xs_watch { + struct qemu_xs_handle *h; + char *path; + xs_watch_fn fn; + void *opaque; + GList *events; +}; + +static char *xs_be_get_domain_path(struct qemu_xs_handle *h, unsigned int = domid) +{ + return g_strdup_printf("/local/domain/%u", domid); +} + +static char **xs_be_directory(struct qemu_xs_handle *h, xs_transaction_t t, + const char *path, unsigned int *num) +{ + GList *items =3D NULL, *l; + unsigned int i =3D 0; + char **items_ret; + int err; + + err =3D xs_impl_directory(h->impl, DOMID_QEMU, t, path, NULL, &items); + if (err) { + errno =3D err; + return NULL; + } + + items_ret =3D g_new0(char *, g_list_length(items) + 1); + *num =3D 0; + for (l =3D items; l; l =3D l->next) { + items_ret[i++] =3D l->data; + (*num)++; + } + g_list_free(items); + return items_ret; +} + +static void *xs_be_read(struct qemu_xs_handle *h, xs_transaction_t t, + const char *path, unsigned int *len) +{ + GByteArray *data =3D g_byte_array_new(); + bool free_segment =3D false; + int err; + + err =3D xs_impl_read(h->impl, DOMID_QEMU, t, path, data); + if (err) { + free_segment =3D true; + errno =3D err; + } else { + if (len) { + *len =3D data->len; + } + /* The xen-bus-helper code expects to get NUL terminated string! */ + g_byte_array_append(data, (void *)"", 1); + } + + return g_byte_array_free(data, free_segment); +} + +static bool xs_be_write(struct qemu_xs_handle *h, xs_transaction_t t, + const char *path, const void *data, unsigned int l= en) +{ + GByteArray *gdata =3D g_byte_array_new(); + int err; + + g_byte_array_append(gdata, data, len); + err =3D xs_impl_write(h->impl, DOMID_QEMU, t, path, gdata); + g_byte_array_unref(gdata); + if (err) { + errno =3D err; + return false; + } + return true; +} + +static bool xs_be_create(struct qemu_xs_handle *h, xs_transaction_t t, + unsigned int owner, unsigned int domid, + unsigned int perms, const char *path) +{ + g_autoptr(GByteArray) data =3D g_byte_array_new(); + GList *perms_list =3D NULL; + int err; + + /* mkdir does this */ + err =3D xs_impl_read(h->impl, DOMID_QEMU, t, path, data); + if (err =3D=3D ENOENT) { + err =3D xs_impl_write(h->impl, DOMID_QEMU, t, path, data); + } + if (err) { + errno =3D err; + return false; + } + + perms_list =3D g_list_append(perms_list, + xs_perm_as_string(XS_PERM_NONE, owner)); + perms_list =3D g_list_append(perms_list, + xs_perm_as_string(perms, domid)); + + err =3D xs_impl_set_perms(h->impl, DOMID_QEMU, t, path, perms_list); + g_list_free_full(perms_list, g_free); + if (err) { + errno =3D err; + return false; + } + return true; +} + +static bool xs_be_destroy(struct qemu_xs_handle *h, xs_transaction_t t, + const char *path) +{ + int err =3D xs_impl_rm(h->impl, DOMID_QEMU, t, path); + if (err) { + errno =3D err; + return false; + } + return true; +} + +static void be_watch_bh(void *_h) +{ + struct qemu_xs_handle *h =3D _h; + GList *l; + + for (l =3D h->watches; l; l =3D l->next) { + struct qemu_xs_watch *w =3D l->data; + + while (w->events) { + struct watch_event *ev =3D w->events->data; + + w->fn(w->opaque, ev->path); + + w->events =3D g_list_remove(w->events, ev); + free_watch_event(ev); + } + } +} + +static void xs_be_watch_cb(void *opaque, const char *path, const char *tok= en) +{ + struct watch_event *ev =3D g_new0(struct watch_event, 1); + struct qemu_xs_watch *w =3D opaque; + + /* We don't care about the token */ + ev->path =3D g_strdup(path); + w->events =3D g_list_append(w->events, ev); + + qemu_bh_schedule(w->h->watch_bh); +} + +static struct qemu_xs_watch *xs_be_watch(struct qemu_xs_handle *h, + const char *path, xs_watch_fn fn, + void *opaque) +{ + struct qemu_xs_watch *w =3D g_new0(struct qemu_xs_watch, 1); + int err; + + w->h =3D h; + w->fn =3D fn; + w->opaque =3D opaque; + + err =3D xs_impl_watch(h->impl, DOMID_QEMU, path, NULL, xs_be_watch_cb,= w); + if (err) { + errno =3D err; + g_free(w); + return NULL; + } + + w->path =3D g_strdup(path); + h->watches =3D g_list_append(h->watches, w); + return w; +} + +static void xs_be_unwatch(struct qemu_xs_handle *h, struct qemu_xs_watch *= w) +{ + xs_impl_unwatch(h->impl, DOMID_QEMU, w->path, NULL, xs_be_watch_cb, w); + + h->watches =3D g_list_remove(h->watches, w); + g_list_free_full(w->events, (GDestroyNotify)free_watch_event); + g_free(w->path); + g_free(w); +} + +static xs_transaction_t xs_be_transaction_start(struct qemu_xs_handle *h) +{ + unsigned int new_tx =3D XBT_NULL; + int err =3D xs_impl_transaction_start(h->impl, DOMID_QEMU, &new_tx); + if (err) { + errno =3D err; + return XBT_NULL; + } + return new_tx; +} + +static bool xs_be_transaction_end(struct qemu_xs_handle *h, xs_transaction= _t t, + bool abort) +{ + int err =3D xs_impl_transaction_end(h->impl, DOMID_QEMU, t, !abort); + if (err) { + errno =3D err; + return false; + } + return true; +} + +static struct qemu_xs_handle *xs_be_open(void) +{ + XenXenstoreState *s =3D xen_xenstore_singleton; + struct qemu_xs_handle *h; + + if (!s && !s->impl) { + errno =3D -ENOSYS; + return NULL; + } + + h =3D g_new0(struct qemu_xs_handle, 1); + h->impl =3D s->impl; + + h->watch_bh =3D aio_bh_new(qemu_get_aio_context(), be_watch_bh, h); + + return h; +} + +static void xs_be_close(struct qemu_xs_handle *h) +{ + while (h->watches) { + struct qemu_xs_watch *w =3D h->watches->data; + xs_be_unwatch(h, w); + } + + qemu_bh_delete(h->watch_bh); + g_free(h); +} + +static struct xenstore_backend_ops emu_xenstore_backend_ops =3D { + .open =3D xs_be_open, + .close =3D xs_be_close, + .get_domain_path =3D xs_be_get_domain_path, + .directory =3D xs_be_directory, + .read =3D xs_be_read, + .write =3D xs_be_write, + .create =3D xs_be_create, + .destroy =3D xs_be_destroy, + .watch =3D xs_be_watch, + .unwatch =3D xs_be_unwatch, + .transaction_start =3D xs_be_transaction_start, + .transaction_end =3D xs_be_transaction_end, +}; --=20 2.39.0