Oliver Neukum de7401
From cf5868c8a22dc2854b96e9569064bb92365549ca Mon Sep 17 00:00:00 2001
Oliver Neukum de7401
From: Mathias Krause <minipli@googlemail.com>
Oliver Neukum de7401
Date: Fri, 8 Sep 2017 20:57:10 +0200
Oliver Neukum de7401
Subject: [PATCH] padata: ensure the reorder timer callback runs on the correct
Oliver Neukum de7401
 CPU
Oliver Neukum de7401
Git-commit: cf5868c8a22dc2854b96e9569064bb92365549ca
Oliver Neukum de7401
References: git-fixes
Oliver Neukum de7401
Patch-mainline: v4.15-rc1
Oliver Neukum de7401
Oliver Neukum de7401
The reorder timer function runs on the CPU where the timer interrupt was
Oliver Neukum de7401
handled which is not necessarily one of the CPUs of the 'pcpu' CPU mask
Oliver Neukum de7401
set.
Oliver Neukum de7401
Oliver Neukum de7401
Ensure the padata_reorder() callback runs on the correct CPU, which is
Oliver Neukum de7401
one in the 'pcpu' CPU mask set and, preferrably, the next expected one.
Oliver Neukum de7401
Do so by comparing the current CPU with the expected target CPU. If they
Oliver Neukum de7401
match, call padata_reorder() right away. If they differ, schedule a work
Oliver Neukum de7401
item on the target CPU that does the padata_reorder() call for us.
Oliver Neukum de7401
Oliver Neukum de7401
Signed-off-by: Mathias Krause <minipli@googlemail.com>
Oliver Neukum de7401
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Oliver Neukum de7401
Signed-off-by: Oliver Neukum <oneukum@suse.com>
Oliver Neukum de7401
---
Oliver Neukum de7401
 include/linux/padata.h |  2 ++
Oliver Neukum de7401
 kernel/padata.c        | 43 ++++++++++++++++++++++++++++++++++++++++++-
Oliver Neukum de7401
 2 files changed, 44 insertions(+), 1 deletion(-)
Oliver Neukum de7401
Oliver Neukum de7401
diff --git a/include/linux/padata.h b/include/linux/padata.h
Oliver Neukum de7401
index 2f9c1f93b1ce..5c0175bbc179 100644
Oliver Neukum de7401
--- a/include/linux/padata.h
Oliver Neukum de7401
+++ b/include/linux/padata.h
Oliver Neukum de7401
@@ -85,6 +85,7 @@ struct padata_serial_queue {
Oliver Neukum de7401
  * @swork: work struct for serialization.
Oliver Neukum de7401
  * @pd: Backpointer to the internal control structure.
Oliver Neukum de7401
  * @work: work struct for parallelization.
Oliver Neukum de7401
+ * @reorder_work: work struct for reordering.
Oliver Neukum de7401
  * @num_obj: Number of objects that are processed by this cpu.
Oliver Neukum de7401
  * @cpu_index: Index of the cpu.
Oliver Neukum de7401
  */
Oliver Neukum de7401
@@ -93,6 +94,7 @@ struct padata_parallel_queue {
Oliver Neukum de7401
        struct padata_list    reorder;
Oliver Neukum de7401
        struct parallel_data *pd;
Oliver Neukum de7401
        struct work_struct    work;
Oliver Neukum de7401
+       struct work_struct    reorder_work;
Oliver Neukum de7401
        atomic_t              num_obj;
Oliver Neukum de7401
        int                   cpu_index;
Oliver Neukum de7401
 };
Oliver Neukum de7401
diff --git a/kernel/padata.c b/kernel/padata.c
Oliver Neukum de7401
index 1b9b4bac4a9b..b4066147bce4 100644
Oliver Neukum de7401
--- a/kernel/padata.c
Oliver Neukum de7401
+++ b/kernel/padata.c
Oliver Neukum de7401
@@ -275,11 +275,51 @@ static void padata_reorder(struct parallel_data *pd)
Oliver Neukum de7401
 	return;
Oliver Neukum de7401
 }
