--- zzzz-none-000/linux-3.10.107/drivers/uio/uio.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/uio/uio.c 2021-02-04 17:41:59.000000000 +0000 @@ -28,19 +28,6 @@ #define UIO_MAX_DEVICES (1U << MINORBITS) -struct uio_device { - struct module *owner; - struct device *dev; - int minor; - atomic_t event; - struct fasync_struct *async_queue; - wait_queue_head_t wait; - int vma_count; - struct uio_info *info; - struct kobject *map_dir; - struct kobject *portio_dir; -}; - static int uio_major; static struct cdev *uio_cdev; static DEFINE_IDR(uio_idr); @@ -69,12 +56,12 @@ static ssize_t map_addr_show(struct uio_mem *mem, char *buf) { - return sprintf(buf, "0x%llx\n", (unsigned long long)mem->addr); + return sprintf(buf, "%pa\n", &mem->addr); } static ssize_t map_size_show(struct uio_mem *mem, char *buf) { - return sprintf(buf, "0x%lx\n", mem->size); + return sprintf(buf, "%pa\n", &mem->size); } static ssize_t map_offset_show(struct uio_mem *mem, char *buf) @@ -224,38 +211,42 @@ .default_attrs = portio_attrs, }; -static ssize_t show_name(struct device *dev, +static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf) { struct uio_device *idev = dev_get_drvdata(dev); return sprintf(buf, "%s\n", idev->info->name); } +static DEVICE_ATTR_RO(name); -static ssize_t show_version(struct device *dev, +static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf) { struct uio_device *idev = dev_get_drvdata(dev); return sprintf(buf, "%s\n", idev->info->version); } +static DEVICE_ATTR_RO(version); -static ssize_t show_event(struct device *dev, +static ssize_t event_show(struct device *dev, struct device_attribute *attr, char *buf) { struct uio_device *idev = dev_get_drvdata(dev); return sprintf(buf, "%u\n", (unsigned int)atomic_read(&idev->event)); } +static DEVICE_ATTR_RO(event); -static struct device_attribute uio_class_attributes[] = { - __ATTR(name, S_IRUGO, show_name, NULL), - __ATTR(version, S_IRUGO, show_version, NULL), - __ATTR(event, S_IRUGO, show_event, NULL), - {} +static struct attribute *uio_attrs[] = { + &dev_attr_name.attr, + &dev_attr_version.attr, + &dev_attr_event.attr, + NULL, }; +ATTRIBUTE_GROUPS(uio); /* UIO class infrastructure */ static struct class uio_class = { .name = "uio", - .dev_attrs = uio_class_attributes, + .dev_groups = uio_groups, }; /* @@ -285,13 +276,13 @@ } map = kzalloc(sizeof(*map), GFP_KERNEL); if (!map) - goto err_map; + goto err_map_kobj; kobject_init(&map->kobj, &map_attr_type); map->mem = mem; mem->map = map; ret = kobject_add(&map->kobj, idev->map_dir, "map%d", mi); if (ret) - goto err_map; + goto err_map_kobj; ret = kobject_uevent(&map->kobj, KOBJ_ADD); if (ret) goto err_map; @@ -310,14 +301,14 @@ } portio = kzalloc(sizeof(*portio), GFP_KERNEL); if (!portio) - goto err_portio; + goto err_portio_kobj; kobject_init(&portio->kobj, &portio_attr_type); portio->port = port; port->portio = portio; ret = kobject_add(&portio->kobj, idev->portio_dir, "port%d", pi); if (ret) - goto err_portio; + goto err_portio_kobj; ret = kobject_uevent(&portio->kobj, KOBJ_ADD); if (ret) goto err_portio; @@ -326,14 +317,18 @@ return 0; err_portio: - for (pi--; pi >= 0; pi--) { + pi--; +err_portio_kobj: + for (; pi >= 0; pi--) { port = &idev->info->port[pi]; portio = port->portio; kobject_put(&portio->kobj); } kobject_put(idev->portio_dir); err_map: - for (mi--; mi>=0; mi--) { + mi--; +err_map_kobj: + for (; mi >= 0; mi--) { mem = &idev->info->mem[mi]; map = mem->map; kobject_put(&map->kobj); @@ -529,6 +524,7 @@ event_count = atomic_read(&idev->event); if (event_count != listener->event_count) { + __set_current_state(TASK_RUNNING); if (copy_to_user(buf, &event_count, count)) retval = -EFAULT; else { @@ -593,23 +589,12 @@ return -1; } -static void uio_vma_open(struct vm_area_struct *vma) -{ - struct uio_device *idev = vma->vm_private_data; - idev->vma_count++; -} - -static void uio_vma_close(struct vm_area_struct *vma) -{ - struct uio_device *idev = vma->vm_private_data; - idev->vma_count--; -} - static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct uio_device *idev = vma->vm_private_data; struct page *page; unsigned long offset; + void *addr; int mi = uio_find_mem_index(vma); if (mi < 0) @@ -621,18 +606,17 @@ */ offset = (vmf->pgoff - mi) << PAGE_SHIFT; + addr = (void *)(unsigned long)idev->info->mem[mi].addr + offset; if (idev->info->mem[mi].memtype == UIO_MEM_LOGICAL) - page = virt_to_page(idev->info->mem[mi].addr + offset); + page = virt_to_page(addr); else - page = vmalloc_to_page((void *)(unsigned long)idev->info->mem[mi].addr + offset); + page = vmalloc_to_page(addr); get_page(page); vmf->page = page; return 0; } static const struct vm_operations_struct uio_logical_vm_ops = { - .open = uio_vma_open, - .close = uio_vma_close, .fault = uio_vma_fault, }; @@ -640,7 +624,6 @@ { vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; vma->vm_ops = &uio_logical_vm_ops; - uio_vma_open(vma); return 0; } @@ -659,6 +642,8 @@ return -EINVAL; mem = idev->info->mem + mi; + if (mem->addr & ~PAGE_MASK) + return -ENODEV; if (vma->vm_end - vma->vm_start > mem->size) return -EINVAL; @@ -698,7 +683,7 @@ if (mi < 0) return -EINVAL; - requested_pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; + requested_pages = vma_pages(vma); actual_pages = ((idev->info->mem[mi].addr & ~PAGE_MASK) + idev->info->mem[mi].size + PAGE_SIZE -1) >> PAGE_SHIFT; if (requested_pages > actual_pages) @@ -821,10 +806,9 @@ info->uio_dev = NULL; - idev = kzalloc(sizeof(*idev), GFP_KERNEL); + idev = devm_kzalloc(parent, sizeof(*idev), GFP_KERNEL); if (!idev) { - ret = -ENOMEM; - goto err_kzalloc; + return -ENOMEM; } idev->owner = owner; @@ -834,7 +818,7 @@ ret = uio_get_minor(idev); if (ret) - goto err_get_minor; + return ret; idev->dev = device_create(&uio_class, parent, MKDEV(uio_major, idev->minor), idev, @@ -852,6 +836,14 @@ info->uio_dev = idev; if (info->irq && (info->irq != UIO_IRQ_CUSTOM)) { + /* + * Note that we deliberately don't use devm_request_irq + * here. The parent module can unregister the UIO device + * and call pci_disable_msi, which requires that this + * irq has been freed. However, the device may have open + * FDs at the time of unregister and therefore may not be + * freed until they are released. + */ ret = request_irq(info->irq, uio_interrupt, info->irq_flags, info->name, idev); if (ret) @@ -866,9 +858,6 @@ device_destroy(&uio_class, MKDEV(uio_major, idev->minor)); err_device_create: uio_free_minor(idev); -err_get_minor: - kfree(idev); -err_kzalloc: return ret; } EXPORT_SYMBOL_GPL(__uio_register_device); @@ -889,13 +878,12 @@ uio_free_minor(idev); - if (info->irq && (info->irq != UIO_IRQ_CUSTOM)) - free_irq(info->irq, idev); - uio_dev_del_attributes(idev); + if (info->irq && info->irq != UIO_IRQ_CUSTOM) + free_irq(info->irq, idev); + device_destroy(&uio_class, MKDEV(uio_major, idev->minor)); - kfree(idev); return; } @@ -909,6 +897,7 @@ static void __exit uio_exit(void) { release_uio_class(); + idr_destroy(&uio_idr); } module_init(uio_init)