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 <[email protected]>
---
 Hi, I'm working on converting tasklet usages to the BH WQ API.

 The virtio-crypto driver uses a tasklet per data queue to process
 completed crypto operations in BH context. This converts that tasklet
 to use the BH workqueue infrastructure.

 This patch was tested by:
    - Building with allmodconfig: no new warnings (compared to v6.18)
    - Building with allyesconfig: no new warnings (compared to v6.18)
    - Booting defconfig kernel via vng and running `uname -a`:
    Linux virtme-ng 6.18.0-virtme #1 SMP PREEMPT_DYNAMIC 0 x86_64 GNU/Linux

 Maintainers can apply this directly to the crypto subsystem tree or ack
 it for the workqueue tree to carry.

 drivers/crypto/virtio/virtio_crypto_common.h |  3 ++-
 drivers/crypto/virtio/virtio_crypto_core.c   | 11 +++++------
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/crypto/virtio/virtio_crypto_common.h 
b/drivers/crypto/virtio/virtio_crypto_common.h
index 19c934af3df6..c758a5a37729 100644
--- a/drivers/crypto/virtio/virtio_crypto_common.h
+++ b/drivers/crypto/virtio/virtio_crypto_common.h
@@ -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 {
diff --git a/drivers/crypto/virtio/virtio_crypto_core.c 
b/drivers/crypto/virtio/virtio_crypto_core.c
index 3d241446099c..345d1f1ed195 100644
--- a/drivers/crypto/virtio/virtio_crypto_core.c
+++ b/drivers/crypto/virtio/virtio_crypto_core.c
@@ -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 int len;
@@ -91,7 +91,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)
@@ -145,8 +145,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);
@@ -497,7 +496,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);
-- 
2.52.0


Reply via email to