USB: Remove BKL from poll()

Replace BKL with usbfs_mutex to protect a global counter
and a per file data structure

Signed-off-by: Oliver Neukum <oliver@neukum.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Oliver Neukum 2010-01-13 15:30:47 +01:00 committed by Greg Kroah-Hartman
parent 08add0c780
commit 554f76962d

View File

@ -118,6 +118,7 @@ static const char *format_endpt =
*/ */
static DECLARE_WAIT_QUEUE_HEAD(deviceconndiscwq); static DECLARE_WAIT_QUEUE_HEAD(deviceconndiscwq);
/* guarded by usbfs_mutex */
static unsigned int conndiscevcnt; static unsigned int conndiscevcnt;
/* this struct stores the poll state for <mountpoint>/devices pollers */ /* this struct stores the poll state for <mountpoint>/devices pollers */
@ -156,7 +157,9 @@ static const struct class_info clas_info[] =
void usbfs_conn_disc_event(void) void usbfs_conn_disc_event(void)
{ {
mutex_lock(&usbfs_mutex);
conndiscevcnt++; conndiscevcnt++;
mutex_unlock(&usbfs_mutex);
wake_up(&deviceconndiscwq); wake_up(&deviceconndiscwq);
} }
@ -629,42 +632,29 @@ static ssize_t usb_device_read(struct file *file, char __user *buf,
static unsigned int usb_device_poll(struct file *file, static unsigned int usb_device_poll(struct file *file,
struct poll_table_struct *wait) struct poll_table_struct *wait)
{ {
struct usb_device_status *st = file->private_data; struct usb_device_status *st;
unsigned int mask = 0; unsigned int mask = 0;
lock_kernel(); mutex_lock(&usbfs_mutex);
st = file->private_data;
if (!st) { if (!st) {
st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL); st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL);
/* we may have dropped BKL -
* need to check for having lost the race */
if (file->private_data) {
kfree(st);
st = file->private_data;
goto lost_race;
}
/* we haven't lost - check for allocation failure now */
if (!st) { if (!st) {
unlock_kernel(); mutex_unlock(&usbfs_mutex);
return POLLIN; return POLLIN;
} }
/*
* need to prevent the module from being unloaded, since
* proc_unregister does not call the release method and
* we would have a memory leak
*/
st->lastev = conndiscevcnt; st->lastev = conndiscevcnt;
file->private_data = st; file->private_data = st;
mask = POLLIN; mask = POLLIN;
} }
lost_race:
if (file->f_mode & FMODE_READ) if (file->f_mode & FMODE_READ)
poll_wait(file, &deviceconndiscwq, wait); poll_wait(file, &deviceconndiscwq, wait);
if (st->lastev != conndiscevcnt) if (st->lastev != conndiscevcnt)
mask |= POLLIN; mask |= POLLIN;
st->lastev = conndiscevcnt; st->lastev = conndiscevcnt;
unlock_kernel(); mutex_unlock(&usbfs_mutex);
return mask; return mask;
} }