mirror of
https://github.com/torvalds/linux.git
synced 2026-05-12 16:18:45 +02:00
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>
This commit is contained in:
parent
404ba6b46b
commit
2127a1bf89
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/crypto.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <crypto/aead.h>
|
||||
#include <crypto/aes.h>
|
||||
#include <crypto/engine.h>
|
||||
|
|
@ -29,7 +30,7 @@ struct data_queue {
|
|||
char name[32];
|
||||
|
||||
struct crypto_engine *engine;
|
||||
struct tasklet_struct done_task;
|
||||
struct work_struct done_work;
|
||||
};
|
||||
|
||||
struct virtio_crypto {
|
||||
|
|
|
|||
|
|
@ -70,9 +70,9 @@ int virtio_crypto_ctrl_vq_request(struct virtio_crypto *vcrypto, struct scatterl
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void virtcrypto_done_task(unsigned long data)
|
||||
static void virtcrypto_done_work(struct work_struct *work)
|
||||
{
|
||||
struct data_queue *data_vq = (struct data_queue *)data;
|
||||
struct data_queue *data_vq = from_work(data_vq, work, done_work);
|
||||
struct virtqueue *vq = data_vq->vq;
|
||||
struct virtio_crypto_request *vc_req;
|
||||
unsigned long flags;
|
||||
|
|
@ -96,7 +96,7 @@ static void virtcrypto_dataq_callback(struct virtqueue *vq)
|
|||
struct virtio_crypto *vcrypto = vq->vdev->priv;
|
||||
struct data_queue *dq = &vcrypto->data_vq[vq->index];
|
||||
|
||||
tasklet_schedule(&dq->done_task);
|
||||
queue_work(system_bh_wq, &dq->done_work);
|
||||
}
|
||||
|
||||
static int virtcrypto_find_vqs(struct virtio_crypto *vi)
|
||||
|
|
@ -150,8 +150,7 @@ static int virtcrypto_find_vqs(struct virtio_crypto *vi)
|
|||
ret = -ENOMEM;
|
||||
goto err_engine;
|
||||
}
|
||||
tasklet_init(&vi->data_vq[i].done_task, virtcrypto_done_task,
|
||||
(unsigned long)&vi->data_vq[i]);
|
||||
INIT_WORK(&vi->data_vq[i].done_work, virtcrypto_done_work);
|
||||
}
|
||||
|
||||
kfree(vqs_info);
|
||||
|
|
@ -501,7 +500,7 @@ static void virtcrypto_remove(struct virtio_device *vdev)
|
|||
if (virtcrypto_dev_started(vcrypto))
|
||||
virtcrypto_dev_stop(vcrypto);
|
||||
for (i = 0; i < vcrypto->max_data_queues; i++)
|
||||
tasklet_kill(&vcrypto->data_vq[i].done_task);
|
||||
cancel_work_sync(&vcrypto->data_vq[i].done_work);
|
||||
virtio_reset_device(vdev);
|
||||
virtcrypto_free_unused_reqs(vcrypto);
|
||||
virtcrypto_clear_crypto_engines(vcrypto);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user