summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '0050-cmdline-document-and-enforce-extra_guest_irqs-upper-.patch')
-rw-r--r--0050-cmdline-document-and-enforce-extra_guest_irqs-upper-.patch156
1 files changed, 156 insertions, 0 deletions
diff --git a/0050-cmdline-document-and-enforce-extra_guest_irqs-upper-.patch b/0050-cmdline-document-and-enforce-extra_guest_irqs-upper-.patch
new file mode 100644
index 0000000..f7f61e8
--- /dev/null
+++ b/0050-cmdline-document-and-enforce-extra_guest_irqs-upper-.patch
@@ -0,0 +1,156 @@
+From 30c695ddaf067cbe7a98037474e7910109238807 Mon Sep 17 00:00:00 2001
+From: Jan Beulich <jbeulich@suse.com>
+Date: Thu, 4 Jul 2024 14:14:16 +0200
+Subject: [PATCH 50/56] cmdline: document and enforce "extra_guest_irqs" upper
+ bounds
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+PHYSDEVOP_pirq_eoi_gmfn_v<N> accepting just a single GFN implies that no
+more than 32k pIRQ-s can be used by a domain on x86. Document this upper
+bound.
+
+To also enforce the limit, (ab)use both arch_hwdom_irqs() (changing its
+parameter type) and setup_system_domains(). This is primarily to avoid
+exposing the two static variables or introducing yet further arch hooks.
+
+While touching arch_hwdom_irqs() also mark it hwdom-init.
+
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+Acked-by: Roger Pau Monné <roger.pau@citrix.com>
+
+amend 'cmdline: document and enforce "extra_guest_irqs" upper bounds'
+
+Address late review comments for what is now commit 17f6d398f765:
+- bound max_irqs right away against nr_irqs
+- introduce a #define for a constant used twice
+
+Requested-by: Roger Pau Monné <roger.pau@citrix.com>
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
+master commit: 17f6d398f76597f8009ec0530842fb8705ece7ba
+master date: 2024-07-02 12:00:27 +0200
+master commit: 1f56accba33ffea0abf7d1c6384710823d10cbd6
+master date: 2024-07-03 14:03:27 +0200
+---
+ docs/misc/xen-command-line.pandoc | 3 ++-
+ xen/arch/x86/io_apic.c | 17 ++++++++++-------
+ xen/common/domain.c | 24 ++++++++++++++++++++++--
+ xen/include/xen/irq.h | 3 ++-
+ 4 files changed, 36 insertions(+), 11 deletions(-)
+
+diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc
+index 10a09bbf23..d857bd0f89 100644
+--- a/docs/misc/xen-command-line.pandoc
++++ b/docs/misc/xen-command-line.pandoc
+@@ -1175,7 +1175,8 @@ common for all domUs, while the optional second number (preceded by a comma)
+ is for dom0. Changing the setting for domU has no impact on dom0 and vice
+ versa. For example to change dom0 without changing domU, use
+ `extra_guest_irqs=,512`. The default value for Dom0 and an eventual separate
+-hardware domain is architecture dependent.
++hardware domain is architecture dependent. The upper limit for both values on
++x86 is such that the resulting total number of IRQs can't be higher than 32768.
+ Note that specifying zero as domU value means zero, while for dom0 it means
+ to use the default.
+
+diff --git a/xen/arch/x86/io_apic.c b/xen/arch/x86/io_apic.c
+index c5342789e8..f7591fd091 100644
+--- a/xen/arch/x86/io_apic.c
++++ b/xen/arch/x86/io_apic.c
+@@ -2664,18 +2664,21 @@ void __init ioapic_init(void)
+ nr_irqs_gsi, nr_irqs - nr_irqs_gsi);
+ }
+
+-unsigned int arch_hwdom_irqs(domid_t domid)
++unsigned int __hwdom_init arch_hwdom_irqs(const struct domain *d)
+ {
+ unsigned int n = fls(num_present_cpus());
++ /* Bounding by the domain pirq EOI bitmap capacity. */
++ const unsigned int max_irqs = min_t(unsigned int, nr_irqs,
++ PAGE_SIZE * BITS_PER_BYTE);
+
+- if ( !domid )
+- n = min(n, dom0_max_vcpus());
+- n = min(nr_irqs_gsi + n * NR_DYNAMIC_VECTORS, nr_irqs);
++ if ( is_system_domain(d) )
++ return max_irqs;
+
+- /* Bounded by the domain pirq eoi bitmap gfn. */
+- n = min_t(unsigned int, n, PAGE_SIZE * BITS_PER_BYTE);
++ if ( !d->domain_id )
++ n = min(n, dom0_max_vcpus());
++ n = min(nr_irqs_gsi + n * NR_DYNAMIC_VECTORS, max_irqs);
+
+- printk("Dom%d has maximum %u PIRQs\n", domid, n);
++ printk("%pd has maximum %u PIRQs\n", d, n);
+
+ return n;
+ }
+diff --git a/xen/common/domain.c b/xen/common/domain.c
+index 003f4ab125..62832a5860 100644
+--- a/xen/common/domain.c
++++ b/xen/common/domain.c
+@@ -351,7 +351,8 @@ static int late_hwdom_init(struct domain *d)
+ }
+
+ static unsigned int __read_mostly extra_hwdom_irqs;
+-static unsigned int __read_mostly extra_domU_irqs = 32;
++#define DEFAULT_EXTRA_DOMU_IRQS 32U
++static unsigned int __read_mostly extra_domU_irqs = DEFAULT_EXTRA_DOMU_IRQS;
+
+ static int __init cf_check parse_extra_guest_irqs(const char *s)
+ {
+@@ -688,7 +689,7 @@ struct domain *domain_create(domid_t domid,
+ d->nr_pirqs = nr_static_irqs + extra_domU_irqs;
+ else
+ d->nr_pirqs = extra_hwdom_irqs ? nr_static_irqs + extra_hwdom_irqs
+- : arch_hwdom_irqs(domid);
++ : arch_hwdom_irqs(d);
+ d->nr_pirqs = min(d->nr_pirqs, nr_irqs);
+
+ radix_tree_init(&d->pirq_tree);
+@@ -812,6 +813,25 @@ void __init setup_system_domains(void)
+ if ( IS_ERR(dom_xen) )
+ panic("Failed to create d[XEN]: %ld\n", PTR_ERR(dom_xen));
+
++#ifdef CONFIG_HAS_PIRQ
++ /* Bound-check values passed via "extra_guest_irqs=". */
++ {
++ unsigned int n = max(arch_hwdom_irqs(dom_xen), nr_static_irqs);
++
++ if ( extra_hwdom_irqs > n - nr_static_irqs )
++ {
++ extra_hwdom_irqs = n - nr_static_irqs;
++ printk(XENLOG_WARNING "hwdom IRQs bounded to %u\n", n);
++ }
++ if ( extra_domU_irqs >
++ max(DEFAULT_EXTRA_DOMU_IRQS, n - nr_static_irqs) )
++ {
++ extra_domU_irqs = n - nr_static_irqs;
++ printk(XENLOG_WARNING "domU IRQs bounded to %u\n", n);
++ }
++ }
++#endif
++
+ /*
+ * Initialise our DOMID_IO domain.
+ * This domain owns I/O pages that are within the range of the page_info
+diff --git a/xen/include/xen/irq.h b/xen/include/xen/irq.h
+index 5dcd2d8f0c..bef170bcb6 100644
+--- a/xen/include/xen/irq.h
++++ b/xen/include/xen/irq.h
+@@ -196,8 +196,9 @@ extern struct irq_desc *pirq_spin_lock_irq_desc(
+
+ unsigned int set_desc_affinity(struct irq_desc *desc, const cpumask_t *mask);
+
++/* When passed a system domain, this returns the maximum permissible value. */
+ #ifndef arch_hwdom_irqs
+-unsigned int arch_hwdom_irqs(domid_t domid);
++unsigned int arch_hwdom_irqs(const struct domain *d);
+ #endif
+
+ #ifndef arch_evtchn_bind_pirq
+--
+2.45.2
+