* [PATCH v3 1/3] xen/events: Cleanup find_virq() return codes
2025-08-28 0:36 [PATCH v3 0/3] xen/events: Fix Global and Domain VIRQ tracking Jason Andryuk
@ 2025-08-28 0:36 ` Jason Andryuk
2025-08-28 0:36 ` [PATCH v3 2/3] xen/events: Return -EEXIST for bound VIRQs Jason Andryuk
2025-08-28 0:36 ` [PATCH v3 3/3] xen/events: Update virq_to_irq on migration Jason Andryuk
2 siblings, 0 replies; 6+ messages in thread
From: Jason Andryuk @ 2025-08-28 0:36 UTC (permalink / raw)
To: Juergen Gross, Stefano Stabellini, Oleksandr Tyshchenko,
Konrad Rzeszutek Wilk, Olaf Hering
Cc: Jason Andryuk, stable, Jan Beulich, xen-devel, linux-kernel
rc is overwritten by the evtchn_status hypercall in each iteration, so
the return value will be whatever the last iteration is. This could
incorrectly return success even if the event channel was not found.
Change to an explicit -ENOENT for an un-found virq and return 0 on a
successful match.
Fixes: 62cc5fc7b2e0 ("xen/pv-on-hvm kexec: rebind virqs to existing eventchannel ports")
Cc: stable@vger.kernel.org
Signed-off-by: Jason Andryuk <jason.andryuk@amd.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
---
v3:
Reduce rc's scope
Add R-b: Jan
Mention false success in commit message
Add Fixes
Cc: stable
Add R-b: Juergen
v2:
New
---
drivers/xen/events/events_base.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c
index 41309d38f78c..374231d84e4f 100644
--- a/drivers/xen/events/events_base.c
+++ b/drivers/xen/events/events_base.c
@@ -1318,10 +1318,11 @@ static int find_virq(unsigned int virq, unsigned int cpu, evtchn_port_t *evtchn)
{
struct evtchn_status status;
evtchn_port_t port;
- int rc = -ENOENT;
memset(&status, 0, sizeof(status));
for (port = 0; port < xen_evtchn_max_channels(); port++) {
+ int rc;
+
status.dom = DOMID_SELF;
status.port = port;
rc = HYPERVISOR_event_channel_op(EVTCHNOP_status, &status);
@@ -1331,10 +1332,10 @@ static int find_virq(unsigned int virq, unsigned int cpu, evtchn_port_t *evtchn)
continue;
if (status.u.virq == virq && status.vcpu == xen_vcpu_nr(cpu)) {
*evtchn = port;
- break;
+ return 0;
}
}
- return rc;
+ return -ENOENT;
}
/**
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v3 2/3] xen/events: Return -EEXIST for bound VIRQs
2025-08-28 0:36 [PATCH v3 0/3] xen/events: Fix Global and Domain VIRQ tracking Jason Andryuk
2025-08-28 0:36 ` [PATCH v3 1/3] xen/events: Cleanup find_virq() return codes Jason Andryuk
@ 2025-08-28 0:36 ` Jason Andryuk
2025-09-02 13:35 ` Juergen Gross
2025-08-28 0:36 ` [PATCH v3 3/3] xen/events: Update virq_to_irq on migration Jason Andryuk
2 siblings, 1 reply; 6+ messages in thread
From: Jason Andryuk @ 2025-08-28 0:36 UTC (permalink / raw)
To: Juergen Gross, Stefano Stabellini, Oleksandr Tyshchenko
Cc: Jason Andryuk, stable, xen-devel, linux-kernel
Change find_virq() to return -EEXIST when a VIRQ is bound to a
different CPU than the one passed in. With that, remove the BUG_ON()
from bind_virq_to_irq() to propogate the error upwards.
Some VIRQs are per-cpu, but others are per-domain or global. Those must
be bound to CPU0 and can then migrate elsewhere. The lookup for
per-domain and global will probably fail when migrated off CPU 0,
especially when the current CPU is tracked. This now returns -EEXIST
instead of BUG_ON().
A second call to bind a per-domain or global VIRQ is not expected, but
make it non-fatal to avoid trying to look up the irq, since we don't
know which per_cpu(virq_to_irq) it will be in.
Cc: stable@vger.kernel.org
Signed-off-by: Jason Andryuk <jason.andryuk@amd.com>
---
v3:
Cc: stable as a pre-req for the subsequent virg tracking change
Call __unbind_from_irq() on error ro avoid leaking info
v2:
New
---
drivers/xen/events/events_base.c | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)
diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c
index 374231d84e4f..b060b5a95f45 100644
--- a/drivers/xen/events/events_base.c
+++ b/drivers/xen/events/events_base.c
@@ -1314,10 +1314,12 @@ int bind_interdomain_evtchn_to_irq_lateeoi(struct xenbus_device *dev,
}
EXPORT_SYMBOL_GPL(bind_interdomain_evtchn_to_irq_lateeoi);
-static int find_virq(unsigned int virq, unsigned int cpu, evtchn_port_t *evtchn)
+static int find_virq(unsigned int virq, unsigned int cpu, evtchn_port_t *evtchn,
+ bool percpu)
{
struct evtchn_status status;
evtchn_port_t port;
+ bool exists = false;
memset(&status, 0, sizeof(status));
for (port = 0; port < xen_evtchn_max_channels(); port++) {
@@ -1330,12 +1332,16 @@ static int find_virq(unsigned int virq, unsigned int cpu, evtchn_port_t *evtchn)
continue;
if (status.status != EVTCHNSTAT_virq)
continue;
- if (status.u.virq == virq && status.vcpu == xen_vcpu_nr(cpu)) {
+ if (status.u.virq != virq)
+ continue;
+ if (status.vcpu == xen_vcpu_nr(cpu)) {
*evtchn = port;
return 0;
+ } else if (!percpu) {
+ exists = true;
}
}
- return -ENOENT;
+ return exists ? -EEXIST : -ENOENT;
}
/**
@@ -1382,8 +1388,11 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu, bool percpu)
evtchn = bind_virq.port;
else {
if (ret == -EEXIST)
- ret = find_virq(virq, cpu, &evtchn);
- BUG_ON(ret < 0);
+ ret = find_virq(virq, cpu, &evtchn, percpu);
+ if (ret) {
+ __unbind_from_irq(info, info->irq);
+ goto out;
+ }
}
ret = xen_irq_info_virq_setup(info, cpu, evtchn, virq);
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v3 2/3] xen/events: Return -EEXIST for bound VIRQs
2025-08-28 0:36 ` [PATCH v3 2/3] xen/events: Return -EEXIST for bound VIRQs Jason Andryuk
@ 2025-09-02 13:35 ` Juergen Gross
0 siblings, 0 replies; 6+ messages in thread
From: Juergen Gross @ 2025-09-02 13:35 UTC (permalink / raw)
To: Jason Andryuk, Stefano Stabellini, Oleksandr Tyshchenko
Cc: stable, xen-devel, linux-kernel
[-- Attachment #1.1.1: Type: text/plain, Size: 904 bytes --]
On 28.08.25 02:36, Jason Andryuk wrote:
> Change find_virq() to return -EEXIST when a VIRQ is bound to a
> different CPU than the one passed in. With that, remove the BUG_ON()
> from bind_virq_to_irq() to propogate the error upwards.
>
> Some VIRQs are per-cpu, but others are per-domain or global. Those must
> be bound to CPU0 and can then migrate elsewhere. The lookup for
> per-domain and global will probably fail when migrated off CPU 0,
> especially when the current CPU is tracked. This now returns -EEXIST
> instead of BUG_ON().
>
> A second call to bind a per-domain or global VIRQ is not expected, but
> make it non-fatal to avoid trying to look up the irq, since we don't
> know which per_cpu(virq_to_irq) it will be in.
>
> Cc: stable@vger.kernel.org
> Signed-off-by: Jason Andryuk <jason.andryuk@amd.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
Juergen
[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3743 bytes --]
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v3 3/3] xen/events: Update virq_to_irq on migration
2025-08-28 0:36 [PATCH v3 0/3] xen/events: Fix Global and Domain VIRQ tracking Jason Andryuk
2025-08-28 0:36 ` [PATCH v3 1/3] xen/events: Cleanup find_virq() return codes Jason Andryuk
2025-08-28 0:36 ` [PATCH v3 2/3] xen/events: Return -EEXIST for bound VIRQs Jason Andryuk
@ 2025-08-28 0:36 ` Jason Andryuk
2025-09-02 13:37 ` Juergen Gross
2 siblings, 1 reply; 6+ messages in thread
From: Jason Andryuk @ 2025-08-28 0:36 UTC (permalink / raw)
To: Juergen Gross, Stefano Stabellini, Oleksandr Tyshchenko,
Jeremy Fitzhardinge, Chris Wright
Cc: Jason Andryuk, stable, xen-devel, linux-kernel
VIRQs come in 3 flavors, per-VPU, per-domain, and global, and the VIRQs
are tracked in per-cpu virq_to_irq arrays.
Per-domain and global VIRQs must be bound on CPU 0, and
bind_virq_to_irq() sets the per_cpu virq_to_irq at registration time
Later, the interrupt can migrate, and info->cpu is updated. When
calling __unbind_from_irq(), the per-cpu virq_to_irq is cleared for a
different cpu. If bind_virq_to_irq() is called again with CPU 0, the
stale irq is returned. There won't be any irq_info for the irq, so
things break.
Make xen_rebind_evtchn_to_cpu() update the per_cpu virq_to_irq mappings
to keep them update to date with the current cpu. This ensures the
correct virq_to_irq is cleared in __unbind_from_irq().
Fixes: e46cdb66c8fc ("xen: event channels")
Cc: stable@vger.kernel.org
Signed-off-by: Jason Andryuk <jason.andryuk@amd.com>
---
v3:
Kernel style brace placement
Delay setting old_cpu and tighten scope of variable
v2:
Different approach changing virq_to_irq
---
drivers/xen/events/events_base.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c
index b060b5a95f45..9478fae014e5 100644
--- a/drivers/xen/events/events_base.c
+++ b/drivers/xen/events/events_base.c
@@ -1797,9 +1797,20 @@ static int xen_rebind_evtchn_to_cpu(struct irq_info *info, unsigned int tcpu)
* virq or IPI channel, which don't actually need to be rebound. Ignore
* it, but don't do the xenlinux-level rebind in that case.
*/
- if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu) >= 0)
+ if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu) >= 0) {
+ int old_cpu = info->cpu;
+
bind_evtchn_to_cpu(info, tcpu, false);
+ if (info->type == IRQT_VIRQ) {
+ int virq = info->u.virq;
+ int irq = per_cpu(virq_to_irq, old_cpu)[virq];
+
+ per_cpu(virq_to_irq, old_cpu)[virq] = -1;
+ per_cpu(virq_to_irq, tcpu)[virq] = irq;
+ }
+ }
+
do_unmask(info, EVT_MASK_REASON_TEMPORARY);
return 0;
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v3 3/3] xen/events: Update virq_to_irq on migration
2025-08-28 0:36 ` [PATCH v3 3/3] xen/events: Update virq_to_irq on migration Jason Andryuk
@ 2025-09-02 13:37 ` Juergen Gross
0 siblings, 0 replies; 6+ messages in thread
From: Juergen Gross @ 2025-09-02 13:37 UTC (permalink / raw)
To: Jason Andryuk, Stefano Stabellini, Oleksandr Tyshchenko,
Jeremy Fitzhardinge, Chris Wright
Cc: stable, xen-devel, linux-kernel
[-- Attachment #1.1.1: Type: text/plain, Size: 1006 bytes --]
On 28.08.25 02:36, Jason Andryuk wrote:
> VIRQs come in 3 flavors, per-VPU, per-domain, and global, and the VIRQs
> are tracked in per-cpu virq_to_irq arrays.
>
> Per-domain and global VIRQs must be bound on CPU 0, and
> bind_virq_to_irq() sets the per_cpu virq_to_irq at registration time
> Later, the interrupt can migrate, and info->cpu is updated. When
> calling __unbind_from_irq(), the per-cpu virq_to_irq is cleared for a
> different cpu. If bind_virq_to_irq() is called again with CPU 0, the
> stale irq is returned. There won't be any irq_info for the irq, so
> things break.
>
> Make xen_rebind_evtchn_to_cpu() update the per_cpu virq_to_irq mappings
> to keep them update to date with the current cpu. This ensures the
> correct virq_to_irq is cleared in __unbind_from_irq().
>
> Fixes: e46cdb66c8fc ("xen: event channels")
> Cc: stable@vger.kernel.org
> Signed-off-by: Jason Andryuk <jason.andryuk@amd.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
Juergen
[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3743 bytes --]
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread