summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@aristanetworks.com>2010-09-14 11:36:27 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2010-10-22 10:16:43 -0700
commit3d4f9d76b0641b7984f95982e390927fc5998ad6 (patch)
tree7f57194438afcfe364fc507b359840b65c63d203
parente52eec13cd6b7f30ab19081b387813e03e592ae5 (diff)
downloadlinux-3d4f9d76b0641b7984f95982e390927fc5998ad6.tar.bz2
uio: Fix lack of locking in init_uio_class
There is no locking in init_uio_class so multiple drivers can race and create multiple uio classes. Fix this by simplifying the code. In particular always register the uio class during module_init and make things simpler. Signed-off-by: Eric W. Biederman <ebiederm@aristanetworks.com> Reviewed-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Hans J. Koch <hjk@linutronix.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/uio/uio.c58
1 files changed, 15 insertions, 43 deletions
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index bff1afbde5a4..bc774cce0a4d 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -45,10 +45,7 @@ static DEFINE_IDR(uio_idr);
static const struct file_operations uio_fops;
/* UIO class infrastructure */
-static struct uio_class {
- struct kref kref;
- struct class *class;
-} *uio_class;
+static struct class *uio_class;
/* Protect idr accesses */
static DEFINE_MUTEX(minor_lock);
@@ -757,55 +754,35 @@ static void uio_major_cleanup(void)
static int init_uio_class(void)
{
- int ret = 0;
-
- if (uio_class != NULL) {
- kref_get(&uio_class->kref);
- goto exit;
- }
+ struct class *class;
+ int ret;
/* This is the first time in here, set everything up properly */
ret = uio_major_init();
if (ret)
goto exit;
- uio_class = kzalloc(sizeof(*uio_class), GFP_KERNEL);
- if (!uio_class) {
- ret = -ENOMEM;
- goto err_kzalloc;
- }
-
- kref_init(&uio_class->kref);
- uio_class->class = class_create(THIS_MODULE, "uio");
- if (IS_ERR(uio_class->class)) {
- ret = IS_ERR(uio_class->class);
+ class = class_create(THIS_MODULE, "uio");
+ if (IS_ERR(class)) {
+ ret = IS_ERR(class);
printk(KERN_ERR "class_create failed for uio\n");
goto err_class_create;
}
+ uio_class = class;
return 0;
err_class_create:
- kfree(uio_class);
- uio_class = NULL;
-err_kzalloc:
uio_major_cleanup();
exit:
return ret;
}
-static void release_uio_class(struct kref *kref)
+static void release_uio_class(void)
{
/* Ok, we cheat as we know we only have one uio_class */
- class_destroy(uio_class->class);
- kfree(uio_class);
- uio_major_cleanup();
+ class_destroy(uio_class);
uio_class = NULL;
-}
-
-static void uio_class_destroy(void)
-{
- if (uio_class)
- kref_put(&uio_class->kref, release_uio_class);
+ uio_major_cleanup();
}
/**
@@ -828,10 +805,6 @@ int __uio_register_device(struct module *owner,
info->uio_dev = NULL;
- ret = init_uio_class();
- if (ret)
- return ret;
-
idev = kzalloc(sizeof(*idev), GFP_KERNEL);
if (!idev) {
ret = -ENOMEM;
@@ -847,7 +820,7 @@ int __uio_register_device(struct module *owner,
if (ret)
goto err_get_minor;
- idev->dev = device_create(uio_class->class, parent,
+ idev->dev = device_create(uio_class, parent,
MKDEV(uio_major, idev->minor), idev,
"uio%d", idev->minor);
if (IS_ERR(idev->dev)) {
@@ -874,13 +847,12 @@ int __uio_register_device(struct module *owner,
err_request_irq:
uio_dev_del_attributes(idev);
err_uio_dev_add_attributes:
- device_destroy(uio_class->class, MKDEV(uio_major, idev->minor));
+ device_destroy(uio_class, MKDEV(uio_major, idev->minor));
err_device_create:
uio_free_minor(idev);
err_get_minor:
kfree(idev);
err_kzalloc:
- uio_class_destroy();
return ret;
}
EXPORT_SYMBOL_GPL(__uio_register_device);
@@ -907,9 +879,8 @@ void uio_unregister_device(struct uio_info *info)
uio_dev_del_attributes(idev);
dev_set_drvdata(idev->dev, NULL);
- device_destroy(uio_class->class, MKDEV(uio_major, idev->minor));
+ device_destroy(uio_class, MKDEV(uio_major, idev->minor));
kfree(idev);
- uio_class_destroy();
return;
}
@@ -917,11 +888,12 @@ EXPORT_SYMBOL_GPL(uio_unregister_device);
static int __init uio_init(void)
{
- return 0;
+ return init_uio_class();
}
static void __exit uio_exit(void)
{
+ release_uio_class();
}
module_init(uio_init)