]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - drivers/char/tty_io.c
tty_io: check return code of tty_register_device
[net-next-2.6.git] / drivers / char / tty_io.c
index 949067a0bd4743151515382b07ccf7aecad11316..e185db36f8ad1e33830f8521f1731f65d6a8c80c 100644 (file)
@@ -183,6 +183,8 @@ struct tty_struct *alloc_tty_struct(void)
 
 void free_tty_struct(struct tty_struct *tty)
 {
+       if (tty->dev)
+               put_device(tty->dev);
        kfree(tty->write_buf);
        tty_buffer_free_all(tty);
        kfree(tty);
@@ -194,12 +196,13 @@ static inline struct tty_struct *file_tty(struct file *file)
 }
 
 /* Associate a new file with the tty structure */
-void tty_add_file(struct tty_struct *tty, struct file *file)
+int tty_add_file(struct tty_struct *tty, struct file *file)
 {
        struct tty_file_private *priv;
 
-       /* XXX: must implement proper error handling in callers */
-       priv = kmalloc(sizeof(*priv), GFP_KERNEL|__GFP_NOFAIL);
+       priv = kmalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
 
        priv->tty = tty;
        priv->file = file;
@@ -208,6 +211,8 @@ void tty_add_file(struct tty_struct *tty, struct file *file)
        spin_lock(&tty_files_lock);
        list_add(&priv->list, &tty->tty_files);
        spin_unlock(&tty_files_lock);
+
+       return 0;
 }
 
 /* Delete file from its tty */
@@ -355,7 +360,7 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
                if (*stp == '\0')
                        stp = NULL;
 
-               if (tty_line >= 0 && tty_line <= p->num && p->ops &&
+               if (tty_line >= 0 && tty_line < p->num && p->ops &&
                    p->ops->poll_init && !p->ops->poll_init(p, tty_line, stp)) {
                        res = tty_driver_kref_get(p);
                        *line = tty_line;
@@ -1875,7 +1880,11 @@ got_driver:
                return PTR_ERR(tty);
        }
 
-       tty_add_file(tty, filp);
+       retval = tty_add_file(tty, filp);
+       if (retval) {
+               tty_unlock();
+               return retval;
+       }
 
        check_tty_count(tty, "tty_open");
        if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
@@ -2783,6 +2792,20 @@ void do_SAK(struct tty_struct *tty)
 
 EXPORT_SYMBOL(do_SAK);
 
+static int dev_match_devt(struct device *dev, void *data)
+{
+       dev_t *devt = data;
+       return dev->devt == *devt;
+}
+
+/* Must put_device() after it's unused! */
+static struct device *tty_get_device(struct tty_struct *tty)
+{
+       dev_t devt = tty_devnum(tty);
+       return class_find_device(tty_class, NULL, &devt, dev_match_devt);
+}
+
+
 /**
  *     initialize_tty_struct
  *     @tty: tty to initialize
@@ -2823,6 +2846,7 @@ void initialize_tty_struct(struct tty_struct *tty,
        tty->ops = driver->ops;
        tty->index = idx;
        tty_line_name(driver, idx, tty->name);
+       tty->dev = tty_get_device(tty);
 }
 
 /**
@@ -2980,6 +3004,7 @@ int tty_register_driver(struct tty_driver *driver)
        int i;
        dev_t dev;
        void **p = NULL;
+       struct device *d;
 
        if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
                p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);
@@ -3027,12 +3052,31 @@ int tty_register_driver(struct tty_driver *driver)
        mutex_unlock(&tty_mutex);
 
        if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) {
-               for (i = 0; i < driver->num; i++)
-                   tty_register_device(driver, i, NULL);
+               for (i = 0; i < driver->num; i++) {
+                       d = tty_register_device(driver, i, NULL);
+                       if (IS_ERR(d)) {
+                               error = PTR_ERR(d);
+                               goto err;
+                       }
+               }
        }
        proc_tty_register_driver(driver);
        driver->flags |= TTY_DRIVER_INSTALLED;
        return 0;
+
+err:
+       for (i--; i >= 0; i--)
+               tty_unregister_device(driver, i);
+
+       mutex_lock(&tty_mutex);
+       list_del(&driver->tty_drivers);
+       mutex_unlock(&tty_mutex);
+
+       unregister_chrdev_region(dev, driver->num);
+       driver->ttys = NULL;
+       driver->termios = NULL;
+       kfree(p);
+       return error;
 }
 
 EXPORT_SYMBOL(tty_register_driver);