summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMathias Krause <minipli@googlemail.com>2017-09-08 14:57:10 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2017-10-07 00:10:31 -0400
commitcf5868c8a22dc2854b96e9569064bb92365549ca (patch)
treefb170091add3a262bd984c4ee092656a9bbc0326
parent1bd845bcb41d5b7f83745e0cb99273eb376f2ec5 (diff)
padata: ensure the reorder timer callback runs on the correct CPU
The reorder timer function runs on the CPU where the timer interrupt was handled which is not necessarily one of the CPUs of the 'pcpu' CPU mask set. Ensure the padata_reorder() callback runs on the correct CPU, which is one in the 'pcpu' CPU mask set and, preferrably, the next expected one. Do so by comparing the current CPU with the expected target CPU. If they match, call padata_reorder() right away. If they differ, schedule a work item on the target CPU that does the padata_reorder() call for us. Signed-off-by: Mathias Krause <minipli@googlemail.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r--include/linux/padata.h2
-rw-r--r--kernel/padata.c43
2 files changed, 44 insertions, 1 deletions
diff --git a/include/linux/padata.h b/include/linux/padata.h
index 2f9c1f93b1ce..5c0175bbc179 100644
--- a/include/linux/padata.h
+++ b/include/linux/padata.h
@@ -85,6 +85,7 @@ struct padata_serial_queue {
85 * @swork: work struct for serialization. 85 * @swork: work struct for serialization.
86 * @pd: Backpointer to the internal control structure. 86 * @pd: Backpointer to the internal control structure.
87 * @work: work struct for parallelization. 87 * @work: work struct for parallelization.
88 * @reorder_work: work struct for reordering.
88 * @num_obj: Number of objects that are processed by this cpu. 89 * @num_obj: Number of objects that are processed by this cpu.
89 * @cpu_index: Index of the cpu. 90 * @cpu_index: Index of the cpu.
90 */ 91 */
@@ -93,6 +94,7 @@ struct padata_parallel_queue {
93 struct padata_list reorder; 94 struct padata_list reorder;
94 struct parallel_data *pd; 95 struct parallel_data *pd;
95 struct work_struct work; 96 struct work_struct work;
97 struct work_struct reorder_work;
96 atomic_t num_obj; 98 atomic_t num_obj;
97 int cpu_index; 99 int cpu_index;
98}; 100};
diff --git a/kernel/padata.c b/kernel/padata.c
index 1b9b4bac4a9b..b4066147bce4 100644
--- a/kernel/padata.c
+++ b/kernel/padata.c
@@ -275,11 +275,51 @@ static void padata_reorder(struct parallel_data *pd)
275 return; 275 return;
276} 276}
277 277
278static void invoke_padata_reorder(struct work_struct *work)
279{
280 struct padata_parallel_queue *pqueue;
281 struct parallel_data *pd;
282
283 local_bh_disable();
284 pqueue = container_of(work, struct padata_parallel_queue, reorder_work);
285 pd = pqueue->pd;
286 padata_reorder(pd);
287 local_bh_enable();
288}
289
278static void padata_reorder_timer(unsigned long arg) 290static void padata_reorder_timer(unsigned long arg)
279{ 291{
280 struct parallel_data *pd = (struct parallel_data *)arg; 292 struct parallel_data *pd = (struct parallel_data *)arg;
293 unsigned int weight;
294 int target_cpu, cpu;
281 295
282 padata_reorder(pd); 296 cpu = get_cpu();
297
298 /* We don't lock pd here to not interfere with parallel processing
299 * padata_reorder() calls on other CPUs. We just need any CPU out of
300 * the cpumask.pcpu set. It would be nice if it's the right one but
301 * it doesn't matter if we're off to the next one by using an outdated
302 * pd->processed value.
303 */
304 weight = cpumask_weight(pd->cpumask.pcpu);
305 target_cpu = padata_index_to_cpu(pd, pd->processed % weight);
306
307 /* ensure to call the reorder callback on the correct CPU */
308 if (cpu != target_cpu) {
309 struct padata_parallel_queue *pqueue;
310 struct padata_instance *pinst;
311
312 /* The timer function is serialized wrt itself -- no locking
313 * needed.
314 */
315 pinst = pd->pinst;
316 pqueue = per_cpu_ptr(pd->pqueue, target_cpu);
317 queue_work_on(target_cpu, pinst->wq, &pqueue->reorder_work);
318 } else {
319 padata_reorder(pd);
320 }
321
322 put_cpu();
283} 323}
284 324
285static void padata_serial_worker(struct work_struct *serial_work) 325static void padata_serial_worker(struct work_struct *serial_work)
@@ -399,6 +439,7 @@ static void padata_init_pqueues(struct parallel_data *pd)
399 __padata_list_init(&pqueue->reorder); 439 __padata_list_init(&pqueue->reorder);
400 __padata_list_init(&pqueue->parallel); 440 __padata_list_init(&pqueue->parallel);
401 INIT_WORK(&pqueue->work, padata_parallel_worker); 441 INIT_WORK(&pqueue->work, padata_parallel_worker);
442 INIT_WORK(&pqueue->reorder_work, invoke_padata_reorder);
402 atomic_set(&pqueue->num_obj, 0); 443 atomic_set(&pqueue->num_obj, 0);
403 } 444 }
404} 445}