Skip to content

Commit 3cd0462

Browse files
committed
Merge branch 'smp-hotplug-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull CPU hotplug updates from Thomas Gleixner: "A small update for the SMP hotplug code code: - Track "booted once" CPUs in a cpumask so the x86 APIC code has an easy way to decide whether broadcast IPIs are safe to use or not. - Implement a cpumask_or_equal() helper for the IPI broadcast evaluation. The above two changes have been also pulled into the x86/apic branch for implementing the conditional IPI broadcast feature. - Cache the number of online CPUs instead of reevaluating it over and over. num_online_cpus() is an unreliable snapshot anyway except when it is used outside a cpu hotplug locked region. The cached access is not changing this, but it's definitely faster than calculating the bitmap wheight especially in hot paths" * 'smp-hotplug-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: cpu/hotplug: Cache number of online CPUs cpumask: Implement cpumask_or_equal() smp/hotplug: Track booted once CPUs in a cpumask
2 parents 16208cd + 0c09ab9 commit 3cd0462

File tree

4 files changed

+106
-13
lines changed

4 files changed

+106
-13
lines changed

include/linux/bitmap.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,10 @@ extern int __bitmap_empty(const unsigned long *bitmap, unsigned int nbits);
120120
extern int __bitmap_full(const unsigned long *bitmap, unsigned int nbits);
121121
extern int __bitmap_equal(const unsigned long *bitmap1,
122122
const unsigned long *bitmap2, unsigned int nbits);
123+
extern bool __pure __bitmap_or_equal(const unsigned long *src1,
124+
const unsigned long *src2,
125+
const unsigned long *src3,
126+
unsigned int nbits);
123127
extern void __bitmap_complement(unsigned long *dst, const unsigned long *src,
124128
unsigned int nbits);
125129
extern void __bitmap_shift_right(unsigned long *dst, const unsigned long *src,
@@ -321,6 +325,25 @@ static inline int bitmap_equal(const unsigned long *src1,
321325
return __bitmap_equal(src1, src2, nbits);
322326
}
323327

328+
/**
329+
* bitmap_or_equal - Check whether the or of two bitnaps is equal to a third
330+
* @src1: Pointer to bitmap 1
331+
* @src2: Pointer to bitmap 2 will be or'ed with bitmap 1
332+
* @src3: Pointer to bitmap 3. Compare to the result of *@src1 | *@src2
333+
*
334+
* Returns: True if (*@src1 | *@src2) == *@src3, false otherwise
335+
*/
336+
static inline bool bitmap_or_equal(const unsigned long *src1,
337+
const unsigned long *src2,
338+
const unsigned long *src3,
339+
unsigned int nbits)
340+
{
341+
if (!small_const_nbits(nbits))
342+
return __bitmap_or_equal(src1, src2, src3, nbits);
343+
344+
return !(((*src1 | *src2) ^ *src3) & BITMAP_LAST_WORD_MASK(nbits));
345+
}
346+
324347
static inline int bitmap_intersects(const unsigned long *src1,
325348
const unsigned long *src2, unsigned int nbits)
326349
{

include/linux/cpumask.h

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <linux/kernel.h>
1111
#include <linux/threads.h>
1212
#include <linux/bitmap.h>
13+
#include <linux/atomic.h>
1314
#include <linux/bug.h>
1415

1516
/* Don't assign or return these: may not be this big! */
@@ -95,8 +96,21 @@ extern struct cpumask __cpu_active_mask;
9596
#define cpu_present_mask ((const struct cpumask *)&__cpu_present_mask)
9697
#define cpu_active_mask ((const struct cpumask *)&__cpu_active_mask)
9798

99+
extern atomic_t __num_online_cpus;
100+
98101
#if NR_CPUS > 1
99-
#define num_online_cpus() cpumask_weight(cpu_online_mask)
102+
/**
103+
* num_online_cpus() - Read the number of online CPUs
104+
*
105+
* Despite the fact that __num_online_cpus is of type atomic_t, this
106+
* interface gives only a momentary snapshot and is not protected against
107+
* concurrent CPU hotplug operations unless invoked from a cpuhp_lock held
108+
* region.
109+
*/
110+
static inline unsigned int num_online_cpus(void)
111+
{
112+
return atomic_read(&__num_online_cpus);
113+
}
100114
#define num_possible_cpus() cpumask_weight(cpu_possible_mask)
101115
#define num_present_cpus() cpumask_weight(cpu_present_mask)
102116
#define num_active_cpus() cpumask_weight(cpu_active_mask)
@@ -115,6 +129,8 @@ extern struct cpumask __cpu_active_mask;
115129
#define cpu_active(cpu) ((cpu) == 0)
116130
#endif
117131

132+
extern cpumask_t cpus_booted_once_mask;
133+
118134
static inline void cpu_max_bits_warn(unsigned int cpu, unsigned int bits)
119135
{
120136
#ifdef CONFIG_DEBUG_PER_CPU_MAPS
@@ -473,6 +489,20 @@ static inline bool cpumask_equal(const struct cpumask *src1p,
473489
nr_cpumask_bits);
474490
}
475491

492+
/**
493+
* cpumask_or_equal - *src1p | *src2p == *src3p
494+
* @src1p: the first input
495+
* @src2p: the second input
496+
* @src3p: the third input
497+
*/
498+
static inline bool cpumask_or_equal(const struct cpumask *src1p,
499+
const struct cpumask *src2p,
500+
const struct cpumask *src3p)
501+
{
502+
return bitmap_or_equal(cpumask_bits(src1p), cpumask_bits(src2p),
503+
cpumask_bits(src3p), nr_cpumask_bits);
504+
}
505+
476506
/**
477507
* cpumask_intersects - (*src1p & *src2p) != 0
478508
* @src1p: the first input
@@ -805,14 +835,7 @@ set_cpu_present(unsigned int cpu, bool present)
805835
cpumask_clear_cpu(cpu, &__cpu_present_mask);
806836
}
807837

808-
static inline void
809-
set_cpu_online(unsigned int cpu, bool online)
810-
{
811-
if (online)
812-
cpumask_set_cpu(cpu, &__cpu_online_mask);
813-
else
814-
cpumask_clear_cpu(cpu, &__cpu_online_mask);
815-
}
838+
void set_cpu_online(unsigned int cpu, bool online);
816839

817840
static inline void
818841
set_cpu_active(unsigned int cpu, bool active)

kernel/cpu.c

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ struct cpuhp_cpu_state {
6262
bool rollback;
6363
bool single;
6464
bool bringup;
65-
bool booted_once;
6665
struct hlist_node *node;
6766
struct hlist_node *last;
6867
enum cpuhp_state cb_state;
@@ -76,6 +75,10 @@ static DEFINE_PER_CPU(struct cpuhp_cpu_state, cpuhp_state) = {
7675
.fail = CPUHP_INVALID,
7776
};
7877

78+
#ifdef CONFIG_SMP
79+
cpumask_t cpus_booted_once_mask;
80+
#endif
81+
7982
#if defined(CONFIG_LOCKDEP) && defined(CONFIG_SMP)
8083
static struct lockdep_map cpuhp_state_up_map =
8184
STATIC_LOCKDEP_MAP_INIT("cpuhp_state-up", &cpuhp_state_up_map);
@@ -433,7 +436,7 @@ static inline bool cpu_smt_allowed(unsigned int cpu)
433436
* CPU. Otherwise, a broadacasted MCE observing CR4.MCE=0b on any
434437
* core will shutdown the machine.
435438
*/
436-
return !per_cpu(cpuhp_state, cpu).booted_once;
439+
return !cpumask_test_cpu(cpu, &cpus_booted_once_mask);
437440
}
438441
#else
439442
static inline bool cpu_smt_allowed(unsigned int cpu) { return true; }
@@ -1066,7 +1069,7 @@ void notify_cpu_starting(unsigned int cpu)
10661069
int ret;
10671070

10681071
rcu_cpu_starting(cpu); /* Enables RCU usage on this CPU. */
1069-
st->booted_once = true;
1072+
cpumask_set_cpu(cpu, &cpus_booted_once_mask);
10701073
while (st->state < target) {
10711074
st->state++;
10721075
ret = cpuhp_invoke_callback(cpu, st->state, true, NULL, NULL);
@@ -2295,6 +2298,9 @@ EXPORT_SYMBOL(__cpu_present_mask);
22952298
struct cpumask __cpu_active_mask __read_mostly;
22962299
EXPORT_SYMBOL(__cpu_active_mask);
22972300

2301+
atomic_t __num_online_cpus __read_mostly;
2302+
EXPORT_SYMBOL(__num_online_cpus);
2303+
22982304
void init_cpu_present(const struct cpumask *src)
22992305
{
23002306
cpumask_copy(&__cpu_present_mask, src);
@@ -2310,6 +2316,27 @@ void init_cpu_online(const struct cpumask *src)
23102316
cpumask_copy(&__cpu_online_mask, src);
23112317
}
23122318

2319+
void set_cpu_online(unsigned int cpu, bool online)
2320+
{
2321+
/*
2322+
* atomic_inc/dec() is required to handle the horrid abuse of this
2323+
* function by the reboot and kexec code which invoke it from
2324+
* IPI/NMI broadcasts when shutting down CPUs. Invocation from
2325+
* regular CPU hotplug is properly serialized.
2326+
*
2327+
* Note, that the fact that __num_online_cpus is of type atomic_t
2328+
* does not protect readers which are not serialized against
2329+
* concurrent hotplug operations.
2330+
*/
2331+
if (online) {
2332+
if (!cpumask_test_and_set_cpu(cpu, &__cpu_online_mask))
2333+
atomic_inc(&__num_online_cpus);
2334+
} else {
2335+
if (cpumask_test_and_clear_cpu(cpu, &__cpu_online_mask))
2336+
atomic_dec(&__num_online_cpus);
2337+
}
2338+
}
2339+
23132340
/*
23142341
* Activate the first processor.
23152342
*/
@@ -2334,7 +2361,7 @@ void __init boot_cpu_init(void)
23342361
void __init boot_cpu_hotplug_init(void)
23352362
{
23362363
#ifdef CONFIG_SMP
2337-
this_cpu_write(cpuhp_state.booted_once, true);
2364+
cpumask_set_cpu(smp_processor_id(), &cpus_booted_once_mask);
23382365
#endif
23392366
this_cpu_write(cpuhp_state.state, CPUHP_ONLINE);
23402367
}

lib/bitmap.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,26 @@ int __bitmap_equal(const unsigned long *bitmap1,
5959
}
6060
EXPORT_SYMBOL(__bitmap_equal);
6161

62+
bool __bitmap_or_equal(const unsigned long *bitmap1,
63+
const unsigned long *bitmap2,
64+
const unsigned long *bitmap3,
65+
unsigned int bits)
66+
{
67+
unsigned int k, lim = bits / BITS_PER_LONG;
68+
unsigned long tmp;
69+
70+
for (k = 0; k < lim; ++k) {
71+
if ((bitmap1[k] | bitmap2[k]) != bitmap3[k])
72+
return false;
73+
}
74+
75+
if (!(bits % BITS_PER_LONG))
76+
return true;
77+
78+
tmp = (bitmap1[k] | bitmap2[k]) ^ bitmap3[k];
79+
return (tmp & BITMAP_LAST_WORD_MASK(bits)) == 0;
80+
}
81+
6282
void __bitmap_complement(unsigned long *dst, const unsigned long *src, unsigned int bits)
6383
{
6484
unsigned int k, lim = BITS_TO_LONGS(bits);

0 commit comments

Comments
 (0)