|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH] hw/xen: Prepare qemu for multi-ioreqpage support
When Xen gains support for ioreq servers backed by more than a single ioreq page, which is needed once a domain's vCPU count exceeds what fits on one page (XC_PAGE_SIZE / sizeof(ioreq_t) = 128 vCPUs), Qemu needs to be extended to request as many ioreq frames as the domain's max vCPU count requires, via xen_map_ioreq_server() and treat the mapped ioreq region as a flat array of ioreq_t rather than a single shared_iopage_t. To support this, xen_map_ioreq_server() now takes max_cpus and computes the number of required ioreq frames and then requests that many frames from the resource-mapping API. XenIOState::shared_page is changed from shared_iopage_t * to ioreq_t *, and xen_vcpu_eport()/xen_vcpu_ioreq() index it directly as a flat array, matching how the Xen side will lay out multiple ioreq pages contiguously via vmap(). Also guard against hosts that don't support multi-page ioreq servers. Currently the xen_get_ioreq_server_info()/xenforeignmemory_map() path only gives out a single ioreq page, so bail out instead of silently mapping fewer pages than max_cpus needs. Continuing past that one page leaves xen_vcpu_eport()/xen_vcpu_ioreq() reading and writing past the single mapped page for vCPUs beyond the first 128. Likewise, a host that recognizes XENMEM_resource_ioreq_server but predates multi-page support rejects frame indices beyond the legacy bufioreq/ioreq pair with EINVAL. Signed-off-by: Julian Vetter <julian.vetter@xxxxxxxxxx> --- This patch is the QEMU counterpart to the corresponding Xen-side ioreq multi-page series, which adds support to expose more than one ioreq frame per server depending on the number of vCPUs: https://lore.kernel.org/xen-devel/20260420093820.825969-1-julian.vetter@xxxxxxxxxx/ As long as this series hasn't landed this patch has no effect, other than explicitly rejecting requests for HVM domains with more than 128 vCPUs. But, this isn't currenly possible because HVM_MAX_VCPUS is still 128 in Xen. So, on an unmodified Xen, num_ioreq_pages can never exceed 1. This patch and the series for Xen is just preparatory work. Once a patch raises the HVM_MAX_VCPUS the ioreq server code is ready. --- hw/xen/xen-hvm-common.c | 39 ++++++++++++++++++++++++++++----- include/hw/xen/xen-hvm-common.h | 10 ++++----- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/hw/xen/xen-hvm-common.c b/hw/xen/xen-hvm-common.c index 62d88804c4..de729ead95 100644 --- a/hw/xen/xen-hvm-common.c +++ b/hw/xen/xen-hvm-common.c @@ -677,16 +677,19 @@ void xen_exit_notifier(Notifier *n, void *data) xs_daemon_close(state->xenstore); } -static int xen_map_ioreq_server(XenIOState *state) +static int xen_map_ioreq_server(XenIOState *state, unsigned int max_cpus) { void *addr = NULL; xen_pfn_t ioreq_pfn; xen_pfn_t bufioreq_pfn; evtchn_port_t bufioreq_evtchn; - unsigned long num_frames = 1; - unsigned long frame = 1; + unsigned long num_ioreq_pages; + unsigned long num_frames; + unsigned long frame; int rc; + num_ioreq_pages = DIV_ROUND_UP(max_cpus, XC_PAGE_SIZE / sizeof(ioreq_t)); + /* * Attempt to map using the resource API and fall back to normal * foreign mapping if this is not supported. @@ -696,7 +699,10 @@ static int xen_map_ioreq_server(XenIOState *state) if (state->has_bufioreq) { frame = 0; - num_frames = 2; + num_frames = 1 + num_ioreq_pages; + } else { + frame = 1; + num_frames = num_ioreq_pages; } state->fres = xenforeignmemory_map_resource(xen_fmem, xen_domid, XENMEM_resource_ioreq_server, @@ -711,6 +717,17 @@ static int xen_map_ioreq_server(XenIOState *state) state->buffered_io_page = addr; state->shared_page = addr + XC_PAGE_SIZE; } + } else if (errno == EINVAL && num_ioreq_pages > 1) { + /* + * The host may predate support for more than a single ioreq frame + * (i.e. it rejects any frame index beyond the single bufioreq/ioreq + * pair with EINVAL). We can't run this many vCPUs without an ioreq + * slot for each of them. + */ + error_report("Xen does not support mapping %lu ioreq pages " + "(needed for %u vCPUs)", + num_ioreq_pages, max_cpus); + return -1; } else if (errno != EOPNOTSUPP) { error_report("failed to map ioreq server resources: error %d handle=%p", errno, xen_xc); @@ -740,6 +757,17 @@ static int xen_map_ioreq_server(XenIOState *state) if (state->shared_page == NULL) { trace_xen_map_ioreq_server_shared_page(ioreq_pfn); + if (num_ioreq_pages > 1) { + /* + * The legacy get_ioreq_server_info()/map() path only ever + * hands out a single ioreq page, so it has no way to give us + * ioreq slots for every vCPU. + */ + error_report("ioreq server fallback path supports only 1 " + "ioreq page. %lu pages are needed for %u vCPUs", + num_ioreq_pages, max_cpus); + return -1; + } state->shared_page = xenforeignmemory_map(xen_fmem, xen_domid, PROT_READ | PROT_WRITE, 1, &ioreq_pfn, NULL); @@ -840,7 +868,7 @@ static void xen_do_ioreq_register(XenIOState *state, */ qemu_register_wakeup_support(); - rc = xen_map_ioreq_server(state); + rc = xen_map_ioreq_server(state, max_cpus); if (rc < 0) { goto err; } @@ -857,7 +885,6 @@ static void xen_do_ioreq_register(XenIOState *state, state->ioreq_local_port = g_new0(evtchn_port_t, max_cpus); - /* FIXME: how about if we overflow the page here? */ for (i = 0; i < max_cpus; i++) { rc = qemu_xen_evtchn_bind_interdomain(state->xce_handle, xen_domid, xen_vcpu_eport(state->shared_page, diff --git a/include/hw/xen/xen-hvm-common.h b/include/hw/xen/xen-hvm-common.h index d177ff14ea..7a0037aa45 100644 --- a/include/hw/xen/xen-hvm-common.h +++ b/include/hw/xen/xen-hvm-common.h @@ -25,13 +25,13 @@ extern DeviceListener xen_device_listener; #define XEN_GRANT_ADDR_OFF (1ULL << 63) -static inline uint32_t xen_vcpu_eport(shared_iopage_t *shared_page, int i) +static inline uint32_t xen_vcpu_eport(ioreq_t *shared_page, int i) { - return shared_page->vcpu_ioreq[i].vp_eport; + return shared_page[i].vp_eport; } -static inline ioreq_t *xen_vcpu_ioreq(shared_iopage_t *shared_page, int vcpu) +static inline ioreq_t *xen_vcpu_ioreq(ioreq_t *shared_page, int vcpu) { - return &shared_page->vcpu_ioreq[vcpu]; + return &shared_page[vcpu]; } #define BUFFER_IO_MAX_DELAY 100 @@ -53,7 +53,7 @@ typedef struct XenPciDevice { typedef struct XenIOState { ioservid_t ioservid; - shared_iopage_t *shared_page; + ioreq_t *shared_page; buffered_iopage_t *buffered_io_page; xenforeignmemory_resource_handle *fres; QEMUTimer *buffered_io_timer; -- 2.53.0 -- | Vates XCP-ng & Xen Orchestra - Vates solutions web: https://vates.tech
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |