Skip to content

Commit

Permalink
crypto: mxs-dcp - Fix wait logic on chan threads
Browse files Browse the repository at this point in the history
commit d80771c08363ad7fbf0f56f5301e7ca65065c582 upstream.

When compiling with CONFIG_DEBUG_ATOMIC_SLEEP=y the mxs-dcp driver
prints warnings such as:

WARNING: CPU: 0 PID: 120 at kernel/sched/core.c:7736 __might_sleep+0x98/0x9c
do not call blocking ops when !TASK_RUNNING; state=1 set at [<8081978c>] dcp_chan_thread_sha+0x3c/0x2ec

The problem is that blocking ops will manipulate current->state
themselves so it is not allowed to call them between
set_current_state(TASK_INTERRUPTIBLE) and schedule().

Fix this by converting the per-chan mutex to a spinlock (it only
protects tiny list ops anyway) and rearranging the wait logic so that
callbacks are called current->state as TASK_RUNNING. Those callbacks
will indeed call blocking ops themselves so this is required.

Cc: <stable@vger.kernel.org>
Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
cdleonard authored and gregkh committed Oct 13, 2018
1 parent ada05f7 commit 1b42ccd
Showing 1 changed file with 30 additions and 23 deletions.
53 changes: 30 additions & 23 deletions drivers/crypto/mxs-dcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ struct dcp {
struct dcp_coherent_block *coh;

struct completion completion[DCP_MAX_CHANS];
struct mutex mutex[DCP_MAX_CHANS];
spinlock_t lock[DCP_MAX_CHANS];
struct task_struct *thread[DCP_MAX_CHANS];
struct crypto_queue queue[DCP_MAX_CHANS];
};
Expand Down Expand Up @@ -349,25 +349,29 @@ static int dcp_chan_thread_aes(void *data)

int ret;

do {
__set_current_state(TASK_INTERRUPTIBLE);
while (!kthread_should_stop()) {
set_current_state(TASK_INTERRUPTIBLE);

mutex_lock(&sdcp->mutex[chan]);
spin_lock(&sdcp->lock[chan]);
backlog = crypto_get_backlog(&sdcp->queue[chan]);
arq = crypto_dequeue_request(&sdcp->queue[chan]);
mutex_unlock(&sdcp->mutex[chan]);
spin_unlock(&sdcp->lock[chan]);

if (!backlog && !arq) {
schedule();
continue;
}

set_current_state(TASK_RUNNING);

if (backlog)
backlog->complete(backlog, -EINPROGRESS);

if (arq) {
ret = mxs_dcp_aes_block_crypt(arq);
arq->complete(arq, ret);
continue;
}

schedule();
} while (!kthread_should_stop());
}

return 0;
}
Expand Down Expand Up @@ -407,9 +411,9 @@ static int mxs_dcp_aes_enqueue(struct ablkcipher_request *req, int enc, int ecb)
rctx->ecb = ecb;
actx->chan = DCP_CHAN_CRYPTO;

mutex_lock(&sdcp->mutex[actx->chan]);
spin_lock(&sdcp->lock[actx->chan]);
ret = crypto_enqueue_request(&sdcp->queue[actx->chan], &req->base);
mutex_unlock(&sdcp->mutex[actx->chan]);
spin_unlock(&sdcp->lock[actx->chan]);

wake_up_process(sdcp->thread[actx->chan]);

Expand Down Expand Up @@ -645,13 +649,20 @@ static int dcp_chan_thread_sha(void *data)
struct ahash_request *req;
int ret, fini;

do {
__set_current_state(TASK_INTERRUPTIBLE);
while (!kthread_should_stop()) {
set_current_state(TASK_INTERRUPTIBLE);

mutex_lock(&sdcp->mutex[chan]);
spin_lock(&sdcp->lock[chan]);
backlog = crypto_get_backlog(&sdcp->queue[chan]);
arq = crypto_dequeue_request(&sdcp->queue[chan]);
mutex_unlock(&sdcp->mutex[chan]);
spin_unlock(&sdcp->lock[chan]);

if (!backlog && !arq) {
schedule();
continue;
}

set_current_state(TASK_RUNNING);

if (backlog)
backlog->complete(backlog, -EINPROGRESS);
Expand All @@ -663,12 +674,8 @@ static int dcp_chan_thread_sha(void *data)
ret = dcp_sha_req_to_buf(arq);
fini = rctx->fini;
arq->complete(arq, ret);
if (!fini)
continue;
}

schedule();
} while (!kthread_should_stop());
}

return 0;
}
Expand Down Expand Up @@ -726,9 +733,9 @@ static int dcp_sha_update_fx(struct ahash_request *req, int fini)
rctx->init = 1;
}

mutex_lock(&sdcp->mutex[actx->chan]);
spin_lock(&sdcp->lock[actx->chan]);
ret = crypto_enqueue_request(&sdcp->queue[actx->chan], &req->base);
mutex_unlock(&sdcp->mutex[actx->chan]);
spin_unlock(&sdcp->lock[actx->chan]);

wake_up_process(sdcp->thread[actx->chan]);
mutex_unlock(&actx->mutex);
Expand Down Expand Up @@ -984,7 +991,7 @@ static int mxs_dcp_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, sdcp);

for (i = 0; i < DCP_MAX_CHANS; i++) {
mutex_init(&sdcp->mutex[i]);
spin_lock_init(&sdcp->lock[i]);
init_completion(&sdcp->completion[i]);
crypto_init_queue(&sdcp->queue[i], 50);
}
Expand Down

0 comments on commit 1b42ccd

Please sign in to comment.