aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/padata.c
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 /kernel/padata.c
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>
Diffstat (limited to 'kernel/padata.c')
-rw-r--r--kernel/padata.c25
1 files changed, 18 insertions, 7 deletions
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);