diff options
author | Jiri Slaby <jslaby@suse.cz> | 2012-08-08 16:26:44 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-08-13 19:45:39 -0400 |
commit | 7e73eca6a7b2967423902a4543821bb97cbbe698 (patch) | |
tree | 8c733036a77be59040ed7e346676445a83043b10 /drivers/tty/tty_io.c | |
parent | 0019b4089ccef8148d8be83cc8adfc81a75b47d4 (diff) |
TTY: move cdev_add to tty_register_device
We need the /dev/ node not to be available before we call
tty_register_device. Otherwise we might race with open and
tty_struct->port might not be available at that time.
This is not an issue now, but would be a problem after "TTY: use
tty_port_register_device" is applied.
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Acked-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/tty_io.c')
-rw-r--r-- | drivers/tty/tty_io.c | 48 |
1 files changed, 41 insertions, 7 deletions
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 4d9898c2b641..28c3e869ebba 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c | |||
@@ -3006,6 +3006,15 @@ EXPORT_SYMBOL_GPL(tty_put_char); | |||
3006 | 3006 | ||
3007 | struct class *tty_class; | 3007 | struct class *tty_class; |
3008 | 3008 | ||
3009 | static int tty_cdev_add(struct tty_driver *driver, dev_t dev, | ||
3010 | unsigned int index, unsigned int count) | ||
3011 | { | ||
3012 | /* init here, since reused cdevs cause crashes */ | ||
3013 | cdev_init(&driver->cdevs[index], &tty_fops); | ||
3014 | driver->cdevs[index].owner = driver->owner; | ||
3015 | return cdev_add(&driver->cdevs[index], dev, count); | ||
3016 | } | ||
3017 | |||
3009 | /** | 3018 | /** |
3010 | * tty_register_device - register a tty device | 3019 | * tty_register_device - register a tty device |
3011 | * @driver: the tty driver that describes the tty device | 3020 | * @driver: the tty driver that describes the tty device |
@@ -3028,8 +3037,10 @@ struct class *tty_class; | |||
3028 | struct device *tty_register_device(struct tty_driver *driver, unsigned index, | 3037 | struct device *tty_register_device(struct tty_driver *driver, unsigned index, |
3029 | struct device *device) | 3038 | struct device *device) |
3030 | { | 3039 | { |
3040 | struct device *ret; | ||
3031 | char name[64]; | 3041 | char name[64]; |
3032 | dev_t dev = MKDEV(driver->major, driver->minor_start) + index; | 3042 | dev_t dev = MKDEV(driver->major, driver->minor_start) + index; |
3043 | bool cdev = false; | ||
3033 | 3044 | ||
3034 | if (index >= driver->num) { | 3045 | if (index >= driver->num) { |
3035 | printk(KERN_ERR "Attempt to register invalid tty line number " | 3046 | printk(KERN_ERR "Attempt to register invalid tty line number " |
@@ -3042,7 +3053,18 @@ struct device *tty_register_device(struct tty_driver *driver, unsigned index, | |||
3042 | else | 3053 | else |
3043 | tty_line_name(driver, index, name); | 3054 | tty_line_name(driver, index, name); |
3044 | 3055 | ||
3045 | return device_create(tty_class, device, dev, NULL, name); | 3056 | if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)) { |
3057 | int error = tty_cdev_add(driver, dev, index, 1); | ||
3058 | if (error) | ||
3059 | return ERR_PTR(error); | ||
3060 | cdev = true; | ||
3061 | } | ||
3062 | |||
3063 | ret = device_create(tty_class, device, dev, NULL, name); | ||
3064 | if (IS_ERR(ret) && cdev) | ||
3065 | cdev_del(&driver->cdevs[index]); | ||
3066 | |||
3067 | return ret; | ||
3046 | } | 3068 | } |
3047 | EXPORT_SYMBOL(tty_register_device); | 3069 | EXPORT_SYMBOL(tty_register_device); |
3048 | 3070 | ||
@@ -3061,6 +3083,8 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index) | |||
3061 | { | 3083 | { |
3062 | device_destroy(tty_class, | 3084 | device_destroy(tty_class, |
3063 | MKDEV(driver->major, driver->minor_start) + index); | 3085 | MKDEV(driver->major, driver->minor_start) + index); |
3086 | if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)) | ||
3087 | cdev_del(&driver->cdevs[index]); | ||
3064 | } | 3088 | } |
3065 | EXPORT_SYMBOL(tty_unregister_device); | 3089 | EXPORT_SYMBOL(tty_unregister_device); |
3066 | 3090 | ||
@@ -3077,6 +3101,7 @@ struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner, | |||
3077 | unsigned long flags) | 3101 | unsigned long flags) |
3078 | { | 3102 | { |
3079 | struct tty_driver *driver; | 3103 | struct tty_driver *driver; |
3104 | unsigned int cdevs = 1; | ||
3080 | int err; | 3105 | int err; |
3081 | 3106 | ||
3082 | if (!lines || (flags & TTY_DRIVER_UNNUMBERED_NODE && lines > 1)) | 3107 | if (!lines || (flags & TTY_DRIVER_UNNUMBERED_NODE && lines > 1)) |
@@ -3110,6 +3135,13 @@ struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner, | |||
3110 | err = -ENOMEM; | 3135 | err = -ENOMEM; |
3111 | goto err_free_all; | 3136 | goto err_free_all; |
3112 | } | 3137 | } |
3138 | cdevs = lines; | ||
3139 | } | ||
3140 | |||
3141 | driver->cdevs = kcalloc(cdevs, sizeof(*driver->cdevs), GFP_KERNEL); | ||
3142 | if (!driver->cdevs) { | ||
3143 | err = -ENOMEM; | ||
3144 | goto err_free_all; | ||
3113 | } | 3145 | } |
3114 | 3146 | ||
3115 | return driver; | 3147 | return driver; |
@@ -3144,8 +3176,10 @@ static void destruct_tty_driver(struct kref *kref) | |||
3144 | tty_unregister_device(driver, i); | 3176 | tty_unregister_device(driver, i); |
3145 | } | 3177 | } |
3146 | proc_tty_unregister_driver(driver); | 3178 | proc_tty_unregister_driver(driver); |
3147 | cdev_del(&driver->cdev); | 3179 | if (driver->flags & TTY_DRIVER_DYNAMIC_ALLOC) |
3180 | cdev_del(&driver->cdevs[0]); | ||
3148 | } | 3181 | } |
3182 | kfree(driver->cdevs); | ||
3149 | kfree(driver->ports); | 3183 | kfree(driver->ports); |
3150 | kfree(driver->termios); | 3184 | kfree(driver->termios); |
3151 | kfree(driver->ttys); | 3185 | kfree(driver->ttys); |
@@ -3195,11 +3229,11 @@ int tty_register_driver(struct tty_driver *driver) | |||
3195 | if (error < 0) | 3229 | if (error < 0) |
3196 | goto err; | 3230 | goto err; |
3197 | 3231 | ||
3198 | cdev_init(&driver->cdev, &tty_fops); | 3232 | if (driver->flags & TTY_DRIVER_DYNAMIC_ALLOC) { |
3199 | driver->cdev.owner = driver->owner; | 3233 | error = tty_cdev_add(driver, dev, 0, driver->num); |
3200 | error = cdev_add(&driver->cdev, dev, driver->num); | 3234 | if (error) |
3201 | if (error) | 3235 | goto err_unreg_char; |
3202 | goto err_unreg_char; | 3236 | } |
3203 | 3237 | ||
3204 | mutex_lock(&tty_mutex); | 3238 | mutex_lock(&tty_mutex); |
3205 | list_add(&driver->tty_drivers, &tty_drivers); | 3239 | list_add(&driver->tty_drivers, &tty_drivers); |