crypto: mxs-dcp - Fix wait logic on chan threads
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>
This commit is contained in:
Родитель
add92a817e
Коммит
d80771c083
|
@ -63,7 +63,7 @@ struct dcp {
|
||||||
struct dcp_coherent_block *coh;
|
struct dcp_coherent_block *coh;
|
||||||
|
|
||||||
struct completion completion[DCP_MAX_CHANS];
|
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 task_struct *thread[DCP_MAX_CHANS];
|
||||||
struct crypto_queue queue[DCP_MAX_CHANS];
|
struct crypto_queue queue[DCP_MAX_CHANS];
|
||||||
};
|
};
|
||||||
|
@ -349,13 +349,20 @@ static int dcp_chan_thread_aes(void *data)
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
do {
|
while (!kthread_should_stop()) {
|
||||||
__set_current_state(TASK_INTERRUPTIBLE);
|
set_current_state(TASK_INTERRUPTIBLE);
|
||||||
|
|
||||||
mutex_lock(&sdcp->mutex[chan]);
|
spin_lock(&sdcp->lock[chan]);
|
||||||
backlog = crypto_get_backlog(&sdcp->queue[chan]);
|
backlog = crypto_get_backlog(&sdcp->queue[chan]);
|
||||||
arq = crypto_dequeue_request(&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)
|
if (backlog)
|
||||||
backlog->complete(backlog, -EINPROGRESS);
|
backlog->complete(backlog, -EINPROGRESS);
|
||||||
|
@ -363,11 +370,8 @@ static int dcp_chan_thread_aes(void *data)
|
||||||
if (arq) {
|
if (arq) {
|
||||||
ret = mxs_dcp_aes_block_crypt(arq);
|
ret = mxs_dcp_aes_block_crypt(arq);
|
||||||
arq->complete(arq, ret);
|
arq->complete(arq, ret);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
schedule();
|
|
||||||
} while (!kthread_should_stop());
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -409,9 +413,9 @@ static int mxs_dcp_aes_enqueue(struct ablkcipher_request *req, int enc, int ecb)
|
||||||
rctx->ecb = ecb;
|
rctx->ecb = ecb;
|
||||||
actx->chan = DCP_CHAN_CRYPTO;
|
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);
|
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]);
|
wake_up_process(sdcp->thread[actx->chan]);
|
||||||
|
|
||||||
|
@ -640,13 +644,20 @@ static int dcp_chan_thread_sha(void *data)
|
||||||
struct ahash_request *req;
|
struct ahash_request *req;
|
||||||
int ret, fini;
|
int ret, fini;
|
||||||
|
|
||||||
do {
|
while (!kthread_should_stop()) {
|
||||||
__set_current_state(TASK_INTERRUPTIBLE);
|
set_current_state(TASK_INTERRUPTIBLE);
|
||||||
|
|
||||||
mutex_lock(&sdcp->mutex[chan]);
|
spin_lock(&sdcp->lock[chan]);
|
||||||
backlog = crypto_get_backlog(&sdcp->queue[chan]);
|
backlog = crypto_get_backlog(&sdcp->queue[chan]);
|
||||||
arq = crypto_dequeue_request(&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)
|
if (backlog)
|
||||||
backlog->complete(backlog, -EINPROGRESS);
|
backlog->complete(backlog, -EINPROGRESS);
|
||||||
|
@ -658,12 +669,8 @@ static int dcp_chan_thread_sha(void *data)
|
||||||
ret = dcp_sha_req_to_buf(arq);
|
ret = dcp_sha_req_to_buf(arq);
|
||||||
fini = rctx->fini;
|
fini = rctx->fini;
|
||||||
arq->complete(arq, ret);
|
arq->complete(arq, ret);
|
||||||
if (!fini)
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
schedule();
|
|
||||||
} while (!kthread_should_stop());
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -721,9 +728,9 @@ static int dcp_sha_update_fx(struct ahash_request *req, int fini)
|
||||||
rctx->init = 1;
|
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);
|
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]);
|
wake_up_process(sdcp->thread[actx->chan]);
|
||||||
mutex_unlock(&actx->mutex);
|
mutex_unlock(&actx->mutex);
|
||||||
|
@ -997,7 +1004,7 @@ static int mxs_dcp_probe(struct platform_device *pdev)
|
||||||
platform_set_drvdata(pdev, sdcp);
|
platform_set_drvdata(pdev, sdcp);
|
||||||
|
|
||||||
for (i = 0; i < DCP_MAX_CHANS; i++) {
|
for (i = 0; i < DCP_MAX_CHANS; i++) {
|
||||||
mutex_init(&sdcp->mutex[i]);
|
spin_lock_init(&sdcp->lock[i]);
|
||||||
init_completion(&sdcp->completion[i]);
|
init_completion(&sdcp->completion[i]);
|
||||||
crypto_init_queue(&sdcp->queue[i], 50);
|
crypto_init_queue(&sdcp->queue[i], 50);
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче