]>
Commit | Line | Data |
---|---|---|
39f3dcdc SLM |
1 | From bc39303df3ffddbcd03a1ae4ca88fa360b5c3e3a Mon Sep 17 00:00:00 2001 |
2 | From: Lars Persson <lars.persson@axis.com> | |
3 | Date: Wed, 23 Jan 2019 12:59:42 +0100 | |
4 | Subject: crypto: axis - fix for recursive locking from bottom half | |
5 | ||
6 | [ Upstream commit c34a83820f59bb275e5f2d55cd5ea99c64f6ef23 ] | |
7 | ||
8 | Clients may submit a new requests from the completion callback | |
9 | context. The driver was not prepared to receive a request in this | |
10 | state because it already held the request queue lock and a recursive | |
11 | lock error is triggered. | |
12 | ||
13 | Now all completions are queued up until we are ready to drop the queue | |
14 | lock and then delivered. | |
15 | ||
16 | The fault was triggered by TCP over an IPsec connection in the LTP | |
17 | test suite: | |
18 | LTP: starting tcp4_ipsec02 (tcp_ipsec.sh -p ah -m transport -s "100 1000 65535") | |
19 | BUG: spinlock recursion on CPU#1, genload/943 | |
20 | lock: 0xbf3c3094, .magic: dead4ead, .owner: genload/943, .owner_cpu: 1 | |
21 | CPU: 1 PID: 943 Comm: genload Tainted: G O 4.9.62-axis5-devel #6 | |
22 | Hardware name: Axis ARTPEC-6 Platform | |
23 | (unwind_backtrace) from [<8010d134>] (show_stack+0x18/0x1c) | |
24 | (show_stack) from [<803a289c>] (dump_stack+0x84/0x98) | |
25 | (dump_stack) from [<8016e164>] (do_raw_spin_lock+0x124/0x128) | |
26 | (do_raw_spin_lock) from [<804de1a4>] (artpec6_crypto_submit+0x2c/0xa0) | |
27 | (artpec6_crypto_submit) from [<804def38>] (artpec6_crypto_prepare_submit_hash+0xd0/0x54c) | |
28 | (artpec6_crypto_prepare_submit_hash) from [<7f3165f0>] (ah_output+0x2a4/0x3dc [ah4]) | |
29 | (ah_output [ah4]) from [<805df9bc>] (xfrm_output_resume+0x178/0x4a4) | |
30 | (xfrm_output_resume) from [<805d283c>] (xfrm4_output+0xac/0xbc) | |
31 | (xfrm4_output) from [<80587928>] (ip_queue_xmit+0x140/0x3b4) | |
32 | (ip_queue_xmit) from [<805a13b4>] (tcp_transmit_skb+0x4c4/0x95c) | |
33 | (tcp_transmit_skb) from [<8059f218>] (tcp_rcv_state_process+0xdf4/0xdfc) | |
34 | (tcp_rcv_state_process) from [<805a7530>] (tcp_v4_do_rcv+0x64/0x1ac) | |
35 | (tcp_v4_do_rcv) from [<805a9724>] (tcp_v4_rcv+0xa34/0xb74) | |
36 | (tcp_v4_rcv) from [<80581d34>] (ip_local_deliver_finish+0x78/0x2b0) | |
37 | (ip_local_deliver_finish) from [<8058259c>] (ip_local_deliver+0xe4/0x104) | |
38 | (ip_local_deliver) from [<805d23ec>] (xfrm4_transport_finish+0xf4/0x144) | |
39 | (xfrm4_transport_finish) from [<805df564>] (xfrm_input+0x4f4/0x74c) | |
40 | (xfrm_input) from [<804de420>] (artpec6_crypto_task+0x208/0x38c) | |
41 | (artpec6_crypto_task) from [<801271b0>] (tasklet_action+0x60/0xec) | |
42 | (tasklet_action) from [<801266d4>] (__do_softirq+0xcc/0x3a4) | |
43 | (__do_softirq) from [<80126d20>] (irq_exit+0xf4/0x15c) | |
44 | (irq_exit) from [<801741e8>] (__handle_domain_irq+0x68/0xbc) | |
45 | (__handle_domain_irq) from [<801014f0>] (gic_handle_irq+0x50/0x94) | |
46 | (gic_handle_irq) from [<80657370>] (__irq_usr+0x50/0x80) | |
47 | ||
48 | Signed-off-by: Lars Persson <larper@axis.com> | |
49 | Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> | |
50 | Signed-off-by: Sasha Levin <sashal@kernel.org> | |
51 | --- | |
52 | drivers/crypto/axis/artpec6_crypto.c | 28 +++++++++++++++++++++++----- | |
53 | 1 file changed, 23 insertions(+), 5 deletions(-) | |
54 | ||
55 | diff --git a/drivers/crypto/axis/artpec6_crypto.c b/drivers/crypto/axis/artpec6_crypto.c | |
56 | index 6eb5cb92b986..9f82e14983f6 100644 | |
57 | --- a/drivers/crypto/axis/artpec6_crypto.c | |
58 | +++ b/drivers/crypto/axis/artpec6_crypto.c | |
59 | @@ -284,6 +284,7 @@ enum artpec6_crypto_hash_flags { | |
60 | ||
61 | struct artpec6_crypto_req_common { | |
62 | struct list_head list; | |
63 | + struct list_head complete_in_progress; | |
64 | struct artpec6_crypto_dma_descriptors *dma; | |
65 | struct crypto_async_request *req; | |
66 | void (*complete)(struct crypto_async_request *req); | |
67 | @@ -2046,7 +2047,8 @@ static int artpec6_crypto_prepare_aead(struct aead_request *areq) | |
68 | return artpec6_crypto_dma_map_descs(common); | |
69 | } | |
70 | ||
71 | -static void artpec6_crypto_process_queue(struct artpec6_crypto *ac) | |
72 | +static void artpec6_crypto_process_queue(struct artpec6_crypto *ac, | |
73 | + struct list_head *completions) | |
74 | { | |
75 | struct artpec6_crypto_req_common *req; | |
76 | ||
77 | @@ -2057,7 +2059,7 @@ static void artpec6_crypto_process_queue(struct artpec6_crypto *ac) | |
78 | list_move_tail(&req->list, &ac->pending); | |
79 | artpec6_crypto_start_dma(req); | |
80 | ||
81 | - req->req->complete(req->req, -EINPROGRESS); | |
82 | + list_add_tail(&req->complete_in_progress, completions); | |
83 | } | |
84 | ||
85 | /* | |
86 | @@ -2087,6 +2089,11 @@ static void artpec6_crypto_task(unsigned long data) | |
87 | struct artpec6_crypto *ac = (struct artpec6_crypto *)data; | |
88 | struct artpec6_crypto_req_common *req; | |
89 | struct artpec6_crypto_req_common *n; | |
90 | + struct list_head complete_done; | |
91 | + struct list_head complete_in_progress; | |
92 | + | |
93 | + INIT_LIST_HEAD(&complete_done); | |
94 | + INIT_LIST_HEAD(&complete_in_progress); | |
95 | ||
96 | if (list_empty(&ac->pending)) { | |
97 | pr_debug("Spurious IRQ\n"); | |
98 | @@ -2120,19 +2127,30 @@ static void artpec6_crypto_task(unsigned long data) | |
99 | ||
100 | pr_debug("Completing request %p\n", req); | |
101 | ||
102 | - list_del(&req->list); | |
103 | + list_move_tail(&req->list, &complete_done); | |
104 | ||
105 | artpec6_crypto_dma_unmap_all(req); | |
106 | artpec6_crypto_copy_bounce_buffers(req); | |
107 | ||
108 | ac->pending_count--; | |
109 | artpec6_crypto_common_destroy(req); | |
110 | - req->complete(req->req); | |
111 | } | |
112 | ||
113 | - artpec6_crypto_process_queue(ac); | |
114 | + artpec6_crypto_process_queue(ac, &complete_in_progress); | |
115 | ||
116 | spin_unlock_bh(&ac->queue_lock); | |
117 | + | |
118 | + /* Perform the completion callbacks without holding the queue lock | |
119 | + * to allow new request submissions from the callbacks. | |
120 | + */ | |
121 | + list_for_each_entry_safe(req, n, &complete_done, list) { | |
122 | + req->complete(req->req); | |
123 | + } | |
124 | + | |
125 | + list_for_each_entry_safe(req, n, &complete_in_progress, | |
126 | + complete_in_progress) { | |
127 | + req->req->complete(req->req, -EINPROGRESS); | |
128 | + } | |
129 | } | |
130 | ||
131 | static void artpec6_crypto_complete_crypto(struct crypto_async_request *req) | |
132 | -- | |
133 | 2.19.1 | |
134 |