diff options
author | Jiri Kosina <jkosina@suse.cz> | 2010-03-25 09:15:11 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2010-03-25 09:29:14 -0400 |
commit | 2e57480b2a717916510b0c23b2851398a4cbd958 (patch) | |
tree | 69491b58b4d661186e4925089d88d49fab8b02f6 | |
parent | 39710479303fd3affb3e204e9a7a75cc676977b5 (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>
-rw-r--r-- | drivers/hid/hidraw.c | 41 |
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: | |||
105 | static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) | 105 | static 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); |
138 | out: | 146 | out_free: |
139 | kfree(buf); | 147 | kfree(buf); |
148 | out: | ||
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 | ||
197 | out_unlock: | 206 | out_unlock: |
198 | mutex_unlock(&minors_lock); | 207 | mutex_unlock(&minors_lock); |
199 | unlock_kernel(); | ||
200 | out: | 208 | out: |
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 | ||