From d0a69069bb22316319835fbabf1a713c381878b8 Mon Sep 17 00:00:00 2001 From: Elliott Mitchell Date: Wed, 13 Oct 2021 16:13:53 -0700 Subject: xen/x86: rework isrc allocation to use list instead of table scanning Scanning the list of interrupts to find an unused entry is rather inefficient. Instead overlay a free list structure and use a list instead. This also has the useful effect of removing the last use of evtchn_type values outside of xen_intr.c. Reviewed by: royger [royger] - Make avail_list static. --- sys/x86/xen/xen_intr.c | 76 +++++++++++++++++++------------------------------- 1 file changed, 29 insertions(+), 47 deletions(-) diff --git a/sys/x86/xen/xen_intr.c b/sys/x86/xen/xen_intr.c index e23a021c069b..fe4a4b0f4dce 100644 --- a/sys/x86/xen/xen_intr.c +++ b/sys/x86/xen/xen_intr.c @@ -74,9 +74,6 @@ static MALLOC_DEFINE(M_XENINTR, "xen_intr", "Xen Interrupt Services"); * Lock for x86-related structures. Notably modifying * xen_intr_auto_vector_count, and allocating interrupts require this lock be * held. - * - * ->xi_type == EVTCHN_TYPE_UNBOUND indicates a xenisrc is under control of - * this lock and operations require it be held. */ static struct mtx xen_intr_x86_lock; @@ -165,6 +162,18 @@ static struct mtx xen_intr_isrc_lock; static u_int xen_intr_auto_vector_count; static struct xenisrc *xen_intr_port_to_isrc[NR_EVENT_CHANNELS]; +/* + * list of released isrcs + * This is meant to overlay struct xenisrc, with only the xen_arch_isrc_t + * portion being preserved, everything else can be wiped. + */ +struct avail_list { + xen_arch_isrc_t preserve; + SLIST_ENTRY(avail_list) free; +}; +static SLIST_HEAD(free, avail_list) avail_list = + SLIST_HEAD_INITIALIZER(avail_list); + /*------------------------- Private Functions --------------------------------*/ /** @@ -242,48 +251,6 @@ evtchn_cpu_unmask_port(u_int cpu, evtchn_port_t port) xen_set_bit(port, pcpu->evtchn_enabled); } -/** - * Search for an already allocated but currently unused Xen interrupt - * source object. - * - * \param type Restrict the search to interrupt sources of the given - * type. - * - * \return A pointer to a free Xen interrupt source object or NULL. - */ -static struct xenisrc * -xen_intr_find_unused_isrc(enum evtchn_type type) -{ - int isrc_idx; - - mtx_assert(&xen_intr_x86_lock, MA_OWNED); - - for (isrc_idx = 0; isrc_idx < xen_intr_auto_vector_count; isrc_idx ++) { - struct xenisrc *isrc; - u_int vector; - - vector = first_evtchn_irq + isrc_idx; - isrc = (struct xenisrc *)intr_lookup_source(vector); - /* - * Since intr_register_source() must be called while unlocked, - * isrc == NULL *will* occur, though very infrequently. - * - * This also allows a very small gap where a foreign intrusion - * into Xen's interrupt range could be examined by this test. - */ - if (__predict_true(isrc != NULL) && - __predict_true(isrc->xi_arch.intsrc.is_pic == - &xen_intr_pic) && - isrc->xi_type == EVTCHN_TYPE_UNBOUND) { - KASSERT(isrc->xi_arch.intsrc.is_handlers == 0, - ("Free evtchn still has handlers")); - isrc->xi_type = type; - return (isrc); - } - } - return (NULL); -} - /** * Allocate a Xen interrupt source object. * @@ -301,9 +268,18 @@ xen_intr_alloc_isrc(enum evtchn_type type) int error; mtx_lock(&xen_intr_x86_lock); - isrc = xen_intr_find_unused_isrc(type); + isrc = (struct xenisrc *)SLIST_FIRST(&avail_list); if (isrc != NULL) { + SLIST_REMOVE_HEAD(&avail_list, free); mtx_unlock(&xen_intr_x86_lock); + + KASSERT(isrc->xi_arch.intsrc.is_pic == &xen_intr_pic, + ("interrupt not owned by Xen code?")); + + KASSERT(isrc->xi_arch.intsrc.is_handlers == 0, + ("Free evtchn still has handlers")); + + isrc->xi_type = type; return (isrc); } @@ -369,8 +345,14 @@ xen_intr_release_isrc(struct xenisrc *isrc) /* not reachable from xen_intr_port_to_isrc[], unlock */ mtx_unlock(&xen_intr_isrc_lock); + _Static_assert(sizeof(struct xenisrc) >= sizeof(struct avail_list), + "unused structure MUST be no larger than in-use structure"); + _Static_assert(offsetof(struct xenisrc, xi_arch) == + offsetof(struct avail_list, preserve), + "unused structure does not properly overlay in-use structure"); + mtx_lock(&xen_intr_x86_lock); - isrc->xi_type = EVTCHN_TYPE_UNBOUND; + SLIST_INSERT_HEAD(&avail_list, (struct avail_list *)isrc, free); mtx_unlock(&xen_intr_x86_lock); return (0); } -- cgit v1.2.3