diff options
author | Robert Richter <robert.richter@amd.com> | 2009-10-08 21:17:44 -0400 |
---|---|---|
committer | Robert Richter <robert.richter@amd.com> | 2009-10-09 15:32:05 -0400 |
commit | c0868934e536e0ff508f2d359d006b25abc4970d (patch) | |
tree | 54932dfb00ee6731a1d3421eba1a87ed025f72dd /drivers/oprofile | |
parent | 066b3aa8454bee3cdc665d86b5de812d8d0513b3 (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.c | 25 |
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 */ |
36 | static atomic_t buffer_ready = ATOMIC_INIT(0); | 36 | static 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 | */ |
42 | void add_event_entry(unsigned long value) | 44 | void 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 | ||
76 | int alloc_event_buffer(void) | 81 | int 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; |
94 | out: | ||
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; |