From patchwork Mon Dec 17 11:40:31 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 1014434 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=citrix.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 43JKFB3m1Nz9s2P for ; Mon, 17 Dec 2018 22:49:18 +1100 (AEDT) Received: from localhost ([::1]:46197 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrOe-0001gN-5f for incoming@patchwork.ozlabs.org; Mon, 17 Dec 2018 06:49:16 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:53099) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrH3-0004WU-Sz for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:41:33 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gYrGw-00070l-Ny for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:41:25 -0500 Received: from smtp03.citrix.com ([162.221.156.55]:44686) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gYrGd-0006Yx-QE; Mon, 17 Dec 2018 06:41:00 -0500 X-IronPort-AV: E=Sophos;i="5.56,365,1539648000"; d="scan'208";a="73532598" From: Paul Durrant To: , , Date: Mon, 17 Dec 2018 11:40:31 +0000 Message-ID: <1545046848-14891-2-git-send-email-paul.durrant@citrix.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> References: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 162.221.156.55 Subject: [Qemu-devel] [PATCH v5 01/18] xen: re-name XenDevice to XenLegacyDevice... X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Stefano Stabellini , Eduardo Habkost , "Michael S. Tsirkin" , Jason Wang , Greg Kurz , Max Reitz , Paul Durrant , Gerd Hoffmann , Paolo Bonzini , =?utf-8?q?M?= =?utf-8?q?arc-Andr=C3=A9_Lureau?= , Richard Henderson Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" ...and xen_backend.h to xen-legacy-backend.h Rather than attempting to convert the existing backend infrastructure to be QOM compliant (which would be hard to do in an incremental fashion), subsequent patches will introduce a completely new framework for Xen PV backends. Hence it is necessary to re-name parts of existing code to avoid name clashes. The re-named 'legacy' infrastructure will be removed once all backends have been ported to the new framework. This patch is purely cosmetic. No functional change. Signed-off-by: Paul Durrant Acked-by: Anthony Perard --- Cc: Stefano Stabellini Cc: Greg Kurz Cc: Kevin Wolf Cc: Max Reitz Cc: "Marc-André Lureau" Cc: Paolo Bonzini Cc: Richard Henderson Cc: Eduardo Habkost Cc: "Michael S. Tsirkin" Cc: Marcel Apfelbaum Cc: Jason Wang Cc: Gerd Hoffmann --- hw/9pfs/xen-9p-backend.c | 16 +- hw/block/xen_disk.c | 24 +- hw/char/xen_console.c | 12 +- hw/display/xenfb.c | 25 +- hw/i386/xen/xen-hvm.c | 2 +- hw/i386/xen/xen-mapcache.c | 2 +- hw/i386/xen/xen_platform.c | 2 +- hw/net/xen_nic.c | 14 +- hw/usb/xen-usb.c | 25 +- hw/xen/Makefile.objs | 2 +- hw/xen/xen-common.c | 2 +- hw/xen/xen-legacy-backend.c | 854 ++++++++++++++++++++++++++++++++++++ hw/xen/xen_backend.c | 845 ----------------------------------- hw/xen/xen_devconfig.c | 2 +- hw/xen/xen_pt.c | 2 +- hw/xen/xen_pt_config_init.c | 2 +- hw/xen/xen_pt_graphics.c | 2 +- hw/xen/xen_pt_msi.c | 2 +- hw/xen/xen_pvdev.c | 20 +- hw/xenpv/xen_domainbuild.c | 2 +- hw/xenpv/xen_machine_pv.c | 2 +- include/hw/xen/xen-legacy-backend.h | 104 +++++ include/hw/xen/xen_backend.h | 99 ----- include/hw/xen/xen_pvdev.h | 38 +- 24 files changed, 1059 insertions(+), 1041 deletions(-) create mode 100644 hw/xen/xen-legacy-backend.c delete mode 100644 hw/xen/xen_backend.c create mode 100644 include/hw/xen/xen-legacy-backend.h delete mode 100644 include/hw/xen/xen_backend.h diff --git a/hw/9pfs/xen-9p-backend.c b/hw/9pfs/xen-9p-backend.c index 3f54a21..3859a06 100644 --- a/hw/9pfs/xen-9p-backend.c +++ b/hw/9pfs/xen-9p-backend.c @@ -12,7 +12,7 @@ #include "hw/hw.h" #include "hw/9pfs/9p.h" -#include "hw/xen/xen_backend.h" +#include "hw/xen/xen-legacy-backend.h" #include "hw/9pfs/xen-9pfs.h" #include "qapi/error.h" #include "qemu/config-file.h" @@ -45,7 +45,7 @@ typedef struct Xen9pfsRing { } Xen9pfsRing; typedef struct Xen9pfsDev { - struct XenDevice xendev; /* must be first */ + struct XenLegacyDevice xendev; /* must be first */ V9fsState state; char *path; char *security_model; @@ -56,7 +56,7 @@ typedef struct Xen9pfsDev { Xen9pfsRing *rings; } Xen9pfsDev; -static void xen_9pfs_disconnect(struct XenDevice *xendev); +static void xen_9pfs_disconnect(struct XenLegacyDevice *xendev); static void xen_9pfs_in_sg(Xen9pfsRing *ring, struct iovec *in_sg, @@ -243,7 +243,7 @@ static const V9fsTransport xen_9p_transport = { .push_and_notify = xen_9pfs_push_and_notify, }; -static int xen_9pfs_init(struct XenDevice *xendev) +static int xen_9pfs_init(struct XenLegacyDevice *xendev) { return 0; } @@ -305,7 +305,7 @@ static void xen_9pfs_evtchn_event(void *opaque) qemu_bh_schedule(ring->bh); } -static void xen_9pfs_disconnect(struct XenDevice *xendev) +static void xen_9pfs_disconnect(struct XenLegacyDevice *xendev) { Xen9pfsDev *xen_9pdev = container_of(xendev, Xen9pfsDev, xendev); int i; @@ -321,7 +321,7 @@ static void xen_9pfs_disconnect(struct XenDevice *xendev) } } -static int xen_9pfs_free(struct XenDevice *xendev) +static int xen_9pfs_free(struct XenLegacyDevice *xendev) { Xen9pfsDev *xen_9pdev = container_of(xendev, Xen9pfsDev, xendev); int i; @@ -354,7 +354,7 @@ static int xen_9pfs_free(struct XenDevice *xendev) return 0; } -static int xen_9pfs_connect(struct XenDevice *xendev) +static int xen_9pfs_connect(struct XenLegacyDevice *xendev) { Error *err = NULL; int i; @@ -467,7 +467,7 @@ out: return -1; } -static void xen_9pfs_alloc(struct XenDevice *xendev) +static void xen_9pfs_alloc(struct XenLegacyDevice *xendev) { xenstore_write_be_str(xendev, "versions", VERSIONS); xenstore_write_be_int(xendev, "max-rings", MAX_RINGS); diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c index 36eff94..75fe55f 100644 --- a/hw/block/xen_disk.c +++ b/hw/block/xen_disk.c @@ -25,7 +25,7 @@ #include #include "hw/hw.h" -#include "hw/xen/xen_backend.h" +#include "hw/xen/xen-legacy-backend.h" #include "xen_blkif.h" #include "sysemu/blockdev.h" #include "sysemu/iothread.h" @@ -63,7 +63,7 @@ struct ioreq { #define MAX_RING_PAGE_ORDER 4 struct XenBlkDev { - struct XenDevice xendev; /* must be first */ + struct XenLegacyDevice xendev; /* must be first */ char *params; char *mode; char *type; @@ -179,7 +179,7 @@ static void ioreq_release(struct ioreq *ioreq, bool finish) static int ioreq_parse(struct ioreq *ioreq) { struct XenBlkDev *blkdev = ioreq->blkdev; - struct XenDevice *xendev = &blkdev->xendev; + struct XenLegacyDevice *xendev = &blkdev->xendev; size_t len; int i; @@ -243,7 +243,7 @@ err: static int ioreq_grant_copy(struct ioreq *ioreq) { struct XenBlkDev *blkdev = ioreq->blkdev; - struct XenDevice *xendev = &blkdev->xendev; + struct XenLegacyDevice *xendev = &blkdev->xendev; XenGrantCopySegment segs[BLKIF_MAX_SEGMENTS_PER_REQUEST]; int i, count, rc; int64_t file_blk = blkdev->file_blk; @@ -289,7 +289,7 @@ static void qemu_aio_complete(void *opaque, int ret) { struct ioreq *ioreq = opaque; struct XenBlkDev *blkdev = ioreq->blkdev; - struct XenDevice *xendev = &blkdev->xendev; + struct XenLegacyDevice *xendev = &blkdev->xendev; aio_context_acquire(blkdev->ctx); @@ -608,7 +608,7 @@ static void blk_bh(void *opaque) aio_context_release(blkdev->ctx); } -static void blk_alloc(struct XenDevice *xendev) +static void blk_alloc(struct XenLegacyDevice *xendev) { struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); Error *err = NULL; @@ -628,7 +628,7 @@ static void blk_alloc(struct XenDevice *xendev) static void blk_parse_discard(struct XenBlkDev *blkdev) { - struct XenDevice *xendev = &blkdev->xendev; + struct XenLegacyDevice *xendev = &blkdev->xendev; int enable; blkdev->feature_discard = true; @@ -642,7 +642,7 @@ static void blk_parse_discard(struct XenBlkDev *blkdev) } } -static int blk_init(struct XenDevice *xendev) +static int blk_init(struct XenLegacyDevice *xendev) { struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); int info = 0; @@ -737,7 +737,7 @@ out_error: return -1; } -static int blk_connect(struct XenDevice *xendev) +static int blk_connect(struct XenLegacyDevice *xendev) { struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); int index, qflags; @@ -941,7 +941,7 @@ static int blk_connect(struct XenDevice *xendev) return 0; } -static void blk_disconnect(struct XenDevice *xendev) +static void blk_disconnect(struct XenLegacyDevice *xendev) { struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); @@ -966,7 +966,7 @@ static void blk_disconnect(struct XenDevice *xendev) } } -static int blk_free(struct XenDevice *xendev) +static int blk_free(struct XenLegacyDevice *xendev) { struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); struct ioreq *ioreq; @@ -992,7 +992,7 @@ static int blk_free(struct XenDevice *xendev) return 0; } -static void blk_event(struct XenDevice *xendev) +static void blk_event(struct XenLegacyDevice *xendev) { struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); diff --git a/hw/char/xen_console.c b/hw/char/xen_console.c index 44f7236..460adc1 100644 --- a/hw/char/xen_console.c +++ b/hw/char/xen_console.c @@ -26,7 +26,7 @@ #include "qapi/error.h" #include "hw/hw.h" #include "chardev/char-fe.h" -#include "hw/xen/xen_backend.h" +#include "hw/xen/xen-legacy-backend.h" #include @@ -39,7 +39,7 @@ struct buffer { }; struct XenConsole { - struct XenDevice xendev; /* must be first */ + struct XenLegacyDevice xendev; /* must be first */ struct buffer buffer; char console[XEN_BUFSIZE]; int ring_ref; @@ -173,7 +173,7 @@ static void xencons_send(struct XenConsole *con) /* -------------------------------------------------------------------- */ -static int con_init(struct XenDevice *xendev) +static int con_init(struct XenLegacyDevice *xendev) { struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); char *type, *dom, label[32]; @@ -222,7 +222,7 @@ out: return ret; } -static int con_initialise(struct XenDevice *xendev) +static int con_initialise(struct XenLegacyDevice *xendev) { struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); int limit; @@ -259,7 +259,7 @@ static int con_initialise(struct XenDevice *xendev) return 0; } -static void con_disconnect(struct XenDevice *xendev) +static void con_disconnect(struct XenLegacyDevice *xendev) { struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); @@ -276,7 +276,7 @@ static void con_disconnect(struct XenDevice *xendev) } } -static void con_event(struct XenDevice *xendev) +static void con_event(struct XenLegacyDevice *xendev) { struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c index 0330dc6..6202f11 100644 --- a/hw/display/xenfb.c +++ b/hw/display/xenfb.c @@ -30,7 +30,7 @@ #include "hw/hw.h" #include "ui/input.h" #include "ui/console.h" -#include "hw/xen/xen_backend.h" +#include "hw/xen/xen-legacy-backend.h" #include #include @@ -46,7 +46,7 @@ /* -------------------------------------------------------------------- */ struct common { - struct XenDevice xendev; /* must be first */ + struct XenLegacyDevice xendev; /* must be first */ void *page; }; @@ -342,14 +342,14 @@ static QemuInputHandler xenfb_rel_mouse = { .sync = xenfb_mouse_sync, }; -static int input_init(struct XenDevice *xendev) +static int input_init(struct XenLegacyDevice *xendev) { xenstore_write_be_int(xendev, "feature-abs-pointer", 1); xenstore_write_be_int(xendev, "feature-raw-pointer", 1); return 0; } -static int input_initialise(struct XenDevice *xendev) +static int input_initialise(struct XenLegacyDevice *xendev) { struct XenInput *in = container_of(xendev, struct XenInput, c.xendev); int rc; @@ -361,7 +361,7 @@ static int input_initialise(struct XenDevice *xendev) return 0; } -static void input_connected(struct XenDevice *xendev) +static void input_connected(struct XenLegacyDevice *xendev) { struct XenInput *in = container_of(xendev, struct XenInput, c.xendev); @@ -395,7 +395,7 @@ static void input_connected(struct XenDevice *xendev) } } -static void input_disconnect(struct XenDevice *xendev) +static void input_disconnect(struct XenLegacyDevice *xendev) { struct XenInput *in = container_of(xendev, struct XenInput, c.xendev); @@ -410,7 +410,7 @@ static void input_disconnect(struct XenDevice *xendev) common_unbind(&in->c); } -static void input_event(struct XenDevice *xendev) +static void input_event(struct XenLegacyDevice *xendev) { struct XenInput *xenfb = container_of(xendev, struct XenInput, c.xendev); struct xenkbd_page *page = xenfb->c.page; @@ -867,7 +867,7 @@ static void xenfb_handle_events(struct XenFB *xenfb) page->out_cons = cons; } -static int fb_init(struct XenDevice *xendev) +static int fb_init(struct XenLegacyDevice *xendev) { #ifdef XENFB_TYPE_RESIZE xenstore_write_be_int(xendev, "feature-resize", 1); @@ -875,7 +875,7 @@ static int fb_init(struct XenDevice *xendev) return 0; } -static int fb_initialise(struct XenDevice *xendev) +static int fb_initialise(struct XenLegacyDevice *xendev) { struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev); struct xenfb_page *fb_page; @@ -912,7 +912,7 @@ static int fb_initialise(struct XenDevice *xendev) return 0; } -static void fb_disconnect(struct XenDevice *xendev) +static void fb_disconnect(struct XenLegacyDevice *xendev) { struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev); @@ -935,7 +935,8 @@ static void fb_disconnect(struct XenDevice *xendev) fb->bug_trigger = 0; } -static void fb_frontend_changed(struct XenDevice *xendev, const char *node) +static void fb_frontend_changed(struct XenLegacyDevice *xendev, + const char *node) { struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev); @@ -953,7 +954,7 @@ static void fb_frontend_changed(struct XenDevice *xendev, const char *node) } } -static void fb_event(struct XenDevice *xendev) +static void fb_event(struct XenLegacyDevice *xendev) { struct XenFB *xenfb = container_of(xendev, struct XenFB, c.xendev); diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c index 935a367..1d63763 100644 --- a/hw/i386/xen/xen-hvm.c +++ b/hw/i386/xen/xen-hvm.c @@ -16,7 +16,7 @@ #include "hw/i386/pc.h" #include "hw/i386/apic-msidef.h" #include "hw/xen/xen_common.h" -#include "hw/xen/xen_backend.h" +#include "hw/xen/xen-legacy-backend.h" #include "qapi/error.h" #include "qapi/qapi-commands-misc.h" #include "qemu/error-report.h" diff --git a/hw/i386/xen/xen-mapcache.c b/hw/i386/xen/xen-mapcache.c index 4e4f069..9134a7b 100644 --- a/hw/i386/xen/xen-mapcache.c +++ b/hw/i386/xen/xen-mapcache.c @@ -14,7 +14,7 @@ #include -#include "hw/xen/xen_backend.h" +#include "hw/xen/xen-legacy-backend.h" #include "qemu/bitmap.h" #include diff --git a/hw/i386/xen/xen_platform.c b/hw/i386/xen/xen_platform.c index deb7a0c..16afb54 100644 --- a/hw/i386/xen/xen_platform.c +++ b/hw/i386/xen/xen_platform.c @@ -30,7 +30,7 @@ #include "hw/pci/pci.h" #include "hw/irq.h" #include "hw/xen/xen_common.h" -#include "hw/xen/xen_backend.h" +#include "hw/xen/xen-legacy-backend.h" #include "trace.h" #include "exec/address-spaces.h" #include "sysemu/block-backend.h" diff --git a/hw/net/xen_nic.c b/hw/net/xen_nic.c index 46a8dbf..37cda8e 100644 --- a/hw/net/xen_nic.c +++ b/hw/net/xen_nic.c @@ -28,14 +28,14 @@ #include "net/net.h" #include "net/checksum.h" #include "net/util.h" -#include "hw/xen/xen_backend.h" +#include "hw/xen/xen-legacy-backend.h" #include /* ------------------------------------------------------------- */ struct XenNetDev { - struct XenDevice xendev; /* must be first */ + struct XenLegacyDevice xendev; /* must be first */ char *mac; int tx_work; int tx_ring_ref; @@ -276,7 +276,7 @@ static NetClientInfo net_xen_info = { .receive = net_rx_packet, }; -static int net_init(struct XenDevice *xendev) +static int net_init(struct XenLegacyDevice *xendev) { struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev); @@ -308,7 +308,7 @@ static int net_init(struct XenDevice *xendev) return 0; } -static int net_connect(struct XenDevice *xendev) +static int net_connect(struct XenLegacyDevice *xendev) { struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev); int rx_copy; @@ -363,7 +363,7 @@ static int net_connect(struct XenDevice *xendev) return 0; } -static void net_disconnect(struct XenDevice *xendev) +static void net_disconnect(struct XenLegacyDevice *xendev) { struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev); @@ -379,14 +379,14 @@ static void net_disconnect(struct XenDevice *xendev) } } -static void net_event(struct XenDevice *xendev) +static void net_event(struct XenLegacyDevice *xendev) { struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev); net_tx_packets(netdev); qemu_flush_queued_packets(qemu_get_queue(netdev->nic)); } -static int net_free(struct XenDevice *xendev) +static int net_free(struct XenLegacyDevice *xendev) { struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev); diff --git a/hw/usb/xen-usb.c b/hw/usb/xen-usb.c index 5b2e21e..9b2da6e 100644 --- a/hw/usb/xen-usb.c +++ b/hw/usb/xen-usb.c @@ -27,7 +27,7 @@ #include "qemu/option.h" #include "hw/sysbus.h" #include "hw/usb.h" -#include "hw/xen/xen_backend.h" +#include "hw/xen/xen-legacy-backend.h" #include "monitor/qdev.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qstring.h" @@ -99,7 +99,7 @@ struct usbback_hotplug { }; struct usbback_info { - struct XenDevice xendev; /* must be first */ + struct XenLegacyDevice xendev; /* must be first */ USBBus bus; void *urb_sring; void *conn_sring; @@ -142,7 +142,7 @@ static int usbback_gnttab_map(struct usbback_req *usbback_req) unsigned int nr_segs, i, prot; uint32_t ref[USBIF_MAX_SEGMENTS_PER_REQUEST]; struct usbback_info *usbif = usbback_req->usbif; - struct XenDevice *xendev = &usbif->xendev; + struct XenLegacyDevice *xendev = &usbif->xendev; struct usbif_request_segment *seg; void *addr; @@ -220,7 +220,7 @@ static int usbback_gnttab_map(struct usbback_req *usbback_req) static int usbback_init_packet(struct usbback_req *usbback_req) { - struct XenDevice *xendev = &usbback_req->usbif->xendev; + struct XenLegacyDevice *xendev = &usbback_req->usbif->xendev; USBPacket *packet = &usbback_req->packet; USBDevice *dev = usbback_req->stub->dev; USBEndpoint *ep; @@ -279,7 +279,7 @@ static void usbback_do_response(struct usbback_req *usbback_req, int32_t status, { struct usbback_info *usbif; struct usbif_urb_response *res; - struct XenDevice *xendev; + struct XenLegacyDevice *xendev; unsigned int notify; usbif = usbback_req->usbif; @@ -824,7 +824,7 @@ static void usbback_process_port(struct usbback_info *usbif, unsigned port) g_free(busid); } -static void usbback_disconnect(struct XenDevice *xendev) +static void usbback_disconnect(struct XenLegacyDevice *xendev) { struct usbback_info *usbif; unsigned int i; @@ -853,7 +853,7 @@ static void usbback_disconnect(struct XenDevice *xendev) TR_BUS(xendev, "finished\n"); } -static int usbback_connect(struct XenDevice *xendev) +static int usbback_connect(struct XenLegacyDevice *xendev) { struct usbback_info *usbif; struct usbif_urb_sring *urb_sring; @@ -909,7 +909,8 @@ static int usbback_connect(struct XenDevice *xendev) return 0; } -static void usbback_backend_changed(struct XenDevice *xendev, const char *node) +static void usbback_backend_changed(struct XenLegacyDevice *xendev, + const char *node) { struct usbback_info *usbif; unsigned int i; @@ -922,7 +923,7 @@ static void usbback_backend_changed(struct XenDevice *xendev, const char *node) } } -static int usbback_init(struct XenDevice *xendev) +static int usbback_init(struct XenLegacyDevice *xendev) { struct usbback_info *usbif; @@ -1001,7 +1002,7 @@ static USBPortOps xen_usb_port_ops = { static USBBusOps xen_usb_bus_ops = { }; -static void usbback_alloc(struct XenDevice *xendev) +static void usbback_alloc(struct XenLegacyDevice *xendev) { struct usbback_info *usbif; USBPort *p; @@ -1027,7 +1028,7 @@ static void usbback_alloc(struct XenDevice *xendev) xen_be_set_max_grant_refs(xendev, max_grants); } -static int usbback_free(struct XenDevice *xendev) +static int usbback_free(struct XenLegacyDevice *xendev) { struct usbback_info *usbif; struct usbback_req *usbback_req; @@ -1066,7 +1067,7 @@ static int usbback_free(struct XenDevice *xendev) return 0; } -static void usbback_event(struct XenDevice *xendev) +static void usbback_event(struct XenLegacyDevice *xendev) { struct usbback_info *usbif; diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs index 9ea5c73..3f64a44 100644 --- a/hw/xen/Makefile.objs +++ b/hw/xen/Makefile.objs @@ -1,5 +1,5 @@ # xen backend driver support -common-obj-$(CONFIG_XEN) += xen_backend.o xen_devconfig.o xen_pvdev.o xen-common.o +common-obj-$(CONFIG_XEN) += xen-legacy-backend.o xen_devconfig.o xen_pvdev.o xen-common.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_graphics.o xen_pt_msi.o diff --git a/hw/xen/xen-common.c b/hw/xen/xen-common.c index 6ec14c7..ef130b2 100644 --- a/hw/xen/xen-common.c +++ b/hw/xen/xen-common.c @@ -10,7 +10,7 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" -#include "hw/xen/xen_backend.h" +#include "hw/xen/xen-legacy-backend.h" #include "chardev/char.h" #include "sysemu/accel.h" #include "migration/misc.h" diff --git a/hw/xen/xen-legacy-backend.c b/hw/xen/xen-legacy-backend.c new file mode 100644 index 0000000..0c26023 --- /dev/null +++ b/hw/xen/xen-legacy-backend.c @@ -0,0 +1,854 @@ +/* + * xen backend driver infrastructure + * (c) 2008 Gerd Hoffmann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +/* + * TODO: add some xenbus / xenstore concepts overview here. + */ + +#include "qemu/osdep.h" +#include + +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/boards.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "hw/xen/xen-legacy-backend.h" +#include "hw/xen/xen_pvdev.h" +#include "monitor/qdev.h" + +#include + +DeviceState *xen_sysdev; +BusState *xen_sysbus; + +/* ------------------------------------------------------------- */ + +/* public */ +struct xs_handle *xenstore; +const char *xen_protocol; + +/* private */ +static bool xen_feature_grant_copy; +static int debug; + +int xenstore_write_be_str(struct XenLegacyDevice *xendev, const char *node, + const char *val) +{ + return xenstore_write_str(xendev->be, node, val); +} + +int xenstore_write_be_int(struct XenLegacyDevice *xendev, const char *node, + int ival) +{ + return xenstore_write_int(xendev->be, node, ival); +} + +int xenstore_write_be_int64(struct XenLegacyDevice *xendev, const char *node, + int64_t ival) +{ + return xenstore_write_int64(xendev->be, node, ival); +} + +char *xenstore_read_be_str(struct XenLegacyDevice *xendev, const char *node) +{ + return xenstore_read_str(xendev->be, node); +} + +int xenstore_read_be_int(struct XenLegacyDevice *xendev, const char *node, + int *ival) +{ + return xenstore_read_int(xendev->be, node, ival); +} + +char *xenstore_read_fe_str(struct XenLegacyDevice *xendev, const char *node) +{ + return xenstore_read_str(xendev->fe, node); +} + +int xenstore_read_fe_int(struct XenLegacyDevice *xendev, const char *node, + int *ival) +{ + return xenstore_read_int(xendev->fe, node, ival); +} + +int xenstore_read_fe_uint64(struct XenLegacyDevice *xendev, const char *node, + uint64_t *uval) +{ + return xenstore_read_uint64(xendev->fe, node, uval); +} + +/* ------------------------------------------------------------- */ + +int xen_be_set_state(struct XenLegacyDevice *xendev, enum xenbus_state state) +{ + int rc; + + rc = xenstore_write_be_int(xendev, "state", state); + if (rc < 0) { + return rc; + } + xen_pv_printf(xendev, 1, "backend state: %s -> %s\n", + xenbus_strstate(xendev->be_state), xenbus_strstate(state)); + xendev->be_state = state; + return 0; +} + +void xen_be_set_max_grant_refs(struct XenLegacyDevice *xendev, + unsigned int nr_refs) +{ + assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV); + + if (xengnttab_set_max_grants(xendev->gnttabdev, nr_refs)) { + xen_pv_printf(xendev, 0, "xengnttab_set_max_grants failed: %s\n", + strerror(errno)); + } +} + +void *xen_be_map_grant_refs(struct XenLegacyDevice *xendev, uint32_t *refs, + unsigned int nr_refs, int prot) +{ + void *ptr; + + assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV); + + ptr = xengnttab_map_domain_grant_refs(xendev->gnttabdev, nr_refs, + xen_domid, refs, prot); + if (!ptr) { + xen_pv_printf(xendev, 0, + "xengnttab_map_domain_grant_refs failed: %s\n", + strerror(errno)); + } + + return ptr; +} + +void xen_be_unmap_grant_refs(struct XenLegacyDevice *xendev, void *ptr, + unsigned int nr_refs) +{ + assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV); + + if (xengnttab_unmap(xendev->gnttabdev, ptr, nr_refs)) { + xen_pv_printf(xendev, 0, "xengnttab_unmap failed: %s\n", + strerror(errno)); + } +} + +static int compat_copy_grant_refs(struct XenLegacyDevice *xendev, + bool to_domain, + XenGrantCopySegment segs[], + unsigned int nr_segs) +{ + uint32_t *refs = g_new(uint32_t, nr_segs); + int prot = to_domain ? PROT_WRITE : PROT_READ; + void *pages; + unsigned int i; + + for (i = 0; i < nr_segs; i++) { + XenGrantCopySegment *seg = &segs[i]; + + refs[i] = to_domain ? + seg->dest.foreign.ref : seg->source.foreign.ref; + } + + pages = 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 = 0; i < nr_segs; i++) { + XenGrantCopySegment *seg = &segs[i]; + void *page = 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; + + assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV); + + if (!xen_feature_grant_copy) { + return compat_copy_grant_refs(xendev, to_domain, segs, nr_segs); + } + + xengnttab_segs = g_new0(xengnttab_grant_copy_segment_t, nr_segs); + + for (i = 0; i < nr_segs; i++) { + XenGrantCopySegment *seg = &segs[i]; + xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i]; + + if (to_domain) { + xengnttab_seg->flags = GNTCOPY_dest_gref; + xengnttab_seg->dest.foreign.domid = xen_domid; + xengnttab_seg->dest.foreign.ref = seg->dest.foreign.ref; + xengnttab_seg->dest.foreign.offset = seg->dest.foreign.offset; + xengnttab_seg->source.virt = seg->source.virt; + } else { + xengnttab_seg->flags = GNTCOPY_source_gref; + xengnttab_seg->source.foreign.domid = xen_domid; + xengnttab_seg->source.foreign.ref = seg->source.foreign.ref; + xengnttab_seg->source.foreign.offset = + seg->source.foreign.offset; + xengnttab_seg->dest.virt = seg->dest.virt; + } + + xengnttab_seg->len = seg->len; + } + + rc = xengnttab_grant_copy(xendev->gnttabdev, nr_segs, xengnttab_segs); + + if (rc) { + xen_pv_printf(xendev, 0, "xengnttab_copy failed: %s\n", + strerror(errno)); + } + + for (i = 0; i < nr_segs; i++) { + xengnttab_grant_copy_segment_t *xengnttab_seg = + &xengnttab_segs[i]; + + if (xengnttab_seg->status != GNTST_okay) { + xen_pv_printf(xendev, 0, "segment[%u] status: %d\n", i, + xengnttab_seg->status); + rc = -1; + } + } + + g_free(xengnttab_segs); + return rc; +} + +/* + * get xen backend device, allocate a new one if it doesn't exist. + */ +static struct XenLegacyDevice *xen_be_get_xendev(const char *type, int dom, + int dev, + struct XenDevOps *ops) +{ + struct XenLegacyDevice *xendev; + + xendev = xen_pv_find_xendev(type, dom, dev); + if (xendev) { + return xendev; + } + + /* init new xendev */ + xendev = g_malloc0(ops->size); + object_initialize(&xendev->qdev, ops->size, TYPE_XENBACKEND); + OBJECT(xendev)->free = g_free; + qdev_set_parent_bus(DEVICE(xendev), xen_sysbus); + qdev_set_id(DEVICE(xendev), g_strdup_printf("xen-%s-%d", type, dev)); + qdev_init_nofail(DEVICE(xendev)); + object_unref(OBJECT(xendev)); + + xendev->type = type; + xendev->dom = dom; + xendev->dev = dev; + xendev->ops = ops; + + snprintf(xendev->be, sizeof(xendev->be), "backend/%s/%d/%d", + xendev->type, xendev->dom, xendev->dev); + snprintf(xendev->name, sizeof(xendev->name), "%s-%d", + xendev->type, xendev->dev); + + xendev->debug = debug; + xendev->local_port = -1; + + xendev->evtchndev = xenevtchn_open(NULL, 0); + if (xendev->evtchndev == 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)); + + xen_pv_insert_xendev(xendev); + + if (xendev->ops->alloc) { + xendev->ops->alloc(xendev); + } + + return xendev; +} + + +/* + * Sync internal data structures on xenstore updates. + * Node specifies the changed field. node = NULL means + * update all fields (used for initialization). + */ +static void xen_be_backend_changed(struct XenLegacyDevice *xendev, + const char *node) +{ + if (node == NULL || strcmp(node, "online") == 0) { + if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1) { + xendev->online = 0; + } + } + + if (node) { + xen_pv_printf(xendev, 2, "backend update: %s\n", node); + if (xendev->ops->backend_changed) { + xendev->ops->backend_changed(xendev, node); + } + } +} + +static void xen_be_frontend_changed(struct XenLegacyDevice *xendev, + const char *node) +{ + int fe_state; + + if (node == NULL || strcmp(node, "state") == 0) { + if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) { + fe_state = XenbusStateUnknown; + } + if (xendev->fe_state != fe_state) { + xen_pv_printf(xendev, 1, "frontend state: %s -> %s\n", + xenbus_strstate(xendev->fe_state), + xenbus_strstate(fe_state)); + } + xendev->fe_state = fe_state; + } + if (node == NULL || strcmp(node, "protocol") == 0) { + g_free(xendev->protocol); + xendev->protocol = xenstore_read_fe_str(xendev, "protocol"); + if (xendev->protocol) { + xen_pv_printf(xendev, 1, "frontend protocol: %s\n", + xendev->protocol); + } + } + + if (node) { + xen_pv_printf(xendev, 2, "frontend update: %s\n", node); + if (xendev->ops->frontend_changed) { + xendev->ops->frontend_changed(xendev, node); + } + } +} + +/* ------------------------------------------------------------- */ +/* Check for possible state transitions and perform them. */ + +/* + * Initial xendev setup. Read frontend path, register watch for it. + * Should succeed once xend finished setting up the backend device. + * + * Also sets initial state (-> Initializing) when done. Which + * only affects the xendev->be_state variable as xenbus should + * already be put into that state by xend. + */ +static int xen_be_try_setup(struct XenLegacyDevice *xendev) +{ + char token[XEN_BUFSIZE]; + int be_state; + + if (xenstore_read_be_int(xendev, "state", &be_state) == -1) { + xen_pv_printf(xendev, 0, "reading backend state failed\n"); + return -1; + } + + if (be_state != XenbusStateInitialising) { + xen_pv_printf(xendev, 0, "initial backend state is wrong (%s)\n", + xenbus_strstate(be_state)); + return -1; + } + + xendev->fe = xenstore_read_be_str(xendev, "frontend"); + if (xendev->fe == NULL) { + xen_pv_printf(xendev, 0, "reading frontend path failed\n"); + return -1; + } + + /* setup frontend watch */ + snprintf(token, sizeof(token), "fe:%p", xendev); + if (!xs_watch(xenstore, xendev->fe, token)) { + xen_pv_printf(xendev, 0, "watching frontend path (%s) failed\n", + xendev->fe); + return -1; + } + xen_be_set_state(xendev, XenbusStateInitialising); + + xen_be_backend_changed(xendev, NULL); + xen_be_frontend_changed(xendev, NULL); + return 0; +} + +/* + * Try initialize xendev. Prepare everything the backend can do + * without synchronizing with the frontend. Fakes hotplug-status. No + * hotplug involved here because this is about userspace drivers, thus + * there are kernel backend devices which could invoke hotplug. + * + * Goes to InitWait on success. + */ +static int xen_be_try_init(struct XenLegacyDevice *xendev) +{ + int rc = 0; + + if (!xendev->online) { + xen_pv_printf(xendev, 1, "not online\n"); + return -1; + } + + if (xendev->ops->init) { + rc = xendev->ops->init(xendev); + } + if (rc != 0) { + xen_pv_printf(xendev, 1, "init() failed\n"); + return rc; + } + + xenstore_write_be_str(xendev, "hotplug-status", "connected"); + xen_be_set_state(xendev, XenbusStateInitWait); + return 0; +} + +/* + * Try to initialise xendev. Depends on the frontend being ready + * for it (shared ring and evtchn info in xenstore, state being + * Initialised or Connected). + * + * Goes to Connected on success. + */ +static int xen_be_try_initialise(struct XenLegacyDevice *xendev) +{ + int rc = 0; + + if (xendev->fe_state != XenbusStateInitialised && + xendev->fe_state != XenbusStateConnected) { + if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) { + xen_pv_printf(xendev, 2, "frontend not ready, ignoring\n"); + } else { + xen_pv_printf(xendev, 2, "frontend not ready (yet)\n"); + return -1; + } + } + + if (xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV) { + xendev->gnttabdev = xengnttab_open(NULL, 0); + if (xendev->gnttabdev == NULL) { + xen_pv_printf(NULL, 0, "can't open gnttab device\n"); + return -1; + } + } else { + xendev->gnttabdev = NULL; + } + + if (xendev->ops->initialise) { + rc = xendev->ops->initialise(xendev); + } + if (rc != 0) { + xen_pv_printf(xendev, 0, "initialise() failed\n"); + return rc; + } + + xen_be_set_state(xendev, XenbusStateConnected); + return 0; +} + +/* + * Try to let xendev know that it is connected. Depends on the + * frontend being Connected. Note that this may be called more + * than once since the backend state is not modified. + */ +static void xen_be_try_connected(struct XenLegacyDevice *xendev) +{ + if (!xendev->ops->connected) { + return; + } + + if (xendev->fe_state != XenbusStateConnected) { + if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) { + xen_pv_printf(xendev, 2, "frontend not ready, ignoring\n"); + } else { + xen_pv_printf(xendev, 2, "frontend not ready (yet)\n"); + return; + } + } + + xendev->ops->connected(xendev); +} + +/* + * Teardown connection. + * + * Goes to Closed when done. + */ +static void xen_be_disconnect(struct XenLegacyDevice *xendev, + enum xenbus_state state) +{ + if (xendev->be_state != XenbusStateClosing && + xendev->be_state != XenbusStateClosed && + xendev->ops->disconnect) { + xendev->ops->disconnect(xendev); + } + if (xendev->gnttabdev) { + xengnttab_close(xendev->gnttabdev); + xendev->gnttabdev = NULL; + } + if (xendev->be_state != state) { + xen_be_set_state(xendev, state); + } +} + +/* + * Try to reset xendev, for reconnection by another frontend instance. + */ +static int xen_be_try_reset(struct XenLegacyDevice *xendev) +{ + if (xendev->fe_state != XenbusStateInitialising) { + return -1; + } + + xen_pv_printf(xendev, 1, "device reset (for re-connect)\n"); + xen_be_set_state(xendev, XenbusStateInitialising); + return 0; +} + +/* + * state change dispatcher function + */ +void xen_be_check_state(struct XenLegacyDevice *xendev) +{ + int rc = 0; + + /* frontend may request shutdown from almost anywhere */ + if (xendev->fe_state == XenbusStateClosing || + xendev->fe_state == XenbusStateClosed) { + xen_be_disconnect(xendev, xendev->fe_state); + return; + } + + /* check for possible backend state transitions */ + for (;;) { + switch (xendev->be_state) { + case XenbusStateUnknown: + rc = xen_be_try_setup(xendev); + break; + case XenbusStateInitialising: + rc = xen_be_try_init(xendev); + break; + case XenbusStateInitWait: + rc = xen_be_try_initialise(xendev); + break; + case XenbusStateConnected: + /* xendev->be_state doesn't change */ + xen_be_try_connected(xendev); + rc = -1; + break; + case XenbusStateClosed: + rc = xen_be_try_reset(xendev); + break; + default: + rc = -1; + } + if (rc != 0) { + break; + } + } +} + +/* ------------------------------------------------------------- */ + +static int xenstore_scan(const char *type, int dom, struct XenDevOps *ops) +{ + struct XenLegacyDevice *xendev; + char path[XEN_BUFSIZE], token[XEN_BUFSIZE]; + char **dev = 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 = xs_directory(xenstore, 0, path, &cdev); + if (!dev) { + return 0; + } + for (j = 0; j < cdev; j++) { + xendev = xen_be_get_xendev(type, dom, atoi(dev[j]), ops); + if (xendev == NULL) { + continue; + } + xen_be_check_state(xendev); + } + free(dev); + return 0; +} + +void xenstore_update_be(char *watch, char *type, int dom, + struct XenDevOps *ops) +{ + struct XenLegacyDevice *xendev; + char path[XEN_BUFSIZE], *bepath; + unsigned int len, dev; + + len = snprintf(path, sizeof(path), "backend/%s/%d", type, dom); + if (strncmp(path, watch, len) != 0) { + return; + } + if (sscanf(watch + len, "/%u/%255s", &dev, path) != 2) { + strcpy(path, ""); + if (sscanf(watch + len, "/%u", &dev) != 1) { + dev = -1; + } + } + if (dev == -1) { + return; + } + + xendev = xen_be_get_xendev(type, dom, dev, ops); + if (xendev != NULL) { + bepath = xs_read(xenstore, 0, xendev->be, &len); + if (bepath == NULL) { + xen_pv_del_xendev(xendev); + } else { + free(bepath); + xen_be_backend_changed(xendev, path); + xen_be_check_state(xendev); + } + } +} + +void xenstore_update_fe(char *watch, struct XenLegacyDevice *xendev) +{ + char *node; + unsigned int len; + + len = strlen(xendev->fe); + if (strncmp(xendev->fe, watch, len) != 0) { + return; + } + if (watch[len] != '/') { + return; + } + node = watch + len + 1; + + xen_be_frontend_changed(xendev, node); + xen_be_check_state(xendev); +} +/* -------------------------------------------------------------------- */ + +int xen_be_init(void) +{ + xengnttab_handle *gnttabdev; + + xenstore = xs_daemon_open(); + if (!xenstore) { + xen_pv_printf(NULL, 0, "can't connect to xenstored\n"); + return -1; + } + + qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL); + + if (xen_xc == NULL || xen_fmem == NULL) { + /* Check if xen_init() have been called */ + goto err; + } + + gnttabdev = xengnttab_open(NULL, 0); + if (gnttabdev != NULL) { + if (xengnttab_grant_copy(gnttabdev, 0, NULL) == 0) { + xen_feature_grant_copy = true; + } + xengnttab_close(gnttabdev); + } + + xen_sysdev = qdev_create(NULL, TYPE_XENSYSDEV); + qdev_init_nofail(xen_sysdev); + xen_sysbus = qbus_create(TYPE_XENSYSBUS, DEVICE(xen_sysdev), "xen-sysbus"); + qbus_set_bus_hotplug_handler(xen_sysbus, &error_abort); + + return 0; + +err: + qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL); + xs_daemon_close(xenstore); + xenstore = NULL; + + return -1; +} + +static void xen_set_dynamic_sysbus(void) +{ + Object *machine = qdev_get_machine(); + ObjectClass *oc = object_get_class(machine); + MachineClass *mc = MACHINE_CLASS(oc); + + machine_class_allow_dynamic_sysbus_dev(mc, TYPE_XENSYSDEV); +} + +int xen_be_register(const char *type, struct XenDevOps *ops) +{ + char path[50]; + int rc; + + if (ops->backend_register) { + rc = ops->backend_register(); + if (rc) { + return rc; + } + } + + snprintf(path, sizeof(path), "device-model/%u/backends/%s", xen_domid, + type); + xenstore_mkdir(path, XS_PERM_NONE); + + return xenstore_scan(type, xen_domid, ops); +} + +void xen_be_register_common(void) +{ + xen_set_dynamic_sysbus(); + + xen_be_register("console", &xen_console_ops); + xen_be_register("vkbd", &xen_kbdmouse_ops); + xen_be_register("qdisk", &xen_blkdev_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 != -1) { + return 0; + } + xendev->local_port = xenevtchn_bind_interdomain + (xendev->evtchndev, xendev->dom, xendev->remote_port); + if (xendev->local_port == -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), + xen_pv_evtchn_event, NULL, xendev); + return 0; +} + + +static Property xendev_properties[] = { + DEFINE_PROP_END_OF_LIST(), +}; + +static void xendev_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->props = xendev_properties; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + /* xen-backend devices can be plugged/unplugged dynamically */ + dc->user_creatable = true; +} + +static const TypeInfo xendev_type_info = { + .name = TYPE_XENBACKEND, + .parent = TYPE_XENSYSDEV, + .class_init = xendev_class_init, + .instance_size = sizeof(struct XenLegacyDevice), +}; + +static void xen_sysbus_class_init(ObjectClass *klass, void *data) +{ + HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); + + hc->unplug = qdev_simple_device_unplug_cb; +} + +static const TypeInfo xensysbus_info = { + .name = TYPE_XENSYSBUS, + .parent = TYPE_BUS, + .class_init = xen_sysbus_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_HOTPLUG_HANDLER }, + { } + } +}; + +static int xen_sysdev_init(SysBusDevice *dev) +{ + return 0; +} + +static Property xen_sysdev_properties[] = { + {/* end of property list */}, +}; + +static void xen_sysdev_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = xen_sysdev_init; + dc->props = xen_sysdev_properties; + dc->bus_type = TYPE_XENSYSBUS; +} + +static const TypeInfo xensysdev_info = { + .name = TYPE_XENSYSDEV, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SysBusDevice), + .class_init = xen_sysdev_class_init, +}; + +static void xenbe_register_types(void) +{ + type_register_static(&xensysbus_info); + type_register_static(&xensysdev_info); + type_register_static(&xendev_type_info); +} + +type_init(xenbe_register_types) diff --git a/hw/xen/xen_backend.c b/hw/xen/xen_backend.c deleted file mode 100644 index 9a8e877..0000000 --- a/hw/xen/xen_backend.c +++ /dev/null @@ -1,845 +0,0 @@ -/* - * xen backend driver infrastructure - * (c) 2008 Gerd Hoffmann - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; under version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -/* - * TODO: add some xenbus / xenstore concepts overview here. - */ - -#include "qemu/osdep.h" -#include - -#include "hw/hw.h" -#include "hw/sysbus.h" -#include "hw/boards.h" -#include "qemu/log.h" -#include "qapi/error.h" -#include "hw/xen/xen_backend.h" -#include "hw/xen/xen_pvdev.h" -#include "monitor/qdev.h" - -#include - -DeviceState *xen_sysdev; -BusState *xen_sysbus; - -/* ------------------------------------------------------------- */ - -/* public */ -struct xs_handle *xenstore = NULL; -const char *xen_protocol; - -/* private */ -static bool xen_feature_grant_copy; -static int debug; - -int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val) -{ - return xenstore_write_str(xendev->be, node, val); -} - -int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival) -{ - return xenstore_write_int(xendev->be, node, ival); -} - -int xenstore_write_be_int64(struct XenDevice *xendev, const char *node, int64_t ival) -{ - return xenstore_write_int64(xendev->be, node, ival); -} - -char *xenstore_read_be_str(struct XenDevice *xendev, const char *node) -{ - return xenstore_read_str(xendev->be, node); -} - -int xenstore_read_be_int(struct XenDevice *xendev, const char *node, int *ival) -{ - return xenstore_read_int(xendev->be, node, ival); -} - -char *xenstore_read_fe_str(struct XenDevice *xendev, const char *node) -{ - return xenstore_read_str(xendev->fe, node); -} - -int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival) -{ - return xenstore_read_int(xendev->fe, node, ival); -} - -int xenstore_read_fe_uint64(struct XenDevice *xendev, const char *node, - uint64_t *uval) -{ - return xenstore_read_uint64(xendev->fe, node, uval); -} - -/* ------------------------------------------------------------- */ - -int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state) -{ - int rc; - - rc = xenstore_write_be_int(xendev, "state", state); - if (rc < 0) { - return rc; - } - xen_pv_printf(xendev, 1, "backend state: %s -> %s\n", - xenbus_strstate(xendev->be_state), xenbus_strstate(state)); - xendev->be_state = state; - return 0; -} - -void xen_be_set_max_grant_refs(struct XenDevice *xendev, - unsigned int nr_refs) -{ - assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV); - - if (xengnttab_set_max_grants(xendev->gnttabdev, nr_refs)) { - xen_pv_printf(xendev, 0, "xengnttab_set_max_grants failed: %s\n", - strerror(errno)); - } -} - -void *xen_be_map_grant_refs(struct XenDevice *xendev, uint32_t *refs, - unsigned int nr_refs, int prot) -{ - void *ptr; - - assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV); - - ptr = xengnttab_map_domain_grant_refs(xendev->gnttabdev, nr_refs, - xen_domid, refs, prot); - if (!ptr) { - xen_pv_printf(xendev, 0, - "xengnttab_map_domain_grant_refs failed: %s\n", - strerror(errno)); - } - - return ptr; -} - -void xen_be_unmap_grant_refs(struct XenDevice *xendev, void *ptr, - unsigned int nr_refs) -{ - assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV); - - if (xengnttab_unmap(xendev->gnttabdev, ptr, nr_refs)) { - xen_pv_printf(xendev, 0, "xengnttab_unmap failed: %s\n", - strerror(errno)); - } -} - -static int compat_copy_grant_refs(struct XenDevice *xendev, - bool to_domain, - XenGrantCopySegment segs[], - unsigned int nr_segs) -{ - uint32_t *refs = g_new(uint32_t, nr_segs); - int prot = to_domain ? PROT_WRITE : PROT_READ; - void *pages; - unsigned int i; - - for (i = 0; i < nr_segs; i++) { - XenGrantCopySegment *seg = &segs[i]; - - refs[i] = to_domain ? - seg->dest.foreign.ref : seg->source.foreign.ref; - } - - pages = 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 = 0; i < nr_segs; i++) { - XenGrantCopySegment *seg = &segs[i]; - void *page = 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 XenDevice *xendev, - bool to_domain, - XenGrantCopySegment segs[], - unsigned int nr_segs) -{ - xengnttab_grant_copy_segment_t *xengnttab_segs; - unsigned int i; - int rc; - - assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV); - - if (!xen_feature_grant_copy) { - return compat_copy_grant_refs(xendev, to_domain, segs, nr_segs); - } - - xengnttab_segs = g_new0(xengnttab_grant_copy_segment_t, nr_segs); - - for (i = 0; i < nr_segs; i++) { - XenGrantCopySegment *seg = &segs[i]; - xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i]; - - if (to_domain) { - xengnttab_seg->flags = GNTCOPY_dest_gref; - xengnttab_seg->dest.foreign.domid = xen_domid; - xengnttab_seg->dest.foreign.ref = seg->dest.foreign.ref; - xengnttab_seg->dest.foreign.offset = seg->dest.foreign.offset; - xengnttab_seg->source.virt = seg->source.virt; - } else { - xengnttab_seg->flags = GNTCOPY_source_gref; - xengnttab_seg->source.foreign.domid = xen_domid; - xengnttab_seg->source.foreign.ref = seg->source.foreign.ref; - xengnttab_seg->source.foreign.offset = - seg->source.foreign.offset; - xengnttab_seg->dest.virt = seg->dest.virt; - } - - xengnttab_seg->len = seg->len; - } - - rc = xengnttab_grant_copy(xendev->gnttabdev, nr_segs, xengnttab_segs); - - if (rc) { - xen_pv_printf(xendev, 0, "xengnttab_copy failed: %s\n", - strerror(errno)); - } - - for (i = 0; i < nr_segs; i++) { - xengnttab_grant_copy_segment_t *xengnttab_seg = - &xengnttab_segs[i]; - - if (xengnttab_seg->status != GNTST_okay) { - xen_pv_printf(xendev, 0, "segment[%u] status: %d\n", i, - xengnttab_seg->status); - rc = -1; - } - } - - g_free(xengnttab_segs); - return rc; -} - -/* - * get xen backend device, allocate a new one if it doesn't exist. - */ -static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev, - struct XenDevOps *ops) -{ - struct XenDevice *xendev; - - xendev = xen_pv_find_xendev(type, dom, dev); - if (xendev) { - return xendev; - } - - /* init new xendev */ - xendev = g_malloc0(ops->size); - object_initialize(&xendev->qdev, ops->size, TYPE_XENBACKEND); - OBJECT(xendev)->free = g_free; - qdev_set_parent_bus(DEVICE(xendev), xen_sysbus); - qdev_set_id(DEVICE(xendev), g_strdup_printf("xen-%s-%d", type, dev)); - qdev_init_nofail(DEVICE(xendev)); - object_unref(OBJECT(xendev)); - - xendev->type = type; - xendev->dom = dom; - xendev->dev = dev; - xendev->ops = ops; - - snprintf(xendev->be, sizeof(xendev->be), "backend/%s/%d/%d", - xendev->type, xendev->dom, xendev->dev); - snprintf(xendev->name, sizeof(xendev->name), "%s-%d", - xendev->type, xendev->dev); - - xendev->debug = debug; - xendev->local_port = -1; - - xendev->evtchndev = xenevtchn_open(NULL, 0); - if (xendev->evtchndev == 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)); - - xen_pv_insert_xendev(xendev); - - if (xendev->ops->alloc) { - xendev->ops->alloc(xendev); - } - - return xendev; -} - - -/* - * Sync internal data structures on xenstore updates. - * Node specifies the changed field. node = NULL means - * update all fields (used for initialization). - */ -static void xen_be_backend_changed(struct XenDevice *xendev, const char *node) -{ - if (node == NULL || strcmp(node, "online") == 0) { - if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1) { - xendev->online = 0; - } - } - - if (node) { - xen_pv_printf(xendev, 2, "backend update: %s\n", node); - if (xendev->ops->backend_changed) { - xendev->ops->backend_changed(xendev, node); - } - } -} - -static void xen_be_frontend_changed(struct XenDevice *xendev, const char *node) -{ - int fe_state; - - if (node == NULL || strcmp(node, "state") == 0) { - if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) { - fe_state = XenbusStateUnknown; - } - if (xendev->fe_state != fe_state) { - xen_pv_printf(xendev, 1, "frontend state: %s -> %s\n", - xenbus_strstate(xendev->fe_state), - xenbus_strstate(fe_state)); - } - xendev->fe_state = fe_state; - } - if (node == NULL || strcmp(node, "protocol") == 0) { - g_free(xendev->protocol); - xendev->protocol = xenstore_read_fe_str(xendev, "protocol"); - if (xendev->protocol) { - xen_pv_printf(xendev, 1, "frontend protocol: %s\n", - xendev->protocol); - } - } - - if (node) { - xen_pv_printf(xendev, 2, "frontend update: %s\n", node); - if (xendev->ops->frontend_changed) { - xendev->ops->frontend_changed(xendev, node); - } - } -} - -/* ------------------------------------------------------------- */ -/* Check for possible state transitions and perform them. */ - -/* - * Initial xendev setup. Read frontend path, register watch for it. - * Should succeed once xend finished setting up the backend device. - * - * Also sets initial state (-> Initializing) when done. Which - * only affects the xendev->be_state variable as xenbus should - * already be put into that state by xend. - */ -static int xen_be_try_setup(struct XenDevice *xendev) -{ - char token[XEN_BUFSIZE]; - int be_state; - - if (xenstore_read_be_int(xendev, "state", &be_state) == -1) { - xen_pv_printf(xendev, 0, "reading backend state failed\n"); - return -1; - } - - if (be_state != XenbusStateInitialising) { - xen_pv_printf(xendev, 0, "initial backend state is wrong (%s)\n", - xenbus_strstate(be_state)); - return -1; - } - - xendev->fe = xenstore_read_be_str(xendev, "frontend"); - if (xendev->fe == NULL) { - xen_pv_printf(xendev, 0, "reading frontend path failed\n"); - return -1; - } - - /* setup frontend watch */ - snprintf(token, sizeof(token), "fe:%p", xendev); - if (!xs_watch(xenstore, xendev->fe, token)) { - xen_pv_printf(xendev, 0, "watching frontend path (%s) failed\n", - xendev->fe); - return -1; - } - xen_be_set_state(xendev, XenbusStateInitialising); - - xen_be_backend_changed(xendev, NULL); - xen_be_frontend_changed(xendev, NULL); - return 0; -} - -/* - * Try initialize xendev. Prepare everything the backend can do - * without synchronizing with the frontend. Fakes hotplug-status. No - * hotplug involved here because this is about userspace drivers, thus - * there are kernel backend devices which could invoke hotplug. - * - * Goes to InitWait on success. - */ -static int xen_be_try_init(struct XenDevice *xendev) -{ - int rc = 0; - - if (!xendev->online) { - xen_pv_printf(xendev, 1, "not online\n"); - return -1; - } - - if (xendev->ops->init) { - rc = xendev->ops->init(xendev); - } - if (rc != 0) { - xen_pv_printf(xendev, 1, "init() failed\n"); - return rc; - } - - xenstore_write_be_str(xendev, "hotplug-status", "connected"); - xen_be_set_state(xendev, XenbusStateInitWait); - return 0; -} - -/* - * Try to initialise xendev. Depends on the frontend being ready - * for it (shared ring and evtchn info in xenstore, state being - * Initialised or Connected). - * - * Goes to Connected on success. - */ -static int xen_be_try_initialise(struct XenDevice *xendev) -{ - int rc = 0; - - if (xendev->fe_state != XenbusStateInitialised && - xendev->fe_state != XenbusStateConnected) { - if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) { - xen_pv_printf(xendev, 2, "frontend not ready, ignoring\n"); - } else { - xen_pv_printf(xendev, 2, "frontend not ready (yet)\n"); - return -1; - } - } - - if (xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV) { - xendev->gnttabdev = xengnttab_open(NULL, 0); - if (xendev->gnttabdev == NULL) { - xen_pv_printf(NULL, 0, "can't open gnttab device\n"); - return -1; - } - } else { - xendev->gnttabdev = NULL; - } - - if (xendev->ops->initialise) { - rc = xendev->ops->initialise(xendev); - } - if (rc != 0) { - xen_pv_printf(xendev, 0, "initialise() failed\n"); - return rc; - } - - xen_be_set_state(xendev, XenbusStateConnected); - return 0; -} - -/* - * Try to let xendev know that it is connected. Depends on the - * frontend being Connected. Note that this may be called more - * than once since the backend state is not modified. - */ -static void xen_be_try_connected(struct XenDevice *xendev) -{ - if (!xendev->ops->connected) { - return; - } - - if (xendev->fe_state != XenbusStateConnected) { - if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) { - xen_pv_printf(xendev, 2, "frontend not ready, ignoring\n"); - } else { - xen_pv_printf(xendev, 2, "frontend not ready (yet)\n"); - return; - } - } - - xendev->ops->connected(xendev); -} - -/* - * Teardown connection. - * - * Goes to Closed when done. - */ -static void xen_be_disconnect(struct XenDevice *xendev, enum xenbus_state state) -{ - if (xendev->be_state != XenbusStateClosing && - xendev->be_state != XenbusStateClosed && - xendev->ops->disconnect) { - xendev->ops->disconnect(xendev); - } - if (xendev->gnttabdev) { - xengnttab_close(xendev->gnttabdev); - xendev->gnttabdev = NULL; - } - if (xendev->be_state != state) { - xen_be_set_state(xendev, state); - } -} - -/* - * Try to reset xendev, for reconnection by another frontend instance. - */ -static int xen_be_try_reset(struct XenDevice *xendev) -{ - if (xendev->fe_state != XenbusStateInitialising) { - return -1; - } - - xen_pv_printf(xendev, 1, "device reset (for re-connect)\n"); - xen_be_set_state(xendev, XenbusStateInitialising); - return 0; -} - -/* - * state change dispatcher function - */ -void xen_be_check_state(struct XenDevice *xendev) -{ - int rc = 0; - - /* frontend may request shutdown from almost anywhere */ - if (xendev->fe_state == XenbusStateClosing || - xendev->fe_state == XenbusStateClosed) { - xen_be_disconnect(xendev, xendev->fe_state); - return; - } - - /* check for possible backend state transitions */ - for (;;) { - switch (xendev->be_state) { - case XenbusStateUnknown: - rc = xen_be_try_setup(xendev); - break; - case XenbusStateInitialising: - rc = xen_be_try_init(xendev); - break; - case XenbusStateInitWait: - rc = xen_be_try_initialise(xendev); - break; - case XenbusStateConnected: - /* xendev->be_state doesn't change */ - xen_be_try_connected(xendev); - rc = -1; - break; - case XenbusStateClosed: - rc = xen_be_try_reset(xendev); - break; - default: - rc = -1; - } - if (rc != 0) { - break; - } - } -} - -/* ------------------------------------------------------------- */ - -static int xenstore_scan(const char *type, int dom, struct XenDevOps *ops) -{ - struct XenDevice *xendev; - char path[XEN_BUFSIZE], token[XEN_BUFSIZE]; - char **dev = 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 = xs_directory(xenstore, 0, path, &cdev); - if (!dev) { - return 0; - } - for (j = 0; j < cdev; j++) { - xendev = xen_be_get_xendev(type, dom, atoi(dev[j]), ops); - if (xendev == NULL) { - continue; - } - xen_be_check_state(xendev); - } - free(dev); - return 0; -} - -void xenstore_update_be(char *watch, char *type, int dom, - struct XenDevOps *ops) -{ - struct XenDevice *xendev; - char path[XEN_BUFSIZE], *bepath; - unsigned int len, dev; - - len = snprintf(path, sizeof(path), "backend/%s/%d", type, dom); - if (strncmp(path, watch, len) != 0) { - return; - } - if (sscanf(watch+len, "/%u/%255s", &dev, path) != 2) { - strcpy(path, ""); - if (sscanf(watch+len, "/%u", &dev) != 1) { - dev = -1; - } - } - if (dev == -1) { - return; - } - - xendev = xen_be_get_xendev(type, dom, dev, ops); - if (xendev != NULL) { - bepath = xs_read(xenstore, 0, xendev->be, &len); - if (bepath == NULL) { - xen_pv_del_xendev(xendev); - } else { - free(bepath); - xen_be_backend_changed(xendev, path); - xen_be_check_state(xendev); - } - } -} - -void xenstore_update_fe(char *watch, struct XenDevice *xendev) -{ - char *node; - unsigned int len; - - len = strlen(xendev->fe); - if (strncmp(xendev->fe, watch, len) != 0) { - return; - } - if (watch[len] != '/') { - return; - } - node = watch + len + 1; - - xen_be_frontend_changed(xendev, node); - xen_be_check_state(xendev); -} -/* -------------------------------------------------------------------- */ - -int xen_be_init(void) -{ - xengnttab_handle *gnttabdev; - - xenstore = xs_daemon_open(); - if (!xenstore) { - xen_pv_printf(NULL, 0, "can't connect to xenstored\n"); - return -1; - } - - qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL); - - if (xen_xc == NULL || xen_fmem == NULL) { - /* Check if xen_init() have been called */ - goto err; - } - - gnttabdev = xengnttab_open(NULL, 0); - if (gnttabdev != NULL) { - if (xengnttab_grant_copy(gnttabdev, 0, NULL) == 0) { - xen_feature_grant_copy = true; - } - xengnttab_close(gnttabdev); - } - - xen_sysdev = qdev_create(NULL, TYPE_XENSYSDEV); - qdev_init_nofail(xen_sysdev); - xen_sysbus = qbus_create(TYPE_XENSYSBUS, DEVICE(xen_sysdev), "xen-sysbus"); - qbus_set_bus_hotplug_handler(xen_sysbus, &error_abort); - - return 0; - -err: - qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL); - xs_daemon_close(xenstore); - xenstore = NULL; - - return -1; -} - -static void xen_set_dynamic_sysbus(void) -{ - Object *machine = qdev_get_machine(); - ObjectClass *oc = object_get_class(machine); - MachineClass *mc = MACHINE_CLASS(oc); - - machine_class_allow_dynamic_sysbus_dev(mc, TYPE_XENSYSDEV); -} - -int xen_be_register(const char *type, struct XenDevOps *ops) -{ - char path[50]; - int rc; - - if (ops->backend_register) { - rc = ops->backend_register(); - if (rc) { - return rc; - } - } - - snprintf(path, sizeof(path), "device-model/%u/backends/%s", xen_domid, - type); - xenstore_mkdir(path, XS_PERM_NONE); - - return xenstore_scan(type, xen_domid, ops); -} - -void xen_be_register_common(void) -{ - xen_set_dynamic_sysbus(); - - xen_be_register("console", &xen_console_ops); - xen_be_register("vkbd", &xen_kbdmouse_ops); - xen_be_register("qdisk", &xen_blkdev_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 XenDevice *xendev) -{ - if (xendev->local_port != -1) { - return 0; - } - xendev->local_port = xenevtchn_bind_interdomain - (xendev->evtchndev, xendev->dom, xendev->remote_port); - if (xendev->local_port == -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), - xen_pv_evtchn_event, NULL, xendev); - return 0; -} - - -static Property xendev_properties[] = { - DEFINE_PROP_END_OF_LIST(), -}; - -static void xendev_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->props = xendev_properties; - set_bit(DEVICE_CATEGORY_MISC, dc->categories); - /* xen-backend devices can be plugged/unplugged dynamically */ - dc->user_creatable = true; -} - -static const TypeInfo xendev_type_info = { - .name = TYPE_XENBACKEND, - .parent = TYPE_XENSYSDEV, - .class_init = xendev_class_init, - .instance_size = sizeof(struct XenDevice), -}; - -static void xen_sysbus_class_init(ObjectClass *klass, void *data) -{ - HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); - - hc->unplug = qdev_simple_device_unplug_cb; -} - -static const TypeInfo xensysbus_info = { - .name = TYPE_XENSYSBUS, - .parent = TYPE_BUS, - .class_init = xen_sysbus_class_init, - .interfaces = (InterfaceInfo[]) { - { TYPE_HOTPLUG_HANDLER }, - { } - } -}; - -static int xen_sysdev_init(SysBusDevice *dev) -{ - return 0; -} - -static Property xen_sysdev_properties[] = { - {/* end of property list */}, -}; - -static void xen_sysdev_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = xen_sysdev_init; - dc->props = xen_sysdev_properties; - dc->bus_type = TYPE_XENSYSBUS; -} - -static const TypeInfo xensysdev_info = { - .name = TYPE_XENSYSDEV, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(SysBusDevice), - .class_init = xen_sysdev_class_init, -}; - -static void xenbe_register_types(void) -{ - type_register_static(&xensysbus_info); - type_register_static(&xensysdev_info); - type_register_static(&xendev_type_info); -} - -type_init(xenbe_register_types) diff --git a/hw/xen/xen_devconfig.c b/hw/xen/xen_devconfig.c index aebc19b..1b30bd7 100644 --- a/hw/xen/xen_devconfig.c +++ b/hw/xen/xen_devconfig.c @@ -1,5 +1,5 @@ #include "qemu/osdep.h" -#include "hw/xen/xen_backend.h" +#include "hw/xen/xen-legacy-backend.h" #include "qemu/option.h" #include "sysemu/blockdev.h" diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index f1f3a37..b20bf3a 100644 --- a/hw/xen/xen_pt.c +++ b/hw/xen/xen_pt.c @@ -59,7 +59,7 @@ #include "hw/pci/pci.h" #include "hw/xen/xen.h" #include "hw/i386/pc.h" -#include "hw/xen/xen_backend.h" +#include "hw/xen/xen-legacy-backend.h" #include "xen_pt.h" #include "qemu/range.h" #include "exec/address-spaces.h" diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c index 47f9010..8111204 100644 --- a/hw/xen/xen_pt_config_init.c +++ b/hw/xen/xen_pt_config_init.c @@ -15,7 +15,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/timer.h" -#include "hw/xen/xen_backend.h" +#include "hw/xen/xen-legacy-backend.h" #include "xen_pt.h" #define XEN_PT_MERGE_VALUE(value, data, val_mask) \ diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c index 135c8df..130cc6c 100644 --- a/hw/xen/xen_pt_graphics.c +++ b/hw/xen/xen_pt_graphics.c @@ -5,7 +5,7 @@ #include "qapi/error.h" #include "xen_pt.h" #include "xen-host-pci-device.h" -#include "hw/xen/xen_backend.h" +#include "hw/xen/xen-legacy-backend.h" static unsigned long igd_guest_opregion; static unsigned long igd_host_opregion; diff --git a/hw/xen/xen_pt_msi.c b/hw/xen/xen_pt_msi.c index cc514f9..fb4b887 100644 --- a/hw/xen/xen_pt_msi.c +++ b/hw/xen/xen_pt_msi.c @@ -11,7 +11,7 @@ #include "qemu/osdep.h" -#include "hw/xen/xen_backend.h" +#include "hw/xen/xen-legacy-backend.h" #include "xen_pt.h" #include "hw/i386/apic-msidef.h" diff --git a/hw/xen/xen_pvdev.c b/hw/xen/xen_pvdev.c index aed783e..61de091 100644 --- a/hw/xen/xen_pvdev.c +++ b/hw/xen/xen_pvdev.c @@ -20,7 +20,7 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "hw/qdev-core.h" -#include "hw/xen/xen_backend.h" +#include "hw/xen/xen-legacy-backend.h" #include "hw/xen/xen_pvdev.h" /* private */ @@ -34,7 +34,7 @@ struct xs_dirs { static QTAILQ_HEAD(xs_dirs_head, xs_dirs) xs_cleanup = QTAILQ_HEAD_INITIALIZER(xs_cleanup); -static QTAILQ_HEAD(XenDeviceHead, XenDevice) xendevs = +static QTAILQ_HEAD(XenLegacyDeviceHead, XenLegacyDevice) xendevs = QTAILQ_HEAD_INITIALIZER(xendevs); /* ------------------------------------------------------------- */ @@ -195,7 +195,7 @@ const char *xenbus_strstate(enum xenbus_state state) * 2 == noisy debug messages (logfile only). * 3 == will flood your log (logfile only). */ -void xen_pv_printf(struct XenDevice *xendev, int msg_level, +void xen_pv_printf(struct XenLegacyDevice *xendev, int msg_level, const char *fmt, ...) { va_list args; @@ -230,7 +230,7 @@ void xen_pv_printf(struct XenDevice *xendev, int msg_level, void xen_pv_evtchn_event(void *opaque) { - struct XenDevice *xendev = opaque; + struct XenLegacyDevice *xendev = opaque; evtchn_port_t port; port = xenevtchn_pending(xendev->evtchndev); @@ -247,7 +247,7 @@ void xen_pv_evtchn_event(void *opaque) } } -void xen_pv_unbind_evtchn(struct XenDevice *xendev) +void xen_pv_unbind_evtchn(struct XenLegacyDevice *xendev) { if (xendev->local_port == -1) { return; @@ -258,16 +258,16 @@ void xen_pv_unbind_evtchn(struct XenDevice *xendev) xendev->local_port = -1; } -int xen_pv_send_notify(struct XenDevice *xendev) +int xen_pv_send_notify(struct XenLegacyDevice *xendev) { return xenevtchn_notify(xendev->evtchndev, xendev->local_port); } /* ------------------------------------------------------------- */ -struct XenDevice *xen_pv_find_xendev(const char *type, int dom, int dev) +struct XenLegacyDevice *xen_pv_find_xendev(const char *type, int dom, int dev) { - struct XenDevice *xendev; + struct XenLegacyDevice *xendev; QTAILQ_FOREACH(xendev, &xendevs, next) { if (xendev->dom != dom) { @@ -287,7 +287,7 @@ struct XenDevice *xen_pv_find_xendev(const char *type, int dom, int dev) /* * release xen backend device. */ -void xen_pv_del_xendev(struct XenDevice *xendev) +void xen_pv_del_xendev(struct XenLegacyDevice *xendev) { if (xendev->ops->free) { xendev->ops->free(xendev); @@ -312,7 +312,7 @@ void xen_pv_del_xendev(struct XenDevice *xendev) qdev_unplug(&xendev->qdev, NULL); } -void xen_pv_insert_xendev(struct XenDevice *xendev) +void xen_pv_insert_xendev(struct XenLegacyDevice *xendev) { QTAILQ_INSERT_TAIL(&xendevs, xendev, next); } diff --git a/hw/xenpv/xen_domainbuild.c b/hw/xenpv/xen_domainbuild.c index 188acac..deb28cf 100644 --- a/hw/xenpv/xen_domainbuild.c +++ b/hw/xenpv/xen_domainbuild.c @@ -1,6 +1,6 @@ #include "qemu/osdep.h" #include "qemu/units.h" -#include "hw/xen/xen_backend.h" +#include "hw/xen/xen-legacy-backend.h" #include "xen_domainbuild.h" #include "qemu/timer.h" #include "qemu/log.h" diff --git a/hw/xenpv/xen_machine_pv.c b/hw/xenpv/xen_machine_pv.c index 44d67b8..8c86fb7 100644 --- a/hw/xenpv/xen_machine_pv.c +++ b/hw/xenpv/xen_machine_pv.c @@ -26,7 +26,7 @@ #include "qemu/error-report.h" #include "hw/hw.h" #include "hw/boards.h" -#include "hw/xen/xen_backend.h" +#include "hw/xen/xen-legacy-backend.h" #include "xen_domainbuild.h" #include "sysemu/block-backend.h" diff --git a/include/hw/xen/xen-legacy-backend.h b/include/hw/xen/xen-legacy-backend.h new file mode 100644 index 0000000..20cb47b --- /dev/null +++ b/include/hw/xen/xen-legacy-backend.h @@ -0,0 +1,104 @@ +#ifndef QEMU_HW_XEN_BACKEND_H +#define QEMU_HW_XEN_BACKEND_H + +#include "hw/xen/xen_common.h" +#include "hw/xen/xen_pvdev.h" +#include "sysemu/sysemu.h" +#include "net/net.h" + +#define TYPE_XENSYSDEV "xen-sysdev" +#define TYPE_XENSYSBUS "xen-sysbus" +#define TYPE_XENBACKEND "xen-backend" + +#define XENBACKEND_DEVICE(obj) \ + OBJECT_CHECK(XenLegacyDevice, (obj), TYPE_XENBACKEND) + +/* variables */ +extern struct xs_handle *xenstore; +extern const char *xen_protocol; +extern DeviceState *xen_sysdev; +extern BusState *xen_sysbus; + +int xenstore_mkdir(char *path, int p); +int xenstore_write_be_str(struct XenLegacyDevice *xendev, const char *node, + const char *val); +int xenstore_write_be_int(struct XenLegacyDevice *xendev, const char *node, + int ival); +int xenstore_write_be_int64(struct XenLegacyDevice *xendev, const char *node, + int64_t ival); +char *xenstore_read_be_str(struct XenLegacyDevice *xendev, const char *node); +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 *node); +int xenstore_read_fe_int(struct XenLegacyDevice *xendev, const char *node, + int *ival); +int xenstore_read_fe_uint64(struct XenLegacyDevice *xendev, const char *node, + uint64_t *uval); + +void xen_be_check_state(struct XenLegacyDevice *xendev); + +/* xen backend driver bits */ +int xen_be_init(void); +void xen_be_register_common(void); +int xen_be_register(const char *type, struct XenDevOps *ops); +int xen_be_set_state(struct XenLegacyDevice *xendev, enum xenbus_state state); +int xen_be_bind_evtchn(struct XenLegacyDevice *xendev); +void xen_be_set_max_grant_refs(struct XenLegacyDevice *xendev, + unsigned int nr_refs); +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); + +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); + +static inline void *xen_be_map_grant_ref(struct XenLegacyDevice *xendev, + uint32_t ref, int prot) +{ + return xen_be_map_grant_refs(xendev, &ref, 1, prot); +} + +static inline void xen_be_unmap_grant_ref(struct XenLegacyDevice *xendev, + void *ptr) +{ + return xen_be_unmap_grant_refs(xendev, ptr, 1); +} + +/* actual backend drivers */ +extern struct XenDevOps xen_console_ops; /* xen_console.c */ +extern struct XenDevOps xen_kbdmouse_ops; /* xen_framebuffer.c */ +extern struct XenDevOps xen_framebuffer_ops; /* xen_framebuffer.c */ +extern struct XenDevOps xen_blkdev_ops; /* xen_disk.c */ +#ifdef CONFIG_VIRTFS +extern struct XenDevOps xen_9pfs_ops; /* xen-9p-backend.c */ +#endif +extern struct XenDevOps xen_netdev_ops; /* xen_nic.c */ +#ifdef CONFIG_USB_LIBUSB +extern struct XenDevOps xen_usb_ops; /* xen-usb.c */ +#endif + +/* configuration (aka xenbus setup) */ +void xen_config_cleanup(void); +int xen_config_dev_blk(DriveInfo *disk); +int xen_config_dev_nic(NICInfo *nic); +int xen_config_dev_vfb(int vdev, const char *type); +int xen_config_dev_vkbd(int vdev); +int xen_config_dev_console(int vdev); + +#endif /* QEMU_HW_XEN_BACKEND_H */ diff --git a/include/hw/xen/xen_backend.h b/include/hw/xen/xen_backend.h deleted file mode 100644 index 9c17fdd..0000000 --- a/include/hw/xen/xen_backend.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef QEMU_HW_XEN_BACKEND_H -#define QEMU_HW_XEN_BACKEND_H - -#include "hw/xen/xen_common.h" -#include "hw/xen/xen_pvdev.h" -#include "sysemu/sysemu.h" -#include "net/net.h" - -#define TYPE_XENSYSDEV "xen-sysdev" -#define TYPE_XENSYSBUS "xen-sysbus" -#define TYPE_XENBACKEND "xen-backend" - -#define XENBACKEND_DEVICE(obj) \ - OBJECT_CHECK(XenDevice, (obj), TYPE_XENBACKEND) - -/* variables */ -extern struct xs_handle *xenstore; -extern const char *xen_protocol; -extern DeviceState *xen_sysdev; -extern BusState *xen_sysbus; - -int xenstore_mkdir(char *path, int p); -int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val); -int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival); -int xenstore_write_be_int64(struct XenDevice *xendev, const char *node, int64_t ival); -char *xenstore_read_be_str(struct XenDevice *xendev, const char *node); -int xenstore_read_be_int(struct XenDevice *xendev, const char *node, int *ival); -void xenstore_update_fe(char *watch, struct XenDevice *xendev); -void xenstore_update_be(char *watch, char *type, int dom, - struct XenDevOps *ops); -char *xenstore_read_fe_str(struct XenDevice *xendev, const char *node); -int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival); -int xenstore_read_fe_uint64(struct XenDevice *xendev, const char *node, - uint64_t *uval); - -void xen_be_check_state(struct XenDevice *xendev); - -/* xen backend driver bits */ -int xen_be_init(void); -void xen_be_register_common(void); -int xen_be_register(const char *type, struct XenDevOps *ops); -int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state); -int xen_be_bind_evtchn(struct XenDevice *xendev); -void xen_be_set_max_grant_refs(struct XenDevice *xendev, - unsigned int nr_refs); -void *xen_be_map_grant_refs(struct XenDevice *xendev, uint32_t *refs, - unsigned int nr_refs, int prot); -void xen_be_unmap_grant_refs(struct XenDevice *xendev, void *ptr, - unsigned int nr_refs); - -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 XenDevice *xendev, - bool to_domain, XenGrantCopySegment segs[], - unsigned int nr_segs); - -static inline void *xen_be_map_grant_ref(struct XenDevice *xendev, - uint32_t ref, int prot) -{ - return xen_be_map_grant_refs(xendev, &ref, 1, prot); -} - -static inline void xen_be_unmap_grant_ref(struct XenDevice *xendev, - void *ptr) -{ - return xen_be_unmap_grant_refs(xendev, ptr, 1); -} - -/* actual backend drivers */ -extern struct XenDevOps xen_console_ops; /* xen_console.c */ -extern struct XenDevOps xen_kbdmouse_ops; /* xen_framebuffer.c */ -extern struct XenDevOps xen_framebuffer_ops; /* xen_framebuffer.c */ -extern struct XenDevOps xen_blkdev_ops; /* xen_disk.c */ -#ifdef CONFIG_VIRTFS -extern struct XenDevOps xen_9pfs_ops; /* xen-9p-backend.c */ -#endif -extern struct XenDevOps xen_netdev_ops; /* xen_nic.c */ -#ifdef CONFIG_USB_LIBUSB -extern struct XenDevOps xen_usb_ops; /* xen-usb.c */ -#endif - -/* configuration (aka xenbus setup) */ -void xen_config_cleanup(void); -int xen_config_dev_blk(DriveInfo *disk); -int xen_config_dev_nic(NICInfo *nic); -int xen_config_dev_vfb(int vdev, const char *type); -int xen_config_dev_vkbd(int vdev); -int xen_config_dev_console(int vdev); - -#endif /* QEMU_HW_XEN_BACKEND_H */ diff --git a/include/hw/xen/xen_pvdev.h b/include/hw/xen/xen_pvdev.h index d473e9b..83e5174 100644 --- a/include/hw/xen/xen_pvdev.h +++ b/include/hw/xen/xen_pvdev.h @@ -6,7 +6,7 @@ #define XEN_BUFSIZE 1024 -struct XenDevice; +struct XenLegacyDevice; /* driver uses grant tables -> open gntdev device (xendev->gnttabdev) */ #define DEVOPS_FLAG_NEED_GNTDEV 1 @@ -16,19 +16,21 @@ struct XenDevice; struct XenDevOps { size_t size; uint32_t flags; - void (*alloc)(struct XenDevice *xendev); - int (*init)(struct XenDevice *xendev); - int (*initialise)(struct XenDevice *xendev); - void (*connected)(struct XenDevice *xendev); - void (*event)(struct XenDevice *xendev); - void (*disconnect)(struct XenDevice *xendev); - int (*free)(struct XenDevice *xendev); - void (*backend_changed)(struct XenDevice *xendev, const char *node); - void (*frontend_changed)(struct XenDevice *xendev, const char *node); + void (*alloc)(struct XenLegacyDevice *xendev); + int (*init)(struct XenLegacyDevice *xendev); + int (*initialise)(struct XenLegacyDevice *xendev); + void (*connected)(struct XenLegacyDevice *xendev); + void (*event)(struct XenLegacyDevice *xendev); + void (*disconnect)(struct XenLegacyDevice *xendev); + int (*free)(struct XenLegacyDevice *xendev); + void (*backend_changed)(struct XenLegacyDevice *xendev, + const char *node); + void (*frontend_changed)(struct XenLegacyDevice *xendev, + const char *node); int (*backend_register)(void); }; -struct XenDevice { +struct XenLegacyDevice { DeviceState qdev; const char *type; int dom; @@ -49,7 +51,7 @@ struct XenDevice { xengnttab_handle *gnttabdev; struct XenDevOps *ops; - QTAILQ_ENTRY(XenDevice) next; + QTAILQ_ENTRY(XenLegacyDevice) next; }; /* ------------------------------------------------------------- */ @@ -66,14 +68,14 @@ void xenstore_update(void *unused); const char *xenbus_strstate(enum xenbus_state state); void xen_pv_evtchn_event(void *opaque); -void xen_pv_insert_xendev(struct XenDevice *xendev); -void xen_pv_del_xendev(struct XenDevice *xendev); -struct XenDevice *xen_pv_find_xendev(const char *type, int dom, int dev); +void xen_pv_insert_xendev(struct XenLegacyDevice *xendev); +void xen_pv_del_xendev(struct XenLegacyDevice *xendev); +struct XenLegacyDevice *xen_pv_find_xendev(const char *type, int dom, int dev); -void xen_pv_unbind_evtchn(struct XenDevice *xendev); -int xen_pv_send_notify(struct XenDevice *xendev); +void xen_pv_unbind_evtchn(struct XenLegacyDevice *xendev); +int xen_pv_send_notify(struct XenLegacyDevice *xendev); -void xen_pv_printf(struct XenDevice *xendev, int msg_level, +void xen_pv_printf(struct XenLegacyDevice *xendev, int msg_level, const char *fmt, ...) GCC_FMT_ATTR(3, 4); #endif /* QEMU_HW_XEN_PVDEV_H */ From patchwork Mon Dec 17 11:40:32 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 1014433 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=citrix.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 43JKCC58Nfz9s2P for ; Mon, 17 Dec 2018 22:47:35 +1100 (AEDT) Received: from localhost ([::1]:46186 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrMz-0000NV-Ax for incoming@patchwork.ozlabs.org; Mon, 17 Dec 2018 06:47:33 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:52930) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrGh-0004Bd-IO for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:41:05 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gYrGf-0006cX-5m for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:41:03 -0500 Received: from smtp03.citrix.com ([162.221.156.55]:44677) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gYrGZ-0006YC-8p; Mon, 17 Dec 2018 06:40:55 -0500 X-IronPort-AV: E=Sophos;i="5.56,365,1539648000"; d="scan'208";a="73532584" From: Paul Durrant To: , , Date: Mon, 17 Dec 2018 11:40:32 +0000 Message-ID: <1545046848-14891-3-git-send-email-paul.durrant@citrix.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> References: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 162.221.156.55 Subject: [Qemu-devel] [PATCH v5 02/18] xen: introduce new 'XenBus' and 'XenDevice' object hierarchy X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Stefano Stabellini , Eduardo Habkost , "Michael S. Tsirkin" , Paul Durrant , Paolo Bonzini , Richard Henderson Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This patch adds the basic boilerplate for a 'XenBus' object that will act as a parent to 'XenDevice' PV backends. A new 'XenBridge' object is also added to connect XenBus to the system bus. The XenBus object is instantiated by a new xen_bus_init() function called from the same sites as the legacy xen_be_init() function. Subsequent patches will flesh-out the functionality of these objects. Signed-off-by: Paul Durrant Reviewed-by: Anthony Perard --- Cc: Stefano Stabellini Cc: "Michael S. Tsirkin" Cc: Marcel Apfelbaum Cc: Paolo Bonzini Cc: Richard Henderson Cc: Eduardo Habkost v3: - Don't use local_err unless it is needed v2: - Fix boilerplate - Make xen-bus hotplug capable --- hw/i386/xen/xen-hvm.c | 3 ++ hw/xen/Makefile.objs | 2 +- hw/xen/trace-events | 6 +++ hw/xen/xen-bus.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++ hw/xenpv/xen_machine_pv.c | 3 ++ include/hw/xen/xen-bus.h | 55 ++++++++++++++++++++ 6 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 hw/xen/xen-bus.c create mode 100644 include/hw/xen/xen-bus.h diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c index 1d63763..4497f75 100644 --- a/hw/i386/xen/xen-hvm.c +++ b/hw/i386/xen/xen-hvm.c @@ -17,6 +17,7 @@ #include "hw/i386/apic-msidef.h" #include "hw/xen/xen_common.h" #include "hw/xen/xen-legacy-backend.h" +#include "hw/xen/xen-bus.h" #include "qapi/error.h" #include "qapi/qapi-commands-misc.h" #include "qemu/error-report.h" @@ -1479,6 +1480,8 @@ void xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory) QLIST_INIT(&state->dev_list); device_listener_register(&state->device_listener); + xen_bus_init(); + /* Initialize backend core & drivers */ if (xen_be_init() != 0) { error_report("xen backend core setup failed"); diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs index 3f64a44..d9d6d7b 100644 --- a/hw/xen/Makefile.objs +++ b/hw/xen/Makefile.objs @@ -1,5 +1,5 @@ # xen backend driver support -common-obj-$(CONFIG_XEN) += xen-legacy-backend.o xen_devconfig.o xen_pvdev.o xen-common.o +common-obj-$(CONFIG_XEN) += xen-legacy-backend.o xen_devconfig.o xen_pvdev.o xen-common.o xen-bus.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_graphics.o xen_pt_msi.o diff --git a/hw/xen/trace-events b/hw/xen/trace-events index c7e7a3b..0172cd4 100644 --- a/hw/xen/trace-events +++ b/hw/xen/trace-events @@ -12,3 +12,9 @@ xen_unmap_portio_range(uint32_t id, uint64_t start_addr, uint64_t end_addr) "id: xen_map_pcidev(uint32_t id, uint8_t bus, uint8_t dev, uint8_t func) "id: %u bdf: %02x.%02x.%02x" xen_unmap_pcidev(uint32_t id, uint8_t bus, uint8_t dev, uint8_t func) "id: %u bdf: %02x.%02x.%02x" xen_domid_restrict(int err) "err: %u" + +# include/hw/xen/xen-bus.c +xen_bus_realize(void) "" +xen_bus_unrealize(void) "" +xen_device_realize(const char *type) "type: %s" +xen_device_unrealize(const char *type) "type: %s" diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c new file mode 100644 index 0000000..bc04da7 --- /dev/null +++ b/hw/xen/xen-bus.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2018 Citrix Systems Inc. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/xen/xen-bus.h" +#include "qapi/error.h" +#include "trace.h" + +static void xen_bus_unrealize(BusState *bus, Error **errp) +{ + trace_xen_bus_unrealize(); +} + +static void xen_bus_realize(BusState *bus, Error **errp) +{ + trace_xen_bus_realize(); +} + +static void xen_bus_class_init(ObjectClass *class, void *data) +{ + BusClass *bus_class = BUS_CLASS(class); + + bus_class->realize = xen_bus_realize; + bus_class->unrealize = xen_bus_unrealize; +} + +static const TypeInfo xen_bus_type_info = { + .name = TYPE_XEN_BUS, + .parent = TYPE_BUS, + .instance_size = sizeof(XenBus), + .class_size = sizeof(XenBusClass), + .class_init = xen_bus_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_HOTPLUG_HANDLER }, + { } + }, +}; + +static void xen_device_unrealize(DeviceState *dev, Error **errp) +{ + XenDevice *xendev = XEN_DEVICE(dev); + XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev); + const char *type = object_get_typename(OBJECT(xendev)); + + trace_xen_device_unrealize(type); + + if (xendev_class->unrealize) { + xendev_class->unrealize(xendev, errp); + } +} + +static void xen_device_realize(DeviceState *dev, Error **errp) +{ + XenDevice *xendev = XEN_DEVICE(dev); + XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev); + const char *type = object_get_typename(OBJECT(xendev)); + Error *local_err = NULL; + + trace_xen_device_realize(type); + + if (xendev_class->realize) { + xendev_class->realize(xendev, &local_err); + if (local_err) { + error_propagate(errp, local_err); + goto unrealize; + } + } + + return; + +unrealize: + xen_device_unrealize(dev, &error_abort); +} + +static void xen_device_class_init(ObjectClass *class, void *data) +{ + DeviceClass *dev_class = DEVICE_CLASS(class); + + dev_class->realize = xen_device_realize; + dev_class->unrealize = xen_device_unrealize; + dev_class->bus_type = TYPE_XEN_BUS; +} + +static const TypeInfo xen_device_type_info = { + .name = TYPE_XEN_DEVICE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(XenDevice), + .abstract = true, + .class_size = sizeof(XenDeviceClass), + .class_init = xen_device_class_init, +}; + +typedef struct XenBridge { + SysBusDevice busdev; +} XenBridge; + +#define TYPE_XEN_BRIDGE "xen-bridge" + +static const TypeInfo xen_bridge_type_info = { + .name = TYPE_XEN_BRIDGE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(XenBridge), +}; + +static void xen_register_types(void) +{ + type_register_static(&xen_bridge_type_info); + type_register_static(&xen_bus_type_info); + type_register_static(&xen_device_type_info); +} + +type_init(xen_register_types) + +void xen_bus_init(void) +{ + DeviceState *dev = qdev_create(NULL, TYPE_XEN_BRIDGE); + BusState *bus = qbus_create(TYPE_XEN_BUS, dev, NULL); + + qdev_init_nofail(dev); + qbus_set_bus_hotplug_handler(bus, &error_abort); +} diff --git a/hw/xenpv/xen_machine_pv.c b/hw/xenpv/xen_machine_pv.c index 8c86fb7..608e591 100644 --- a/hw/xenpv/xen_machine_pv.c +++ b/hw/xenpv/xen_machine_pv.c @@ -27,6 +27,7 @@ #include "hw/hw.h" #include "hw/boards.h" #include "hw/xen/xen-legacy-backend.h" +#include "hw/xen/xen-bus.h" #include "xen_domainbuild.h" #include "sysemu/block-backend.h" @@ -93,6 +94,8 @@ static void xen_init_pv(MachineState *machine) xen_config_dev_nic(nd_table + i); } + xen_bus_init(); + /* config cleanup hook */ atexit(xen_config_cleanup); } diff --git a/include/hw/xen/xen-bus.h b/include/hw/xen/xen-bus.h new file mode 100644 index 0000000..0cb1246 --- /dev/null +++ b/include/hw/xen/xen-bus.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018 Citrix Systems Inc. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef HW_XEN_BUS_H +#define HW_XEN_BUS_H + +#include "hw/sysbus.h" + +typedef struct XenDevice { + DeviceState qdev; +} XenDevice; + +typedef void (*XenDeviceRealize)(XenDevice *xendev, Error **errp); +typedef void (*XenDeviceUnrealize)(XenDevice *xendev, Error **errp); + +typedef struct XenDeviceClass { + /*< private >*/ + DeviceClass parent_class; + /*< public >*/ + XenDeviceRealize realize; + XenDeviceUnrealize unrealize; +} XenDeviceClass; + +#define TYPE_XEN_DEVICE "xen-device" +#define XEN_DEVICE(obj) \ + OBJECT_CHECK(XenDevice, (obj), TYPE_XEN_DEVICE) +#define XEN_DEVICE_CLASS(class) \ + OBJECT_CLASS_CHECK(XenDeviceClass, (class), TYPE_XEN_DEVICE) +#define XEN_DEVICE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(XenDeviceClass, (obj), TYPE_XEN_DEVICE) + +typedef struct XenBus { + BusState qbus; +} XenBus; + +typedef struct XenBusClass { + /*< private >*/ + BusClass parent_class; +} XenBusClass; + +#define TYPE_XEN_BUS "xen-bus" +#define XEN_BUS(obj) \ + OBJECT_CHECK(XenBus, (obj), TYPE_XEN_BUS) +#define XEN_BUS_CLASS(class) \ + OBJECT_CLASS_CHECK(XenBusClass, (class), TYPE_XEN_BUS) +#define XEN_BUS_GET_CLASS(obj) \ + OBJECT_GET_CLASS(XenBusClass, (obj), TYPE_XEN_BUS) + +void xen_bus_init(void); + +#endif /* HW_XEN_BUS_H */ From patchwork Mon Dec 17 11:40:33 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 1014428 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=citrix.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 43JK4j4tBmz9s2P for ; Mon, 17 Dec 2018 22:41:57 +1100 (AEDT) Received: from localhost ([::1]:46155 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrHX-0004KS-A8 for incoming@patchwork.ozlabs.org; Mon, 17 Dec 2018 06:41:55 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:52843) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrGc-00048s-Qu for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:41:01 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gYrGa-0006Zs-Ms for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:40:58 -0500 Received: from smtp03.citrix.com ([162.221.156.55]:44677) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gYrGa-0006YC-Ds; Mon, 17 Dec 2018 06:40:56 -0500 X-IronPort-AV: E=Sophos;i="5.56,365,1539648000"; d="scan'208";a="73532591" From: Paul Durrant To: , , Date: Mon, 17 Dec 2018 11:40:33 +0000 Message-ID: <1545046848-14891-4-git-send-email-paul.durrant@citrix.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> References: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 162.221.156.55 Subject: [Qemu-devel] [PATCH v5 03/18] xen: introduce 'xen-block', 'xen-disk' and 'xen-cdrom' X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Paul Durrant , Stefano Stabellini , Max Reitz Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This patch adds new XenDevice-s: 'xen-disk' and 'xen-cdrom', both derived from a common 'xen-block' parent type. These will eventually replace the 'xen_disk' (note the underscore rather than hyphen) legacy PV backend but it is illustrative to build up the implementation incrementally, along with the XenBus/XenDevice framework. Subsequent patches will therefore add to these devices' implementation as new features are added to the framework. After this patch has been applied it is possible to instantiate new 'xen-disk' or 'xen-cdrom' devices with a single 'vdev' parameter, which accepts values adhering to the Xen VBD naming scheme [1]. For example, a command-line instantiation of a xen-disk can be done with an argument similar to the following: -device xen-disk,vdev=hda The implementation of the vdev parameter formulates the appropriate VBD number for use in the PV protocol. [1] https://xenbits.xen.org/docs/unstable/man/xen-vbd-interface.7.html Signed-off-by: Paul Durrant Reviewed-by: Anthony Perard --- Cc: Kevin Wolf Cc: Max Reitz Cc: Stefano Stabellini v5: - Introduce properties sub-structure (which will be useful later) - Keeping Anthony's R-b from v4 since change is trivial v3: - Fix vdev parsing again, and vdev formatting this time - Remove an unnecessary local_err v2: - Fix boilerplate - Fix vdev parsing - Change name from 'xen-qdisk' to 'xen-block', make abstract, and split off 'xen-disk' and 'xen-cdrom' as concrete sub-types --- MAINTAINERS | 2 +- hw/block/Makefile.objs | 1 + hw/block/trace-events | 8 ++ hw/block/xen-block.c | 343 +++++++++++++++++++++++++++++++++++++++++++++ include/hw/xen/xen-block.h | 73 ++++++++++ 5 files changed, 426 insertions(+), 1 deletion(-) create mode 100644 hw/block/xen-block.c create mode 100644 include/hw/xen/xen-block.h diff --git a/MAINTAINERS b/MAINTAINERS index 63effdc..dd728c3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -403,7 +403,7 @@ F: hw/9pfs/xen-9p-backend.c F: hw/char/xen_console.c F: hw/display/xenfb.c F: hw/net/xen_nic.c -F: hw/block/xen_* +F: hw/block/xen* F: hw/xen/ F: hw/xenpv/ F: hw/i386/xen/ diff --git a/hw/block/Makefile.objs b/hw/block/Makefile.objs index 53ce575..f34813a 100644 --- a/hw/block/Makefile.objs +++ b/hw/block/Makefile.objs @@ -4,6 +4,7 @@ common-obj-$(CONFIG_SSI_M25P80) += m25p80.o common-obj-$(CONFIG_NAND) += nand.o common-obj-$(CONFIG_PFLASH_CFI01) += pflash_cfi01.o common-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o +common-obj-$(CONFIG_XEN) += xen-block.o common-obj-$(CONFIG_XEN) += xen_disk.o common-obj-$(CONFIG_ECC) += ecc.o common-obj-$(CONFIG_ONENAND) += onenand.o diff --git a/hw/block/trace-events b/hw/block/trace-events index 335c092..4afbd62 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -127,3 +127,11 @@ xen_disk_init(char *name) "%s" xen_disk_connect(char *name) "%s" xen_disk_disconnect(char *name) "%s" xen_disk_free(char *name) "%s" + +# hw/block/xen-block.c +xen_block_realize(const char *type, uint32_t disk, uint32_t partition) "%s d%up%u" +xen_block_unrealize(const char *type, uint32_t disk, uint32_t partition) "%s d%up%u" +xen_disk_realize(void) "" +xen_disk_unrealize(void) "" +xen_cdrom_realize(void) "" +xen_cdrom_unrealize(void) "" diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c new file mode 100644 index 0000000..8e78b6a --- /dev/null +++ b/hw/block/xen-block.c @@ -0,0 +1,343 @@ +/* + * Copyright (c) 2018 Citrix Systems Inc. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/cutils.h" +#include "qapi/error.h" +#include "qapi/visitor.h" +#include "hw/hw.h" +#include "hw/xen/xen-block.h" +#include "trace.h" + +static void xen_block_unrealize(XenDevice *xendev, Error **errp) +{ + XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev); + XenBlockDeviceClass *blockdev_class = + XEN_BLOCK_DEVICE_GET_CLASS(xendev); + const char *type = object_get_typename(OBJECT(blockdev)); + XenBlockVdev *vdev = &blockdev->props.vdev; + + if (vdev->type == XEN_BLOCK_VDEV_TYPE_INVALID) { + return; + } + + trace_xen_block_unrealize(type, vdev->disk, vdev->partition); + + if (blockdev_class->unrealize) { + blockdev_class->unrealize(blockdev, errp); + } +} + +static void xen_block_realize(XenDevice *xendev, Error **errp) +{ + XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev); + XenBlockDeviceClass *blockdev_class = + XEN_BLOCK_DEVICE_GET_CLASS(xendev); + const char *type = object_get_typename(OBJECT(blockdev)); + XenBlockVdev *vdev = &blockdev->props.vdev; + Error *local_err = NULL; + + if (vdev->type == XEN_BLOCK_VDEV_TYPE_INVALID) { + error_setg(errp, "vdev property not set"); + return; + } + + trace_xen_block_realize(type, vdev->disk, vdev->partition); + + if (blockdev_class->realize) { + blockdev_class->realize(blockdev, &local_err); + if (local_err) { + error_propagate(errp, local_err); + } + } +} + +static char *disk_to_vbd_name(unsigned int disk) +{ + char *name, *prefix = (disk >= 26) ? + disk_to_vbd_name((disk / 26) - 1) : g_strdup(""); + + name = g_strdup_printf("%s%c", prefix, 'a' + disk % 26); + g_free(prefix); + + return name; +} + +static void xen_block_get_vdev(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + XenBlockVdev *vdev = qdev_get_prop_ptr(dev, prop); + char *str; + + switch (vdev->type) { + case XEN_BLOCK_VDEV_TYPE_DP: + str = g_strdup_printf("d%lup%lu", vdev->disk, vdev->partition); + break; + + case XEN_BLOCK_VDEV_TYPE_XVD: + case XEN_BLOCK_VDEV_TYPE_HD: + case XEN_BLOCK_VDEV_TYPE_SD: { + char *name = disk_to_vbd_name(vdev->disk); + + str = g_strdup_printf("%s%s%lu", + (vdev->type == XEN_BLOCK_VDEV_TYPE_XVD) ? + "xvd" : + (vdev->type == XEN_BLOCK_VDEV_TYPE_HD) ? + "hd" : + "sd", + name, vdev->partition); + g_free(name); + break; + } + default: + error_setg(errp, "invalid vdev type"); + return; + } + + visit_type_str(v, name, &str, errp); + g_free(str); +} + +static unsigned int vbd_name_to_disk(const char *name, const char **endp) +{ + unsigned int disk = 0; + + while (*name != '\0') { + if (!g_ascii_isalpha(*name) || !g_ascii_islower(*name)) { + break; + } + + disk *= 26; + disk += *name++ - 'a' + 1; + } + *endp = name; + + return disk - 1; +} + +static void xen_block_set_vdev(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + XenBlockVdev *vdev = qdev_get_prop_ptr(dev, prop); + Error *local_err = NULL; + char *str, *p; + const char *end; + + if (dev->realized) { + qdev_prop_set_after_realize(dev, name, errp); + return; + } + + visit_type_str(v, name, &str, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + p = strchr(str, 'd'); + if (!p) { + goto invalid; + } + + *p++ = '\0'; + if (*str == '\0') { + vdev->type = XEN_BLOCK_VDEV_TYPE_DP; + } else if (strcmp(str, "xv") == 0) { + vdev->type = XEN_BLOCK_VDEV_TYPE_XVD; + } else if (strcmp(str, "h") == 0) { + vdev->type = XEN_BLOCK_VDEV_TYPE_HD; + } else if (strcmp(str, "s") == 0) { + vdev->type = XEN_BLOCK_VDEV_TYPE_SD; + } else { + goto invalid; + } + + if (vdev->type == XEN_BLOCK_VDEV_TYPE_DP) { + if (qemu_strtoul(p, &end, 10, &vdev->disk)) { + goto invalid; + } + + if (*end == 'p') { + p = (char *) ++end; + if (*end == '\0') { + goto invalid; + } + } + } else { + vdev->disk = vbd_name_to_disk(p, &end); + } + + if (*end != '\0') { + p = (char *)end; + + if (qemu_strtoul(p, &end, 10, &vdev->partition)) { + goto invalid; + } + + if (*end != '\0') { + goto invalid; + } + } else { + vdev->partition = 0; + } + + switch (vdev->type) { + case XEN_BLOCK_VDEV_TYPE_DP: + case XEN_BLOCK_VDEV_TYPE_XVD: + if (vdev->disk < (1 << 4) && vdev->partition < (1 << 4)) { + vdev->number = (202 << 8) | (vdev->disk << 4) | + vdev->partition; + } else if (vdev->disk < (1 << 20) && vdev->partition < (1 << 8)) { + vdev->number = (1 << 28) | (vdev->disk << 8) | + vdev->partition; + } else { + goto invalid; + } + break; + + case XEN_BLOCK_VDEV_TYPE_HD: + if ((vdev->disk == 0 || vdev->disk == 1) && + vdev->partition < (1 << 6)) { + vdev->number = (3 << 8) | (vdev->disk << 6) | vdev->partition; + } else if ((vdev->disk == 2 || vdev->disk == 3) && + vdev->partition < (1 << 6)) { + vdev->number = (22 << 8) | ((vdev->disk - 2) << 6) | + vdev->partition; + } else { + goto invalid; + } + break; + + case XEN_BLOCK_VDEV_TYPE_SD: + if (vdev->disk < (1 << 4) && vdev->partition < (1 << 4)) { + vdev->number = (8 << 8) | (vdev->disk << 4) | vdev->partition; + } else { + goto invalid; + } + break; + + default: + goto invalid; + } + + g_free(str); + return; + +invalid: + error_setg(errp, "invalid virtual disk specifier"); + + vdev->type = XEN_BLOCK_VDEV_TYPE_INVALID; + g_free(str); +} + +/* + * This property deals with 'vdev' names adhering to the Xen VBD naming + * scheme described in: + * + * https://xenbits.xen.org/docs/unstable/man/xen-vbd-interface.7.html + */ +const PropertyInfo xen_block_prop_vdev = { + .name = "str", + .description = "Virtual Disk specifier: d*p*/xvd*/hd*/sd*", + .get = xen_block_get_vdev, + .set = xen_block_set_vdev, +}; + +static Property xen_block_props[] = { + DEFINE_PROP("vdev", XenBlockDevice, props.vdev, + xen_block_prop_vdev, XenBlockVdev), + DEFINE_PROP_END_OF_LIST() +}; + +static void xen_block_class_init(ObjectClass *class, void *data) +{ + DeviceClass *dev_class = DEVICE_CLASS(class); + XenDeviceClass *xendev_class = XEN_DEVICE_CLASS(class); + + xendev_class->realize = xen_block_realize; + xendev_class->unrealize = xen_block_unrealize; + + dev_class->props = xen_block_props; +} + +static const TypeInfo xen_block_type_info = { + .name = TYPE_XEN_BLOCK_DEVICE, + .parent = TYPE_XEN_DEVICE, + .instance_size = sizeof(XenBlockDevice), + .abstract = true, + .class_size = sizeof(XenBlockDeviceClass), + .class_init = xen_block_class_init, +}; + +static void xen_disk_unrealize(XenBlockDevice *blockdev, Error **errp) +{ + trace_xen_disk_unrealize(); +} + +static void xen_disk_realize(XenBlockDevice *blockdev, Error **errp) +{ + trace_xen_disk_realize(); +} + +static void xen_disk_class_init(ObjectClass *class, void *data) +{ + DeviceClass *dev_class = DEVICE_CLASS(class); + XenBlockDeviceClass *blockdev_class = XEN_BLOCK_DEVICE_CLASS(class); + + blockdev_class->realize = xen_disk_realize; + blockdev_class->unrealize = xen_disk_unrealize; + + dev_class->desc = "Xen Disk Device"; +} + +static const TypeInfo xen_disk_type_info = { + .name = TYPE_XEN_DISK_DEVICE, + .parent = TYPE_XEN_BLOCK_DEVICE, + .instance_size = sizeof(XenDiskDevice), + .class_init = xen_disk_class_init, +}; + +static void xen_cdrom_unrealize(XenBlockDevice *blockdev, Error **errp) +{ + trace_xen_cdrom_unrealize(); +} + +static void xen_cdrom_realize(XenBlockDevice *blockdev, Error **errp) +{ + trace_xen_cdrom_realize(); +} + +static void xen_cdrom_class_init(ObjectClass *class, void *data) +{ + DeviceClass *dev_class = DEVICE_CLASS(class); + XenBlockDeviceClass *blockdev_class = XEN_BLOCK_DEVICE_CLASS(class); + + blockdev_class->realize = xen_cdrom_realize; + blockdev_class->unrealize = xen_cdrom_unrealize; + + dev_class->desc = "Xen CD-ROM Device"; +} + +static const TypeInfo xen_cdrom_type_info = { + .name = TYPE_XEN_CDROM_DEVICE, + .parent = TYPE_XEN_BLOCK_DEVICE, + .instance_size = sizeof(XenCDRomDevice), + .class_init = xen_cdrom_class_init, +}; + +static void xen_block_register_types(void) +{ + type_register_static(&xen_block_type_info); + type_register_static(&xen_disk_type_info); + type_register_static(&xen_cdrom_type_info); +} + +type_init(xen_block_register_types) diff --git a/include/hw/xen/xen-block.h b/include/hw/xen/xen-block.h new file mode 100644 index 0000000..2941325 --- /dev/null +++ b/include/hw/xen/xen-block.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2018 Citrix Systems Inc. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef HW_XEN_BLOCK_H +#define HW_XEN_BLOCK_H + +#include "hw/xen/xen-bus.h" + +typedef enum XenBlockVdevType { + XEN_BLOCK_VDEV_TYPE_INVALID, + XEN_BLOCK_VDEV_TYPE_DP, + XEN_BLOCK_VDEV_TYPE_XVD, + XEN_BLOCK_VDEV_TYPE_HD, + XEN_BLOCK_VDEV_TYPE_SD, + XEN_BLOCK_VDEV_TYPE__MAX +} XenBlockVdevType; + +typedef struct XenBlockVdev { + XenBlockVdevType type; + unsigned long disk; + unsigned long partition; + unsigned long number; +} XenBlockVdev; + +typedef struct XenBlockProperties { + XenBlockVdev vdev; +} XenBlockProperties; + +typedef struct XenBlockDevice { + XenDevice xendev; + XenBlockProperties props; +} XenBlockDevice; + +typedef void (*XenBlockDeviceRealize)(XenBlockDevice *blockdev, Error **errp); +typedef void (*XenBlockDeviceUnrealize)(XenBlockDevice *blockdev, Error **errp); + +typedef struct XenBlockDeviceClass { + /*< private >*/ + XenDeviceClass parent_class; + /*< public >*/ + XenBlockDeviceRealize realize; + XenBlockDeviceUnrealize unrealize; +} XenBlockDeviceClass; + +#define TYPE_XEN_BLOCK_DEVICE "xen-block" +#define XEN_BLOCK_DEVICE(obj) \ + OBJECT_CHECK(XenBlockDevice, (obj), TYPE_XEN_BLOCK_DEVICE) +#define XEN_BLOCK_DEVICE_CLASS(class) \ + OBJECT_CLASS_CHECK(XenBlockDeviceClass, (class), TYPE_XEN_BLOCK_DEVICE) +#define XEN_BLOCK_DEVICE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(XenBlockDeviceClass, (obj), TYPE_XEN_BLOCK_DEVICE) + +typedef struct XenDiskDevice { + XenBlockDevice blockdev; +} XenDiskDevice; + +#define TYPE_XEN_DISK_DEVICE "xen-disk" +#define XEN_DISK_DEVICE(obj) \ + OBJECT_CHECK(XenDiskDevice, (obj), TYPE_XEN_DISK_DEVICE) + +typedef struct XenCDRomDevice { + XenBlockDevice blockdev; +} XenCDRomDevice; + +#define TYPE_XEN_CDROM_DEVICE "xen-cdrom" +#define XEN_CDROM_DEVICE(obj) \ + OBJECT_CHECK(XenCDRomDevice, (obj), TYPE_XEN_CDROM_DEVICE) + +#endif /* HW_XEN_BLOCK_H */ From patchwork Mon Dec 17 11:40:34 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 1014432 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=citrix.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 43JK9K1gBGz9s2P for ; Mon, 17 Dec 2018 22:45:57 +1100 (AEDT) Received: from localhost ([::1]:46177 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrLO-0007bW-Rk for incoming@patchwork.ozlabs.org; Mon, 17 Dec 2018 06:45:54 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:52876) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrGe-000494-H7 for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:41:04 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gYrGb-0006aG-BP for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:41:00 -0500 Received: from smtp03.citrix.com ([162.221.156.55]:44677) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gYrGb-0006YC-0K; Mon, 17 Dec 2018 06:40:57 -0500 X-IronPort-AV: E=Sophos;i="5.56,365,1539648000"; d="scan'208";a="73532595" From: Paul Durrant To: , , Date: Mon, 17 Dec 2018 11:40:34 +0000 Message-ID: <1545046848-14891-5-git-send-email-paul.durrant@citrix.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> References: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 162.221.156.55 Subject: [Qemu-devel] [PATCH v5 04/18] xen: create xenstore areas for XenDevice-s X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Paul Durrant , Stefano Stabellini , Max Reitz Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This patch adds a new source module, xen-bus-helper.c, which builds on basic libxenstore primitives to provide functions to create (setting permissions appropriately) and destroy xenstore areas, and functions to 'printf' and 'scanf' nodes therein. The main xen-bus code then uses these primitives [1] to initialize and destroy the frontend and backend areas for a XenDevice during realize and unrealize respectively. The 'xen-block' implementation is extended with a 'get_name' method that returns the VBD number. This number is required to 'name' the xenstore areas. NOTE: An exit handler is also added to make sure the xenstore areas are cleaned up if QEMU terminates without devices being unrealized. [1] The 'scanf' functions are actually not yet needed, but they will be needed by code delivered in subsequent patches. Signed-off-by: Paul Durrant Reviewed-by: Anthony Perard --- Cc: Stefano Stabellini Cc: Kevin Wolf Cc: Max Reitz v5: - Re-base v3: - Add transaction id parameters to xen-bus-helper functions - Not added Anthony's R-b because of change v2: - Fix boilerplate - Add error pointers to all xs_node... helpers - Add GCC_FMT_ATTR to declarations of printf-like helpers --- hw/block/xen-block.c | 9 ++ hw/xen/Makefile.objs | 2 +- hw/xen/trace-events | 12 +- hw/xen/xen-bus-helper.c | 150 +++++++++++++++++++ hw/xen/xen-bus.c | 321 +++++++++++++++++++++++++++++++++++++++- include/hw/xen/xen-bus-helper.h | 39 +++++ include/hw/xen/xen-bus.h | 12 ++ 7 files changed, 540 insertions(+), 5 deletions(-) create mode 100644 hw/xen/xen-bus-helper.c create mode 100644 include/hw/xen/xen-bus-helper.h diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c index 8e78b6a..d27a286 100644 --- a/hw/block/xen-block.c +++ b/hw/block/xen-block.c @@ -13,6 +13,14 @@ #include "hw/xen/xen-block.h" #include "trace.h" +static char *xen_block_get_name(XenDevice *xendev, Error **errp) +{ + XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev); + XenBlockVdev *vdev = &blockdev->props.vdev; + + return g_strdup_printf("%lu", vdev->number); +} + static void xen_block_unrealize(XenDevice *xendev, Error **errp) { XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev); @@ -262,6 +270,7 @@ static void xen_block_class_init(ObjectClass *class, void *data) DeviceClass *dev_class = DEVICE_CLASS(class); XenDeviceClass *xendev_class = XEN_DEVICE_CLASS(class); + xendev_class->get_name = xen_block_get_name; xendev_class->realize = xen_block_realize; xendev_class->unrealize = xen_block_unrealize; diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs index d9d6d7b..77c0868 100644 --- a/hw/xen/Makefile.objs +++ b/hw/xen/Makefile.objs @@ -1,5 +1,5 @@ # xen backend driver support -common-obj-$(CONFIG_XEN) += xen-legacy-backend.o xen_devconfig.o xen_pvdev.o xen-common.o xen-bus.o +common-obj-$(CONFIG_XEN) += xen-legacy-backend.o xen_devconfig.o xen_pvdev.o xen-common.o xen-bus.o xen-bus-helper.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_graphics.o xen_pt_msi.o diff --git a/hw/xen/trace-events b/hw/xen/trace-events index 0172cd4..75dc226 100644 --- a/hw/xen/trace-events +++ b/hw/xen/trace-events @@ -16,5 +16,13 @@ xen_domid_restrict(int err) "err: %u" # include/hw/xen/xen-bus.c xen_bus_realize(void) "" xen_bus_unrealize(void) "" -xen_device_realize(const char *type) "type: %s" -xen_device_unrealize(const char *type) "type: %s" +xen_device_realize(const char *type, char *name) "type: %s name: %s" +xen_device_unrealize(const char *type, char *name) "type: %s name: %s" +xen_device_backend_state(const char *type, char *name, const char *state) "type: %s name: %s -> %s" +xen_device_frontend_state(const char *type, char *name, const char *state) "type: %s name: %s -> %s" + +# include/hw/xen/xen-bus-helper.c +xs_node_create(const char *node) "%s" +xs_node_destroy(const char *node) "%s" +xs_node_vprintf(char *path, char *value) "%s %s" +xs_node_vscanf(char *path, char *value) "%s %s" diff --git a/hw/xen/xen-bus-helper.c b/hw/xen/xen-bus-helper.c new file mode 100644 index 0000000..15b3ad8 --- /dev/null +++ b/hw/xen/xen-bus-helper.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2018 Citrix Systems Inc. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/xen/xen.h" +#include "hw/xen/xen-bus.h" +#include "hw/xen/xen-bus-helper.h" +#include "qapi/error.h" + +#include + +struct xs_state { + enum xenbus_state statenum; + const char *statestr; +}; +#define XS_STATE(state) { state, #state } + +static struct xs_state xs_state[] = { + XS_STATE(XenbusStateUnknown), + XS_STATE(XenbusStateInitialising), + XS_STATE(XenbusStateInitWait), + XS_STATE(XenbusStateInitialised), + XS_STATE(XenbusStateConnected), + XS_STATE(XenbusStateClosing), + XS_STATE(XenbusStateClosed), + XS_STATE(XenbusStateReconfiguring), + XS_STATE(XenbusStateReconfigured), +}; + +#undef XS_STATE + +const char *xs_strstate(enum xenbus_state state) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(xs_state); i++) { + if (xs_state[i].statenum == state) { + return xs_state[i].statestr; + } + } + + return "INVALID"; +} + +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) +{ + trace_xs_node_create(node); + + if (!xs_write(xsh, tid, node, "", 0)) { + 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); + } +} + +void xs_node_destroy(struct xs_handle *xsh, xs_transaction_t tid, + const char *node, Error **errp) +{ + trace_xs_node_destroy(node); + + if (!xs_rm(xsh, tid, node)) { + error_setg_errno(errp, errno, "failed to destroy node '%s'", node); + } +} + +void xs_node_vprintf(struct xs_handle *xsh, xs_transaction_t tid, + const char *node, const char *key, Error **errp, + const char *fmt, va_list ap) +{ + char *path, *value; + int len; + + path = (strlen(node) != 0) ? g_strdup_printf("%s/%s", node, key) : + g_strdup(key); + len = g_vasprintf(&value, fmt, ap); + + trace_xs_node_vprintf(path, value); + + if (!xs_write(xsh, tid, path, value, len)) { + error_setg_errno(errp, errno, "failed to write '%s' to '%s'", + value, path); + } + + g_free(value); + g_free(path); +} + +void xs_node_printf(struct xs_handle *xsh, xs_transaction_t tid, + const char *node, const char *key, Error **errp, + const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + xs_node_vprintf(xsh, tid, node, key, errp, fmt, ap); + va_end(ap); +} + +int xs_node_vscanf(struct xs_handle *xsh, xs_transaction_t tid, + const char *node, const char *key, Error **errp, + const char *fmt, va_list ap) +{ + char *path, *value; + int rc; + + path = (strlen(node) != 0) ? g_strdup_printf("%s/%s", node, key) : + g_strdup(key); + value = xs_read(xsh, tid, path, NULL); + + trace_xs_node_vscanf(path, value); + + if (value) { + rc = vsscanf(value, fmt, ap); + } else { + error_setg_errno(errp, errno, "failed to read from '%s'", + path); + rc = EOF; + } + + free(value); + g_free(path); + + return rc; +} + +int xs_node_scanf(struct xs_handle *xsh, xs_transaction_t tid, + const char *node, const char *key, Error **errp, + const char *fmt, ...) +{ + va_list ap; + int rc; + + va_start(ap, fmt); + rc = xs_node_vscanf(xsh, tid, node, key, errp, fmt, ap); + va_end(ap); + + return rc; +} diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c index bc04da7..843fda2 100644 --- a/hw/xen/xen-bus.c +++ b/hw/xen/xen-bus.c @@ -8,24 +8,102 @@ #include "qemu/osdep.h" #include "hw/hw.h" #include "hw/sysbus.h" +#include "hw/xen/xen.h" #include "hw/xen/xen-bus.h" +#include "hw/xen/xen-bus-helper.h" +#include "monitor/monitor.h" #include "qapi/error.h" +#include "sysemu/sysemu.h" #include "trace.h" +static char *xen_device_get_backend_path(XenDevice *xendev) +{ + XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); + XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev); + const char *type = object_get_typename(OBJECT(xendev)); + const char *backend = xendev_class->backend; + + if (!backend) { + backend = type; + } + + return g_strdup_printf("/local/domain/%u/backend/%s/%u/%s", + xenbus->backend_id, backend, xendev->frontend_id, + xendev->name); +} + +static char *xen_device_get_frontend_path(XenDevice *xendev) +{ + XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev); + const char *type = object_get_typename(OBJECT(xendev)); + const char *device = xendev_class->device; + + if (!device) { + device = type; + } + + return g_strdup_printf("/local/domain/%u/device/%s/%s", + xendev->frontend_id, device, xendev->name); +} + +static void xen_bus_print_dev(Monitor *mon, DeviceState *dev, int indent) +{ + XenDevice *xendev = XEN_DEVICE(dev); + + monitor_printf(mon, "%*sname = '%s' frontend_id = %u\n", + indent, "", xendev->name, xendev->frontend_id); +} + +static char *xen_bus_get_dev_path(DeviceState *dev) +{ + return xen_device_get_backend_path(XEN_DEVICE(dev)); +} + static void xen_bus_unrealize(BusState *bus, Error **errp) { + XenBus *xenbus = XEN_BUS(bus); + trace_xen_bus_unrealize(); + + if (!xenbus->xsh) { + return; + } + + xs_close(xenbus->xsh); } static void xen_bus_realize(BusState *bus, Error **errp) { + XenBus *xenbus = XEN_BUS(bus); + unsigned int domid; + trace_xen_bus_realize(); + + xenbus->xsh = xs_open(0); + if (!xenbus->xsh) { + error_setg_errno(errp, errno, "failed xs_open"); + goto fail; + } + + if (xs_node_scanf(xenbus->xsh, XBT_NULL, "", /* domain root node */ + "domid", NULL, "%u", &domid) == 1) { + xenbus->backend_id = domid; + } else { + xenbus->backend_id = 0; /* Assume lack of node means dom0 */ + } + + return; + +fail: + xen_bus_unrealize(bus, &error_abort); } static void xen_bus_class_init(ObjectClass *class, void *data) { BusClass *bus_class = BUS_CLASS(class); + bus_class->print_dev = xen_bus_print_dev; + bus_class->get_dev_path = xen_bus_get_dev_path; bus_class->realize = xen_bus_realize; bus_class->unrealize = xen_bus_unrealize; } @@ -42,27 +120,241 @@ static const TypeInfo xen_bus_type_info = { }, }; +static void xen_device_backend_printf(XenDevice *xendev, const char *key, + const char *fmt, ...) +{ + XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); + Error *local_err = NULL; + va_list ap; + + g_assert(xenbus->xsh); + + va_start(ap, fmt); + xs_node_vprintf(xenbus->xsh, XBT_NULL, xendev->backend_path, key, + &local_err, fmt, ap); + va_end(ap); + + if (local_err) { + error_report_err(local_err); + } +} + +static void xen_device_backend_set_state(XenDevice *xendev, + enum xenbus_state state) +{ + const char *type = object_get_typename(OBJECT(xendev)); + + if (xendev->backend_state == state) { + return; + } + + trace_xen_device_backend_state(type, xendev->name, + xs_strstate(state)); + + xendev->backend_state = state; + xen_device_backend_printf(xendev, "state", "%u", state); +} + +static void xen_device_backend_create(XenDevice *xendev, Error **errp) +{ + XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); + struct xs_permissions perms[2]; + Error *local_err = NULL; + + xendev->backend_path = xen_device_get_backend_path(xendev); + + perms[0].id = xenbus->backend_id; + perms[0].perms = XS_PERM_NONE; + perms[1].id = xendev->frontend_id; + perms[1].perms = XS_PERM_READ; + + g_assert(xenbus->xsh); + + xs_node_create(xenbus->xsh, XBT_NULL, xendev->backend_path, perms, + ARRAY_SIZE(perms), &local_err); + if (local_err) { + error_propagate_prepend(errp, local_err, + "failed to create backend: "); + } +} + +static void xen_device_backend_destroy(XenDevice *xendev) +{ + XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); + Error *local_err = NULL; + + if (!xendev->backend_path) { + return; + } + + g_assert(xenbus->xsh); + + xs_node_destroy(xenbus->xsh, XBT_NULL, xendev->backend_path, + &local_err); + g_free(xendev->backend_path); + xendev->backend_path = NULL; + + if (local_err) { + error_report_err(local_err); + } +} + +static void xen_device_frontend_printf(XenDevice *xendev, const char *key, + const char *fmt, ...) +{ + XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); + Error *local_err = NULL; + va_list ap; + + g_assert(xenbus->xsh); + + va_start(ap, fmt); + xs_node_vprintf(xenbus->xsh, XBT_NULL, xendev->frontend_path, key, + &local_err, fmt, ap); + va_end(ap); + + if (local_err) { + error_report_err(local_err); + } +} + +static void xen_device_frontend_set_state(XenDevice *xendev, + enum xenbus_state state) +{ + const char *type = object_get_typename(OBJECT(xendev)); + + if (xendev->frontend_state == state) { + return; + } + + trace_xen_device_frontend_state(type, xendev->name, + xs_strstate(state)); + + xendev->frontend_state = state; + xen_device_frontend_printf(xendev, "state", "%u", state); +} + +static void xen_device_frontend_create(XenDevice *xendev, Error **errp) +{ + XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); + struct xs_permissions perms[2]; + Error *local_err = NULL; + + xendev->frontend_path = xen_device_get_frontend_path(xendev); + + perms[0].id = xendev->frontend_id; + perms[0].perms = XS_PERM_NONE; + perms[1].id = xenbus->backend_id; + perms[1].perms = XS_PERM_READ | XS_PERM_WRITE; + + g_assert(xenbus->xsh); + + xs_node_create(xenbus->xsh, XBT_NULL, xendev->frontend_path, perms, + ARRAY_SIZE(perms), &local_err); + if (local_err) { + error_propagate_prepend(errp, local_err, + "failed to create frontend: "); + } +} + +static void xen_device_frontend_destroy(XenDevice *xendev) +{ + XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); + Error *local_err = NULL; + + if (!xendev->frontend_path) { + return; + } + + g_assert(xenbus->xsh); + + xs_node_destroy(xenbus->xsh, XBT_NULL, xendev->frontend_path, + &local_err); + g_free(xendev->frontend_path); + xendev->frontend_path = NULL; + + if (local_err) { + error_report_err(local_err); + } +} + static void xen_device_unrealize(DeviceState *dev, Error **errp) { XenDevice *xendev = XEN_DEVICE(dev); XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev); const char *type = object_get_typename(OBJECT(xendev)); - trace_xen_device_unrealize(type); + if (!xendev->name) { + return; + } + + trace_xen_device_unrealize(type, xendev->name); + + if (xendev->exit.notify) { + qemu_remove_exit_notifier(&xendev->exit); + xendev->exit.notify = NULL; + } if (xendev_class->unrealize) { xendev_class->unrealize(xendev, errp); } + + xen_device_frontend_destroy(xendev); + xen_device_backend_destroy(xendev); + + g_free(xendev->name); + xendev->name = NULL; +} + +static void xen_device_exit(Notifier *n, void *data) +{ + XenDevice *xendev = container_of(n, XenDevice, exit); + + xen_device_unrealize(DEVICE(xendev), &error_abort); } static void xen_device_realize(DeviceState *dev, Error **errp) { XenDevice *xendev = XEN_DEVICE(dev); XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev); + XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); const char *type = object_get_typename(OBJECT(xendev)); Error *local_err = NULL; - trace_xen_device_realize(type); + if (xendev->frontend_id == DOMID_INVALID) { + xendev->frontend_id = xen_domid; + } + + if (xendev->frontend_id >= DOMID_FIRST_RESERVED) { + error_setg(errp, "invalid frontend-id"); + goto unrealize; + } + + if (!xendev_class->get_name) { + error_setg(errp, "get_name method not implemented"); + goto unrealize; + } + + xendev->name = xendev_class->get_name(xendev, &local_err); + if (local_err) { + error_propagate_prepend(errp, local_err, + "failed to get device name: "); + goto unrealize; + } + + trace_xen_device_realize(type, xendev->name); + + xen_device_backend_create(xendev, &local_err); + if (local_err) { + error_propagate(errp, local_err); + goto unrealize; + } + + xen_device_frontend_create(xendev, &local_err); + if (local_err) { + error_propagate(errp, local_err); + goto unrealize; + } if (xendev_class->realize) { xendev_class->realize(xendev, &local_err); @@ -72,18 +364,43 @@ static void xen_device_realize(DeviceState *dev, Error **errp) } } + xen_device_backend_printf(xendev, "frontend", "%s", + xendev->frontend_path); + xen_device_backend_printf(xendev, "frontend-id", "%u", + xendev->frontend_id); + xen_device_backend_printf(xendev, "online", "%u", 1); + xen_device_backend_printf(xendev, "hotplug-status", "connected"); + + xen_device_backend_set_state(xendev, XenbusStateInitWait); + + xen_device_frontend_printf(xendev, "backend", "%s", + xendev->backend_path); + xen_device_frontend_printf(xendev, "backend-id", "%u", + xenbus->backend_id); + + xen_device_frontend_set_state(xendev, XenbusStateInitialising); + + xendev->exit.notify = xen_device_exit; + qemu_add_exit_notifier(&xendev->exit); return; unrealize: xen_device_unrealize(dev, &error_abort); } +static Property xen_device_props[] = { + DEFINE_PROP_UINT16("frontend-id", XenDevice, frontend_id, + DOMID_INVALID), + DEFINE_PROP_END_OF_LIST() +}; + static void xen_device_class_init(ObjectClass *class, void *data) { DeviceClass *dev_class = DEVICE_CLASS(class); dev_class->realize = xen_device_realize; dev_class->unrealize = xen_device_unrealize; + dev_class->props = xen_device_props; dev_class->bus_type = TYPE_XEN_BUS; } diff --git a/include/hw/xen/xen-bus-helper.h b/include/hw/xen/xen-bus-helper.h new file mode 100644 index 0000000..5cd9c3d --- /dev/null +++ b/include/hw/xen/xen-bus-helper.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2018 Citrix Systems Inc. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef HW_XEN_BUS_HELPER_H +#define HW_XEN_BUS_HELPER_H + +#include "hw/xen/xen_common.h" + +const char *xs_strstate(enum xenbus_state state); + +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, + const char *node, Error **errp); + +/* 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, + const char *node, const char *key, Error **errp, + const char *fmt, va_list ap) + GCC_FMT_ATTR(6, 0); +void xs_node_printf(struct xs_handle *xsh, xs_transaction_t tid, + const char *node, const char *key, Error **errp, + const char *fmt, ...) + GCC_FMT_ATTR(6, 7); + +/* 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, + const char *node, const char *key, Error **errp, + const char *fmt, va_list ap); +int xs_node_scanf(struct xs_handle *xsh, xs_transaction_t tid, + const char *node, const char *key, Error **errp, + const char *fmt, ...); + +#endif /* HW_XEN_BUS_HELPER_H */ diff --git a/include/hw/xen/xen-bus.h b/include/hw/xen/xen-bus.h index 0cb1246..85a75d8 100644 --- a/include/hw/xen/xen-bus.h +++ b/include/hw/xen/xen-bus.h @@ -8,12 +8,19 @@ #ifndef HW_XEN_BUS_H #define HW_XEN_BUS_H +#include "hw/xen/xen_common.h" #include "hw/sysbus.h" typedef struct XenDevice { DeviceState qdev; + domid_t frontend_id; + char *name; + char *backend_path, *frontend_path; + enum xenbus_state backend_state, frontend_state; + Notifier exit; } XenDevice; +typedef char *(*XenDeviceGetName)(XenDevice *xendev, Error **errp); typedef void (*XenDeviceRealize)(XenDevice *xendev, Error **errp); typedef void (*XenDeviceUnrealize)(XenDevice *xendev, Error **errp); @@ -21,6 +28,9 @@ typedef struct XenDeviceClass { /*< private >*/ DeviceClass parent_class; /*< public >*/ + const char *backend; + const char *device; + XenDeviceGetName get_name; XenDeviceRealize realize; XenDeviceUnrealize unrealize; } XenDeviceClass; @@ -35,6 +45,8 @@ typedef struct XenDeviceClass { typedef struct XenBus { BusState qbus; + domid_t backend_id; + struct xs_handle *xsh; } XenBus; typedef struct XenBusClass { From patchwork Mon Dec 17 11:40:35 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 1014435 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=citrix.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 43JKFv34npz9s2P for ; Mon, 17 Dec 2018 22:49:55 +1100 (AEDT) Received: from localhost ([::1]:46202 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrPF-0002Hc-0l for incoming@patchwork.ozlabs.org; Mon, 17 Dec 2018 06:49:53 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:52854) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrGd-00048x-Oz for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:41:07 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gYrGb-0006a6-5C for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:40:59 -0500 Received: from smtp03.citrix.com ([162.221.156.55]:44686) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gYrGa-0006Yx-RQ; Mon, 17 Dec 2018 06:40:57 -0500 X-IronPort-AV: E=Sophos;i="5.56,365,1539648000"; d="scan'208";a="73532594" From: Paul Durrant To: , , Date: Mon, 17 Dec 2018 11:40:35 +0000 Message-ID: <1545046848-14891-6-git-send-email-paul.durrant@citrix.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> References: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 162.221.156.55 Subject: [Qemu-devel] [PATCH v5 05/18] xen: add xenstore watcher infrastructure X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Paul Durrant , Stefano Stabellini , Max Reitz Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" A Xen PV frontend communicates its state to the PV backend by writing to the 'state' key in the frontend area in xenstore. It is therefore necessary for a XenDevice implementation to be notified whenever the value of this key changes. This patch adds code to do this as follows: - an 'fd handler' is registered on the libxenstore handle which will be triggered whenever a 'watch' event occurs - primitives are added to xen-bus-helper to add or remove watch events - a list of Notifier objects is added to XenBus to provide a mechanism to call the appropriate 'watch handler' when its associated event occurs The xen-block implementation is extended with a 'frontend_changed' method, which calls as-yet stub 'connect' and 'disconnect' functions when the relevant frontend state transitions occur. A subsequent patch will supply a full implementation for these functions. Signed-off-by: Paul Durrant Reviewed-by: Anthony Perard --- Cc: Kevin Wolf Cc: Max Reitz Cc: Stefano Stabellini v5: - Re-base v3: - Remove unnecessary instances of local_err v2: - Don't crash when xen_block_disconnect() fails - Check xs_unwatch() for error - Add new_watch() and free_watch() utility functions - Use xs_check_watch() rather than xs_read_watch() --- hw/block/trace-events | 2 + hw/block/xen-block.c | 70 +++++++++++++ hw/xen/trace-events | 6 ++ hw/xen/xen-bus-helper.c | 34 +++++++ hw/xen/xen-bus.c | 211 +++++++++++++++++++++++++++++++++++++++- include/hw/xen/xen-bus-helper.h | 6 ++ include/hw/xen/xen-bus.h | 15 +++ 7 files changed, 342 insertions(+), 2 deletions(-) diff --git a/hw/block/trace-events b/hw/block/trace-events index 4afbd62..89e2583 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -130,6 +130,8 @@ xen_disk_free(char *name) "%s" # hw/block/xen-block.c xen_block_realize(const char *type, uint32_t disk, uint32_t partition) "%s d%up%u" +xen_block_connect(const char *type, uint32_t disk, uint32_t partition) "%s d%up%u" +xen_block_disconnect(const char *type, uint32_t disk, uint32_t partition) "%s d%up%u" xen_block_unrealize(const char *type, uint32_t disk, uint32_t partition) "%s d%up%u" xen_disk_realize(void) "" xen_disk_unrealize(void) "" diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c index d27a286..3a963b0 100644 --- a/hw/block/xen-block.c +++ b/hw/block/xen-block.c @@ -21,6 +21,24 @@ static char *xen_block_get_name(XenDevice *xendev, Error **errp) return g_strdup_printf("%lu", vdev->number); } +static void xen_block_disconnect(XenDevice *xendev, Error **errp) +{ + XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev); + const char *type = object_get_typename(OBJECT(blockdev)); + XenBlockVdev *vdev = &blockdev->props.vdev; + + trace_xen_block_disconnect(type, vdev->disk, vdev->partition); +} + +static void xen_block_connect(XenDevice *xendev, Error **errp) +{ + XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev); + const char *type = object_get_typename(OBJECT(blockdev)); + XenBlockVdev *vdev = &blockdev->props.vdev; + + trace_xen_block_connect(type, vdev->disk, vdev->partition); +} + static void xen_block_unrealize(XenDevice *xendev, Error **errp) { XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev); @@ -35,6 +53,9 @@ static void xen_block_unrealize(XenDevice *xendev, Error **errp) trace_xen_block_unrealize(type, vdev->disk, vdev->partition); + /* Disconnect from the frontend in case this has not already happened */ + xen_block_disconnect(xendev, NULL); + if (blockdev_class->unrealize) { blockdev_class->unrealize(blockdev, errp); } @@ -64,6 +85,54 @@ static void xen_block_realize(XenDevice *xendev, Error **errp) } } +static void xen_block_frontend_changed(XenDevice *xendev, + enum xenbus_state frontend_state, + Error **errp) +{ + enum xenbus_state backend_state = xen_device_backend_get_state(xendev); + Error *local_err = NULL; + + switch (frontend_state) { + case XenbusStateInitialised: + case XenbusStateConnected: + if (backend_state == XenbusStateConnected) { + break; + } + + xen_block_disconnect(xendev, &local_err); + if (local_err) { + error_propagate(errp, local_err); + break; + } + + xen_block_connect(xendev, &local_err); + if (local_err) { + error_propagate(errp, local_err); + break; + } + + xen_device_backend_set_state(xendev, XenbusStateConnected); + break; + + case XenbusStateClosing: + xen_device_backend_set_state(xendev, XenbusStateClosing); + break; + + case XenbusStateClosed: + xen_block_disconnect(xendev, &local_err); + if (local_err) { + error_propagate(errp, local_err); + break; + } + + xen_device_backend_set_state(xendev, XenbusStateClosed); + break; + + default: + break; + } +} + static char *disk_to_vbd_name(unsigned int disk) { char *name, *prefix = (disk >= 26) ? @@ -272,6 +341,7 @@ static void xen_block_class_init(ObjectClass *class, void *data) xendev_class->get_name = xen_block_get_name; xendev_class->realize = xen_block_realize; + xendev_class->frontend_changed = xen_block_frontend_changed; xendev_class->unrealize = xen_block_unrealize; dev_class->props = xen_block_props; diff --git a/hw/xen/trace-events b/hw/xen/trace-events index 75dc226..22055b5 100644 --- a/hw/xen/trace-events +++ b/hw/xen/trace-events @@ -16,13 +16,19 @@ xen_domid_restrict(int err) "err: %u" # include/hw/xen/xen-bus.c xen_bus_realize(void) "" xen_bus_unrealize(void) "" +xen_bus_add_watch(const char *node, const char *key, char *token) "node: %s key: %s token: %s" +xen_bus_remove_watch(const char *node, const char *key, char *token) "node: %s key: %s token: %s" +xen_bus_watch(const char *token) "token: %s" xen_device_realize(const char *type, char *name) "type: %s name: %s" xen_device_unrealize(const char *type, char *name) "type: %s name: %s" xen_device_backend_state(const char *type, char *name, const char *state) "type: %s name: %s -> %s" xen_device_frontend_state(const char *type, char *name, const char *state) "type: %s name: %s -> %s" +xen_device_frontend_changed(const char *type, char *name) "type: %s name: %s" # include/hw/xen/xen-bus-helper.c xs_node_create(const char *node) "%s" xs_node_destroy(const char *node) "%s" xs_node_vprintf(char *path, char *value) "%s %s" xs_node_vscanf(char *path, char *value) "%s %s" +xs_node_watch(char *path) "%s" +xs_node_unwatch(char *path) "%s" diff --git a/hw/xen/xen-bus-helper.c b/hw/xen/xen-bus-helper.c index 15b3ad8..5f7a4b2 100644 --- a/hw/xen/xen-bus-helper.c +++ b/hw/xen/xen-bus-helper.c @@ -148,3 +148,37 @@ int xs_node_scanf(struct xs_handle *xsh, xs_transaction_t tid, return rc; } + +void xs_node_watch(struct xs_handle *xsh, const char *node, const char *key, + char *token, Error **errp) +{ + char *path; + + path = (strlen(node) != 0) ? g_strdup_printf("%s/%s", node, key) : + g_strdup(key); + + trace_xs_node_watch(path); + + if (!xs_watch(xsh, path, token)) { + error_setg_errno(errp, errno, "failed to watch node '%s'", path); + } + + g_free(path); +} + +void xs_node_unwatch(struct xs_handle *xsh, const char *node, + const char *key, const char *token, Error **errp) +{ + char *path; + + path = (strlen(node) != 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); +} diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c index 843fda2..5e19592 100644 --- a/hw/xen/xen-bus.c +++ b/hw/xen/xen-bus.c @@ -6,6 +6,8 @@ */ #include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "qemu/uuid.h" #include "hw/hw.h" #include "hw/sysbus.h" #include "hw/xen/xen.h" @@ -59,6 +61,87 @@ static char *xen_bus_get_dev_path(DeviceState *dev) return xen_device_get_backend_path(XEN_DEVICE(dev)); } +struct XenWatch { + char *node, *key; + char *token; + XenWatchHandler handler; + void *opaque; + Notifier notifier; +}; + +static void watch_notify(Notifier *n, void *data) +{ + XenWatch *watch = container_of(n, XenWatch, notifier); + const char *token = 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 = g_new0(XenWatch, 1); + QemuUUID uuid; + + qemu_uuid_generate(&uuid); + + watch->token = qemu_uuid_unparse_strdup(&uuid); + watch->node = g_strdup(node); + watch->key = g_strdup(key); + watch->handler = handler; + watch->opaque = opaque; + watch->notifier.notify = 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); +} + +static XenWatch *xen_bus_add_watch(XenBus *xenbus, const char *node, + const char *key, XenWatchHandler handler, + void *opaque, Error **errp) +{ + XenWatch *watch = new_watch(node, key, handler, opaque); + Error *local_err = NULL; + + trace_xen_bus_add_watch(watch->node, watch->key, watch->token); + + notifier_list_add(&xenbus->watch_notifiers, &watch->notifier); + + xs_node_watch(xenbus->xsh, node, key, watch->token, &local_err); + if (local_err) { + error_propagate(errp, local_err); + + notifier_remove(&watch->notifier); + free_watch(watch); + + return NULL; + } + + return watch; +} + +static void xen_bus_remove_watch(XenBus *xenbus, XenWatch *watch, + Error **errp) +{ + trace_xen_bus_remove_watch(watch->node, watch->key, watch->token); + + xs_node_unwatch(xenbus->xsh, watch->node, watch->key, watch->token, + errp); + + notifier_remove(&watch->notifier); + free_watch(watch); +} + static void xen_bus_unrealize(BusState *bus, Error **errp) { XenBus *xenbus = XEN_BUS(bus); @@ -69,9 +152,33 @@ static void xen_bus_unrealize(BusState *bus, Error **errp) return; } + qemu_set_fd_handler(xs_fileno(xenbus->xsh), NULL, NULL, NULL); + xs_close(xenbus->xsh); } +static void xen_bus_watch(void *opaque) +{ + XenBus *xenbus = opaque; + char **v; + const char *token; + + g_assert(xenbus->xsh); + + v = xs_check_watch(xenbus->xsh); + if (!v) { + return; + } + + token = v[XS_WATCH_TOKEN]; + + trace_xen_bus_watch(token); + + notifier_list_notify(&xenbus->watch_notifiers, (void *)token); + + free(v); +} + static void xen_bus_realize(BusState *bus, Error **errp) { XenBus *xenbus = XEN_BUS(bus); @@ -92,6 +199,9 @@ static void xen_bus_realize(BusState *bus, Error **errp) xenbus->backend_id = 0; /* Assume lack of node means dom0 */ } + notifier_list_init(&xenbus->watch_notifiers); + qemu_set_fd_handler(xs_fileno(xenbus->xsh), xen_bus_watch, NULL, + xenbus); return; fail: @@ -139,8 +249,25 @@ static void xen_device_backend_printf(XenDevice *xendev, const char *key, } } -static void xen_device_backend_set_state(XenDevice *xendev, - enum xenbus_state state) +static int xen_device_backend_scanf(XenDevice *xendev, const char *key, + const char *fmt, ...) +{ + XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); + va_list ap; + int rc; + + g_assert(xenbus->xsh); + + va_start(ap, fmt); + rc = xs_node_vscanf(xenbus->xsh, XBT_NULL, xendev->backend_path, key, + NULL, fmt, ap); + va_end(ap); + + return rc; +} + +void xen_device_backend_set_state(XenDevice *xendev, + enum xenbus_state state) { const char *type = object_get_typename(OBJECT(xendev)); @@ -155,6 +282,11 @@ static void xen_device_backend_set_state(XenDevice *xendev, xen_device_backend_printf(xendev, "state", "%u", state); } +enum xenbus_state xen_device_backend_get_state(XenDevice *xendev) +{ + return xendev->backend_state; +} + static void xen_device_backend_create(XenDevice *xendev, Error **errp) { XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); @@ -218,6 +350,23 @@ static void xen_device_frontend_printf(XenDevice *xendev, const char *key, } } +static int xen_device_frontend_scanf(XenDevice *xendev, const char *key, + const char *fmt, ...) +{ + XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); + va_list ap; + int rc; + + g_assert(xenbus->xsh); + + va_start(ap, fmt); + rc = xs_node_vscanf(xenbus->xsh, XBT_NULL, xendev->frontend_path, key, + NULL, fmt, ap); + va_end(ap); + + return rc; +} + static void xen_device_frontend_set_state(XenDevice *xendev, enum xenbus_state state) { @@ -234,6 +383,50 @@ static void xen_device_frontend_set_state(XenDevice *xendev, xen_device_frontend_printf(xendev, "state", "%u", state); } +static void xen_device_frontend_changed(void *opaque) +{ + XenDevice *xendev = opaque; + XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev); + const char *type = object_get_typename(OBJECT(xendev)); + enum xenbus_state state; + + trace_xen_device_frontend_changed(type, xendev->name); + + if (xen_device_frontend_scanf(xendev, "state", "%u", &state) != 1) { + state = XenbusStateUnknown; + } + + xen_device_frontend_set_state(xendev, state); + + if (xendev_class->frontend_changed) { + Error *local_err = NULL; + + xendev_class->frontend_changed(xendev, state, &local_err); + + if (local_err) { + error_reportf_err(local_err, "frontend change error: "); + } + } + + /* + * If a backend is still 'online' then its state should be cycled + * back round to InitWait in order for a new frontend instance to + * connect. This may happen when, for example, a frontend driver is + * re-installed or updated. + */ + if (xendev->backend_state == XenbusStateClosed) { + unsigned int online; + + if (xen_device_backend_scanf(xendev, "online", "%u", &online) != 1) { + online = 0; + } + + if (online) { + xen_device_backend_set_state(xendev, XenbusStateInitWait); + } + } +} + static void xen_device_frontend_create(XenDevice *xendev, Error **errp) { XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); @@ -254,6 +447,15 @@ static void xen_device_frontend_create(XenDevice *xendev, Error **errp) if (local_err) { error_propagate_prepend(errp, local_err, "failed to create frontend: "); + return; + } + + xendev->frontend_state_watch = + xen_bus_add_watch(xenbus, xendev->frontend_path, "state", + xen_device_frontend_changed, xendev, &local_err); + if (local_err) { + error_propagate_prepend(errp, local_err, + "failed to watch frontend state: "); } } @@ -262,6 +464,11 @@ static void xen_device_frontend_destroy(XenDevice *xendev) XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); Error *local_err = NULL; + if (xendev->frontend_state_watch) { + xen_bus_remove_watch(xenbus, xendev->frontend_state_watch, NULL); + xendev->frontend_state_watch = NULL; + } + if (!xendev->frontend_path) { return; } diff --git a/include/hw/xen/xen-bus-helper.h b/include/hw/xen/xen-bus-helper.h index 5cd9c3d..4c0f747 100644 --- a/include/hw/xen/xen-bus-helper.h +++ b/include/hw/xen/xen-bus-helper.h @@ -36,4 +36,10 @@ int xs_node_scanf(struct xs_handle *xsh, xs_transaction_t tid, const char *node, const char *key, Error **errp, const char *fmt, ...); +/* 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 *key, + char *token, Error **errp); +void xs_node_unwatch(struct xs_handle *xsh, const char *node, const char *key, + const char *token, Error **errp); + #endif /* HW_XEN_BUS_HELPER_H */ diff --git a/include/hw/xen/xen-bus.h b/include/hw/xen/xen-bus.h index 85a75d8..df73674 100644 --- a/include/hw/xen/xen-bus.h +++ b/include/hw/xen/xen-bus.h @@ -10,6 +10,11 @@ #include "hw/xen/xen_common.h" #include "hw/sysbus.h" +#include "qemu/notify.h" + +typedef void (*XenWatchHandler)(void *opaque); + +typedef struct XenWatch XenWatch; typedef struct XenDevice { DeviceState qdev; @@ -18,10 +23,14 @@ typedef struct XenDevice { char *backend_path, *frontend_path; enum xenbus_state backend_state, frontend_state; Notifier exit; + XenWatch *frontend_state_watch; } XenDevice; typedef char *(*XenDeviceGetName)(XenDevice *xendev, Error **errp); typedef void (*XenDeviceRealize)(XenDevice *xendev, Error **errp); +typedef void (*XenDeviceFrontendChanged)(XenDevice *xendev, + enum xenbus_state frontend_state, + Error **errp); typedef void (*XenDeviceUnrealize)(XenDevice *xendev, Error **errp); typedef struct XenDeviceClass { @@ -32,6 +41,7 @@ typedef struct XenDeviceClass { const char *device; XenDeviceGetName get_name; XenDeviceRealize realize; + XenDeviceFrontendChanged frontend_changed; XenDeviceUnrealize unrealize; } XenDeviceClass; @@ -47,6 +57,7 @@ typedef struct XenBus { BusState qbus; domid_t backend_id; struct xs_handle *xsh; + NotifierList watch_notifiers; } XenBus; typedef struct XenBusClass { @@ -64,4 +75,8 @@ typedef struct XenBusClass { void xen_bus_init(void); +void xen_device_backend_set_state(XenDevice *xendev, + enum xenbus_state state); +enum xenbus_state xen_device_backend_get_state(XenDevice *xendev); + #endif /* HW_XEN_BUS_H */ From patchwork Mon Dec 17 11:40:36 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 1014430 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=citrix.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 43JK7q3RZGz9s2P for ; Mon, 17 Dec 2018 22:44:39 +1100 (AEDT) Received: from localhost ([::1]:46164 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrK9-0006cw-2Z for incoming@patchwork.ozlabs.org; Mon, 17 Dec 2018 06:44:37 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:52839) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrGc-00048q-Po for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:41:00 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gYrGa-0006Zj-G9 for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:40:58 -0500 Received: from smtp03.citrix.com ([162.221.156.55]:44686) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gYrGa-0006Yx-5P; Mon, 17 Dec 2018 06:40:56 -0500 X-IronPort-AV: E=Sophos;i="5.56,365,1539648000"; d="scan'208";a="73532590" From: Paul Durrant To: , , Date: Mon, 17 Dec 2018 11:40:36 +0000 Message-ID: <1545046848-14891-7-git-send-email-paul.durrant@citrix.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> References: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 162.221.156.55 Subject: [Qemu-devel] [PATCH v5 06/18] xen: add grant table interface for XenDevice-s X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Paul Durrant , Stefano Stabellini Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" The legacy PV backend infrastructure provides functions to map, unmap and copy pages granted by frontends. Similar functionality will be required by XenDevice implementations so this patch adds the necessary support. Signed-off-by: Paul Durrant Reviewed-by: Anthony Perard --- Cc: Stefano Stabellini --- hw/xen/xen-bus.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++ include/hw/xen/xen-bus.h | 25 ++++++++ 2 files changed, 171 insertions(+) diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c index 5e19592..faa9fd3 100644 --- a/hw/xen/xen-bus.c +++ b/hw/xen/xen-bus.c @@ -485,6 +485,138 @@ static void xen_device_frontend_destroy(XenDevice *xendev) } } +void xen_device_set_max_grant_refs(XenDevice *xendev, unsigned int nr_refs, + Error **errp) +{ + if (xengnttab_set_max_grants(xendev->xgth, nr_refs)) { + error_setg_errno(errp, errno, "xengnttab_set_max_grants failed"); + } +} + +void *xen_device_map_grant_refs(XenDevice *xendev, uint32_t *refs, + unsigned int nr_refs, int prot, + Error **errp) +{ + void *map = xengnttab_map_domain_grant_refs(xendev->xgth, nr_refs, + xendev->frontend_id, refs, + prot); + + if (!map) { + error_setg_errno(errp, errno, + "xengnttab_map_domain_grant_refs failed"); + } + + return map; +} + +void xen_device_unmap_grant_refs(XenDevice *xendev, void *map, + unsigned int nr_refs, Error **errp) +{ + if (xengnttab_unmap(xendev->xgth, map, nr_refs)) { + error_setg_errno(errp, errno, "xengnttab_unmap failed"); + } +} + +static void compat_copy_grant_refs(XenDevice *xendev, bool to_domain, + XenDeviceGrantCopySegment segs[], + unsigned int nr_segs, Error **errp) +{ + uint32_t *refs = g_new(uint32_t, nr_segs); + int prot = to_domain ? PROT_WRITE : PROT_READ; + void *map; + unsigned int i; + + for (i = 0; i < nr_segs; i++) { + XenDeviceGrantCopySegment *seg = &segs[i]; + + refs[i] = to_domain ? seg->dest.foreign.ref : + seg->source.foreign.ref; + } + + map = 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 = 0; i < nr_segs; i++) { + XenDeviceGrantCopySegment *seg = &segs[i]; + void *page = 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 = g_new0(xengnttab_grant_copy_segment_t, nr_segs); + + for (i = 0; i < nr_segs; i++) { + XenDeviceGrantCopySegment *seg = &segs[i]; + xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i]; + + if (to_domain) { + xengnttab_seg->flags = GNTCOPY_dest_gref; + xengnttab_seg->dest.foreign.domid = xendev->frontend_id; + xengnttab_seg->dest.foreign.ref = seg->dest.foreign.ref; + xengnttab_seg->dest.foreign.offset = seg->dest.foreign.offset; + xengnttab_seg->source.virt = seg->source.virt; + } else { + xengnttab_seg->flags = GNTCOPY_source_gref; + xengnttab_seg->source.foreign.domid = xendev->frontend_id; + xengnttab_seg->source.foreign.ref = seg->source.foreign.ref; + xengnttab_seg->source.foreign.offset = + seg->source.foreign.offset; + xengnttab_seg->dest.virt = seg->dest.virt; + } + + xengnttab_seg->len = 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 = 0; i < nr_segs; i++) { + xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i]; + + if (xengnttab_seg->status != GNTST_okay) { + error_setg(errp, "xengnttab_grant_copy seg[%u] failed", i); + break; + } + } + +done: + g_free(xengnttab_segs); +} + static void xen_device_unrealize(DeviceState *dev, Error **errp) { XenDevice *xendev = XEN_DEVICE(dev); @@ -509,6 +641,11 @@ static void xen_device_unrealize(DeviceState *dev, Error **errp) xen_device_frontend_destroy(xendev); xen_device_backend_destroy(xendev); + if (xendev->xgth) { + xengnttab_close(xendev->xgth); + xendev->xgth = NULL; + } + g_free(xendev->name); xendev->name = NULL; } @@ -551,6 +688,15 @@ static void xen_device_realize(DeviceState *dev, Error **errp) trace_xen_device_realize(type, xendev->name); + xendev->xgth = xengnttab_open(NULL, 0); + if (!xendev->xgth) { + error_setg_errno(errp, errno, "failed xengnttab_open"); + goto unrealize; + } + + xendev->feature_grant_copy = + (xengnttab_grant_copy(xendev->xgth, 0, NULL) == 0); + xen_device_backend_create(xendev, &local_err); if (local_err) { error_propagate(errp, local_err); diff --git a/include/hw/xen/xen-bus.h b/include/hw/xen/xen-bus.h index df73674..63a09b6 100644 --- a/include/hw/xen/xen-bus.h +++ b/include/hw/xen/xen-bus.h @@ -24,6 +24,8 @@ typedef struct XenDevice { enum xenbus_state backend_state, frontend_state; Notifier exit; XenWatch *frontend_state_watch; + xengnttab_handle *xgth; + bool feature_grant_copy; } XenDevice; typedef char *(*XenDeviceGetName)(XenDevice *xendev, Error **errp); @@ -79,4 +81,27 @@ void xen_device_backend_set_state(XenDevice *xendev, enum xenbus_state state); enum xenbus_state xen_device_backend_get_state(XenDevice *xendev); +void xen_device_set_max_grant_refs(XenDevice *xendev, unsigned int nr_refs, + Error **errp); +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, + unsigned int nr_refs, Error **errp); + +typedef struct XenDeviceGrantCopySegment { + union { + void *virt; + struct { + uint32_t ref; + off_t offset; + } foreign; + } source, dest; + size_t len; +} XenDeviceGrantCopySegment; + +void xen_device_copy_grant_refs(XenDevice *xendev, bool to_domain, + XenDeviceGrantCopySegment segs[], + unsigned int nr_segs, Error **errp); + #endif /* HW_XEN_BUS_H */ From patchwork Mon Dec 17 11:40:37 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 1014426 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=citrix.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 43JK4W1x9Wz9sD9 for ; Mon, 17 Dec 2018 22:41:46 +1100 (AEDT) Received: from localhost ([::1]:46151 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrHK-00049K-Pp for incoming@patchwork.ozlabs.org; Mon, 17 Dec 2018 06:41:42 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:52842) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrGc-00048r-QX for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:41:00 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gYrGa-0006ZT-3x for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:40:58 -0500 Received: from smtp03.citrix.com ([162.221.156.55]:44677) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gYrGZ-0006YC-S4; Mon, 17 Dec 2018 06:40:56 -0500 X-IronPort-AV: E=Sophos;i="5.56,365,1539648000"; d="scan'208";a="73532588" From: Paul Durrant To: , , Date: Mon, 17 Dec 2018 11:40:37 +0000 Message-ID: <1545046848-14891-8-git-send-email-paul.durrant@citrix.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> References: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 162.221.156.55 Subject: [Qemu-devel] [PATCH v5 07/18] xen: add event channel interface for XenDevice-s X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Paul Durrant , Stefano Stabellini Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" The legacy PV backend infrastructure provides functions to bind, unbind and send notifications to event channnels. Similar functionality will be required by XenDevice implementations so this patch adds the necessary support. Signed-off-by: Paul Durrant Reviewed-by: Anthony Perard --- Cc: Stefano Stabellini v2: - Added error pointers to notify and unbind --- hw/xen/xen-bus.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++ include/hw/xen/xen-bus.h | 18 +++++++++ 2 files changed, 119 insertions(+) diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c index faa9fd3..9443f27 100644 --- a/hw/xen/xen-bus.c +++ b/hw/xen/xen-bus.c @@ -617,6 +617,81 @@ done: g_free(xengnttab_segs); } +struct XenEventChannel { + unsigned int local_port; + XenEventHandler handler; + void *opaque; + Notifier notifier; +}; + +static void event_notify(Notifier *n, void *data) +{ + XenEventChannel *channel = container_of(n, XenEventChannel, notifier); + unsigned long port = (unsigned long)data; + + if (port == channel->local_port) { + channel->handler(channel->opaque); + } +} + +XenEventChannel *xen_device_bind_event_channel(XenDevice *xendev, + unsigned int port, + XenEventHandler handler, + void *opaque, Error **errp) +{ + XenEventChannel *channel = g_new0(XenEventChannel, 1); + + channel->local_port = xenevtchn_bind_interdomain(xendev->xeh, + xendev->frontend_id, + port); + if (xendev->local_port < 0) { + error_setg_errno(errp, errno, "xenevtchn_bind_interdomain failed"); + + g_free(channel); + return NULL; + } + + channel->handler = handler; + channel->opaque = opaque; + channel->notifier.notify = event_notify; + + notifier_list_add(&xendev->event_notifiers, &channel->notifier); + + return channel; +} + +void xen_device_notify_event_channel(XenDevice *xendev, + XenEventChannel *channel, + Error **errp) +{ + if (!channel) { + error_setg(errp, "bad channel"); + return; + } + + if (xenevtchn_notify(xendev->xeh, channel->local_port) < 0) { + error_setg_errno(errp, errno, "xenevtchn_notify failed"); + } +} + +void xen_device_unbind_event_channel(XenDevice *xendev, + XenEventChannel *channel, + Error **errp) +{ + if (!channel) { + error_setg(errp, "bad channel"); + return; + } + + notifier_remove(&channel->notifier); + + if (xenevtchn_unbind(xendev->xeh, channel->local_port) < 0) { + error_setg_errno(errp, errno, "xenevtchn_unbind failed"); + } + + g_free(channel); +} + static void xen_device_unrealize(DeviceState *dev, Error **errp) { XenDevice *xendev = XEN_DEVICE(dev); @@ -641,6 +716,12 @@ static void xen_device_unrealize(DeviceState *dev, Error **errp) xen_device_frontend_destroy(xendev); xen_device_backend_destroy(xendev); + if (xendev->xeh) { + qemu_set_fd_handler(xenevtchn_fd(xendev->xeh), NULL, NULL, NULL); + xenevtchn_close(xendev->xeh); + xendev->xeh = NULL; + } + if (xendev->xgth) { xengnttab_close(xendev->xgth); xendev->xgth = NULL; @@ -657,6 +738,16 @@ static void xen_device_exit(Notifier *n, void *data) xen_device_unrealize(DEVICE(xendev), &error_abort); } +static void xen_device_event(void *opaque) +{ + XenDevice *xendev = opaque; + unsigned long port = xenevtchn_pending(xendev->xeh); + + notifier_list_notify(&xendev->event_notifiers, (void *)port); + + xenevtchn_unmask(xendev->xeh, port); +} + static void xen_device_realize(DeviceState *dev, Error **errp) { XenDevice *xendev = XEN_DEVICE(dev); @@ -697,6 +788,16 @@ static void xen_device_realize(DeviceState *dev, Error **errp) xendev->feature_grant_copy = (xengnttab_grant_copy(xendev->xgth, 0, NULL) == 0); + xendev->xeh = xenevtchn_open(NULL, 0); + if (!xendev->xeh) { + error_setg_errno(errp, errno, "failed xenevtchn_open"); + goto unrealize; + } + + notifier_list_init(&xendev->event_notifiers); + qemu_set_fd_handler(xenevtchn_fd(xendev->xeh), xen_device_event, NULL, + xendev); + xen_device_backend_create(xendev, &local_err); if (local_err) { error_propagate(errp, local_err); diff --git a/include/hw/xen/xen-bus.h b/include/hw/xen/xen-bus.h index 63a09b6..f83a95c 100644 --- a/include/hw/xen/xen-bus.h +++ b/include/hw/xen/xen-bus.h @@ -26,6 +26,9 @@ typedef struct XenDevice { XenWatch *frontend_state_watch; xengnttab_handle *xgth; bool feature_grant_copy; + xenevtchn_handle *xeh; + xenevtchn_port_or_error_t local_port; + NotifierList event_notifiers; } XenDevice; typedef char *(*XenDeviceGetName)(XenDevice *xendev, Error **errp); @@ -104,4 +107,19 @@ void xen_device_copy_grant_refs(XenDevice *xendev, bool to_domain, XenDeviceGrantCopySegment segs[], unsigned int nr_segs, Error **errp); +typedef struct XenEventChannel XenEventChannel; + +typedef void (*XenEventHandler)(void *opaque); + +XenEventChannel *xen_device_bind_event_channel(XenDevice *xendev, + unsigned int port, + XenEventHandler handler, + void *opaque, Error **errp); +void xen_device_notify_event_channel(XenDevice *xendev, + XenEventChannel *channel, + Error **errp); +void xen_device_unbind_event_channel(XenDevice *xendev, + XenEventChannel *channel, + Error **errp); + #endif /* HW_XEN_BUS_H */ From patchwork Mon Dec 17 11:40:38 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 1014431 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=citrix.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 43JK8T190Kz9s4s for ; Mon, 17 Dec 2018 22:45:13 +1100 (AEDT) Received: from localhost ([::1]:46172 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrKg-00072H-M0 for incoming@patchwork.ozlabs.org; Mon, 17 Dec 2018 06:45:10 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:52949) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrGi-0004Cr-JJ for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:41:08 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gYrGc-0006b3-RA for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:41:04 -0500 Received: from smtp03.citrix.com ([162.221.156.55]:44686) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gYrGc-0006Yx-ES; Mon, 17 Dec 2018 06:40:58 -0500 X-IronPort-AV: E=Sophos;i="5.56,365,1539648000"; d="scan'208";a="73532597" From: Paul Durrant To: , , Date: Mon, 17 Dec 2018 11:40:38 +0000 Message-ID: <1545046848-14891-9-git-send-email-paul.durrant@citrix.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> References: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 162.221.156.55 Subject: [Qemu-devel] [PATCH v5 08/18] xen: duplicate xen_disk.c as basis of dataplane/xen-block.c X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Paul Durrant , Stefano Stabellini , Stefan Hajnoczi , Max Reitz Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" The new xen-block XenDevice implementation requires the same core dataplane as the legacy xen_disk implementation it will eventually replace. This patch therefore copies the legacy xen_disk.c source module into a new dataplane/xen-block.c source module as the basis for the new dataplane and adjusts the MAINTAINERS file accordingly. NOTE: The duplicated code is not yet built. It is simply put into place by this patch (just fixing style violations) such that the modifications that will need to be made to the code are not conflated with code movement, thus making review harder. Signed-off-by: Paul Durrant Acked-by: Anthony Perard --- Cc: Stefano Stabellini Cc: Stefan Hajnoczi Cc: Kevin Wolf Cc: Max Reitz --- MAINTAINERS | 1 + hw/block/dataplane/xen-block.c | 1019 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1020 insertions(+) create mode 100644 hw/block/dataplane/xen-block.c diff --git a/MAINTAINERS b/MAINTAINERS index dd728c3..ab62ad4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -404,6 +404,7 @@ F: hw/char/xen_console.c F: hw/display/xenfb.c F: hw/net/xen_nic.c F: hw/block/xen* +F: hw/block/dataplane/xen* F: hw/xen/ F: hw/xenpv/ F: hw/i386/xen/ diff --git a/hw/block/dataplane/xen-block.c b/hw/block/dataplane/xen-block.c new file mode 100644 index 0000000..9fae505 --- /dev/null +++ b/hw/block/dataplane/xen-block.c @@ -0,0 +1,1019 @@ +/* + * xen paravirt block device backend + * + * (c) Gerd Hoffmann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/units.h" +#include +#include + +#include "hw/hw.h" +#include "hw/xen/xen_backend.h" +#include "xen_blkif.h" +#include "sysemu/blockdev.h" +#include "sysemu/iothread.h" +#include "sysemu/block-backend.h" +#include "qapi/error.h" +#include "qapi/qmp/qdict.h" +#include "qapi/qmp/qstring.h" +#include "trace.h" + +/* ------------------------------------------------------------- */ + +#define BLOCK_SIZE 512 +#define IOCB_COUNT (BLKIF_MAX_SEGMENTS_PER_REQUEST + 2) + +struct ioreq { + blkif_request_t req; + int16_t status; + + /* parsed request */ + off_t start; + QEMUIOVector v; + void *buf; + size_t size; + int presync; + + /* aio status */ + int aio_inflight; + int aio_errors; + + struct XenBlkDev *blkdev; + QLIST_ENTRY(ioreq) list; + BlockAcctCookie acct; +}; + +#define MAX_RING_PAGE_ORDER 4 + +struct XenBlkDev { + struct XenLegacyDevice xendev; /* must be first */ + char *params; + char *mode; + char *type; + char *dev; + char *devtype; + bool directiosafe; + const char *fileproto; + const char *filename; + unsigned int ring_ref[1 << MAX_RING_PAGE_ORDER]; + unsigned int nr_ring_ref; + void *sring; + int64_t file_blk; + int64_t file_size; + int protocol; + blkif_back_rings_t rings; + int more_work; + + /* request lists */ + QLIST_HEAD(inflight_head, ioreq) inflight; + QLIST_HEAD(finished_head, ioreq) finished; + QLIST_HEAD(freelist_head, ioreq) freelist; + int requests_total; + int requests_inflight; + int requests_finished; + unsigned int max_requests; + + gboolean feature_discard; + + /* qemu block driver */ + DriveInfo *dinfo; + BlockBackend *blk; + QEMUBH *bh; + + IOThread *iothread; + AioContext *ctx; +}; + +/* ------------------------------------------------------------- */ + +static void ioreq_reset(struct ioreq *ioreq) +{ + memset(&ioreq->req, 0, sizeof(ioreq->req)); + ioreq->status = 0; + ioreq->start = 0; + ioreq->buf = NULL; + ioreq->size = 0; + ioreq->presync = 0; + + ioreq->aio_inflight = 0; + ioreq->aio_errors = 0; + + ioreq->blkdev = NULL; + memset(&ioreq->list, 0, sizeof(ioreq->list)); + memset(&ioreq->acct, 0, sizeof(ioreq->acct)); + + qemu_iovec_reset(&ioreq->v); +} + +static struct ioreq *ioreq_start(struct XenBlkDev *blkdev) +{ + struct ioreq *ioreq = NULL; + + if (QLIST_EMPTY(&blkdev->freelist)) { + if (blkdev->requests_total >= blkdev->max_requests) { + goto out; + } + /* allocate new struct */ + ioreq = g_malloc0(sizeof(*ioreq)); + ioreq->blkdev = blkdev; + blkdev->requests_total++; + qemu_iovec_init(&ioreq->v, 1); + } else { + /* get one from freelist */ + ioreq = QLIST_FIRST(&blkdev->freelist); + QLIST_REMOVE(ioreq, list); + } + QLIST_INSERT_HEAD(&blkdev->inflight, ioreq, list); + blkdev->requests_inflight++; + +out: + return ioreq; +} + +static void ioreq_finish(struct ioreq *ioreq) +{ + struct XenBlkDev *blkdev = ioreq->blkdev; + + QLIST_REMOVE(ioreq, list); + QLIST_INSERT_HEAD(&blkdev->finished, ioreq, list); + blkdev->requests_inflight--; + blkdev->requests_finished++; +} + +static void ioreq_release(struct ioreq *ioreq, bool finish) +{ + struct XenBlkDev *blkdev = ioreq->blkdev; + + QLIST_REMOVE(ioreq, list); + ioreq_reset(ioreq); + ioreq->blkdev = blkdev; + QLIST_INSERT_HEAD(&blkdev->freelist, ioreq, list); + if (finish) { + blkdev->requests_finished--; + } else { + blkdev->requests_inflight--; + } +} + +/* + * translate request into iovec + start offset + * do sanity checks along the way + */ +static int ioreq_parse(struct ioreq *ioreq) +{ + struct XenBlkDev *blkdev = ioreq->blkdev; + struct XenLegacyDevice *xendev = &blkdev->xendev; + size_t len; + int i; + + xen_pv_printf( + xendev, 3, + "op %d, nr %d, handle %d, id %" PRId64 ", sector %" PRId64 "\n", + ioreq->req.operation, ioreq->req.nr_segments, + ioreq->req.handle, ioreq->req.id, ioreq->req.sector_number); + switch (ioreq->req.operation) { + case BLKIF_OP_READ: + break; + case BLKIF_OP_FLUSH_DISKCACHE: + ioreq->presync = 1; + if (!ioreq->req.nr_segments) { + return 0; + } + /* fall through */ + case BLKIF_OP_WRITE: + break; + case BLKIF_OP_DISCARD: + return 0; + default: + xen_pv_printf(xendev, 0, "error: unknown operation (%d)\n", + ioreq->req.operation); + goto err; + }; + + if (ioreq->req.operation != BLKIF_OP_READ && blkdev->mode[0] != 'w') { + xen_pv_printf(xendev, 0, "error: write req for ro device\n"); + goto err; + } + + ioreq->start = ioreq->req.sector_number * blkdev->file_blk; + for (i = 0; i < ioreq->req.nr_segments; i++) { + if (i == BLKIF_MAX_SEGMENTS_PER_REQUEST) { + xen_pv_printf(xendev, 0, "error: nr_segments too big\n"); + goto err; + } + if (ioreq->req.seg[i].first_sect > ioreq->req.seg[i].last_sect) { + xen_pv_printf(xendev, 0, "error: first > last sector\n"); + goto err; + } + if (ioreq->req.seg[i].last_sect * BLOCK_SIZE >= XC_PAGE_SIZE) { + xen_pv_printf(xendev, 0, "error: page crossing\n"); + goto err; + } + + len = (ioreq->req.seg[i].last_sect - + ioreq->req.seg[i].first_sect + 1) * blkdev->file_blk; + ioreq->size += len; + } + if (ioreq->start + ioreq->size > blkdev->file_size) { + xen_pv_printf(xendev, 0, "error: access beyond end of file\n"); + goto err; + } + return 0; + +err: + ioreq->status = BLKIF_RSP_ERROR; + return -1; +} + +static int ioreq_grant_copy(struct ioreq *ioreq) +{ + struct XenBlkDev *blkdev = ioreq->blkdev; + struct XenLegacyDevice *xendev = &blkdev->xendev; + XenGrantCopySegment segs[BLKIF_MAX_SEGMENTS_PER_REQUEST]; + int i, count, rc; + int64_t file_blk = blkdev->file_blk; + bool to_domain = (ioreq->req.operation == BLKIF_OP_READ); + void *virt = ioreq->buf; + + if (ioreq->req.nr_segments == 0) { + return 0; + } + + count = ioreq->req.nr_segments; + + for (i = 0; i < count; i++) { + if (to_domain) { + segs[i].dest.foreign.ref = ioreq->req.seg[i].gref; + segs[i].dest.foreign.offset = ioreq->req.seg[i].first_sect * + file_blk; + segs[i].source.virt = virt; + } else { + segs[i].source.foreign.ref = ioreq->req.seg[i].gref; + segs[i].source.foreign.offset = ioreq->req.seg[i].first_sect * + file_blk; + segs[i].dest.virt = virt; + } + segs[i].len = (ioreq->req.seg[i].last_sect + - ioreq->req.seg[i].first_sect + 1) * file_blk; + virt += segs[i].len; + } + + rc = xen_be_copy_grant_refs(xendev, to_domain, segs, count); + + if (rc) { + xen_pv_printf(xendev, 0, + "failed to copy data %d\n", rc); + ioreq->aio_errors++; + return -1; + } + + return rc; +} + +static int ioreq_runio_qemu_aio(struct ioreq *ioreq); + +static void qemu_aio_complete(void *opaque, int ret) +{ + struct ioreq *ioreq = opaque; + struct XenBlkDev *blkdev = ioreq->blkdev; + struct XenLegacyDevice *xendev = &blkdev->xendev; + + aio_context_acquire(blkdev->ctx); + + if (ret != 0) { + xen_pv_printf(xendev, 0, "%s I/O error\n", + ioreq->req.operation == BLKIF_OP_READ ? "read" : "write"); + ioreq->aio_errors++; + } + + ioreq->aio_inflight--; + if (ioreq->presync) { + ioreq->presync = 0; + ioreq_runio_qemu_aio(ioreq); + goto done; + } + if (ioreq->aio_inflight > 0) { + goto done; + } + + switch (ioreq->req.operation) { + case BLKIF_OP_READ: + /* in case of failure ioreq->aio_errors is increased */ + if (ret == 0) { + ioreq_grant_copy(ioreq); + } + qemu_vfree(ioreq->buf); + break; + case BLKIF_OP_WRITE: + case BLKIF_OP_FLUSH_DISKCACHE: + if (!ioreq->req.nr_segments) { + break; + } + qemu_vfree(ioreq->buf); + break; + default: + break; + } + + ioreq->status = ioreq->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY; + ioreq_finish(ioreq); + + switch (ioreq->req.operation) { + case BLKIF_OP_WRITE: + case BLKIF_OP_FLUSH_DISKCACHE: + if (!ioreq->req.nr_segments) { + break; + } + case BLKIF_OP_READ: + if (ioreq->status == BLKIF_RSP_OKAY) { + block_acct_done(blk_get_stats(blkdev->blk), &ioreq->acct); + } else { + block_acct_failed(blk_get_stats(blkdev->blk), &ioreq->acct); + } + break; + case BLKIF_OP_DISCARD: + default: + break; + } + qemu_bh_schedule(blkdev->bh); + +done: + aio_context_release(blkdev->ctx); +} + +static bool blk_split_discard(struct ioreq *ioreq, blkif_sector_t sector_number, + uint64_t nr_sectors) +{ + struct XenBlkDev *blkdev = ioreq->blkdev; + int64_t byte_offset; + int byte_chunk; + uint64_t byte_remaining, limit; + uint64_t sec_start = sector_number; + uint64_t sec_count = nr_sectors; + + /* Wrap around, or overflowing byte limit? */ + if (sec_start + sec_count < sec_count || + sec_start + sec_count > INT64_MAX >> BDRV_SECTOR_BITS) { + return false; + } + + limit = BDRV_REQUEST_MAX_SECTORS << BDRV_SECTOR_BITS; + byte_offset = sec_start << BDRV_SECTOR_BITS; + byte_remaining = sec_count << BDRV_SECTOR_BITS; + + do { + byte_chunk = byte_remaining > limit ? limit : byte_remaining; + ioreq->aio_inflight++; + blk_aio_pdiscard(blkdev->blk, byte_offset, byte_chunk, + qemu_aio_complete, ioreq); + byte_remaining -= byte_chunk; + byte_offset += byte_chunk; + } while (byte_remaining > 0); + + return true; +} + +static int ioreq_runio_qemu_aio(struct ioreq *ioreq) +{ + struct XenBlkDev *blkdev = ioreq->blkdev; + + ioreq->buf = qemu_memalign(XC_PAGE_SIZE, ioreq->size); + if (ioreq->req.nr_segments && + (ioreq->req.operation == BLKIF_OP_WRITE || + ioreq->req.operation == BLKIF_OP_FLUSH_DISKCACHE) && + ioreq_grant_copy(ioreq)) { + qemu_vfree(ioreq->buf); + goto err; + } + + ioreq->aio_inflight++; + if (ioreq->presync) { + blk_aio_flush(ioreq->blkdev->blk, qemu_aio_complete, ioreq); + return 0; + } + + switch (ioreq->req.operation) { + case BLKIF_OP_READ: + qemu_iovec_add(&ioreq->v, ioreq->buf, ioreq->size); + block_acct_start(blk_get_stats(blkdev->blk), &ioreq->acct, + ioreq->v.size, BLOCK_ACCT_READ); + ioreq->aio_inflight++; + blk_aio_preadv(blkdev->blk, ioreq->start, &ioreq->v, 0, + qemu_aio_complete, ioreq); + break; + case BLKIF_OP_WRITE: + case BLKIF_OP_FLUSH_DISKCACHE: + if (!ioreq->req.nr_segments) { + break; + } + + qemu_iovec_add(&ioreq->v, ioreq->buf, ioreq->size); + block_acct_start(blk_get_stats(blkdev->blk), &ioreq->acct, + ioreq->v.size, + ioreq->req.operation == BLKIF_OP_WRITE ? + BLOCK_ACCT_WRITE : BLOCK_ACCT_FLUSH); + ioreq->aio_inflight++; + blk_aio_pwritev(blkdev->blk, ioreq->start, &ioreq->v, 0, + qemu_aio_complete, ioreq); + break; + case BLKIF_OP_DISCARD: + { + struct blkif_request_discard *req = (void *)&ioreq->req; + if (!blk_split_discard(ioreq, req->sector_number, req->nr_sectors)) { + goto err; + } + break; + } + default: + /* unknown operation (shouldn't happen -- parse catches this) */ + goto err; + } + + qemu_aio_complete(ioreq, 0); + + return 0; + +err: + ioreq_finish(ioreq); + ioreq->status = BLKIF_RSP_ERROR; + return -1; +} + +static int blk_send_response_one(struct ioreq *ioreq) +{ + struct XenBlkDev *blkdev = ioreq->blkdev; + int send_notify = 0; + int have_requests = 0; + blkif_response_t *resp; + + /* Place on the response ring for the relevant domain. */ + switch (blkdev->protocol) { + case BLKIF_PROTOCOL_NATIVE: + resp = (blkif_response_t *)RING_GET_RESPONSE( + &blkdev->rings.native, + blkdev->rings.native.rsp_prod_pvt); + break; + case BLKIF_PROTOCOL_X86_32: + resp = (blkif_response_t *)RING_GET_RESPONSE( + &blkdev->rings.x86_32_part, + blkdev->rings.x86_32_part.rsp_prod_pvt); + break; + case BLKIF_PROTOCOL_X86_64: + resp = (blkif_response_t *)RING_GET_RESPONSE( + &blkdev->rings.x86_64_part, + blkdev->rings.x86_64_part.rsp_prod_pvt); + break; + default: + return 0; + } + + resp->id = ioreq->req.id; + resp->operation = ioreq->req.operation; + resp->status = ioreq->status; + + blkdev->rings.common.rsp_prod_pvt++; + + RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&blkdev->rings.common, send_notify); + if (blkdev->rings.common.rsp_prod_pvt == blkdev->rings.common.req_cons) { + /* + * Tail check for pending requests. Allows frontend to avoid + * notifications if requests are already in flight (lower + * overheads and promotes batching). + */ + RING_FINAL_CHECK_FOR_REQUESTS(&blkdev->rings.common, have_requests); + } else if (RING_HAS_UNCONSUMED_REQUESTS(&blkdev->rings.common)) { + have_requests = 1; + } + + if (have_requests) { + blkdev->more_work++; + } + return send_notify; +} + +/* walk finished list, send outstanding responses, free requests */ +static void blk_send_response_all(struct XenBlkDev *blkdev) +{ + struct ioreq *ioreq; + int send_notify = 0; + + while (!QLIST_EMPTY(&blkdev->finished)) { + ioreq = QLIST_FIRST(&blkdev->finished); + send_notify += blk_send_response_one(ioreq); + ioreq_release(ioreq, true); + } + if (send_notify) { + xen_pv_send_notify(&blkdev->xendev); + } +} + +static int blk_get_request(struct XenBlkDev *blkdev, struct ioreq *ioreq, + RING_IDX rc) +{ + switch (blkdev->protocol) { + case BLKIF_PROTOCOL_NATIVE: + memcpy(&ioreq->req, RING_GET_REQUEST(&blkdev->rings.native, rc), + sizeof(ioreq->req)); + break; + case BLKIF_PROTOCOL_X86_32: + blkif_get_x86_32_req(&ioreq->req, + RING_GET_REQUEST(&blkdev->rings.x86_32_part, rc)); + break; + case BLKIF_PROTOCOL_X86_64: + blkif_get_x86_64_req(&ioreq->req, + RING_GET_REQUEST(&blkdev->rings.x86_64_part, rc)); + break; + } + /* Prevent the compiler from accessing the on-ring fields instead. */ + barrier(); + return 0; +} + +static void blk_handle_requests(struct XenBlkDev *blkdev) +{ + RING_IDX rc, rp; + struct ioreq *ioreq; + + blkdev->more_work = 0; + + rc = blkdev->rings.common.req_cons; + rp = blkdev->rings.common.sring->req_prod; + xen_rmb(); /* Ensure we see queued requests up to 'rp'. */ + + blk_send_response_all(blkdev); + while (rc != rp) { + /* pull request from ring */ + if (RING_REQUEST_CONS_OVERFLOW(&blkdev->rings.common, rc)) { + break; + } + ioreq = ioreq_start(blkdev); + if (ioreq == NULL) { + blkdev->more_work++; + break; + } + blk_get_request(blkdev, ioreq, rc); + blkdev->rings.common.req_cons = ++rc; + + /* parse them */ + if (ioreq_parse(ioreq) != 0) { + + switch (ioreq->req.operation) { + case BLKIF_OP_READ: + block_acct_invalid(blk_get_stats(blkdev->blk), + BLOCK_ACCT_READ); + break; + case BLKIF_OP_WRITE: + block_acct_invalid(blk_get_stats(blkdev->blk), + BLOCK_ACCT_WRITE); + break; + case BLKIF_OP_FLUSH_DISKCACHE: + block_acct_invalid(blk_get_stats(blkdev->blk), + BLOCK_ACCT_FLUSH); + default: + break; + }; + + if (blk_send_response_one(ioreq)) { + xen_pv_send_notify(&blkdev->xendev); + } + ioreq_release(ioreq, false); + continue; + } + + ioreq_runio_qemu_aio(ioreq); + } + + if (blkdev->more_work && blkdev->requests_inflight < blkdev->max_requests) { + qemu_bh_schedule(blkdev->bh); + } +} + +/* ------------------------------------------------------------- */ + +static void blk_bh(void *opaque) +{ + struct XenBlkDev *blkdev = opaque; + + aio_context_acquire(blkdev->ctx); + blk_handle_requests(blkdev); + aio_context_release(blkdev->ctx); +} + +static void blk_alloc(struct XenLegacyDevice *xendev) +{ + struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); + Error *err = NULL; + + trace_xen_disk_alloc(xendev->name); + + QLIST_INIT(&blkdev->inflight); + QLIST_INIT(&blkdev->finished); + QLIST_INIT(&blkdev->freelist); + + blkdev->iothread = iothread_create(xendev->name, &err); + assert(!err); + + blkdev->ctx = iothread_get_aio_context(blkdev->iothread); + blkdev->bh = aio_bh_new(blkdev->ctx, blk_bh, blkdev); +} + +static void blk_parse_discard(struct XenBlkDev *blkdev) +{ + struct XenLegacyDevice *xendev = &blkdev->xendev; + int enable; + + blkdev->feature_discard = true; + + if (xenstore_read_be_int(xendev, "discard-enable", &enable) == 0) { + blkdev->feature_discard = !!enable; + } + + if (blkdev->feature_discard) { + xenstore_write_be_int(xendev, "feature-discard", 1); + } +} + +static int blk_init(struct XenLegacyDevice *xendev) +{ + struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); + int info = 0; + char *directiosafe = NULL; + + trace_xen_disk_init(xendev->name); + + /* read xenstore entries */ + if (blkdev->params == NULL) { + char *h = NULL; + blkdev->params = xenstore_read_be_str(xendev, "params"); + if (blkdev->params != NULL) { + h = strchr(blkdev->params, ':'); + } + if (h != NULL) { + blkdev->fileproto = blkdev->params; + blkdev->filename = h + 1; + *h = 0; + } else { + blkdev->fileproto = ""; + blkdev->filename = blkdev->params; + } + } + if (!strcmp("aio", blkdev->fileproto)) { + blkdev->fileproto = "raw"; + } + if (!strcmp("vhd", blkdev->fileproto)) { + blkdev->fileproto = "vpc"; + } + if (blkdev->mode == NULL) { + blkdev->mode = xenstore_read_be_str(xendev, "mode"); + } + if (blkdev->type == NULL) { + blkdev->type = xenstore_read_be_str(xendev, "type"); + } + if (blkdev->dev == NULL) { + blkdev->dev = xenstore_read_be_str(xendev, "dev"); + } + if (blkdev->devtype == NULL) { + blkdev->devtype = xenstore_read_be_str(xendev, "device-type"); + } + directiosafe = xenstore_read_be_str(xendev, "direct-io-safe"); + blkdev->directiosafe = (directiosafe && atoi(directiosafe)); + + /* do we have all we need? */ + if (blkdev->params == NULL || + blkdev->mode == NULL || + blkdev->type == NULL || + blkdev->dev == NULL) { + goto out_error; + } + + /* read-only ? */ + if (strcmp(blkdev->mode, "w")) { + info |= VDISK_READONLY; + } + + /* cdrom ? */ + if (blkdev->devtype && !strcmp(blkdev->devtype, "cdrom")) { + info |= VDISK_CDROM; + } + + blkdev->file_blk = BLOCK_SIZE; + + /* fill info + * blk_connect supplies sector-size and sectors + */ + xenstore_write_be_int(xendev, "feature-flush-cache", 1); + xenstore_write_be_int(xendev, "info", info); + + xenstore_write_be_int(xendev, "max-ring-page-order", + MAX_RING_PAGE_ORDER); + + blk_parse_discard(blkdev); + + g_free(directiosafe); + return 0; + +out_error: + g_free(blkdev->params); + blkdev->params = NULL; + g_free(blkdev->mode); + blkdev->mode = NULL; + g_free(blkdev->type); + blkdev->type = NULL; + g_free(blkdev->dev); + blkdev->dev = NULL; + g_free(blkdev->devtype); + blkdev->devtype = NULL; + g_free(directiosafe); + blkdev->directiosafe = false; + return -1; +} + +static int blk_connect(struct XenLegacyDevice *xendev) +{ + struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); + int index, qflags; + bool readonly = true; + bool writethrough = true; + int order, ring_ref; + unsigned int ring_size, max_grants; + unsigned int i; + + trace_xen_disk_connect(xendev->name); + + /* read-only ? */ + if (blkdev->directiosafe) { + qflags = BDRV_O_NOCACHE | BDRV_O_NATIVE_AIO; + } else { + qflags = 0; + writethrough = false; + } + if (strcmp(blkdev->mode, "w") == 0) { + qflags |= BDRV_O_RDWR; + readonly = false; + } + if (blkdev->feature_discard) { + qflags |= BDRV_O_UNMAP; + } + + /* init qemu block driver */ + index = (xendev->dev - 202 * 256) / 16; + blkdev->dinfo = drive_get(IF_XEN, 0, index); + if (!blkdev->dinfo) { + Error *local_err = NULL; + QDict *options = NULL; + + if (strcmp(blkdev->fileproto, "")) { + options = qdict_new(); + qdict_put_str(options, "driver", blkdev->fileproto); + } + + /* setup via xenbus -> create new block driver instance */ + xen_pv_printf(xendev, 2, "create new bdrv (xenbus setup)\n"); + blkdev->blk = blk_new_open(blkdev->filename, NULL, options, + qflags, &local_err); + if (!blkdev->blk) { + xen_pv_printf(xendev, 0, "error: %s\n", + error_get_pretty(local_err)); + error_free(local_err); + return -1; + } + blk_set_enable_write_cache(blkdev->blk, !writethrough); + } else { + /* setup via qemu cmdline -> already setup for us */ + xen_pv_printf(xendev, 2, + "get configured bdrv (cmdline setup)\n"); + blkdev->blk = blk_by_legacy_dinfo(blkdev->dinfo); + if (blk_is_read_only(blkdev->blk) && !readonly) { + xen_pv_printf(xendev, 0, "Unexpected read-only drive"); + blkdev->blk = NULL; + return -1; + } + /* blkdev->blk is not create by us, we get a reference + * so we can blk_unref() unconditionally */ + blk_ref(blkdev->blk); + } + blk_attach_dev_legacy(blkdev->blk, blkdev); + blkdev->file_size = blk_getlength(blkdev->blk); + if (blkdev->file_size < 0) { + BlockDriverState *bs = blk_bs(blkdev->blk); + const char *drv_name = bs ? bdrv_get_format_name(bs) : NULL; + xen_pv_printf(xendev, 1, "blk_getlength: %d (%s) | drv %s\n", + (int)blkdev->file_size, strerror(-blkdev->file_size), + drv_name ?: "-"); + blkdev->file_size = 0; + } + + xen_pv_printf(xendev, 1, "type \"%s\", fileproto \"%s\", filename \"%s\"," + " size %" PRId64 " (%" PRId64 " MB)\n", + blkdev->type, blkdev->fileproto, blkdev->filename, + blkdev->file_size, blkdev->file_size / MiB); + + /* Fill in number of sector size and number of sectors */ + xenstore_write_be_int(xendev, "sector-size", blkdev->file_blk); + xenstore_write_be_int64(xendev, "sectors", + blkdev->file_size / blkdev->file_blk); + + if (xenstore_read_fe_int(xendev, "ring-page-order", + &order) == -1) { + blkdev->nr_ring_ref = 1; + + if (xenstore_read_fe_int(xendev, "ring-ref", + &ring_ref) == -1) { + return -1; + } + blkdev->ring_ref[0] = ring_ref; + + } else if (order >= 0 && order <= MAX_RING_PAGE_ORDER) { + blkdev->nr_ring_ref = 1 << order; + + for (i = 0; i < blkdev->nr_ring_ref; i++) { + char *key; + + key = g_strdup_printf("ring-ref%u", i); + if (!key) { + return -1; + } + + if (xenstore_read_fe_int(xendev, key, + &ring_ref) == -1) { + g_free(key); + return -1; + } + blkdev->ring_ref[i] = ring_ref; + + g_free(key); + } + } else { + xen_pv_printf(xendev, 0, "invalid ring-page-order: %d\n", + order); + return -1; + } + + if (xenstore_read_fe_int(xendev, "event-channel", + &xendev->remote_port) == -1) { + return -1; + } + + if (!xendev->protocol) { + blkdev->protocol = BLKIF_PROTOCOL_NATIVE; + } else if (strcmp(xendev->protocol, XEN_IO_PROTO_ABI_NATIVE) == 0) { + blkdev->protocol = BLKIF_PROTOCOL_NATIVE; + } else if (strcmp(xendev->protocol, XEN_IO_PROTO_ABI_X86_32) == 0) { + blkdev->protocol = BLKIF_PROTOCOL_X86_32; + } else if (strcmp(xendev->protocol, XEN_IO_PROTO_ABI_X86_64) == 0) { + blkdev->protocol = BLKIF_PROTOCOL_X86_64; + } else { + blkdev->protocol = BLKIF_PROTOCOL_NATIVE; + } + + ring_size = XC_PAGE_SIZE * blkdev->nr_ring_ref; + switch (blkdev->protocol) { + case BLKIF_PROTOCOL_NATIVE: + { + blkdev->max_requests = __CONST_RING_SIZE(blkif, ring_size); + break; + } + case BLKIF_PROTOCOL_X86_32: + { + blkdev->max_requests = __CONST_RING_SIZE(blkif_x86_32, ring_size); + break; + } + case BLKIF_PROTOCOL_X86_64: + { + blkdev->max_requests = __CONST_RING_SIZE(blkif_x86_64, ring_size); + break; + } + default: + return -1; + } + + /* Add on the number needed for the ring pages */ + max_grants = blkdev->nr_ring_ref; + + xen_be_set_max_grant_refs(xendev, max_grants); + blkdev->sring = xen_be_map_grant_refs(xendev, blkdev->ring_ref, + blkdev->nr_ring_ref, + PROT_READ | PROT_WRITE); + if (!blkdev->sring) { + return -1; + } + + switch (blkdev->protocol) { + case BLKIF_PROTOCOL_NATIVE: + { + blkif_sring_t *sring_native = blkdev->sring; + BACK_RING_INIT(&blkdev->rings.native, sring_native, ring_size); + break; + } + case BLKIF_PROTOCOL_X86_32: + { + blkif_x86_32_sring_t *sring_x86_32 = blkdev->sring; + + BACK_RING_INIT(&blkdev->rings.x86_32_part, sring_x86_32, ring_size); + break; + } + case BLKIF_PROTOCOL_X86_64: + { + blkif_x86_64_sring_t *sring_x86_64 = blkdev->sring; + + BACK_RING_INIT(&blkdev->rings.x86_64_part, sring_x86_64, ring_size); + break; + } + } + + blk_set_aio_context(blkdev->blk, blkdev->ctx); + + xen_be_bind_evtchn(xendev); + + xen_pv_printf(xendev, 1, "ok: proto %s, nr-ring-ref %u, " + "remote port %d, local port %d\n", + xendev->protocol, blkdev->nr_ring_ref, + xendev->remote_port, xendev->local_port); + return 0; +} + +static void blk_disconnect(struct XenLegacyDevice *xendev) +{ + struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); + + trace_xen_disk_disconnect(xendev->name); + + aio_context_acquire(blkdev->ctx); + + if (blkdev->blk) { + blk_set_aio_context(blkdev->blk, qemu_get_aio_context()); + blk_detach_dev(blkdev->blk, blkdev); + blk_unref(blkdev->blk); + blkdev->blk = NULL; + } + xen_pv_unbind_evtchn(xendev); + + aio_context_release(blkdev->ctx); + + if (blkdev->sring) { + xen_be_unmap_grant_refs(xendev, blkdev->sring, + blkdev->nr_ring_ref); + blkdev->sring = NULL; + } +} + +static int blk_free(struct XenLegacyDevice *xendev) +{ + struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); + struct ioreq *ioreq; + + trace_xen_disk_free(xendev->name); + + blk_disconnect(xendev); + + while (!QLIST_EMPTY(&blkdev->freelist)) { + ioreq = QLIST_FIRST(&blkdev->freelist); + QLIST_REMOVE(ioreq, list); + qemu_iovec_destroy(&ioreq->v); + g_free(ioreq); + } + + g_free(blkdev->params); + g_free(blkdev->mode); + g_free(blkdev->type); + g_free(blkdev->dev); + g_free(blkdev->devtype); + qemu_bh_delete(blkdev->bh); + iothread_destroy(blkdev->iothread); + return 0; +} + +static void blk_event(struct XenLegacyDevice *xendev) +{ + struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); + + qemu_bh_schedule(blkdev->bh); +} + +struct XenDevOps xen_blkdev_ops = { + .flags = DEVOPS_FLAG_NEED_GNTDEV, + .size = sizeof(struct XenBlkDev), + .alloc = blk_alloc, + .init = blk_init, + .initialise = blk_connect, + .disconnect = blk_disconnect, + .event = blk_event, + .free = blk_free, +}; From patchwork Mon Dec 17 11:40:39 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 1014429 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=citrix.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 43JK652xt7z9s2P for ; Mon, 17 Dec 2018 22:43:09 +1100 (AEDT) Received: from localhost ([::1]:46157 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrIg-0005HD-Sb for incoming@patchwork.ozlabs.org; Mon, 17 Dec 2018 06:43:06 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:52872) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrGe-000493-E3 for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:41:03 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gYrGb-0006af-Qt for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:41:00 -0500 Received: from smtp03.citrix.com ([162.221.156.55]:44686) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gYrGb-0006Yx-GO; Mon, 17 Dec 2018 06:40:57 -0500 X-IronPort-AV: E=Sophos;i="5.56,365,1539648000"; d="scan'208";a="73532596" From: Paul Durrant To: , , Date: Mon, 17 Dec 2018 11:40:39 +0000 Message-ID: <1545046848-14891-10-git-send-email-paul.durrant@citrix.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> References: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 162.221.156.55 Subject: [Qemu-devel] [PATCH v5 09/18] xen: remove unnecessary code from dataplane/xen-block.c X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Paul Durrant , Stefano Stabellini , Stefan Hajnoczi , Max Reitz Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Not all of the code duplicated from xen_disk.c is required as the basis for the new dataplane implementation so this patch removes extraneous code, along with the legacy #includes and calls to the legacy xen_pv_printf() function. Error messages are changed to be reported using error_report(). NOTE: The code is still not yet built. Further transformations will be required to make it correctly interface to the new XenBus/XenDevice framework. They will be delivered in a subsequent patch. Signed-off-by: Paul Durrant Acked-by: Anthony Perard --- Cc: Stefano Stabellini Cc: Stefan Hajnoczi Cc: Kevin Wolf Cc: Max Reitz v2: - Leave existing boilerplate alone, other than removing the now-incorrect description --- hw/block/dataplane/xen-block.c | 409 ++--------------------------------------- 1 file changed, 16 insertions(+), 393 deletions(-) diff --git a/hw/block/dataplane/xen-block.c b/hw/block/dataplane/xen-block.c index 9fae505..98f987d 100644 --- a/hw/block/dataplane/xen-block.c +++ b/hw/block/dataplane/xen-block.c @@ -1,6 +1,4 @@ /* - * xen paravirt block device backend - * * (c) Gerd Hoffmann * * This program is free software; you can redistribute it and/or modify @@ -19,26 +17,12 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "qemu/osdep.h" -#include "qemu/units.h" -#include -#include - -#include "hw/hw.h" -#include "hw/xen/xen_backend.h" -#include "xen_blkif.h" -#include "sysemu/blockdev.h" -#include "sysemu/iothread.h" -#include "sysemu/block-backend.h" -#include "qapi/error.h" -#include "qapi/qmp/qdict.h" -#include "qapi/qmp/qstring.h" -#include "trace.h" - -/* ------------------------------------------------------------- */ - -#define BLOCK_SIZE 512 -#define IOCB_COUNT (BLKIF_MAX_SEGMENTS_PER_REQUEST + 2) +/* + * Copyright (c) 2018 Citrix Systems Inc. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ struct ioreq { blkif_request_t req; @@ -101,8 +85,6 @@ struct XenBlkDev { AioContext *ctx; }; -/* ------------------------------------------------------------- */ - static void ioreq_reset(struct ioreq *ioreq) { memset(&ioreq->req, 0, sizeof(ioreq->req)); @@ -183,11 +165,6 @@ static int ioreq_parse(struct ioreq *ioreq) size_t len; int i; - xen_pv_printf( - xendev, 3, - "op %d, nr %d, handle %d, id %" PRId64 ", sector %" PRId64 "\n", - ioreq->req.operation, ioreq->req.nr_segments, - ioreq->req.handle, ioreq->req.id, ioreq->req.sector_number); switch (ioreq->req.operation) { case BLKIF_OP_READ: break; @@ -202,28 +179,27 @@ static int ioreq_parse(struct ioreq *ioreq) case BLKIF_OP_DISCARD: return 0; default: - xen_pv_printf(xendev, 0, "error: unknown operation (%d)\n", - ioreq->req.operation); + error_report("error: unknown operation (%d)", ioreq->req.operation); goto err; }; if (ioreq->req.operation != BLKIF_OP_READ && blkdev->mode[0] != 'w') { - xen_pv_printf(xendev, 0, "error: write req for ro device\n"); + error_report("error: write req for ro device"); goto err; } ioreq->start = ioreq->req.sector_number * blkdev->file_blk; for (i = 0; i < ioreq->req.nr_segments; i++) { if (i == BLKIF_MAX_SEGMENTS_PER_REQUEST) { - xen_pv_printf(xendev, 0, "error: nr_segments too big\n"); + error_report("error: nr_segments too big"); goto err; } if (ioreq->req.seg[i].first_sect > ioreq->req.seg[i].last_sect) { - xen_pv_printf(xendev, 0, "error: first > last sector\n"); + error_report("error: first > last sector"); goto err; } if (ioreq->req.seg[i].last_sect * BLOCK_SIZE >= XC_PAGE_SIZE) { - xen_pv_printf(xendev, 0, "error: page crossing\n"); + error_report("error: page crossing"); goto err; } @@ -232,7 +208,7 @@ static int ioreq_parse(struct ioreq *ioreq) ioreq->size += len; } if (ioreq->start + ioreq->size > blkdev->file_size) { - xen_pv_printf(xendev, 0, "error: access beyond end of file\n"); + error_report("error: access beyond end of file"); goto err; } return 0; @@ -278,8 +254,7 @@ static int ioreq_grant_copy(struct ioreq *ioreq) rc = xen_be_copy_grant_refs(xendev, to_domain, segs, count); if (rc) { - xen_pv_printf(xendev, 0, - "failed to copy data %d\n", rc); + error_report("failed to copy data %d", rc); ioreq->aio_errors++; return -1; } @@ -298,8 +273,9 @@ static void qemu_aio_complete(void *opaque, int ret) aio_context_acquire(blkdev->ctx); if (ret != 0) { - xen_pv_printf(xendev, 0, "%s I/O error\n", - ioreq->req.operation == BLKIF_OP_READ ? "read" : "write"); + error_report("%s I/O error", + ioreq->req.operation == BLKIF_OP_READ ? + "read" : "write"); ioreq->aio_errors++; } @@ -605,8 +581,6 @@ static void blk_handle_requests(struct XenBlkDev *blkdev) } } -/* ------------------------------------------------------------- */ - static void blk_bh(void *opaque) { struct XenBlkDev *blkdev = opaque; @@ -634,346 +608,6 @@ static void blk_alloc(struct XenLegacyDevice *xendev) blkdev->bh = aio_bh_new(blkdev->ctx, blk_bh, blkdev); } -static void blk_parse_discard(struct XenBlkDev *blkdev) -{ - struct XenLegacyDevice *xendev = &blkdev->xendev; - int enable; - - blkdev->feature_discard = true; - - if (xenstore_read_be_int(xendev, "discard-enable", &enable) == 0) { - blkdev->feature_discard = !!enable; - } - - if (blkdev->feature_discard) { - xenstore_write_be_int(xendev, "feature-discard", 1); - } -} - -static int blk_init(struct XenLegacyDevice *xendev) -{ - struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); - int info = 0; - char *directiosafe = NULL; - - trace_xen_disk_init(xendev->name); - - /* read xenstore entries */ - if (blkdev->params == NULL) { - char *h = NULL; - blkdev->params = xenstore_read_be_str(xendev, "params"); - if (blkdev->params != NULL) { - h = strchr(blkdev->params, ':'); - } - if (h != NULL) { - blkdev->fileproto = blkdev->params; - blkdev->filename = h + 1; - *h = 0; - } else { - blkdev->fileproto = ""; - blkdev->filename = blkdev->params; - } - } - if (!strcmp("aio", blkdev->fileproto)) { - blkdev->fileproto = "raw"; - } - if (!strcmp("vhd", blkdev->fileproto)) { - blkdev->fileproto = "vpc"; - } - if (blkdev->mode == NULL) { - blkdev->mode = xenstore_read_be_str(xendev, "mode"); - } - if (blkdev->type == NULL) { - blkdev->type = xenstore_read_be_str(xendev, "type"); - } - if (blkdev->dev == NULL) { - blkdev->dev = xenstore_read_be_str(xendev, "dev"); - } - if (blkdev->devtype == NULL) { - blkdev->devtype = xenstore_read_be_str(xendev, "device-type"); - } - directiosafe = xenstore_read_be_str(xendev, "direct-io-safe"); - blkdev->directiosafe = (directiosafe && atoi(directiosafe)); - - /* do we have all we need? */ - if (blkdev->params == NULL || - blkdev->mode == NULL || - blkdev->type == NULL || - blkdev->dev == NULL) { - goto out_error; - } - - /* read-only ? */ - if (strcmp(blkdev->mode, "w")) { - info |= VDISK_READONLY; - } - - /* cdrom ? */ - if (blkdev->devtype && !strcmp(blkdev->devtype, "cdrom")) { - info |= VDISK_CDROM; - } - - blkdev->file_blk = BLOCK_SIZE; - - /* fill info - * blk_connect supplies sector-size and sectors - */ - xenstore_write_be_int(xendev, "feature-flush-cache", 1); - xenstore_write_be_int(xendev, "info", info); - - xenstore_write_be_int(xendev, "max-ring-page-order", - MAX_RING_PAGE_ORDER); - - blk_parse_discard(blkdev); - - g_free(directiosafe); - return 0; - -out_error: - g_free(blkdev->params); - blkdev->params = NULL; - g_free(blkdev->mode); - blkdev->mode = NULL; - g_free(blkdev->type); - blkdev->type = NULL; - g_free(blkdev->dev); - blkdev->dev = NULL; - g_free(blkdev->devtype); - blkdev->devtype = NULL; - g_free(directiosafe); - blkdev->directiosafe = false; - return -1; -} - -static int blk_connect(struct XenLegacyDevice *xendev) -{ - struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); - int index, qflags; - bool readonly = true; - bool writethrough = true; - int order, ring_ref; - unsigned int ring_size, max_grants; - unsigned int i; - - trace_xen_disk_connect(xendev->name); - - /* read-only ? */ - if (blkdev->directiosafe) { - qflags = BDRV_O_NOCACHE | BDRV_O_NATIVE_AIO; - } else { - qflags = 0; - writethrough = false; - } - if (strcmp(blkdev->mode, "w") == 0) { - qflags |= BDRV_O_RDWR; - readonly = false; - } - if (blkdev->feature_discard) { - qflags |= BDRV_O_UNMAP; - } - - /* init qemu block driver */ - index = (xendev->dev - 202 * 256) / 16; - blkdev->dinfo = drive_get(IF_XEN, 0, index); - if (!blkdev->dinfo) { - Error *local_err = NULL; - QDict *options = NULL; - - if (strcmp(blkdev->fileproto, "")) { - options = qdict_new(); - qdict_put_str(options, "driver", blkdev->fileproto); - } - - /* setup via xenbus -> create new block driver instance */ - xen_pv_printf(xendev, 2, "create new bdrv (xenbus setup)\n"); - blkdev->blk = blk_new_open(blkdev->filename, NULL, options, - qflags, &local_err); - if (!blkdev->blk) { - xen_pv_printf(xendev, 0, "error: %s\n", - error_get_pretty(local_err)); - error_free(local_err); - return -1; - } - blk_set_enable_write_cache(blkdev->blk, !writethrough); - } else { - /* setup via qemu cmdline -> already setup for us */ - xen_pv_printf(xendev, 2, - "get configured bdrv (cmdline setup)\n"); - blkdev->blk = blk_by_legacy_dinfo(blkdev->dinfo); - if (blk_is_read_only(blkdev->blk) && !readonly) { - xen_pv_printf(xendev, 0, "Unexpected read-only drive"); - blkdev->blk = NULL; - return -1; - } - /* blkdev->blk is not create by us, we get a reference - * so we can blk_unref() unconditionally */ - blk_ref(blkdev->blk); - } - blk_attach_dev_legacy(blkdev->blk, blkdev); - blkdev->file_size = blk_getlength(blkdev->blk); - if (blkdev->file_size < 0) { - BlockDriverState *bs = blk_bs(blkdev->blk); - const char *drv_name = bs ? bdrv_get_format_name(bs) : NULL; - xen_pv_printf(xendev, 1, "blk_getlength: %d (%s) | drv %s\n", - (int)blkdev->file_size, strerror(-blkdev->file_size), - drv_name ?: "-"); - blkdev->file_size = 0; - } - - xen_pv_printf(xendev, 1, "type \"%s\", fileproto \"%s\", filename \"%s\"," - " size %" PRId64 " (%" PRId64 " MB)\n", - blkdev->type, blkdev->fileproto, blkdev->filename, - blkdev->file_size, blkdev->file_size / MiB); - - /* Fill in number of sector size and number of sectors */ - xenstore_write_be_int(xendev, "sector-size", blkdev->file_blk); - xenstore_write_be_int64(xendev, "sectors", - blkdev->file_size / blkdev->file_blk); - - if (xenstore_read_fe_int(xendev, "ring-page-order", - &order) == -1) { - blkdev->nr_ring_ref = 1; - - if (xenstore_read_fe_int(xendev, "ring-ref", - &ring_ref) == -1) { - return -1; - } - blkdev->ring_ref[0] = ring_ref; - - } else if (order >= 0 && order <= MAX_RING_PAGE_ORDER) { - blkdev->nr_ring_ref = 1 << order; - - for (i = 0; i < blkdev->nr_ring_ref; i++) { - char *key; - - key = g_strdup_printf("ring-ref%u", i); - if (!key) { - return -1; - } - - if (xenstore_read_fe_int(xendev, key, - &ring_ref) == -1) { - g_free(key); - return -1; - } - blkdev->ring_ref[i] = ring_ref; - - g_free(key); - } - } else { - xen_pv_printf(xendev, 0, "invalid ring-page-order: %d\n", - order); - return -1; - } - - if (xenstore_read_fe_int(xendev, "event-channel", - &xendev->remote_port) == -1) { - return -1; - } - - if (!xendev->protocol) { - blkdev->protocol = BLKIF_PROTOCOL_NATIVE; - } else if (strcmp(xendev->protocol, XEN_IO_PROTO_ABI_NATIVE) == 0) { - blkdev->protocol = BLKIF_PROTOCOL_NATIVE; - } else if (strcmp(xendev->protocol, XEN_IO_PROTO_ABI_X86_32) == 0) { - blkdev->protocol = BLKIF_PROTOCOL_X86_32; - } else if (strcmp(xendev->protocol, XEN_IO_PROTO_ABI_X86_64) == 0) { - blkdev->protocol = BLKIF_PROTOCOL_X86_64; - } else { - blkdev->protocol = BLKIF_PROTOCOL_NATIVE; - } - - ring_size = XC_PAGE_SIZE * blkdev->nr_ring_ref; - switch (blkdev->protocol) { - case BLKIF_PROTOCOL_NATIVE: - { - blkdev->max_requests = __CONST_RING_SIZE(blkif, ring_size); - break; - } - case BLKIF_PROTOCOL_X86_32: - { - blkdev->max_requests = __CONST_RING_SIZE(blkif_x86_32, ring_size); - break; - } - case BLKIF_PROTOCOL_X86_64: - { - blkdev->max_requests = __CONST_RING_SIZE(blkif_x86_64, ring_size); - break; - } - default: - return -1; - } - - /* Add on the number needed for the ring pages */ - max_grants = blkdev->nr_ring_ref; - - xen_be_set_max_grant_refs(xendev, max_grants); - blkdev->sring = xen_be_map_grant_refs(xendev, blkdev->ring_ref, - blkdev->nr_ring_ref, - PROT_READ | PROT_WRITE); - if (!blkdev->sring) { - return -1; - } - - switch (blkdev->protocol) { - case BLKIF_PROTOCOL_NATIVE: - { - blkif_sring_t *sring_native = blkdev->sring; - BACK_RING_INIT(&blkdev->rings.native, sring_native, ring_size); - break; - } - case BLKIF_PROTOCOL_X86_32: - { - blkif_x86_32_sring_t *sring_x86_32 = blkdev->sring; - - BACK_RING_INIT(&blkdev->rings.x86_32_part, sring_x86_32, ring_size); - break; - } - case BLKIF_PROTOCOL_X86_64: - { - blkif_x86_64_sring_t *sring_x86_64 = blkdev->sring; - - BACK_RING_INIT(&blkdev->rings.x86_64_part, sring_x86_64, ring_size); - break; - } - } - - blk_set_aio_context(blkdev->blk, blkdev->ctx); - - xen_be_bind_evtchn(xendev); - - xen_pv_printf(xendev, 1, "ok: proto %s, nr-ring-ref %u, " - "remote port %d, local port %d\n", - xendev->protocol, blkdev->nr_ring_ref, - xendev->remote_port, xendev->local_port); - return 0; -} - -static void blk_disconnect(struct XenLegacyDevice *xendev) -{ - struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); - - trace_xen_disk_disconnect(xendev->name); - - aio_context_acquire(blkdev->ctx); - - if (blkdev->blk) { - blk_set_aio_context(blkdev->blk, qemu_get_aio_context()); - blk_detach_dev(blkdev->blk, blkdev); - blk_unref(blkdev->blk); - blkdev->blk = NULL; - } - xen_pv_unbind_evtchn(xendev); - - aio_context_release(blkdev->ctx); - - if (blkdev->sring) { - xen_be_unmap_grant_refs(xendev, blkdev->sring, - blkdev->nr_ring_ref); - blkdev->sring = NULL; - } -} - static int blk_free(struct XenLegacyDevice *xendev) { struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); @@ -1006,14 +640,3 @@ static void blk_event(struct XenLegacyDevice *xendev) qemu_bh_schedule(blkdev->bh); } - -struct XenDevOps xen_blkdev_ops = { - .flags = DEVOPS_FLAG_NEED_GNTDEV, - .size = sizeof(struct XenBlkDev), - .alloc = blk_alloc, - .init = blk_init, - .initialise = blk_connect, - .disconnect = blk_disconnect, - .event = blk_event, - .free = blk_free, -}; From patchwork Mon Dec 17 11:40:40 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 1014447 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=citrix.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 43JKdD337Yz9s2P for ; Mon, 17 Dec 2018 23:06:40 +1100 (AEDT) Received: from localhost ([::1]:46287 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrfS-00049K-1h for incoming@patchwork.ozlabs.org; Mon, 17 Dec 2018 07:06:38 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:58117) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrY8-0007f1-2N for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:59:07 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gYrY2-0003bF-B3 for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:59:02 -0500 Received: from smtp03.citrix.com ([162.221.156.55]:45524) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gYrY0-0003UR-H5; Mon, 17 Dec 2018 06:58:58 -0500 X-IronPort-AV: E=Sophos;i="5.56,365,1539648000"; d="scan'208";a="73533632" From: Paul Durrant To: , , Date: Mon, 17 Dec 2018 11:40:40 +0000 Message-ID: <1545046848-14891-11-git-send-email-paul.durrant@citrix.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> References: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 162.221.156.55 Subject: [Qemu-devel] [PATCH v5 10/18] xen: add header and build dataplane/xen-block.c X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Paul Durrant , Stefano Stabellini , Stefan Hajnoczi , Max Reitz Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This patch adds the transformations necessary to get dataplane/xen-block.c to build against the new XenBus/XenDevice framework. MAINTAINERS is also updated due to the introduction of dataplane/xen-block.h. NOTE: Existing data structure names are retained for the moment. These will be modified by subsequent patches. A typedef for XenBlockDataPlane has been added to the header (based on the old struct XenBlkDev name for the moment) so that the old names don't need to leak out of the dataplane code. Signed-off-by: Paul Durrant Reviewed-by: Anthony Perard --- Cc: Stefan Hajnoczi Cc: Kevin Wolf Cc: Max Reitz Cc: Stefano Stabellini v2: - Tidy up header inclusions - Get rid of error_fatal --- MAINTAINERS | 1 + hw/block/dataplane/Makefile.objs | 1 + hw/block/dataplane/xen-block.c | 356 ++++++++++++++++++++++++++++----------- hw/block/dataplane/xen-block.h | 29 ++++ 4 files changed, 287 insertions(+), 100 deletions(-) create mode 100644 hw/block/dataplane/xen-block.h diff --git a/MAINTAINERS b/MAINTAINERS index ab62ad4..9875581 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -408,6 +408,7 @@ F: hw/block/dataplane/xen* F: hw/xen/ F: hw/xenpv/ F: hw/i386/xen/ +F: include/hw/block/dataplane/xen* F: include/hw/xen/ F: include/sysemu/xen-mapcache.h diff --git a/hw/block/dataplane/Makefile.objs b/hw/block/dataplane/Makefile.objs index e786f66..c6c68db 100644 --- a/hw/block/dataplane/Makefile.objs +++ b/hw/block/dataplane/Makefile.objs @@ -1 +1,2 @@ obj-y += virtio-blk.o +obj-$(CONFIG_XEN) += xen-block.o diff --git a/hw/block/dataplane/xen-block.c b/hw/block/dataplane/xen-block.c index 98f987d..20d16e7 100644 --- a/hw/block/dataplane/xen-block.c +++ b/hw/block/dataplane/xen-block.c @@ -24,65 +24,53 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "hw/hw.h" +#include "hw/xen/xen_common.h" +#include "hw/block/xen_blkif.h" +#include "sysemu/block-backend.h" +#include "sysemu/iothread.h" +#include "xen-block.h" + struct ioreq { - blkif_request_t req; - int16_t status; - - /* parsed request */ - off_t start; - QEMUIOVector v; - void *buf; - size_t size; - int presync; - - /* aio status */ - int aio_inflight; - int aio_errors; - - struct XenBlkDev *blkdev; - QLIST_ENTRY(ioreq) list; - BlockAcctCookie acct; + blkif_request_t req; + int16_t status; + off_t start; + QEMUIOVector v; + void *buf; + size_t size; + int presync; + int aio_inflight; + int aio_errors; + struct XenBlkDev *blkdev; + QLIST_ENTRY(ioreq) list; + BlockAcctCookie acct; }; -#define MAX_RING_PAGE_ORDER 4 - struct XenBlkDev { - struct XenLegacyDevice xendev; /* must be first */ - char *params; - char *mode; - char *type; - char *dev; - char *devtype; - bool directiosafe; - const char *fileproto; - const char *filename; - unsigned int ring_ref[1 << MAX_RING_PAGE_ORDER]; - unsigned int nr_ring_ref; - void *sring; - int64_t file_blk; - int64_t file_size; - int protocol; - blkif_back_rings_t rings; - int more_work; - - /* request lists */ + XenDevice *xendev; + XenEventChannel *event_channel; + unsigned int *ring_ref; + unsigned int nr_ring_ref; + void *sring; + int64_t file_blk; + int64_t file_size; + int protocol; + blkif_back_rings_t rings; + int more_work; QLIST_HEAD(inflight_head, ioreq) inflight; QLIST_HEAD(finished_head, ioreq) finished; QLIST_HEAD(freelist_head, ioreq) freelist; - int requests_total; - int requests_inflight; - int requests_finished; - unsigned int max_requests; - - gboolean feature_discard; - - /* qemu block driver */ - DriveInfo *dinfo; - BlockBackend *blk; - QEMUBH *bh; - - IOThread *iothread; - AioContext *ctx; + int requests_total; + int requests_inflight; + int requests_finished; + unsigned int max_requests; + BlockBackend *blk; + QEMUBH *bh; + IOThread *iothread; + AioContext *ctx; }; static void ioreq_reset(struct ioreq *ioreq) @@ -161,7 +149,6 @@ static void ioreq_release(struct ioreq *ioreq, bool finish) static int ioreq_parse(struct ioreq *ioreq) { struct XenBlkDev *blkdev = ioreq->blkdev; - struct XenLegacyDevice *xendev = &blkdev->xendev; size_t len; int i; @@ -183,7 +170,8 @@ static int ioreq_parse(struct ioreq *ioreq) goto err; }; - if (ioreq->req.operation != BLKIF_OP_READ && blkdev->mode[0] != 'w') { + if (ioreq->req.operation != BLKIF_OP_READ && + blk_is_read_only(blkdev->blk)) { error_report("error: write req for ro device"); goto err; } @@ -198,7 +186,7 @@ static int ioreq_parse(struct ioreq *ioreq) error_report("error: first > last sector"); goto err; } - if (ioreq->req.seg[i].last_sect * BLOCK_SIZE >= XC_PAGE_SIZE) { + if (ioreq->req.seg[i].last_sect * blkdev->file_blk >= XC_PAGE_SIZE) { error_report("error: page crossing"); goto err; } @@ -221,12 +209,13 @@ err: static int ioreq_grant_copy(struct ioreq *ioreq) { struct XenBlkDev *blkdev = ioreq->blkdev; - struct XenLegacyDevice *xendev = &blkdev->xendev; - XenGrantCopySegment segs[BLKIF_MAX_SEGMENTS_PER_REQUEST]; - int i, count, rc; + XenDevice *xendev = blkdev->xendev; + XenDeviceGrantCopySegment segs[BLKIF_MAX_SEGMENTS_PER_REQUEST]; + int i, count; int64_t file_blk = blkdev->file_blk; bool to_domain = (ioreq->req.operation == BLKIF_OP_READ); void *virt = ioreq->buf; + Error *local_err = NULL; if (ioreq->req.nr_segments == 0) { return 0; @@ -246,20 +235,21 @@ static int ioreq_grant_copy(struct ioreq *ioreq) file_blk; segs[i].dest.virt = virt; } - segs[i].len = (ioreq->req.seg[i].last_sect - - ioreq->req.seg[i].first_sect + 1) * file_blk; + segs[i].len = (ioreq->req.seg[i].last_sect - + ioreq->req.seg[i].first_sect + 1) * file_blk; virt += segs[i].len; } - rc = xen_be_copy_grant_refs(xendev, to_domain, segs, count); + xen_device_copy_grant_refs(xendev, to_domain, segs, count, &local_err); + + if (local_err) { + error_reportf_err(local_err, "failed to copy data: "); - if (rc) { - error_report("failed to copy data %d", rc); ioreq->aio_errors++; return -1; } - return rc; + return 0; } static int ioreq_runio_qemu_aio(struct ioreq *ioreq); @@ -268,7 +258,6 @@ static void qemu_aio_complete(void *opaque, int ret) { struct ioreq *ioreq = opaque; struct XenBlkDev *blkdev = ioreq->blkdev; - struct XenLegacyDevice *xendev = &blkdev->xendev; aio_context_acquire(blkdev->ctx); @@ -346,13 +335,13 @@ static bool blk_split_discard(struct ioreq *ioreq, blkif_sector_t sector_number, /* Wrap around, or overflowing byte limit? */ if (sec_start + sec_count < sec_count || - sec_start + sec_count > INT64_MAX >> BDRV_SECTOR_BITS) { + sec_start + sec_count > INT64_MAX / blkdev->file_blk) { return false; } - limit = BDRV_REQUEST_MAX_SECTORS << BDRV_SECTOR_BITS; - byte_offset = sec_start << BDRV_SECTOR_BITS; - byte_remaining = sec_count << BDRV_SECTOR_BITS; + limit = BDRV_REQUEST_MAX_SECTORS * blkdev->file_blk; + byte_offset = sec_start * blkdev->file_blk; + byte_remaining = sec_count * blkdev->file_blk; do { byte_chunk = byte_remaining > limit ? limit : byte_remaining; @@ -434,10 +423,10 @@ err: static int blk_send_response_one(struct ioreq *ioreq) { - struct XenBlkDev *blkdev = ioreq->blkdev; - int send_notify = 0; - int have_requests = 0; - blkif_response_t *resp; + struct XenBlkDev *blkdev = ioreq->blkdev; + int send_notify = 0; + int have_requests = 0; + blkif_response_t *resp; /* Place on the response ring for the relevant domain. */ switch (blkdev->protocol) { @@ -460,9 +449,9 @@ static int blk_send_response_one(struct ioreq *ioreq) return 0; } - resp->id = ioreq->req.id; + resp->id = ioreq->req.id; resp->operation = ioreq->req.operation; - resp->status = ioreq->status; + resp->status = ioreq->status; blkdev->rings.common.rsp_prod_pvt++; @@ -496,7 +485,14 @@ static void blk_send_response_all(struct XenBlkDev *blkdev) ioreq_release(ioreq, true); } if (send_notify) { - xen_pv_send_notify(&blkdev->xendev); + Error *local_err = NULL; + + xen_device_notify_event_channel(blkdev->xendev, + blkdev->event_channel, + &local_err); + if (local_err) { + error_report_err(local_err); + } } } @@ -567,7 +563,14 @@ static void blk_handle_requests(struct XenBlkDev *blkdev) }; if (blk_send_response_one(ioreq)) { - xen_pv_send_notify(&blkdev->xendev); + Error *local_err = NULL; + + xen_device_notify_event_channel(blkdev->xendev, + blkdev->event_channel, + &local_err); + if (local_err) { + error_report_err(local_err); + } } ioreq_release(ioreq, false); continue; @@ -590,32 +593,47 @@ static void blk_bh(void *opaque) aio_context_release(blkdev->ctx); } -static void blk_alloc(struct XenLegacyDevice *xendev) +static void blk_event(void *opaque) +{ + struct XenBlkDev *blkdev = opaque; + + qemu_bh_schedule(blkdev->bh); +} + +struct XenBlkDev *xen_block_dataplane_create(XenDevice *xendev, + BlockConf *conf, + IOThread *iothread) { - struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); - Error *err = NULL; + struct XenBlkDev *blkdev = g_new0(struct XenBlkDev, 1); - trace_xen_disk_alloc(xendev->name); + blkdev->xendev = xendev; + blkdev->file_blk = conf->logical_block_size; + blkdev->blk = conf->blk; + blkdev->file_size = blk_getlength(blkdev->blk); QLIST_INIT(&blkdev->inflight); QLIST_INIT(&blkdev->finished); QLIST_INIT(&blkdev->freelist); - blkdev->iothread = iothread_create(xendev->name, &err); - assert(!err); - - blkdev->ctx = iothread_get_aio_context(blkdev->iothread); + if (iothread) { + blkdev->iothread = iothread; + object_ref(OBJECT(blkdev->iothread)); + blkdev->ctx = iothread_get_aio_context(blkdev->iothread); + } else { + blkdev->ctx = qemu_get_aio_context(); + } blkdev->bh = aio_bh_new(blkdev->ctx, blk_bh, blkdev); + + return blkdev; } -static int blk_free(struct XenLegacyDevice *xendev) +void xen_block_dataplane_destroy(struct XenBlkDev *blkdev) { - struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); struct ioreq *ioreq; - trace_xen_disk_free(xendev->name); - - blk_disconnect(xendev); + if (!blkdev) { + return; + } while (!QLIST_EMPTY(&blkdev->freelist)) { ioreq = QLIST_FIRST(&blkdev->freelist); @@ -624,19 +642,157 @@ static int blk_free(struct XenLegacyDevice *xendev) g_free(ioreq); } - g_free(blkdev->params); - g_free(blkdev->mode); - g_free(blkdev->type); - g_free(blkdev->dev); - g_free(blkdev->devtype); qemu_bh_delete(blkdev->bh); - iothread_destroy(blkdev->iothread); - return 0; + if (blkdev->iothread) { + object_unref(OBJECT(blkdev->iothread)); + } + + g_free(blkdev); } -static void blk_event(struct XenLegacyDevice *xendev) + +void xen_block_dataplane_stop(struct XenBlkDev *blkdev) { - struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); + XenDevice *xendev; - qemu_bh_schedule(blkdev->bh); + if (!blkdev) { + return; + } + + aio_context_acquire(blkdev->ctx); + blk_set_aio_context(blkdev->blk, qemu_get_aio_context()); + aio_context_release(blkdev->ctx); + + xendev = blkdev->xendev; + + if (blkdev->event_channel) { + Error *local_err = NULL; + + xen_device_unbind_event_channel(xendev, blkdev->event_channel, + &local_err); + blkdev->event_channel = NULL; + + if (local_err) { + error_report_err(local_err); + } + } + + if (blkdev->sring) { + Error *local_err = NULL; + + xen_device_unmap_grant_refs(xendev, blkdev->sring, + blkdev->nr_ring_ref, &local_err); + blkdev->sring = NULL; + + if (local_err) { + error_report_err(local_err); + } + } + + g_free(blkdev->ring_ref); + blkdev->ring_ref = NULL; +} + +void xen_block_dataplane_start(struct XenBlkDev *blkdev, + const unsigned int ring_ref[], + unsigned int nr_ring_ref, + unsigned int event_channel, + unsigned int protocol, + Error **errp) +{ + XenDevice *xendev = blkdev->xendev; + Error *local_err = NULL; + unsigned int ring_size; + unsigned int i; + + blkdev->nr_ring_ref = nr_ring_ref; + blkdev->ring_ref = g_new(unsigned int, nr_ring_ref); + + for (i = 0; i < nr_ring_ref; i++) { + blkdev->ring_ref[i] = ring_ref[i]; + } + + blkdev->protocol = protocol; + + ring_size = XC_PAGE_SIZE * blkdev->nr_ring_ref; + switch (blkdev->protocol) { + case BLKIF_PROTOCOL_NATIVE: + { + blkdev->max_requests = __CONST_RING_SIZE(blkif, ring_size); + break; + } + case BLKIF_PROTOCOL_X86_32: + { + blkdev->max_requests = __CONST_RING_SIZE(blkif_x86_32, ring_size); + break; + } + case BLKIF_PROTOCOL_X86_64: + { + blkdev->max_requests = __CONST_RING_SIZE(blkif_x86_64, ring_size); + break; + } + default: + error_setg(errp, "unknown protocol %u", blkdev->protocol); + return; + } + + xen_device_set_max_grant_refs(xendev, blkdev->nr_ring_ref, + &local_err); + if (local_err) { + error_propagate(errp, local_err); + goto stop; + } + + blkdev->sring = xen_device_map_grant_refs(xendev, + blkdev->ring_ref, + blkdev->nr_ring_ref, + PROT_READ | PROT_WRITE, + &local_err); + if (local_err) { + error_propagate(errp, local_err); + goto stop; + } + + switch (blkdev->protocol) { + case BLKIF_PROTOCOL_NATIVE: + { + blkif_sring_t *sring_native = blkdev->sring; + + BACK_RING_INIT(&blkdev->rings.native, sring_native, ring_size); + break; + } + case BLKIF_PROTOCOL_X86_32: + { + blkif_x86_32_sring_t *sring_x86_32 = blkdev->sring; + + BACK_RING_INIT(&blkdev->rings.x86_32_part, sring_x86_32, + ring_size); + break; + } + case BLKIF_PROTOCOL_X86_64: + { + blkif_x86_64_sring_t *sring_x86_64 = blkdev->sring; + + BACK_RING_INIT(&blkdev->rings.x86_64_part, sring_x86_64, + ring_size); + break; + } + } + + blkdev->event_channel = + xen_device_bind_event_channel(xendev, event_channel, + blk_event, blkdev, + &local_err); + if (local_err) { + error_propagate(errp, local_err); + goto stop; + } + + aio_context_acquire(blkdev->ctx); + blk_set_aio_context(blkdev->blk, blkdev->ctx); + aio_context_release(blkdev->ctx); + return; + +stop: + xen_block_dataplane_stop(blkdev); } diff --git a/hw/block/dataplane/xen-block.h b/hw/block/dataplane/xen-block.h new file mode 100644 index 0000000..f31da38 --- /dev/null +++ b/hw/block/dataplane/xen-block.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2018 Citrix Systems Inc. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef HW_BLOCK_DATAPLANE_XEN_BLOCK_H +#define HW_BLOCK_DATAPLANE_XEN_BLOCK_H + +#include "hw/block/block.h" +#include "hw/xen/xen-bus.h" +#include "sysemu/iothread.h" + +typedef struct XenBlkDev XenBlockDataPlane; + +XenBlockDataPlane *xen_block_dataplane_create(XenDevice *xendev, + BlockConf *conf, + IOThread *iothread); +void xen_block_dataplane_destroy(XenBlockDataPlane *dataplane); +void xen_block_dataplane_start(XenBlockDataPlane *dataplane, + const unsigned int ring_ref[], + unsigned int nr_ring_ref, + unsigned int event_channel, + unsigned int protocol, + Error **errp); +void xen_block_dataplane_stop(XenBlockDataPlane *dataplane); + +#endif /* HW_BLOCK_DATAPLANE_XEN_BLOCK_H */ From patchwork Mon Dec 17 11:40:41 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 1014441 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=citrix.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 43JKT24Rdwz9s4s for ; Mon, 17 Dec 2018 22:59:34 +1100 (AEDT) Received: from localhost ([::1]:46242 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrYY-0007OB-9x for incoming@patchwork.ozlabs.org; Mon, 17 Dec 2018 06:59:32 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:58004) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrXu-0007IS-T1 for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:58:53 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gYrXp-0003RP-OA for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:58:50 -0500 Received: from smtp03.citrix.com ([162.221.156.55]:45515) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gYrXp-0003Qj-C4; Mon, 17 Dec 2018 06:58:45 -0500 X-IronPort-AV: E=Sophos;i="5.56,365,1539648000"; d="scan'208";a="73533624" From: Paul Durrant To: , , Date: Mon, 17 Dec 2018 11:40:41 +0000 Message-ID: <1545046848-14891-12-git-send-email-paul.durrant@citrix.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> References: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 162.221.156.55 Subject: [Qemu-devel] [PATCH v5 11/18] xen: remove 'XenBlkDev' and 'blkdev' names from dataplane/xen-block X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Paul Durrant , Stefano Stabellini , Stefan Hajnoczi , Max Reitz Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This is a purely cosmetic patch that substitutes the old 'struct XenBlkDev' name with 'XenBlockDataPlane' and 'blkdev' field/variable names with 'dataplane', and then does necessary fix-up to adhere to coding style. No functional change. Signed-off-by: Paul Durrant Acked-by: Anthony Perard --- Cc: Stefano Stabellini Cc: Stefan Hajnoczi Cc: Kevin Wolf Cc: Max Reitz --- hw/block/dataplane/xen-block.c | 352 +++++++++++++++++++++-------------------- hw/block/dataplane/xen-block.h | 2 +- 2 files changed, 183 insertions(+), 171 deletions(-) diff --git a/hw/block/dataplane/xen-block.c b/hw/block/dataplane/xen-block.c index 20d16e7..6ecd160 100644 --- a/hw/block/dataplane/xen-block.c +++ b/hw/block/dataplane/xen-block.c @@ -44,12 +44,12 @@ struct ioreq { int presync; int aio_inflight; int aio_errors; - struct XenBlkDev *blkdev; + XenBlockDataPlane *dataplane; QLIST_ENTRY(ioreq) list; BlockAcctCookie acct; }; -struct XenBlkDev { +struct XenBlockDataPlane { XenDevice *xendev; XenEventChannel *event_channel; unsigned int *ring_ref; @@ -85,33 +85,33 @@ static void ioreq_reset(struct ioreq *ioreq) ioreq->aio_inflight = 0; ioreq->aio_errors = 0; - ioreq->blkdev = NULL; + ioreq->dataplane = NULL; memset(&ioreq->list, 0, sizeof(ioreq->list)); memset(&ioreq->acct, 0, sizeof(ioreq->acct)); qemu_iovec_reset(&ioreq->v); } -static struct ioreq *ioreq_start(struct XenBlkDev *blkdev) +static struct ioreq *ioreq_start(XenBlockDataPlane *dataplane) { struct ioreq *ioreq = NULL; - if (QLIST_EMPTY(&blkdev->freelist)) { - if (blkdev->requests_total >= blkdev->max_requests) { + if (QLIST_EMPTY(&dataplane->freelist)) { + if (dataplane->requests_total >= dataplane->max_requests) { goto out; } /* allocate new struct */ ioreq = g_malloc0(sizeof(*ioreq)); - ioreq->blkdev = blkdev; - blkdev->requests_total++; + ioreq->dataplane = dataplane; + dataplane->requests_total++; qemu_iovec_init(&ioreq->v, 1); } else { /* get one from freelist */ - ioreq = QLIST_FIRST(&blkdev->freelist); + ioreq = QLIST_FIRST(&dataplane->freelist); QLIST_REMOVE(ioreq, list); } - QLIST_INSERT_HEAD(&blkdev->inflight, ioreq, list); - blkdev->requests_inflight++; + QLIST_INSERT_HEAD(&dataplane->inflight, ioreq, list); + dataplane->requests_inflight++; out: return ioreq; @@ -119,26 +119,26 @@ out: static void ioreq_finish(struct ioreq *ioreq) { - struct XenBlkDev *blkdev = ioreq->blkdev; + XenBlockDataPlane *dataplane = ioreq->dataplane; QLIST_REMOVE(ioreq, list); - QLIST_INSERT_HEAD(&blkdev->finished, ioreq, list); - blkdev->requests_inflight--; - blkdev->requests_finished++; + QLIST_INSERT_HEAD(&dataplane->finished, ioreq, list); + dataplane->requests_inflight--; + dataplane->requests_finished++; } static void ioreq_release(struct ioreq *ioreq, bool finish) { - struct XenBlkDev *blkdev = ioreq->blkdev; + XenBlockDataPlane *dataplane = ioreq->dataplane; QLIST_REMOVE(ioreq, list); ioreq_reset(ioreq); - ioreq->blkdev = blkdev; - QLIST_INSERT_HEAD(&blkdev->freelist, ioreq, list); + ioreq->dataplane = dataplane; + QLIST_INSERT_HEAD(&dataplane->freelist, ioreq, list); if (finish) { - blkdev->requests_finished--; + dataplane->requests_finished--; } else { - blkdev->requests_inflight--; + dataplane->requests_inflight--; } } @@ -148,7 +148,7 @@ static void ioreq_release(struct ioreq *ioreq, bool finish) */ static int ioreq_parse(struct ioreq *ioreq) { - struct XenBlkDev *blkdev = ioreq->blkdev; + XenBlockDataPlane *dataplane = ioreq->dataplane; size_t len; int i; @@ -171,12 +171,12 @@ static int ioreq_parse(struct ioreq *ioreq) }; if (ioreq->req.operation != BLKIF_OP_READ && - blk_is_read_only(blkdev->blk)) { + blk_is_read_only(dataplane->blk)) { error_report("error: write req for ro device"); goto err; } - ioreq->start = ioreq->req.sector_number * blkdev->file_blk; + ioreq->start = ioreq->req.sector_number * dataplane->file_blk; for (i = 0; i < ioreq->req.nr_segments; i++) { if (i == BLKIF_MAX_SEGMENTS_PER_REQUEST) { error_report("error: nr_segments too big"); @@ -186,16 +186,16 @@ static int ioreq_parse(struct ioreq *ioreq) error_report("error: first > last sector"); goto err; } - if (ioreq->req.seg[i].last_sect * blkdev->file_blk >= XC_PAGE_SIZE) { + if (ioreq->req.seg[i].last_sect * dataplane->file_blk >= XC_PAGE_SIZE) { error_report("error: page crossing"); goto err; } len = (ioreq->req.seg[i].last_sect - - ioreq->req.seg[i].first_sect + 1) * blkdev->file_blk; + ioreq->req.seg[i].first_sect + 1) * dataplane->file_blk; ioreq->size += len; } - if (ioreq->start + ioreq->size > blkdev->file_size) { + if (ioreq->start + ioreq->size > dataplane->file_size) { error_report("error: access beyond end of file"); goto err; } @@ -208,11 +208,11 @@ err: static int ioreq_grant_copy(struct ioreq *ioreq) { - struct XenBlkDev *blkdev = ioreq->blkdev; - XenDevice *xendev = blkdev->xendev; + XenBlockDataPlane *dataplane = ioreq->dataplane; + XenDevice *xendev = dataplane->xendev; XenDeviceGrantCopySegment segs[BLKIF_MAX_SEGMENTS_PER_REQUEST]; int i, count; - int64_t file_blk = blkdev->file_blk; + int64_t file_blk = dataplane->file_blk; bool to_domain = (ioreq->req.operation == BLKIF_OP_READ); void *virt = ioreq->buf; Error *local_err = NULL; @@ -257,9 +257,9 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq); static void qemu_aio_complete(void *opaque, int ret) { struct ioreq *ioreq = opaque; - struct XenBlkDev *blkdev = ioreq->blkdev; + XenBlockDataPlane *dataplane = ioreq->dataplane; - aio_context_acquire(blkdev->ctx); + aio_context_acquire(dataplane->ctx); if (ret != 0) { error_report("%s I/O error", @@ -308,25 +308,25 @@ static void qemu_aio_complete(void *opaque, int ret) } case BLKIF_OP_READ: if (ioreq->status == BLKIF_RSP_OKAY) { - block_acct_done(blk_get_stats(blkdev->blk), &ioreq->acct); + block_acct_done(blk_get_stats(dataplane->blk), &ioreq->acct); } else { - block_acct_failed(blk_get_stats(blkdev->blk), &ioreq->acct); + block_acct_failed(blk_get_stats(dataplane->blk), &ioreq->acct); } break; case BLKIF_OP_DISCARD: default: break; } - qemu_bh_schedule(blkdev->bh); + qemu_bh_schedule(dataplane->bh); done: - aio_context_release(blkdev->ctx); + aio_context_release(dataplane->ctx); } static bool blk_split_discard(struct ioreq *ioreq, blkif_sector_t sector_number, uint64_t nr_sectors) { - struct XenBlkDev *blkdev = ioreq->blkdev; + XenBlockDataPlane *dataplane = ioreq->dataplane; int64_t byte_offset; int byte_chunk; uint64_t byte_remaining, limit; @@ -335,18 +335,18 @@ static bool blk_split_discard(struct ioreq *ioreq, blkif_sector_t sector_number, /* Wrap around, or overflowing byte limit? */ if (sec_start + sec_count < sec_count || - sec_start + sec_count > INT64_MAX / blkdev->file_blk) { + sec_start + sec_count > INT64_MAX / dataplane->file_blk) { return false; } - limit = BDRV_REQUEST_MAX_SECTORS * blkdev->file_blk; - byte_offset = sec_start * blkdev->file_blk; - byte_remaining = sec_count * blkdev->file_blk; + limit = BDRV_REQUEST_MAX_SECTORS * dataplane->file_blk; + byte_offset = sec_start * dataplane->file_blk; + byte_remaining = sec_count * dataplane->file_blk; do { byte_chunk = byte_remaining > limit ? limit : byte_remaining; ioreq->aio_inflight++; - blk_aio_pdiscard(blkdev->blk, byte_offset, byte_chunk, + blk_aio_pdiscard(dataplane->blk, byte_offset, byte_chunk, qemu_aio_complete, ioreq); byte_remaining -= byte_chunk; byte_offset += byte_chunk; @@ -357,7 +357,7 @@ static bool blk_split_discard(struct ioreq *ioreq, blkif_sector_t sector_number, static int ioreq_runio_qemu_aio(struct ioreq *ioreq) { - struct XenBlkDev *blkdev = ioreq->blkdev; + XenBlockDataPlane *dataplane = ioreq->dataplane; ioreq->buf = qemu_memalign(XC_PAGE_SIZE, ioreq->size); if (ioreq->req.nr_segments && @@ -370,17 +370,17 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq) ioreq->aio_inflight++; if (ioreq->presync) { - blk_aio_flush(ioreq->blkdev->blk, qemu_aio_complete, ioreq); + blk_aio_flush(ioreq->dataplane->blk, qemu_aio_complete, ioreq); return 0; } switch (ioreq->req.operation) { case BLKIF_OP_READ: qemu_iovec_add(&ioreq->v, ioreq->buf, ioreq->size); - block_acct_start(blk_get_stats(blkdev->blk), &ioreq->acct, + block_acct_start(blk_get_stats(dataplane->blk), &ioreq->acct, ioreq->v.size, BLOCK_ACCT_READ); ioreq->aio_inflight++; - blk_aio_preadv(blkdev->blk, ioreq->start, &ioreq->v, 0, + blk_aio_preadv(dataplane->blk, ioreq->start, &ioreq->v, 0, qemu_aio_complete, ioreq); break; case BLKIF_OP_WRITE: @@ -390,12 +390,12 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq) } qemu_iovec_add(&ioreq->v, ioreq->buf, ioreq->size); - block_acct_start(blk_get_stats(blkdev->blk), &ioreq->acct, + block_acct_start(blk_get_stats(dataplane->blk), &ioreq->acct, ioreq->v.size, ioreq->req.operation == BLKIF_OP_WRITE ? BLOCK_ACCT_WRITE : BLOCK_ACCT_FLUSH); ioreq->aio_inflight++; - blk_aio_pwritev(blkdev->blk, ioreq->start, &ioreq->v, 0, + blk_aio_pwritev(dataplane->blk, ioreq->start, &ioreq->v, 0, qemu_aio_complete, ioreq); break; case BLKIF_OP_DISCARD: @@ -423,27 +423,27 @@ err: static int blk_send_response_one(struct ioreq *ioreq) { - struct XenBlkDev *blkdev = ioreq->blkdev; + XenBlockDataPlane *dataplane = ioreq->dataplane; int send_notify = 0; int have_requests = 0; blkif_response_t *resp; /* Place on the response ring for the relevant domain. */ - switch (blkdev->protocol) { + switch (dataplane->protocol) { case BLKIF_PROTOCOL_NATIVE: resp = (blkif_response_t *)RING_GET_RESPONSE( - &blkdev->rings.native, - blkdev->rings.native.rsp_prod_pvt); + &dataplane->rings.native, + dataplane->rings.native.rsp_prod_pvt); break; case BLKIF_PROTOCOL_X86_32: resp = (blkif_response_t *)RING_GET_RESPONSE( - &blkdev->rings.x86_32_part, - blkdev->rings.x86_32_part.rsp_prod_pvt); + &dataplane->rings.x86_32_part, + dataplane->rings.x86_32_part.rsp_prod_pvt); break; case BLKIF_PROTOCOL_X86_64: resp = (blkif_response_t *)RING_GET_RESPONSE( - &blkdev->rings.x86_64_part, - blkdev->rings.x86_64_part.rsp_prod_pvt); + &dataplane->rings.x86_64_part, + dataplane->rings.x86_64_part.rsp_prod_pvt); break; default: return 0; @@ -453,42 +453,45 @@ static int blk_send_response_one(struct ioreq *ioreq) resp->operation = ioreq->req.operation; resp->status = ioreq->status; - blkdev->rings.common.rsp_prod_pvt++; + dataplane->rings.common.rsp_prod_pvt++; - RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&blkdev->rings.common, send_notify); - if (blkdev->rings.common.rsp_prod_pvt == blkdev->rings.common.req_cons) { + RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&dataplane->rings.common, + send_notify); + if (dataplane->rings.common.rsp_prod_pvt == + dataplane->rings.common.req_cons) { /* * Tail check for pending requests. Allows frontend to avoid * notifications if requests are already in flight (lower * overheads and promotes batching). */ - RING_FINAL_CHECK_FOR_REQUESTS(&blkdev->rings.common, have_requests); - } else if (RING_HAS_UNCONSUMED_REQUESTS(&blkdev->rings.common)) { + RING_FINAL_CHECK_FOR_REQUESTS(&dataplane->rings.common, + have_requests); + } else if (RING_HAS_UNCONSUMED_REQUESTS(&dataplane->rings.common)) { have_requests = 1; } if (have_requests) { - blkdev->more_work++; + dataplane->more_work++; } return send_notify; } /* walk finished list, send outstanding responses, free requests */ -static void blk_send_response_all(struct XenBlkDev *blkdev) +static void blk_send_response_all(XenBlockDataPlane *dataplane) { struct ioreq *ioreq; int send_notify = 0; - while (!QLIST_EMPTY(&blkdev->finished)) { - ioreq = QLIST_FIRST(&blkdev->finished); + while (!QLIST_EMPTY(&dataplane->finished)) { + ioreq = QLIST_FIRST(&dataplane->finished); send_notify += blk_send_response_one(ioreq); ioreq_release(ioreq, true); } if (send_notify) { Error *local_err = NULL; - xen_device_notify_event_channel(blkdev->xendev, - blkdev->event_channel, + xen_device_notify_event_channel(dataplane->xendev, + dataplane->event_channel, &local_err); if (local_err) { error_report_err(local_err); @@ -496,67 +499,76 @@ static void blk_send_response_all(struct XenBlkDev *blkdev) } } -static int blk_get_request(struct XenBlkDev *blkdev, struct ioreq *ioreq, +static int blk_get_request(XenBlockDataPlane *dataplane, struct ioreq *ioreq, RING_IDX rc) { - switch (blkdev->protocol) { - case BLKIF_PROTOCOL_NATIVE: - memcpy(&ioreq->req, RING_GET_REQUEST(&blkdev->rings.native, rc), - sizeof(ioreq->req)); + switch (dataplane->protocol) { + case BLKIF_PROTOCOL_NATIVE: { + blkif_request_t *req = + RING_GET_REQUEST(&dataplane->rings.native, rc); + + memcpy(&ioreq->req, req, sizeof(ioreq->req)); break; - case BLKIF_PROTOCOL_X86_32: - blkif_get_x86_32_req(&ioreq->req, - RING_GET_REQUEST(&blkdev->rings.x86_32_part, rc)); + } + case BLKIF_PROTOCOL_X86_32: { + blkif_x86_32_request_t *req = + RING_GET_REQUEST(&dataplane->rings.x86_32_part, rc); + + blkif_get_x86_32_req(&ioreq->req, req); break; - case BLKIF_PROTOCOL_X86_64: - blkif_get_x86_64_req(&ioreq->req, - RING_GET_REQUEST(&blkdev->rings.x86_64_part, rc)); + } + case BLKIF_PROTOCOL_X86_64: { + blkif_x86_64_request_t *req = + RING_GET_REQUEST(&dataplane->rings.x86_64_part, rc); + + blkif_get_x86_64_req(&ioreq->req, req); break; } + } /* Prevent the compiler from accessing the on-ring fields instead. */ barrier(); return 0; } -static void blk_handle_requests(struct XenBlkDev *blkdev) +static void blk_handle_requests(XenBlockDataPlane *dataplane) { RING_IDX rc, rp; struct ioreq *ioreq; - blkdev->more_work = 0; + dataplane->more_work = 0; - rc = blkdev->rings.common.req_cons; - rp = blkdev->rings.common.sring->req_prod; + rc = dataplane->rings.common.req_cons; + rp = dataplane->rings.common.sring->req_prod; xen_rmb(); /* Ensure we see queued requests up to 'rp'. */ - blk_send_response_all(blkdev); + blk_send_response_all(dataplane); while (rc != rp) { /* pull request from ring */ - if (RING_REQUEST_CONS_OVERFLOW(&blkdev->rings.common, rc)) { + if (RING_REQUEST_CONS_OVERFLOW(&dataplane->rings.common, rc)) { break; } - ioreq = ioreq_start(blkdev); + ioreq = ioreq_start(dataplane); if (ioreq == NULL) { - blkdev->more_work++; + dataplane->more_work++; break; } - blk_get_request(blkdev, ioreq, rc); - blkdev->rings.common.req_cons = ++rc; + blk_get_request(dataplane, ioreq, rc); + dataplane->rings.common.req_cons = ++rc; /* parse them */ if (ioreq_parse(ioreq) != 0) { switch (ioreq->req.operation) { case BLKIF_OP_READ: - block_acct_invalid(blk_get_stats(blkdev->blk), + block_acct_invalid(blk_get_stats(dataplane->blk), BLOCK_ACCT_READ); break; case BLKIF_OP_WRITE: - block_acct_invalid(blk_get_stats(blkdev->blk), + block_acct_invalid(blk_get_stats(dataplane->blk), BLOCK_ACCT_WRITE); break; case BLKIF_OP_FLUSH_DISKCACHE: - block_acct_invalid(blk_get_stats(blkdev->blk), + block_acct_invalid(blk_get_stats(dataplane->blk), BLOCK_ACCT_FLUSH); default: break; @@ -565,8 +577,8 @@ static void blk_handle_requests(struct XenBlkDev *blkdev) if (blk_send_response_one(ioreq)) { Error *local_err = NULL; - xen_device_notify_event_channel(blkdev->xendev, - blkdev->event_channel, + xen_device_notify_event_channel(dataplane->xendev, + dataplane->event_channel, &local_err); if (local_err) { error_report_err(local_err); @@ -579,173 +591,173 @@ static void blk_handle_requests(struct XenBlkDev *blkdev) ioreq_runio_qemu_aio(ioreq); } - if (blkdev->more_work && blkdev->requests_inflight < blkdev->max_requests) { - qemu_bh_schedule(blkdev->bh); + if (dataplane->more_work && + dataplane->requests_inflight < dataplane->max_requests) { + qemu_bh_schedule(dataplane->bh); } } static void blk_bh(void *opaque) { - struct XenBlkDev *blkdev = opaque; + XenBlockDataPlane *dataplane = opaque; - aio_context_acquire(blkdev->ctx); - blk_handle_requests(blkdev); - aio_context_release(blkdev->ctx); + aio_context_acquire(dataplane->ctx); + blk_handle_requests(dataplane); + aio_context_release(dataplane->ctx); } static void blk_event(void *opaque) { - struct XenBlkDev *blkdev = opaque; + XenBlockDataPlane *dataplane = opaque; - qemu_bh_schedule(blkdev->bh); + qemu_bh_schedule(dataplane->bh); } -struct XenBlkDev *xen_block_dataplane_create(XenDevice *xendev, - BlockConf *conf, - IOThread *iothread) +XenBlockDataPlane *xen_block_dataplane_create(XenDevice *xendev, + BlockConf *conf, + IOThread *iothread) { - struct XenBlkDev *blkdev = g_new0(struct XenBlkDev, 1); + XenBlockDataPlane *dataplane = g_new0(XenBlockDataPlane, 1); - blkdev->xendev = xendev; - blkdev->file_blk = conf->logical_block_size; - blkdev->blk = conf->blk; - blkdev->file_size = blk_getlength(blkdev->blk); + dataplane->xendev = xendev; + dataplane->file_blk = conf->logical_block_size; + dataplane->blk = conf->blk; + dataplane->file_size = blk_getlength(dataplane->blk); - QLIST_INIT(&blkdev->inflight); - QLIST_INIT(&blkdev->finished); - QLIST_INIT(&blkdev->freelist); + QLIST_INIT(&dataplane->inflight); + QLIST_INIT(&dataplane->finished); + QLIST_INIT(&dataplane->freelist); if (iothread) { - blkdev->iothread = iothread; - object_ref(OBJECT(blkdev->iothread)); - blkdev->ctx = iothread_get_aio_context(blkdev->iothread); + dataplane->iothread = iothread; + object_ref(OBJECT(dataplane->iothread)); + dataplane->ctx = iothread_get_aio_context(dataplane->iothread); } else { - blkdev->ctx = qemu_get_aio_context(); + dataplane->ctx = qemu_get_aio_context(); } - blkdev->bh = aio_bh_new(blkdev->ctx, blk_bh, blkdev); + dataplane->bh = aio_bh_new(dataplane->ctx, blk_bh, dataplane); - return blkdev; + return dataplane; } -void xen_block_dataplane_destroy(struct XenBlkDev *blkdev) +void xen_block_dataplane_destroy(XenBlockDataPlane *dataplane) { struct ioreq *ioreq; - if (!blkdev) { + if (!dataplane) { return; } - while (!QLIST_EMPTY(&blkdev->freelist)) { - ioreq = QLIST_FIRST(&blkdev->freelist); + while (!QLIST_EMPTY(&dataplane->freelist)) { + ioreq = QLIST_FIRST(&dataplane->freelist); QLIST_REMOVE(ioreq, list); qemu_iovec_destroy(&ioreq->v); g_free(ioreq); } - qemu_bh_delete(blkdev->bh); - if (blkdev->iothread) { - object_unref(OBJECT(blkdev->iothread)); + qemu_bh_delete(dataplane->bh); + if (dataplane->iothread) { + object_unref(OBJECT(dataplane->iothread)); } - g_free(blkdev); + g_free(dataplane); } - -void xen_block_dataplane_stop(struct XenBlkDev *blkdev) +void xen_block_dataplane_stop(XenBlockDataPlane *dataplane) { XenDevice *xendev; - if (!blkdev) { + if (!dataplane) { return; } - aio_context_acquire(blkdev->ctx); - blk_set_aio_context(blkdev->blk, qemu_get_aio_context()); - aio_context_release(blkdev->ctx); + aio_context_acquire(dataplane->ctx); + blk_set_aio_context(dataplane->blk, qemu_get_aio_context()); + aio_context_release(dataplane->ctx); - xendev = blkdev->xendev; + xendev = dataplane->xendev; - if (blkdev->event_channel) { + if (dataplane->event_channel) { Error *local_err = NULL; - xen_device_unbind_event_channel(xendev, blkdev->event_channel, + xen_device_unbind_event_channel(xendev, dataplane->event_channel, &local_err); - blkdev->event_channel = NULL; + dataplane->event_channel = NULL; if (local_err) { error_report_err(local_err); } } - if (blkdev->sring) { + if (dataplane->sring) { Error *local_err = NULL; - xen_device_unmap_grant_refs(xendev, blkdev->sring, - blkdev->nr_ring_ref, &local_err); - blkdev->sring = NULL; + xen_device_unmap_grant_refs(xendev, dataplane->sring, + dataplane->nr_ring_ref, &local_err); + dataplane->sring = NULL; if (local_err) { error_report_err(local_err); } } - g_free(blkdev->ring_ref); - blkdev->ring_ref = NULL; + g_free(dataplane->ring_ref); + dataplane->ring_ref = NULL; } -void xen_block_dataplane_start(struct XenBlkDev *blkdev, +void xen_block_dataplane_start(XenBlockDataPlane *dataplane, const unsigned int ring_ref[], unsigned int nr_ring_ref, unsigned int event_channel, unsigned int protocol, Error **errp) { - XenDevice *xendev = blkdev->xendev; + XenDevice *xendev = dataplane->xendev; Error *local_err = NULL; unsigned int ring_size; unsigned int i; - blkdev->nr_ring_ref = nr_ring_ref; - blkdev->ring_ref = g_new(unsigned int, nr_ring_ref); + dataplane->nr_ring_ref = nr_ring_ref; + dataplane->ring_ref = g_new(unsigned int, nr_ring_ref); for (i = 0; i < nr_ring_ref; i++) { - blkdev->ring_ref[i] = ring_ref[i]; + dataplane->ring_ref[i] = ring_ref[i]; } - blkdev->protocol = protocol; + dataplane->protocol = protocol; - ring_size = XC_PAGE_SIZE * blkdev->nr_ring_ref; - switch (blkdev->protocol) { + ring_size = XC_PAGE_SIZE * dataplane->nr_ring_ref; + switch (dataplane->protocol) { case BLKIF_PROTOCOL_NATIVE: { - blkdev->max_requests = __CONST_RING_SIZE(blkif, ring_size); + dataplane->max_requests = __CONST_RING_SIZE(blkif, ring_size); break; } case BLKIF_PROTOCOL_X86_32: { - blkdev->max_requests = __CONST_RING_SIZE(blkif_x86_32, ring_size); + dataplane->max_requests = __CONST_RING_SIZE(blkif_x86_32, ring_size); break; } case BLKIF_PROTOCOL_X86_64: { - blkdev->max_requests = __CONST_RING_SIZE(blkif_x86_64, ring_size); + dataplane->max_requests = __CONST_RING_SIZE(blkif_x86_64, ring_size); break; } default: - error_setg(errp, "unknown protocol %u", blkdev->protocol); + error_setg(errp, "unknown protocol %u", dataplane->protocol); return; } - xen_device_set_max_grant_refs(xendev, blkdev->nr_ring_ref, + xen_device_set_max_grant_refs(xendev, dataplane->nr_ring_ref, &local_err); if (local_err) { error_propagate(errp, local_err); goto stop; } - blkdev->sring = xen_device_map_grant_refs(xendev, - blkdev->ring_ref, - blkdev->nr_ring_ref, + dataplane->sring = xen_device_map_grant_refs(xendev, + dataplane->ring_ref, + dataplane->nr_ring_ref, PROT_READ | PROT_WRITE, &local_err); if (local_err) { @@ -753,46 +765,46 @@ void xen_block_dataplane_start(struct XenBlkDev *blkdev, goto stop; } - switch (blkdev->protocol) { + switch (dataplane->protocol) { case BLKIF_PROTOCOL_NATIVE: { - blkif_sring_t *sring_native = blkdev->sring; + blkif_sring_t *sring_native = dataplane->sring; - BACK_RING_INIT(&blkdev->rings.native, sring_native, ring_size); + BACK_RING_INIT(&dataplane->rings.native, sring_native, ring_size); break; } case BLKIF_PROTOCOL_X86_32: { - blkif_x86_32_sring_t *sring_x86_32 = blkdev->sring; + blkif_x86_32_sring_t *sring_x86_32 = dataplane->sring; - BACK_RING_INIT(&blkdev->rings.x86_32_part, sring_x86_32, + BACK_RING_INIT(&dataplane->rings.x86_32_part, sring_x86_32, ring_size); break; } case BLKIF_PROTOCOL_X86_64: { - blkif_x86_64_sring_t *sring_x86_64 = blkdev->sring; + blkif_x86_64_sring_t *sring_x86_64 = dataplane->sring; - BACK_RING_INIT(&blkdev->rings.x86_64_part, sring_x86_64, + BACK_RING_INIT(&dataplane->rings.x86_64_part, sring_x86_64, ring_size); break; } } - blkdev->event_channel = + dataplane->event_channel = xen_device_bind_event_channel(xendev, event_channel, - blk_event, blkdev, + blk_event, dataplane, &local_err); if (local_err) { error_propagate(errp, local_err); goto stop; } - aio_context_acquire(blkdev->ctx); - blk_set_aio_context(blkdev->blk, blkdev->ctx); - aio_context_release(blkdev->ctx); + aio_context_acquire(dataplane->ctx); + blk_set_aio_context(dataplane->blk, dataplane->ctx); + aio_context_release(dataplane->ctx); return; stop: - xen_block_dataplane_stop(blkdev); + xen_block_dataplane_stop(dataplane); } diff --git a/hw/block/dataplane/xen-block.h b/hw/block/dataplane/xen-block.h index f31da38..d6fa6d2 100644 --- a/hw/block/dataplane/xen-block.h +++ b/hw/block/dataplane/xen-block.h @@ -12,7 +12,7 @@ #include "hw/xen/xen-bus.h" #include "sysemu/iothread.h" -typedef struct XenBlkDev XenBlockDataPlane; +typedef struct XenBlockDataPlane XenBlockDataPlane; XenBlockDataPlane *xen_block_dataplane_create(XenDevice *xendev, BlockConf *conf, From patchwork Mon Dec 17 11:40:42 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 1014440 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=citrix.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 43JKT04ch4z9s2P for ; Mon, 17 Dec 2018 22:59:31 +1100 (AEDT) Received: from localhost ([::1]:46240 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrYT-0007JO-Sh for incoming@patchwork.ozlabs.org; Mon, 17 Dec 2018 06:59:25 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:57982) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrXs-0007H7-Ci for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:58:50 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gYrXo-0003QI-5V for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:58:47 -0500 Received: from smtp03.citrix.com ([162.221.156.55]:45508) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gYrXn-0003Ov-PR; Mon, 17 Dec 2018 06:58:44 -0500 X-IronPort-AV: E=Sophos;i="5.56,365,1539648000"; d="scan'208";a="73533621" From: Paul Durrant To: , , Date: Mon, 17 Dec 2018 11:40:42 +0000 Message-ID: <1545046848-14891-13-git-send-email-paul.durrant@citrix.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> References: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 162.221.156.55 Subject: [Qemu-devel] [PATCH v5 12/18] xen: remove 'ioreq' struct/varable/field names from dataplane/xen-block.c X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Paul Durrant , Stefano Stabellini , Stefan Hajnoczi , Max Reitz Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This is a purely cosmetic patch that purges the name 'ioreq' from struct, variable and field names. (This name has been problematic for a long time as 'ioreq' is the name used for generic I/O requests coming from Xen). The patch replaces 'struct ioreq' with a new 'XenBlockRequest' type and 'ioreq' field/variable names with 'request', and then does necessary fix-up to adhere to coding style. Function names are not modified by this patch. They will be dealt with in a subsequent patch. No functional change. Signed-off-by: Paul Durrant Acked-by: Anthony Perard --- Cc: Stefan Hajnoczi Cc: Stefano Stabellini Cc: Kevin Wolf Cc: Max Reitz --- hw/block/dataplane/xen-block.c | 310 +++++++++++++++++++++-------------------- 1 file changed, 156 insertions(+), 154 deletions(-) diff --git a/hw/block/dataplane/xen-block.c b/hw/block/dataplane/xen-block.c index 6ecd160..426e83c 100644 --- a/hw/block/dataplane/xen-block.c +++ b/hw/block/dataplane/xen-block.c @@ -34,7 +34,7 @@ #include "sysemu/iothread.h" #include "xen-block.h" -struct ioreq { +typedef struct XenBlockRequest { blkif_request_t req; int16_t status; off_t start; @@ -45,9 +45,9 @@ struct ioreq { int aio_inflight; int aio_errors; XenBlockDataPlane *dataplane; - QLIST_ENTRY(ioreq) list; + QLIST_ENTRY(XenBlockRequest) list; BlockAcctCookie acct; -}; +} XenBlockRequest; struct XenBlockDataPlane { XenDevice *xendev; @@ -60,9 +60,9 @@ struct XenBlockDataPlane { int protocol; blkif_back_rings_t rings; int more_work; - QLIST_HEAD(inflight_head, ioreq) inflight; - QLIST_HEAD(finished_head, ioreq) finished; - QLIST_HEAD(freelist_head, ioreq) freelist; + QLIST_HEAD(inflight_head, XenBlockRequest) inflight; + QLIST_HEAD(finished_head, XenBlockRequest) finished; + QLIST_HEAD(freelist_head, XenBlockRequest) freelist; int requests_total; int requests_inflight; int requests_finished; @@ -73,68 +73,68 @@ struct XenBlockDataPlane { AioContext *ctx; }; -static void ioreq_reset(struct ioreq *ioreq) +static void ioreq_reset(XenBlockRequest *request) { - memset(&ioreq->req, 0, sizeof(ioreq->req)); - ioreq->status = 0; - ioreq->start = 0; - ioreq->buf = NULL; - ioreq->size = 0; - ioreq->presync = 0; + memset(&request->req, 0, sizeof(request->req)); + request->status = 0; + request->start = 0; + request->buf = NULL; + request->size = 0; + request->presync = 0; - ioreq->aio_inflight = 0; - ioreq->aio_errors = 0; + request->aio_inflight = 0; + request->aio_errors = 0; - ioreq->dataplane = NULL; - memset(&ioreq->list, 0, sizeof(ioreq->list)); - memset(&ioreq->acct, 0, sizeof(ioreq->acct)); + request->dataplane = NULL; + memset(&request->list, 0, sizeof(request->list)); + memset(&request->acct, 0, sizeof(request->acct)); - qemu_iovec_reset(&ioreq->v); + qemu_iovec_reset(&request->v); } -static struct ioreq *ioreq_start(XenBlockDataPlane *dataplane) +static XenBlockRequest *ioreq_start(XenBlockDataPlane *dataplane) { - struct ioreq *ioreq = NULL; + XenBlockRequest *request = NULL; if (QLIST_EMPTY(&dataplane->freelist)) { if (dataplane->requests_total >= dataplane->max_requests) { goto out; } /* allocate new struct */ - ioreq = g_malloc0(sizeof(*ioreq)); - ioreq->dataplane = dataplane; + request = g_malloc0(sizeof(*request)); + request->dataplane = dataplane; dataplane->requests_total++; - qemu_iovec_init(&ioreq->v, 1); + qemu_iovec_init(&request->v, 1); } else { /* get one from freelist */ - ioreq = QLIST_FIRST(&dataplane->freelist); - QLIST_REMOVE(ioreq, list); + request = QLIST_FIRST(&dataplane->freelist); + QLIST_REMOVE(request, list); } - QLIST_INSERT_HEAD(&dataplane->inflight, ioreq, list); + QLIST_INSERT_HEAD(&dataplane->inflight, request, list); dataplane->requests_inflight++; out: - return ioreq; + return request; } -static void ioreq_finish(struct ioreq *ioreq) +static void ioreq_finish(XenBlockRequest *request) { - XenBlockDataPlane *dataplane = ioreq->dataplane; + XenBlockDataPlane *dataplane = request->dataplane; - QLIST_REMOVE(ioreq, list); - QLIST_INSERT_HEAD(&dataplane->finished, ioreq, list); + QLIST_REMOVE(request, list); + QLIST_INSERT_HEAD(&dataplane->finished, request, list); dataplane->requests_inflight--; dataplane->requests_finished++; } -static void ioreq_release(struct ioreq *ioreq, bool finish) +static void ioreq_release(XenBlockRequest *request, bool finish) { - XenBlockDataPlane *dataplane = ioreq->dataplane; + XenBlockDataPlane *dataplane = request->dataplane; - QLIST_REMOVE(ioreq, list); - ioreq_reset(ioreq); - ioreq->dataplane = dataplane; - QLIST_INSERT_HEAD(&dataplane->freelist, ioreq, list); + QLIST_REMOVE(request, list); + ioreq_reset(request); + request->dataplane = dataplane; + QLIST_INSERT_HEAD(&dataplane->freelist, request, list); if (finish) { dataplane->requests_finished--; } else { @@ -146,18 +146,18 @@ static void ioreq_release(struct ioreq *ioreq, bool finish) * translate request into iovec + start offset * do sanity checks along the way */ -static int ioreq_parse(struct ioreq *ioreq) +static int ioreq_parse(XenBlockRequest *request) { - XenBlockDataPlane *dataplane = ioreq->dataplane; + XenBlockDataPlane *dataplane = request->dataplane; size_t len; int i; - switch (ioreq->req.operation) { + switch (request->req.operation) { case BLKIF_OP_READ: break; case BLKIF_OP_FLUSH_DISKCACHE: - ioreq->presync = 1; - if (!ioreq->req.nr_segments) { + request->presync = 1; + if (!request->req.nr_segments) { return 0; } /* fall through */ @@ -166,77 +166,78 @@ static int ioreq_parse(struct ioreq *ioreq) case BLKIF_OP_DISCARD: return 0; default: - error_report("error: unknown operation (%d)", ioreq->req.operation); + error_report("error: unknown operation (%d)", request->req.operation); goto err; }; - if (ioreq->req.operation != BLKIF_OP_READ && + if (request->req.operation != BLKIF_OP_READ && blk_is_read_only(dataplane->blk)) { error_report("error: write req for ro device"); goto err; } - ioreq->start = ioreq->req.sector_number * dataplane->file_blk; - for (i = 0; i < ioreq->req.nr_segments; i++) { + request->start = request->req.sector_number * dataplane->file_blk; + for (i = 0; i < request->req.nr_segments; i++) { if (i == BLKIF_MAX_SEGMENTS_PER_REQUEST) { error_report("error: nr_segments too big"); goto err; } - if (ioreq->req.seg[i].first_sect > ioreq->req.seg[i].last_sect) { + if (request->req.seg[i].first_sect > request->req.seg[i].last_sect) { error_report("error: first > last sector"); goto err; } - if (ioreq->req.seg[i].last_sect * dataplane->file_blk >= XC_PAGE_SIZE) { + if (request->req.seg[i].last_sect * dataplane->file_blk >= + XC_PAGE_SIZE) { error_report("error: page crossing"); goto err; } - len = (ioreq->req.seg[i].last_sect - - ioreq->req.seg[i].first_sect + 1) * dataplane->file_blk; - ioreq->size += len; + len = (request->req.seg[i].last_sect - + request->req.seg[i].first_sect + 1) * dataplane->file_blk; + request->size += len; } - if (ioreq->start + ioreq->size > dataplane->file_size) { + if (request->start + request->size > dataplane->file_size) { error_report("error: access beyond end of file"); goto err; } return 0; err: - ioreq->status = BLKIF_RSP_ERROR; + request->status = BLKIF_RSP_ERROR; return -1; } -static int ioreq_grant_copy(struct ioreq *ioreq) +static int ioreq_grant_copy(XenBlockRequest *request) { - XenBlockDataPlane *dataplane = ioreq->dataplane; + XenBlockDataPlane *dataplane = request->dataplane; XenDevice *xendev = dataplane->xendev; XenDeviceGrantCopySegment segs[BLKIF_MAX_SEGMENTS_PER_REQUEST]; int i, count; int64_t file_blk = dataplane->file_blk; - bool to_domain = (ioreq->req.operation == BLKIF_OP_READ); - void *virt = ioreq->buf; + bool to_domain = (request->req.operation == BLKIF_OP_READ); + void *virt = request->buf; Error *local_err = NULL; - if (ioreq->req.nr_segments == 0) { + if (request->req.nr_segments == 0) { return 0; } - count = ioreq->req.nr_segments; + count = request->req.nr_segments; for (i = 0; i < count; i++) { if (to_domain) { - segs[i].dest.foreign.ref = ioreq->req.seg[i].gref; - segs[i].dest.foreign.offset = ioreq->req.seg[i].first_sect * + segs[i].dest.foreign.ref = request->req.seg[i].gref; + segs[i].dest.foreign.offset = request->req.seg[i].first_sect * file_blk; segs[i].source.virt = virt; } else { - segs[i].source.foreign.ref = ioreq->req.seg[i].gref; - segs[i].source.foreign.offset = ioreq->req.seg[i].first_sect * + segs[i].source.foreign.ref = request->req.seg[i].gref; + segs[i].source.foreign.offset = request->req.seg[i].first_sect * file_blk; segs[i].dest.virt = virt; } - segs[i].len = (ioreq->req.seg[i].last_sect - - ioreq->req.seg[i].first_sect + 1) * file_blk; + segs[i].len = (request->req.seg[i].last_sect - + request->req.seg[i].first_sect + 1) * file_blk; virt += segs[i].len; } @@ -245,72 +246,72 @@ static int ioreq_grant_copy(struct ioreq *ioreq) if (local_err) { error_reportf_err(local_err, "failed to copy data: "); - ioreq->aio_errors++; + request->aio_errors++; return -1; } return 0; } -static int ioreq_runio_qemu_aio(struct ioreq *ioreq); +static int ioreq_runio_qemu_aio(XenBlockRequest *request); static void qemu_aio_complete(void *opaque, int ret) { - struct ioreq *ioreq = opaque; - XenBlockDataPlane *dataplane = ioreq->dataplane; + XenBlockRequest *request = opaque; + XenBlockDataPlane *dataplane = request->dataplane; aio_context_acquire(dataplane->ctx); if (ret != 0) { error_report("%s I/O error", - ioreq->req.operation == BLKIF_OP_READ ? + request->req.operation == BLKIF_OP_READ ? "read" : "write"); - ioreq->aio_errors++; + request->aio_errors++; } - ioreq->aio_inflight--; - if (ioreq->presync) { - ioreq->presync = 0; - ioreq_runio_qemu_aio(ioreq); + request->aio_inflight--; + if (request->presync) { + request->presync = 0; + ioreq_runio_qemu_aio(request); goto done; } - if (ioreq->aio_inflight > 0) { + if (request->aio_inflight > 0) { goto done; } - switch (ioreq->req.operation) { + switch (request->req.operation) { case BLKIF_OP_READ: - /* in case of failure ioreq->aio_errors is increased */ + /* in case of failure request->aio_errors is increased */ if (ret == 0) { - ioreq_grant_copy(ioreq); + ioreq_grant_copy(request); } - qemu_vfree(ioreq->buf); + qemu_vfree(request->buf); break; case BLKIF_OP_WRITE: case BLKIF_OP_FLUSH_DISKCACHE: - if (!ioreq->req.nr_segments) { + if (!request->req.nr_segments) { break; } - qemu_vfree(ioreq->buf); + qemu_vfree(request->buf); break; default: break; } - ioreq->status = ioreq->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY; - ioreq_finish(ioreq); + request->status = request->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY; + ioreq_finish(request); - switch (ioreq->req.operation) { + switch (request->req.operation) { case BLKIF_OP_WRITE: case BLKIF_OP_FLUSH_DISKCACHE: - if (!ioreq->req.nr_segments) { + if (!request->req.nr_segments) { break; } case BLKIF_OP_READ: - if (ioreq->status == BLKIF_RSP_OKAY) { - block_acct_done(blk_get_stats(dataplane->blk), &ioreq->acct); + if (request->status == BLKIF_RSP_OKAY) { + block_acct_done(blk_get_stats(dataplane->blk), &request->acct); } else { - block_acct_failed(blk_get_stats(dataplane->blk), &ioreq->acct); + block_acct_failed(blk_get_stats(dataplane->blk), &request->acct); } break; case BLKIF_OP_DISCARD: @@ -323,10 +324,11 @@ done: aio_context_release(dataplane->ctx); } -static bool blk_split_discard(struct ioreq *ioreq, blkif_sector_t sector_number, +static bool blk_split_discard(XenBlockRequest *request, + blkif_sector_t sector_number, uint64_t nr_sectors) { - XenBlockDataPlane *dataplane = ioreq->dataplane; + XenBlockDataPlane *dataplane = request->dataplane; int64_t byte_offset; int byte_chunk; uint64_t byte_remaining, limit; @@ -345,9 +347,9 @@ static bool blk_split_discard(struct ioreq *ioreq, blkif_sector_t sector_number, do { byte_chunk = byte_remaining > limit ? limit : byte_remaining; - ioreq->aio_inflight++; + request->aio_inflight++; blk_aio_pdiscard(dataplane->blk, byte_offset, byte_chunk, - qemu_aio_complete, ioreq); + qemu_aio_complete, request); byte_remaining -= byte_chunk; byte_offset += byte_chunk; } while (byte_remaining > 0); @@ -355,53 +357,53 @@ static bool blk_split_discard(struct ioreq *ioreq, blkif_sector_t sector_number, return true; } -static int ioreq_runio_qemu_aio(struct ioreq *ioreq) +static int ioreq_runio_qemu_aio(XenBlockRequest *request) { - XenBlockDataPlane *dataplane = ioreq->dataplane; - - ioreq->buf = qemu_memalign(XC_PAGE_SIZE, ioreq->size); - if (ioreq->req.nr_segments && - (ioreq->req.operation == BLKIF_OP_WRITE || - ioreq->req.operation == BLKIF_OP_FLUSH_DISKCACHE) && - ioreq_grant_copy(ioreq)) { - qemu_vfree(ioreq->buf); + XenBlockDataPlane *dataplane = request->dataplane; + + request->buf = qemu_memalign(XC_PAGE_SIZE, request->size); + if (request->req.nr_segments && + (request->req.operation == BLKIF_OP_WRITE || + request->req.operation == BLKIF_OP_FLUSH_DISKCACHE) && + ioreq_grant_copy(request)) { + qemu_vfree(request->buf); goto err; } - ioreq->aio_inflight++; - if (ioreq->presync) { - blk_aio_flush(ioreq->dataplane->blk, qemu_aio_complete, ioreq); + request->aio_inflight++; + if (request->presync) { + blk_aio_flush(request->dataplane->blk, qemu_aio_complete, request); return 0; } - switch (ioreq->req.operation) { + switch (request->req.operation) { case BLKIF_OP_READ: - qemu_iovec_add(&ioreq->v, ioreq->buf, ioreq->size); - block_acct_start(blk_get_stats(dataplane->blk), &ioreq->acct, - ioreq->v.size, BLOCK_ACCT_READ); - ioreq->aio_inflight++; - blk_aio_preadv(dataplane->blk, ioreq->start, &ioreq->v, 0, - qemu_aio_complete, ioreq); + qemu_iovec_add(&request->v, request->buf, request->size); + block_acct_start(blk_get_stats(dataplane->blk), &request->acct, + request->v.size, BLOCK_ACCT_READ); + request->aio_inflight++; + blk_aio_preadv(dataplane->blk, request->start, &request->v, 0, + qemu_aio_complete, request); break; case BLKIF_OP_WRITE: case BLKIF_OP_FLUSH_DISKCACHE: - if (!ioreq->req.nr_segments) { + if (!request->req.nr_segments) { break; } - qemu_iovec_add(&ioreq->v, ioreq->buf, ioreq->size); - block_acct_start(blk_get_stats(dataplane->blk), &ioreq->acct, - ioreq->v.size, - ioreq->req.operation == BLKIF_OP_WRITE ? + qemu_iovec_add(&request->v, request->buf, request->size); + block_acct_start(blk_get_stats(dataplane->blk), &request->acct, + request->v.size, + request->req.operation == BLKIF_OP_WRITE ? BLOCK_ACCT_WRITE : BLOCK_ACCT_FLUSH); - ioreq->aio_inflight++; - blk_aio_pwritev(dataplane->blk, ioreq->start, &ioreq->v, 0, - qemu_aio_complete, ioreq); + request->aio_inflight++; + blk_aio_pwritev(dataplane->blk, request->start, &request->v, 0, + qemu_aio_complete, request); break; case BLKIF_OP_DISCARD: { - struct blkif_request_discard *req = (void *)&ioreq->req; - if (!blk_split_discard(ioreq, req->sector_number, req->nr_sectors)) { + struct blkif_request_discard *req = (void *)&request->req; + if (!blk_split_discard(request, req->sector_number, req->nr_sectors)) { goto err; } break; @@ -411,19 +413,19 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq) goto err; } - qemu_aio_complete(ioreq, 0); + qemu_aio_complete(request, 0); return 0; err: - ioreq_finish(ioreq); - ioreq->status = BLKIF_RSP_ERROR; + ioreq_finish(request); + request->status = BLKIF_RSP_ERROR; return -1; } -static int blk_send_response_one(struct ioreq *ioreq) +static int blk_send_response_one(XenBlockRequest *request) { - XenBlockDataPlane *dataplane = ioreq->dataplane; + XenBlockDataPlane *dataplane = request->dataplane; int send_notify = 0; int have_requests = 0; blkif_response_t *resp; @@ -449,9 +451,9 @@ static int blk_send_response_one(struct ioreq *ioreq) return 0; } - resp->id = ioreq->req.id; - resp->operation = ioreq->req.operation; - resp->status = ioreq->status; + resp->id = request->req.id; + resp->operation = request->req.operation; + resp->status = request->status; dataplane->rings.common.rsp_prod_pvt++; @@ -479,13 +481,13 @@ static int blk_send_response_one(struct ioreq *ioreq) /* walk finished list, send outstanding responses, free requests */ static void blk_send_response_all(XenBlockDataPlane *dataplane) { - struct ioreq *ioreq; + XenBlockRequest *request; int send_notify = 0; while (!QLIST_EMPTY(&dataplane->finished)) { - ioreq = QLIST_FIRST(&dataplane->finished); - send_notify += blk_send_response_one(ioreq); - ioreq_release(ioreq, true); + request = QLIST_FIRST(&dataplane->finished); + send_notify += blk_send_response_one(request); + ioreq_release(request, true); } if (send_notify) { Error *local_err = NULL; @@ -499,29 +501,29 @@ static void blk_send_response_all(XenBlockDataPlane *dataplane) } } -static int blk_get_request(XenBlockDataPlane *dataplane, struct ioreq *ioreq, - RING_IDX rc) +static int blk_get_request(XenBlockDataPlane *dataplane, + XenBlockRequest *request, RING_IDX rc) { switch (dataplane->protocol) { case BLKIF_PROTOCOL_NATIVE: { blkif_request_t *req = RING_GET_REQUEST(&dataplane->rings.native, rc); - memcpy(&ioreq->req, req, sizeof(ioreq->req)); + memcpy(&request->req, req, sizeof(request->req)); break; } case BLKIF_PROTOCOL_X86_32: { blkif_x86_32_request_t *req = RING_GET_REQUEST(&dataplane->rings.x86_32_part, rc); - blkif_get_x86_32_req(&ioreq->req, req); + blkif_get_x86_32_req(&request->req, req); break; } case BLKIF_PROTOCOL_X86_64: { blkif_x86_64_request_t *req = RING_GET_REQUEST(&dataplane->rings.x86_64_part, rc); - blkif_get_x86_64_req(&ioreq->req, req); + blkif_get_x86_64_req(&request->req, req); break; } } @@ -533,7 +535,7 @@ static int blk_get_request(XenBlockDataPlane *dataplane, struct ioreq *ioreq, static void blk_handle_requests(XenBlockDataPlane *dataplane) { RING_IDX rc, rp; - struct ioreq *ioreq; + XenBlockRequest *request; dataplane->more_work = 0; @@ -547,18 +549,18 @@ static void blk_handle_requests(XenBlockDataPlane *dataplane) if (RING_REQUEST_CONS_OVERFLOW(&dataplane->rings.common, rc)) { break; } - ioreq = ioreq_start(dataplane); - if (ioreq == NULL) { + request = ioreq_start(dataplane); + if (request == NULL) { dataplane->more_work++; break; } - blk_get_request(dataplane, ioreq, rc); + blk_get_request(dataplane, request, rc); dataplane->rings.common.req_cons = ++rc; /* parse them */ - if (ioreq_parse(ioreq) != 0) { + if (ioreq_parse(request) != 0) { - switch (ioreq->req.operation) { + switch (request->req.operation) { case BLKIF_OP_READ: block_acct_invalid(blk_get_stats(dataplane->blk), BLOCK_ACCT_READ); @@ -574,7 +576,7 @@ static void blk_handle_requests(XenBlockDataPlane *dataplane) break; }; - if (blk_send_response_one(ioreq)) { + if (blk_send_response_one(request)) { Error *local_err = NULL; xen_device_notify_event_channel(dataplane->xendev, @@ -584,11 +586,11 @@ static void blk_handle_requests(XenBlockDataPlane *dataplane) error_report_err(local_err); } } - ioreq_release(ioreq, false); + ioreq_release(request, false); continue; } - ioreq_runio_qemu_aio(ioreq); + ioreq_runio_qemu_aio(request); } if (dataplane->more_work && @@ -642,17 +644,17 @@ XenBlockDataPlane *xen_block_dataplane_create(XenDevice *xendev, void xen_block_dataplane_destroy(XenBlockDataPlane *dataplane) { - struct ioreq *ioreq; + XenBlockRequest *request; if (!dataplane) { return; } while (!QLIST_EMPTY(&dataplane->freelist)) { - ioreq = QLIST_FIRST(&dataplane->freelist); - QLIST_REMOVE(ioreq, list); - qemu_iovec_destroy(&ioreq->v); - g_free(ioreq); + request = QLIST_FIRST(&dataplane->freelist); + QLIST_REMOVE(request, list); + qemu_iovec_destroy(&request->v); + g_free(request); } qemu_bh_delete(dataplane->bh); From patchwork Mon Dec 17 11:40:43 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 1014444 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=citrix.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 43JKXy52dHz9s2P for ; Mon, 17 Dec 2018 23:02:58 +1100 (AEDT) Received: from localhost ([::1]:46264 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrbs-0001XE-BF for incoming@patchwork.ozlabs.org; Mon, 17 Dec 2018 07:02:56 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:58123) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrY9-0007f3-3H for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:59:07 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gYrY4-0003cd-9o for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:59:04 -0500 Received: from smtp03.citrix.com ([162.221.156.55]:45522) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gYrY2-0003Tf-7v; Mon, 17 Dec 2018 06:59:00 -0500 X-IronPort-AV: E=Sophos;i="5.56,365,1539648000"; d="scan'208";a="73533636" From: Paul Durrant To: , , Date: Mon, 17 Dec 2018 11:40:43 +0000 Message-ID: <1545046848-14891-14-git-send-email-paul.durrant@citrix.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> References: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 162.221.156.55 Subject: [Qemu-devel] [PATCH v5 13/18] xen: purge 'blk' and 'ioreq' from function names in dataplane/xen-block.c X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Paul Durrant , Stefano Stabellini , Stefan Hajnoczi , Max Reitz Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This is a purely cosmetic patch that purges remaining use of 'blk' and 'ioreq' in local function names, and then makes sure all functions are prefixed with 'xen_block_'. No functional change. Signed-off-by: Paul Durrant Acked-by: Anthony Perard --- Cc: Stefano Stabellini Cc: Stefan Hajnoczi Cc: Kevin Wolf Cc: Max Reitz v2: - Add 'xen_block_' prefix --- hw/block/dataplane/xen-block.c | 90 +++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 44 deletions(-) diff --git a/hw/block/dataplane/xen-block.c b/hw/block/dataplane/xen-block.c index 426e83c..8c451ae 100644 --- a/hw/block/dataplane/xen-block.c +++ b/hw/block/dataplane/xen-block.c @@ -73,7 +73,7 @@ struct XenBlockDataPlane { AioContext *ctx; }; -static void ioreq_reset(XenBlockRequest *request) +static void reset_request(XenBlockRequest *request) { memset(&request->req, 0, sizeof(request->req)); request->status = 0; @@ -92,7 +92,7 @@ static void ioreq_reset(XenBlockRequest *request) qemu_iovec_reset(&request->v); } -static XenBlockRequest *ioreq_start(XenBlockDataPlane *dataplane) +static XenBlockRequest *xen_block_start_request(XenBlockDataPlane *dataplane) { XenBlockRequest *request = NULL; @@ -117,7 +117,7 @@ out: return request; } -static void ioreq_finish(XenBlockRequest *request) +static void xen_block_finish_request(XenBlockRequest *request) { XenBlockDataPlane *dataplane = request->dataplane; @@ -127,12 +127,12 @@ static void ioreq_finish(XenBlockRequest *request) dataplane->requests_finished++; } -static void ioreq_release(XenBlockRequest *request, bool finish) +static void xen_block_release_request(XenBlockRequest *request, bool finish) { XenBlockDataPlane *dataplane = request->dataplane; QLIST_REMOVE(request, list); - ioreq_reset(request); + reset_request(request); request->dataplane = dataplane; QLIST_INSERT_HEAD(&dataplane->freelist, request, list); if (finish) { @@ -146,7 +146,7 @@ static void ioreq_release(XenBlockRequest *request, bool finish) * translate request into iovec + start offset * do sanity checks along the way */ -static int ioreq_parse(XenBlockRequest *request) +static int xen_block_parse_request(XenBlockRequest *request) { XenBlockDataPlane *dataplane = request->dataplane; size_t len; @@ -207,7 +207,7 @@ err: return -1; } -static int ioreq_grant_copy(XenBlockRequest *request) +static int xen_block_copy_request(XenBlockRequest *request) { XenBlockDataPlane *dataplane = request->dataplane; XenDevice *xendev = dataplane->xendev; @@ -253,9 +253,9 @@ static int ioreq_grant_copy(XenBlockRequest *request) return 0; } -static int ioreq_runio_qemu_aio(XenBlockRequest *request); +static int xen_block_do_aio(XenBlockRequest *request); -static void qemu_aio_complete(void *opaque, int ret) +static void xen_block_complete_aio(void *opaque, int ret) { XenBlockRequest *request = opaque; XenBlockDataPlane *dataplane = request->dataplane; @@ -272,7 +272,7 @@ static void qemu_aio_complete(void *opaque, int ret) request->aio_inflight--; if (request->presync) { request->presync = 0; - ioreq_runio_qemu_aio(request); + xen_block_do_aio(request); goto done; } if (request->aio_inflight > 0) { @@ -283,7 +283,7 @@ static void qemu_aio_complete(void *opaque, int ret) case BLKIF_OP_READ: /* in case of failure request->aio_errors is increased */ if (ret == 0) { - ioreq_grant_copy(request); + xen_block_copy_request(request); } qemu_vfree(request->buf); break; @@ -299,7 +299,7 @@ static void qemu_aio_complete(void *opaque, int ret) } request->status = request->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY; - ioreq_finish(request); + xen_block_finish_request(request); switch (request->req.operation) { case BLKIF_OP_WRITE: @@ -324,9 +324,9 @@ done: aio_context_release(dataplane->ctx); } -static bool blk_split_discard(XenBlockRequest *request, - blkif_sector_t sector_number, - uint64_t nr_sectors) +static bool xen_block_split_discard(XenBlockRequest *request, + blkif_sector_t sector_number, + uint64_t nr_sectors) { XenBlockDataPlane *dataplane = request->dataplane; int64_t byte_offset; @@ -349,7 +349,7 @@ static bool blk_split_discard(XenBlockRequest *request, byte_chunk = byte_remaining > limit ? limit : byte_remaining; request->aio_inflight++; blk_aio_pdiscard(dataplane->blk, byte_offset, byte_chunk, - qemu_aio_complete, request); + xen_block_complete_aio, request); byte_remaining -= byte_chunk; byte_offset += byte_chunk; } while (byte_remaining > 0); @@ -357,7 +357,7 @@ static bool blk_split_discard(XenBlockRequest *request, return true; } -static int ioreq_runio_qemu_aio(XenBlockRequest *request) +static int xen_block_do_aio(XenBlockRequest *request) { XenBlockDataPlane *dataplane = request->dataplane; @@ -365,14 +365,15 @@ static int ioreq_runio_qemu_aio(XenBlockRequest *request) if (request->req.nr_segments && (request->req.operation == BLKIF_OP_WRITE || request->req.operation == BLKIF_OP_FLUSH_DISKCACHE) && - ioreq_grant_copy(request)) { + xen_block_copy_request(request)) { qemu_vfree(request->buf); goto err; } request->aio_inflight++; if (request->presync) { - blk_aio_flush(request->dataplane->blk, qemu_aio_complete, request); + blk_aio_flush(request->dataplane->blk, xen_block_complete_aio, + request); return 0; } @@ -383,7 +384,7 @@ static int ioreq_runio_qemu_aio(XenBlockRequest *request) request->v.size, BLOCK_ACCT_READ); request->aio_inflight++; blk_aio_preadv(dataplane->blk, request->start, &request->v, 0, - qemu_aio_complete, request); + xen_block_complete_aio, request); break; case BLKIF_OP_WRITE: case BLKIF_OP_FLUSH_DISKCACHE: @@ -398,12 +399,13 @@ static int ioreq_runio_qemu_aio(XenBlockRequest *request) BLOCK_ACCT_WRITE : BLOCK_ACCT_FLUSH); request->aio_inflight++; blk_aio_pwritev(dataplane->blk, request->start, &request->v, 0, - qemu_aio_complete, request); + xen_block_complete_aio, request); break; case BLKIF_OP_DISCARD: { struct blkif_request_discard *req = (void *)&request->req; - if (!blk_split_discard(request, req->sector_number, req->nr_sectors)) { + if (!xen_block_split_discard(request, req->sector_number, + req->nr_sectors)) { goto err; } break; @@ -413,17 +415,17 @@ static int ioreq_runio_qemu_aio(XenBlockRequest *request) goto err; } - qemu_aio_complete(request, 0); + xen_block_complete_aio(request, 0); return 0; err: - ioreq_finish(request); + xen_block_finish_request(request); request->status = BLKIF_RSP_ERROR; return -1; } -static int blk_send_response_one(XenBlockRequest *request) +static int xen_block_send_response_one(XenBlockRequest *request) { XenBlockDataPlane *dataplane = request->dataplane; int send_notify = 0; @@ -479,15 +481,15 @@ static int blk_send_response_one(XenBlockRequest *request) } /* walk finished list, send outstanding responses, free requests */ -static void blk_send_response_all(XenBlockDataPlane *dataplane) +static void xen_block_send_response_all(XenBlockDataPlane *dataplane) { XenBlockRequest *request; int send_notify = 0; while (!QLIST_EMPTY(&dataplane->finished)) { request = QLIST_FIRST(&dataplane->finished); - send_notify += blk_send_response_one(request); - ioreq_release(request, true); + send_notify += xen_block_send_response_one(request); + xen_block_release_request(request, true); } if (send_notify) { Error *local_err = NULL; @@ -501,8 +503,8 @@ static void blk_send_response_all(XenBlockDataPlane *dataplane) } } -static int blk_get_request(XenBlockDataPlane *dataplane, - XenBlockRequest *request, RING_IDX rc) +static int xen_block_get_request(XenBlockDataPlane *dataplane, + XenBlockRequest *request, RING_IDX rc) { switch (dataplane->protocol) { case BLKIF_PROTOCOL_NATIVE: { @@ -532,7 +534,7 @@ static int blk_get_request(XenBlockDataPlane *dataplane, return 0; } -static void blk_handle_requests(XenBlockDataPlane *dataplane) +static void xen_block_handle_requests(XenBlockDataPlane *dataplane) { RING_IDX rc, rp; XenBlockRequest *request; @@ -543,23 +545,22 @@ static void blk_handle_requests(XenBlockDataPlane *dataplane) rp = dataplane->rings.common.sring->req_prod; xen_rmb(); /* Ensure we see queued requests up to 'rp'. */ - blk_send_response_all(dataplane); + xen_block_send_response_all(dataplane); while (rc != rp) { /* pull request from ring */ if (RING_REQUEST_CONS_OVERFLOW(&dataplane->rings.common, rc)) { break; } - request = ioreq_start(dataplane); + request = xen_block_start_request(dataplane); if (request == NULL) { dataplane->more_work++; break; } - blk_get_request(dataplane, request, rc); + xen_block_get_request(dataplane, request, rc); dataplane->rings.common.req_cons = ++rc; /* parse them */ - if (ioreq_parse(request) != 0) { - + if (xen_block_parse_request(request) != 0) { switch (request->req.operation) { case BLKIF_OP_READ: block_acct_invalid(blk_get_stats(dataplane->blk), @@ -576,7 +577,7 @@ static void blk_handle_requests(XenBlockDataPlane *dataplane) break; }; - if (blk_send_response_one(request)) { + if (xen_block_send_response_one(request)) { Error *local_err = NULL; xen_device_notify_event_channel(dataplane->xendev, @@ -586,11 +587,11 @@ static void blk_handle_requests(XenBlockDataPlane *dataplane) error_report_err(local_err); } } - ioreq_release(request, false); + xen_block_release_request(request, false); continue; } - ioreq_runio_qemu_aio(request); + xen_block_do_aio(request); } if (dataplane->more_work && @@ -599,16 +600,16 @@ static void blk_handle_requests(XenBlockDataPlane *dataplane) } } -static void blk_bh(void *opaque) +static void xen_block_dataplane_bh(void *opaque) { XenBlockDataPlane *dataplane = opaque; aio_context_acquire(dataplane->ctx); - blk_handle_requests(dataplane); + xen_block_handle_requests(dataplane); aio_context_release(dataplane->ctx); } -static void blk_event(void *opaque) +static void xen_block_dataplane_event(void *opaque) { XenBlockDataPlane *dataplane = opaque; @@ -637,7 +638,8 @@ XenBlockDataPlane *xen_block_dataplane_create(XenDevice *xendev, } else { dataplane->ctx = qemu_get_aio_context(); } - dataplane->bh = aio_bh_new(dataplane->ctx, blk_bh, dataplane); + dataplane->bh = aio_bh_new(dataplane->ctx, xen_block_dataplane_bh, + dataplane); return dataplane; } @@ -795,7 +797,7 @@ void xen_block_dataplane_start(XenBlockDataPlane *dataplane, dataplane->event_channel = xen_device_bind_event_channel(xendev, event_channel, - blk_event, dataplane, + xen_block_dataplane_event, dataplane, &local_err); if (local_err) { error_propagate(errp, local_err); From patchwork Mon Dec 17 11:40:44 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 1014448 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=citrix.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 43JKfX58Xpz9s2P for ; Mon, 17 Dec 2018 23:07:48 +1100 (AEDT) Received: from localhost ([::1]:46291 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrgY-0004sD-Ad for incoming@patchwork.ozlabs.org; Mon, 17 Dec 2018 07:07:46 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:58121) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrY9-0007f2-1T for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:59:07 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gYrY4-0003cl-Ax for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:59:04 -0500 Received: from smtp03.citrix.com ([162.221.156.55]:45515) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gYrY2-0003Qj-A5; Mon, 17 Dec 2018 06:59:00 -0500 X-IronPort-AV: E=Sophos;i="5.56,365,1539648000"; d="scan'208";a="73533631" From: Paul Durrant To: , , Date: Mon, 17 Dec 2018 11:40:44 +0000 Message-ID: <1545046848-14891-15-git-send-email-paul.durrant@citrix.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> References: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 162.221.156.55 Subject: [Qemu-devel] [PATCH v5 14/18] xen: add implementations of xen-block connect and disconnect functions... X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Paul Durrant , Stefano Stabellini , Max Reitz Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" ...and wire in the dataplane. This patch adds the remaining code to make the xen-block XenDevice functional. The parameters that a block frontend expects to find are populated in the backend xenstore area, and the 'ring-ref' and 'event-channel' values specified in the frontend xenstore area are mapped/bound and used to set up the dataplane. Signed-off-by: Paul Durrant Reviewed-by: Anthony Perard --- Cc: Stefano Stabellini Cc: Kevin Wolf Cc: Max Reitz v5: - Re-base v3: - Add missing return statement to xen_block_realize() - Set device name to 'vbd' now the backend is functional - Add an unplug handler - Move backend watch code from subsequent patch since it's now needed to handle unplug v2: - Tidy up header inclusions - Stop leaking ring_ref on error - Auto-create drive for CDRom devices --- hw/block/xen-block.c | 166 ++++++++++++++++++++++++++++++++++++++++ hw/xen/trace-events | 3 + hw/xen/xen-bus.c | 187 +++++++++++++++++++++++++++++++++++++++------ include/hw/xen/xen-block.h | 9 +++ include/hw/xen/xen-bus.h | 14 +++- 5 files changed, 353 insertions(+), 26 deletions(-) diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c index 3a963b0..a7c37c1 100644 --- a/hw/block/xen-block.c +++ b/hw/block/xen-block.c @@ -10,7 +10,13 @@ #include "qapi/error.h" #include "qapi/visitor.h" #include "hw/hw.h" +#include "hw/xen/xen_common.h" +#include "hw/block/xen_blkif.h" #include "hw/xen/xen-block.h" +#include "sysemu/blockdev.h" +#include "sysemu/block-backend.h" +#include "sysemu/iothread.h" +#include "dataplane/xen-block.h" #include "trace.h" static char *xen_block_get_name(XenDevice *xendev, Error **errp) @@ -28,6 +34,8 @@ static void xen_block_disconnect(XenDevice *xendev, Error **errp) XenBlockVdev *vdev = &blockdev->props.vdev; trace_xen_block_disconnect(type, vdev->disk, vdev->partition); + + xen_block_dataplane_stop(blockdev->dataplane); } static void xen_block_connect(XenDevice *xendev, Error **errp) @@ -35,8 +43,72 @@ static void xen_block_connect(XenDevice *xendev, Error **errp) XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev); const char *type = object_get_typename(OBJECT(blockdev)); XenBlockVdev *vdev = &blockdev->props.vdev; + unsigned int order, nr_ring_ref, *ring_ref, event_channel, protocol; + char *str; trace_xen_block_connect(type, vdev->disk, vdev->partition); + + if (xen_device_frontend_scanf(xendev, "ring-page-order", "%u", + &order) != 1) { + nr_ring_ref = 1; + ring_ref = g_new(unsigned int, nr_ring_ref); + + if (xen_device_frontend_scanf(xendev, "ring-ref", "%u", + &ring_ref[0]) != 1) { + error_setg(errp, "failed to read ring-ref"); + g_free(ring_ref); + return; + } + } else if (order <= blockdev->props.max_ring_page_order) { + unsigned int i; + + nr_ring_ref = 1 << order; + ring_ref = g_new(unsigned int, nr_ring_ref); + + for (i = 0; i < nr_ring_ref; i++) { + const char *key = g_strdup_printf("ring-ref%u", i); + + if (xen_device_frontend_scanf(xendev, key, "%u", + &ring_ref[i]) != 1) { + error_setg(errp, "failed to read %s", key); + g_free((gpointer)key); + g_free(ring_ref); + return; + } + + g_free((gpointer)key); + } + } else { + error_setg(errp, "invalid ring-page-order (%d)", order); + return; + } + + if (xen_device_frontend_scanf(xendev, "event-channel", "%u", + &event_channel) != 1) { + error_setg(errp, "failed to read event-channel"); + g_free(ring_ref); + return; + } + + if (xen_device_frontend_scanf(xendev, "protocol", "%ms", + &str) != 1) { + protocol = BLKIF_PROTOCOL_NATIVE; + } else { + if (strcmp(str, XEN_IO_PROTO_ABI_X86_32) == 0) { + protocol = BLKIF_PROTOCOL_X86_32; + } else if (strcmp(str, XEN_IO_PROTO_ABI_X86_64) == 0) { + protocol = BLKIF_PROTOCOL_X86_64; + } else { + protocol = BLKIF_PROTOCOL_NATIVE; + } + + free(str); + } + + xen_block_dataplane_start(blockdev->dataplane, ring_ref, nr_ring_ref, + event_channel, protocol, errp); + + g_free(ring_ref); } static void xen_block_unrealize(XenDevice *xendev, Error **errp) @@ -56,6 +128,9 @@ static void xen_block_unrealize(XenDevice *xendev, Error **errp) /* Disconnect from the frontend in case this has not already happened */ xen_block_disconnect(xendev, NULL); + xen_block_dataplane_destroy(blockdev->dataplane); + blockdev->dataplane = NULL; + if (blockdev_class->unrealize) { blockdev_class->unrealize(blockdev, errp); } @@ -68,6 +143,7 @@ static void xen_block_realize(XenDevice *xendev, Error **errp) XEN_BLOCK_DEVICE_GET_CLASS(xendev); const char *type = object_get_typename(OBJECT(blockdev)); XenBlockVdev *vdev = &blockdev->props.vdev; + BlockConf *conf = &blockdev->props.conf; Error *local_err = NULL; if (vdev->type == XEN_BLOCK_VDEV_TYPE_INVALID) { @@ -81,8 +157,62 @@ static void xen_block_realize(XenDevice *xendev, Error **errp) blockdev_class->realize(blockdev, &local_err); if (local_err) { error_propagate(errp, local_err); + return; } } + + /* + * The blkif protocol does not deal with removable media, so it must + * always be present, even for CDRom devices. + */ + assert(conf->blk); + if (!blk_is_inserted(conf->blk)) { + error_setg(errp, "device needs media, but drive is empty"); + return; + } + + if (!blkconf_apply_backend_options(conf, blockdev->info & VDISK_READONLY, + false, errp)) { + return; + } + + if (!(blockdev->info & VDISK_CDROM) && + !blkconf_geometry(conf, NULL, 65535, 255, 255, errp)) { + return; + } + + blkconf_blocksizes(conf); + + if (conf->logical_block_size > conf->physical_block_size) { + error_setg( + errp, "logical_block_size > physical_block_size not supported"); + return; + } + + blk_set_guest_block_size(conf->blk, conf->logical_block_size); + + if (conf->discard_granularity > 0) { + xen_device_backend_printf(xendev, "feature-discard", "%u", 1); + } + + 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); + xen_device_backend_printf(xendev, "info", "%u", blockdev->info); + + xen_device_frontend_printf(xendev, "virtual-device", "%lu", + vdev->number); + xen_device_frontend_printf(xendev, "device-type", "%s", + blockdev->device_type); + + xen_device_backend_printf(xendev, "sector-size", "%u", + conf->logical_block_size); + xen_device_backend_printf(xendev, "sectors", "%lu", + blk_getlength(conf->blk) / + conf->logical_block_size); + + blockdev->dataplane = + xen_block_dataplane_create(xendev, conf, blockdev->props.iothread); } static void xen_block_frontend_changed(XenDevice *xendev, @@ -331,6 +461,11 @@ const PropertyInfo xen_block_prop_vdev = { static Property xen_block_props[] = { DEFINE_PROP("vdev", XenBlockDevice, props.vdev, xen_block_prop_vdev, XenBlockVdev), + DEFINE_BLOCK_PROPERTIES(XenBlockDevice, props.conf), + DEFINE_PROP_UINT32("max-ring-page-order", XenBlockDevice, + props.max_ring_page_order, 4), + DEFINE_PROP_LINK("iothread", XenBlockDevice, props.iothread, + TYPE_IOTHREAD, IOThread *), DEFINE_PROP_END_OF_LIST() }; @@ -339,6 +474,7 @@ static void xen_block_class_init(ObjectClass *class, void *data) DeviceClass *dev_class = DEVICE_CLASS(class); XenDeviceClass *xendev_class = XEN_DEVICE_CLASS(class); + xendev_class->device = "vbd"; xendev_class->get_name = xen_block_get_name; xendev_class->realize = xen_block_realize; xendev_class->frontend_changed = xen_block_frontend_changed; @@ -363,7 +499,18 @@ static void xen_disk_unrealize(XenBlockDevice *blockdev, Error **errp) static void xen_disk_realize(XenBlockDevice *blockdev, Error **errp) { + BlockConf *conf = &blockdev->props.conf; + trace_xen_disk_realize(); + + blockdev->device_type = "disk"; + + if (!conf->blk) { + error_setg(errp, "drive property not set"); + return; + } + + blockdev->info = blk_is_read_only(conf->blk) ? VDISK_READONLY : 0; } static void xen_disk_class_init(ObjectClass *class, void *data) @@ -391,7 +538,26 @@ static void xen_cdrom_unrealize(XenBlockDevice *blockdev, Error **errp) static void xen_cdrom_realize(XenBlockDevice *blockdev, Error **errp) { + BlockConf *conf = &blockdev->props.conf; + trace_xen_cdrom_realize(); + + blockdev->device_type = "cdrom"; + + if (!conf->blk) { + int rc; + + /* Set up an empty drive */ + conf->blk = blk_new(0, BLK_PERM_ALL); + + rc = blk_attach_dev(conf->blk, DEVICE(blockdev)); + if (!rc) { + error_setg_errno(errp, -rc, "failed to create drive"); + return; + } + } + + blockdev->info = VDISK_READONLY | VDISK_CDROM; } static void xen_cdrom_class_init(ObjectClass *class, void *data) diff --git a/hw/xen/trace-events b/hw/xen/trace-events index 22055b5..d4651bd 100644 --- a/hw/xen/trace-events +++ b/hw/xen/trace-events @@ -22,8 +22,11 @@ xen_bus_watch(const char *token) "token: %s" xen_device_realize(const char *type, char *name) "type: %s name: %s" xen_device_unrealize(const char *type, char *name) "type: %s name: %s" xen_device_backend_state(const char *type, char *name, const char *state) "type: %s name: %s -> %s" +xen_device_backend_online(const char *type, char *name, bool online) "type: %s name: %s -> %u" +xen_device_backend_changed(const char *type, char *name) "type: %s name: %s" xen_device_frontend_state(const char *type, char *name, const char *state) "type: %s name: %s -> %s" xen_device_frontend_changed(const char *type, char *name) "type: %s name: %s" +xen_device_unplug(const char *type, char *name) "type: %s name: %s" # include/hw/xen/xen-bus-helper.c xs_node_create(const char *node) "%s" diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c index 9443f27..a22aa49 100644 --- a/hw/xen/xen-bus.c +++ b/hw/xen/xen-bus.c @@ -48,6 +48,54 @@ static char *xen_device_get_frontend_path(XenDevice *xendev) xendev->frontend_id, device, xendev->name); } +static void xen_device_unplug(XenDevice *xendev, Error **errp) +{ + XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); + const char *type = object_get_typename(OBJECT(xendev)); + Error *local_err = NULL; + xs_transaction_t tid; + + trace_xen_device_unplug(type, xendev->name); + + /* Mimic the way the Xen toolstack does an unplug */ +again: + tid = xs_transaction_start(xenbus->xsh); + if (tid == XBT_NULL) { + error_setg_errno(errp, errno, "failed xs_transaction_start"); + return; + } + + xs_node_printf(xenbus->xsh, tid, xendev->backend_path, "online", + &local_err, "%u", 0); + if (local_err) { + goto abort; + } + + xs_node_printf(xenbus->xsh, tid, xendev->backend_path, "state", + &local_err, "%u", XenbusStateClosing); + if (local_err) { + goto abort; + } + + if (!xs_transaction_end(xenbus->xsh, tid, false)) { + if (errno == EAGAIN) { + goto again; + } + + error_setg_errno(errp, errno, "failed xs_transaction_end"); + } + + return; + +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); + error_propagate(errp, local_err); +} + static void xen_bus_print_dev(Monitor *mon, DeviceState *dev, int indent) { XenDevice *xendev = XEN_DEVICE(dev); @@ -208,14 +256,26 @@ fail: xen_bus_unrealize(bus, &error_abort); } +static void xen_bus_unplug_request(HotplugHandler *hotplug, + DeviceState *dev, + Error **errp) +{ + XenDevice *xendev = XEN_DEVICE(dev); + + xen_device_unplug(xendev, errp); +} + static void xen_bus_class_init(ObjectClass *class, void *data) { BusClass *bus_class = BUS_CLASS(class); + HotplugHandlerClass *hotplug_class = HOTPLUG_HANDLER_CLASS(class); bus_class->print_dev = xen_bus_print_dev; bus_class->get_dev_path = xen_bus_get_dev_path; bus_class->realize = xen_bus_realize; bus_class->unrealize = xen_bus_unrealize; + + hotplug_class->unplug_request = xen_bus_unplug_request; } static const TypeInfo xen_bus_type_info = { @@ -230,8 +290,8 @@ static const TypeInfo xen_bus_type_info = { }, }; -static void xen_device_backend_printf(XenDevice *xendev, const char *key, - const char *fmt, ...) +void xen_device_backend_printf(XenDevice *xendev, const char *key, + const char *fmt, ...) { XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); Error *local_err = NULL; @@ -287,6 +347,70 @@ enum xenbus_state xen_device_backend_get_state(XenDevice *xendev) return xendev->backend_state; } +static void xen_device_backend_set_online(XenDevice *xendev, bool online) +{ + const char *type = object_get_typename(OBJECT(xendev)); + + if (xendev->backend_online == online) { + return; + } + + trace_xen_device_backend_online(type, xendev->name, online); + + xendev->backend_online = online; + xen_device_backend_printf(xendev, "online", "%u", online); +} + +static void xen_device_backend_changed(void *opaque) +{ + XenDevice *xendev = opaque; + const char *type = object_get_typename(OBJECT(xendev)); + enum xenbus_state state; + unsigned int online; + + trace_xen_device_backend_changed(type, xendev->name); + + if (xen_device_backend_scanf(xendev, "state", "%u", &state) != 1) { + state = XenbusStateUnknown; + } + + xen_device_backend_set_state(xendev, state); + + if (xen_device_backend_scanf(xendev, "online", "%u", &online) != 1) { + online = 0; + } + + xen_device_backend_set_online(xendev, !!online); + + /* + * If the toolstack (or unplug request callback) has set the backend + * state to Closing, but there is no active frontend (i.e. the + * state is not Connected) then set the backend state to Closed. + */ + if (xendev->backend_state == XenbusStateClosing && + xendev->frontend_state != XenbusStateConnected) { + xen_device_backend_set_state(xendev, XenbusStateClosed); + } + + /* + * If a backend is still 'online' then its state should be cycled + * back round to InitWait in order for a new frontend instance to + * connect. This may happen when, for example, a frontend driver is + * re-installed or updated. + * If a backend is not 'online' then the device should be destroyed. + */ + if (xendev->backend_online && + xendev->backend_state == XenbusStateClosed) { + xen_device_backend_set_state(xendev, XenbusStateInitWait); + } else if (!xendev->backend_online && + (xendev->backend_state == XenbusStateClosed || + xendev->backend_state == XenbusStateInitialising || + xendev->backend_state == XenbusStateInitWait || + xendev->backend_state == XenbusStateUnknown)) { + object_unparent(OBJECT(xendev)); + } +} + static void xen_device_backend_create(XenDevice *xendev, Error **errp) { XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); @@ -307,6 +431,27 @@ static void xen_device_backend_create(XenDevice *xendev, Error **errp) if (local_err) { error_propagate_prepend(errp, local_err, "failed to create backend: "); + return; + } + + xendev->backend_state_watch = + xen_bus_add_watch(xenbus, xendev->backend_path, + "state", xen_device_backend_changed, + xendev, &local_err); + if (local_err) { + error_propagate_prepend(errp, local_err, + "failed to watch backend state: "); + return; + } + + xendev->backend_online_watch = + xen_bus_add_watch(xenbus, xendev->backend_path, + "online", xen_device_backend_changed, + xendev, &local_err); + if (local_err) { + error_propagate_prepend(errp, local_err, + "failed to watch backend online: "); + return; } } @@ -315,6 +460,16 @@ static void xen_device_backend_destroy(XenDevice *xendev) XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); Error *local_err = NULL; + if (xendev->backend_online_watch) { + xen_bus_remove_watch(xenbus, xendev->backend_online_watch, NULL); + xendev->backend_online_watch = NULL; + } + + if (xendev->backend_state_watch) { + xen_bus_remove_watch(xenbus, xendev->backend_state_watch, NULL); + xendev->backend_state_watch = NULL; + } + if (!xendev->backend_path) { return; } @@ -331,8 +486,8 @@ static void xen_device_backend_destroy(XenDevice *xendev) } } -static void xen_device_frontend_printf(XenDevice *xendev, const char *key, - const char *fmt, ...) +void xen_device_frontend_printf(XenDevice *xendev, const char *key, + const char *fmt, ...) { XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); Error *local_err = NULL; @@ -350,8 +505,8 @@ static void xen_device_frontend_printf(XenDevice *xendev, const char *key, } } -static int xen_device_frontend_scanf(XenDevice *xendev, const char *key, - const char *fmt, ...) +int xen_device_frontend_scanf(XenDevice *xendev, const char *key, + const char *fmt, ...) { XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); va_list ap; @@ -407,24 +562,6 @@ static void xen_device_frontend_changed(void *opaque) error_reportf_err(local_err, "frontend change error: "); } } - - /* - * If a backend is still 'online' then its state should be cycled - * back round to InitWait in order for a new frontend instance to - * connect. This may happen when, for example, a frontend driver is - * re-installed or updated. - */ - if (xendev->backend_state == XenbusStateClosed) { - unsigned int online; - - if (xen_device_backend_scanf(xendev, "online", "%u", &online) != 1) { - online = 0; - } - - if (online) { - xen_device_backend_set_state(xendev, XenbusStateInitWait); - } - } } static void xen_device_frontend_create(XenDevice *xendev, Error **errp) @@ -822,9 +959,9 @@ static void xen_device_realize(DeviceState *dev, Error **errp) xendev->frontend_path); xen_device_backend_printf(xendev, "frontend-id", "%u", xendev->frontend_id); - xen_device_backend_printf(xendev, "online", "%u", 1); xen_device_backend_printf(xendev, "hotplug-status", "connected"); + xen_device_backend_set_online(xendev, true); xen_device_backend_set_state(xendev, XenbusStateInitWait); xen_device_frontend_printf(xendev, "backend", "%s", diff --git a/include/hw/xen/xen-block.h b/include/hw/xen/xen-block.h index 2941325..c4223f9 100644 --- a/include/hw/xen/xen-block.h +++ b/include/hw/xen/xen-block.h @@ -9,6 +9,9 @@ #define HW_XEN_BLOCK_H #include "hw/xen/xen-bus.h" +#include "hw/block/block.h" +#include "hw/block/dataplane/xen-block.h" +#include "sysemu/iothread.h" typedef enum XenBlockVdevType { XEN_BLOCK_VDEV_TYPE_INVALID, @@ -28,11 +31,17 @@ typedef struct XenBlockVdev { typedef struct XenBlockProperties { XenBlockVdev vdev; + BlockConf conf; + unsigned int max_ring_page_order; + IOThread *iothread; } XenBlockProperties; typedef struct XenBlockDevice { XenDevice xendev; XenBlockProperties props; + const char *device_type; + unsigned int info; + XenBlockDataPlane *dataplane; } XenBlockDevice; typedef void (*XenBlockDeviceRealize)(XenBlockDevice *blockdev, Error **errp); diff --git a/include/hw/xen/xen-bus.h b/include/hw/xen/xen-bus.h index f83a95c..0834cb3 100644 --- a/include/hw/xen/xen-bus.h +++ b/include/hw/xen/xen-bus.h @@ -23,7 +23,9 @@ typedef struct XenDevice { char *backend_path, *frontend_path; enum xenbus_state backend_state, frontend_state; Notifier exit; - XenWatch *frontend_state_watch; + XenWatch *backend_state_watch, *frontend_state_watch; + bool backend_online; + XenWatch *backend_online_watch; xengnttab_handle *xgth; bool feature_grant_copy; xenevtchn_handle *xeh; @@ -84,6 +86,16 @@ void xen_device_backend_set_state(XenDevice *xendev, enum xenbus_state state); enum xenbus_state xen_device_backend_get_state(XenDevice *xendev); +void xen_device_backend_printf(XenDevice *xendev, const char *key, + const char *fmt, ...) + GCC_FMT_ATTR(3, 4); +void xen_device_frontend_printf(XenDevice *xendev, const char *key, + const char *fmt, ...) + GCC_FMT_ATTR(3, 4); + +int xen_device_frontend_scanf(XenDevice *xendev, const char *key, + const char *fmt, ...); + void xen_device_set_max_grant_refs(XenDevice *xendev, unsigned int nr_refs, Error **errp); void *xen_device_map_grant_refs(XenDevice *xendev, uint32_t *refs, From patchwork Mon Dec 17 11:40:45 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 1014443 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=citrix.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 43JKXF4LBSz9s2P for ; Mon, 17 Dec 2018 23:02:21 +1100 (AEDT) Received: from localhost ([::1]:46260 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrbH-00017X-6T for incoming@patchwork.ozlabs.org; Mon, 17 Dec 2018 07:02:19 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:57975) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrXr-0007H6-31 for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:58:50 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gYrXn-0003Pl-KW for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:58:46 -0500 Received: from smtp03.citrix.com ([162.221.156.55]:45501) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gYrXn-0003Nv-9R; Mon, 17 Dec 2018 06:58:43 -0500 X-IronPort-AV: E=Sophos;i="5.56,365,1539648000"; d="scan'208";a="73533620" From: Paul Durrant To: , , Date: Mon, 17 Dec 2018 11:40:45 +0000 Message-ID: <1545046848-14891-16-git-send-email-paul.durrant@citrix.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> References: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 162.221.156.55 Subject: [Qemu-devel] [PATCH v5 15/18] xen: add a mechanism to automatically create XenDevice-s... X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Anthony Perard , Paul Durrant , Stefano Stabellini Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" ...that maintains compatibility with existing Xen toolstacks. Xen toolstacks instantiate PV backends by simply writing information into xenstore and expecting a backend implementation to be watching for this. This patch adds a new 'xen-backend' module to allow individual XenDevice implementations to register create and destroy functions. The creator will be called when a tool-stack instantiates a new backend in this way, and the destructor will then be called after the resulting XenDevice object is unrealized. To support this it is also necessary to add new watchers into the XenBus implementation to handle enumeration of new backends and also destruction of XenDevice-s when the toolstack sets the backend 'online' key to 0. NOTE: This patch only adds the framework. A subsequent patch will add a creator function for xen-block devices. Signed-off-by: Paul Durrant --- Cc: Anthony Perard Cc: Stefano Stabellini Cc: Anthony Perard v5: - Added destructor function, therefore Anthony's R-b is not carried from v4 v3: - Use a xenstore transaction in enumeration code to ensure consistent parameters - Not adding Anthony's R-b because of change v2: - Sort out error paths and error reporting --- hw/xen/Makefile.objs | 2 +- hw/xen/trace-events | 3 + hw/xen/xen-backend.c | 165 +++++++++++++++++++++++++++++++++++++++++++ hw/xen/xen-bus.c | 164 +++++++++++++++++++++++++++++++++++++++++- include/hw/xen/xen-backend.h | 39 ++++++++++ include/hw/xen/xen-bus.h | 1 + include/qemu/module.h | 3 + 7 files changed, 375 insertions(+), 2 deletions(-) create mode 100644 hw/xen/xen-backend.c create mode 100644 include/hw/xen/xen-backend.h diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs index 77c0868..84df60a 100644 --- a/hw/xen/Makefile.objs +++ b/hw/xen/Makefile.objs @@ -1,5 +1,5 @@ # xen backend driver support -common-obj-$(CONFIG_XEN) += xen-legacy-backend.o xen_devconfig.o xen_pvdev.o xen-common.o xen-bus.o xen-bus-helper.o +common-obj-$(CONFIG_XEN) += xen-legacy-backend.o xen_devconfig.o xen_pvdev.o xen-common.o xen-bus.o xen-bus-helper.o xen-backend.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_graphics.o xen_pt_msi.o diff --git a/hw/xen/trace-events b/hw/xen/trace-events index d4651bd..f694462 100644 --- a/hw/xen/trace-events +++ b/hw/xen/trace-events @@ -16,6 +16,9 @@ xen_domid_restrict(int err) "err: %u" # include/hw/xen/xen-bus.c xen_bus_realize(void) "" xen_bus_unrealize(void) "" +xen_bus_enumerate(void) "" +xen_bus_type_enumerate(const char *type) "type: %s" +xen_bus_backend_create(const char *type, const char *path) "type: %s path: %s" xen_bus_add_watch(const char *node, const char *key, char *token) "node: %s key: %s token: %s" xen_bus_remove_watch(const char *node, const char *key, char *token) "node: %s key: %s token: %s" xen_bus_watch(const char *token) "token: %s" diff --git a/hw/xen/xen-backend.c b/hw/xen/xen-backend.c new file mode 100644 index 0000000..da065f8 --- /dev/null +++ b/hw/xen/xen-backend.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2018 Citrix Systems Inc. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "hw/xen/xen-backend.h" +#include "hw/xen/xen-bus.h" + +typedef struct XenBackendImpl { + const char *type; + XenBackendDeviceCreate create; + XenBackendDeviceDestroy destroy; +} XenBackendImpl; + +struct XenBackendInstance { + QLIST_ENTRY(XenBackendInstance) entry; + const XenBackendImpl *impl; + XenBus *xenbus; + char *name; + XenDevice *xendev; +}; + +static GHashTable *xen_backend_table_get(void) +{ + static GHashTable *table; + + if (table == NULL) { + table = g_hash_table_new(g_str_hash, g_str_equal); + } + + return table; +} + +static void xen_backend_table_add(XenBackendImpl *impl) +{ + g_hash_table_insert(xen_backend_table_get(), (void *)impl->type, impl); +} + +static const XenBackendImpl *xen_backend_table_lookup(const char *type) +{ + return g_hash_table_lookup(xen_backend_table_get(), type); +} + +void xen_backend_register(const XenBackendInfo *info) +{ + XenBackendImpl *impl = g_new0(XenBackendImpl, 1); + + g_assert(info->type); + + if (xen_backend_table_lookup(info->type)) { + error_report("attempt to register duplicate Xen backend type '%s'", + info->type); + abort(); + } + + if (!info->create) { + error_report("backend type '%s' has no creator", info->type); + abort(); + } + + impl->type = info->type; + impl->create = info->create; + impl->destroy = info->destroy; + + xen_backend_table_add(impl); +} + +static QLIST_HEAD(, XenBackendInstance) backend_list; + +static void xen_backend_list_add(XenBackendInstance *backend) +{ + QLIST_INSERT_HEAD(&backend_list, backend, entry); +} + +static XenBackendInstance *xen_backend_list_find(XenDevice *xendev) +{ + XenBackendInstance *backend; + + QLIST_FOREACH(backend, &backend_list, entry) { + if (backend->xendev == xendev) { + return backend; + } + } + + return NULL; +} + +static void xen_backend_list_remove(XenBackendInstance *backend) +{ + QLIST_REMOVE(backend, entry); +} + +void xen_backend_device_create(XenBus *xenbus, const char *type, + const char *name, QDict *opts, Error **errp) +{ + const XenBackendImpl *impl = xen_backend_table_lookup(type); + XenBackendInstance *backend; + Error *local_error = NULL; + + if (!impl) { + return; + } + + backend = g_new0(XenBackendInstance, 1); + backend->xenbus = xenbus; + backend->name = g_strdup(name); + + impl->create(backend, opts, &local_error); + if (local_error) { + error_propagate(errp, local_error); + g_free(backend->name); + g_free(backend); + return; + } + + backend->impl = impl; + xen_backend_list_add(backend); +} + +XenBus *xen_backend_get_bus(XenBackendInstance *backend) +{ + return backend->xenbus; +} + +const char *xen_backend_get_name(XenBackendInstance *backend) +{ + return backend->name; +} + +void xen_backend_set_device(XenBackendInstance *backend, + XenDevice *xendev) +{ + g_assert(!backend->xendev); + backend->xendev = xendev; +} + +XenDevice *xen_backend_get_device(XenBackendInstance *backend) +{ + return backend->xendev; +} + + +bool xen_backend_try_device_destroy(XenDevice *xendev, Error **errp) +{ + XenBackendInstance *backend = xen_backend_list_find(xendev); + const XenBackendImpl *impl; + + if (!backend) { + return false; + } + + impl = backend->impl; + impl->destroy(backend, errp); + + xen_backend_list_remove(backend); + g_free(backend->name); + g_free(backend); + + return true; +} diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c index a22aa49..f90bcf2 100644 --- a/hw/xen/xen-bus.c +++ b/hw/xen/xen-bus.c @@ -11,10 +11,12 @@ #include "hw/hw.h" #include "hw/sysbus.h" #include "hw/xen/xen.h" +#include "hw/xen/xen-backend.h" #include "hw/xen/xen-bus.h" #include "hw/xen/xen-bus-helper.h" #include "monitor/monitor.h" #include "qapi/error.h" +#include "qapi/qmp/qdict.h" #include "sysemu/sysemu.h" #include "trace.h" @@ -190,12 +192,151 @@ static void xen_bus_remove_watch(XenBus *xenbus, XenWatch *watch, free_watch(watch); } +static void xen_bus_backend_create(XenBus *xenbus, const char *type, + const char *name, char *path, + Error **errp) +{ + xs_transaction_t tid; + char **key; + QDict *opts; + unsigned int i, n; + Error *local_err = NULL; + + trace_xen_bus_backend_create(type, path); + +again: + tid = xs_transaction_start(xenbus->xsh); + if (tid == XBT_NULL) { + error_setg(errp, "failed xs_transaction_start"); + return; + } + + key = xs_directory(xenbus->xsh, tid, path, &n); + if (!key) { + if (!xs_transaction_end(xenbus->xsh, tid, true)) { + error_setg_errno(errp, errno, "failed xs_transaction_end"); + } + return; + } + + opts = qdict_new(); + for (i = 0; i < n; i++) { + char *val; + + /* + * Assume anything found in the xenstore backend area, other than + * the keys created for a generic XenDevice, are parameters + * to be used to configure the backend. + */ + if (!strcmp(key[i], "state") || + !strcmp(key[i], "online") || + !strcmp(key[i], "frontend") || + !strcmp(key[i], "frontend-id") || + !strcmp(key[i], "hotplug-status")) + continue; + + if (xs_node_scanf(xenbus->xsh, tid, path, key[i], NULL, "%ms", + &val) == 1) { + qdict_put_str(opts, key[i], val); + free(val); + } + } + + free(key); + + if (!xs_transaction_end(xenbus->xsh, tid, false)) { + qobject_unref(opts); + + if (errno == EAGAIN) { + goto again; + } + + error_setg_errno(errp, errno, "failed xs_transaction_end"); + return; + } + + xen_backend_device_create(xenbus, type, name, opts, &local_err); + qobject_unref(opts); + + if (local_err) { + error_propagate_prepend(errp, local_err, + "failed to create '%s' device '%s': ", + type, name); + } +} + +static void xen_bus_type_enumerate(XenBus *xenbus, const char *type) +{ + char *domain_path = g_strdup_printf("backend/%s/%u", type, xen_domid); + char **backend; + unsigned int i, n; + + trace_xen_bus_type_enumerate(type); + + backend = xs_directory(xenbus->xsh, XBT_NULL, domain_path, &n); + if (!backend) { + goto out; + } + + for (i = 0; i < n; i++) { + char *backend_path = g_strdup_printf("%s/%s", domain_path, + backend[i]); + enum xenbus_state backend_state; + + if (xs_node_scanf(xenbus->xsh, XBT_NULL, backend_path, "state", + NULL, "%u", &backend_state) != 1) + backend_state = XenbusStateUnknown; + + if (backend_state == XenbusStateInitialising) { + Error *local_err = NULL; + + xen_bus_backend_create(xenbus, type, backend[i], backend_path, + &local_err); + if (local_err) { + error_report_err(local_err); + } + } + + g_free(backend_path); + } + + free(backend); + +out: + g_free(domain_path); +} + +static void xen_bus_enumerate(void *opaque) +{ + XenBus *xenbus = opaque; + char **type; + unsigned int i, n; + + trace_xen_bus_enumerate(); + + type = xs_directory(xenbus->xsh, XBT_NULL, "backend", &n); + if (!type) { + return; + } + + for (i = 0; i < n; i++) { + xen_bus_type_enumerate(xenbus, type[i]); + } + + free(type); +} + static void xen_bus_unrealize(BusState *bus, Error **errp) { XenBus *xenbus = XEN_BUS(bus); trace_xen_bus_unrealize(); + if (xenbus->backend_watch) { + xen_bus_remove_watch(xenbus, xenbus->backend_watch, NULL); + xenbus->backend_watch = NULL; + } + if (!xenbus->xsh) { return; } @@ -231,6 +372,7 @@ static void xen_bus_realize(BusState *bus, Error **errp) { XenBus *xenbus = XEN_BUS(bus); unsigned int domid; + Error *local_err = NULL; trace_xen_bus_realize(); @@ -250,6 +392,18 @@ static void xen_bus_realize(BusState *bus, Error **errp) notifier_list_init(&xenbus->watch_notifiers); qemu_set_fd_handler(xs_fileno(xenbus->xsh), xen_bus_watch, NULL, xenbus); + + module_call_init(MODULE_INIT_XEN_BACKEND); + + xenbus->backend_watch = + xen_bus_add_watch(xenbus, "", /* domain root node */ + "backend", xen_bus_enumerate, xenbus, &local_err); + if (local_err) { + /* This need not be treated as a hard error so don't propagate */ + error_reportf_err(local_err, + "failed to set up enumeration watch: "); + } + return; fail: @@ -407,7 +561,15 @@ static void xen_device_backend_changed(void *opaque) xendev->backend_state == XenbusStateInitialising || xendev->backend_state == XenbusStateInitWait || xendev->backend_state == XenbusStateUnknown)) { - object_unparent(OBJECT(xendev)); + Error *local_err = NULL; + + if (!xen_backend_try_device_destroy(xendev, &local_err)) { + object_unparent(OBJECT(xendev)); + } + + if (local_err) { + error_report_err(local_err); + } } } diff --git a/include/hw/xen/xen-backend.h b/include/hw/xen/xen-backend.h new file mode 100644 index 0000000..010d712 --- /dev/null +++ b/include/hw/xen/xen-backend.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2018 Citrix Systems Inc. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef HW_XEN_BACKEND_H +#define HW_XEN_BACKEND_H + +#include "hw/xen/xen-bus.h" + +typedef struct XenBackendInstance XenBackendInstance; + +typedef void (*XenBackendDeviceCreate)(XenBackendInstance *backend, + QDict *opts, Error **errp); +typedef void (*XenBackendDeviceDestroy)(XenBackendInstance *backend, + Error **errp); + +typedef struct XenBackendInfo { + const char *type; + XenBackendDeviceCreate create; + XenBackendDeviceDestroy destroy; +} XenBackendInfo; + +XenBus *xen_backend_get_bus(XenBackendInstance *backend); +const char *xen_backend_get_name(XenBackendInstance *backend); + +void xen_backend_set_device(XenBackendInstance *backend, + XenDevice *xendevice); +XenDevice *xen_backend_get_device(XenBackendInstance *backend); + +void xen_backend_register(const XenBackendInfo *info); + +void xen_backend_device_create(XenBus *xenbus, const char *type, + const char *name, QDict *opts, Error **errp); +bool xen_backend_try_device_destroy(XenDevice *xendev, Error **errp); + +#endif /* HW_XEN_BACKEND_H */ diff --git a/include/hw/xen/xen-bus.h b/include/hw/xen/xen-bus.h index 0834cb3..e55a5de 100644 --- a/include/hw/xen/xen-bus.h +++ b/include/hw/xen/xen-bus.h @@ -65,6 +65,7 @@ typedef struct XenBus { domid_t backend_id; struct xs_handle *xsh; NotifierList watch_notifiers; + XenWatch *backend_watch; } XenBus; typedef struct XenBusClass { diff --git a/include/qemu/module.h b/include/qemu/module.h index 54300ab..55dd2be 100644 --- a/include/qemu/module.h +++ b/include/qemu/module.h @@ -44,6 +44,7 @@ typedef enum { MODULE_INIT_OPTS, MODULE_INIT_QOM, MODULE_INIT_TRACE, + MODULE_INIT_XEN_BACKEND, MODULE_INIT_MAX } module_init_type; @@ -51,6 +52,8 @@ typedef enum { #define opts_init(function) module_init(function, MODULE_INIT_OPTS) #define type_init(function) module_init(function, MODULE_INIT_QOM) #define trace_init(function) module_init(function, MODULE_INIT_TRACE) +#define xen_backend_init(function) module_init(function, \ + MODULE_INIT_XEN_BACKEND) #define block_module_load_one(lib) module_load_one("block-", lib) #define ui_module_load_one(lib) module_load_one("ui-", lib) From patchwork Mon Dec 17 11:40:46 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 1014445 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=citrix.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 43JKYv2lz8z9s4s for ; Mon, 17 Dec 2018 23:03:47 +1100 (AEDT) Received: from localhost ([::1]:46269 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrce-00025D-U6 for incoming@patchwork.ozlabs.org; Mon, 17 Dec 2018 07:03:44 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:58071) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrY4-0007ZS-8f for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:59:05 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gYrY0-0003ZU-0b for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:59:00 -0500 Received: from smtp03.citrix.com ([162.221.156.55]:45515) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gYrXq-0003Qj-66; Mon, 17 Dec 2018 06:58:46 -0500 X-IronPort-AV: E=Sophos;i="5.56,365,1539648000"; d="scan'208";a="73533627" From: Paul Durrant To: , , Date: Mon, 17 Dec 2018 11:40:46 +0000 Message-ID: <1545046848-14891-17-git-send-email-paul.durrant@citrix.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> References: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 162.221.156.55 Subject: [Qemu-devel] [PATCH v5 16/18] xen: automatically create XenBlockDevice-s X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Anthony Perard , Kevin Wolf , Paul Durrant , Stefano Stabellini , Max Reitz Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This patch adds create and destroy function for XenBlockDevice-s so that they can be created automatically when the Xen toolstack instantiates a new PV backend via xenstore. When the XenBlockDevice is created this way it is also necessary to create a 'drive' which matches the configuration that the Xen toolstack has written into xenstore. This is done by formulating the parameters necessary for each 'blockdev' layer of the drive and then using qmp_blockdev_add() to create the layers. Also, for compatibility with the legacy 'xen_disk' implementation, an iothread is automatically created for the new XenBlockDevice. This, like the driver layers, will be destroyed after the XenBlockDevice is unrealized. The legacy backend scan for 'qdisk' is removed by this patch, which makes the 'xen_disk' code is redundant. The code will be removed by a subsequent patch. Signed-off-by: Paul Durrant --- Cc: Anthony Perard Cc: Kevin Wolf Cc: Max Reitz Cc: Stefano Stabellini v5: - Extensively re-worked to avoid using drive_new() and use qmp_blockdev_add() instead - Also use qmp_object_add() for IOThread - Dropped Anthony's R-b because of the code changes v2: - Get rid of error_abort - Don't use qdev_init_nofail - Explain why file locking needs to be off --- hw/block/trace-events | 4 + hw/block/xen-block.c | 419 ++++++++++++++++++++++++++++++++++++++++++++ hw/xen/xen-legacy-backend.c | 1 - include/hw/xen/xen-block.h | 13 ++ 4 files changed, 436 insertions(+), 1 deletion(-) diff --git a/hw/block/trace-events b/hw/block/trace-events index 89e2583..55e5a55 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -137,3 +137,7 @@ xen_disk_realize(void) "" xen_disk_unrealize(void) "" xen_cdrom_realize(void) "" xen_cdrom_unrealize(void) "" +xen_block_blockdev_add(char *str) "%s" +xen_block_blockdev_del(const char *node_name) "%s" +xen_block_device_create(unsigned int number) "%u" +xen_block_device_destroy(unsigned int number) "%u" diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c index a7c37c1..5e69fa0 100644 --- a/hw/block/xen-block.c +++ b/hw/block/xen-block.c @@ -7,12 +7,20 @@ #include "qemu/osdep.h" #include "qemu/cutils.h" +#include "qemu/option.h" #include "qapi/error.h" +#include "qapi/qapi-commands-block-core.h" +#include "qapi/qapi-commands-misc.h" +#include "qapi/qapi-visit-block-core.h" #include "qapi/visitor.h" +#include "qapi/qmp/qdict.h" +#include "qapi/qmp/qstring.h" +#include "block/qdict.h" #include "hw/hw.h" #include "hw/xen/xen_common.h" #include "hw/block/xen_blkif.h" #include "hw/xen/xen-block.h" +#include "hw/xen/xen-backend.h" #include "sysemu/blockdev.h" #include "sysemu/block-backend.h" #include "sysemu/iothread.h" @@ -474,6 +482,7 @@ static void xen_block_class_init(ObjectClass *class, void *data) DeviceClass *dev_class = DEVICE_CLASS(class); XenDeviceClass *xendev_class = XEN_DEVICE_CLASS(class); + xendev_class->backend = "qdisk"; xendev_class->device = "vbd"; xendev_class->get_name = xen_block_get_name; xendev_class->realize = xen_block_realize; @@ -586,3 +595,413 @@ static void xen_block_register_types(void) } type_init(xen_block_register_types) + +static void xen_block_blockdev_del(const char *node_name, Error **errp) +{ + trace_xen_block_blockdev_del(node_name); + + qmp_blockdev_del(node_name, errp); +} + +static void add_item(const char *key, QObject *obj, void *opaque) +{ + const char *val = qobject_get_try_str(obj); + char **strp = opaque; + char *str = *strp; + + *strp = (!str) ? g_strdup_printf("%s=%s", key, val) : + g_strdup_printf("%s %s=%s", str, key, val); + g_free(str); +} + +static char *xen_block_blockdev_add(const char *id, QDict *qdict, + Error **errp) +{ + const char *driver = qdict_get_try_str(qdict, "driver"); + BlockdevOptions *options = NULL; + Error *local_err = NULL; + char *str = NULL; + char *node_name; + Visitor *v; + + if (!driver) { + error_setg(errp, "no 'driver' parameter"); + return NULL; + } + + node_name = g_strdup_printf("%s-%s", id, driver); + qdict_put_str(qdict, "node-name", node_name); + + qdict_iter(qdict, add_item, &str); + + trace_xen_block_blockdev_add(str); + g_free(str); + + v = qobject_input_visitor_new_flat_confused(qdict, errp); + if (!v) { + goto fail; + } + + visit_type_BlockdevOptions(v, NULL, &options, &local_err); + visit_free(v); + + if (local_err) { + error_propagate(errp, local_err); + goto fail; + } + + qmp_blockdev_add(options, &local_err); + + if (local_err) { + error_propagate(errp, local_err); + goto fail; + } + + qapi_free_BlockdevOptions(options); + + return node_name; + +fail: + if (options) { + qapi_free_BlockdevOptions(options); + } + g_free(node_name); + + return NULL; +} + +static void xen_block_drive_destroy(XenBlockDrive *drive, Error **errp) +{ + while (drive->layers-- != 0) { + char *node_name = drive->node_name[drive->layers]; + Error *local_err = NULL; + + xen_block_blockdev_del(node_name, &local_err); + if (local_err) { + error_propagate(errp, local_err); + drive->layers++; + return; + } + } + g_free(drive->id); + g_free(drive); +} + +static void xen_block_drive_layer_add(XenBlockDrive *drive, QDict *qdict, + Error **errp) +{ + unsigned int i = drive->layers; + char *node_name; + + g_assert(drive->layers < ARRAY_SIZE(drive->node_name)); + + if (i != 0) { + /* Link to the lower layer */ + qdict_put_str(qdict, "file", drive->node_name[i - 1]); + } + + node_name = xen_block_blockdev_add(drive->id, qdict, errp); + if (!node_name) { + return; + } + + drive->node_name[i] = node_name; + drive->layers++; +} + +static XenBlockDrive *xen_block_drive_create(const char *id, + const char *device_type, + QDict *opts, Error **errp) +{ + const char *params = qdict_get_try_str(opts, "params"); + const char *mode = qdict_get_try_str(opts, "mode"); + const char *direct_io_safe = qdict_get_try_str(opts, "direct-io-safe"); + const char *discard_enable = qdict_get_try_str(opts, "discard-enable"); + char *driver = NULL; + char *filename = NULL; + XenBlockDrive *drive = NULL; + Error *local_err = NULL; + QDict *qdict; + + if (params) { + char **v = g_strsplit(params, ":", 2); + + if (v[1] == NULL) { + filename = g_strdup(v[0]); + driver = g_strdup("file"); + } else { + if (strcmp(v[0], "aio") == 0) { + driver = g_strdup("file"); + } else if (strcmp(v[0], "vhd") == 0) { + driver = g_strdup("vpc"); + } else { + driver = g_strdup(v[0]); + } + filename = g_strdup(v[1]); + } + + g_strfreev(v); + } + + if (!filename) { + error_setg(errp, "no filename"); + goto done; + } + assert(driver); + + drive = g_new0(XenBlockDrive, 1); + drive->id = g_strdup(id); + + qdict = qdict_new(); + + qdict_put_str(qdict, "driver", "file"); + qdict_put_str(qdict, "filename", filename); + + if (mode && *mode != 'w') { + qdict_put_str(qdict, "read-only", "on"); + } + + if (direct_io_safe) { + unsigned long value; + + if (!qemu_strtoul(direct_io_safe, NULL, 2, &value) && !!value) { + qdict_put_str(qdict, "cache.direct", "on"); + qdict_put_str(qdict, "aio", "native"); + } + } + + if (discard_enable) { + unsigned long value; + + if (!qemu_strtoul(discard_enable, NULL, 2, &value) && !!value) { + qdict_put_str(qdict, "discard", "unmap"); + } + } + + /* + * It is necessary to turn file locking off as an emulated device + * may have already opened the same image file. + */ + qdict_put_str(qdict, "locking", "off"); + + xen_block_drive_layer_add(drive, qdict, &local_err); + qobject_unref(qdict); + + if (local_err) { + error_propagate(errp, local_err); + goto done; + } + + /* If the image is a raw file then we are done */ + if (!strcmp(driver, "file")) { + goto done; + } + + qdict = qdict_new(); + + qdict_put_str(qdict, "driver", driver); + + xen_block_drive_layer_add(drive, qdict, &local_err); + qobject_unref(qdict); + +done: + g_free(driver); + g_free(filename); + + if (local_err) { + xen_block_drive_destroy(drive, NULL); + return NULL; + } + + return drive; +} + +static const char *xen_block_drive_get_node_name(XenBlockDrive *drive) +{ + return drive->layers ? drive->node_name[drive->layers - 1] : ""; +} + +static void xen_block_iothread_destroy(XenBlockIOThread *iothread, + Error **errp) +{ + qmp_object_del(iothread->id, errp); + + g_free(iothread->id); + g_free(iothread); +} + +static XenBlockIOThread *xen_block_iothread_create(const char *id, + Error **errp) +{ + XenBlockIOThread *iothread = g_new(XenBlockIOThread, 1); + Error *local_err = NULL; + + iothread->id = g_strdup(id); + + qmp_object_add(TYPE_IOTHREAD, id, false, NULL, &local_err); + if (local_err) { + error_propagate(errp, local_err); + + g_free(iothread->id); + g_free(iothread); + return NULL; + } + + return iothread; +} + +static void xen_block_device_create(XenBackendInstance *backend, + QDict *opts, Error **errp) +{ + XenBus *xenbus = xen_backend_get_bus(backend); + const char *name = xen_backend_get_name(backend); + unsigned long number; + const char *vdev, *device_type; + XenBlockDrive *drive = NULL; + XenBlockIOThread *iothread = NULL; + XenDevice *xendev = NULL; + Error *local_err = NULL; + const char *type; + XenBlockDevice *blockdev; + + if (qemu_strtoul(name, NULL, 10, &number)) { + error_setg(errp, "failed to parse name '%s'", name); + goto fail; + } + + trace_xen_block_device_create(number); + + vdev = qdict_get_try_str(opts, "dev"); + if (!vdev) { + error_setg(errp, "no dev parameter"); + goto fail; + } + + device_type = qdict_get_try_str(opts, "device-type"); + if (!device_type) { + error_setg(errp, "no device-type parameter"); + goto fail; + } + + if (!strcmp(device_type, "disk")) { + type = TYPE_XEN_DISK_DEVICE; + } else if (!strcmp(device_type, "cdrom")) { + type = TYPE_XEN_CDROM_DEVICE; + } else { + error_setg(errp, "invalid device-type parameter '%s'", device_type); + goto fail; + } + + drive = xen_block_drive_create(vdev, device_type, opts, &local_err); + if (!drive) { + error_propagate_prepend(errp, local_err, "failed to create drive: "); + goto fail; + } + + iothread = xen_block_iothread_create(vdev, &local_err); + if (local_err) { + error_propagate_prepend(errp, local_err, + "failed to create iothread: "); + goto fail; + } + + xendev = XEN_DEVICE(qdev_create(BUS(xenbus), type)); + blockdev = XEN_BLOCK_DEVICE(xendev); + + object_property_set_str(OBJECT(xendev), vdev, "vdev", &local_err); + if (local_err) { + error_propagate_prepend(errp, local_err, "failed to set 'vdev': "); + goto fail; + } + + object_property_set_str(OBJECT(xendev), + xen_block_drive_get_node_name(drive), "drive", + &local_err); + if (local_err) { + error_propagate_prepend(errp, local_err, "failed to set 'drive': "); + goto fail; + } + + object_property_set_str(OBJECT(xendev), iothread->id, "iothread", + &local_err); + if (local_err) { + error_propagate_prepend(errp, local_err, + "failed to set 'iothread': "); + goto fail; + } + + blockdev->iothread = iothread; + blockdev->drive = drive; + + object_property_set_bool(OBJECT(xendev), true, "realized", &local_err); + if (local_err) { + error_propagate_prepend(errp, local_err, + "realization of device %s failed: ", + type); + goto fail; + } + + xen_backend_set_device(backend, xendev); + return; + +fail: + if (xendev) { + object_unparent(OBJECT(xendev)); + } + + if (iothread) { + xen_block_iothread_destroy(iothread, NULL); + } + + if (drive) { + xen_block_drive_destroy(drive, NULL); + } +} + +static void xen_block_device_destroy(XenBackendInstance *backend, + Error **errp) +{ + XenDevice *xendev = xen_backend_get_device(backend); + XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev); + XenBlockVdev *vdev = &blockdev->props.vdev; + XenBlockDrive *drive = blockdev->drive; + XenBlockIOThread *iothread = blockdev->iothread; + + trace_xen_block_device_destroy(vdev->number); + + object_unparent(OBJECT(xendev)); + + if (iothread) { + Error *local_err = NULL; + + xen_block_iothread_destroy(iothread, &local_err); + if (local_err) { + error_propagate_prepend(errp, local_err, + "failed to destroy iothread: "); + return; + } + } + + if (drive) { + Error *local_err = NULL; + + xen_block_drive_destroy(drive, &local_err); + if (local_err) { + error_propagate_prepend(errp, local_err, + "failed to destroy drive: "); + } + } +} + +static const XenBackendInfo xen_block_backend_info = { + .type = "qdisk", + .create = xen_block_device_create, + .destroy = xen_block_device_destroy, +}; + +static void xen_block_register_backend(void) +{ + xen_backend_register(&xen_block_backend_info); +} + +xen_backend_init(xen_block_register_backend); diff --git a/hw/xen/xen-legacy-backend.c b/hw/xen/xen-legacy-backend.c index 0c26023..fb227de 100644 --- a/hw/xen/xen-legacy-backend.c +++ b/hw/xen/xen-legacy-backend.c @@ -753,7 +753,6 @@ void xen_be_register_common(void) xen_be_register("console", &xen_console_ops); xen_be_register("vkbd", &xen_kbdmouse_ops); - xen_be_register("qdisk", &xen_blkdev_ops); #ifdef CONFIG_VIRTFS xen_be_register("9pfs", &xen_9pfs_ops); #endif diff --git a/include/hw/xen/xen-block.h b/include/hw/xen/xen-block.h index c4223f9..6f5d675 100644 --- a/include/hw/xen/xen-block.h +++ b/include/hw/xen/xen-block.h @@ -29,6 +29,7 @@ typedef struct XenBlockVdev { unsigned long number; } XenBlockVdev; + typedef struct XenBlockProperties { XenBlockVdev vdev; BlockConf conf; @@ -36,12 +37,24 @@ typedef struct XenBlockProperties { IOThread *iothread; } XenBlockProperties; +typedef struct XenBlockDrive { + char *id; + char *node_name[2]; + unsigned int layers; +} XenBlockDrive; + +typedef struct XenBlockIOThread { + char *id; +} XenBlockIOThread; + typedef struct XenBlockDevice { XenDevice xendev; XenBlockProperties props; const char *device_type; unsigned int info; XenBlockDataPlane *dataplane; + XenBlockDrive *drive; + XenBlockIOThread *iothread; } XenBlockDevice; typedef void (*XenBlockDeviceRealize)(XenBlockDevice *blockdev, Error **errp); From patchwork Mon Dec 17 11:40:47 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 1014442 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=citrix.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 43JKV40Wzyz9s2P for ; Mon, 17 Dec 2018 23:00:28 +1100 (AEDT) Received: from localhost ([::1]:46244 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrZR-0008De-JY for incoming@patchwork.ozlabs.org; Mon, 17 Dec 2018 07:00:25 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:58026) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrXz-0007Sl-TR for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:58:56 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gYrXu-0003Uf-CJ for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:58:52 -0500 Received: from smtp03.citrix.com ([162.221.156.55]:45515) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gYrXr-0003Qj-4S; Mon, 17 Dec 2018 06:58:48 -0500 X-IronPort-AV: E=Sophos;i="5.56,365,1539648000"; d="scan'208";a="73533628" From: Paul Durrant To: , , Date: Mon, 17 Dec 2018 11:40:47 +0000 Message-ID: <1545046848-14891-18-git-send-email-paul.durrant@citrix.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> References: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 162.221.156.55 Subject: [Qemu-devel] [PATCH v5 17/18] MAINTAINERS: add myself as a Xen maintainer X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Paolo Bonzini , Paul Durrant Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" I have made many significant contributions to the Xen code in QEMU, particularly the recent patches introducing a new PV device framework. I intend to make further significant contributions, porting other PV back- ends to the new framework with the intent of eventually removing the legacy code. It therefore seems reasonable that I become a maintainer of the Xen code. Signed-off-by: Paul Durrant Acked-by: Anthony Perard Acked-by: Stefano Stabellini --- Cc: Paolo Bonzini v2: - Fix typo --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 9875581..e6bd441 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -396,6 +396,7 @@ Guest CPU Cores (Xen): X86 M: Stefano Stabellini M: Anthony Perard +M: Paul Durrant L: xen-devel@lists.xenproject.org S: Supported F: */xen* From patchwork Mon Dec 17 11:40:48 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 1014446 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=citrix.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 43JKbm2J9Zz9s2P for ; Mon, 17 Dec 2018 23:05:24 +1100 (AEDT) Received: from localhost ([::1]:46274 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYreD-0003Bf-Ir for incoming@patchwork.ozlabs.org; Mon, 17 Dec 2018 07:05:21 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:58073) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gYrY4-0007ZW-8s for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:59:05 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gYrXz-0003Z6-TV for qemu-devel@nongnu.org; Mon, 17 Dec 2018 06:59:00 -0500 Received: from smtp03.citrix.com ([162.221.156.55]:45522) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gYrXu-0003Tf-Ed; Mon, 17 Dec 2018 06:58:52 -0500 X-IronPort-AV: E=Sophos;i="5.56,365,1539648000"; d="scan'208";a="73533629" From: Paul Durrant To: , , Date: Mon, 17 Dec 2018 11:40:48 +0000 Message-ID: <1545046848-14891-19-git-send-email-paul.durrant@citrix.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> References: <1545046848-14891-1-git-send-email-paul.durrant@citrix.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 162.221.156.55 Subject: [Qemu-devel] [PATCH v5 18/18] xen: remove the legacy 'xen_disk' backend X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Paul Durrant , Stefano Stabellini , Max Reitz Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This backend has now been replaced by the 'xen-qdisk' XenDevice. Signed-off-by: Paul Durrant Acked-by: Anthony Perard --- Cc: Kevin Wolf Cc: Max Reitz Cc: Stefano Stabellini --- hw/block/Makefile.objs | 1 - hw/block/xen_disk.c | 1011 ------------------------------------------------ 2 files changed, 1012 deletions(-) delete mode 100644 hw/block/xen_disk.c diff --git a/hw/block/Makefile.objs b/hw/block/Makefile.objs index f34813a..e206b8e 100644 --- a/hw/block/Makefile.objs +++ b/hw/block/Makefile.objs @@ -5,7 +5,6 @@ common-obj-$(CONFIG_NAND) += nand.o common-obj-$(CONFIG_PFLASH_CFI01) += pflash_cfi01.o common-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o common-obj-$(CONFIG_XEN) += xen-block.o -common-obj-$(CONFIG_XEN) += xen_disk.o common-obj-$(CONFIG_ECC) += ecc.o common-obj-$(CONFIG_ONENAND) += onenand.o common-obj-$(CONFIG_NVME_PCI) += nvme.o diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c deleted file mode 100644 index 75fe55f..0000000 --- a/hw/block/xen_disk.c +++ /dev/null @@ -1,1011 +0,0 @@ -/* - * xen paravirt block device backend - * - * (c) Gerd Hoffmann - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; under version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -#include "qemu/osdep.h" -#include "qemu/units.h" -#include -#include - -#include "hw/hw.h" -#include "hw/xen/xen-legacy-backend.h" -#include "xen_blkif.h" -#include "sysemu/blockdev.h" -#include "sysemu/iothread.h" -#include "sysemu/block-backend.h" -#include "qapi/error.h" -#include "qapi/qmp/qdict.h" -#include "qapi/qmp/qstring.h" -#include "trace.h" - -/* ------------------------------------------------------------- */ - -#define BLOCK_SIZE 512 -#define IOCB_COUNT (BLKIF_MAX_SEGMENTS_PER_REQUEST + 2) - -struct ioreq { - blkif_request_t req; - int16_t status; - - /* parsed request */ - off_t start; - QEMUIOVector v; - void *buf; - size_t size; - int presync; - - /* aio status */ - int aio_inflight; - int aio_errors; - - struct XenBlkDev *blkdev; - QLIST_ENTRY(ioreq) list; - BlockAcctCookie acct; -}; - -#define MAX_RING_PAGE_ORDER 4 - -struct XenBlkDev { - struct XenLegacyDevice xendev; /* must be first */ - char *params; - char *mode; - char *type; - char *dev; - char *devtype; - bool directiosafe; - const char *fileproto; - const char *filename; - unsigned int ring_ref[1 << MAX_RING_PAGE_ORDER]; - unsigned int nr_ring_ref; - void *sring; - int64_t file_blk; - int64_t file_size; - int protocol; - blkif_back_rings_t rings; - int more_work; - - /* request lists */ - QLIST_HEAD(inflight_head, ioreq) inflight; - QLIST_HEAD(finished_head, ioreq) finished; - QLIST_HEAD(freelist_head, ioreq) freelist; - int requests_total; - int requests_inflight; - int requests_finished; - unsigned int max_requests; - - gboolean feature_discard; - - /* qemu block driver */ - DriveInfo *dinfo; - BlockBackend *blk; - QEMUBH *bh; - - IOThread *iothread; - AioContext *ctx; -}; - -/* ------------------------------------------------------------- */ - -static void ioreq_reset(struct ioreq *ioreq) -{ - memset(&ioreq->req, 0, sizeof(ioreq->req)); - ioreq->status = 0; - ioreq->start = 0; - ioreq->buf = NULL; - ioreq->size = 0; - ioreq->presync = 0; - - ioreq->aio_inflight = 0; - ioreq->aio_errors = 0; - - ioreq->blkdev = NULL; - memset(&ioreq->list, 0, sizeof(ioreq->list)); - memset(&ioreq->acct, 0, sizeof(ioreq->acct)); - - qemu_iovec_reset(&ioreq->v); -} - -static struct ioreq *ioreq_start(struct XenBlkDev *blkdev) -{ - struct ioreq *ioreq = NULL; - - if (QLIST_EMPTY(&blkdev->freelist)) { - if (blkdev->requests_total >= blkdev->max_requests) { - goto out; - } - /* allocate new struct */ - ioreq = g_malloc0(sizeof(*ioreq)); - ioreq->blkdev = blkdev; - blkdev->requests_total++; - qemu_iovec_init(&ioreq->v, 1); - } else { - /* get one from freelist */ - ioreq = QLIST_FIRST(&blkdev->freelist); - QLIST_REMOVE(ioreq, list); - } - QLIST_INSERT_HEAD(&blkdev->inflight, ioreq, list); - blkdev->requests_inflight++; - -out: - return ioreq; -} - -static void ioreq_finish(struct ioreq *ioreq) -{ - struct XenBlkDev *blkdev = ioreq->blkdev; - - QLIST_REMOVE(ioreq, list); - QLIST_INSERT_HEAD(&blkdev->finished, ioreq, list); - blkdev->requests_inflight--; - blkdev->requests_finished++; -} - -static void ioreq_release(struct ioreq *ioreq, bool finish) -{ - struct XenBlkDev *blkdev = ioreq->blkdev; - - QLIST_REMOVE(ioreq, list); - ioreq_reset(ioreq); - ioreq->blkdev = blkdev; - QLIST_INSERT_HEAD(&blkdev->freelist, ioreq, list); - if (finish) { - blkdev->requests_finished--; - } else { - blkdev->requests_inflight--; - } -} - -/* - * translate request into iovec + start offset - * do sanity checks along the way - */ -static int ioreq_parse(struct ioreq *ioreq) -{ - struct XenBlkDev *blkdev = ioreq->blkdev; - struct XenLegacyDevice *xendev = &blkdev->xendev; - size_t len; - int i; - - xen_pv_printf(xendev, 3, - "op %d, nr %d, handle %d, id %" PRId64 ", sector %" PRId64 "\n", - ioreq->req.operation, ioreq->req.nr_segments, - ioreq->req.handle, ioreq->req.id, ioreq->req.sector_number); - switch (ioreq->req.operation) { - case BLKIF_OP_READ: - break; - case BLKIF_OP_FLUSH_DISKCACHE: - ioreq->presync = 1; - if (!ioreq->req.nr_segments) { - return 0; - } - /* fall through */ - case BLKIF_OP_WRITE: - break; - case BLKIF_OP_DISCARD: - return 0; - default: - xen_pv_printf(xendev, 0, "error: unknown operation (%d)\n", - ioreq->req.operation); - goto err; - }; - - if (ioreq->req.operation != BLKIF_OP_READ && blkdev->mode[0] != 'w') { - xen_pv_printf(xendev, 0, "error: write req for ro device\n"); - goto err; - } - - ioreq->start = ioreq->req.sector_number * blkdev->file_blk; - for (i = 0; i < ioreq->req.nr_segments; i++) { - if (i == BLKIF_MAX_SEGMENTS_PER_REQUEST) { - xen_pv_printf(xendev, 0, "error: nr_segments too big\n"); - goto err; - } - if (ioreq->req.seg[i].first_sect > ioreq->req.seg[i].last_sect) { - xen_pv_printf(xendev, 0, "error: first > last sector\n"); - goto err; - } - if (ioreq->req.seg[i].last_sect * BLOCK_SIZE >= XC_PAGE_SIZE) { - xen_pv_printf(xendev, 0, "error: page crossing\n"); - goto err; - } - - len = (ioreq->req.seg[i].last_sect - ioreq->req.seg[i].first_sect + 1) * blkdev->file_blk; - ioreq->size += len; - } - if (ioreq->start + ioreq->size > blkdev->file_size) { - xen_pv_printf(xendev, 0, "error: access beyond end of file\n"); - goto err; - } - return 0; - -err: - ioreq->status = BLKIF_RSP_ERROR; - return -1; -} - -static int ioreq_grant_copy(struct ioreq *ioreq) -{ - struct XenBlkDev *blkdev = ioreq->blkdev; - struct XenLegacyDevice *xendev = &blkdev->xendev; - XenGrantCopySegment segs[BLKIF_MAX_SEGMENTS_PER_REQUEST]; - int i, count, rc; - int64_t file_blk = blkdev->file_blk; - bool to_domain = (ioreq->req.operation == BLKIF_OP_READ); - void *virt = ioreq->buf; - - if (ioreq->req.nr_segments == 0) { - return 0; - } - - count = ioreq->req.nr_segments; - - for (i = 0; i < count; i++) { - if (to_domain) { - segs[i].dest.foreign.ref = ioreq->req.seg[i].gref; - segs[i].dest.foreign.offset = ioreq->req.seg[i].first_sect * file_blk; - segs[i].source.virt = virt; - } else { - segs[i].source.foreign.ref = ioreq->req.seg[i].gref; - segs[i].source.foreign.offset = ioreq->req.seg[i].first_sect * file_blk; - segs[i].dest.virt = virt; - } - segs[i].len = (ioreq->req.seg[i].last_sect - - ioreq->req.seg[i].first_sect + 1) * file_blk; - virt += segs[i].len; - } - - rc = xen_be_copy_grant_refs(xendev, to_domain, segs, count); - - if (rc) { - xen_pv_printf(xendev, 0, - "failed to copy data %d\n", rc); - ioreq->aio_errors++; - return -1; - } - - return rc; -} - -static int ioreq_runio_qemu_aio(struct ioreq *ioreq); - -static void qemu_aio_complete(void *opaque, int ret) -{ - struct ioreq *ioreq = opaque; - struct XenBlkDev *blkdev = ioreq->blkdev; - struct XenLegacyDevice *xendev = &blkdev->xendev; - - aio_context_acquire(blkdev->ctx); - - if (ret != 0) { - xen_pv_printf(xendev, 0, "%s I/O error\n", - ioreq->req.operation == BLKIF_OP_READ ? "read" : "write"); - ioreq->aio_errors++; - } - - ioreq->aio_inflight--; - if (ioreq->presync) { - ioreq->presync = 0; - ioreq_runio_qemu_aio(ioreq); - goto done; - } - if (ioreq->aio_inflight > 0) { - goto done; - } - - switch (ioreq->req.operation) { - case BLKIF_OP_READ: - /* in case of failure ioreq->aio_errors is increased */ - if (ret == 0) { - ioreq_grant_copy(ioreq); - } - qemu_vfree(ioreq->buf); - break; - case BLKIF_OP_WRITE: - case BLKIF_OP_FLUSH_DISKCACHE: - if (!ioreq->req.nr_segments) { - break; - } - qemu_vfree(ioreq->buf); - break; - default: - break; - } - - ioreq->status = ioreq->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY; - ioreq_finish(ioreq); - - switch (ioreq->req.operation) { - case BLKIF_OP_WRITE: - case BLKIF_OP_FLUSH_DISKCACHE: - if (!ioreq->req.nr_segments) { - break; - } - case BLKIF_OP_READ: - if (ioreq->status == BLKIF_RSP_OKAY) { - block_acct_done(blk_get_stats(blkdev->blk), &ioreq->acct); - } else { - block_acct_failed(blk_get_stats(blkdev->blk), &ioreq->acct); - } - break; - case BLKIF_OP_DISCARD: - default: - break; - } - qemu_bh_schedule(blkdev->bh); - -done: - aio_context_release(blkdev->ctx); -} - -static bool blk_split_discard(struct ioreq *ioreq, blkif_sector_t sector_number, - uint64_t nr_sectors) -{ - struct XenBlkDev *blkdev = ioreq->blkdev; - int64_t byte_offset; - int byte_chunk; - uint64_t byte_remaining, limit; - uint64_t sec_start = sector_number; - uint64_t sec_count = nr_sectors; - - /* Wrap around, or overflowing byte limit? */ - if (sec_start + sec_count < sec_count || - sec_start + sec_count > INT64_MAX >> BDRV_SECTOR_BITS) { - return false; - } - - limit = BDRV_REQUEST_MAX_SECTORS << BDRV_SECTOR_BITS; - byte_offset = sec_start << BDRV_SECTOR_BITS; - byte_remaining = sec_count << BDRV_SECTOR_BITS; - - do { - byte_chunk = byte_remaining > limit ? limit : byte_remaining; - ioreq->aio_inflight++; - blk_aio_pdiscard(blkdev->blk, byte_offset, byte_chunk, - qemu_aio_complete, ioreq); - byte_remaining -= byte_chunk; - byte_offset += byte_chunk; - } while (byte_remaining > 0); - - return true; -} - -static int ioreq_runio_qemu_aio(struct ioreq *ioreq) -{ - struct XenBlkDev *blkdev = ioreq->blkdev; - - ioreq->buf = qemu_memalign(XC_PAGE_SIZE, ioreq->size); - if (ioreq->req.nr_segments && - (ioreq->req.operation == BLKIF_OP_WRITE || - ioreq->req.operation == BLKIF_OP_FLUSH_DISKCACHE) && - ioreq_grant_copy(ioreq)) { - qemu_vfree(ioreq->buf); - goto err; - } - - ioreq->aio_inflight++; - if (ioreq->presync) { - blk_aio_flush(ioreq->blkdev->blk, qemu_aio_complete, ioreq); - return 0; - } - - switch (ioreq->req.operation) { - case BLKIF_OP_READ: - qemu_iovec_add(&ioreq->v, ioreq->buf, ioreq->size); - block_acct_start(blk_get_stats(blkdev->blk), &ioreq->acct, - ioreq->v.size, BLOCK_ACCT_READ); - ioreq->aio_inflight++; - blk_aio_preadv(blkdev->blk, ioreq->start, &ioreq->v, 0, - qemu_aio_complete, ioreq); - break; - case BLKIF_OP_WRITE: - case BLKIF_OP_FLUSH_DISKCACHE: - if (!ioreq->req.nr_segments) { - break; - } - - qemu_iovec_add(&ioreq->v, ioreq->buf, ioreq->size); - block_acct_start(blk_get_stats(blkdev->blk), &ioreq->acct, - ioreq->v.size, - ioreq->req.operation == BLKIF_OP_WRITE ? - BLOCK_ACCT_WRITE : BLOCK_ACCT_FLUSH); - ioreq->aio_inflight++; - blk_aio_pwritev(blkdev->blk, ioreq->start, &ioreq->v, 0, - qemu_aio_complete, ioreq); - break; - case BLKIF_OP_DISCARD: - { - struct blkif_request_discard *req = (void *)&ioreq->req; - if (!blk_split_discard(ioreq, req->sector_number, req->nr_sectors)) { - goto err; - } - break; - } - default: - /* unknown operation (shouldn't happen -- parse catches this) */ - goto err; - } - - qemu_aio_complete(ioreq, 0); - - return 0; - -err: - ioreq_finish(ioreq); - ioreq->status = BLKIF_RSP_ERROR; - return -1; -} - -static int blk_send_response_one(struct ioreq *ioreq) -{ - struct XenBlkDev *blkdev = ioreq->blkdev; - int send_notify = 0; - int have_requests = 0; - blkif_response_t *resp; - - /* Place on the response ring for the relevant domain. */ - switch (blkdev->protocol) { - case BLKIF_PROTOCOL_NATIVE: - resp = (blkif_response_t *) RING_GET_RESPONSE(&blkdev->rings.native, - blkdev->rings.native.rsp_prod_pvt); - break; - case BLKIF_PROTOCOL_X86_32: - resp = (blkif_response_t *) RING_GET_RESPONSE(&blkdev->rings.x86_32_part, - blkdev->rings.x86_32_part.rsp_prod_pvt); - break; - case BLKIF_PROTOCOL_X86_64: - resp = (blkif_response_t *) RING_GET_RESPONSE(&blkdev->rings.x86_64_part, - blkdev->rings.x86_64_part.rsp_prod_pvt); - break; - default: - return 0; - } - - resp->id = ioreq->req.id; - resp->operation = ioreq->req.operation; - resp->status = ioreq->status; - - blkdev->rings.common.rsp_prod_pvt++; - - RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&blkdev->rings.common, send_notify); - if (blkdev->rings.common.rsp_prod_pvt == blkdev->rings.common.req_cons) { - /* - * Tail check for pending requests. Allows frontend to avoid - * notifications if requests are already in flight (lower - * overheads and promotes batching). - */ - RING_FINAL_CHECK_FOR_REQUESTS(&blkdev->rings.common, have_requests); - } else if (RING_HAS_UNCONSUMED_REQUESTS(&blkdev->rings.common)) { - have_requests = 1; - } - - if (have_requests) { - blkdev->more_work++; - } - return send_notify; -} - -/* walk finished list, send outstanding responses, free requests */ -static void blk_send_response_all(struct XenBlkDev *blkdev) -{ - struct ioreq *ioreq; - int send_notify = 0; - - while (!QLIST_EMPTY(&blkdev->finished)) { - ioreq = QLIST_FIRST(&blkdev->finished); - send_notify += blk_send_response_one(ioreq); - ioreq_release(ioreq, true); - } - if (send_notify) { - xen_pv_send_notify(&blkdev->xendev); - } -} - -static int blk_get_request(struct XenBlkDev *blkdev, struct ioreq *ioreq, RING_IDX rc) -{ - switch (blkdev->protocol) { - case BLKIF_PROTOCOL_NATIVE: - memcpy(&ioreq->req, RING_GET_REQUEST(&blkdev->rings.native, rc), - sizeof(ioreq->req)); - break; - case BLKIF_PROTOCOL_X86_32: - blkif_get_x86_32_req(&ioreq->req, - RING_GET_REQUEST(&blkdev->rings.x86_32_part, rc)); - break; - case BLKIF_PROTOCOL_X86_64: - blkif_get_x86_64_req(&ioreq->req, - RING_GET_REQUEST(&blkdev->rings.x86_64_part, rc)); - break; - } - /* Prevent the compiler from accessing the on-ring fields instead. */ - barrier(); - return 0; -} - -static void blk_handle_requests(struct XenBlkDev *blkdev) -{ - RING_IDX rc, rp; - struct ioreq *ioreq; - - blkdev->more_work = 0; - - rc = blkdev->rings.common.req_cons; - rp = blkdev->rings.common.sring->req_prod; - xen_rmb(); /* Ensure we see queued requests up to 'rp'. */ - - blk_send_response_all(blkdev); - while (rc != rp) { - /* pull request from ring */ - if (RING_REQUEST_CONS_OVERFLOW(&blkdev->rings.common, rc)) { - break; - } - ioreq = ioreq_start(blkdev); - if (ioreq == NULL) { - blkdev->more_work++; - break; - } - blk_get_request(blkdev, ioreq, rc); - blkdev->rings.common.req_cons = ++rc; - - /* parse them */ - if (ioreq_parse(ioreq) != 0) { - - switch (ioreq->req.operation) { - case BLKIF_OP_READ: - block_acct_invalid(blk_get_stats(blkdev->blk), - BLOCK_ACCT_READ); - break; - case BLKIF_OP_WRITE: - block_acct_invalid(blk_get_stats(blkdev->blk), - BLOCK_ACCT_WRITE); - break; - case BLKIF_OP_FLUSH_DISKCACHE: - block_acct_invalid(blk_get_stats(blkdev->blk), - BLOCK_ACCT_FLUSH); - default: - break; - }; - - if (blk_send_response_one(ioreq)) { - xen_pv_send_notify(&blkdev->xendev); - } - ioreq_release(ioreq, false); - continue; - } - - ioreq_runio_qemu_aio(ioreq); - } - - if (blkdev->more_work && blkdev->requests_inflight < blkdev->max_requests) { - qemu_bh_schedule(blkdev->bh); - } -} - -/* ------------------------------------------------------------- */ - -static void blk_bh(void *opaque) -{ - struct XenBlkDev *blkdev = opaque; - - aio_context_acquire(blkdev->ctx); - blk_handle_requests(blkdev); - aio_context_release(blkdev->ctx); -} - -static void blk_alloc(struct XenLegacyDevice *xendev) -{ - struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); - Error *err = NULL; - - trace_xen_disk_alloc(xendev->name); - - QLIST_INIT(&blkdev->inflight); - QLIST_INIT(&blkdev->finished); - QLIST_INIT(&blkdev->freelist); - - blkdev->iothread = iothread_create(xendev->name, &err); - assert(!err); - - blkdev->ctx = iothread_get_aio_context(blkdev->iothread); - blkdev->bh = aio_bh_new(blkdev->ctx, blk_bh, blkdev); -} - -static void blk_parse_discard(struct XenBlkDev *blkdev) -{ - struct XenLegacyDevice *xendev = &blkdev->xendev; - int enable; - - blkdev->feature_discard = true; - - if (xenstore_read_be_int(xendev, "discard-enable", &enable) == 0) { - blkdev->feature_discard = !!enable; - } - - if (blkdev->feature_discard) { - xenstore_write_be_int(xendev, "feature-discard", 1); - } -} - -static int blk_init(struct XenLegacyDevice *xendev) -{ - struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); - int info = 0; - char *directiosafe = NULL; - - trace_xen_disk_init(xendev->name); - - /* read xenstore entries */ - if (blkdev->params == NULL) { - char *h = NULL; - blkdev->params = xenstore_read_be_str(xendev, "params"); - if (blkdev->params != NULL) { - h = strchr(blkdev->params, ':'); - } - if (h != NULL) { - blkdev->fileproto = blkdev->params; - blkdev->filename = h+1; - *h = 0; - } else { - blkdev->fileproto = ""; - blkdev->filename = blkdev->params; - } - } - if (!strcmp("aio", blkdev->fileproto)) { - blkdev->fileproto = "raw"; - } - if (!strcmp("vhd", blkdev->fileproto)) { - blkdev->fileproto = "vpc"; - } - if (blkdev->mode == NULL) { - blkdev->mode = xenstore_read_be_str(xendev, "mode"); - } - if (blkdev->type == NULL) { - blkdev->type = xenstore_read_be_str(xendev, "type"); - } - if (blkdev->dev == NULL) { - blkdev->dev = xenstore_read_be_str(xendev, "dev"); - } - if (blkdev->devtype == NULL) { - blkdev->devtype = xenstore_read_be_str(xendev, "device-type"); - } - directiosafe = xenstore_read_be_str(xendev, "direct-io-safe"); - blkdev->directiosafe = (directiosafe && atoi(directiosafe)); - - /* do we have all we need? */ - if (blkdev->params == NULL || - blkdev->mode == NULL || - blkdev->type == NULL || - blkdev->dev == NULL) { - goto out_error; - } - - /* read-only ? */ - if (strcmp(blkdev->mode, "w")) { - info |= VDISK_READONLY; - } - - /* cdrom ? */ - if (blkdev->devtype && !strcmp(blkdev->devtype, "cdrom")) { - info |= VDISK_CDROM; - } - - blkdev->file_blk = BLOCK_SIZE; - - /* fill info - * blk_connect supplies sector-size and sectors - */ - xenstore_write_be_int(xendev, "feature-flush-cache", 1); - xenstore_write_be_int(xendev, "info", info); - - xenstore_write_be_int(xendev, "max-ring-page-order", - MAX_RING_PAGE_ORDER); - - blk_parse_discard(blkdev); - - g_free(directiosafe); - return 0; - -out_error: - g_free(blkdev->params); - blkdev->params = NULL; - g_free(blkdev->mode); - blkdev->mode = NULL; - g_free(blkdev->type); - blkdev->type = NULL; - g_free(blkdev->dev); - blkdev->dev = NULL; - g_free(blkdev->devtype); - blkdev->devtype = NULL; - g_free(directiosafe); - blkdev->directiosafe = false; - return -1; -} - -static int blk_connect(struct XenLegacyDevice *xendev) -{ - struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); - int index, qflags; - bool readonly = true; - bool writethrough = true; - int order, ring_ref; - unsigned int ring_size, max_grants; - unsigned int i; - - trace_xen_disk_connect(xendev->name); - - /* read-only ? */ - if (blkdev->directiosafe) { - qflags = BDRV_O_NOCACHE | BDRV_O_NATIVE_AIO; - } else { - qflags = 0; - writethrough = false; - } - if (strcmp(blkdev->mode, "w") == 0) { - qflags |= BDRV_O_RDWR; - readonly = false; - } - if (blkdev->feature_discard) { - qflags |= BDRV_O_UNMAP; - } - - /* init qemu block driver */ - index = (xendev->dev - 202 * 256) / 16; - blkdev->dinfo = drive_get(IF_XEN, 0, index); - if (!blkdev->dinfo) { - Error *local_err = NULL; - QDict *options = NULL; - - if (strcmp(blkdev->fileproto, "")) { - options = qdict_new(); - qdict_put_str(options, "driver", blkdev->fileproto); - } - - /* setup via xenbus -> create new block driver instance */ - xen_pv_printf(xendev, 2, "create new bdrv (xenbus setup)\n"); - blkdev->blk = blk_new_open(blkdev->filename, NULL, options, - qflags, &local_err); - if (!blkdev->blk) { - xen_pv_printf(xendev, 0, "error: %s\n", - error_get_pretty(local_err)); - error_free(local_err); - return -1; - } - blk_set_enable_write_cache(blkdev->blk, !writethrough); - } else { - /* setup via qemu cmdline -> already setup for us */ - xen_pv_printf(xendev, 2, - "get configured bdrv (cmdline setup)\n"); - blkdev->blk = blk_by_legacy_dinfo(blkdev->dinfo); - if (blk_is_read_only(blkdev->blk) && !readonly) { - xen_pv_printf(xendev, 0, "Unexpected read-only drive"); - blkdev->blk = NULL; - return -1; - } - /* blkdev->blk is not create by us, we get a reference - * so we can blk_unref() unconditionally */ - blk_ref(blkdev->blk); - } - blk_attach_dev_legacy(blkdev->blk, blkdev); - blkdev->file_size = blk_getlength(blkdev->blk); - if (blkdev->file_size < 0) { - BlockDriverState *bs = blk_bs(blkdev->blk); - const char *drv_name = bs ? bdrv_get_format_name(bs) : NULL; - xen_pv_printf(xendev, 1, "blk_getlength: %d (%s) | drv %s\n", - (int)blkdev->file_size, strerror(-blkdev->file_size), - drv_name ?: "-"); - blkdev->file_size = 0; - } - - xen_pv_printf(xendev, 1, "type \"%s\", fileproto \"%s\", filename \"%s\"," - " size %" PRId64 " (%" PRId64 " MB)\n", - blkdev->type, blkdev->fileproto, blkdev->filename, - blkdev->file_size, blkdev->file_size / MiB); - - /* Fill in number of sector size and number of sectors */ - xenstore_write_be_int(xendev, "sector-size", blkdev->file_blk); - xenstore_write_be_int64(xendev, "sectors", - blkdev->file_size / blkdev->file_blk); - - if (xenstore_read_fe_int(xendev, "ring-page-order", - &order) == -1) { - blkdev->nr_ring_ref = 1; - - if (xenstore_read_fe_int(xendev, "ring-ref", - &ring_ref) == -1) { - return -1; - } - blkdev->ring_ref[0] = ring_ref; - - } else if (order >= 0 && order <= MAX_RING_PAGE_ORDER) { - blkdev->nr_ring_ref = 1 << order; - - for (i = 0; i < blkdev->nr_ring_ref; i++) { - char *key; - - key = g_strdup_printf("ring-ref%u", i); - if (!key) { - return -1; - } - - if (xenstore_read_fe_int(xendev, key, - &ring_ref) == -1) { - g_free(key); - return -1; - } - blkdev->ring_ref[i] = ring_ref; - - g_free(key); - } - } else { - xen_pv_printf(xendev, 0, "invalid ring-page-order: %d\n", - order); - return -1; - } - - if (xenstore_read_fe_int(xendev, "event-channel", - &xendev->remote_port) == -1) { - return -1; - } - - if (!xendev->protocol) { - blkdev->protocol = BLKIF_PROTOCOL_NATIVE; - } else if (strcmp(xendev->protocol, XEN_IO_PROTO_ABI_NATIVE) == 0) { - blkdev->protocol = BLKIF_PROTOCOL_NATIVE; - } else if (strcmp(xendev->protocol, XEN_IO_PROTO_ABI_X86_32) == 0) { - blkdev->protocol = BLKIF_PROTOCOL_X86_32; - } else if (strcmp(xendev->protocol, XEN_IO_PROTO_ABI_X86_64) == 0) { - blkdev->protocol = BLKIF_PROTOCOL_X86_64; - } else { - blkdev->protocol = BLKIF_PROTOCOL_NATIVE; - } - - ring_size = XC_PAGE_SIZE * blkdev->nr_ring_ref; - switch (blkdev->protocol) { - case BLKIF_PROTOCOL_NATIVE: - { - blkdev->max_requests = __CONST_RING_SIZE(blkif, ring_size); - break; - } - case BLKIF_PROTOCOL_X86_32: - { - blkdev->max_requests = __CONST_RING_SIZE(blkif_x86_32, ring_size); - break; - } - case BLKIF_PROTOCOL_X86_64: - { - blkdev->max_requests = __CONST_RING_SIZE(blkif_x86_64, ring_size); - break; - } - default: - return -1; - } - - /* Add on the number needed for the ring pages */ - max_grants = blkdev->nr_ring_ref; - - xen_be_set_max_grant_refs(xendev, max_grants); - blkdev->sring = xen_be_map_grant_refs(xendev, blkdev->ring_ref, - blkdev->nr_ring_ref, - PROT_READ | PROT_WRITE); - if (!blkdev->sring) { - return -1; - } - - switch (blkdev->protocol) { - case BLKIF_PROTOCOL_NATIVE: - { - blkif_sring_t *sring_native = blkdev->sring; - BACK_RING_INIT(&blkdev->rings.native, sring_native, ring_size); - break; - } - case BLKIF_PROTOCOL_X86_32: - { - blkif_x86_32_sring_t *sring_x86_32 = blkdev->sring; - - BACK_RING_INIT(&blkdev->rings.x86_32_part, sring_x86_32, ring_size); - break; - } - case BLKIF_PROTOCOL_X86_64: - { - blkif_x86_64_sring_t *sring_x86_64 = blkdev->sring; - - BACK_RING_INIT(&blkdev->rings.x86_64_part, sring_x86_64, ring_size); - break; - } - } - - blk_set_aio_context(blkdev->blk, blkdev->ctx); - - xen_be_bind_evtchn(xendev); - - xen_pv_printf(xendev, 1, "ok: proto %s, nr-ring-ref %u, " - "remote port %d, local port %d\n", - xendev->protocol, blkdev->nr_ring_ref, - xendev->remote_port, xendev->local_port); - return 0; -} - -static void blk_disconnect(struct XenLegacyDevice *xendev) -{ - struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); - - trace_xen_disk_disconnect(xendev->name); - - aio_context_acquire(blkdev->ctx); - - if (blkdev->blk) { - blk_set_aio_context(blkdev->blk, qemu_get_aio_context()); - blk_detach_dev(blkdev->blk, blkdev); - blk_unref(blkdev->blk); - blkdev->blk = NULL; - } - xen_pv_unbind_evtchn(xendev); - - aio_context_release(blkdev->ctx); - - if (blkdev->sring) { - xen_be_unmap_grant_refs(xendev, blkdev->sring, - blkdev->nr_ring_ref); - blkdev->sring = NULL; - } -} - -static int blk_free(struct XenLegacyDevice *xendev) -{ - struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); - struct ioreq *ioreq; - - trace_xen_disk_free(xendev->name); - - blk_disconnect(xendev); - - while (!QLIST_EMPTY(&blkdev->freelist)) { - ioreq = QLIST_FIRST(&blkdev->freelist); - QLIST_REMOVE(ioreq, list); - qemu_iovec_destroy(&ioreq->v); - g_free(ioreq); - } - - g_free(blkdev->params); - g_free(blkdev->mode); - g_free(blkdev->type); - g_free(blkdev->dev); - g_free(blkdev->devtype); - qemu_bh_delete(blkdev->bh); - iothread_destroy(blkdev->iothread); - return 0; -} - -static void blk_event(struct XenLegacyDevice *xendev) -{ - struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); - - qemu_bh_schedule(blkdev->bh); -} - -struct XenDevOps xen_blkdev_ops = { - .flags = DEVOPS_FLAG_NEED_GNTDEV, - .size = sizeof(struct XenBlkDev), - .alloc = blk_alloc, - .init = blk_init, - .initialise = blk_connect, - .disconnect = blk_disconnect, - .event = blk_event, - .free = blk_free, -};