aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2008-06-24 14:47:04 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2008-07-21 18:16:40 -0400
commitcd9f03759d3eb588e185b04e1854c778b050833e (patch)
treec4d3ad70cec5c77569c05d6e657b253b2b6253c9 /drivers
parent78d9a487ee961c356e1a934d9a92eca38ffb3a70 (diff)
usbfs: send disconnect signals when device is unregistered
USB device files are accessible in two ways: as files in usbfs and as character device nodes. The two paths are supposed to behave identically, but they don't. When the underlying USB device is unplugged, disconnect signals are sent to processes with open usbfs files (if they requested these signals) but not to processes with open device node files. This patch (as1104) fixes the bug by moving the disconnect-signalling code into a common subroutine which is called from both paths. Putting this subroutine in devio.c removes the only out-of-file reference to struct dev_state, and so the structure's declaration can be moved from usb.h into devio.c. Finally, the new subroutine performs one extra action: It kills all the outstanding async URBs. (I'd kill the outstanding synchronous URBs too, if there was any way to do it.) In the past this hasn't mattered much, because devices were unregistered from usbfs only when they were disconnected. But now the unregistration can also occur whenever devices are unbound from the usb_generic driver. At any rate, killing URBs when a device is unregistered from usbfs seems like a good thing to do. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/core/devio.c39
-rw-r--r--drivers/usb/core/inode.c16
-rw-r--r--drivers/usb/core/usb.h17
3 files changed, 41 insertions, 31 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index e09935acae80..bbd029f68faa 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -59,6 +59,22 @@
59/* Mutual exclusion for removal, open, and release */ 59/* Mutual exclusion for removal, open, and release */
60DEFINE_MUTEX(usbfs_mutex); 60DEFINE_MUTEX(usbfs_mutex);
61 61
62struct dev_state {
63 struct list_head list; /* state list */
64 struct usb_device *dev;
65 struct file *file;
66 spinlock_t lock; /* protects the async urb lists */
67 struct list_head async_pending;
68 struct list_head async_completed;
69 wait_queue_head_t wait; /* wake up if a request completed */
70 unsigned int discsignr;
71 struct pid *disc_pid;
72 uid_t disc_uid, disc_euid;
73 void __user *disccontext;
74 unsigned long ifclaimed;
75 u32 secid;
76};
77
62struct async { 78struct async {
63 struct list_head asynclist; 79 struct list_head asynclist;
64 struct dev_state *ps; 80 struct dev_state *ps;
@@ -1680,6 +1696,28 @@ const struct file_operations usbdev_file_operations = {
1680 .release = usbdev_release, 1696 .release = usbdev_release,
1681}; 1697};
1682 1698
1699void usb_fs_classdev_common_remove(struct usb_device *udev)
1700{
1701 struct dev_state *ps;
1702 struct siginfo sinfo;
1703
1704 while (!list_empty(&udev->filelist)) {
1705 ps = list_entry(udev->filelist.next, struct dev_state, list);
1706 destroy_all_async(ps);
1707 wake_up_all(&ps->wait);
1708 list_del_init(&ps->list);
1709 if (ps->discsignr) {
1710 sinfo.si_signo = ps->discsignr;
1711 sinfo.si_errno = EPIPE;
1712 sinfo.si_code = SI_ASYNCIO;
1713 sinfo.si_addr = ps->disccontext;
1714 kill_pid_info_as_uid(ps->discsignr, &sinfo,
1715 ps->disc_pid, ps->disc_uid,
1716 ps->disc_euid, ps->secid);
1717 }
1718 }
1719}
1720
1683#ifdef CONFIG_USB_DEVICE_CLASS 1721#ifdef CONFIG_USB_DEVICE_CLASS
1684static struct class *usb_classdev_class; 1722static struct class *usb_classdev_class;
1685 1723
@@ -1699,6 +1737,7 @@ static int usb_classdev_add(struct usb_device *dev)
1699static void usb_classdev_remove(struct usb_device *dev) 1737static void usb_classdev_remove(struct usb_device *dev)
1700{ 1738{
1701 device_unregister(dev->usb_classdev); 1739 device_unregister(dev->usb_classdev);
1740 usb_fs_classdev_common_remove(dev);
1702} 1741}
1703 1742
1704static int usb_classdev_notify(struct notifier_block *self, 1743static int usb_classdev_notify(struct notifier_block *self,
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index 1d253dd4ea81..db410e92c80d 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -712,25 +712,11 @@ static void usbfs_add_device(struct usb_device *dev)
712 712
713static void usbfs_remove_device(struct usb_device *dev) 713static void usbfs_remove_device(struct usb_device *dev)
714{ 714{
715 struct dev_state *ds;
716 struct siginfo sinfo;
717
718 if (dev->usbfs_dentry) { 715 if (dev->usbfs_dentry) {
719 fs_remove_file (dev->usbfs_dentry); 716 fs_remove_file (dev->usbfs_dentry);
720 dev->usbfs_dentry = NULL; 717 dev->usbfs_dentry = NULL;
721 } 718 }
722 while (!list_empty(&dev->filelist)) { 719 usb_fs_classdev_common_remove(dev);
723 ds = list_entry(dev->filelist.next, struct dev_state, list);
724 wake_up_all(&ds->wait);
725 list_del_init(&ds->list);
726 if (ds->discsignr) {
727 sinfo.si_signo = ds->discsignr;
728 sinfo.si_errno = EPIPE;
729 sinfo.si_code = SI_ASYNCIO;
730 sinfo.si_addr = ds->disccontext;
731 kill_pid_info_as_uid(ds->discsignr, &sinfo, ds->disc_pid, ds->disc_uid, ds->disc_euid, ds->secid);
732 }
733 }
734} 720}
735 721
736static int usbfs_notify(struct notifier_block *self, unsigned long action, void *dev) 722static int usbfs_notify(struct notifier_block *self, unsigned long action, void *dev)
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index d3eb0a29bca1..d9a6e16dbf84 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -142,26 +142,11 @@ extern struct usb_driver usbfs_driver;
142extern const struct file_operations usbfs_devices_fops; 142extern const struct file_operations usbfs_devices_fops;
143extern const struct file_operations usbdev_file_operations; 143extern const struct file_operations usbdev_file_operations;
144extern void usbfs_conn_disc_event(void); 144extern void usbfs_conn_disc_event(void);
145extern void usb_fs_classdev_common_remove(struct usb_device *udev);
145 146
146extern int usb_devio_init(void); 147extern int usb_devio_init(void);
147extern void usb_devio_cleanup(void); 148extern void usb_devio_cleanup(void);
148 149
149struct dev_state {
150 struct list_head list; /* state list */
151 struct usb_device *dev;
152 struct file *file;
153 spinlock_t lock; /* protects the async urb lists */
154 struct list_head async_pending;
155 struct list_head async_completed;
156 wait_queue_head_t wait; /* wake up if a request completed */
157 unsigned int discsignr;
158 struct pid *disc_pid;
159 uid_t disc_uid, disc_euid;
160 void __user *disccontext;
161 unsigned long ifclaimed;
162 u32 secid;
163};
164
165/* internal notify stuff */ 150/* internal notify stuff */
166extern void usb_notify_add_device(struct usb_device *udev); 151extern void usb_notify_add_device(struct usb_device *udev);
167extern void usb_notify_remove_device(struct usb_device *udev); 152extern void usb_notify_remove_device(struct usb_device *udev);