Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

crypto: virtio - Handle dataq logic with tasklet

Doing ipsec produces a spinlock recursion warning.
This is due to crypto_finalize_request() being called in the upper half.
Move virtual data queue processing of virtio-crypto driver to tasklet.

Fixes: dbaf0624ffa57 ("crypto: add virtio-crypto driver")
Reported-by: Halil Pasic <pasic@linux.ibm.com>
Signed-off-by: wangyangxin <wangyangxin1@huawei.com>
Signed-off-by: Gonglei <arei.gonglei@huawei.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

authored by

Gonglei (Arei) and committed by
Herbert Xu
fed93fb6 8a0d929b

+15 -10
+2
drivers/crypto/virtio/virtio_crypto_common.h
··· 10 10 #include <linux/virtio.h> 11 11 #include <linux/crypto.h> 12 12 #include <linux/spinlock.h> 13 + #include <linux/interrupt.h> 13 14 #include <crypto/aead.h> 14 15 #include <crypto/aes.h> 15 16 #include <crypto/engine.h> ··· 29 28 char name[32]; 30 29 31 30 struct crypto_engine *engine; 31 + struct tasklet_struct done_task; 32 32 }; 33 33 34 34 struct virtio_crypto {
+13 -10
drivers/crypto/virtio/virtio_crypto_core.c
··· 72 72 return 0; 73 73 } 74 74 75 - static void virtcrypto_dataq_callback(struct virtqueue *vq) 75 + static void virtcrypto_done_task(unsigned long data) 76 76 { 77 - struct virtio_crypto *vcrypto = vq->vdev->priv; 77 + struct data_queue *data_vq = (struct data_queue *)data; 78 + struct virtqueue *vq = data_vq->vq; 78 79 struct virtio_crypto_request *vc_req; 79 - unsigned long flags; 80 80 unsigned int len; 81 - unsigned int qid = vq->index; 82 81 83 - spin_lock_irqsave(&vcrypto->data_vq[qid].lock, flags); 84 82 do { 85 83 virtqueue_disable_cb(vq); 86 84 while ((vc_req = virtqueue_get_buf(vq, &len)) != NULL) { 87 - spin_unlock_irqrestore( 88 - &vcrypto->data_vq[qid].lock, flags); 89 85 if (vc_req->alg_cb) 90 86 vc_req->alg_cb(vc_req, len); 91 - spin_lock_irqsave( 92 - &vcrypto->data_vq[qid].lock, flags); 93 87 } 94 88 } while (!virtqueue_enable_cb(vq)); 95 - spin_unlock_irqrestore(&vcrypto->data_vq[qid].lock, flags); 89 + } 90 + 91 + static void virtcrypto_dataq_callback(struct virtqueue *vq) 92 + { 93 + struct virtio_crypto *vcrypto = vq->vdev->priv; 94 + struct data_queue *dq = &vcrypto->data_vq[vq->index]; 95 + 96 + tasklet_schedule(&dq->done_task); 96 97 } 97 98 98 99 static int virtcrypto_find_vqs(struct virtio_crypto *vi) ··· 151 150 ret = -ENOMEM; 152 151 goto err_engine; 153 152 } 153 + tasklet_init(&vi->data_vq[i].done_task, virtcrypto_done_task, 154 + (unsigned long)&vi->data_vq[i]); 154 155 } 155 156 156 157 kfree(names);