forked from mirrors/linux
		
	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:
		
							parent
							
								
									08add0c780
								
							
						
					
					
						commit
						554f76962d
					
				
					 1 changed files with 9 additions and 19 deletions
				
			
		| 
						 | 
					@ -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;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue