]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
xen/events: Return -EEXIST for bound VIRQs
authorJason Andryuk <jason.andryuk@amd.com>
Thu, 28 Aug 2025 00:36:02 +0000 (20:36 -0400)
committerJuergen Gross <jgross@suse.com>
Tue, 9 Sep 2025 07:09:30 +0000 (09:09 +0200)
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>
Signed-off-by: Juergen Gross <jgross@suse.com>
Message-ID: <20250828003604.8949-3-jason.andryuk@amd.com>

drivers/xen/events/events_base.c

index 374231d84e4f7758556cf92cb45a454e373c60f7..b060b5a95f458d27243589d0367d50252d3f15ed 100644 (file)
@@ -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);