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

Configure Feed

Select the types of activity you want to include in your feed.

crypto: virtio - Convert from tasklet to BH workqueue

The only generic interface to execute asynchronously in the BH context
is tasklet; however, it's marked deprecated and has some design flaws
such as the execution code accessing the tasklet item after the
execution is complete which can lead to subtle use-after-free in certain
usage scenarios and less-developed flush and cancel mechanisms.

To replace tasklets, BH workqueue support was recently added. A BH
workqueue behaves similarly to regular workqueues except that the queued
work items are executed in the BH context.

Convert virtio_crypto_core.c from tasklet to BH workqueue.

Semantically, this is an equivalent conversion and there shouldn't be
any user-visible behavior changes. The BH workqueue implementation uses
the same softirq infrastructure, and performance-critical networking
conversions have shown no measurable performance impact.

Signed-off-by: Pat Somaru <patso@likewhatevs.io>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

authored by

Pat Somaru and committed by
Herbert Xu
2127a1bf 404ba6b4

+7 -7
+2 -1
drivers/crypto/virtio/virtio_crypto_common.h
··· 11 11 #include <linux/crypto.h> 12 12 #include <linux/spinlock.h> 13 13 #include <linux/interrupt.h> 14 + #include <linux/workqueue.h> 14 15 #include <crypto/aead.h> 15 16 #include <crypto/aes.h> 16 17 #include <crypto/engine.h> ··· 30 29 char name[32]; 31 30 32 31 struct crypto_engine *engine; 33 - struct tasklet_struct done_task; 32 + struct work_struct done_work; 34 33 }; 35 34 36 35 struct virtio_crypto {
+5 -6
drivers/crypto/virtio/virtio_crypto_core.c
··· 70 70 return 0; 71 71 } 72 72 73 - static void virtcrypto_done_task(unsigned long data) 73 + static void virtcrypto_done_work(struct work_struct *work) 74 74 { 75 - struct data_queue *data_vq = (struct data_queue *)data; 75 + struct data_queue *data_vq = from_work(data_vq, work, done_work); 76 76 struct virtqueue *vq = data_vq->vq; 77 77 struct virtio_crypto_request *vc_req; 78 78 unsigned long flags; ··· 96 96 struct virtio_crypto *vcrypto = vq->vdev->priv; 97 97 struct data_queue *dq = &vcrypto->data_vq[vq->index]; 98 98 99 - tasklet_schedule(&dq->done_task); 99 + queue_work(system_bh_wq, &dq->done_work); 100 100 } 101 101 102 102 static int virtcrypto_find_vqs(struct virtio_crypto *vi) ··· 150 150 ret = -ENOMEM; 151 151 goto err_engine; 152 152 } 153 - tasklet_init(&vi->data_vq[i].done_task, virtcrypto_done_task, 154 - (unsigned long)&vi->data_vq[i]); 153 + INIT_WORK(&vi->data_vq[i].done_work, virtcrypto_done_work); 155 154 } 156 155 157 156 kfree(vqs_info); ··· 500 501 if (virtcrypto_dev_started(vcrypto)) 501 502 virtcrypto_dev_stop(vcrypto); 502 503 for (i = 0; i < vcrypto->max_data_queues; i++) 503 - tasklet_kill(&vcrypto->data_vq[i].done_task); 504 + cancel_work_sync(&vcrypto->data_vq[i].done_work); 504 505 virtio_reset_device(vdev); 505 506 virtcrypto_free_unused_reqs(vcrypto); 506 507 virtcrypto_clear_crypto_engines(vcrypto);