diff options
author | Bjorn Steinbrink <B.Steinbrink@gmx.de> | 2007-06-01 03:47:15 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-06-01 11:18:30 -0400 |
commit | 9fcc15ec3c1c287a781a4620e52522b6186f26f6 (patch) | |
tree | 86a0214fc404c0ca6e0ca283c83f22bd15aa2eb4 /kernel | |
parent | c79d9c9e9ace5eeae54f484f62fbd86bf27a344a (diff) |
timer statistics: fix race
Fix two races in the timer stats lookup code. One by ensuring that the
initialization of a new entry is finished upon insertion of that entry.
The other by cleaning up the hash table when the entries array is cleared,
so that we don't have any "pre-inserted" entries.
Thanks to Eric Dumazet for reminding me of the memory barriers.
Signed-off-by: Bjorn Steinbrink <B.Steinbrink@gmx.de>
Signed-off-by: Ian Kumlien <pomac@vapor.com>
Acked-by: Ingo Molnar <mingo@elte.hu>
Cc: Eric Dumazet <dada1@cosmosbay.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/time/timer_stats.c | 37 |
1 files changed, 21 insertions, 16 deletions
diff --git a/kernel/time/timer_stats.c b/kernel/time/timer_stats.c index 868f1bceb07f..fa3d380ca8c0 100644 --- a/kernel/time/timer_stats.c +++ b/kernel/time/timer_stats.c | |||
@@ -117,21 +117,6 @@ static struct entry entries[MAX_ENTRIES]; | |||
117 | 117 | ||
118 | static atomic_t overflow_count; | 118 | static atomic_t overflow_count; |
119 | 119 | ||
120 | static void reset_entries(void) | ||
121 | { | ||
122 | nr_entries = 0; | ||
123 | memset(entries, 0, sizeof(entries)); | ||
124 | atomic_set(&overflow_count, 0); | ||
125 | } | ||
126 | |||
127 | static struct entry *alloc_entry(void) | ||
128 | { | ||
129 | if (nr_entries >= MAX_ENTRIES) | ||
130 | return NULL; | ||
131 | |||
132 | return entries + nr_entries++; | ||
133 | } | ||
134 | |||
135 | /* | 120 | /* |
136 | * The entries are in a hash-table, for fast lookup: | 121 | * The entries are in a hash-table, for fast lookup: |
137 | */ | 122 | */ |
@@ -149,6 +134,22 @@ static struct entry *alloc_entry(void) | |||
149 | 134 | ||
150 | static struct entry *tstat_hash_table[TSTAT_HASH_SIZE] __read_mostly; | 135 | static struct entry *tstat_hash_table[TSTAT_HASH_SIZE] __read_mostly; |
151 | 136 | ||
137 | static void reset_entries(void) | ||
138 | { | ||
139 | nr_entries = 0; | ||
140 | memset(entries, 0, sizeof(entries)); | ||
141 | memset(tstat_hash_table, 0, sizeof(tstat_hash_table)); | ||
142 | atomic_set(&overflow_count, 0); | ||
143 | } | ||
144 | |||
145 | static struct entry *alloc_entry(void) | ||
146 | { | ||
147 | if (nr_entries >= MAX_ENTRIES) | ||
148 | return NULL; | ||
149 | |||
150 | return entries + nr_entries++; | ||
151 | } | ||
152 | |||
152 | static int match_entries(struct entry *entry1, struct entry *entry2) | 153 | static int match_entries(struct entry *entry1, struct entry *entry2) |
153 | { | 154 | { |
154 | return entry1->timer == entry2->timer && | 155 | return entry1->timer == entry2->timer && |
@@ -202,12 +203,15 @@ static struct entry *tstat_lookup(struct entry *entry, char *comm) | |||
202 | if (curr) { | 203 | if (curr) { |
203 | *curr = *entry; | 204 | *curr = *entry; |
204 | curr->count = 0; | 205 | curr->count = 0; |
206 | curr->next = NULL; | ||
205 | memcpy(curr->comm, comm, TASK_COMM_LEN); | 207 | memcpy(curr->comm, comm, TASK_COMM_LEN); |
208 | |||
209 | smp_mb(); /* Ensure that curr is initialized before insert */ | ||
210 | |||
206 | if (prev) | 211 | if (prev) |
207 | prev->next = curr; | 212 | prev->next = curr; |
208 | else | 213 | else |
209 | *head = curr; | 214 | *head = curr; |
210 | curr->next = NULL; | ||
211 | } | 215 | } |
212 | out_unlock: | 216 | out_unlock: |
213 | spin_unlock(&table_lock); | 217 | spin_unlock(&table_lock); |
@@ -360,6 +364,7 @@ static ssize_t tstats_write(struct file *file, const char __user *buf, | |||
360 | if (!active) { | 364 | if (!active) { |
361 | reset_entries(); | 365 | reset_entries(); |
362 | time_start = ktime_get(); | 366 | time_start = ktime_get(); |
367 | smp_mb(); | ||
363 | active = 1; | 368 | active = 1; |
364 | } | 369 | } |
365 | break; | 370 | break; |