diff options
| author | Mathias Krause <minipli@googlemail.com> | 2017-09-08 20:57:11 +0200 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2020-05-27 16:42:50 +0200 |
| commit | 0a9ac7ce3927b135390faaa27398d5932a70c3b7 (patch) | |
| tree | a8a5fe2f605812d941ade2990fd0331d4950efff /kernel | |
| parent | a68ca9a23e83c3e1003e091d1ce802b821efc5db (diff) | |
| download | linux-0a9ac7ce3927b135390faaa27398d5932a70c3b7.tar.gz linux-0a9ac7ce3927b135390faaa27398d5932a70c3b7.tar.bz2 linux-0a9ac7ce3927b135390faaa27398d5932a70c3b7.zip | |
padata: ensure padata_do_serial() runs on the correct CPU
commit 350ef88e7e922354f82a931897ad4a4ce6c686ff upstream.
If the algorithm we're parallelizing is asynchronous we might change
CPUs between padata_do_parallel() and padata_do_serial(). However, we
don't expect this to happen as we need to enqueue the padata object into
the per-cpu reorder queue we took it from, i.e. the same-cpu's parallel
queue.
Ensure we're not switching CPUs for a given padata object by tracking
the CPU within the padata object. If the serial callback gets called on
the wrong CPU, defer invoking padata_reorder() via a kernel worker on
the CPU we're expected to run on.
Signed-off-by: Mathias Krause <minipli@googlemail.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Cc: Ben Hutchings <ben@decadent.org.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/padata.c | 20 |
1 files changed, 19 insertions, 1 deletions
diff --git a/kernel/padata.c b/kernel/padata.c index 9b4ee749dd1d..40a0ebb8ea51 100644 --- a/kernel/padata.c +++ b/kernel/padata.c @@ -133,6 +133,7 @@ int padata_do_parallel(struct padata_instance *pinst, padata->cb_cpu = cb_cpu; target_cpu = padata_cpu_hash(pd); + padata->cpu = target_cpu; queue = per_cpu_ptr(pd->pqueue, target_cpu); spin_lock(&queue->parallel.lock); @@ -376,10 +377,21 @@ void padata_do_serial(struct padata_priv *padata) int cpu; struct padata_parallel_queue *pqueue; struct parallel_data *pd; + int reorder_via_wq = 0; pd = padata->pd; cpu = get_cpu(); + + /* We need to run on the same CPU padata_do_parallel(.., padata, ..) + * was called on -- or, at least, enqueue the padata object into the + * correct per-cpu queue. + */ + if (cpu != padata->cpu) { + reorder_via_wq = 1; + cpu = padata->cpu; + } + pqueue = per_cpu_ptr(pd->pqueue, cpu); spin_lock(&pqueue->reorder.lock); @@ -396,7 +408,13 @@ void padata_do_serial(struct padata_priv *padata) put_cpu(); - padata_reorder(pd); + /* If we're running on the wrong CPU, call padata_reorder() via a + * kernel worker. + */ + if (reorder_via_wq) + queue_work_on(cpu, pd->pinst->wq, &pqueue->reorder_work); + else + padata_reorder(pd); } EXPORT_SYMBOL(padata_do_serial); |
