aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/oprofile
diff options
context:
space:
mode:
authorRobert Richter <robert.richter@amd.com>2009-10-08 21:17:44 -0400
committerRobert Richter <robert.richter@amd.com>2009-10-09 15:32:05 -0400
commitc0868934e536e0ff508f2d359d006b25abc4970d (patch)
tree54932dfb00ee6731a1d3421eba1a87ed025f72dd /drivers/oprofile
parent066b3aa8454bee3cdc665d86b5de812d8d0513b3 (diff)
oprofile: warn on freeing event buffer too early
A race shouldn't happen since all workqueues or handlers are canceled or flushed before the event buffer is freed. A warning is triggered now if the buffer is freed too early. Also, this patch adds some comments about event buffer protection, reworks some code and adds code to clear buffer_pos during alloc and free of the event buffer. Cc: David Rientjes <rientjes@google.com> Cc: Stephane Eranian <eranian@google.com> Signed-off-by: Robert Richter <robert.richter@amd.com>
Diffstat (limited to 'drivers/oprofile')
-rw-r--r--drivers/oprofile/event_buffer.c25
1 files changed, 15 insertions, 10 deletions
diff --git a/drivers/oprofile/event_buffer.c b/drivers/oprofile/event_buffer.c
index c38adb389064..5df60a6b6776 100644
--- a/drivers/oprofile/event_buffer.c
+++ b/drivers/oprofile/event_buffer.c
@@ -35,17 +35,22 @@ static size_t buffer_pos;
35/* atomic_t because wait_event checks it outside of buffer_mutex */ 35/* atomic_t because wait_event checks it outside of buffer_mutex */
36static atomic_t buffer_ready = ATOMIC_INIT(0); 36static atomic_t buffer_ready = ATOMIC_INIT(0);
37 37
38/* Add an entry to the event buffer. When we 38/*
39 * get near to the end we wake up the process 39 * Add an entry to the event buffer. When we get near to the end we
40 * sleeping on the read() of the file. 40 * wake up the process sleeping on the read() of the file. To protect
41 * the event_buffer this function may only be called when buffer_mutex
42 * is set.
41 */ 43 */
42void add_event_entry(unsigned long value) 44void add_event_entry(unsigned long value)
43{ 45{
44 /* 46 /*
45 * catch potential error 47 * This shouldn't happen since all workqueues or handlers are
48 * canceled or flushed before the event buffer is freed.
46 */ 49 */
47 if (!event_buffer) 50 if (!event_buffer) {
51 WARN_ON_ONCE(1);
48 return; 52 return;
53 }
49 54
50 if (buffer_pos == buffer_size) { 55 if (buffer_pos == buffer_size) {
51 atomic_inc(&oprofile_stats.event_lost_overflow); 56 atomic_inc(&oprofile_stats.event_lost_overflow);
@@ -75,7 +80,6 @@ void wake_up_buffer_waiter(void)
75 80
76int alloc_event_buffer(void) 81int alloc_event_buffer(void)
77{ 82{
78 int err = -ENOMEM;
79 unsigned long flags; 83 unsigned long flags;
80 84
81 spin_lock_irqsave(&oprofilefs_lock, flags); 85 spin_lock_irqsave(&oprofilefs_lock, flags);
@@ -86,13 +90,12 @@ int alloc_event_buffer(void)
86 if (buffer_watershed >= buffer_size) 90 if (buffer_watershed >= buffer_size)
87 return -EINVAL; 91 return -EINVAL;
88 92
93 buffer_pos = 0;
89 event_buffer = vmalloc(sizeof(unsigned long) * buffer_size); 94 event_buffer = vmalloc(sizeof(unsigned long) * buffer_size);
90 if (!event_buffer) 95 if (!event_buffer)
91 goto out; 96 return -ENOMEM;
92 97
93 err = 0; 98 return 0;
94out:
95 return err;
96} 99}
97 100
98 101
@@ -100,6 +103,7 @@ void free_event_buffer(void)
100{ 103{
101 mutex_lock(&buffer_mutex); 104 mutex_lock(&buffer_mutex);
102 vfree(event_buffer); 105 vfree(event_buffer);
106 buffer_pos = 0;
103 event_buffer = NULL; 107 event_buffer = NULL;
104 mutex_unlock(&buffer_mutex); 108 mutex_unlock(&buffer_mutex);
105} 109}
@@ -174,6 +178,7 @@ static ssize_t event_buffer_read(struct file *file, char __user *buf,
174 178
175 mutex_lock(&buffer_mutex); 179 mutex_lock(&buffer_mutex);
176 180
181 /* May happen if the buffer is freed during pending reads. */
177 if (!event_buffer) { 182 if (!event_buffer) {
178 retval = -EINTR; 183 retval = -EINTR;
179 goto out; 184 goto out;