From 2e57480b2a717916510b0c23b2851398a4cbd958 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Thu, 25 Mar 2010 14:15:11 +0100 Subject: HID: remove BKL from hidraw Remove BKL from hidraw, which is possible through fixing the locking of minors_lock mutex properly -- it is now used to guard all accessess to hidraw_table[], preventing it to becoming NULL unexpectedly by unregistering the device. Signed-off-by: Jiri Kosina --- drivers/hid/hidraw.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) (limited to 'drivers/hid/hidraw.c') diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index d04476700b7b..589dac5b5f56 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -105,38 +105,48 @@ out: static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { unsigned int minor = iminor(file->f_path.dentry->d_inode); - /* FIXME: What stops hidraw_table going NULL */ - struct hid_device *dev = hidraw_table[minor]->hid; + struct hid_device *dev; __u8 *buf; int ret = 0; - if (!dev->hid_output_raw_report) - return -ENODEV; + mutex_lock(&minors_lock); + dev = hidraw_table[minor]->hid; + + if (!dev->hid_output_raw_report) { + ret = -ENODEV; + goto out; + } if (count > HID_MAX_BUFFER_SIZE) { printk(KERN_WARNING "hidraw: pid %d passed too large report\n", task_pid_nr(current)); - return -EINVAL; + ret = -EINVAL; + goto out; } if (count < 2) { printk(KERN_WARNING "hidraw: pid %d passed too short report\n", task_pid_nr(current)); - return -EINVAL; + ret = -EINVAL; + goto out; } buf = kmalloc(count * sizeof(__u8), GFP_KERNEL); - if (!buf) - return -ENOMEM; + if (!buf) { + ret = -ENOMEM; + goto out; + } if (copy_from_user(buf, buffer, count)) { ret = -EFAULT; - goto out; + goto out_free; } ret = dev->hid_output_raw_report(dev, buf, count, HID_OUTPUT_REPORT); -out: +out_free: kfree(buf); +out: + mutex_unlock(&minors_lock); return ret; } @@ -164,7 +174,6 @@ static int hidraw_open(struct inode *inode, struct file *file) goto out; } - lock_kernel(); mutex_lock(&minors_lock); if (!hidraw_table[minor]) { printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n", @@ -196,7 +205,6 @@ static int hidraw_open(struct inode *inode, struct file *file) out_unlock: mutex_unlock(&minors_lock); - unlock_kernel(); out: return err; @@ -237,11 +245,12 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd, struct inode *inode = file->f_path.dentry->d_inode; unsigned int minor = iminor(inode); long ret = 0; - /* FIXME: What stops hidraw_table going NULL */ - struct hidraw *dev = hidraw_table[minor]; + struct hidraw *dev; void __user *user_arg = (void __user*) arg; - lock_kernel(); + mutex_lock(&minors_lock); + dev = hidraw_table[minor]; + switch (cmd) { case HIDIOCGRDESCSIZE: if (put_user(dev->hid->rsize, (int __user *)arg)) @@ -314,7 +323,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd, ret = -ENOTTY; } - unlock_kernel(); + mutex_unlock(&minors_lock); return ret; } -- cgit v1.2.3 From 0a504541b3ba593535d70f3124546e5e471a175e Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Thu, 25 Mar 2010 15:20:01 +0100 Subject: HID: remove excessive _EMERG messages from hidraw We don't need to shout loudly when device gets disconnected while hidraw node has been open, as this is properly handled in disconnect() and protected by minors_lock already. Signed-off-by: Jiri Kosina --- drivers/hid/hidraw.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/hid/hidraw.c') diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 589dac5b5f56..7919d3e843b6 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -176,8 +176,6 @@ static int hidraw_open(struct inode *inode, struct file *file) mutex_lock(&minors_lock); if (!hidraw_table[minor]) { - printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n", - minor); kfree(list); err = -ENODEV; goto out_unlock; @@ -216,11 +214,8 @@ static int hidraw_release(struct inode * inode, struct file * file) struct hidraw *dev; struct hidraw_list *list = file->private_data; - if (!hidraw_table[minor]) { - printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n", - minor); + if (!hidraw_table[minor]) return -ENODEV; - } list_del(&list->node); dev = hidraw_table[minor]; -- cgit v1.2.3