]> xenbits.xensource.com Git - xen.git/commitdiff
x86/smp: do not use shorthand IPI destinations in CPU hot{,un}plug contexts
authorRoger Pau Monné <roger.pau@citrix.com>
Wed, 26 Jun 2024 12:08:40 +0000 (14:08 +0200)
committerJan Beulich <jbeulich@suse.com>
Wed, 26 Jun 2024 12:08:40 +0000 (14:08 +0200)
Due to the current rwlock logic, if the CPU calling get_cpu_maps() does
so from a cpu_hotplug_{begin,done}() region the function will still
return success, because a CPU taking the rwlock in read mode after
having taken it in write mode is allowed.  Such corner case makes using
get_cpu_maps() alone not enough to prevent using the shorthand in CPU
hotplug regions.

Introduce a new helper to detect whether the current caller is between a
cpu_hotplug_{begin,done}() region and use it in send_IPI_mask() to restrict
shorthand usage.

Fixes: 5500d265a2a8 ('x86/smp: use APIC ALLBUT destination shorthand when possible')
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
master commit: 171c52fba5d94e050d704770480dcb983490d0ad
master date: 2024-06-12 14:29:31 +0200

xen/arch/x86/smp.c
xen/common/cpu.c
xen/include/xen/cpu.h
xen/include/xen/rwlock.h

index b42603c351c29a2ea3100b0f7e927ed0acb76cf4..1f27b20286da13bd571c7684a3937a6b115594b9 100644 (file)
@@ -89,7 +89,7 @@ void send_IPI_mask(const cpumask_t *mask, int vector)
      * the system have been accounted for.
      */
     if ( system_state > SYS_STATE_smp_boot &&
-         !unaccounted_cpus && !disabled_cpus &&
+         !unaccounted_cpus && !disabled_cpus && !cpu_in_hotplug_context() &&
          /* NB: get_cpu_maps lock requires enabled interrupts. */
          local_irq_is_enabled() && (cpus_locked = get_cpu_maps()) &&
          (park_offline_cpus ||
index 778b6820b7546eea4bbd07c29a18dc16909a4d61..9a2c088873c09ad4f1f6b7c9d57ee97ee97a2f2f 100644 (file)
@@ -68,6 +68,11 @@ void cpu_hotplug_done(void)
     write_unlock(&cpu_add_remove_lock);
 }
 
+bool cpu_in_hotplug_context(void)
+{
+    return rw_is_write_locked_by_me(&cpu_add_remove_lock);
+}
+
 static NOTIFIER_HEAD(cpu_chain);
 
 void __init register_cpu_notifier(struct notifier_block *nb)
index e8eeb217a05f9bf2e048ca4320aba411ae27b781..8a1afb183704c59ee1cf9d16b4b24f1e7f1ff1a1 100644 (file)
@@ -13,6 +13,16 @@ void put_cpu_maps(void);
 void cpu_hotplug_begin(void);
 void cpu_hotplug_done(void);
 
+/*
+ * Returns true when the caller CPU is between a cpu_hotplug_{begin,done}()
+ * region.
+ *
+ * This is required to safely identify hotplug contexts, as get_cpu_maps()
+ * would otherwise succeed because a caller holding the lock in write mode is
+ * allowed to acquire the same lock in read mode.
+ */
+bool cpu_in_hotplug_context(void);
+
 /* Receive notification of CPU hotplug events. */
 void register_cpu_notifier(struct notifier_block *nb);
 
index abe0804bf7d565e6944f6ddbc896b2970e6502fa..02369079f9496a20bdabb9db8d50086363d0cb7c 100644 (file)
@@ -297,6 +297,8 @@ static always_inline void write_lock_irq(rwlock_t *l)
 
 #define rw_is_locked(l)               _rw_is_locked(l)
 #define rw_is_write_locked(l)         _rw_is_write_locked(l)
+#define rw_is_write_locked_by_me(l) \
+    lock_evaluate_nospec(_is_write_locked_by_me(atomic_read(&(l)->cnts)))
 
 
 typedef struct percpu_rwlock percpu_rwlock_t;