aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/uio/uio.c
diff options
context:
space:
mode:
authorUwe Kleine-König <Uwe.Kleine-Koenig@digi.com>2008-04-11 05:07:39 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2008-04-19 22:10:18 -0400
commit610ad5064cb90aec35f5837bbde3d316fe02aca7 (patch)
tree7c254ffa06ebd33b5a5b40dc28147eeba615d374 /drivers/uio/uio.c
parentb54f2863a26d2b7c002d96abcde149940733c8e6 (diff)
UIO: hold a reference to the device's owner while the device is open
Otherwise the device might just disappear while /dev/uioX is being used which results in an Oops. Signed-off-by: Uwe Kleine-König <Uwe.Kleine-Koenig@digi.com> Signed-off-by: Hans J Koch <hjk@linutronix.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/uio/uio.c')
-rw-r--r--drivers/uio/uio.c36
1 files changed, 21 insertions, 15 deletions
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index 11759080ca5..55cc7b80422 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -301,23 +301,33 @@ static int uio_open(struct inode *inode, struct file *filep)
301 if (!idev) 301 if (!idev)
302 return -ENODEV; 302 return -ENODEV;
303 303
304 if (!try_module_get(idev->owner))
305 return -ENODEV;
306
304 listener = kmalloc(sizeof(*listener), GFP_KERNEL); 307 listener = kmalloc(sizeof(*listener), GFP_KERNEL);
305 if (!listener) 308 if (!listener) {
306 return -ENOMEM; 309 ret = -ENOMEM;
310 goto err_alloc_listener;
311 }
307 312
308 listener->dev = idev; 313 listener->dev = idev;
309 listener->event_count = atomic_read(&idev->event); 314 listener->event_count = atomic_read(&idev->event);
310 filep->private_data = listener; 315 filep->private_data = listener;
311 316
312 if (idev->info->open) { 317 if (idev->info->open) {
313 if (!try_module_get(idev->owner))
314 return -ENODEV;
315 ret = idev->info->open(idev->info, inode); 318 ret = idev->info->open(idev->info, inode);
316 module_put(idev->owner); 319 if (ret)
320 goto err_infoopen;
317 } 321 }
318 322
319 if (ret) 323 return 0;
320 kfree(listener); 324
325err_infoopen:
326
327 kfree(listener);
328err_alloc_listener:
329
330 module_put(idev->owner);
321 331
322 return ret; 332 return ret;
323} 333}
@@ -336,12 +346,11 @@ static int uio_release(struct inode *inode, struct file *filep)
336 struct uio_listener *listener = filep->private_data; 346 struct uio_listener *listener = filep->private_data;
337 struct uio_device *idev = listener->dev; 347 struct uio_device *idev = listener->dev;
338 348
339 if (idev->info->release) { 349 if (idev->info->release)
340 if (!try_module_get(idev->owner))
341 return -ENODEV;
342 ret = idev->info->release(idev->info, inode); 350 ret = idev->info->release(idev->info, inode);
343 module_put(idev->owner); 351
344 } 352 module_put(idev->owner);
353
345 if (filep->f_flags & FASYNC) 354 if (filep->f_flags & FASYNC)
346 ret = uio_fasync(-1, filep, 0); 355 ret = uio_fasync(-1, filep, 0);
347 kfree(listener); 356 kfree(listener);
@@ -510,10 +519,7 @@ static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
510 return -EINVAL; 519 return -EINVAL;
511 520
512 if (idev->info->mmap) { 521 if (idev->info->mmap) {
513 if (!try_module_get(idev->owner))
514 return -ENODEV;
515 ret = idev->info->mmap(idev->info, vma); 522 ret = idev->info->mmap(idev->info, vma);
516 module_put(idev->owner);
517 return ret; 523 return ret;
518 } 524 }
519 525