Commit a74aa967 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'char-misc-4.18-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc

Pull char/misc fixes from Greg KH:
 "Here are a few char/misc driver fixes for 4.18-rc5.

  The "largest" stuff here is fixes for the UIO changes in 4.18-rc1 that
  caused breakages for some people. Thanks to Xiubo Li for fixing them
  quickly. Other than that, minor fixes for thunderbolt, vmw_balloon,
  nvmem, mei, ibmasm, and mei drivers. There's also a MAINTAINERS update
  where Rafael is offering to help out with reviewing driver core
  patches.

  All of these have been in linux-next with no reported issues"

* tag 'char-misc-4.18-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc:
  nvmem: Don't let a NULL cell_id for nvmem_cell_get() crash us
  thunderbolt: Notify userspace when boot_acl is changed
  uio: fix crash after the device is unregistered
  uio: change to use the mutex lock instead of the spin lock
  uio: use request_threaded_irq instead
  fpga: altera-cvp: Fix an error handling path in 'altera_cvp_probe()'
  ibmasm: don't write out of bounds in read handler
  MAINTAINERS: Add myself as driver core changes reviewer
  mei: discard messages from not connected client during power down.
  vmw_balloon: fix inflation with batching
parents 1dc85ac2 87ed1405
......@@ -4460,6 +4460,7 @@ F: Documentation/blockdev/drbd/
DRIVER CORE, KOBJECTS, DEBUGFS AND SYSFS
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
R: "Rafael J. Wysocki" <rafael@kernel.org>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
S: Supported
F: Documentation/kobject.txt
......
......@@ -455,8 +455,10 @@ static int altera_cvp_probe(struct pci_dev *pdev,
mgr = fpga_mgr_create(&pdev->dev, conf->mgr_name,
&altera_cvp_ops, conf);
if (!mgr)
return -ENOMEM;
if (!mgr) {
ret = -ENOMEM;
goto err_unmap;
}
pci_set_drvdata(pdev, mgr);
......
......@@ -507,35 +507,14 @@ static int remote_settings_file_close(struct inode *inode, struct file *file)
static ssize_t remote_settings_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
{
void __iomem *address = (void __iomem *)file->private_data;
unsigned char *page;
int retval;
int len = 0;
unsigned int value;
if (*offset < 0)
return -EINVAL;
if (count == 0 || count > 1024)
return 0;
if (*offset != 0)
return 0;
page = (unsigned char *)__get_free_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
char lbuf[20];
value = readl(address);
len = sprintf(page, "%d\n", value);
if (copy_to_user(buf, page, len)) {
retval = -EFAULT;
goto exit;
}
*offset += len;
retval = len;
len = snprintf(lbuf, sizeof(lbuf), "%d\n", value);
exit:
free_page((unsigned long)page);
return retval;
return simple_read_from_buffer(buf, count, offset, lbuf, len);
}
static ssize_t remote_settings_file_write(struct file *file, const char __user *ubuff, size_t count, loff_t *offset)
......
......@@ -310,8 +310,11 @@ int mei_irq_read_handler(struct mei_device *dev,
if (&cl->link == &dev->file_list) {
/* A message for not connected fixed address clients
* should be silently discarded
* On power down client may be force cleaned,
* silently discard such messages
*/
if (hdr_is_fixed(mei_hdr)) {
if (hdr_is_fixed(mei_hdr) ||
dev->dev_state == MEI_DEV_POWER_DOWN) {
mei_irq_discard_msg(dev, mei_hdr);
ret = 0;
goto reset_slots;
......
......@@ -467,7 +467,7 @@ static int vmballoon_send_batched_lock(struct vmballoon *b,
unsigned int num_pages, bool is_2m_pages, unsigned int *target)
{
unsigned long status;
unsigned long pfn = page_to_pfn(b->page);
unsigned long pfn = PHYS_PFN(virt_to_phys(b->batch_page));
STATS_INC(b->stats.lock[is_2m_pages]);
......@@ -515,7 +515,7 @@ static bool vmballoon_send_batched_unlock(struct vmballoon *b,
unsigned int num_pages, bool is_2m_pages, unsigned int *target)
{
unsigned long status;
unsigned long pfn = page_to_pfn(b->page);
unsigned long pfn = PHYS_PFN(virt_to_phys(b->batch_page));
STATS_INC(b->stats.unlock[is_2m_pages]);
......
......@@ -936,6 +936,10 @@ struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *cell_id)
return cell;
}
/* NULL cell_id only allowed for device tree; invalid otherwise */
if (!cell_id)
return ERR_PTR(-EINVAL);
return nvmem_cell_get_from_list(cell_id);
}
EXPORT_SYMBOL_GPL(nvmem_cell_get);
......
......@@ -213,6 +213,10 @@ static ssize_t boot_acl_store(struct device *dev, struct device_attribute *attr,
goto err_free_acl;
}
ret = tb->cm_ops->set_boot_acl(tb, acl, tb->nboot_acl);
if (!ret) {
/* Notify userspace about the change */
kobject_uevent(&tb->dev.kobj, KOBJ_CHANGE);
}
mutex_unlock(&tb->lock);
err_free_acl:
......
......@@ -215,7 +215,20 @@ 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);
int ret;
mutex_lock(&idev->info_lock);
if (!idev->info) {
ret = -EINVAL;
dev_err(dev, "the device has been unregistered\n");
goto out;
}
ret = sprintf(buf, "%s\n", idev->info->name);
out:
mutex_unlock(&idev->info_lock);
return ret;
}
static DEVICE_ATTR_RO(name);
......@@ -223,7 +236,20 @@ 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);
int ret;
mutex_lock(&idev->info_lock);
if (!idev->info) {
ret = -EINVAL;
dev_err(dev, "the device has been unregistered\n");
goto out;
}
ret = sprintf(buf, "%s\n", idev->info->version);
out:
mutex_unlock(&idev->info_lock);
return ret;
}
static DEVICE_ATTR_RO(version);
......@@ -415,11 +441,15 @@ EXPORT_SYMBOL_GPL(uio_event_notify);
static irqreturn_t uio_interrupt(int irq, void *dev_id)
{
struct uio_device *idev = (struct uio_device *)dev_id;
irqreturn_t ret = idev->info->handler(irq, idev->info);
irqreturn_t ret;
mutex_lock(&idev->info_lock);
ret = idev->info->handler(irq, idev->info);
if (ret == IRQ_HANDLED)
uio_event_notify(idev->info);
mutex_unlock(&idev->info_lock);
return ret;
}
......@@ -433,7 +463,6 @@ static int uio_open(struct inode *inode, struct file *filep)
struct uio_device *idev;
struct uio_listener *listener;
int ret = 0;
unsigned long flags;
mutex_lock(&minor_lock);
idev = idr_find(&uio_idr, iminor(inode));
......@@ -460,10 +489,16 @@ static int uio_open(struct inode *inode, struct file *filep)
listener->event_count = atomic_read(&idev->event);
filep->private_data = listener;
spin_lock_irqsave(&idev->info_lock, flags);
mutex_lock(&idev->info_lock);
if (!idev->info) {
mutex_unlock(&idev->info_lock);
ret = -EINVAL;
goto err_alloc_listener;
}
if (idev->info && idev->info->open)
ret = idev->info->open(idev->info, inode);
spin_unlock_irqrestore(&idev->info_lock, flags);
mutex_unlock(&idev->info_lock);
if (ret)
goto err_infoopen;
......@@ -495,12 +530,11 @@ static int uio_release(struct inode *inode, struct file *filep)
int ret = 0;
struct uio_listener *listener = filep->private_data;
struct uio_device *idev = listener->dev;
unsigned long flags;
spin_lock_irqsave(&idev->info_lock, flags);
mutex_lock(&idev->info_lock);
if (idev->info && idev->info->release)
ret = idev->info->release(idev->info, inode);
spin_unlock_irqrestore(&idev->info_lock, flags);
mutex_unlock(&idev->info_lock);
module_put(idev->owner);
kfree(listener);
......@@ -513,12 +547,11 @@ static __poll_t uio_poll(struct file *filep, poll_table *wait)
struct uio_listener *listener = filep->private_data;
struct uio_device *idev = listener->dev;
__poll_t ret = 0;
unsigned long flags;
spin_lock_irqsave(&idev->info_lock, flags);
mutex_lock(&idev->info_lock);
if (!idev->info || !idev->info->irq)
ret = -EIO;
spin_unlock_irqrestore(&idev->info_lock, flags);
mutex_unlock(&idev->info_lock);
if (ret)
return ret;
......@@ -537,12 +570,11 @@ static ssize_t uio_read(struct file *filep, char __user *buf,
DECLARE_WAITQUEUE(wait, current);
ssize_t retval = 0;
s32 event_count;
unsigned long flags;
spin_lock_irqsave(&idev->info_lock, flags);
mutex_lock(&idev->info_lock);
if (!idev->info || !idev->info->irq)
retval = -EIO;
spin_unlock_irqrestore(&idev->info_lock, flags);
mutex_unlock(&idev->info_lock);
if (retval)
return retval;
......@@ -592,9 +624,13 @@ static ssize_t uio_write(struct file *filep, const char __user *buf,
struct uio_device *idev = listener->dev;
ssize_t retval;
s32 irq_on;
unsigned long flags;
spin_lock_irqsave(&idev->info_lock, flags);
mutex_lock(&idev->info_lock);
if (!idev->info) {
retval = -EINVAL;
goto out;
}
if (!idev->info || !idev->info->irq) {
retval = -EIO;
goto out;
......@@ -618,7 +654,7 @@ static ssize_t uio_write(struct file *filep, const char __user *buf,
retval = idev->info->irqcontrol(idev->info, irq_on);
out:
spin_unlock_irqrestore(&idev->info_lock, flags);
mutex_unlock(&idev->info_lock);
return retval ? retval : sizeof(s32);
}
......@@ -640,10 +676,20 @@ static vm_fault_t uio_vma_fault(struct vm_fault *vmf)
struct page *page;
unsigned long offset;
void *addr;
int ret = 0;
int mi;
int mi = uio_find_mem_index(vmf->vma);
if (mi < 0)
return VM_FAULT_SIGBUS;
mutex_lock(&idev->info_lock);
if (!idev->info) {
ret = VM_FAULT_SIGBUS;
goto out;
}
mi = uio_find_mem_index(vmf->vma);
if (mi < 0) {
ret = VM_FAULT_SIGBUS;
goto out;
}
/*
* We need to subtract mi because userspace uses offset = N*PAGE_SIZE
......@@ -658,7 +704,11 @@ static vm_fault_t uio_vma_fault(struct vm_fault *vmf)
page = vmalloc_to_page(addr);
get_page(page);
vmf->page = page;
return 0;
out:
mutex_unlock(&idev->info_lock);
return ret;
}
static const struct vm_operations_struct uio_logical_vm_ops = {
......@@ -683,6 +733,7 @@ static int uio_mmap_physical(struct vm_area_struct *vma)
struct uio_device *idev = vma->vm_private_data;
int mi = uio_find_mem_index(vma);
struct uio_mem *mem;
if (mi < 0)
return -EINVAL;
mem = idev->info->mem + mi;
......@@ -724,30 +775,46 @@ static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
vma->vm_private_data = idev;
mutex_lock(&idev->info_lock);
if (!idev->info) {
ret = -EINVAL;
goto out;
}
mi = uio_find_mem_index(vma);
if (mi < 0)
return -EINVAL;
if (mi < 0) {
ret = -EINVAL;
goto out;
}
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)
return -EINVAL;
if (requested_pages > actual_pages) {
ret = -EINVAL;
goto out;
}
if (idev->info->mmap) {
ret = idev->info->mmap(idev->info, vma);
return ret;
goto out;
}
switch (idev->info->mem[mi].memtype) {
case UIO_MEM_PHYS:
return uio_mmap_physical(vma);
ret = uio_mmap_physical(vma);
break;
case UIO_MEM_LOGICAL:
case UIO_MEM_VIRTUAL:
return uio_mmap_logical(vma);
ret = uio_mmap_logical(vma);
break;
default:
return -EINVAL;
ret = -EINVAL;
}
out:
mutex_unlock(&idev->info_lock);
return 0;
}
static const struct file_operations uio_fops = {
......@@ -865,7 +932,7 @@ int __uio_register_device(struct module *owner,
idev->owner = owner;
idev->info = info;
spin_lock_init(&idev->info_lock);
mutex_init(&idev->info_lock);
init_waitqueue_head(&idev->wait);
atomic_set(&idev->event, 0);
......@@ -902,8 +969,9 @@ int __uio_register_device(struct module *owner,
* 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);
ret = request_threaded_irq(info->irq, NULL, uio_interrupt,
info->irq_flags, info->name, idev);
if (ret)
goto err_request_irq;
}
......@@ -928,7 +996,6 @@ EXPORT_SYMBOL_GPL(__uio_register_device);
void uio_unregister_device(struct uio_info *info)
{
struct uio_device *idev;
unsigned long flags;
if (!info || !info->uio_dev)
return;
......@@ -937,14 +1004,14 @@ void uio_unregister_device(struct uio_info *info)
uio_free_minor(idev);
mutex_lock(&idev->info_lock);
uio_dev_del_attributes(idev);
if (info->irq && info->irq != UIO_IRQ_CUSTOM)
free_irq(info->irq, idev);
spin_lock_irqsave(&idev->info_lock, flags);
idev->info = NULL;
spin_unlock_irqrestore(&idev->info_lock, flags);
mutex_unlock(&idev->info_lock);
device_unregister(&idev->dev);
......
......@@ -75,7 +75,7 @@ struct uio_device {
struct fasync_struct *async_queue;
wait_queue_head_t wait;
struct uio_info *info;
spinlock_t info_lock;
struct mutex info_lock;
struct kobject *map_dir;
struct kobject *portio_dir;
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment