aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2010-03-25 09:15:11 -0400
committerJiri Kosina <jkosina@suse.cz>2010-03-25 09:29:14 -0400
commit2e57480b2a717916510b0c23b2851398a4cbd958 (patch)
tree69491b58b4d661186e4925089d88d49fab8b02f6 /drivers/hid
parent39710479303fd3affb3e204e9a7a75cc676977b5 (diff)
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 <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/hidraw.c41
1 files changed, 25 insertions, 16 deletions
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:
105static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) 105static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
106{ 106{
107 unsigned int minor = iminor(file->f_path.dentry->d_inode); 107 unsigned int minor = iminor(file->f_path.dentry->d_inode);
108 /* FIXME: What stops hidraw_table going NULL */ 108 struct hid_device *dev;
109 struct hid_device *dev = hidraw_table[minor]->hid;
110 __u8 *buf; 109 __u8 *buf;
111 int ret = 0; 110 int ret = 0;
112 111
113 if (!dev->hid_output_raw_report) 112 mutex_lock(&minors_lock);
114 return -ENODEV; 113 dev = hidraw_table[minor]->hid;
114
115 if (!dev->hid_output_raw_report) {
116 ret = -ENODEV;
117 goto out;
118 }
115 119
116 if (count > HID_MAX_BUFFER_SIZE) { 120 if (count > HID_MAX_BUFFER_SIZE) {
117 printk(KERN_WARNING "hidraw: pid %d passed too large report\n", 121 printk(KERN_WARNING "hidraw: pid %d passed too large report\n",
118 task_pid_nr(current)); 122 task_pid_nr(current));
119 return -EINVAL; 123 ret = -EINVAL;
124 goto out;
120 } 125 }
121 126
122 if (count < 2) { 127 if (count < 2) {
123 printk(KERN_WARNING "hidraw: pid %d passed too short report\n", 128 printk(KERN_WARNING "hidraw: pid %d passed too short report\n",
124 task_pid_nr(current)); 129 task_pid_nr(current));
125 return -EINVAL; 130 ret = -EINVAL;
131 goto out;
126 } 132 }
127 133
128 buf = kmalloc(count * sizeof(__u8), GFP_KERNEL); 134 buf = kmalloc(count * sizeof(__u8), GFP_KERNEL);
129 if (!buf) 135 if (!buf) {
130 return -ENOMEM; 136 ret = -ENOMEM;
137 goto out;
138 }
131 139
132 if (copy_from_user(buf, buffer, count)) { 140 if (copy_from_user(buf, buffer, count)) {
133 ret = -EFAULT; 141 ret = -EFAULT;
134 goto out; 142 goto out_free;
135 } 143 }
136 144
137 ret = dev->hid_output_raw_report(dev, buf, count, HID_OUTPUT_REPORT); 145 ret = dev->hid_output_raw_report(dev, buf, count, HID_OUTPUT_REPORT);
138out: 146out_free:
139 kfree(buf); 147 kfree(buf);
148out:
149 mutex_unlock(&minors_lock);
140 return ret; 150 return ret;
141} 151}
142 152
@@ -164,7 +174,6 @@ static int hidraw_open(struct inode *inode, struct file *file)
164 goto out; 174 goto out;
165 } 175 }
166 176
167 lock_kernel();
168 mutex_lock(&minors_lock); 177 mutex_lock(&minors_lock);
169 if (!hidraw_table[minor]) { 178 if (!hidraw_table[minor]) {
170 printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n", 179 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)
196 205
197out_unlock: 206out_unlock:
198 mutex_unlock(&minors_lock); 207 mutex_unlock(&minors_lock);
199 unlock_kernel();
200out: 208out:
201 return err; 209 return err;
202 210
@@ -237,11 +245,12 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
237 struct inode *inode = file->f_path.dentry->d_inode; 245 struct inode *inode = file->f_path.dentry->d_inode;
238 unsigned int minor = iminor(inode); 246 unsigned int minor = iminor(inode);
239 long ret = 0; 247 long ret = 0;
240 /* FIXME: What stops hidraw_table going NULL */ 248 struct hidraw *dev;
241 struct hidraw *dev = hidraw_table[minor];
242 void __user *user_arg = (void __user*) arg; 249 void __user *user_arg = (void __user*) arg;
243 250
244 lock_kernel(); 251 mutex_lock(&minors_lock);
252 dev = hidraw_table[minor];
253
245 switch (cmd) { 254 switch (cmd) {
246 case HIDIOCGRDESCSIZE: 255 case HIDIOCGRDESCSIZE:
247 if (put_user(dev->hid->rsize, (int __user *)arg)) 256 if (put_user(dev->hid->rsize, (int __user *)arg))
@@ -314,7 +323,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
314 323
315 ret = -ENOTTY; 324 ret = -ENOTTY;
316 } 325 }
317 unlock_kernel(); 326 mutex_unlock(&minors_lock);
318 return ret; 327 return ret;
319} 328}
320 329