aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteffen Klassert <steffen.klassert@secunet.com>2010-05-18 23:43:14 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2010-05-18 23:43:14 -0400
commitd46a5ac7a7e2045e33c6ad6ffb8cf18a7e86a15a (patch)
tree2ccfba3ee24ed28e80ae3e3be330a7b44f77dbcf
parent18eb8ea6ee4cc9ed39b45f95b734f523bcfb586b (diff)
padata: Use a timer to handle remaining objects in the reorder queues
padata_get_next needs to check whether the next object that need serialization must be parallel processed by the local cpu. This check was wrong implemented and returned always true, so the try_again loop in padata_reorder was never taken. This can lead to object leaks in some rare cases due to a race that appears with the trylock in padata_reorder. The try_again loop was not a good idea after all, because a cpu could take that loop frequently, so we handle this with a timer instead. This patch adds a timer to handle the race that appears with the trylock. If cpu1 queues an object to the reorder queue while cpu2 holds the pd->lock but left the while loop in padata_reorder already, cpu2 can't care for this object and cpu1 exits because it can't get the lock. Usually the next cpu that takes the lock cares for this object too. We need the timer just if this object was the last one that arrives to the reorder queues. The timer function sends it out in this case. Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r--include/linux/padata.h2
-rw-r--r--kernel/padata.c25
2 files changed, 20 insertions, 7 deletions
diff --git a/include/linux/padata.h b/include/linux/padata.h
index 51611da9c498..64836a63bd17 100644
--- a/include/linux/padata.h
+++ b/include/linux/padata.h
@@ -24,6 +24,7 @@
24#include <linux/workqueue.h> 24#include <linux/workqueue.h>
25#include <linux/spinlock.h> 25#include <linux/spinlock.h>
26#include <linux/list.h> 26#include <linux/list.h>
27#include <linux/timer.h>
27 28
28struct padata_priv { 29struct padata_priv {
29 struct list_head list; 30 struct list_head list;
@@ -60,6 +61,7 @@ struct parallel_data {
60 unsigned int max_seq_nr; 61 unsigned int max_seq_nr;
61 cpumask_var_t cpumask; 62 cpumask_var_t cpumask;
62 spinlock_t lock; 63 spinlock_t lock;
64 struct timer_list timer;
63}; 65};
64 66
65struct padata_instance { 67struct padata_instance {
diff --git a/kernel/padata.c b/kernel/padata.c
index 82958e01564b..6d7ea481b716 100644
--- a/kernel/padata.c
+++ b/kernel/padata.c
@@ -231,7 +231,8 @@ static struct padata_priv *padata_get_next(struct parallel_data *pd)
231 goto out; 231 goto out;
232 } 232 }
233 233
234 if (next_nr % num_cpus == next_queue->cpu_index) { 234 queue = per_cpu_ptr(pd->queue, smp_processor_id());
235 if (queue->cpu_index == next_queue->cpu_index) {
235 padata = ERR_PTR(-ENODATA); 236 padata = ERR_PTR(-ENODATA);
236 goto out; 237 goto out;
237 } 238 }
@@ -247,9 +248,8 @@ static void padata_reorder(struct parallel_data *pd)
247 struct padata_queue *queue; 248 struct padata_queue *queue;
248 struct padata_instance *pinst = pd->pinst; 249 struct padata_instance *pinst = pd->pinst;
249 250
250try_again:
251 if (!spin_trylock_bh(&pd->lock)) 251 if (!spin_trylock_bh(&pd->lock))
252 goto out; 252 return;
253 253
254 while (1) { 254 while (1) {
255 padata = padata_get_next(pd); 255 padata = padata_get_next(pd);
@@ -258,8 +258,9 @@ try_again:
258 break; 258 break;
259 259
260 if (PTR_ERR(padata) == -ENODATA) { 260 if (PTR_ERR(padata) == -ENODATA) {
261 del_timer(&pd->timer);
261 spin_unlock_bh(&pd->lock); 262 spin_unlock_bh(&pd->lock);
262 goto out; 263 return;
263 } 264 }
264 265
265 queue = per_cpu_ptr(pd->queue, padata->cb_cpu); 266 queue = per_cpu_ptr(pd->queue, padata->cb_cpu);
@@ -273,13 +274,22 @@ try_again:
273 274
274 spin_unlock_bh(&pd->lock); 275 spin_unlock_bh(&pd->lock);
275 276
276 if (atomic_read(&pd->reorder_objects)) 277 if (atomic_read(&pd->reorder_objects)
277 goto try_again; 278 && !(pinst->flags & PADATA_RESET))
279 mod_timer(&pd->timer, jiffies + HZ);
280 else
281 del_timer(&pd->timer);
278 282
279out:
280 return; 283 return;
281} 284}
282 285
286static void padata_reorder_timer(unsigned long arg)
287{
288 struct parallel_data *pd = (struct parallel_data *)arg;
289
290 padata_reorder(pd);
291}
292
283static void padata_serial_worker(struct work_struct *work) 293static void padata_serial_worker(struct work_struct *work)
284{ 294{
285 struct padata_queue *queue; 295 struct padata_queue *queue;
@@ -383,6 +393,7 @@ static struct parallel_data *padata_alloc_pd(struct padata_instance *pinst,
383 num_cpus = cpumask_weight(pd->cpumask); 393 num_cpus = cpumask_weight(pd->cpumask);
384 pd->max_seq_nr = (MAX_SEQ_NR / num_cpus) * num_cpus - 1; 394 pd->max_seq_nr = (MAX_SEQ_NR / num_cpus) * num_cpus - 1;
385 395
396 setup_timer(&pd->timer, padata_reorder_timer, (unsigned long)pd);
386 atomic_set(&pd->seq_nr, -1); 397 atomic_set(&pd->seq_nr, -1);
387 atomic_set(&pd->reorder_objects, 0); 398 atomic_set(&pd->reorder_objects, 0);
388 atomic_set(&pd->refcnt, 0); 399 atomic_set(&pd->refcnt, 0);