diff options
| author | Greg Kroah-Hartman <gregkh@google.com> | 2017-10-12 12:05:45 +0200 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@google.com> | 2017-10-12 12:05:45 +0200 |
| commit | 73a2b70bdf78f3ad747dd740c9e55c062c71b86c (patch) | |
| tree | ec10e734d1d3ba0cd6630bd59a27e94a1f59ca3b /drivers/usb/gadget/legacy/inode.c | |
| parent | 35091a1d8b61ccc35eba80850f20deed1f543928 (diff) | |
| parent | 69f53f5d37d53ba17ca744947226b4cdadb90c13 (diff) | |
Merge 4.4.92 into android-4.4
Changes in 4.4.92
usb: gadget: inode.c: fix unbalanced spin_lock in ep0_write
USB: gadgetfs: Fix crash caused by inadequate synchronization
USB: gadgetfs: fix copy_to_user while holding spinlock
usb: gadget: udc: atmel: set vbus irqflags explicitly
usb-storage: unusual_devs entry to fix write-access regression for Seagate external drives
usb: renesas_usbhs: fix the BCLR setting condition for non-DCP pipe
usb: renesas_usbhs: fix usbhsf_fifo_clear() for RX direction
ALSA: usb-audio: Check out-of-bounds access by corrupted buffer descriptor
usb: pci-quirks.c: Corrected timeout values used in handshake
USB: dummy-hcd: fix connection failures (wrong speed)
USB: dummy-hcd: fix infinite-loop resubmission bug
USB: dummy-hcd: Fix erroneous synchronization change
USB: devio: Don't corrupt user memory
usb: gadget: mass_storage: set msg_registered after msg registered
USB: g_mass_storage: Fix deadlock when driver is unbound
lsm: fix smack_inode_removexattr and xattr_getsecurity memleak
ALSA: compress: Remove unused variable
ALSA: usx2y: Suppress kernel warning at page allocation failures
driver core: platform: Don't read past the end of "driver_override" buffer
Drivers: hv: fcopy: restore correct transfer length
stm class: Fix a use-after-free
ftrace: Fix kmemleak in unregister_ftrace_graph
HID: i2c-hid: allocate hid buffers for real worst case
iwlwifi: add workaround to disable wide channels in 5GHz
scsi: sd: Do not override max_sectors_kb sysfs setting
USB: uas: fix bug in handling of alternate settings
USB: core: harden cdc_parse_cdc_header
usb: Increase quirk delay for USB devices
USB: fix out-of-bounds in usb_set_configuration
xhci: fix finding correct bus_state structure for USB 3.1 hosts
iio: adc: twl4030: Fix an error handling path in 'twl4030_madc_probe()'
iio: adc: twl4030: Disable the vusb3v1 rugulator in the error handling path of 'twl4030_madc_probe()'
iio: ad_sigma_delta: Implement a dedicated reset function
staging: iio: ad7192: Fix - use the dedicated reset function avoiding dma from stack.
iio: core: Return error for failed read_reg
iio: ad7793: Fix the serial interface reset
iio: adc: mcp320x: Fix readout of negative voltages
iio: adc: mcp320x: Fix oops on module unload
uwb: properly check kthread_run return value
uwb: ensure that endpoint is interrupt
brcmfmac: setup passive scan if requested by user-space
drm/i915/bios: ignore HDMI on port A
nvme: protect against simultaneous shutdown invocations
sched/cpuset/pm: Fix cpuset vs. suspend-resume bugs
ext4: fix data corruption for mmap writes
ext4: Don't clear SGID when inheriting ACLs
ext4: don't allow encrypted operations without keys
Linux 4.4.92
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Diffstat (limited to 'drivers/usb/gadget/legacy/inode.c')
| -rw-r--r-- | drivers/usb/gadget/legacy/inode.c | 49 |
1 files changed, 41 insertions, 8 deletions
diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c index 43ce2cfcdb4d..b6df47aa25af 100644 --- a/drivers/usb/gadget/legacy/inode.c +++ b/drivers/usb/gadget/legacy/inode.c @@ -27,7 +27,7 @@ #include <linux/mmu_context.h> #include <linux/aio.h> #include <linux/uio.h> - +#include <linux/delay.h> #include <linux/device.h> #include <linux/moduleparam.h> @@ -116,6 +116,7 @@ enum ep0_state { struct dev_data { spinlock_t lock; atomic_t count; + int udc_usage; enum ep0_state state; /* P: lock */ struct usb_gadgetfs_event event [N_EVENT]; unsigned ev_next; @@ -512,9 +513,9 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) INIT_WORK(&priv->work, ep_user_copy_worker); schedule_work(&priv->work); } - spin_unlock(&epdata->dev->lock); usb_ep_free_request(ep, req); + spin_unlock(&epdata->dev->lock); put_ep(epdata); } @@ -938,9 +939,11 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) struct usb_request *req = dev->req; if ((retval = setup_req (ep, req, 0)) == 0) { + ++dev->udc_usage; spin_unlock_irq (&dev->lock); retval = usb_ep_queue (ep, req, GFP_KERNEL); spin_lock_irq (&dev->lock); + --dev->udc_usage; } dev->state = STATE_DEV_CONNECTED; @@ -982,11 +985,14 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) retval = -EIO; else { len = min (len, (size_t)dev->req->actual); -// FIXME don't call this with the spinlock held ... + ++dev->udc_usage; + spin_unlock_irq(&dev->lock); if (copy_to_user (buf, dev->req->buf, len)) retval = -EFAULT; else retval = len; + spin_lock_irq(&dev->lock); + --dev->udc_usage; clean_req (dev->gadget->ep0, dev->req); /* NOTE userspace can't yet choose to stall */ } @@ -1130,6 +1136,7 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) retval = setup_req (dev->gadget->ep0, dev->req, len); if (retval == 0) { dev->state = STATE_DEV_CONNECTED; + ++dev->udc_usage; spin_unlock_irq (&dev->lock); if (copy_from_user (dev->req->buf, buf, len)) retval = -EFAULT; @@ -1140,10 +1147,10 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) dev->gadget->ep0, dev->req, GFP_KERNEL); } + spin_lock_irq(&dev->lock); + --dev->udc_usage; if (retval < 0) { - spin_lock_irq (&dev->lock); clean_req (dev->gadget->ep0, dev->req); - spin_unlock_irq (&dev->lock); } else retval = len; @@ -1240,9 +1247,21 @@ static long dev_ioctl (struct file *fd, unsigned code, unsigned long value) struct usb_gadget *gadget = dev->gadget; long ret = -ENOTTY; - if (gadget->ops->ioctl) + spin_lock_irq(&dev->lock); + if (dev->state == STATE_DEV_OPENED || + dev->state == STATE_DEV_UNBOUND) { + /* Not bound to a UDC */ + } else if (gadget->ops->ioctl) { + ++dev->udc_usage; + spin_unlock_irq(&dev->lock); + ret = gadget->ops->ioctl (gadget, code, value); + spin_lock_irq(&dev->lock); + --dev->udc_usage; + } + spin_unlock_irq(&dev->lock); + return ret; } @@ -1460,10 +1479,12 @@ delegate: if (value < 0) break; + ++dev->udc_usage; spin_unlock (&dev->lock); value = usb_ep_queue (gadget->ep0, dev->req, GFP_KERNEL); spin_lock (&dev->lock); + --dev->udc_usage; if (value < 0) { clean_req (gadget->ep0, dev->req); break; @@ -1487,8 +1508,12 @@ delegate: req->length = value; req->zero = value < w_length; + ++dev->udc_usage; spin_unlock (&dev->lock); value = usb_ep_queue (gadget->ep0, req, GFP_KERNEL); + spin_lock(&dev->lock); + --dev->udc_usage; + spin_unlock(&dev->lock); if (value < 0) { DBG (dev, "ep_queue --> %d\n", value); req->status = 0; @@ -1515,21 +1540,24 @@ static void destroy_ep_files (struct dev_data *dev) /* break link to FS */ ep = list_first_entry (&dev->epfiles, struct ep_data, epfiles); list_del_init (&ep->epfiles); + spin_unlock_irq (&dev->lock); + dentry = ep->dentry; ep->dentry = NULL; parent = d_inode(dentry->d_parent); /* break link to controller */ + mutex_lock(&ep->lock); if (ep->state == STATE_EP_ENABLED) (void) usb_ep_disable (ep->ep); ep->state = STATE_EP_UNBOUND; usb_ep_free_request (ep->ep, ep->req); ep->ep = NULL; + mutex_unlock(&ep->lock); + wake_up (&ep->wait); put_ep (ep); - spin_unlock_irq (&dev->lock); - /* break link to dcache */ mutex_lock (&parent->i_mutex); d_delete (dentry); @@ -1600,6 +1628,11 @@ gadgetfs_unbind (struct usb_gadget *gadget) spin_lock_irq (&dev->lock); dev->state = STATE_DEV_UNBOUND; + while (dev->udc_usage > 0) { + spin_unlock_irq(&dev->lock); + usleep_range(1000, 2000); + spin_lock_irq(&dev->lock); + } spin_unlock_irq (&dev->lock); destroy_ep_files (dev); |
