1
0
Fork 0

Char/Misc fixes for 4.18-rc5

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.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCW0Xg+Q8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ynuzwCeP5imDvO+/phRkeuwpchIusaBZDIAoIsVjdoa
 UXNqthmixT4kmZzkdw4/
 =NB+C
 -----END PGP SIGNATURE-----

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
hifive-unleashed-5.1
Linus Torvalds 2018-07-11 10:10:50 -07:00
commit a74aa9676c
9 changed files with 126 additions and 66 deletions

View File

@ -4460,6 +4460,7 @@ F: Documentation/blockdev/drbd/
DRIVER CORE, KOBJECTS, DEBUGFS AND SYSFS DRIVER CORE, KOBJECTS, DEBUGFS AND SYSFS
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> 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 T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
S: Supported S: Supported
F: Documentation/kobject.txt F: Documentation/kobject.txt

View File

@ -455,8 +455,10 @@ static int altera_cvp_probe(struct pci_dev *pdev,
mgr = fpga_mgr_create(&pdev->dev, conf->mgr_name, mgr = fpga_mgr_create(&pdev->dev, conf->mgr_name,
&altera_cvp_ops, conf); &altera_cvp_ops, conf);
if (!mgr) if (!mgr) {
return -ENOMEM; ret = -ENOMEM;
goto err_unmap;
}
pci_set_drvdata(pdev, mgr); pci_set_drvdata(pdev, mgr);

View File

@ -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) 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; void __iomem *address = (void __iomem *)file->private_data;
unsigned char *page;
int retval;
int len = 0; int len = 0;
unsigned int value; unsigned int value;
char lbuf[20];
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;
value = readl(address); value = readl(address);
len = sprintf(page, "%d\n", value); len = snprintf(lbuf, sizeof(lbuf), "%d\n", value);
if (copy_to_user(buf, page, len)) { return simple_read_from_buffer(buf, count, offset, lbuf, len);
retval = -EFAULT;
goto exit;
}
*offset += len;
retval = len;
exit:
free_page((unsigned long)page);
return retval;
} }
static ssize_t remote_settings_file_write(struct file *file, const char __user *ubuff, size_t count, loff_t *offset) static ssize_t remote_settings_file_write(struct file *file, const char __user *ubuff, size_t count, loff_t *offset)

View File

