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:40:23 +0200 |
commit | 3c74e59f30ccfb4937a9814631cc828f64427de3 (patch) | |
tree | adbc1afea65fa3d8c9cdf228d1118015d42a6a98 /kernel | |
parent | f4fb6f1523d43cd2b56f99559ba4b86b83901a25 (diff) | |
download | linux-stable-3c74e59f30ccfb4937a9814631cc828f64427de3.tar.gz linux-stable-3c74e59f30ccfb4937a9814631cc828f64427de3.tar.bz2 linux-stable-3c74e59f30ccfb4937a9814631cc828f64427de3.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 7f4a76e5904b..8aef48c3267b 100644 --- a/kernel/padata.c +++ b/kernel/padata.c @@ -132,6 +132,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); @@ -375,10 +376,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); @@ -395,7 +407,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); |