static int pty_install(struct tty_driver *driver, struct tty_struct *tty) { struct tty_struct *o_tty; int idx = tty->index; int retval; o_tty = alloc_tty_struct(); if (!o_tty) return -ENOMEM; if (!try_module_get(driver->other->owner)) { /* This cannot in fact currently happen */ retval = -ENOMEM; goto err_free_tty; } initialize_tty_struct(o_tty, driver->other, idx); /* We always use new tty termios data so we can do this the easy way .. */ retval = tty_init_termios(tty); if (retval) goto err_deinit_tty; retval = tty_init_termios(o_tty); if (retval) goto err_free_termios; /* * Everything allocated ... set up the o_tty structure. */ driver->other->ttys[idx] = o_tty; tty_driver_kref_get(driver->other); if (driver->subtype == PTY_TYPE_MASTER) o_tty->count++; /* Establish the links in both directions */ tty->link = o_tty; o_tty->link = tty; tty_driver_kref_get(driver); tty->count++; driver->ttys[idx] = tty; return 0; err_free_termios: tty_free_termios(tty); err_deinit_tty: deinitialize_tty_struct(o_tty); module_put(o_tty->driver->owner); err_free_tty: free_tty_struct(o_tty); return retval; }
static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty) { struct tty_struct *o_tty; int idx = tty->index; o_tty = alloc_tty_struct(); if (!o_tty) return -ENOMEM; if (!try_module_get(driver->other->owner)) { /* This cannot in fact currently happen */ goto err_free_tty; } initialize_tty_struct(o_tty, driver->other, idx); tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL); if (tty->termios == NULL) goto err_free_mem; *tty->termios = driver->init_termios; tty->termios_locked = tty->termios + 1; o_tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL); if (o_tty->termios == NULL) goto err_free_mem; *o_tty->termios = driver->other->init_termios; o_tty->termios_locked = o_tty->termios + 1; tty_driver_kref_get(driver->other); if (driver->subtype == PTY_TYPE_MASTER) o_tty->count++; /* Establish the links in both directions */ tty->link = o_tty; o_tty->link = tty; /* * All structures have been allocated, so now we install them. * Failures after this point use release_tty to clean up, so * there's no need to null out the local pointers. */ tty_driver_kref_get(driver); tty->count++; return 0; err_free_mem: deinitialize_tty_struct(o_tty); kfree(o_tty->termios); kfree(tty->termios); module_put(o_tty->driver->owner); err_free_tty: free_tty_struct(o_tty); return -ENOMEM; }
/** * pty_common_install - set up the pty pair * @driver: the pty driver * @tty: the tty being instantiated * @bool: legacy, true if this is BSD style * * Perform the initial set up for the tty/pty pair. Called from the * tty layer when the port is first opened. * * Locking: the caller must hold the tty_mutex */ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty, bool legacy) { struct tty_struct *o_tty; struct tty_port *ports[2]; int idx = tty->index; int retval = -ENOMEM; o_tty = alloc_tty_struct(); if (!o_tty) goto err; ports[0] = kmalloc(sizeof **ports, GFP_KERNEL); ports[1] = kmalloc(sizeof **ports, GFP_KERNEL); if (!ports[0] || !ports[1]) goto err_free_tty; if (!try_module_get(driver->other->owner)) { /* This cannot in fact currently happen */ goto err_free_tty; } initialize_tty_struct(o_tty, driver->other, idx); if (legacy) { /* We always use new tty termios data so we can do this the easy way .. */ retval = tty_init_termios(tty); if (retval) goto err_deinit_tty; retval = tty_init_termios(o_tty); if (retval) goto err_free_termios; driver->other->ttys[idx] = o_tty; driver->ttys[idx] = tty; } else { memset(&tty->termios_locked, 0, sizeof(tty->termios_locked)); tty->termios = driver->init_termios; memset(&o_tty->termios_locked, 0, sizeof(tty->termios_locked)); o_tty->termios = driver->other->init_termios; } /* * Everything allocated ... set up the o_tty structure. */ tty_driver_kref_get(driver->other); if (driver->subtype == PTY_TYPE_MASTER) o_tty->count++; /* Establish the links in both directions */ tty->link = o_tty; o_tty->link = tty; tty_port_init(ports[0]); tty_port_init(ports[1]); o_tty->port = ports[0]; tty->port = ports[1]; o_tty->port->itty = o_tty; tty_driver_kref_get(driver); tty->count++; return 0; err_free_termios: if (legacy) tty_free_termios(tty); err_deinit_tty: deinitialize_tty_struct(o_tty); module_put(o_tty->driver->owner); err_free_tty: kfree(ports[0]); kfree(ports[1]); free_tty_struct(o_tty); err: return retval; }
/* * This is so ripe with races that you should *really* not touch this * unless you know exactly what you are doing. All the changes have to be * made atomically, or there may be incorrect pointers all over the place. */ static int init_dev(int dev) { struct tty_struct *tty, *o_tty; struct termios *tp, *o_tp, *ltp, *o_ltp; int retval; int o_dev; o_dev = PTY_OTHER(dev); tty = o_tty = NULL; tp = o_tp = NULL; ltp = o_ltp = NULL; repeat: retval = -EAGAIN; if (IS_A_PTY_MASTER(dev) && tty_table[dev] && tty_table[dev]->count) goto end_init; retval = -ENOMEM; if (!tty_table[dev] && !tty) { if (!(tty = (struct tty_struct*) get_free_page(GFP_KERNEL))) goto end_init; initialize_tty_struct(dev, tty); goto repeat; } if (!tty_termios[dev] && !tp) { tp = (struct termios *) kmalloc(sizeof(struct termios), GFP_KERNEL); if (!tp) goto end_init; initialize_termios(dev, tp); goto repeat; } if (!termios_locked[dev] && !ltp) { ltp = (struct termios *) kmalloc(sizeof(struct termios), GFP_KERNEL); if (!ltp) goto end_init; memset(ltp, 0, sizeof(struct termios)); goto repeat; } if (IS_A_PTY(dev)) { if (!tty_table[o_dev] && !o_tty) { o_tty = (struct tty_struct *) get_free_page(GFP_KERNEL); if (!o_tty) goto end_init; initialize_tty_struct(o_dev, o_tty); goto repeat; } if (!tty_termios[o_dev] && !o_tp) { o_tp = (struct termios *) kmalloc(sizeof(struct termios), GFP_KERNEL); if (!o_tp) goto end_init; initialize_termios(o_dev, o_tp); goto repeat; } if (!termios_locked[o_dev] && !o_ltp) { o_ltp = (struct termios *) kmalloc(sizeof(struct termios), GFP_KERNEL); if (!o_ltp) goto end_init; memset(o_ltp, 0, sizeof(struct termios)); goto repeat; } } /* Now we have allocated all the structures: update all the pointers.. */ if (!tty_termios[dev]) { tty_termios[dev] = tp; tp = NULL; } if (!tty_table[dev]) { tty->termios = tty_termios[dev]; tty_table[dev] = tty; tty = NULL; } if (!termios_locked[dev]) { termios_locked[dev] = ltp; ltp = NULL; } if (IS_A_PTY(dev)) { if (!tty_termios[o_dev]) { tty_termios[o_dev] = o_tp; o_tp = NULL; } if (!termios_locked[o_dev]) { termios_locked[o_dev] = o_ltp; o_ltp = NULL; } if (!tty_table[o_dev]) { o_tty->termios = tty_termios[o_dev]; tty_table[o_dev] = o_tty; o_tty = NULL; } tty_table[dev]->link = tty_table[o_dev]; tty_table[o_dev]->link = tty_table[dev]; } tty_table[dev]->count++; if (IS_A_PTY_MASTER(dev)) tty_table[o_dev]->count++; retval = 0; end_init: if (tty) free_page((unsigned long) tty); if (o_tty) free_page((unsigned long) o_tty); if (tp) kfree_s(tp, sizeof(struct termios)); if (o_tp) kfree_s(o_tp, sizeof(struct termios)); if (ltp) kfree_s(ltp, sizeof(struct termios)); if (o_ltp) kfree_s(o_ltp, sizeof(struct termios)); return retval; }