Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xen/events: Return -EEXIST for bound VIRQs

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>

authored by

Jason Andryuk and committed by
Juergen Gross
07ce121d 08df2d7d

+14 -5
+14 -5
drivers/xen/events/events_base.c
··· 1314 1314 } 1315 1315 EXPORT_SYMBOL_GPL(bind_interdomain_evtchn_to_irq_lateeoi); 1316 1316 1317 - static int find_virq(unsigned int virq, unsigned int cpu, evtchn_port_t *evtchn) 1317 + static int find_virq(unsigned int virq, unsigned int cpu, evtchn_port_t *evtchn, 1318 + bool percpu) 1318 1319 { 1319 1320 struct evtchn_status status; 1320 1321 evtchn_port_t port; 1322 + bool exists = false; 1321 1323 1322 1324 memset(&status, 0, sizeof(status)); 1323 1325 for (port = 0; port < xen_evtchn_max_channels(); port++) { ··· 1332 1330 continue; 1333 1331 if (status.status != EVTCHNSTAT_virq) 1334 1332 continue; 1335 - if (status.u.virq == virq && status.vcpu == xen_vcpu_nr(cpu)) { 1333 + if (status.u.virq != virq) 1334 + continue; 1335 + if (status.vcpu == xen_vcpu_nr(cpu)) { 1336 1336 *evtchn = port; 1337 1337 return 0; 1338 + } else if (!percpu) { 1339 + exists = true; 1338 1340 } 1339 1341 } 1340 - return -ENOENT; 1342 + return exists ? -EEXIST : -ENOENT; 1341 1343 } 1342 1344 1343 1345 /** ··· 1388 1382 evtchn = bind_virq.port; 1389 1383 else { 1390 1384 if (ret == -EEXIST) 1391 - ret = find_virq(virq, cpu, &evtchn); 1392 - BUG_ON(ret < 0); 1385 + ret = find_virq(virq, cpu, &evtchn, percpu); 1386 + if (ret) { 1387 + __unbind_from_irq(info, info->irq); 1388 + goto out; 1389 + } 1393 1390 } 1394 1391 1395 1392 ret = xen_irq_info_virq_setup(info, cpu, evtchn, virq);