Skip to content

Commit a22681f

Browse files
committed
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: VFS: Fix race between CPU hotplug and lglocks
2 parents 6d451c5 + e30e2fd commit a22681f

File tree

1 file changed

+32
-4
lines changed

1 file changed

+32
-4
lines changed

include/linux/lglock.h

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <linux/spinlock.h>
2323
#include <linux/lockdep.h>
2424
#include <linux/percpu.h>
25+
#include <linux/cpu.h>
2526

2627
/* can make br locks by using local lock for read side, global lock for write */
2728
#define br_lock_init(name) name##_lock_init()
@@ -72,9 +73,31 @@
7273

7374
#define DEFINE_LGLOCK(name) \
7475
\
76+
DEFINE_SPINLOCK(name##_cpu_lock); \
77+
cpumask_t name##_cpus __read_mostly; \
7578
DEFINE_PER_CPU(arch_spinlock_t, name##_lock); \
7679
DEFINE_LGLOCK_LOCKDEP(name); \
7780
\
81+
static int \
82+
name##_lg_cpu_callback(struct notifier_block *nb, \
83+
unsigned long action, void *hcpu) \
84+
{ \
85+
switch (action & ~CPU_TASKS_FROZEN) { \
86+
case CPU_UP_PREPARE: \
87+
spin_lock(&name##_cpu_lock); \
88+
cpu_set((unsigned long)hcpu, name##_cpus); \
89+
spin_unlock(&name##_cpu_lock); \
90+
break; \
91+
case CPU_UP_CANCELED: case CPU_DEAD: \
92+
spin_lock(&name##_cpu_lock); \
93+
cpu_clear((unsigned long)hcpu, name##_cpus); \
94+
spin_unlock(&name##_cpu_lock); \
95+
} \
96+
return NOTIFY_OK; \
97+
} \
98+
static struct notifier_block name##_lg_cpu_notifier = { \
99+
.notifier_call = name##_lg_cpu_callback, \
100+
}; \
78101
void name##_lock_init(void) { \
79102
int i; \
80103
LOCKDEP_INIT_MAP(&name##_lock_dep_map, #name, &name##_lock_key, 0); \
@@ -83,6 +106,11 @@
83106
lock = &per_cpu(name##_lock, i); \
84107
*lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; \
85108
} \
109+
register_hotcpu_notifier(&name##_lg_cpu_notifier); \
110+
get_online_cpus(); \
111+
for_each_online_cpu(i) \
112+
cpu_set(i, name##_cpus); \
113+
put_online_cpus(); \
86114
} \
87115
EXPORT_SYMBOL(name##_lock_init); \
88116
\
@@ -124,9 +152,9 @@
124152
\
125153
void name##_global_lock_online(void) { \
126154
int i; \
127-
preempt_disable();\
155+
spin_lock(&name##_cpu_lock);\
128156
rwlock_acquire(&name##_lock_dep_map, 0, 0, _RET_IP_); \
129-
for_each_online_cpu(i) { \
157+
for_each_cpu(i, &name##_cpus) { \
130158
arch_spinlock_t *lock; \
131159
lock = &per_cpu(name##_lock, i); \
132160
arch_spin_lock(lock); \
@@ -137,12 +165,12 @@
137165
void name##_global_unlock_online(void) { \
138166
int i; \
139167
rwlock_release(&name##_lock_dep_map, 1, _RET_IP_); \
140-
for_each_online_cpu(i) { \
168+
for_each_cpu(i, &name##_cpus) { \
141169
arch_spinlock_t *lock; \
142170
lock = &per_cpu(name##_lock, i); \
143171
arch_spin_unlock(lock); \
144172
} \
145-
preempt_enable();\
173+
spin_unlock(&name##_cpu_lock);\
146174
} \
147175
EXPORT_SYMBOL(name##_global_unlock_online); \
148176
\

0 commit comments

Comments
 (0)