diff options
| author | Eric W. Biederman <ebiederm@aristanetworks.com> | 2010-09-14 14:36:27 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-10-22 13:16:43 -0400 |
| commit | 3d4f9d76b0641b7984f95982e390927fc5998ad6 (patch) | |
| tree | 7f57194438afcfe364fc507b359840b65c63d203 | |
| parent | e52eec13cd6b7f30ab19081b387813e03e592ae5 (diff) | |
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.c | 58 |
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); | |||
| 45 | static const struct file_operations uio_fops; | 45 | static const struct file_operations uio_fops; |
| 46 | 46 | ||
| 47 | /* UIO class infrastructure */ | 47 | /* UIO class infrastructure */ |
| 48 | static struct uio_class { | 48 | static struct class *uio_class; |
| 49 | struct kref kref; | ||
| 50 | struct class *class; | ||
| 51 | } *uio_class; | ||
| 52 | 49 | ||
| 53 | /* Protect idr accesses */ | 50 | /* Protect idr accesses */ |
| 54 | static DEFINE_MUTEX(minor_lock); | 51 | static DEFINE_MUTEX(minor_lock); |
| @@ -757,55 +754,35 @@ static void uio_major_cleanup(void) | |||
| 757 | 754 | ||
| 758 | static int init_uio_class(void) | 755 | static int init_uio_class(void) |
| 759 | { | 756 | { |
| 760 | int ret = 0; | 757 | struct class *class; |
| 761 | 758 | int ret; | |
| 762 | if (uio_class != NULL) { | ||
| 763 | kref_get(&uio_class->kref); | ||
| 764 | goto exit; | ||
| 765 | } | ||
| 766 | 759 | ||
| 767 | /* This is the first time in here, set everything up properly */ | 760 | /* This is the first time in here, set everything up properly */ |
| 768 | ret = uio_major_init(); | 761 | ret = uio_major_init(); |
| 769 | if (ret) | 762 | if (ret) |
| 770 | goto exit; | 763 | goto exit; |
| 771 | 764 | ||
| 772 | uio_class = kzalloc(sizeof(*uio_class), GFP_KERNEL); | 765 | class = class_create(THIS_MODULE, "uio"); |
| 773 | if (!uio_class) { | 766 | if (IS_ERR(class)) { |
| 774 | ret = -ENOMEM; | 767 | ret = IS_ERR(class); |
| 775 | goto err_kzalloc; | ||
| 776 | } | ||
| 777 | |||
| 778 | kref_init(&uio_class->kref); | ||
| 779 | uio_class->class = class_create(THIS_MODULE, "uio"); | ||
| 780 | if (IS_ERR(uio_class->class)) { | ||
| 781 | ret = IS_ERR(uio_class->class); | ||
| 782 | printk(KERN_ERR "class_create failed for uio\n"); | 768 | printk(KERN_ERR "class_create failed for uio\n"); |
| 783 | goto err_class_create; | 769 | goto err_class_create; |
| 784 | } | 770 | } |
| 771 | uio_class = class; | ||
| 785 | return 0; | 772 | return 0; |
| 786 | 773 | ||
| 787 | err_class_create: | 774 | err_class_create: |
| 788 | kfree(uio_class); | ||
| 789 | uio_class = NULL; | ||
| 790 | err_kzalloc: | ||
| 791 | uio_major_cleanup(); | 775 | uio_major_cleanup(); |
| 792 | exit: | 776 | exit: |
| 793 | return ret; | 777 | return ret; |
| 794 | } | 778 | } |
| 795 | 779 | ||
| 796 | static void release_uio_class(struct kref *kref) | 780 | static void release_uio_class(void) |
| 797 | { | 781 | { |
| 798 | /* Ok, we cheat as we know we only have one uio_class */ | 782 | /* Ok, we cheat as we know we only have one uio_class */ |
| 799 | class_destroy(uio_class->class); | 783 | class_destroy(uio_class); |
| 800 | kfree(uio_class); | ||
| 801 | uio_major_cleanup(); | ||
| 802 | uio_class = NULL; | 784 | uio_class = NULL; |
| 803 | } | 785 | uio_major_cleanup(); |
| 804 | |||
| 805 | static void uio_class_destroy(void) | ||
| 806 | { | ||
| 807 | if (uio_class) | ||
| 808 | kref_put(&uio_class->kref, release_uio_class); | ||
| 809 | } | 786 | } |
| 810 | 787 | ||
| 811 | /** | 788 | /** |
| @@ -828,10 +805,6 @@ int __uio_register_device(struct module *owner, | |||
| 828 | 805 | ||
| 829 | info->uio_dev = NULL; | 806 | info->uio_dev = NULL; |
| 830 | 807 | ||
| 831 | ret = init_uio_class(); | ||
| 832 | if (ret) | ||
| 833 | return ret; | ||
| 834 | |||
| 835 | idev = kzalloc(sizeof(*idev), GFP_KERNEL); | 808 | idev = kzalloc(sizeof(*idev), GFP_KERNEL); |
| 836 | if (!idev) { | 809 | if (!idev) { |
| 837 | ret = -ENOMEM; | 810 | ret = -ENOMEM; |
| @@ -847,7 +820,7 @@ int __uio_register_device(struct module *owner, | |||
| 847 | if (ret) | 820 | if (ret) |
| 848 | goto err_get_minor; | 821 | goto err_get_minor; |
| 849 | 822 | ||
| 850 | idev->dev = device_create(uio_class->class, parent, | 823 | idev->dev = device_create(uio_class, parent, |
| 851 | MKDEV(uio_major, idev->minor), idev, | 824 | MKDEV(uio_major, idev->minor), idev, |
| 852 | "uio%d", idev->minor); | 825 | "uio%d", idev->minor); |
| 853 | if (IS_ERR(idev->dev)) { | 826 | if (IS_ERR(idev->dev)) { |
| @@ -874,13 +847,12 @@ int __uio_register_device(struct module *owner, | |||
| 874 | err_request_irq: | 847 | err_request_irq: |
| 875 | uio_dev_del_attributes(idev); | 848 | uio_dev_del_attributes(idev); |
| 876 | err_uio_dev_add_attributes: | 849 | err_uio_dev_add_attributes: |
| 877 | device_destroy(uio_class->class, MKDEV(uio_major, idev->minor)); | 850 | device_destroy(uio_class, MKDEV(uio_major, idev->minor)); |
| 878 | err_device_create: | 851 | err_device_create: |
| 879 | uio_free_minor(idev); | 852 | uio_free_minor(idev); |
| 880 | err_get_minor: | 853 | err_get_minor: |
| 881 | kfree(idev); | 854 | kfree(idev); |
| 882 | err_kzalloc: | 855 | err_kzalloc: |
| 883 | uio_class_destroy(); | ||
| 884 | return ret; | 856 | return ret; |
| 885 | } | 857 | } |
| 886 | EXPORT_SYMBOL_GPL(__uio_register_device); | 858 | EXPORT_SYMBOL_GPL(__uio_register_device); |
| @@ -907,9 +879,8 @@ void uio_unregister_device(struct uio_info *info) | |||
| 907 | uio_dev_del_attributes(idev); | 879 | uio_dev_del_attributes(idev); |
| 908 | 880 | ||
| 909 | dev_set_drvdata(idev->dev, NULL); | 881 | dev_set_drvdata(idev->dev, NULL); |
| 910 | device_destroy(uio_class->class, MKDEV(uio_major, idev->minor)); | 882 | device_destroy(uio_class, MKDEV(uio_major, idev->minor)); |
| 911 | kfree(idev); | 883 | kfree(idev); |
| 912 | uio_class_destroy(); | ||
| 913 | 884 | ||
| 914 | return; | 885 | return; |
| 915 | } | 886 | } |
| @@ -917,11 +888,12 @@ EXPORT_SYMBOL_GPL(uio_unregister_device); | |||
| 917 | 888 | ||
| 918 | static int __init uio_init(void) | 889 | static int __init uio_init(void) |
| 919 | { | 890 | { |
| 920 | return 0; | 891 | return init_uio_class(); |
| 921 | } | 892 | } |
| 922 | 893 | ||
| 923 | static void __exit uio_exit(void) | 894 | static void __exit uio_exit(void) |
| 924 | { | 895 | { |
| 896 | release_uio_class(); | ||
| 925 | } | 897 | } |
| 926 | 898 | ||
| 927 | module_init(uio_init) | 899 | module_init(uio_init) |
