diff options
author | Uwe Kleine-König <Uwe.Kleine-Koenig@digi.com> | 2008-04-11 05:07:39 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-04-19 22:10:18 -0400 |
commit | 610ad5064cb90aec35f5837bbde3d316fe02aca7 (patch) | |
tree | 7c254ffa06ebd33b5a5b40dc28147eeba615d374 | |
parent | b54f2863a26d2b7c002d96abcde149940733c8e6 (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>
-rw-r--r-- | drivers/uio/uio.c | 36 |
1 files changed, 21 insertions, 15 deletions
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index 11759080ca54..55cc7b80422a 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 | |
325 | err_infoopen: | ||
326 | |||
327 | kfree(listener); | ||
328 | err_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 | ||