@ -310,8 +310,11 @@ int mei_irq_read_handler(struct mei_device *dev,
if (&cl->link == &dev->file_list) { if (&cl->link == &dev->file_list) {
/* A message for not connected fixed address clients /* A message for not connected fixed address clients
* should be silently discarded * 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); mei_irq_discard_msg(dev, mei_hdr);
ret = 0; ret = 0;
goto reset_slots; goto reset_slots;

View File

@ -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 int num_pages, bool is_2m_pages, unsigned int *target)
{ {
unsigned long status; 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]); 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 int num_pages, bool is_2m_pages, unsigned int *target)
{ {
unsigned long status; 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]); STATS_INC(b->stats.unlock[is_2m_pages]);

View File

@ -936,6 +936,10 @@ struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *cell_id)
return cell; 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); return nvmem_cell_get_from_list(cell_id);
} }
EXPORT_SYMBOL_GPL(nvmem_cell_get); EXPORT_SYMBOL_GPL(nvmem_cell_get);

View File

@ -213,6 +213,10 @@ static ssize_t boot_acl_store(struct device *dev, struct device_attribute *attr,
goto err_free_acl; goto err_free_acl;
} }
ret = tb->cm_ops->set_boot_acl(tb, acl, tb->nboot_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); mutex_unlock(&tb->lock);
err_free_acl: err_free_acl:

View File

@ -215,7 +215,20 @@ static ssize_t name_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct uio_device *idev = dev_get_drvdata(dev); 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); static DEVICE_ATTR_RO(name);
@ -223,7 +236,20 @@ static ssize_t version_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct uio_device *idev = dev_get_drvdata(dev); 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); 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) static irqreturn_t uio_interrupt(int irq, void *dev_id)
{ {
struct uio_device *idev = (struct uio_device *)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) if (ret == IRQ_HANDLED)
uio_event_notify(idev->info); uio_event_notify(idev->info);
mutex_unlock(&idev->info_lock);
return ret; return ret;
} }
@ -433,7 +463,6 @@ static int uio_open(struct inode *inode, struct file *filep)
struct uio_device *idev; struct uio_device *idev;
struct uio_listener *listener; struct uio_listener *listener;
int ret = 0; int ret = 0;
unsigned long flags;
mutex_lock(&minor_lock); mutex_lock(&minor_lock);
idev = idr_find(&uio_idr, iminor(inode)); 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); listener->event_count = atomic_read(&idev->event);
filep->private_data = listener; 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) if (idev->info && idev->info->open)
ret = idev->info->open(idev->info, inode); ret = idev->info->open(idev->info, inode);
spin_unlock_irqrestore(&idev->info_lock, flags); mutex_unlock(&idev->info_lock);
if (ret) if (ret)
goto err_infoopen; goto err_infoopen;
@ -495,12 +530,11 @@ static int uio_release(struct inode *inode, struct file *filep)
int ret = 0; int ret = 0;
struct uio_listener *listener = filep->private_data; struct uio_listener *listener = filep->private_data;
struct uio_device *idev = listener->dev; 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) if (idev->info && idev->info->release)
ret = idev->info->release(idev->info, inode); ret = idev->info->release(idev->info, inode);
spin_unlock_irqrestore(&idev->info_lock, flags); mutex_unlock(&idev->info_lock);
module_put(idev->owner); module_put(idev->owner);
kfree(listener); 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_listener *listener = filep->private_data;
struct uio_device *idev = listener->dev; struct uio_device *idev = listener->dev;
__poll_t ret = 0; __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) if (!idev->info || !idev->info->irq)
ret = -EIO; ret = -EIO;
spin_unlock_irqrestore(&idev->info_lock, flags); mutex_unlock(&idev->info_lock);
if (ret) if (ret)
return ret; return ret;
@ -537,12 +570,11 @@ static ssize_t uio_read(struct file *filep, char __user *buf,
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
ssize_t retval = 0; ssize_t retval = 0;
s32 event_count; s32 event_count;
unsigned long flags;
spin_lock_irqsave(&idev->info_lock, flags); mutex_lock(&idev->info_lock);
if (!idev->info || !idev->info->irq) if (!idev->info || !idev->info->irq)
retval = -EIO; retval = -EIO;
spin_unlock_irqrestore(&idev->info_lock, flags); mutex_unlock(&idev->info_lock);
if (retval) if (retval)
return 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; struct uio_device *idev = listener->dev;
ssize_t retval; ssize_t retval;
s32 irq_on; 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) { if (!idev->info || !idev->info->irq) {
retval = -EIO; retval = -EIO;
goto out; 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); retval = idev->info->irqcontrol(idev->info, irq_on);
out: out:
spin_unlock_irqrestore(&idev->info_lock, flags); mutex_unlock(&idev->info_lock);
return retval ? retval : sizeof(s32); return retval ? retval : sizeof(s32);
} }
@ -640,10 +676,20 @@ static vm_fault_t uio_vma_fault(struct vm_fault *vmf)
struct page *page; struct page *page;
unsigned long offset; unsigned long offset;
void *addr; void *addr;
int ret = 0;
int mi;
int mi = uio_find_mem_index(vmf->vma); mutex_lock(&idev->info_lock);
if (mi < 0) if (!idev->info) {
return VM_FAULT_SIGBUS; 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 * 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); page = vmalloc_to_page(addr);
get_page(page); get_page(page);
vmf->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 = { 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; struct uio_device *idev = vma->vm_private_data;
int mi = uio_find_mem_index(vma); int mi = uio_find_mem_index(vma);
struct uio_mem *mem; struct uio_mem *mem;
if (mi < 0) if (mi < 0)
return -EINVAL; return -EINVAL;
mem = idev->info->mem + mi; 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; vma->vm_private_data = idev;
mutex_lock(&idev->info_lock);
if (!idev->info) {
ret = -EINVAL;
goto out;
}
mi = uio_find_mem_index(vma); mi = uio_find_mem_index(vma);
if (mi < 0) if (mi < 0) {
return -EINVAL; ret = -EINVAL;
goto out;
}
requested_pages = vma_pages(vma); requested_pages = vma_pages(vma);
actual_pages = ((idev->info->mem[mi].addr & ~PAGE_MASK) actual_pages = ((idev->info->mem[mi].addr & ~PAGE_MASK)
+ idev->info->mem[mi].size + PAGE_SIZE -1) >> PAGE_SHIFT; + idev->info->mem[mi].size + PAGE_SIZE -1) >> PAGE_SHIFT;
if (requested_pages > actual_pages) if (requested_pages > actual_pages) {
return -EINVAL; ret = -EINVAL;
goto out;
}
if (idev->info->mmap) { if (idev->info->mmap) {
ret = idev->info->mmap(idev->info, vma); ret = idev->info->mmap(idev->info, vma);
return ret; goto out;
} }
switch (idev->info->mem[mi].memtype) { switch (idev->info->mem[mi].memtype) {
case UIO_MEM_PHYS: case UIO_MEM_PHYS:
return uio_mmap_physical(vma); ret = uio_mmap_physical(vma);
break;
case UIO_MEM_LOGICAL: case UIO_MEM_LOGICAL:
case UIO_MEM_VIRTUAL: case UIO_MEM_VIRTUAL:
return uio_mmap_logical(vma); ret = uio_mmap_logical(vma);
break;
default: default:
return -EINVAL; ret = -EINVAL;
} }
out:
mutex_unlock(&idev->info_lock);
return 0;
} }
static const struct file_operations uio_fops = { static const struct file_operations uio_fops = {
@ -865,7 +932,7 @@ int __uio_register_device(struct module *owner,
idev->owner = owner; idev->owner = owner;
idev->info = info; idev->info = info;
spin_lock_init(&idev->info_lock); mutex_init(&idev->info_lock);
init_waitqueue_head(&idev->wait); init_waitqueue_head(&idev->wait);
atomic_set(&idev->event, 0); 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 * FDs at the time of unregister and therefore may not be
* freed until they are released. * freed until they are released.
*/ */
ret = request_irq(info->irq, uio_interrupt, ret = request_threaded_irq(info->irq, NULL, uio_interrupt,
info->irq_flags, info->name, idev); info->irq_flags, info->name, idev);
if (ret) if (ret)
goto err_request_irq; goto err_request_irq;
} }
@ -928,7 +996,6 @@ EXPORT_SYMBOL_GPL(__uio_register_device);
void uio_unregister_device(struct uio_info *info) void uio_unregister_device(struct uio_info *info)
{ {
struct uio_device *idev; struct uio_device *idev;
unsigned long flags;
if (!info || !info->uio_dev) if (!info || !info->uio_dev)
return; return;
@ -937,14 +1004,14 @@ void uio_unregister_device(struct uio_info *info)
uio_free_minor(idev); uio_free_minor(idev);
mutex_lock(&idev->info_lock);
uio_dev_del_attributes(idev); uio_dev_del_attributes(idev);
if (info->irq && info->irq != UIO_IRQ_CUSTOM) if (info->irq && info->irq != UIO_IRQ_CUSTOM)
free_irq(info->irq, idev); free_irq(info->irq, idev);
spin_lock_irqsave(&idev->info_lock, flags);
idev->info = NULL; idev->info = NULL;
spin_unlock_irqrestore(&idev->info_lock, flags); mutex_unlock(&idev->info_lock);
device_unregister(&idev->dev); device_unregister(&idev->dev);

View File

@ -75,7 +75,7 @@ struct uio_device {
struct fasync_struct *async_queue; struct fasync_struct *async_queue;
wait_queue_head_t wait; wait_queue_head_t wait;
struct uio_info *info; struct uio_info *info;
spinlock_t info_lock; struct mutex info_lock;
struct kobject *map_dir; struct kobject *map_dir;
struct kobject *portio_dir; struct kobject *portio_dir;
}; };