Oliver Neukum de7401
 
Oliver Neukum de7401
+static void invoke_padata_reorder(struct work_struct *work)
Oliver Neukum de7401
+{
Oliver Neukum de7401
+	struct padata_parallel_queue *pqueue;
Oliver Neukum de7401
+	struct parallel_data *pd;
Oliver Neukum de7401
+
Oliver Neukum de7401
+	local_bh_disable();
Oliver Neukum de7401
+	pqueue = container_of(work, struct padata_parallel_queue, reorder_work);
Oliver Neukum de7401
+	pd = pqueue->pd;
Oliver Neukum de7401
+	padata_reorder(pd);
Oliver Neukum de7401
+	local_bh_enable();
Oliver Neukum de7401
+}
Oliver Neukum de7401
+
Oliver Neukum de7401
 static void padata_reorder_timer(unsigned long arg)
Oliver Neukum de7401
 {
Oliver Neukum de7401
 	struct parallel_data *pd = (struct parallel_data *)arg;
Oliver Neukum de7401
+	unsigned int weight;
Oliver Neukum de7401
+	int target_cpu, cpu;
Oliver Neukum de7401
 
Oliver Neukum de7401
-	padata_reorder(pd);
Oliver Neukum de7401
+	cpu = get_cpu();
Oliver Neukum de7401
+
Oliver Neukum de7401
+	/* We don't lock pd here to not interfere with parallel processing
Oliver Neukum de7401
+	 * padata_reorder() calls on other CPUs. We just need any CPU out of
Oliver Neukum de7401
+	 * the cpumask.pcpu set. It would be nice if it's the right one but
Oliver Neukum de7401
+	 * it doesn't matter if we're off to the next one by using an outdated
Oliver Neukum de7401
+	 * pd->processed value.
Oliver Neukum de7401
+	 */
Oliver Neukum de7401
+	weight = cpumask_weight(pd->cpumask.pcpu);
Oliver Neukum de7401
+	target_cpu = padata_index_to_cpu(pd, pd->processed % weight);
Oliver Neukum de7401
+
Oliver Neukum de7401
+	/* ensure to call the reorder callback on the correct CPU */
Oliver Neukum de7401
+	if (cpu != target_cpu) {
Oliver Neukum de7401
+		struct padata_parallel_queue *pqueue;
Oliver Neukum de7401
+		struct padata_instance *pinst;
Oliver Neukum de7401
+
Oliver Neukum de7401
+		/* The timer function is serialized wrt itself -- no locking
Oliver Neukum de7401
+		 * needed.
Oliver Neukum de7401
+		 */
Oliver Neukum de7401
+		pinst = pd->pinst;
Oliver Neukum de7401
+		pqueue = per_cpu_ptr(pd->pqueue, target_cpu);
Oliver Neukum de7401
+		queue_work_on(target_cpu, pinst->wq, &pqueue->reorder_work);
Oliver Neukum de7401
+	} else {
Oliver Neukum de7401
+		padata_reorder(pd);
Oliver Neukum de7401
+	}
Oliver Neukum de7401
+
Oliver Neukum de7401
+	put_cpu();
Oliver Neukum de7401
 }
Oliver Neukum de7401
 
Oliver Neukum de7401
 static void padata_serial_worker(struct work_struct *serial_work)
Oliver Neukum de7401
@@ -399,6 +439,7 @@ static void padata_init_pqueues(struct parallel_data *pd)
Oliver Neukum de7401
 		__padata_list_init(&pqueue->reorder);
Oliver Neukum de7401
 		__padata_list_init(&pqueue->parallel);
Oliver Neukum de7401
 		INIT_WORK(&pqueue->work, padata_parallel_worker);
Oliver Neukum de7401
+		INIT_WORK(&pqueue->reorder_work, invoke_padata_reorder);
Oliver Neukum de7401
 		atomic_set(&pqueue->num_obj, 0);
Oliver Neukum de7401
 	}
Oliver Neukum de7401
 }
Oliver Neukum de7401
-- 
Oliver Neukum de7401
2.16.4
Oliver Neukum de7401