diff options
Diffstat (limited to 'features/rt/crypto-cryptd-add-a-lock-instead-preempt_disable-loc.patch')
-rw-r--r-- | features/rt/crypto-cryptd-add-a-lock-instead-preempt_disable-loc.patch | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/features/rt/crypto-cryptd-add-a-lock-instead-preempt_disable-loc.patch b/features/rt/crypto-cryptd-add-a-lock-instead-preempt_disable-loc.patch new file mode 100644 index 00000000..68cc1e5a --- /dev/null +++ b/features/rt/crypto-cryptd-add-a-lock-instead-preempt_disable-loc.patch @@ -0,0 +1,84 @@ +From bdce470739405260aab0f96686cd9b15cecde177 Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Date: Thu, 26 Jul 2018 18:52:00 +0200 +Subject: [PATCH 146/191] crypto: cryptd - add a lock instead + preempt_disable/local_bh_disable + +cryptd has a per-CPU lock which protected with local_bh_disable() and +preempt_disable(). +Add an explicit spin_lock to make the locking context more obvious and +visible to lockdep. Since it is a per-CPU lock, there should be no lock +contention on the actual spinlock. +There is a small race-window where we could be migrated to another CPU +after the cpu_queue has been obtain. This is not a problem because the +actual ressource is protected by the spinlock. + +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + crypto/cryptd.c | 19 +++++++++---------- + 1 file changed, 9 insertions(+), 10 deletions(-) + +diff --git a/crypto/cryptd.c b/crypto/cryptd.c +index a1bea0f4baa8..5f8ca8c1f59c 100644 +--- a/crypto/cryptd.c ++++ b/crypto/cryptd.c +@@ -36,6 +36,7 @@ static struct workqueue_struct *cryptd_wq; + struct cryptd_cpu_queue { + struct crypto_queue queue; + struct work_struct work; ++ spinlock_t qlock; + }; + + struct cryptd_queue { +@@ -105,6 +106,7 @@ static int cryptd_init_queue(struct cryptd_queue *queue, + cpu_queue = per_cpu_ptr(queue->cpu_queue, cpu); + crypto_init_queue(&cpu_queue->queue, max_cpu_qlen); + INIT_WORK(&cpu_queue->work, cryptd_queue_worker); ++ spin_lock_init(&cpu_queue->qlock); + } + pr_info("cryptd: max_cpu_qlen set to %d\n", max_cpu_qlen); + return 0; +@@ -129,8 +131,10 @@ static int cryptd_enqueue_request(struct cryptd_queue *queue, + struct cryptd_cpu_queue *cpu_queue; + refcount_t *refcnt; + +- cpu = get_cpu(); +- cpu_queue = this_cpu_ptr(queue->cpu_queue); ++ cpu_queue = raw_cpu_ptr(queue->cpu_queue); ++ spin_lock_bh(&cpu_queue->qlock); ++ cpu = smp_processor_id(); ++ + err = crypto_enqueue_request(&cpu_queue->queue, request); + + refcnt = crypto_tfm_ctx(request->tfm); +@@ -146,7 +150,7 @@ static int cryptd_enqueue_request(struct cryptd_queue *queue, + refcount_inc(refcnt); + + out_put_cpu: +- put_cpu(); ++ spin_unlock_bh(&cpu_queue->qlock); + + return err; + } +@@ -162,16 +166,11 @@ static void cryptd_queue_worker(struct work_struct *work) + cpu_queue = container_of(work, struct cryptd_cpu_queue, work); + /* + * Only handle one request at a time to avoid hogging crypto workqueue. +- * preempt_disable/enable is used to prevent being preempted by +- * cryptd_enqueue_request(). local_bh_disable/enable is used to prevent +- * cryptd_enqueue_request() being accessed from software interrupts. + */ +- local_bh_disable(); +- preempt_disable(); ++ spin_lock_bh(&cpu_queue->qlock); + backlog = crypto_get_backlog(&cpu_queue->queue); + req = crypto_dequeue_request(&cpu_queue->queue); +- preempt_enable(); +- local_bh_enable(); ++ spin_unlock_bh(&cpu_queue->qlock); + + if (!req) + return; +-- +2.19.1 + |