linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/3] xen/events: Fix Global and Domain VIRQ tracking
@ 2025-08-28  0:36 Jason Andryuk
  2025-08-28  0:36 ` [PATCH v3 1/3] xen/events: Cleanup find_virq() return codes Jason Andryuk
                   ` (2 more replies)
  0 siblings, 3 replies; 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, xen-devel, linux-kernel

v2 and v3 are now series first changing find_virq() to return -EEXIST in
some cases, and then tracking cpu movement of VIRQs.  This keeps ensures
the cpu is correct when calling unbind_from_irq().

I'm adding Cc stable to all patches.  Patch 2 doesn't have a Fixes, but
it goes together with patch 3.

Jason Andryuk (3):
  xen/events: Cleanup find_virq() return codes
  xen/events: Return -EEXIST for bound VIRQs
  xen/events: Update virq_to_irq on migration

 drivers/xen/events/events_base.c | 37 +++++++++++++++++++++++++-------
 1 file changed, 29 insertions(+), 8 deletions(-)

-- 
2.34.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [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

* [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 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

* 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

end of thread, other threads:[~2025-09-02 13:37 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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-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
2025-09-02 13:37   ` Juergen Gross

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).