Skip to content

Commit c0403ec

Browse files
vwaxsnitm
authored andcommitted
Revert "dm crypt: fix deadlock when async crypto algorithm returns -EBUSY"
This reverts Linux 4.1-rc1 commit 0618764. The problem which that commit attempts to fix actually lies in the Freescale CAAM crypto driver not dm-crypt. dm-crypt uses CRYPTO_TFM_REQ_MAY_BACKLOG. This means the the crypto driver should internally backlog requests which arrive when the queue is full and process them later. Until the crypto hw's queue becomes full, the driver returns -EINPROGRESS. When the crypto hw's queue if full, the driver returns -EBUSY, and if CRYPTO_TFM_REQ_MAY_BACKLOG is set, is expected to backlog the request and process it when the hardware has queue space. At the point when the driver takes the request from the backlog and starts processing it, it calls the completion function with a status of -EINPROGRESS. The completion function is called (for a second time, in the case of backlogged requests) with a status/err of 0 when a request is done. Crypto drivers for hardware without hardware queueing use the helpers, crypto_init_queue(), crypto_enqueue_request(), crypto_dequeue_request() and crypto_get_backlog() helpers to implement this behaviour correctly, while others implement this behaviour without these helpers (ccp, for example). dm-crypt (before the patch that needs reverting) uses this API correctly. It queues up as many requests as the hw queues will allow (i.e. as long as it gets back -EINPROGRESS from the request function). Then, when it sees at least one backlogged request (gets -EBUSY), it waits till that backlogged request is handled (completion gets called with -EINPROGRESS), and then continues. The references to af_alg_wait_for_completion() and af_alg_complete() in that commit's commit message are irrelevant because those functions only handle one request at a time, unlink dm-crypt. The problem is that the Freescale CAAM driver, which that commit describes as having being tested with, fails to implement the backlogging behaviour correctly. In cam_jr_enqueue(), if the hardware queue is full, it simply returns -EBUSY without backlogging the request. What the observed deadlock was is not described in the commit message but it is obviously the wait_for_completion() in crypto_convert() where dm-crypto would wait for the completion being called with -EINPROGRESS in the case of backlogged requests. This completion will never be completed due to the bug in the CAAM driver. Commit 0618764 incorrectly made dm-crypt wait for every request, even when the driver/hardware queues are not full, which means that dm-crypt will never see -EBUSY. This means that that commit will cause a performance regression on all crypto drivers which implement the API correctly. Revert it. Correct backlog handling should be implemented in the CAAM driver instead. Cc'ing stable purely because commit 0618764 did. If for some reason a stable@ kernel did pick up commit 0618764 it should get reverted. Signed-off-by: Rabin Vincent <[email protected]> Reviewed-by: Horia Geanta <[email protected]> Cc: [email protected] Signed-off-by: Mike Snitzer <[email protected]>
1 parent aa6df8d commit c0403ec

File tree

1 file changed

+6
-6
lines changed

1 file changed

+6
-6
lines changed

drivers/md/dm-crypt.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -925,10 +925,11 @@ static int crypt_convert(struct crypt_config *cc,
925925

926926
switch (r) {
927927
/* async */
928-
case -EINPROGRESS:
929928
case -EBUSY:
930929
wait_for_completion(&ctx->restart);
931930
reinit_completion(&ctx->restart);
931+
/* fall through*/
932+
case -EINPROGRESS:
932933
ctx->req = NULL;
933934
ctx->cc_sector++;
934935
continue;
@@ -1345,8 +1346,10 @@ static void kcryptd_async_done(struct crypto_async_request *async_req,
13451346
struct dm_crypt_io *io = container_of(ctx, struct dm_crypt_io, ctx);
13461347
struct crypt_config *cc = io->cc;
13471348

1348-
if (error == -EINPROGRESS)
1349+
if (error == -EINPROGRESS) {
1350+
complete(&ctx->restart);
13491351
return;
1352+
}
13501353

13511354
if (!error && cc->iv_gen_ops && cc->iv_gen_ops->post)
13521355
error = cc->iv_gen_ops->post(cc, iv_of_dmreq(cc, dmreq), dmreq);
@@ -1357,15 +1360,12 @@ static void kcryptd_async_done(struct crypto_async_request *async_req,
13571360
crypt_free_req(cc, req_of_dmreq(cc, dmreq), io->base_bio);
13581361

13591362
if (!atomic_dec_and_test(&ctx->cc_pending))
1360-
goto done;
1363+
return;
13611364

13621365
if (bio_data_dir(io->base_bio) == READ)
13631366
kcryptd_crypt_read_done(io);
13641367
else
13651368
kcryptd_crypt_write_io_submit(io, 1);
1366-
done:
1367-
if (!completion_done(&ctx->restart))
1368-
complete(&ctx->restart);
13691369
}
13701370

13711371
static void kcryptd_crypt(struct work_struct *work)

0 commit comments

Comments
 (0)