Skip to content

Commit f56809c

Browse files
Cyrille Pitchenherbertx
authored andcommitted
crypto: atmel-sha - fix a race between the 'done' tasklet and the crypto client
The 'done' tasklet handler used to check the 'BUSY' flag to either finalize the processing of a crypto request which had just completed or manage the crypto queue to start the next crypto request. On request R1 completion, the driver calls atmel_sha_finish_req(), which: 1 - clears the 'BUSY' flag since the hardware is no longer used and is ready again to process new crypto requests. 2 - notifies the above layer (the client) about the completion of the asynchronous crypto request R1 by calling its base.complete() callback. 3 - schedules the 'done' task to check the crypto queue and start to process the next crypto request (the 'BUSY' flag is supposed to be cleared at that moment) if such a pending request exists. However step 2 might wake the client up so it can now ask our driver to process a new crypto request R2. This request is enqueued by calling the atmel_sha_handle_queue() function, which sets the 'BUSY' flags then starts to process R2. If the 'done' tasklet, scheduled by step 3, runs just after, it would see that the 'BUSY' flag is set then understand that R2 has just completed, which is wrong! So the state of 'BUSY' flag is not a proper way to detect and handle crypto request completion. This patch fixes this race condition by using two different tasklets, one to handle the crypto request completion events, the other to manage the crypto queue if needed. Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
1 parent 1900c58 commit f56809c

File tree

1 file changed

+13
-6
lines changed

1 file changed

+13
-6
lines changed

drivers/crypto/atmel-sha.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ struct atmel_sha_dev {
122122
spinlock_t lock;
123123
int err;
124124
struct tasklet_struct done_task;
125+
struct tasklet_struct queue_task;
125126

126127
unsigned long flags;
127128
struct crypto_queue queue;
@@ -788,7 +789,7 @@ static void atmel_sha_finish_req(struct ahash_request *req, int err)
788789
req->base.complete(&req->base, err);
789790

790791
/* handle new request */
791-
tasklet_schedule(&dd->done_task);
792+
tasklet_schedule(&dd->queue_task);
792793
}
793794

794795
static int atmel_sha_hw_init(struct atmel_sha_dev *dd)
@@ -1101,16 +1102,18 @@ static struct ahash_alg sha_384_512_algs[] = {
11011102
},
11021103
};
11031104

1105+
static void atmel_sha_queue_task(unsigned long data)
1106+
{
1107+
struct atmel_sha_dev *dd = (struct atmel_sha_dev *)data;
1108+
1109+
atmel_sha_handle_queue(dd, NULL);
1110+
}
1111+
11041112
static void atmel_sha_done_task(unsigned long data)
11051113
{
11061114
struct atmel_sha_dev *dd = (struct atmel_sha_dev *)data;
11071115
int err = 0;
11081116

1109-
if (!(SHA_FLAGS_BUSY & dd->flags)) {
1110-
atmel_sha_handle_queue(dd, NULL);
1111-
return;
1112-
}
1113-
11141117
if (SHA_FLAGS_CPU & dd->flags) {
11151118
if (SHA_FLAGS_OUTPUT_READY & dd->flags) {
11161119
dd->flags &= ~SHA_FLAGS_OUTPUT_READY;
@@ -1367,6 +1370,8 @@ static int atmel_sha_probe(struct platform_device *pdev)
13671370

13681371
tasklet_init(&sha_dd->done_task, atmel_sha_done_task,
13691372
(unsigned long)sha_dd);
1373+
tasklet_init(&sha_dd->queue_task, atmel_sha_queue_task,
1374+
(unsigned long)sha_dd);
13701375

13711376
crypto_init_queue(&sha_dd->queue, ATMEL_SHA_QUEUE_LENGTH);
13721377

@@ -1459,6 +1464,7 @@ static int atmel_sha_probe(struct platform_device *pdev)
14591464
atmel_sha_dma_cleanup(sha_dd);
14601465
err_sha_dma:
14611466
res_err:
1467+
tasklet_kill(&sha_dd->queue_task);
14621468
tasklet_kill(&sha_dd->done_task);
14631469
sha_dd_err:
14641470
dev_err(dev, "initialization failed.\n");
@@ -1479,6 +1485,7 @@ static int atmel_sha_remove(struct platform_device *pdev)
14791485

14801486
atmel_sha_unregister_algs(sha_dd);
14811487

1488+
tasklet_kill(&sha_dd->queue_task);
14821489
tasklet_kill(&sha_dd->done_task);
14831490

14841491
if (sha_dd->caps.has_dma)

0 commit comments

Comments
 (0)