The uacce parent's module can be removed when uacce is working,
which may cause troubles.

If rmmod/uacce_remove happens just after fops_open: bind_queue,
the uacce_remove can not remove the bound queue since it is not
added to the queue list yet, which blocks the uacce_disable_sva.

Change queues_lock area to make sure the bound queue is added to
the list thereby can be searched in uacce_remove.

And uacce->parent->driver is checked immediately in case rmmod is
just happening.

Also the parent driver must always stop DMA before calling
uacce_remove.

Signed-off-by: Yang Shen <[email protected]>
Signed-off-by: Zhangfei Gao <[email protected]>
---
 drivers/misc/uacce/uacce.c | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/drivers/misc/uacce/uacce.c b/drivers/misc/uacce/uacce.c
index 281c54003edc..b6219c6bfb48 100644
--- a/drivers/misc/uacce/uacce.c
+++ b/drivers/misc/uacce/uacce.c
@@ -136,9 +136,16 @@ static int uacce_fops_open(struct inode *inode, struct 
file *filep)
        if (!q)
                return -ENOMEM;
 
+       mutex_lock(&uacce->queues_lock);
+
+       if (!uacce->parent->driver) {
+               ret = -ENODEV;
+               goto out_with_lock;
+       }
+
        ret = uacce_bind_queue(uacce, q);
        if (ret)
-               goto out_with_mem;
+               goto out_with_lock;
 
        q->uacce = uacce;
 
@@ -153,7 +160,6 @@ static int uacce_fops_open(struct inode *inode, struct file 
*filep)
        uacce->inode = inode;
        q->state = UACCE_Q_INIT;
 
-       mutex_lock(&uacce->queues_lock);
        list_add(&q->list, &uacce->queues);
        mutex_unlock(&uacce->queues_lock);
 
@@ -161,7 +167,8 @@ static int uacce_fops_open(struct inode *inode, struct file 
*filep)
 
 out_with_bond:
        uacce_unbind_queue(q);
-out_with_mem:
+out_with_lock:
+       mutex_unlock(&uacce->queues_lock);
        kfree(q);
        return ret;
 }
@@ -171,10 +178,10 @@ static int uacce_fops_release(struct inode *inode, struct 
file *filep)
        struct uacce_queue *q = filep->private_data;
 
        mutex_lock(&q->uacce->queues_lock);
-       list_del(&q->list);
-       mutex_unlock(&q->uacce->queues_lock);
        uacce_put_queue(q);
        uacce_unbind_queue(q);
+       list_del(&q->list);
+       mutex_unlock(&q->uacce->queues_lock);
        kfree(q);
 
        return 0;
@@ -513,10 +520,10 @@ void uacce_remove(struct uacce_device *uacce)
                uacce_put_queue(q);
                uacce_unbind_queue(q);
        }
-       mutex_unlock(&uacce->queues_lock);
 
        /* disable sva now since no opened queues */
        uacce_disable_sva(uacce);
+       mutex_unlock(&uacce->queues_lock);
 
        if (uacce->cdev)
                cdev_device_del(uacce->cdev, &uacce->dev);
-- 
2.36.1

_______________________________________________
iommu mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Reply via email to