From: JiangShui Yang yangjiangshui@h-partners.com
Weili Qian (3): uacce: fix NULL pointer when unbind device uacce: cleanup some unused codes uacce: remove unused file 'dev_state'
drivers/crypto/hisilicon/qm.c | 12 ----- drivers/misc/uacce/uacce.c | 87 +++++++++++------------------------ include/linux/uacce.h | 17 ------- 3 files changed, 27 insertions(+), 89 deletions(-)
driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I867RA CVE: NA
----------------------------------------------------------------------
When the user space process and 'unbind' device operations are performed at the same time, the 'unbind' operation may be completed before the memory is unmap(uacce_vma_close()). Since 'uacce->parent' is set to NULL in uacce_remove(), 'pdev->driver' will trigger panic in uacce_free_dma_buffers(). Therefore, the memory release process is added to uacce_remove(), and uacce->mutex ensures that the memory is released only once.
Signed-off-by: Weili Qian qianweili@huawei.com Signed-off-by: JiangShui Yang yangjiangshui@h-partners.com --- drivers/misc/uacce/uacce.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-)
diff --git a/drivers/misc/uacce/uacce.c b/drivers/misc/uacce/uacce.c index bb4af54c0386..d00a5d98980e 100644 --- a/drivers/misc/uacce/uacce.c +++ b/drivers/misc/uacce/uacce.c @@ -199,11 +199,9 @@ static void uacce_free_dma_buffers(struct uacce_queue *q) struct device *pdev = q->uacce->parent; int i = 0;
- if (module_refcount(pdev->driver->owner) > 0) - module_put(pdev->driver->owner); - if (!qfr->dma_list) return; + while (i < qfr->dma_list[0].total_num) { WARN_ON(!qfr->dma_list[i].size || !qfr->dma_list[i].dma); dev_dbg(pdev, "free dma qfr (index = %d)\n", i); @@ -368,18 +366,19 @@ static int uacce_fops_open(struct inode *inode, struct file *filep) static int uacce_fops_release(struct inode *inode, struct file *filep) { struct uacce_queue *q = filep->private_data; - struct uacce_qfile_region *ss = q->qfrs[UACCE_QFRT_SS]; struct uacce_device *uacce = q->uacce; + struct uacce_qfile_region *ss;
mutex_lock(&uacce->mutex); uacce_put_queue(q); uacce_unbind_queue(q); - list_del(&q->list); - mutex_unlock(&uacce->mutex); + ss = q->qfrs[UACCE_QFRT_SS]; if (ss && ss != &noiommu_ss_default_qfr) { uacce_free_dma_buffers(q); kfree(ss); } + list_del(&q->list); + mutex_unlock(&uacce->mutex); kfree(q);
return 0; @@ -403,14 +402,22 @@ static void uacce_vma_close(struct vm_area_struct *vma)
if (qfr->type == UACCE_QFRT_SS && atomic_read(¤t->active_mm->mm_users) > 0) { + /* + * uacce_vma_close() and uacce_remove() may be executed concurrently. + * To avoid accessing the same address at the same time, takes the uacce->mutex. + */ + mutex_lock(&uacce->mutex); if ((q->state == UACCE_Q_STARTED) && uacce->ops->stop_queue) uacce->ops->stop_queue(q); uacce_free_dma_buffers(q); - kfree(qfr); q->qfrs[vma->vm_pgoff] = NULL; - } else if (qfr->type != UACCE_QFRT_SS) { + mutex_unlock(&uacce->mutex); kfree(qfr); + } else if (qfr->type != UACCE_QFRT_SS) { + mutex_lock(&q->mutex); q->qfrs[vma->vm_pgoff] = NULL; + mutex_unlock(&q->mutex); + kfree(qfr); } }
@@ -522,7 +529,6 @@ static int uacce_alloc_dma_buffers(struct uacce_queue *q, if (!slice) return -ENOMEM;
- (void)try_module_get(pdev->driver->owner); qfr->dma_list = slice; for (i = 0; i < ss_num; i++) { if (start + max_size > vma->vm_end) @@ -1047,6 +1053,7 @@ void uacce_remove(struct uacce_device *uacce) mutex_lock(&uacce->mutex); /* ensure no open queue remains */ list_for_each_entry_safe(q, next_q, &uacce->queues, list) { + struct uacce_qfile_region *ss = q->qfrs[UACCE_QFRT_SS]; /* * Taking q->mutex ensures that fops do not use the defunct * uacce->ops after the queue is disabled. @@ -1061,6 +1068,8 @@ void uacce_remove(struct uacce_device *uacce) * access the mmaped area while parent device is already removed */ unmap_mapping_range(q->mapping, 0, 0, 1); + if (ss && ss != &noiommu_ss_default_qfr) + uacce_free_dma_buffers(q); }
/* disable sva now since no opened queues */
driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I867RA CVE: NA
----------------------------------------------------------------------
1.Remove unmatched comments. 2.Remove unused struct uacce_err_isolate. 3.Remove unused ops 'dump_queue'. 4.Remove unused function dev_to uacce(). 5.Use jump labels in uacce_alloc_dma_buffers(), remove jump labels in uacce_init().
Signed-off-by: Weili Qian qianweili@huawei.com Signed-off-by: JiangShui Yang yangjiangshui@h-partners.com --- drivers/misc/uacce/uacce.c | 50 +++++++------------------------------- include/linux/uacce.h | 16 ------------ 2 files changed, 9 insertions(+), 57 deletions(-)
diff --git a/drivers/misc/uacce/uacce.c b/drivers/misc/uacce/uacce.c index d00a5d98980e..7bdccfe6f5f9 100644 --- a/drivers/misc/uacce/uacce.c +++ b/drivers/misc/uacce/uacce.c @@ -18,38 +18,6 @@ static struct uacce_qfile_region noiommu_ss_default_qfr = { .type = UACCE_QFRT_SS, };
-static int cdev_get(struct device *dev, void *data) -{ - struct uacce_device *uacce; - struct device **t_dev = data; - - uacce = container_of(dev, struct uacce_device, dev); - if (uacce->parent == *t_dev) { - *t_dev = dev; - return 1; - } - - return 0; -} - -/** - * dev_to_uacce - Get structure uacce device from its parent device - * @dev: the device - */ -struct uacce_device *dev_to_uacce(struct device *dev) -{ - struct device **tdev = &dev; - int ret; - - ret = class_for_each_device(uacce_class, NULL, tdev, cdev_get); - if (ret) { - dev = *tdev; - return container_of(dev, struct uacce_device, dev); - } - return NULL; -} -EXPORT_SYMBOL_GPL(dev_to_uacce); - /* * If the parent driver or the device disappears, the queue state is invalid and * ops are not usable anymore. @@ -544,8 +512,8 @@ static int uacce_alloc_dma_buffers(struct uacce_queue *q, dev_err(pdev, "get dma slice(sz = %lu,slice num = %d) fail!\n", size, i); slice[0].total_num = i; - uacce_free_dma_buffers(q); - return -ENOMEM; + ret = -ENOMEM; + goto free_buffer; } slice[i].size = (size + PAGE_SIZE - 1) & PAGE_MASK; slice[i].total_num = ss_num; @@ -556,11 +524,15 @@ static int uacce_alloc_dma_buffers(struct uacce_queue *q, &slice[ss_num]); if (ret) { dev_err(pdev, "failed to sort dma buffers.\n"); - uacce_free_dma_buffers(q); - return ret; + goto free_buffer; }
return 0; + +free_buffer: + uacce_free_dma_buffers(q); + + return ret; }
static int uacce_mmap_dma_buffers(struct uacce_queue *q, @@ -1099,12 +1071,8 @@ static int __init uacce_init(void)
ret = alloc_chrdev_region(&uacce_devt, 0, MINORMASK, UACCE_NAME); if (ret) - goto destroy_class; + class_destroy(uacce_class);
- return 0; - -destroy_class: - class_destroy(uacce_class); return ret; }
diff --git a/include/linux/uacce.h b/include/linux/uacce.h index 8a4bb77b1bc8..07a96a771da9 100644 --- a/include/linux/uacce.h +++ b/include/linux/uacce.h @@ -17,11 +17,6 @@ struct uacce_queue; struct uacce_device;
-struct uacce_err_isolate { - u32 hw_err_isolate_hz; /* user cfg freq which triggers isolation */ - atomic_t is_isolate; -}; - struct uacce_dma_slice { void *kaddr; /* kernel address for ss */ dma_addr_t dma; /* dma address, if created by dma api */ @@ -52,14 +47,11 @@ struct uacce_qfile_region { * @start_queue: make the queue start work after get_queue * @stop_queue: make the queue stop work before put_queue * @is_q_updated: check whether the task is finished - * @mask_notify: mask the task irq of queue * @mmap: mmap addresses of queue to user space * @ioctl: ioctl for user space users of the queue * @get_isolate_state: get the device state after set the isolate strategy * @isolate_err_threshold_write: stored the isolate error threshold to the device * @isolate_err_threshold_read: read the isolate error threshold value from the device - * @reset: reset the WD device - * @reset_queue: reset the queue */ struct uacce_ops { int (*get_available_instances)(struct uacce_device *uacce); @@ -68,7 +60,6 @@ struct uacce_ops { void (*put_queue)(struct uacce_queue *q); int (*start_queue)(struct uacce_queue *q); void (*stop_queue)(struct uacce_queue *q); - void (*dump_queue)(const struct uacce_queue *q); int (*is_q_updated)(struct uacce_queue *q); int (*mmap)(struct uacce_queue *q, struct vm_area_struct *vma, struct uacce_qfile_region *qfr); @@ -163,7 +154,6 @@ struct uacce_device { struct device dev; struct mutex mutex; void *priv; - struct uacce_err_isolate *isolate; struct list_head queues; };
@@ -173,7 +163,6 @@ struct uacce_device *uacce_alloc(struct device *parent, struct uacce_interface *interface); int uacce_register(struct uacce_device *uacce); void uacce_remove(struct uacce_device *uacce); -struct uacce_device *dev_to_uacce(struct device *dev); void uacce_wake_up(struct uacce_queue *q); #else /* CONFIG_UACCE */
@@ -190,11 +179,6 @@ static inline int uacce_register(struct uacce_device *uacce) }
static inline void uacce_remove(struct uacce_device *uacce) {} - -static inline struct uacce_device *dev_to_uacce(struct device *dev) -{ - return NULL; -} static inline void uacce_wake_up(struct uacce_queue *q) {} #endif /* CONFIG_UACCE */
driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I867RA CVE: NA
----------------------------------------------------------------------
Remove 'dev_state' since it is not in use.
Signed-off-by: Weili Qian qianweili@huawei.com Signed-off-by: JiangShui Yang yangjiangshui@h-partners.com --- drivers/crypto/hisilicon/qm.c | 12 ------------ drivers/misc/uacce/uacce.c | 10 ---------- include/linux/uacce.h | 1 - 3 files changed, 23 deletions(-)
diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index f428850a376d..1a39f3166a66 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -2571,17 +2571,6 @@ static long hisi_qm_uacce_ioctl(struct uacce_queue *q, unsigned int cmd, return -EINVAL; }
-static enum uacce_dev_state hisi_qm_get_state(struct uacce_device *uacce) -{ - struct hisi_qm *qm = uacce->priv; - enum qm_state curr; - - curr = atomic_read(&qm->status.flags); - if (curr == QM_STOP) - return UACCE_DEV_ERR; - - return UACCE_DEV_NORMAL; -} static void qm_uacce_api_ver_init(struct hisi_qm *qm) { struct uacce_device *uacce = qm->uacce; @@ -2758,7 +2747,6 @@ static const struct uacce_ops uacce_qm_ops = { .stop_queue = hisi_qm_uacce_stop_queue, .mmap = hisi_qm_uacce_mmap, .ioctl = hisi_qm_uacce_ioctl, - .get_dev_state = hisi_qm_get_state, .is_q_updated = hisi_qm_is_q_updated, .get_isolate_state = hisi_qm_get_isolate_state, .isolate_err_threshold_write = hisi_qm_isolate_threshold_write, diff --git a/drivers/misc/uacce/uacce.c b/drivers/misc/uacce/uacce.c index 7bdccfe6f5f9..687b7fad9a29 100644 --- a/drivers/misc/uacce/uacce.c +++ b/drivers/misc/uacce/uacce.c @@ -795,14 +795,6 @@ static ssize_t isolate_strategy_store(struct device *dev, struct device_attribut return count; }
-static ssize_t dev_state_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct uacce_device *uacce = to_uacce_device(dev); - - return sysfs_emit(buf, "%d\n", uacce->ops->get_dev_state(uacce)); -} - static ssize_t node_id_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -839,7 +831,6 @@ static DEVICE_ATTR_RO(region_mmio_size); static DEVICE_ATTR_RO(region_dus_size); static DEVICE_ATTR_RO(isolate); static DEVICE_ATTR_RW(isolate_strategy); -static DEVICE_ATTR_RO(dev_state); static DEVICE_ATTR_RO(numa_distance);
static struct attribute *uacce_dev_attrs[] = { @@ -852,7 +843,6 @@ static struct attribute *uacce_dev_attrs[] = { &dev_attr_region_dus_size.attr, &dev_attr_isolate.attr, &dev_attr_isolate_strategy.attr, - &dev_attr_dev_state.attr, &dev_attr_numa_distance.attr, NULL, }; diff --git a/include/linux/uacce.h b/include/linux/uacce.h index 07a96a771da9..fca9cb703e53 100644 --- a/include/linux/uacce.h +++ b/include/linux/uacce.h @@ -68,7 +68,6 @@ struct uacce_ops { enum uacce_dev_state (*get_isolate_state)(struct uacce_device *uacce); int (*isolate_err_threshold_write)(struct uacce_device *uacce, u32 num); u32 (*isolate_err_threshold_read)(struct uacce_device *uacce); - enum uacce_dev_state (*get_dev_state)(struct uacce_device *uacce); };
/**
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,转换为PR失败! 邮件列表地址:https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/2... 失败原因:应用补丁/补丁集失败,Patch failed at 0001 uacce: fix NULL pointer when unbind device 建议解决方法:请查看失败原因, 确认补丁是否可以应用在当前期望分支的最新代码上
FeedBack: The patch(es) which you have sent to kernel@openeuler.org has been converted to PR failed! Mailing list address: https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/2... Failed Reason: apply patch(es) failed, Patch failed at 0001 uacce: fix NULL pointer when unbind device Suggest Solution: please checkout if the failed patch(es) can work on the newest codes in expected branch