diff options
-rw-r--r-- | include/linux/perf_counter.h | 1 | ||||
-rw-r--r-- | kernel/perf_counter.c | 14 |
2 files changed, 13 insertions, 2 deletions
diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h index 2b5e66d5ebdf..48212c15b7d6 100644 --- a/include/linux/perf_counter.h +++ b/include/linux/perf_counter.h | |||
@@ -246,6 +246,7 @@ struct file; | |||
246 | struct perf_mmap_data { | 246 | struct perf_mmap_data { |
247 | struct rcu_head rcu_head; | 247 | struct rcu_head rcu_head; |
248 | int nr_pages; | 248 | int nr_pages; |
249 | atomic_t wakeup; | ||
249 | atomic_t head; | 250 | atomic_t head; |
250 | struct perf_counter_mmap_page *user_page; | 251 | struct perf_counter_mmap_page *user_page; |
251 | void *data_pages[0]; | 252 | void *data_pages[0]; |
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index 0dfe91094fd1..affe227d56a0 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c | |||
@@ -1161,7 +1161,16 @@ perf_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) | |||
1161 | static unsigned int perf_poll(struct file *file, poll_table *wait) | 1161 | static unsigned int perf_poll(struct file *file, poll_table *wait) |
1162 | { | 1162 | { |
1163 | struct perf_counter *counter = file->private_data; | 1163 | struct perf_counter *counter = file->private_data; |
1164 | unsigned int events = POLLIN; | 1164 | struct perf_mmap_data *data; |
1165 | unsigned int events; | ||
1166 | |||
1167 | rcu_read_lock(); | ||
1168 | data = rcu_dereference(counter->data); | ||
1169 | if (data) | ||
1170 | events = atomic_xchg(&data->wakeup, 0); | ||
1171 | else | ||
1172 | events = POLL_HUP; | ||
1173 | rcu_read_unlock(); | ||
1165 | 1174 | ||
1166 | poll_wait(file, &counter->waitq, wait); | 1175 | poll_wait(file, &counter->waitq, wait); |
1167 | 1176 | ||
@@ -1425,7 +1434,7 @@ static int perf_output_write(struct perf_counter *counter, int nmi, | |||
1425 | 1434 | ||
1426 | do { | 1435 | do { |
1427 | offset = head = atomic_read(&data->head); | 1436 | offset = head = atomic_read(&data->head); |
1428 | head += sizeof(u64); | 1437 | head += size; |
1429 | } while (atomic_cmpxchg(&data->head, offset, head) != offset); | 1438 | } while (atomic_cmpxchg(&data->head, offset, head) != offset); |
1430 | 1439 | ||
1431 | wakeup = (offset >> PAGE_SHIFT) != (head >> PAGE_SHIFT); | 1440 | wakeup = (offset >> PAGE_SHIFT) != (head >> PAGE_SHIFT); |
@@ -1446,6 +1455,7 @@ static int perf_output_write(struct perf_counter *counter, int nmi, | |||
1446 | * generate a poll() wakeup for every page boundary crossed | 1455 | * generate a poll() wakeup for every page boundary crossed |
1447 | */ | 1456 | */ |
1448 | if (wakeup) { | 1457 | if (wakeup) { |
1458 | atomic_xchg(&data->wakeup, POLL_IN); | ||
1449 | __perf_counter_update_userpage(counter, data); | 1459 | __perf_counter_update_userpage(counter, data); |
1450 | if (nmi) { | 1460 | if (nmi) { |
1451 | counter->wakeup_pending = 1; | 1461 | counter->wakeup_pending = 1; |