Commit 3d4f9d76 authored by Eric W. Biederman's avatar Eric W. Biederman Committed by Greg Kroah-Hartman

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: default avatarEric W. Biederman <ebiederm@aristanetworks.com>
Reviewed-by: default avatarThomas Gleixner <tglx@linutronix.de>
Signed-off-by: default avatarHans J. Koch <hjk@linutronix.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent e52eec13
...@@ -45,10 +45,7 @@ static DEFINE_IDR(uio_idr); ...@@ -45,10 +45,7 @@ static DEFINE_IDR(uio_idr);
static const struct file_operations uio_fops; static const struct file_operations uio_fops;
/* UIO class infrastructure */ /* UIO class infrastructure */
static struct uio_class { static struct class *uio_class;
struct kref kref;
struct class *class;
} *uio_class;
/* Protect idr accesses */ /* Protect idr accesses */
static DEFINE_MUTEX(minor_lock); static DEFINE_MUTEX(minor_lock);
...@@ -757,55 +754,35 @@ static void uio_major_cleanup(void) ...@@ -757,55 +754,35 @@ static void uio_major_cleanup(void)
static int init_uio_class(void) static int init_uio_class(void)
{ {
int ret = 0; struct class *class;
int ret;
if (uio_class != NULL) {
kref_get(&uio_class->kref);
goto exit;
}
/* This is the first time in here, set everything up properly */ /* This is the first time in here, set everything up properly */
ret = uio_major_init(); ret = uio_major_init();
if (ret) if (ret)
goto exit; goto exit;
uio_class = kzalloc(sizeof(*uio_class), GFP_KERNEL); class = class_create(THIS_MODULE, "uio");
if (!uio_class) { if (IS_ERR(class)) {
ret = -ENOMEM; ret = IS_ERR(class);
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);
printk(KERN_ERR "class_create failed for uio\n"); printk(KERN_ERR "class_create failed for uio\n");
goto err_class_create; goto err_class_create;
} }
uio_class = class;
return 0; return 0;
err_class_create: err_class_create:
kfree(uio_class);
uio_class = NULL;
err_kzalloc:
uio_major_cleanup(); uio_major_cleanup();
exit: exit:
return ret; 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 */ /* Ok, we cheat as we know we only have one uio_class */
class_destroy(uio_class->class); class_destroy(uio_class);
kfree(uio_class);
uio_major_cleanup();
uio_class = NULL; uio_class = NULL;
} uio_major_cleanup();
static void uio_class_destroy(void)
{
if (uio_class)
kref_put(&uio_class->kref, release_uio_class);
} }
/** /**
...@@ -828,10 +805,6 @@ int __uio_register_device(struct module *owner, ...@@ -828,10 +805,6 @@ int __uio_register_device(struct module *owner,
info->uio_dev = NULL; info->uio_dev = NULL;
ret = init_uio_class();
if (ret)
return ret;
idev = kzalloc(sizeof(*idev), GFP_KERNEL); idev = kzalloc(sizeof(*idev), GFP_KERNEL);
if (!idev) { if (!idev) {
ret = -ENOMEM; ret = -ENOMEM;
...@@ -847,7 +820,7 @@ int __uio_register_device(struct module *owner, ...@@ -847,7 +820,7 @@ int __uio_register_device(struct module *owner,
if (ret) if (ret)
goto err_get_minor; 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, MKDEV(uio_major, idev->minor), idev,
"uio%d", idev->minor); "uio%d", idev->minor);
if (IS_ERR(idev->dev)) { if (IS_ERR(idev->dev)) {
...@@ -874,13 +847,12 @@ int __uio_register_device(struct module *owner, ...@@ -874,13 +847,12 @@ int __uio_register_device(struct module *owner,
err_request_irq: err_request_irq:
uio_dev_del_attributes(idev); uio_dev_del_attributes(idev);
err_uio_dev_add_attributes: 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: err_device_create:
uio_free_minor(idev); uio_free_minor(idev);
err_get_minor: err_get_minor:
kfree(idev); kfree(idev);
err_kzalloc: err_kzalloc:
uio_class_destroy();
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(__uio_register_device); EXPORT_SYMBOL_GPL(__uio_register_device);
...@@ -907,9 +879,8 @@ void uio_unregister_device(struct uio_info *info) ...@@ -907,9 +879,8 @@ void uio_unregister_device(struct uio_info *info)
uio_dev_del_attributes(idev); uio_dev_del_attributes(idev);
dev_set_drvdata(idev->dev, NULL); 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); kfree(idev);
uio_class_destroy();
return; return;
} }
...@@ -917,11 +888,12 @@ EXPORT_SYMBOL_GPL(uio_unregister_device); ...@@ -917,11 +888,12 @@ EXPORT_SYMBOL_GPL(uio_unregister_device);
static int __init uio_init(void) static int __init uio_init(void)
{ {
return 0; return init_uio_class();
} }
static void __exit uio_exit(void) static void __exit uio_exit(void)
{ {
release_uio_class();
} }
module_init(uio_init) module_init(uio_init)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment