crypto: cryptd - serialize RT request enqueue/dequeue with a local lock
RFC PATCH 1/1 crypto: cryptd - serialize RT request enqueue/dequeue with a local lock
Note: patch is the result of code inspection...
cryptod disables preemption to provide request enqueue/dequeue exclusion, use a LOCAL_IRQ_LOCK to do the same for RT, keeping preemption enabled.
--- crypto/cryptd.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
crypto/cryptd.c +6 -4
@@ -31,10 +31,12 @@#include <linux/scatterlist.h> #include <linux/sched.h> #include <linux/slab.h> +#include <linux/locallock.h> static unsigned int cryptd_max_cpu_qlen =1000 ;module_param (cryptd_max_cpu_qlen, uint,0 );MODULE_PARM_DESC (cryptd_max_cpu_qlen,"Set cryptd Max queue depth" ); +static DEFINE_LOCAL_IRQ_LOCK (cryptod_request_lock);struct cryptd_cpu_queue {struct crypto_queue queue;
@@ -141,7 +143,7 @@ static int cryptd_enqueue_request(structstruct cryptd_cpu_queue *cpu_queue;atomic_t *refcnt; - cpu =get_cpu (); + cpu =local_lock_cpu (cryptod_request_lock); cpu_queue =this_cpu_ptr (queue->cpu_queue); err =crypto_enqueue_request (&cpu_queue->queue, request);
@@ -158,7 +160,7 @@ static int cryptd_enqueue_request(structatomic_inc (refcnt); out_put_cpu: -put_cpu (); +local_unlock_cpu (cryptod_request_lock);return err; }
@@ -179,10 +181,10 @@ static void cryptd_queue_worker(struct w* cryptd_enqueue_request() being accessed from software interrupts. */ local_bh_disable (); -preempt_disable (); +local_lock (cryptod_request_lock); backlog =crypto_get_backlog (&cpu_queue->queue); req =crypto_dequeue_request (&cpu_queue->queue); -preempt_enable (); +local_unlock (cryptod_request_lock);local_bh_enable ();if (!req)
Quoted 4 lines · Mike Galbraith
Note: patch is the result of code inspection...
cryptod disables preemption to provide request enqueue/dequeue exclusion, use a
LOCAL_IRQ_LOCKto do the same for RT, keeping preemption enabled.
What about this:
-------- >8
From: Sebastian Andrzej Siewior <[email protected]>
Date: Thu, 26 Jul 2018 18:52:00 +0200
Subject: [PATCH] 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.
--- crypto/cryptd.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-)
crypto/cryptd.c +9 -10
@@ -39,6 +39,7 @@ MODULE_PARM_DESC(cryptd_max_cpu_qlen, "Set cryptd Max queue depth");struct cryptd_cpu_queue {struct crypto_queue queue;struct work_struct work; +spinlock_t qlock; };struct cryptd_queue {
@@ -117,6 +118,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 ;
@@ -141,8 +143,10 @@ static int cryptd_enqueue_request(struct cryptd_queue *queue,struct cryptd_cpu_queue *cpu_queue;atomic_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);
@@ -158,7 +162,7 @@ static int cryptd_enqueue_request(struct cryptd_queue *queue,atomic_inc (refcnt); out_put_cpu: -put_cpu (); +spin_unlock_bh (&cpu_queue->qlock);return err; }
@@ -174,16 +178,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 ;
Signature · 1 line
2.18.0
Quoted 7 lines · Sebastian Andrzej Siewior
Quoted 4 lines · Mike Galbraith
Note: patch is the result of code inspection...
cryptod disables preemption to provide request enqueue/dequeue exclusion, use a
LOCAL_IRQ_LOCKto do the same for RT, keeping preemption enabled.What about this:
Looks fine to me, I'll ask my arm-thing box for its opinion.
Quoted 82 lines
-------- >8
From: Sebastian Andrzej Siewior <[email protected]>
Date: Thu, 26 Jul 2018 18:52:00 +0200
Subject: [PATCH] crypto: cryptd - add a lock instead
preempt_disable/local_bh_disablecryptd has a per-CPU lock which protected with
local_bh_disable()andpreempt_disable().
Add an explicitspin_lockto 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 thecpu_queuehas been obtain. This is not a problem because the actual ressource is protected by the spinlock.Signed-off-by Sebastian Andrzej Siewior <[email protected]>--- crypto/cryptd.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-)crypto/cryptd.c +9
-10@@ -39,6 +39,7 @@ MODULE_PARM_DESC(cryptd_max_cpu_qlen, "Set cryptd Max queue depth");struct cryptd_cpu_queue {struct crypto_queue queue;struct work_struct work; +spinlock_t qlock; };struct cryptd_queue {@@ -117,6 +118,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 ;@@ -141,8 +143,10 @@ static int cryptd_enqueue_request(struct cryptd_queue *queue,struct cryptd_cpu_queue *cpu_queue;atomic_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);@@ -158,7 +162,7 @@ static int cryptd_enqueue_request(struct cryptd_queue *queue,atomic_inc (refcnt); out_put_cpu: -put_cpu (); +spin_unlock_bh (&cpu_queue->qlock);return err; }@@ -174,16 +178,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 ;