forked from mirrors/linux
		
	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:
		
							parent
							
								
									add92a817e
								
							
						
					
					
						commit
						d80771c083
					
				
					 1 changed files with 30 additions and 23 deletions
				
			
		|  | @ -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]; | ||||
| }; | ||||
|  | @ -349,13 +349,20 @@ 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); | ||||
|  | @ -363,11 +370,8 @@ static int dcp_chan_thread_aes(void *data) | |||
| 		if (arq) { | ||||
| 			ret = mxs_dcp_aes_block_crypt(arq); | ||||
| 			arq->complete(arq, ret); | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		schedule(); | ||||
| 	} while (!kthread_should_stop()); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
|  | @ -409,9 +413,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]); | ||||
| 
 | ||||
|  | @ -640,13 +644,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); | ||||
|  | @ -658,12 +669,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; | ||||
| } | ||||
|  | @ -721,9 +728,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); | ||||
|  | @ -997,7 +1004,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); | ||||
| 	} | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Leonard Crestez
						Leonard Crestez