Skip to content

Commit b21172c

Browse files
committed
Merge branch 'ras-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull RAS fix from Ingo Molnar: "Fix an RCU warning that triggers when /dev/mcelog is used" * 'ras-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/mcelog: Get rid of RCU remnants
2 parents 9d9cc4a + 7298f08 commit b21172c

File tree

1 file changed

+27
-94
lines changed

1 file changed

+27
-94
lines changed

arch/x86/kernel/cpu/mcheck/dev-mcelog.c

Lines changed: 27 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,6 @@ static DEFINE_MUTEX(mce_chrdev_read_mutex);
2424
static char mce_helper[128];
2525
static char *mce_helper_argv[2] = { mce_helper, NULL };
2626

27-
#define mce_log_get_idx_check(p) \
28-
({ \
29-
RCU_LOCKDEP_WARN(!rcu_read_lock_sched_held() && \
30-
!lockdep_is_held(&mce_chrdev_read_mutex), \
31-
"suspicious mce_log_get_idx_check() usage"); \
32-
smp_load_acquire(&(p)); \
33-
})
34-
3527
/*
3628
* Lockless MCE logging infrastructure.
3729
* This avoids deadlocks on printk locks without having to break locks. Also
@@ -53,43 +45,32 @@ static int dev_mce_log(struct notifier_block *nb, unsigned long val,
5345
void *data)
5446
{
5547
struct mce *mce = (struct mce *)data;
56-
unsigned int next, entry;
57-
58-
wmb();
59-
for (;;) {
60-
entry = mce_log_get_idx_check(mcelog.next);
61-
for (;;) {
62-
63-
/*
64-
* When the buffer fills up discard new entries.
65-
* Assume that the earlier errors are the more
66-
* interesting ones:
67-
*/
68-
if (entry >= MCE_LOG_LEN) {
69-
set_bit(MCE_OVERFLOW,
70-
(unsigned long *)&mcelog.flags);
71-
return NOTIFY_OK;
72-
}
73-
/* Old left over entry. Skip: */
74-
if (mcelog.entry[entry].finished) {
75-
entry++;
76-
continue;
77-
}
78-
break;
79-
}
80-
smp_rmb();
81-
next = entry + 1;
82-
if (cmpxchg(&mcelog.next, entry, next) == entry)
83-
break;
48+
unsigned int entry;
49+
50+
mutex_lock(&mce_chrdev_read_mutex);
51+
52+
entry = mcelog.next;
53+
54+
/*
55+
* When the buffer fills up discard new entries. Assume that the
56+
* earlier errors are the more interesting ones:
57+
*/
58+
if (entry >= MCE_LOG_LEN) {
59+
set_bit(MCE_OVERFLOW, (unsigned long *)&mcelog.flags);
60+
goto unlock;
8461
}
62+
63+
mcelog.next = entry + 1;
64+
8565
memcpy(mcelog.entry + entry, mce, sizeof(struct mce));
86-
wmb();
8766
mcelog.entry[entry].finished = 1;
88-
wmb();
8967

9068
/* wake processes polling /dev/mcelog */
9169
wake_up_interruptible(&mce_chrdev_wait);
9270

71+
unlock:
72+
mutex_unlock(&mce_chrdev_read_mutex);
73+
9374
return NOTIFY_OK;
9475
}
9576

@@ -177,13 +158,6 @@ static int mce_chrdev_release(struct inode *inode, struct file *file)
177158
return 0;
178159
}
179160

180-
static void collect_tscs(void *data)
181-
{
182-
unsigned long *cpu_tsc = (unsigned long *)data;
183-
184-
cpu_tsc[smp_processor_id()] = rdtsc();
185-
}
186-
187161
static int mce_apei_read_done;
188162

189163
/* Collect MCE record of previous boot in persistent storage via APEI ERST. */
@@ -231,14 +205,9 @@ static ssize_t mce_chrdev_read(struct file *filp, char __user *ubuf,
231205
size_t usize, loff_t *off)
232206
{
233207
char __user *buf = ubuf;
234-
unsigned long *cpu_tsc;
235-
unsigned prev, next;
208+
unsigned next;
236209
int i, err;
237210

238-
cpu_tsc = kmalloc(nr_cpu_ids * sizeof(long), GFP_KERNEL);
239-
if (!cpu_tsc)
240-
return -ENOMEM;
241-
242211
mutex_lock(&mce_chrdev_read_mutex);
243212

244213
if (!mce_apei_read_done) {
@@ -247,65 +216,29 @@ static ssize_t mce_chrdev_read(struct file *filp, char __user *ubuf,
247216
goto out;
248217
}
249218

250-
next = mce_log_get_idx_check(mcelog.next);
251-
252219
/* Only supports full reads right now */
253220
err = -EINVAL;
254221
if (*off != 0 || usize < MCE_LOG_LEN*sizeof(struct mce))
255222
goto out;
256223

224+
next = mcelog.next;
257225
err = 0;
258-
prev = 0;
259-
do {
260-
for (i = prev; i < next; i++) {
261-
unsigned long start = jiffies;
262-
struct mce *m = &mcelog.entry[i];
263-
264-
while (!m->finished) {
265-
if (time_after_eq(jiffies, start + 2)) {
266-
memset(m, 0, sizeof(*m));
267-
goto timeout;
268-
}
269-
cpu_relax();
270-
}
271-
smp_rmb();
272-
err |= copy_to_user(buf, m, sizeof(*m));
273-
buf += sizeof(*m);
274-
timeout:
275-
;
276-
}
277-
278-
memset(mcelog.entry + prev, 0,
279-
(next - prev) * sizeof(struct mce));
280-
prev = next;
281-
next = cmpxchg(&mcelog.next, prev, 0);
282-
} while (next != prev);
283-
284-
synchronize_sched();
285226

286-
/*
287-
* Collect entries that were still getting written before the
288-
* synchronize.
289-
*/
290-
on_each_cpu(collect_tscs, cpu_tsc, 1);
291-
292-
for (i = next; i < MCE_LOG_LEN; i++) {
227+
for (i = 0; i < next; i++) {
293228
struct mce *m = &mcelog.entry[i];
294229

295-
if (m->finished && m->tsc < cpu_tsc[m->cpu]) {
296-
err |= copy_to_user(buf, m, sizeof(*m));
297-
smp_rmb();
298-
buf += sizeof(*m);
299-
memset(m, 0, sizeof(*m));
300-
}
230+
err |= copy_to_user(buf, m, sizeof(*m));
231+
buf += sizeof(*m);
301232
}
302233

234+
memset(mcelog.entry, 0, next * sizeof(struct mce));
235+
mcelog.next = 0;
236+
303237
if (err)
304238
err = -EFAULT;
305239

306240
out:
307241
mutex_unlock(&mce_chrdev_read_mutex);
308-
kfree(cpu_tsc);
309242

310243
return err ? err : buf - ubuf;
311244
}

0 commit comments

Comments
 (0)