[PATCH] uacce: fix concurrency of fops_open and uacce_remove
From: Zhangfei Gao <zhangfei.gao@linaro.org>
Date: 2022-06-10 12:34:44
Also in:
linux-iommu, lkml
Subsystem:
char and misc drivers, the rest, uacce accelerator framework · Maintainers:
Arnd Bergmann, Greg Kroah-Hartman, Linus Torvalds, Zhangfei Gao, Zhou Wang
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 <shenyang39@huawei.com> Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org> --- 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