Skip to content

Commit 5682830

Browse files
larperaxisgregkh
authored andcommitted
crypto: axis - fix for recursive locking from bottom half
[ Upstream commit c34a838 ] Clients may submit a new requests from the completion callback context. The driver was not prepared to receive a request in this state because it already held the request queue lock and a recursive lock error is triggered. Now all completions are queued up until we are ready to drop the queue lock and then delivered. The fault was triggered by TCP over an IPsec connection in the LTP test suite: LTP: starting tcp4_ipsec02 (tcp_ipsec.sh -p ah -m transport -s "100 1000 65535") BUG: spinlock recursion on CPU#1, genload/943 lock: 0xbf3c3094, .magic: dead4ead, .owner: genload/943, .owner_cpu: 1 CPU: 1 PID: 943 Comm: genload Tainted: G O 4.9.62-axis5-devel #6 Hardware name: Axis ARTPEC-6 Platform (unwind_backtrace) from [<8010d134>] (show_stack+0x18/0x1c) (show_stack) from [<803a289c>] (dump_stack+0x84/0x98) (dump_stack) from [<8016e164>] (do_raw_spin_lock+0x124/0x128) (do_raw_spin_lock) from [<804de1a4>] (artpec6_crypto_submit+0x2c/0xa0) (artpec6_crypto_submit) from [<804def38>] (artpec6_crypto_prepare_submit_hash+0xd0/0x54c) (artpec6_crypto_prepare_submit_hash) from [<7f3165f0>] (ah_output+0x2a4/0x3dc [ah4]) (ah_output [ah4]) from [<805df9bc>] (xfrm_output_resume+0x178/0x4a4) (xfrm_output_resume) from [<805d283c>] (xfrm4_output+0xac/0xbc) (xfrm4_output) from [<80587928>] (ip_queue_xmit+0x140/0x3b4) (ip_queue_xmit) from [<805a13b4>] (tcp_transmit_skb+0x4c4/0x95c) (tcp_transmit_skb) from [<8059f218>] (tcp_rcv_state_process+0xdf4/0xdfc) (tcp_rcv_state_process) from [<805a7530>] (tcp_v4_do_rcv+0x64/0x1ac) (tcp_v4_do_rcv) from [<805a9724>] (tcp_v4_rcv+0xa34/0xb74) (tcp_v4_rcv) from [<80581d34>] (ip_local_deliver_finish+0x78/0x2b0) (ip_local_deliver_finish) from [<8058259c>] (ip_local_deliver+0xe4/0x104) (ip_local_deliver) from [<805d23ec>] (xfrm4_transport_finish+0xf4/0x144) (xfrm4_transport_finish) from [<805df564>] (xfrm_input+0x4f4/0x74c) (xfrm_input) from [<804de420>] (artpec6_crypto_task+0x208/0x38c) (artpec6_crypto_task) from [<801271b0>] (tasklet_action+0x60/0xec) (tasklet_action) from [<801266d4>] (__do_softirq+0xcc/0x3a4) (__do_softirq) from [<80126d20>] (irq_exit+0xf4/0x15c) (irq_exit) from [<801741e8>] (__handle_domain_irq+0x68/0xbc) (__handle_domain_irq) from [<801014f0>] (gic_handle_irq+0x50/0x94) (gic_handle_irq) from [<80657370>] (__irq_usr+0x50/0x80) Signed-off-by: Lars Persson <[email protected]> Signed-off-by: Herbert Xu <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent 61bea6a commit 5682830

File tree

1 file changed

+23
-5
lines changed

1 file changed

+23
-5
lines changed

drivers/crypto/axis/artpec6_crypto.c

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ enum artpec6_crypto_hash_flags {
284284

285285
struct artpec6_crypto_req_common {
286286
struct list_head list;
287+
struct list_head complete_in_progress;
287288
struct artpec6_crypto_dma_descriptors *dma;
288289
struct crypto_async_request *req;
289290
void (*complete)(struct crypto_async_request *req);
@@ -2046,7 +2047,8 @@ static int artpec6_crypto_prepare_aead(struct aead_request *areq)
20462047
return artpec6_crypto_dma_map_descs(common);
20472048
}
20482049

2049-
static void artpec6_crypto_process_queue(struct artpec6_crypto *ac)
2050+
static void artpec6_crypto_process_queue(struct artpec6_crypto *ac,
2051+
struct list_head *completions)
20502052
{
20512053
struct artpec6_crypto_req_common *req;
20522054

@@ -2057,7 +2059,7 @@ static void artpec6_crypto_process_queue(struct artpec6_crypto *ac)
20572059
list_move_tail(&req->list, &ac->pending);
20582060
artpec6_crypto_start_dma(req);
20592061

2060-
req->req->complete(req->req, -EINPROGRESS);
2062+
list_add_tail(&req->complete_in_progress, completions);
20612063
}
20622064

20632065
/*
@@ -2087,6 +2089,11 @@ static void artpec6_crypto_task(unsigned long data)
20872089
struct artpec6_crypto *ac = (struct artpec6_crypto *)data;
20882090
struct artpec6_crypto_req_common *req;
20892091
struct artpec6_crypto_req_common *n;
2092+
struct list_head complete_done;
2093+
struct list_head complete_in_progress;
2094+
2095+
INIT_LIST_HEAD(&complete_done);
2096+
INIT_LIST_HEAD(&complete_in_progress);
20902097

20912098
if (list_empty(&ac->pending)) {
20922099
pr_debug("Spurious IRQ\n");
@@ -2120,19 +2127,30 @@ static void artpec6_crypto_task(unsigned long data)
21202127

21212128
pr_debug("Completing request %p\n", req);
21222129

2123-
list_del(&req->list);
2130+
list_move_tail(&req->list, &complete_done);
21242131

21252132
artpec6_crypto_dma_unmap_all(req);
21262133
artpec6_crypto_copy_bounce_buffers(req);
21272134

21282135
ac->pending_count--;
21292136
artpec6_crypto_common_destroy(req);
2130-
req->complete(req->req);
21312137
}
21322138

2133-
artpec6_crypto_process_queue(ac);
2139+
artpec6_crypto_process_queue(ac, &complete_in_progress);
21342140

21352141
spin_unlock_bh(&ac->queue_lock);
2142+
2143+
/* Perform the completion callbacks without holding the queue lock
2144+
* to allow new request submissions from the callbacks.
2145+
*/
2146+
list_for_each_entry_safe(req, n, &complete_done, list) {
2147+
req->complete(req->req);
2148+
}
2149+
2150+
list_for_each_entry_safe(req, n, &complete_in_progress,
2151+
complete_in_progress) {
2152+
req->req->complete(req->req, -EINPROGRESS);
2153+
}
21362154
}
21372155

21382156
static void artpec6_crypto_complete_crypto(struct crypto_async_request *req)

0 commit comments

Comments
 (0)