[PATCH 00/80] TTY updates for 2.6.28 - Kernel

This is a discussion on [PATCH 00/80] TTY updates for 2.6.28 - Kernel ; From: Alan Cox This is pure tty code so put it in the tty layer where it can be with the locking relevant material it uses Signed-off-by: Alan Cox --- drivers/char/tty_io.c | 25 +++++++++++++++++++++++++ kernel/printk.c | 16 ---------------- 2 files ...

+ Reply to Thread
Page 2 of 4 FirstFirst 1 2 3 4 LastLast
Results 21 to 40 of 70

Thread: [PATCH 00/80] TTY updates for 2.6.28

  1. [PATCH 43/80] tty: Move tty_write_message out of kernel/printk

    From: Alan Cox

    This is pure tty code so put it in the tty layer where it can be with the
    locking relevant material it uses

    Signed-off-by: Alan Cox
    ---

    drivers/char/tty_io.c | 25 +++++++++++++++++++++++++
    kernel/printk.c | 16 ----------------
    2 files changed, 25 insertions(+), 16 deletions(-)


    diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
    index 4c0e4ed..913b502 100644
    --- a/drivers/char/tty_io.c
    +++ b/drivers/char/tty_io.c
    @@ -1081,6 +1081,31 @@ out:
    return ret;
    }

    +/**
    + * tty_write_message - write a message to a certain tty, not just the console.
    + * @tty: the destination tty_struct
    + * @msg: the message to write
    + *
    + * This is used for messages that need to be redirected to a specific tty.
    + * We don't put it into the syslog queue right now maybe in the future if
    + * really needed.
    + *
    + * We must still hold the BKL and test the CLOSING flag for the moment.
    + */
    +
    +void tty_write_message(struct tty_struct *tty, char *msg)
    +{
    + lock_kernel();
    + if (tty) {
    + mutex_lock(&tty->atomic_write_lock);
    + if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags))
    + tty->ops->write(tty, msg, strlen(msg));
    + tty_write_unlock(tty);
    + }
    + unlock_kernel();
    + return;
    +}
    +

    /**
    * tty_write - write method for tty device file
    diff --git a/kernel/printk.c b/kernel/printk.c
    index b51b156..a430fd0 100644
    --- a/kernel/printk.c
    +++ b/kernel/printk.c
    @@ -1291,22 +1291,6 @@ static int __init disable_boot_consoles(void)
    }
    late_initcall(disable_boot_consoles);

    -/**
    - * tty_write_message - write a message to a certain tty, not just the console.
    - * @tty: the destination tty_struct
    - * @msg: the message to write
    - *
    - * This is used for messages that need to be redirected to a specific tty.
    - * We don't put it into the syslog queue right now maybe in the future if
    - * really needed.
    - */
    -void tty_write_message(struct tty_struct *tty, char *msg)
    -{
    - if (tty && tty->ops->write)
    - tty->ops->write(tty, msg, strlen(msg));
    - return;
    -}
    -
    #if defined CONFIG_PRINTK

    /*

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  2. [PATCH 33/80] tty: Split tty_port into its own file

    From: Alan Cox

    Not much in it yet but this will grow a lot

    Signed-off-by: Alan Cox
    ---

    drivers/char/Makefile | 2 +-
    drivers/char/tty_io.c | 36 -------------------------------
    drivers/char/tty_port.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++
    3 files changed, 56 insertions(+), 37 deletions(-)
    create mode 100644 drivers/char/tty_port.c


    diff --git a/drivers/char/Makefile b/drivers/char/Makefile
    index 77ea41b..1a4247d 100644
    --- a/drivers/char/Makefile
    +++ b/drivers/char/Makefile
    @@ -7,7 +7,7 @@
    #
    FONTMAPFILE = cp437.uni

    -obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o
    +obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o tty_port.o

    obj-$(CONFIG_LEGACY_PTYS) += pty.o
    obj-$(CONFIG_UNIX98_PTYS) += pty.o
    diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
    index 3a72693..7323168 100644
    --- a/drivers/char/tty_io.c
    +++ b/drivers/char/tty_io.c
    @@ -1139,42 +1139,6 @@ ssize_t redirected_tty_write(struct file *file, const char __user *buf,
    return tty_write(file, buf, count, ppos);
    }

    -void tty_port_init(struct tty_port *port)
    -{
    - memset(port, 0, sizeof(*port));
    - init_waitqueue_head(&port->open_wait);
    - init_waitqueue_head(&port->close_wait);
    - mutex_init(&port->mutex);
    - port->close_delay = (50 * HZ) / 100;
    - port->closing_wait = (3000 * HZ) / 100;
    -}
    -EXPORT_SYMBOL(tty_port_init);
    -
    -int tty_port_alloc_xmit_buf(struct tty_port *port)
    -{
    - /* We may sleep in get_zeroed_page() */
    - mutex_lock(&port->mutex);
    - if (port->xmit_buf == NULL)
    - port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
    - mutex_unlock(&port->mutex);
    - if (port->xmit_buf == NULL)
    - return -ENOMEM;
    - return 0;
    -}
    -EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
    -
    -void tty_port_free_xmit_buf(struct tty_port *port)
    -{
    - mutex_lock(&port->mutex);
    - if (port->xmit_buf != NULL) {
    - free_page((unsigned long)port->xmit_buf);
    - port->xmit_buf = NULL;
    - }
    - mutex_unlock(&port->mutex);
    -}
    -EXPORT_SYMBOL(tty_port_free_xmit_buf);
    -
    -
    static char ptychar[] = "pqrstuvwxyzabcde";

    /**
    diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c
    new file mode 100644
    index 0000000..6fadb19
    --- /dev/null
    +++ b/drivers/char/tty_port.c
    @@ -0,0 +1,55 @@
    +/*
    + * Tty port functions
    + */
    +
    +#include
    +#include
    +#include
    +#include
    +#include
    +#include
    +#include
    +#include
    +#include
    +#include
    +#include
    +#include
    +#include
    +#include
    +
    +void tty_port_init(struct tty_port *port)
    +{
    + memset(port, 0, sizeof(*port));
    + init_waitqueue_head(&port->open_wait);
    + init_waitqueue_head(&port->close_wait);
    + mutex_init(&port->mutex);
    + port->close_delay = (50 * HZ) / 100;
    + port->closing_wait = (3000 * HZ) / 100;
    +}
    +EXPORT_SYMBOL(tty_port_init);
    +
    +int tty_port_alloc_xmit_buf(struct tty_port *port)
    +{
    + /* We may sleep in get_zeroed_page() */
    + mutex_lock(&port->mutex);
    + if (port->xmit_buf == NULL)
    + port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
    + mutex_unlock(&port->mutex);
    + if (port->xmit_buf == NULL)
    + return -ENOMEM;
    + return 0;
    +}
    +EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
    +
    +void tty_port_free_xmit_buf(struct tty_port *port)
    +{
    + mutex_lock(&port->mutex);
    + if (port->xmit_buf != NULL) {
    + free_page((unsigned long)port->xmit_buf);
    + port->xmit_buf = NULL;
    + }
    + mutex_unlock(&port->mutex);
    +}
    +EXPORT_SYMBOL(tty_port_free_xmit_buf);
    +
    +

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  3. [PATCH 23/80] nozomi: Fix close on error

    From: Alan Cox

    Nozomi assumes the close method isn't called if open errors. The tty layer
    is different to other drives in this respect however. Pointed out by Denis J
    Barrow.

    Signed-off-by: Alan Cox
    ---

    drivers/char/nozomi.c | 5 ++++-
    1 files changed, 4 insertions(+), 1 deletions(-)


    diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c
    index 66a0f93..9a34a19 100644
    --- a/drivers/char/nozomi.c
    +++ b/drivers/char/nozomi.c
    @@ -1599,7 +1599,10 @@ static int ntty_open(struct tty_struct *tty, struct file *file)
    return 0;
    }

    -/* Called when the userspace process close the tty, /dev/noz*. */
    +/* Called when the userspace process close the tty, /dev/noz*. Also
    + called immediately if ntty_open fails in which case tty->driver_data
    + will be NULL an we exit by the first return */
    +
    static void ntty_close(struct tty_struct *tty, struct file *file)
    {
    struct nozomi *dc = get_dc_by_tty(tty);

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  4. [PATCH 26/80] ftdi: A few errors are err() that should be debug which causes much spewage

    From: Alan Cox

    Fixes #10783

    Signed-off-by: Alan Cox
    ---

    drivers/usb/serial/ftdi_sio.c | 6 +++---
    1 files changed, 3 insertions(+), 3 deletions(-)


    diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
    index 3dc93b5..1ac7e80 100644
    --- a/drivers/usb/serial/ftdi_sio.c
    +++ b/drivers/usb/serial/ftdi_sio.c
    @@ -860,7 +860,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set,

    kfree(buf);
    if (rv < 0) {
    - err("%s Error from MODEM_CTRL urb: DTR %s, RTS %s",
    + dbg("%s Error from MODEM_CTRL urb: DTR %s, RTS %s",
    __func__,
    (set & TIOCM_DTR) ? "HIGH" :
    (clear & TIOCM_DTR) ? "LOW" : "unchanged",
    @@ -2256,7 +2256,7 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file)
    0, 0,
    buf, 1, WDR_TIMEOUT);
    if (ret < 0) {
    - err("%s Could not get modem status of device - err: %d", __func__,
    + dbg("%s Could not get modem status of device - err: %d", __func__,
    ret);
    return ret;
    }
    @@ -2275,7 +2275,7 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file)
    0, priv->interface,
    buf, 2, WDR_TIMEOUT);
    if (ret < 0) {
    - err("%s Could not get modem status of device - err: %d", __func__,
    + dbg("%s Could not get modem status of device - err: %d", __func__,
    ret);
    return ret;
    }

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  5. [PATCH 41/80] tty: compare the tty winsize

    From: Alan Cox

    We always use the real tty one for stuff so the pty one should not be
    compared. As we propogate window changes to both it doesn't currently
    matter but will when we tidy up the pty termios logic a bit more

    Signed-off-by: Alan Cox
    ---

    drivers/char/tty_io.c | 2 +-
    1 files changed, 1 insertions(+), 1 deletions(-)


    diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
    index ac53d7f..9a76db3 100644
    --- a/drivers/char/tty_io.c
    +++ b/drivers/char/tty_io.c
    @@ -2133,7 +2133,7 @@ int tty_do_resize(struct tty_struct *tty, struct tty_struct *real_tty,

    /* For a PTY we need to lock the tty side */
    mutex_lock(&real_tty->termios_mutex);
    - if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
    + if (!memcmp(ws, &real_tty->winsize, sizeof(*ws)))
    goto done;
    /* Get the PID values and reference them so we can
    avoid holding the tty ctrl lock while sending signals */

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  6. [PATCH 42/80] tty: Make get_current_tty use a kref

    From: Alan Cox

    We now return a kref covered tty reference. That ensures the tty structure
    doesn't go away when you have a return from get_current_tty. This is not
    enough to protect you from most of the resources being freed behind your
    back - yet.

    [Updated to include fixes for SELinux problems found by Andrew Morton and
    an s390 leak found while debugging the former]

    Signed-off-by: Alan Cox
    ---

    drivers/char/tty_io.c | 10 ++++++----
    drivers/s390/char/fs3270.c | 3 ++-
    fs/dquot.c | 6 +++---
    security/selinux/hooks.c | 3 ++-
    4 files changed, 13 insertions(+), 9 deletions(-)


    diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
    index 9a76db3..4c0e4ed 100644
    --- a/drivers/char/tty_io.c
    +++ b/drivers/char/tty_io.c
    @@ -786,12 +786,12 @@ void disassociate_ctty(int on_exit)
    tty = get_current_tty();
    if (tty) {
    tty_pgrp = get_pid(tty->pgrp);
    - lock_kernel();
    mutex_unlock(&tty_mutex);
    - /* XXX: here we race, there is nothing protecting tty */
    + lock_kernel();
    if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY)
    tty_vhangup(tty);
    unlock_kernel();
    + tty_kref_put(tty);
    } else if (on_exit) {
    struct pid *old_pgrp;
    spin_lock_irq(&current->sighand->siglock);
    @@ -819,7 +819,6 @@ void disassociate_ctty(int on_exit)
    spin_unlock_irq(&current->sighand->siglock);

    mutex_lock(&tty_mutex);
    - /* It is possible that do_tty_hangup has free'd this tty */
    tty = get_current_tty();
    if (tty) {
    unsigned long flags;
    @@ -829,6 +828,7 @@ void disassociate_ctty(int on_exit)
    tty->session = NULL;
    tty->pgrp = NULL;
    spin_unlock_irqrestore(&tty->ctrl_lock, flags);
    + tty_kref_put(tty);
    } else {
    #ifdef TTY_DEBUG_HANGUP
    printk(KERN_DEBUG "error attempted to write to tty [0x%p]"
    @@ -1806,6 +1806,8 @@ retry_open:
    index = tty->index;
    filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
    /* noctty = 1; */
    + /* FIXME: Should we take a driver reference ? */
    + tty_kref_put(tty);
    goto got_driver;
    }
    #ifdef CONFIG_VT
    @@ -3135,7 +3137,7 @@ struct tty_struct *get_current_tty(void)
    {
    struct tty_struct *tty;
    WARN_ON_ONCE(!mutex_is_locked(&tty_mutex));
    - tty = current->signal->tty;
    + tty = tty_kref_get(current->signal->tty);
    /*
    * session->tty can be changed/cleared from under us, make sure we
    * issue the load. The obtained pointer, when not NULL, is valid as
    diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c
    index d18e6d2..3ef5425 100644
    --- a/drivers/s390/char/fs3270.c
    +++ b/drivers/s390/char/fs3270.c
    @@ -430,11 +430,12 @@ fs3270_open(struct inode *inode, struct file *filp)
    mutex_lock(&tty_mutex);
    tty = get_current_tty();
    if (!tty || tty->driver->major != IBM_TTY3270_MAJOR) {
    - mutex_unlock(&tty_mutex);
    + tty_kref_put(tty);
    rc = -ENODEV;
    goto out;
    }
    minor = tty->index + RAW3270_FIRSTMINOR;
    + tty_kref_put(tty);
    mutex_unlock(&tty_mutex);
    }
    /* Check if some other program is already using fullscreen mode. */
    diff --git a/fs/dquot.c b/fs/dquot.c
    index 8ec4d6c..7417a6c 100644
    --- a/fs/dquot.c
    +++ b/fs/dquot.c
    @@ -897,8 +897,9 @@ static void print_warning(struct dquot *dquot, const int warntype)

    mutex_lock(&tty_mutex);
    tty = get_current_tty();
    + mutex_unlock(&tty_mutex);
    if (!tty)
    - goto out_lock;
    + return;
    tty_write_message(tty, dquot->dq_sb->s_id);
    if (warntype == QUOTA_NL_ISOFTWARN || warntype == QUOTA_NL_BSOFTWARN)
    tty_write_message(tty, ": warning, ");
    @@ -926,8 +927,7 @@ static void print_warning(struct dquot *dquot, const int warntype)
    break;
    }
    tty_write_message(tty, msg);
    -out_lock:
    - mutex_unlock(&tty_mutex);
    + tty_kref_put(tty);
    }
    #endif

    diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
    index 4a7374c..089d61a 100644
    --- a/security/selinux/hooks.c
    +++ b/security/selinux/hooks.c
    @@ -2123,6 +2123,7 @@ static inline void flush_unauthorized_files(struct files_struct *files)

    mutex_lock(&tty_mutex);
    tty = get_current_tty();
    + mutex_unlock(&tty_mutex);
    if (tty) {
    file_list_lock();
    file = list_entry(tty->tty_files.next, typeof(*file), f_u.fu_list);
    @@ -2139,8 +2140,8 @@ static inline void flush_unauthorized_files(struct files_struct *files)
    }
    }
    file_list_unlock();
    + tty_kref_put(tty);
    }
    - mutex_unlock(&tty_mutex);
    /* Reset controlling tty. */
    if (drop_tty)
    no_tty();

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  7. [PATCH 25/80] usb: fix pl2303 initialization

    From: Jason Wessel

    This patch removes the private check for the termios_initialized for
    the pl2303 usb driver. It forced the baud to 9600 on the first call
    to pl2303_set_termios()

    Based on the tty changes in the 2.6.27 kernel, the termios passed to
    the *_set_termios functions is always populated the first time.

    This means there is no need to privately initialize the settings the
    first time, and doing so will not allow the use of the kernel
    parameter "console=ttyUSB0,115200" as an example.

    Signed-off-by: Jason Wessel
    Signed-off-by: Alan Cox
    ---

    drivers/usb/serial/pl2303.c | 11 -----------
    1 files changed, 0 insertions(+), 11 deletions(-)


    diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
    index 1ede144..8d60068 100644
    --- a/drivers/usb/serial/pl2303.c
    +++ b/drivers/usb/serial/pl2303.c
    @@ -154,7 +154,6 @@ struct pl2303_private {
    wait_queue_head_t delta_msr_wait;
    u8 line_control;
    u8 line_status;
    - u8 termios_initialized;
    enum pl2303_type type;
    };

    @@ -526,16 +525,6 @@ static void pl2303_set_termios(struct tty_struct *tty,

    dbg("%s - port %d", __func__, port->number);

    - spin_lock_irqsave(&priv->lock, flags);
    - if (!priv->termios_initialized) {
    - *(tty->termios) = tty_std_termios;
    - tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
    - tty->termios->c_ispeed = 9600;
    - tty->termios->c_ospeed = 9600;
    - priv->termios_initialized = 1;
    - }
    - spin_unlock_irqrestore(&priv->lock, flags);
    -
    /* The PL2303 is reported to lose bytes if you change
    serial settings even to the same values as before. Thus
    we actually need to filter in this specific case */

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  8. [PATCH 34/80] pps: Reserve a line discipline number for PPS

    From: Alan Cox

    Add a new line discipline for "pulse per second" devices connected to
    a serial port.

    Signed-off-by: Rodolfo Giometti
    Signed-off-by: Alan Cox
    ---

    include/linux/tty.h | 3 ++-
    1 files changed, 2 insertions(+), 1 deletions(-)


    diff --git a/include/linux/tty.h b/include/linux/tty.h
    index 7271c62..e3612c3 100644
    --- a/include/linux/tty.h
    +++ b/include/linux/tty.h
    @@ -23,7 +23,7 @@
    */
    #define NR_UNIX98_PTY_DEFAULT 4096 /* Default maximum for Unix98 ptys */
    #define NR_UNIX98_PTY_MAX (1 << MINORBITS) /* Absolute limit */
    -#define NR_LDISCS 18
    +#define NR_LDISCS 19

    /* line disciplines */
    #define N_TTY 0
    @@ -45,6 +45,7 @@
    #define N_HCI 15 /* Bluetooth HCI UART */
    #define N_GIGASET_M101 16 /* Siemens Gigaset M101 serial DECT adapter */
    #define N_SLCAN 17 /* Serial / USB serial CAN Adaptors */
    +#define N_PPS 18 /* Pulse per Second */

    /*
    * This character is the same as _POSIX_VDISABLE: it cannot be used as

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  9. [PATCH 36/80] tty: use krefs to protect driver module counts

    From: Alan Cox

    The tty layer keeps driver module counts that are used so the driver knows
    when it can be unloaded. For obvious reasons we want to tie that to the
    refcounting properly.

    At this point the driver side itself isn't refcounted nicely but we can do
    that later and kref the drivers.

    Signed-off-by: Alan Cox
    ---

    drivers/char/tty_io.c | 17 +++++++++++------
    1 files changed, 11 insertions(+), 6 deletions(-)


    diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
    index 310e070..fa162c9 100644
    --- a/drivers/char/tty_io.c
    +++ b/drivers/char/tty_io.c
    @@ -1293,6 +1293,12 @@ static int init_dev(struct tty_driver *driver, int idx,
    o_tty = alloc_tty_struct();
    if (!o_tty)
    goto free_mem_out;
    + if (!try_module_get(driver->other->owner)) {
    + /* This cannot in fact currently happen */
    + free_tty_struct(o_tty);
    + o_tty = NULL;
    + goto free_mem_out;
    + }
    initialize_tty_struct(o_tty);
    o_tty->driver = driver->other;
    o_tty->ops = driver->ops;
    @@ -1411,8 +1417,10 @@ end_init:
    /* Release locally allocated memory ... nothing placed in slots */
    free_mem_out:
    kfree(o_tp);
    - if (o_tty)
    + if (o_tty) {
    + module_put(o_tty->driver->owner);
    free_tty_struct(o_tty);
    + }
    kfree(ltp);
    kfree(tp);
    free_tty_struct(tty);
    @@ -1447,6 +1455,7 @@ release_mem_out:
    static void release_one_tty(struct kref *kref)
    {
    struct tty_struct *tty = container_of(kref, struct tty_struct, kref);
    + struct tty_driver *driver = tty->driver;
    int devpts = tty->driver->flags & TTY_DRIVER_DEVPTS_MEM;
    struct ktermios *tp;
    int idx = tty->index;
    @@ -1471,6 +1480,7 @@ static void release_one_tty(struct kref *kref)
    tty->magic = 0;
    /* FIXME: locking on tty->driver->refcount */
    tty->driver->refcount--;
    + module_put(driver->owner);

    file_list_lock();
    list_del_init(&tty->tty_files);
    @@ -1506,20 +1516,15 @@ EXPORT_SYMBOL(tty_kref_put);
    * of ttys that the driver keeps.
    * FIXME: should we require tty_mutex is held here ??
    *
    - * FIXME: We want to defer the module put of the driver to the
    - * destructor.
    */
    static void release_tty(struct tty_struct *tty, int idx)
    {
    - struct tty_driver *driver = tty->driver;
    -
    /* This should always be true but check for the moment */
    WARN_ON(tty->index != idx);

    if (tty->link)
    tty_kref_put(tty->link);
    tty_kref_put(tty);
    - module_put(driver->owner);
    }

    /*

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  10. [PATCH 56/80] tty: Clean up the tty_init_dev changes further

    From: Alan Cox

    Fix up the naming, style and extract some bits of code into the driver
    specific code

    Signed-off-by: Alan Cox
    ---

    drivers/char/pty.c | 49 +++++++++++++++++++++++++++++++++-
    drivers/char/tty_io.c | 64 +++++++++++++++++---------------------------
    include/linux/tty_driver.h | 9 ++++++
    3 files changed, 81 insertions(+), 41 deletions(-)


    diff --git a/drivers/char/pty.c b/drivers/char/pty.c
    index 328e8ac..6e148ad 100644
    --- a/drivers/char/pty.c
    +++ b/drivers/char/pty.c
    @@ -391,6 +391,41 @@ static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file,
    return -ENOIOCTLCMD;
    }

    +/**
    + * ptm_unix98_lookup - find a pty master
    + * @driver: ptm driver
    + * @idx: tty index
    + *
    + * Look up a pty master device. Called under the tty_mutex for now.
    + * This provides our locking.
    + */
    +
    +static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver, int idx)
    +{
    + struct tty_struct *tty = devpts_get_tty(idx);
    + if (tty)
    + tty = tty->link;
    + return tty;
    +}
    +
    +/**
    + * pts_unix98_lookup - find a pty slave
    + * @driver: pts driver
    + * @idx: tty index
    + *
    + * Look up a pty master device. Called under the tty_mutex for now.
    + * This provides our locking.
    + */
    +
    +static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver, int idx)
    +{
    + struct tty_struct *tty = devpts_get_tty(idx);
    + /* Master must be open before slave */
    + if (!tty)
    + return ERR_PTR(-EIO);
    + return tty;
    +}
    +
    static void pty_shutdown(struct tty_struct *tty)
    {
    /* We have our own method as we don't use the tty index */
    @@ -399,6 +434,7 @@ static void pty_shutdown(struct tty_struct *tty)
    }

    static const struct tty_operations ptm_unix98_ops = {
    + .lookup = ptm_unix98_lookup,
    .open = pty_open,
    .close = pty_close,
    .write = pty_write,
    @@ -411,6 +447,17 @@ static const struct tty_operations ptm_unix98_ops = {
    .shutdown = pty_shutdown
    };

    +static const struct tty_operations pty_unix98_ops = {
    + .lookup = pts_unix98_lookup,
    + .open = pty_open,
    + .close = pty_close,
    + .write = pty_write,
    + .write_room = pty_write_room,
    + .flush_buffer = pty_flush_buffer,
    + .chars_in_buffer = pty_chars_in_buffer,
    + .unthrottle = pty_unthrottle,
    + .set_termios = pty_set_termios,
    +};

    /**
    * ptmx_open - open a unix 98 pty master
    @@ -517,7 +564,7 @@ static void __init unix98_pty_init(void)
    pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
    TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
    pts_driver->other = ptm_driver;
    - tty_set_operations(pts_driver, &pty_ops);
    + tty_set_operations(pts_driver, &pty_unix98_ops);

    if (tty_register_driver(ptm_driver))
    panic("Couldn't register Unix98 ptm driver");
    diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
    index a540849..ac41af8 100644
    --- a/drivers/char/tty_io.c
    +++ b/drivers/char/tty_io.c
    @@ -1204,53 +1204,38 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p)
    sprintf(p, "%s%d", driver->name, index + driver->name_base);
    }

    -/*
    - * find_tty() - find an existing tty, if any
    - * @driver: the driver for the tty
    - * @idx: the minor number
    +/**
    + * tty_driver_lookup_tty() - find an existing tty, if any
    + * @driver: the driver for the tty
    + * @idx: the minor number
    *
    - * Return the tty, if found or ERR_PTR() otherwise.
    + * Return the tty, if found or ERR_PTR() otherwise.
    *
    - * Locking: tty_mutex must be held. If tty is found, the mutex must
    - * be held until the 'fast-open' is also done.
    + * Locking: tty_mutex must be held. If tty is found, the mutex must
    + * be held until the 'fast-open' is also done. Will change once we
    + * have refcounting in the driver and per driver locking
    */
    -struct tty_struct *find_tty(struct tty_driver *driver, int idx)
    +struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver, int idx)
    {
    struct tty_struct *tty;

    - /* check whether we're reopening an existing tty */
    - if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
    - tty = devpts_get_tty(idx);
    - /*
    - * If we don't have a tty here on a slave open, it's because
    - * the master already started the close process and there's
    - * no relation between devpts file and tty anymore.
    - */
    - if (!tty && driver->subtype == PTY_TYPE_SLAVE)
    - return ERR_PTR(-EIO);
    + if (driver->ops->lookup)
    + return driver->ops->lookup(driver, idx);

    - /*
    - * tty is safe on because we are called with tty_mutex held
    - * and release_dev() won't change tty->count or tty->flags
    - * without grabbing tty_mutex.
    - */
    - if (tty && driver->subtype == PTY_TYPE_MASTER)
    - tty = tty->link;
    - } else
    tty = driver->ttys[idx];
    return tty;
    }

    -/*
    - * fast_tty_open() - fast re-open of an open tty
    - * @tty - the tty to open
    +/**
    + * tty_reopen() - fast re-open of an open tty
    + * @tty - the tty to open
    *
    - * Return 0 on success, -errno on error.
    + * Return 0 on success, -errno on error.
    *
    - * Locking: tty_mutex must be held from the time the tty was found
    - * till this open completes.
    + * Locking: tty_mutex must be held from the time the tty was found
    + * till this open completes.
    */
    -static int fast_tty_open(struct tty_struct *tty)
    +static int tty_reopen(struct tty_struct *tty)
    {
    struct tty_driver *driver = tty->driver;

    @@ -1271,9 +1256,7 @@ static int fast_tty_open(struct tty_struct *tty)
    tty->count++;
    tty->driver = driver; /* N.B. why do this every time?? */

    - /* FIXME */
    - if (!test_bit(TTY_LDISC, &tty->flags))
    - printk(KERN_ERR "fast_tty_open: no ldisc\n");
    + WARN_ON(!test_bit(TTY_LDISC, &tty->flags));

    return 0;
    }
    @@ -1312,14 +1295,14 @@ int tty_init_dev(struct tty_driver *driver, int idx,
    int retval = 0;

    /* check whether we're reopening an existing tty */
    - tty = find_tty(driver, idx);
    + tty = tty_driver_lookup_tty(driver, idx);
    if (IS_ERR(tty)) {
    retval = PTR_ERR(tty);
    goto end_init;
    }

    if (tty) {
    - retval = fast_tty_open(tty);
    + retval = tty_reopen(tty);
    if (retval)
    return retval;
    *ret_tty = tty;
    @@ -1440,6 +1423,8 @@ int tty_init_dev(struct tty_driver *driver, int idx,
    * 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.
    + *
    + * FIXME: We want a 'driver->install method ?
    */
    if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM))
    driver->ttys[idx] = tty;
    @@ -1466,9 +1451,8 @@ int tty_init_dev(struct tty_driver *driver, int idx,

    if (retval)
    goto release_mem_out;
    -success:
    - *ret_tty = tty;

    + *ret_tty = tty;
    /* All paths come through here to release the mutex */
    end_init:
    return retval;
    diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
    index 2322313..2c5c35c 100644
    --- a/include/linux/tty_driver.h
    +++ b/include/linux/tty_driver.h
    @@ -7,6 +7,14 @@
    * defined; unless noted otherwise, they are optional, and can be
    * filled in with a null pointer.
    *
    + * struct tty_struct * (*lookup)(struct tty_driver *self, int idx)
    + *
    + * Return the tty device corresponding to idx, NULL if there is not
    + * one currently in use and an ERR_PTR value on error. Called under
    + * tty_mutex (for now!)
    + *
    + * Optional method. Default behaviour is to use the ttys array
    + *
    * int (*open)(struct tty_struct * tty, struct file * filp);
    *
    * This routine is called when a particular tty device is opened.
    @@ -203,6 +211,7 @@ struct tty_struct;
    struct tty_driver;

    struct tty_operations {
    + struct tty_struct * (*lookup)(struct tty_driver *driver, int idx);
    int (*open)(struct tty_struct * tty, struct file * filp);
    void (*close)(struct tty_struct * tty, struct file * filp);
    void (*shutdown)(struct tty_struct *tty);

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  11. [PATCH 64/80] Simplify devpts_pty_new()

    From: Sukadev Bhattiprolu

    devpts_pty_new() is called when setting up a new pty and would not
    will not have an existing dentry or inode for the pty. So don't bother
    looking for an existing dentry - just create a new one.

    Signed-off-by: Sukadev Bhattiprolu
    Signed-off-by: Alan Cox
    ---

    fs/devpts/inode.c | 11 ++++++++---
    1 files changed, 8 insertions(+), 3 deletions(-)


    diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
    index b292ed7..50e885f 100644
    --- a/fs/devpts/inode.c
    +++ b/fs/devpts/inode.c
    @@ -220,6 +220,7 @@ int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty)
    dev_t device = MKDEV(driver->major, driver->minor_start+number);
    struct dentry *dentry;
    struct inode *inode = new_inode(devpts_mnt->mnt_sb);
    + char s[12];

    /* We're supposed to be given the slave end of a pty */
    BUG_ON(driver->type != TTY_DRIVER_TYPE_PTY);
    @@ -235,9 +236,13 @@ int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty)
    init_special_inode(inode, S_IFCHR|config.mode, device);
    inode->i_private = tty;

    - dentry = get_node(number);
    - if (!IS_ERR(dentry) && !dentry->d_inode) {
    - d_instantiate(dentry, inode);
    + sprintf(s, "%d", number);
    +
    + mutex_lock(&devpts_root->d_inode->i_mutex);
    +
    + dentry = d_alloc_name(devpts_root, s);
    + if (!IS_ERR(dentry)) {
    + d_add(dentry, inode);
    fsnotify_create(devpts_root->d_inode, dentry);
    }


    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  12. [PATCH 47/80] mxser: Switch to kref tty

    From: Alan Cox

    Signed-off-by: Alan Cox
    ---

    drivers/char/mxser.c | 192 +++++++++++++++++++++++++++-----------------------
    1 files changed, 103 insertions(+), 89 deletions(-)


    diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
    index b638403..308cb60 100644
    --- a/drivers/char/mxser.c
    +++ b/drivers/char/mxser.c
    @@ -610,15 +610,16 @@ static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp,
    return 0;
    }

    -static int mxser_set_baud(struct mxser_port *info, long newspd)
    +static int mxser_set_baud(struct tty_struct *tty, long newspd)
    {
    + struct mxser_port *info = tty->driver_data;
    int quot = 0, baud;
    unsigned char cval;

    - if (!info->port.tty || !info->port.tty->termios)
    + if (!tty->termios)
    return -1;

    - if (!(info->ioaddr))
    + if (!info->ioaddr)
    return -1;

    if (newspd > info->max_baud)
    @@ -626,13 +627,13 @@ static int mxser_set_baud(struct mxser_port *info, long newspd)

    if (newspd == 134) {
    quot = 2 * info->baud_base / 269;
    - tty_encode_baud_rate(info->port.tty, 134, 134);
    + tty_encode_baud_rate(tty, 134, 134);
    } else if (newspd) {
    quot = info->baud_base / newspd;
    if (quot == 0)
    quot = 1;
    baud = info->baud_base/quot;
    - tty_encode_baud_rate(info->port.tty, baud, baud);
    + tty_encode_baud_rate(tty, baud, baud);
    } else {
    quot = 0;
    }
    @@ -658,7 +659,7 @@ static int mxser_set_baud(struct mxser_port *info, long newspd)
    outb(cval, info->ioaddr + UART_LCR); /* reset DLAB */

    #ifdef BOTHER
    - if (C_BAUD(info->port.tty) == BOTHER) {
    + if (C_BAUD(tty) == BOTHER) {
    quot = info->baud_base % newspd;
    quot *= 8;
    if (quot % newspd > newspd / 2) {
    @@ -679,21 +680,22 @@ static int mxser_set_baud(struct mxser_port *info, long newspd)
    * This routine is called to set the UART divisor registers to match
    * the specified baud rate for a serial port.
    */
    -static int mxser_change_speed(struct mxser_port *info,
    - struct ktermios *old_termios)
    +static int mxser_change_speed(struct tty_struct *tty,
    + struct ktermios *old_termios)
    {
    + struct mxser_port *info = tty->driver_data;
    unsigned cflag, cval, fcr;
    int ret = 0;
    unsigned char status;

    - if (!info->port.tty || !info->port.tty->termios)
    + if (!tty->termios)
    return ret;
    - cflag = info->port.tty->termios->c_cflag;
    - if (!(info->ioaddr))
    + cflag = tty->termios->c_cflag;
    + if (!info->ioaddr)
    return ret;

    - if (mxser_set_baud_method[info->port.tty->index] == 0)
    - mxser_set_baud(info, tty_get_baud_rate(info->port.tty));
    + if (mxser_set_baud_method[tty->index] == 0)
    + mxser_set_baud(tty, tty_get_baud_rate(tty));

    /* byte size and parity */
    switch (cflag & CSIZE) {
    @@ -762,9 +764,9 @@ static int mxser_change_speed(struct mxser_port *info,
    info->MCR |= UART_MCR_AFE;
    } else {
    status = inb(info->ioaddr + UART_MSR);
    - if (info->port.tty->hw_stopped) {
    + if (tty->hw_stopped) {
    if (status & UART_MSR_CTS) {
    - info->port.tty->hw_stopped = 0;
    + tty->hw_stopped = 0;
    if (info->type != PORT_16550A &&
    !info->board->chip_flag) {
    outb(info->IER & ~UART_IER_THRI,
    @@ -774,11 +776,11 @@ static int mxser_change_speed(struct mxser_port *info,
    outb(info->IER, info->ioaddr +
    UART_IER);
    }
    - tty_wakeup(info->port.tty);
    + tty_wakeup(tty);
    }
    } else {
    if (!(status & UART_MSR_CTS)) {
    - info->port.tty->hw_stopped = 1;
    + tty->hw_stopped = 1;
    if ((info->type != PORT_16550A) &&
    (!info->board->chip_flag)) {
    info->IER &= ~UART_IER_THRI;
    @@ -804,21 +806,21 @@ static int mxser_change_speed(struct mxser_port *info,
    * Set up parity check flag
    */
    info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
    - if (I_INPCK(info->port.tty))
    + if (I_INPCK(tty))
    info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
    - if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty))
    + if (I_BRKINT(tty) || I_PARMRK(tty))
    info->read_status_mask |= UART_LSR_BI;

    info->ignore_status_mask = 0;

    - if (I_IGNBRK(info->port.tty)) {
    + if (I_IGNBRK(tty)) {
    info->ignore_status_mask |= UART_LSR_BI;
    info->read_status_mask |= UART_LSR_BI;
    /*
    * If we're ignore parity and break indicators, ignore
    * overruns too. (For real raw support).
    */
    - if (I_IGNPAR(info->port.tty)) {
    + if (I_IGNPAR(tty)) {
    info->ignore_status_mask |=
    UART_LSR_OE |
    UART_LSR_PE |
    @@ -830,16 +832,16 @@ static int mxser_change_speed(struct mxser_port *info,
    }
    }
    if (info->board->chip_flag) {
    - mxser_set_must_xon1_value(info->ioaddr, START_CHAR(info->port.tty));
    - mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(info->port.tty));
    - if (I_IXON(info->port.tty)) {
    + mxser_set_must_xon1_value(info->ioaddr, START_CHAR(tty));
    + mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(tty));
    + if (I_IXON(tty)) {
    mxser_enable_must_rx_software_flow_control(
    info->ioaddr);
    } else {
    mxser_disable_must_rx_software_flow_control(
    info->ioaddr);
    }
    - if (I_IXOFF(info->port.tty)) {
    + if (I_IXOFF(tty)) {
    mxser_enable_must_tx_software_flow_control(
    info->ioaddr);
    } else {
    @@ -855,7 +857,8 @@ static int mxser_change_speed(struct mxser_port *info,
    return ret;
    }

    -static void mxser_check_modem_status(struct mxser_port *port, int status)
    +static void mxser_check_modem_status(struct tty_struct *tty,
    + struct mxser_port *port, int status)
    {
    /* update input line counters */
    if (status & UART_MSR_TERI)
    @@ -874,10 +877,11 @@ static void mxser_check_modem_status(struct mxser_port *port, int status)
    wake_up_interruptible(&port->port.open_wait);
    }

    + tty = tty_port_tty_get(&port->port);
    if (port->port.flags & ASYNC_CTS_FLOW) {
    - if (port->port.tty->hw_stopped) {
    + if (tty->hw_stopped) {
    if (status & UART_MSR_CTS) {
    - port->port.tty->hw_stopped = 0;
    + tty->hw_stopped = 0;

    if ((port->type != PORT_16550A) &&
    (!port->board->chip_flag)) {
    @@ -887,11 +891,11 @@ static void mxser_check_modem_status(struct mxser_port *port, int status)
    outb(port->IER, port->ioaddr +
    UART_IER);
    }
    - tty_wakeup(port->port.tty);
    + tty_wakeup(tty);
    }
    } else {
    if (!(status & UART_MSR_CTS)) {
    - port->port.tty->hw_stopped = 1;
    + tty->hw_stopped = 1;
    if (port->type != PORT_16550A &&
    !port->board->chip_flag) {
    port->IER &= ~UART_IER_THRI;
    @@ -903,8 +907,9 @@ static void mxser_check_modem_status(struct mxser_port *port, int status)
    }
    }

    -static int mxser_startup(struct mxser_port *info)
    +static int mxser_startup(struct tty_struct *tty)
    {
    + struct mxser_port *info = tty->driver_data;
    unsigned long page;
    unsigned long flags;

    @@ -921,8 +926,7 @@ static int mxser_startup(struct mxser_port *info)
    }

    if (!info->ioaddr || !info->type) {
    - if (info->port.tty)
    - set_bit(TTY_IO_ERROR, &info->port.tty->flags);
    + set_bit(TTY_IO_ERROR, &tty->flags);
    free_page(page);
    spin_unlock_irqrestore(&info->slock, flags);
    return 0;
    @@ -952,8 +956,8 @@ static int mxser_startup(struct mxser_port *info)
    if (inb(info->ioaddr + UART_LSR) == 0xff) {
    spin_unlock_irqrestore(&info->slock, flags);
    if (capable(CAP_SYS_ADMIN)) {
    - if (info->port.tty)
    - set_bit(TTY_IO_ERROR, &info->port.tty->flags);
    + if (tty)
    + set_bit(TTY_IO_ERROR, &tty->flags);
    return 0;
    } else
    return -ENODEV;
    @@ -991,14 +995,13 @@ static int mxser_startup(struct mxser_port *info)
    (void) inb(info->ioaddr + UART_IIR);
    (void) inb(info->ioaddr + UART_MSR);

    - if (info->port.tty)
    - clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
    + clear_bit(TTY_IO_ERROR, &tty->flags);
    info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;

    /*
    * and set the speed of the serial port
    */
    - mxser_change_speed(info, NULL);
    + mxser_change_speed(tty, NULL);
    info->port.flags |= ASYNC_INITIALIZED;
    spin_unlock_irqrestore(&info->slock, flags);

    @@ -1009,8 +1012,9 @@ static int mxser_startup(struct mxser_port *info)
    * This routine will shutdown a serial port; interrupts maybe disabled, and
    * DTR is dropped if the hangup on close termio flag is on.
    */
    -static void mxser_shutdown(struct mxser_port *info)
    +static void mxser_shutdown(struct tty_struct *tty)
    {
    + struct mxser_port *info = tty->driver_data;
    unsigned long flags;

    if (!(info->port.flags & ASYNC_INITIALIZED))
    @@ -1035,7 +1039,7 @@ static void mxser_shutdown(struct mxser_port *info)
    info->IER = 0;
    outb(0x00, info->ioaddr + UART_IER);

    - if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL))
    + if (tty->termios->c_cflag & HUPCL)
    info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS);
    outb(info->MCR, info->ioaddr + UART_MCR);

    @@ -1051,8 +1055,7 @@ static void mxser_shutdown(struct mxser_port *info)
    /* read data port to reset things */
    (void) inb(info->ioaddr + UART_RX);

    - if (info->port.tty)
    - set_bit(TTY_IO_ERROR, &info->port.tty->flags);
    + set_bit(TTY_IO_ERROR, &tty->flags);

    info->port.flags &= ~ASYNC_INITIALIZED;

    @@ -1084,14 +1087,14 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
    return -ENODEV;

    tty->driver_data = info;
    - info->port.tty = tty;
    + tty_port_tty_set(&info->port, tty);
    /*
    * Start up serial port
    */
    spin_lock_irqsave(&info->slock, flags);
    info->port.count++;
    spin_unlock_irqrestore(&info->slock, flags);
    - retval = mxser_startup(info);
    + retval = mxser_startup(tty);
    if (retval)
    return retval;

    @@ -1209,13 +1212,13 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
    break;
    }
    }
    - mxser_shutdown(info);
    + mxser_shutdown(tty);

    mxser_flush_buffer(tty);
    tty_ldisc_flush(tty);

    tty->closing = 0;
    - info->port.tty = NULL;
    + tty_port_tty_set(&info->port, NULL);
    if (info->port.blocked_open) {
    if (info->port.close_delay)
    schedule_timeout_interruptible(info->port.close_delay);
    @@ -1337,12 +1340,13 @@ static int mxser_chars_in_buffer(struct tty_struct *tty)
    * friends of mxser_ioctl()
    * ------------------------------------------------------------
    */
    -static int mxser_get_serial_info(struct mxser_port *info,
    +static int mxser_get_serial_info(struct tty_struct *tty,
    struct serial_struct __user *retinfo)
    {
    + struct mxser_port *info = tty->driver_data;
    struct serial_struct tmp = {
    .type = info->type,
    - .line = info->port.tty->index,
    + .line = tty->index,
    .port = info->ioaddr,
    .irq = info->board->irq,
    .flags = info->port.flags,
    @@ -1357,9 +1361,10 @@ static int mxser_get_serial_info(struct mxser_port *info,
    return 0;
    }

    -static int mxser_set_serial_info(struct mxser_port *info,
    +static int mxser_set_serial_info(struct tty_struct *tty,
    struct serial_struct __user *new_info)
    {
    + struct mxser_port *info = tty->driver_data;
    struct serial_struct new_serial;
    speed_t baud;
    unsigned long sl_flags;
    @@ -1393,14 +1398,14 @@ static int mxser_set_serial_info(struct mxser_port *info,
    (new_serial.flags & ASYNC_FLAGS));
    info->port.close_delay = new_serial.close_delay * HZ / 100;
    info->port.closing_wait = new_serial.closing_wait * HZ / 100;
    - info->port.tty->low_latency =
    - (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
    + tty->low_latency = (info->port.flags & ASYNC_LOW_LATENCY)
    + ? 1 : 0;
    if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
    (new_serial.baud_base != info->baud_base ||
    new_serial.custom_divisor !=
    info->custom_divisor)) {
    baud = new_serial.baud_base / new_serial.custom_divisor;
    - tty_encode_baud_rate(info->port.tty, baud, baud);
    + tty_encode_baud_rate(tty, baud, baud);
    }
    }

    @@ -1411,11 +1416,11 @@ static int mxser_set_serial_info(struct mxser_port *info,
    if (info->port.flags & ASYNC_INITIALIZED) {
    if (flags != (info->port.flags & ASYNC_SPD_MASK)) {
    spin_lock_irqsave(&info->slock, sl_flags);
    - mxser_change_speed(info, NULL);
    + mxser_change_speed(tty, NULL);
    spin_unlock_irqrestore(&info->slock, sl_flags);
    }
    } else
    - retval = mxser_startup(info);
    + retval = mxser_startup(tty);

    return retval;
    }
    @@ -1461,7 +1466,7 @@ static int mxser_tiocmget(struct tty_struct *tty, struct file *file)
    spin_lock_irqsave(&info->slock, flags);
    status = inb(info->ioaddr + UART_MSR);
    if (status & UART_MSR_ANY_DELTA)
    - mxser_check_modem_status(info, status);
    + mxser_check_modem_status(tty, info, status);
    spin_unlock_irqrestore(&info->slock, flags);
    return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) |
    ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) |
    @@ -1606,6 +1611,7 @@ static int __init mxser_read_register(int port, unsigned short *regs)
    static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
    {
    struct mxser_port *port;
    + struct tty_struct *tty;
    int result, status;
    unsigned int i, j;
    int ret = 0;
    @@ -1643,12 +1649,14 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)

    if (!port->ioaddr)
    goto copy;
    +
    + tty = tty_port_tty_get(&port->port);

    - if (!port->port.tty || !port->port.tty->termios)
    + if (!tty || !tty->termios)
    ms.cflag = port->normal_termios.c_cflag;
    else
    - ms.cflag = port->port.tty->termios->c_cflag;
    -
    + ms.cflag = tty->termios->c_cflag;
    + tty_kref_put(tty);
    status = inb(port->ioaddr + UART_MSR);
    if (status & UART_MSR_DCD)
    ms.dcd = 1;
    @@ -1704,15 +1712,18 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
    me->up_txcnt[p] = port->mon_data.up_txcnt;
    me->modem_status[p] =
    port->mon_data.modem_status;
    - me->baudrate[p] = tty_get_baud_rate(port->port.tty);
    + tty = tty_port_tty_get(&port->port);

    - if (!port->port.tty || !port->port.tty->termios) {
    + if (!tty || !tty->termios) {
    cflag = port->normal_termios.c_cflag;
    iflag = port->normal_termios.c_iflag;
    + me->baudrate[p] = tty_termios_baud_rate(&port->normal_termios);
    } else {
    - cflag = port->port.tty->termios->c_cflag;
    - iflag = port->port.tty->termios->c_iflag;
    + cflag = tty->termios->c_cflag;
    + iflag = tty->termios->c_iflag;
    + me->baudrate[p] = tty_get_baud_rate(tty);
    }
    + tty_kref_put(tty);

    me->databits[p] = cflag & CSIZE;
    me->stopbits[p] = cflag & CSTOPB;
    @@ -1822,12 +1833,12 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
    switch (cmd) {
    case TIOCGSERIAL:
    lock_kernel();
    - retval = mxser_get_serial_info(info, argp);
    + retval = mxser_get_serial_info(tty, argp);
    unlock_kernel();
    return retval;
    case TIOCSSERIAL:
    lock_kernel();
    - retval = mxser_set_serial_info(info, argp);
    + retval = mxser_set_serial_info(tty, argp);
    unlock_kernel();
    return retval;
    case TIOCSERGETLSR: /* Get line status register */
    @@ -1896,7 +1907,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,

    lock_kernel();
    status = mxser_get_msr(info->ioaddr, 1, tty->index);
    - mxser_check_modem_status(info, status);
    + mxser_check_modem_status(tty, info, status);

    mcr = inb(info->ioaddr + UART_MCR);
    if (mcr & MOXA_MUST_MCR_XON_FLAG)
    @@ -1909,7 +1920,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
    else
    info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT;

    - if (info->port.tty->hw_stopped)
    + if (tty->hw_stopped)
    info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD;
    else
    info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
    @@ -1958,7 +1969,7 @@ static void mxser_stoprx(struct tty_struct *tty)
    }
    }

    - if (info->port.tty->termios->c_cflag & CRTSCTS) {
    + if (tty->termios->c_cflag & CRTSCTS) {
    info->MCR &= ~UART_MCR_RTS;
    outb(info->MCR, info->ioaddr + UART_MCR);
    }
    @@ -1995,7 +2006,7 @@ static void mxser_unthrottle(struct tty_struct *tty)
    }
    }

    - if (info->port.tty->termios->c_cflag & CRTSCTS) {
    + if (tty->termios->c_cflag & CRTSCTS) {
    info->MCR |= UART_MCR_RTS;
    outb(info->MCR, info->ioaddr + UART_MCR);
    }
    @@ -2040,7 +2051,7 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi
    unsigned long flags;

    spin_lock_irqsave(&info->slock, flags);
    - mxser_change_speed(info, old_termios);
    + mxser_change_speed(tty, old_termios);
    spin_unlock_irqrestore(&info->slock, flags);

    if ((old_termios->c_cflag & CRTSCTS) &&
    @@ -2138,10 +2149,10 @@ static void mxser_hangup(struct tty_struct *tty)
    struct mxser_port *info = tty->driver_data;

    mxser_flush_buffer(tty);
    - mxser_shutdown(info);
    + mxser_shutdown(tty);
    info->port.count = 0;
    info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
    - info->port.tty = NULL;
    + tty_port_tty_set(&info->port, NULL);
    wake_up_interruptible(&info->port.open_wait);
    }

    @@ -2164,9 +2175,9 @@ static int mxser_rs_break(struct tty_struct *tty, int break_state)
    return 0;
    }

    -static void mxser_receive_chars(struct mxser_port *port, int *status)
    +static void mxser_receive_chars(struct tty_struct *tty,
    + struct mxser_port *port, int *status)
    {
    - struct tty_struct *tty = port->port.tty;
    unsigned char ch, gdl;
    int ignored = 0;
    int cnt = 0;
    @@ -2174,9 +2185,8 @@ static void mxser_receive_chars(struct mxser_port *port, int *status)
    int max = 256;

    recv_room = tty->receive_room;
    - if ((recv_room == 0) && (!port->ldisc_stop_rx))
    + if (recv_room == 0 && !port->ldisc_stop_rx)
    mxser_stoprx(tty);
    -
    if (port->board->chip_flag != MOXA_OTHER_UART) {

    if (*status & UART_LSR_SPECIAL)
    @@ -2253,7 +2263,7 @@ intr_old:
    } while (*status & UART_LSR_DR);

    end_intr:
    - mxvar_log.rxcnt[port->port.tty->index] += cnt;
    + mxvar_log.rxcnt[tty->index] += cnt;
    port->mon_data.rxcnt += cnt;
    port->mon_data.up_rxcnt += cnt;

    @@ -2267,14 +2277,14 @@ end_intr:
    spin_lock(&port->slock);
    }

    -static void mxser_transmit_chars(struct mxser_port *port)
    +static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port)
    {
    int count, cnt;

    if (port->x_char) {
    outb(port->x_char, port->ioaddr + UART_TX);
    port->x_char = 0;
    - mxvar_log.txcnt[port->port.tty->index]++;
    + mxvar_log.txcnt[tty->index]++;
    port->mon_data.txcnt++;
    port->mon_data.up_txcnt++;
    port->icount.tx++;
    @@ -2284,8 +2294,8 @@ static void mxser_transmit_chars(struct mxser_port *port)
    if (port->port.xmit_buf == NULL)
    return;

    - if ((port->xmit_cnt <= 0) || port->port.tty->stopped ||
    - (port->port.tty->hw_stopped &&
    + if (port->xmit_cnt <= 0 || tty->stopped ||
    + (tty->hw_stopped &&
    (port->type != PORT_16550A) &&
    (!port->board->chip_flag))) {
    port->IER &= ~UART_IER_THRI;
    @@ -2302,14 +2312,14 @@ static void mxser_transmit_chars(struct mxser_port *port)
    if (--port->xmit_cnt <= 0)
    break;
    } while (--count > 0);
    - mxvar_log.txcnt[port->port.tty->index] += (cnt - port->xmit_cnt);
    + mxvar_log.txcnt[tty->index] += (cnt - port->xmit_cnt);

    port->mon_data.txcnt += (cnt - port->xmit_cnt);
    port->mon_data.up_txcnt += (cnt - port->xmit_cnt);
    port->icount.tx += (cnt - port->xmit_cnt);

    - if (port->xmit_cnt < WAKEUP_CHARS)
    - tty_wakeup(port->port.tty);
    + if (port->xmit_cnt < WAKEUP_CHARS && tty)
    + tty_wakeup(tty);

    if (port->xmit_cnt <= 0) {
    port->IER &= ~UART_IER_THRI;
    @@ -2328,6 +2338,7 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
    int max, irqbits, bits, msr;
    unsigned int int_cnt, pass_counter = 0;
    int handled = IRQ_NONE;
    + struct tty_struct *tty;

    for (i = 0; i < MXSER_BOARDS; i++)
    if (dev_id == &mxser_boards[i]) {
    @@ -2360,13 +2371,15 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
    if (iir & UART_IIR_NO_INT)
    break;
    iir &= MOXA_MUST_IIR_MASK;
    - if (!port->port.tty ||
    + tty = tty_port_tty_get(&port->port);
    + if (!tty ||
    (port->port.flags & ASYNC_CLOSING) ||
    !(port->port.flags &
    ASYNC_INITIALIZED)) {
    status = inb(port->ioaddr + UART_LSR);
    outb(0x27, port->ioaddr + UART_FCR);
    inb(port->ioaddr + UART_MSR);
    + tty_kref_put(tty);
    break;
    }

    @@ -2387,27 +2400,28 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
    iir == MOXA_MUST_IIR_RDA ||
    iir == MOXA_MUST_IIR_RTO ||
    iir == MOXA_MUST_IIR_LSR)
    - mxser_receive_chars(port,
    + mxser_receive_chars(tty, port,
    &status);

    } else {
    status &= port->read_status_mask;
    if (status & UART_LSR_DR)
    - mxser_receive_chars(port,
    + mxser_receive_chars(tty, port,
    &status);
    }
    msr = inb(port->ioaddr + UART_MSR);
    if (msr & UART_MSR_ANY_DELTA)
    - mxser_check_modem_status(port, msr);
    + mxser_check_modem_status(tty, port, msr);

    if (port->board->chip_flag) {
    if (iir == 0x02 && (status &
    UART_LSR_THRE))
    - mxser_transmit_chars(port);
    + mxser_transmit_chars(tty, port);
    } else {
    if (status & UART_LSR_THRE)
    - mxser_transmit_chars(port);
    + mxser_transmit_chars(tty, port);
    }
    + tty_kref_put(tty);
    } while (int_cnt++ < MXSER_ISR_PASS_LIMIT);
    spin_unlock(&port->slock);
    }

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  13. [PATCH 46/80] stallion: Use krefs

    From: Alan Cox

    Use tty_port_init and krefs in the stallion drivers to protect us from devices
    going away underneath us. As with the other drives some rearranging is done to
    pass the tty structure down properly on the user side.

    Signed-off-by: Alan Cox
    ---

    drivers/char/Kconfig | 4 +-
    drivers/char/istallion.c | 107 +++++++++++++++++++++++++---------------------
    drivers/char/stallion.c | 105 ++++++++++++++++++++++++++++-----------------
    3 files changed, 123 insertions(+), 93 deletions(-)


    diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
    index caff851..700ff96 100644
    --- a/drivers/char/Kconfig
    +++ b/drivers/char/Kconfig
    @@ -350,7 +350,7 @@ config STALDRV

    config STALLION
    tristate "Stallion EasyIO or EC8/32 support"
    - depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI)
    + depends on STALDRV && (ISA || EISA || PCI)
    help
    If you have an EasyIO or EasyConnection 8/32 multiport Stallion
    card, then this is for you; say Y. Make sure to read
    @@ -361,7 +361,7 @@ config STALLION

    config ISTALLION
    tristate "Stallion EC8/64, ONboard, Brumby support"
    - depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI)
    + depends on STALDRV && (ISA || EISA || PCI)
    help
    If you have an EasyConnection 8/64, ONboard, Brumby or Stallion
    serial multiport card, say Y here. Make sure to read
    diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
    index 843a2af..96ee112 100644
    --- a/drivers/char/istallion.c
    +++ b/drivers/char/istallion.c
    @@ -623,24 +623,25 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
    static void stli_brdpoll(struct stlibrd *brdp, cdkhdr_t __iomem *hdrp);
    static void stli_poll(unsigned long arg);
    static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp);
    -static int stli_initopen(struct stlibrd *brdp, struct stliport *portp);
    +static int stli_initopen(struct tty_struct *tty, struct stlibrd *brdp, struct stliport *portp);
    static int stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait);
    static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait);
    -static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct file *filp);
    -static int stli_setport(struct stliport *portp);
    +static int stli_waitcarrier(struct tty_struct *tty, struct stlibrd *brdp,
    + struct stliport *portp, struct file *filp);
    +static int stli_setport(struct tty_struct *tty);
    static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
    static void stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
    static void __stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
    static void stli_dodelaycmd(struct stliport *portp, cdkctrl_t __iomem *cp);
    -static void stli_mkasyport(struct stliport *portp, asyport_t *pp, struct ktermios *tiosp);
    +static void stli_mkasyport(struct tty_struct *tty, struct stliport *portp, asyport_t *pp, struct ktermios *tiosp);
    static void stli_mkasysigs(asysigs_t *sp, int dtr, int rts);
    static long stli_mktiocm(unsigned long sigvalue);
    static void stli_read(struct stlibrd *brdp, struct stliport *portp);
    static int stli_getserial(struct stliport *portp, struct serial_struct __user *sp);
    -static int stli_setserial(struct stliport *portp, struct serial_struct __user *sp);
    +static int stli_setserial(struct tty_struct *tty, struct serial_struct __user *sp);
    static int stli_getbrdstats(combrd_t __user *bp);
    -static int stli_getportstats(struct stliport *portp, comstats_t __user *cp);
    -static int stli_portcmdstats(struct stliport *portp);
    +static int stli_getportstats(struct tty_struct *tty, struct stliport *portp, comstats_t __user *cp);
    +static int stli_portcmdstats(struct tty_struct *tty, struct stliport *portp);
    static int stli_clrportstats(struct stliport *portp, comstats_t __user *cp);
    static int stli_getportstruct(struct stliport __user *arg);
    static int stli_getbrdstruct(struct stlibrd __user *arg);
    @@ -731,12 +732,16 @@ static void stli_cleanup_ports(struct stlibrd *brdp)
    {
    struct stliport *portp;
    unsigned int j;
    + struct tty_struct *tty;

    for (j = 0; j < STL_MAXPORTS; j++) {
    portp = brdp->ports[j];
    if (portp != NULL) {
    - if (portp->port.tty != NULL)
    - tty_hangup(portp->port.tty);
    + tty = tty_port_tty_get(&portp->port);
    + if (tty != NULL) {
    + tty_hangup(tty);
    + tty_kref_put(tty);
    + }
    kfree(portp);
    }
    }
    @@ -824,7 +829,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
    * requires several commands to the board we will need to wait for any
    * other open that is already initializing the port.
    */
    - portp->port.tty = tty;
    + tty_port_tty_set(&portp->port, tty);
    tty->driver_data = portp;
    portp->port.count++;

    @@ -835,7 +840,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp)

    if ((portp->port.flags & ASYNC_INITIALIZED) == 0) {
    set_bit(ST_INITIALIZING, &portp->state);
    - if ((rc = stli_initopen(brdp, portp)) >= 0) {
    + if ((rc = stli_initopen(tty, brdp, portp)) >= 0) {
    portp->port.flags |= ASYNC_INITIALIZED;
    clear_bit(TTY_IO_ERROR, &tty->flags);
    }
    @@ -864,7 +869,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
    * then also we might have to wait for carrier.
    */
    if (!(filp->f_flags & O_NONBLOCK)) {
    - if ((rc = stli_waitcarrier(brdp, portp, filp)) != 0)
    + if ((rc = stli_waitcarrier(tty, brdp, portp, filp)) != 0)
    return rc;
    }
    portp->port.flags |= ASYNC_NORMAL_ACTIVE;
    @@ -930,7 +935,7 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
    stli_flushbuffer(tty);

    tty->closing = 0;
    - portp->port.tty = NULL;
    + tty_port_tty_set(&portp->port, NULL);

    if (portp->openwaitcnt) {
    if (portp->close_delay)
    @@ -952,9 +957,9 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
    * this still all happens pretty quickly.
    */

    -static int stli_initopen(struct stlibrd *brdp, struct stliport *portp)
    +static int stli_initopen(struct tty_struct *tty,
    + struct stlibrd *brdp, struct stliport *portp)
    {
    - struct tty_struct *tty;
    asynotify_t nt;
    asyport_t aport;
    int rc;
    @@ -969,10 +974,7 @@ static int stli_initopen(struct stlibrd *brdp, struct stliport *portp)
    sizeof(asynotify_t), 0)) < 0)
    return rc;

    - tty = portp->port.tty;
    - if (tty == NULL)
    - return -ENODEV;
    - stli_mkasyport(portp, &aport, tty->termios);
    + stli_mkasyport(tty, portp, &aport, tty->termios);
    if ((rc = stli_cmdwait(brdp, portp, A_SETPORT, &aport,
    sizeof(asyport_t), 0)) < 0)
    return rc;
    @@ -1161,22 +1163,21 @@ static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned l
    * waiting for the command to complete - so must have user context.
    */

    -static int stli_setport(struct stliport *portp)
    +static int stli_setport(struct tty_struct *tty)
    {
    + struct stliport *portp = tty->driver_data;
    struct stlibrd *brdp;
    asyport_t aport;

    if (portp == NULL)
    return -ENODEV;
    - if (portp->port.tty == NULL)
    - return -ENODEV;
    if (portp->brdnr >= stli_nrbrds)
    return -ENODEV;
    brdp = stli_brds[portp->brdnr];
    if (brdp == NULL)
    return -ENODEV;

    - stli_mkasyport(portp, &aport, portp->port.tty->termios);
    + stli_mkasyport(tty, portp, &aport, tty->termios);
    return(stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0));
    }

    @@ -1187,7 +1188,8 @@ static int stli_setport(struct stliport *portp)
    * maybe because if we are clocal then we don't need to wait...
    */

    -static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct file *filp)
    +static int stli_waitcarrier(struct tty_struct *tty, struct stlibrd *brdp,
    + struct stliport *portp, struct file *filp)
    {
    unsigned long flags;
    int rc, doclocal;
    @@ -1195,7 +1197,7 @@ static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct
    rc = 0;
    doclocal = 0;

    - if (portp->port.tty->termios->c_cflag & CLOCAL)
    + if (tty->termios->c_cflag & CLOCAL)
    doclocal++;

    spin_lock_irqsave(&stli_lock, flags);
    @@ -1572,10 +1574,11 @@ static int stli_getserial(struct stliport *portp, struct serial_struct __user *s
    * just quietly ignore any requests to change irq, etc.
    */

    -static int stli_setserial(struct stliport *portp, struct serial_struct __user *sp)
    +static int stli_setserial(struct tty_struct *tty, struct serial_struct __user *sp)
    {
    struct serial_struct sio;
    int rc;
    + struct stliport *portp = tty->driver_data;

    if (copy_from_user(&sio, sp, sizeof(struct serial_struct)))
    return -EFAULT;
    @@ -1594,7 +1597,7 @@ static int stli_setserial(struct stliport *portp, struct serial_struct __user *s
    portp->closing_wait = sio.closing_wait;
    portp->custom_divisor = sio.custom_divisor;

    - if ((rc = stli_setport(portp)) < 0)
    + if ((rc = stli_setport(tty)) < 0)
    return rc;
    return 0;
    }
    @@ -1685,17 +1688,17 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm
    rc = stli_getserial(portp, argp);
    break;
    case TIOCSSERIAL:
    - rc = stli_setserial(portp, argp);
    + rc = stli_setserial(tty, argp);
    break;
    case STL_GETPFLAG:
    rc = put_user(portp->pflag, (unsigned __user *)argp);
    break;
    case STL_SETPFLAG:
    if ((rc = get_user(portp->pflag, (unsigned __user *)argp)) == 0)
    - stli_setport(portp);
    + stli_setport(tty);
    break;
    case COM_GETPORTSTATS:
    - rc = stli_getportstats(portp, argp);
    + rc = stli_getportstats(tty, portp, argp);
    break;
    case COM_CLRPORTSTATS:
    rc = stli_clrportstats(portp, argp);
    @@ -1742,7 +1745,7 @@ static void stli_settermios(struct tty_struct *tty, struct ktermios *old)

    tiosp = tty->termios;

    - stli_mkasyport(portp, &aport, tiosp);
    + stli_mkasyport(tty, portp, &aport, tiosp);
    stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0);
    stli_mkasysigs(&portp->asig, ((tiosp->c_cflag & CBAUD) ? 1 : 0), -1);
    stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig,
    @@ -1854,7 +1857,7 @@ static void stli_hangup(struct tty_struct *tty)
    clear_bit(ST_TXBUSY, &portp->state);
    clear_bit(ST_RXSTOP, &portp->state);
    set_bit(TTY_IO_ERROR, &tty->flags);
    - portp->port.tty = NULL;
    + tty_port_tty_set(&portp->port, NULL);
    portp->port.flags &= ~ASYNC_NORMAL_ACTIVE;
    portp->port.count = 0;
    spin_unlock_irqrestore(&stli_lock, flags);
    @@ -1998,7 +2001,7 @@ static int stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portn
    char *sp, *uart;
    int rc, cnt;

    - rc = stli_portcmdstats(portp);
    + rc = stli_portcmdstats(NULL, portp);

    uart = "UNKNOWN";
    if (brdp->state & BST_STARTED) {
    @@ -2188,7 +2191,7 @@ static void stli_read(struct stlibrd *brdp, struct stliport *portp)

    if (test_bit(ST_RXSTOP, &portp->state))
    return;
    - tty = portp->port.tty;
    + tty = tty_port_tty_get(&portp->port);
    if (tty == NULL)
    return;

    @@ -2230,6 +2233,7 @@ static void stli_read(struct stlibrd *brdp, struct stliport *portp)
    set_bit(ST_RXING, &portp->state);

    tty_schedule_flip(tty);
    + tty_kref_put(tty);
    }

    /************************************************** ***************************/
    @@ -2362,7 +2366,7 @@ static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp)
    if (ap->notify) {
    nt = ap->changed;
    ap->notify = 0;
    - tty = portp->port.tty;
    + tty = tty_port_tty_get(&portp->port);

    if (nt.signal & SG_DCD) {
    oldsigs = portp->sigs;
    @@ -2399,6 +2403,7 @@ static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp)
    tty_schedule_flip(tty);
    }
    }
    + tty_kref_put(tty);

    if (nt.data & DT_RXBUSY) {
    donerx++;
    @@ -2535,14 +2540,15 @@ static void stli_poll(unsigned long arg)
    * the slave.
    */

    -static void stli_mkasyport(struct stliport *portp, asyport_t *pp, struct ktermios *tiosp)
    +static void stli_mkasyport(struct tty_struct *tty, struct stliport *portp,
    + asyport_t *pp, struct ktermios *tiosp)
    {
    memset(pp, 0, sizeof(asyport_t));

    /*
    * Start of by setting the baud, char size, parity and stop bit info.
    */
    - pp->baudout = tty_get_baud_rate(portp->port.tty);
    + pp->baudout = tty_get_baud_rate(tty);
    if ((tiosp->c_cflag & CBAUD) == B38400) {
    if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
    pp->baudout = 57600;
    @@ -2695,7 +2701,7 @@ static int stli_initports(struct stlibrd *brdp)
    printk("STALLION: failed to allocate port structure\n");
    continue;
    }
    -
    + tty_port_init(&portp->port);
    portp->magic = STLI_PORTMAGIC;
    portp->portnr = i;
    portp->brdnr = brdp->brdnr;
    @@ -4220,7 +4226,7 @@ static struct stliport *stli_getport(unsigned int brdnr, unsigned int panelnr,
    * what port to get stats for (used through board control device).
    */

    -static int stli_portcmdstats(struct stliport *portp)
    +static int stli_portcmdstats(struct tty_struct *tty, struct stliport *portp)
    {
    unsigned long flags;
    struct stlibrd *brdp;
    @@ -4249,15 +4255,15 @@ static int stli_portcmdstats(struct stliport *portp)
    stli_comstats.flags = portp->port.flags;

    spin_lock_irqsave(&brd_lock, flags);
    - if (portp->port.tty != NULL) {
    - if (portp->port.tty->driver_data == portp) {
    - stli_comstats.ttystate = portp->port.tty->flags;
    + if (tty != NULL) {
    + if (portp->port.tty == tty) {
    + stli_comstats.ttystate = tty->flags;
    stli_comstats.rxbuffered = -1;
    - if (portp->port.tty->termios != NULL) {
    - stli_comstats.cflags = portp->port.tty->termios->c_cflag;
    - stli_comstats.iflags = portp->port.tty->termios->c_iflag;
    - stli_comstats.oflags = portp->port.tty->termios->c_oflag;
    - stli_comstats.lflags = portp->port.tty->termios->c_lflag;
    + if (tty->termios != NULL) {
    + stli_comstats.cflags = tty->termios->c_cflag;
    + stli_comstats.iflags = tty->termios->c_iflag;
    + stli_comstats.oflags = tty->termios->c_oflag;
    + stli_comstats.lflags = tty->termios->c_lflag;
    }
    }
    }
    @@ -4294,7 +4300,8 @@ static int stli_portcmdstats(struct stliport *portp)
    * what port to get stats for (used through board control device).
    */

    -static int stli_getportstats(struct stliport *portp, comstats_t __user *cp)
    +static int stli_getportstats(struct tty_struct *tty, struct stliport *portp,
    + comstats_t __user *cp)
    {
    struct stlibrd *brdp;
    int rc;
    @@ -4312,7 +4319,7 @@ static int stli_getportstats(struct stliport *portp, comstats_t __user *cp)
    if (!brdp)
    return -ENODEV;

    - if ((rc = stli_portcmdstats(portp)) < 0)
    + if ((rc = stli_portcmdstats(tty, portp)) < 0)
    return rc;

    return copy_to_user(cp, &stli_comstats, sizeof(comstats_t)) ?
    @@ -4427,7 +4434,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un

    switch (cmd) {
    case COM_GETPORTSTATS:
    - rc = stli_getportstats(NULL, argp);
    + rc = stli_getportstats(NULL, NULL, argp);
    done++;
    break;
    case COM_CLRPORTSTATS:
    diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
    index 19db1eb..81b3234 100644
    --- a/drivers/char/stallion.c
    +++ b/drivers/char/stallion.c
    @@ -405,9 +405,9 @@ static unsigned int stl_baudrates[] = {

    static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);
    static int stl_brdinit(struct stlbrd *brdp);
    -static int stl_getportstats(struct stlport *portp, comstats_t __user *cp);
    +static int stl_getportstats(struct tty_struct *tty, struct stlport *portp, comstats_t __user *cp);
    static int stl_clrportstats(struct stlport *portp, comstats_t __user *cp);
    -static int stl_waitcarrier(struct stlport *portp, struct file *filp);
    +static int stl_waitcarrier(struct tty_struct *tty, struct stlport *portp, struct file *filp);

    /*
    * CD1400 uart specific handling functions.
    @@ -612,8 +612,9 @@ static struct class *stallion_class;
    static void stl_cd_change(struct stlport *portp)
    {
    unsigned int oldsigs = portp->sigs;
    + struct tty_struct *tty = tty_port_tty_get(&portp->port);

    - if (!portp->port.tty)
    + if (!tty)
    return;

    portp->sigs = stl_getsignals(portp);
    @@ -623,7 +624,8 @@ static void stl_cd_change(struct stlport *portp)

    if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0))
    if (portp->port.flags & ASYNC_CHECK_CD)
    - tty_hangup(portp->port.tty);
    + tty_hangup(tty);
    + tty_kref_put(tty);
    }

    /*
    @@ -734,7 +736,7 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
    * On the first open of the device setup the port hardware, and
    * initialize the per port data structure.
    */
    - portp->port.tty = tty;
    + tty_port_tty_set(&portp->port, tty);
    tty->driver_data = portp;
    portp->port.count++;

    @@ -774,7 +776,7 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
    * then also we might have to wait for carrier.
    */
    if (!(filp->f_flags & O_NONBLOCK))
    - if ((rc = stl_waitcarrier(portp, filp)) != 0)
    + if ((rc = stl_waitcarrier(tty, portp, filp)) != 0)
    return rc;

    portp->port.flags |= ASYNC_NORMAL_ACTIVE;
    @@ -789,7 +791,8 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
    * maybe because if we are clocal then we don't need to wait...
    */

    -static int stl_waitcarrier(struct stlport *portp, struct file *filp)
    +static int stl_waitcarrier(struct tty_struct *tty, struct stlport *portp,
    + struct file *filp)
    {
    unsigned long flags;
    int rc, doclocal;
    @@ -801,7 +804,7 @@ static int stl_waitcarrier(struct stlport *portp, struct file *filp)

    spin_lock_irqsave(&stallion_lock, flags);

    - if (portp->port.tty->termios->c_cflag & CLOCAL)
    + if (tty->termios->c_cflag & CLOCAL)
    doclocal++;

    portp->openwaitcnt++;
    @@ -949,7 +952,7 @@ static void stl_close(struct tty_struct *tty, struct file *filp)
    tty_ldisc_flush(tty);

    tty->closing = 0;
    - portp->port.tty = NULL;
    + tty_port_tty_set(&portp->port, NULL);

    if (portp->openwaitcnt) {
    if (portp->close_delay)
    @@ -1183,8 +1186,9 @@ static int stl_getserial(struct stlport *portp, struct serial_struct __user *sp)
    * just quietly ignore any requests to change irq, etc.
    */

    -static int stl_setserial(struct stlport *portp, struct serial_struct __user *sp)
    +static int stl_setserial(struct tty_struct *tty, struct serial_struct __user *sp)
    {
    + struct stlport * portp = tty->driver_data;
    struct serial_struct sio;

    pr_debug("stl_setserial(portp=%p,sp=%p)\n", portp, sp);
    @@ -1205,7 +1209,7 @@ static int stl_setserial(struct stlport *portp, struct serial_struct __user *sp)
    portp->close_delay = sio.close_delay;
    portp->closing_wait = sio.closing_wait;
    portp->custom_divisor = sio.custom_divisor;
    - stl_setport(portp, portp->port.tty->termios);
    + stl_setport(portp, tty->termios);
    return 0;
    }

    @@ -1282,10 +1286,10 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd
    rc = stl_getserial(portp, argp);
    break;
    case TIOCSSERIAL:
    - rc = stl_setserial(portp, argp);
    + rc = stl_setserial(tty, argp);
    break;
    case COM_GETPORTSTATS:
    - rc = stl_getportstats(portp, argp);
    + rc = stl_getportstats(tty, portp, argp);
    break;
    case COM_CLRPORTSTATS:
    rc = stl_clrportstats(portp, argp);
    @@ -1452,7 +1456,7 @@ static void stl_hangup(struct tty_struct *tty)
    portp->tx.head = NULL;
    portp->tx.tail = NULL;
    }
    - portp->port.tty = NULL;
    + tty_port_tty_set(&portp->port, NULL);
    portp->port.flags &= ~ASYNC_NORMAL_ACTIVE;
    portp->port.count = 0;
    wake_up_interruptible(&portp->port.open_wait);
    @@ -1805,7 +1809,7 @@ static int __devinit stl_initports(struct stlbrd *brdp, struct stlpanel *panelp)
    "(size=%Zd)\n", sizeof(struct stlport));
    break;
    }
    -
    + tty_port_init(&portp->port);
    portp->magic = STL_PORTMAGIC;
    portp->portnr = i;
    portp->brdnr = panelp->brdnr;
    @@ -1832,6 +1836,7 @@ static void stl_cleanup_panels(struct stlbrd *brdp)
    struct stlpanel *panelp;
    struct stlport *portp;
    unsigned int j, k;
    + struct tty_struct *tty;

    for (j = 0; j < STL_MAXPANELS; j++) {
    panelp = brdp->panels[j];
    @@ -1841,8 +1846,11 @@ static void stl_cleanup_panels(struct stlbrd *brdp)
    portp = panelp->ports[k];
    if (portp == NULL)
    continue;
    - if (portp->port.tty != NULL)
    - stl_hangup(portp->port.tty);
    + tty = tty_port_tty_get(&portp->port);
    + if (tty != NULL) {
    + stl_hangup(tty);
    + tty_kref_put(tty);
    + }
    kfree(portp->tx.buf);
    kfree(portp);
    }
    @@ -2498,7 +2506,7 @@ static struct stlport *stl_getport(int brdnr, int panelnr, int portnr)
    * what port to get stats for (used through board control device).
    */

    -static int stl_getportstats(struct stlport *portp, comstats_t __user *cp)
    +static int stl_getportstats(struct tty_struct *tty, struct stlport *portp, comstats_t __user *cp)
    {
    comstats_t stl_comstats;
    unsigned char *head, *tail;
    @@ -2525,18 +2533,17 @@ static int stl_getportstats(struct stlport *portp, comstats_t __user *cp)
    portp->stats.rxbuffered = 0;

    spin_lock_irqsave(&stallion_lock, flags);
    - if (portp->port.tty != NULL)
    - if (portp->port.tty->driver_data == portp) {
    - portp->stats.ttystate = portp->port.tty->flags;
    - /* No longer available as a statistic */
    - portp->stats.rxbuffered = 1; /*portp->port.tty->flip.count; */
    - if (portp->port.tty->termios != NULL) {
    - portp->stats.cflags = portp->port.tty->termios->c_cflag;
    - portp->stats.iflags = portp->port.tty->termios->c_iflag;
    - portp->stats.oflags = portp->port.tty->termios->c_oflag;
    - portp->stats.lflags = portp->port.tty->termios->c_lflag;
    - }
    + if (tty != NULL && portp->port.tty == tty) {
    + portp->stats.ttystate = tty->flags;
    + /* No longer available as a statistic */
    + portp->stats.rxbuffered = 1; /*tty->flip.count; */
    + if (tty->termios != NULL) {
    + portp->stats.cflags = tty->termios->c_cflag;
    + portp->stats.iflags = tty->termios->c_iflag;
    + portp->stats.oflags = tty->termios->c_oflag;
    + portp->stats.lflags = tty->termios->c_lflag;
    }
    + }
    spin_unlock_irqrestore(&stallion_lock, flags);

    head = portp->tx.head;
    @@ -2640,7 +2647,7 @@ static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, uns

    switch (cmd) {
    case COM_GETPORTSTATS:
    - rc = stl_getportstats(NULL, argp);
    + rc = stl_getportstats(NULL, NULL, argp);
    break;
    case COM_CLRPORTSTATS:
    rc = stl_clrportstats(NULL, argp);
    @@ -3243,7 +3250,7 @@ static void stl_cd1400flowctrl(struct stlport *portp, int state)

    if (portp == NULL)
    return;
    - tty = portp->port.tty;
    + tty = tty_port_tty_get(&portp->port);
    if (tty == NULL)
    return;

    @@ -3288,6 +3295,7 @@ static void stl_cd1400flowctrl(struct stlport *portp, int state)

    BRDDISABLE(portp->brdnr);
    spin_unlock_irqrestore(&brd_lock, flags);
    + tty_kref_put(tty);
    }

    /************************************************** ***************************/
    @@ -3305,7 +3313,7 @@ static void stl_cd1400sendflow(struct stlport *portp, int state)

    if (portp == NULL)
    return;
    - tty = portp->port.tty;
    + tty = tty_port_tty_get(&portp->port);
    if (tty == NULL)
    return;

    @@ -3325,6 +3333,7 @@ static void stl_cd1400sendflow(struct stlport *portp, int state)
    }
    BRDDISABLE(portp->brdnr);
    spin_unlock_irqrestore(&brd_lock, flags);
    + tty_kref_put(tty);
    }

    /************************************************** ***************************/
    @@ -3478,6 +3487,7 @@ static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr)
    int len, stlen;
    char *head, *tail;
    unsigned char ioack, srer;
    + struct tty_struct *tty;

    pr_debug("stl_cd1400txisr(panelp=%p,ioaddr=%x)\n", panelp, ioaddr);

    @@ -3504,8 +3514,11 @@ static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr)
    if ((len == 0) || ((len < STL_TXBUFLOW) &&
    (test_bit(ASYI_TXLOW, &portp->istate) == 0))) {
    set_bit(ASYI_TXLOW, &portp->istate);
    - if (portp->port.tty)
    - tty_wakeup(portp->port.tty);
    + tty = tty_port_tty_get(&portp->port);
    + if (tty) {
    + tty_wakeup(tty);
    + tty_kref_put(tty);
    + }
    }

    if (len == 0) {
    @@ -3569,7 +3582,7 @@ static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr)
    return;
    }
    portp = panelp->ports[(ioack >> 3)];
    - tty = portp->port.tty;
    + tty = tty_port_tty_get(&portp->port);

    if ((ioack & ACK_TYPMASK) == ACK_TYPRXGOOD) {
    outb((RDCR + portp->uartaddr), ioaddr);
    @@ -3633,10 +3646,12 @@ static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr)
    }
    } else {
    printk("STALLION: bad RX interrupt ack value=%x\n", ioack);
    + tty_kref_put(tty);
    return;
    }

    stl_rxalldone:
    + tty_kref_put(tty);
    outb((EOSRR + portp->uartaddr), ioaddr);
    outb(0, (ioaddr + EREG_DATA));
    }
    @@ -4175,7 +4190,7 @@ static void stl_sc26198flowctrl(struct stlport *portp, int state)

    if (portp == NULL)
    return;
    - tty = portp->port.tty;
    + tty = tty_port_tty_get(&portp->port);
    if (tty == NULL)
    return;

    @@ -4226,6 +4241,7 @@ static void stl_sc26198flowctrl(struct stlport *portp, int state)

    BRDDISABLE(portp->brdnr);
    spin_unlock_irqrestore(&brd_lock, flags);
    + tty_kref_put(tty);
    }

    /************************************************** ***************************/
    @@ -4244,7 +4260,7 @@ static void stl_sc26198sendflow(struct stlport *portp, int state)

    if (portp == NULL)
    return;
    - tty = portp->port.tty;
    + tty = tty_port_tty_get(&portp->port);
    if (tty == NULL)
    return;

    @@ -4269,6 +4285,7 @@ static void stl_sc26198sendflow(struct stlport *portp, int state)
    }
    BRDDISABLE(portp->brdnr);
    spin_unlock_irqrestore(&brd_lock, flags);
    + tty_kref_put(tty);
    }

    /************************************************** ***************************/
    @@ -4408,6 +4425,7 @@ static void stl_sc26198intr(struct stlpanel *panelp, unsigned int iobase)

    static void stl_sc26198txisr(struct stlport *portp)
    {
    + struct tty_struct *tty;
    unsigned int ioaddr;
    unsigned char mr0;
    int len, stlen;
    @@ -4422,8 +4440,11 @@ static void stl_sc26198txisr(struct stlport *portp)
    if ((len == 0) || ((len < STL_TXBUFLOW) &&
    (test_bit(ASYI_TXLOW, &portp->istate) == 0))) {
    set_bit(ASYI_TXLOW, &portp->istate);
    - if (portp->port.tty)
    - tty_wakeup(portp->port.tty);
    + tty = tty_port_tty_get(&portp->port);
    + if (tty) {
    + tty_wakeup(tty);
    + tty_kref_put(tty);
    + }
    }

    if (len == 0) {
    @@ -4476,7 +4497,7 @@ static void stl_sc26198rxisr(struct stlport *portp, unsigned int iack)

    pr_debug("stl_sc26198rxisr(portp=%p,iack=%x)\n", portp, iack);

    - tty = portp->port.tty;
    + tty = tty_port_tty_get(&portp->port);
    ioaddr = portp->ioaddr;
    outb(GIBCR, (ioaddr + XP_ADDR));
    len = inb(ioaddr + XP_DATA) + 1;
    @@ -4515,6 +4536,7 @@ static void stl_sc26198rxisr(struct stlport *portp, unsigned int iack)
    stl_sc26198txunflow(portp, tty);
    }
    }
    + tty_kref_put(tty);
    }

    /************************************************** ***************************/
    @@ -4528,7 +4550,7 @@ static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char
    struct tty_struct *tty;
    unsigned int ioaddr;

    - tty = portp->port.tty;
    + tty = tty_port_tty_get(&portp->port);
    ioaddr = portp->ioaddr;

    if (status & SR_RXPARITY)
    @@ -4566,6 +4588,7 @@ static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char
    if (status == 0)
    portp->stats.rxtotal++;
    }
    + tty_kref_put(tty);
    }

    /************************************************** ***************************/

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  14. [PATCH 60/80] tty: extract the pty init time special cases

    From: Alan Cox

    The majority of the remaining init_dev code is pty special cases. We
    refactor this code into the driver->install method.

    Signed-off-by: Alan Cox
    ---

    drivers/char/pty.c | 126 ++++++++++++++++++++++++++++---
    drivers/char/tty_io.c | 198 +++++++++++++++++--------------------------------
    include/linux/tty.h | 5 +
    3 files changed, 187 insertions(+), 142 deletions(-)


    diff --git a/drivers/char/pty.c b/drivers/char/pty.c
    index c984500..c5a192d 100644
    --- a/drivers/char/pty.c
    +++ b/drivers/char/pty.c
    @@ -227,7 +227,58 @@ static void pty_set_termios(struct tty_struct *tty, struct ktermios *old_termios
    tty->termios->c_cflag |= (CS8 | CREAD);
    }

    +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 */
    + free_tty_struct(o_tty);
    + return -ENOMEM;
    + }
    + 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 free_mem_out;
    +
    + retval = tty_init_termios(o_tty);
    + if (retval) {
    + tty_free_termios(tty);
    + goto free_mem_out;
    + }
    +
    + /*
    + * 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;
    +free_mem_out:
    + module_put(o_tty->driver->owner);
    + free_tty_struct(o_tty);
    + return -ENOMEM;
    +}
    +
    +
    static const struct tty_operations pty_ops = {
    + .install = pty_install,
    .open = pty_open,
    .close = pty_close,
    .write = pty_write,
    @@ -332,6 +383,7 @@ static inline void legacy_pty_init(void) { }
    int pty_limit = NR_UNIX98_PTY_DEFAULT;
    static int pty_limit_min = 0;
    static int pty_limit_max = NR_UNIX98_PTY_MAX;
    +static int pty_count = 0;

    static struct cdev ptmx_cdev;

    @@ -351,6 +403,7 @@ static struct ctl_table pty_table[] = {
    .procname = "nr",
    .maxlen = sizeof(int),
    .mode = 0444,
    + .data = &pty_count,
    .proc_handler = &proc_dointvec,
    }, {
    .ctl_name = 0
    @@ -426,7 +479,7 @@ static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver, int idx)
    return tty;
    }

    -static void pty_shutdown(struct tty_struct *tty)
    +static void pty_unix98_shutdown(struct tty_struct *tty)
    {
    /* We have our own method as we don't use the tty index */
    kfree(tty->termios);
    @@ -436,19 +489,71 @@ static void pty_shutdown(struct tty_struct *tty)
    /* We have no need to install and remove our tty objects as devpts does all
    the work for us */

    -static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
    +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 */
    + free_tty_struct(o_tty);
    + return -ENOMEM;
    + }
    + initialize_tty_struct(o_tty, driver->other, idx);
    +
    + tty->termios = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
    + if (tty->termios == NULL)
    + goto free_mem_out;
    + *tty->termios = driver->init_termios;
    + tty->termios_locked = kzalloc(sizeof(struct ktermios), GFP_KERNEL);
    + if (tty->termios_locked == NULL)
    + goto free_mem_out;
    + o_tty->termios = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
    + if (o_tty->termios == NULL)
    + goto free_mem_out;
    + *o_tty->termios = driver->other->init_termios;
    + o_tty->termios_locked = kzalloc(sizeof(struct ktermios), GFP_KERNEL);
    + if (o_tty->termios_locked == NULL)
    + goto free_mem_out;
    +
    + 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++;
    + pty_count++;
    return 0;
    +free_mem_out:
    + kfree(o_tty->termios);
    + module_put(o_tty->driver->owner);
    + free_tty_struct(o_tty);
    + kfree(tty->termios_locked);
    + kfree(tty->termios);
    + free_tty_struct(tty);
    + module_put(driver->owner);
    + return -ENOMEM;
    }

    -static void pty_remove(struct tty_driver *driver, struct tty_struct *tty)
    +static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
    {
    + pty_count--;
    }

    static const struct tty_operations ptm_unix98_ops = {
    .lookup = ptm_unix98_lookup,
    - .install = pty_install,
    - .remove = pty_remove,
    + .install = pty_unix98_install,
    + .remove = pty_unix98_remove,
    .open = pty_open,
    .close = pty_close,
    .write = pty_write,
    @@ -458,13 +563,13 @@ static const struct tty_operations ptm_unix98_ops = {
    .unthrottle = pty_unthrottle,
    .set_termios = pty_set_termios,
    .ioctl = pty_unix98_ioctl,
    - .shutdown = pty_shutdown
    + .shutdown = pty_unix98_shutdown
    };

    static const struct tty_operations pty_unix98_ops = {
    .lookup = pts_unix98_lookup,
    - .install = pty_install,
    - .remove = pty_remove,
    + .install = pty_unix98_install,
    + .remove = pty_unix98_remove,
    .open = pty_open,
    .close = pty_close,
    .write = pty_write,
    @@ -473,6 +578,7 @@ static const struct tty_operations pty_unix98_ops = {
    .chars_in_buffer = pty_chars_in_buffer,
    .unthrottle = pty_unthrottle,
    .set_termios = pty_set_termios,
    + .shutdown = pty_unix98_shutdown
    };

    /**
    @@ -589,10 +695,6 @@ static void __init unix98_pty_init(void)
    if (tty_register_driver(pts_driver))
    panic("Couldn't register Unix98 pts driver");

    - /* FIXME: WTF */
    -#if 0
    - pty_table[1].data = &ptm_driver->refcount;
    -#endif
    register_sysctl_table(pty_root_table);

    /* Now create the /dev/ptmx special device */
    diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
    index b0ad488..e881e9e 100644
    --- a/drivers/char/tty_io.c
    +++ b/drivers/char/tty_io.c
    @@ -136,8 +136,6 @@ LIST_HEAD(tty_drivers); /* linked list of tty drivers */
    DEFINE_MUTEX(tty_mutex);
    EXPORT_SYMBOL(tty_mutex);

    -static void initialize_tty_struct(struct tty_struct *tty);
    -
    static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *);
    static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *);
    ssize_t redirected_tty_write(struct file *, const char __user *,
    @@ -166,7 +164,7 @@ static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
    * Locking: none
    */

    -static struct tty_struct *alloc_tty_struct(void)
    +struct tty_struct *alloc_tty_struct(void)
    {
    return kzalloc(sizeof(struct tty_struct), GFP_KERNEL);
    }
    @@ -180,7 +178,7 @@ static struct tty_struct *alloc_tty_struct(void)
    * Locking: none. Must be called after tty is definitely unused
    */

    -static inline void free_tty_struct(struct tty_struct *tty)
    +void free_tty_struct(struct tty_struct *tty)
    {
    kfree(tty->write_buf);
    tty_buffer_free_all(tty);
    @@ -1227,22 +1225,70 @@ struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver, int idx)
    }

    /**
    + * tty_init_termios - helper for termios setup
    + * @tty: the tty to set up
    + *
    + * Initialise the termios structures for this tty. Thus runs under
    + * the tty_mutex currently so we can be relaxed about ordering.
    + */
    +
    +int tty_init_termios(struct tty_struct *tty)
    +{
    + struct ktermios *tp, *ltp;
    + int idx = tty->index;
    +
    + tp = tty->driver->termios[idx];
    + ltp = tty->driver->termios_locked[idx];
    + if (tp == NULL) {
    + WARN_ON(ltp != NULL);
    + tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
    + ltp = kzalloc(sizeof(struct ktermios), GFP_KERNEL);
    + if (tp == NULL || ltp == NULL) {
    + kfree(tp);
    + kfree(ltp);
    + return -ENOMEM;
    + }
    + memcpy(tp, &tty->driver->init_termios,
    + sizeof(struct ktermios));
    + tty->driver->termios[idx] = tp;
    + tty->driver->termios_locked[idx] = ltp;
    + }
    + tty->termios = tp;
    + tty->termios_locked = ltp;
    +
    + /* Compatibility until drivers always set this */
    + tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
    + tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
    + return 0;
    +}
    +
    +/**
    * tty_driver_install_tty() - install a tty entry in the driver
    * @driver: the driver for the tty
    * @tty: the tty
    *
    * Install a tty object into the driver tables. The tty->index field
    - * will be set by the time this is called.
    + * will be set by the time this is called. This method is responsible
    + * for ensuring any need additional structures are allocated and
    + * configured.
    *
    * Locking: tty_mutex for now
    */
    static int tty_driver_install_tty(struct tty_driver *driver,
    struct tty_struct *tty)
    {
    + int idx = tty->index;
    +
    if (driver->ops->install)
    return driver->ops->install(driver, tty);
    - driver->ttys[tty->index] = tty;
    - return 0;
    +
    + if (tty_init_termios(tty) == 0) {
    + tty_driver_kref_get(driver);
    + tty->count++;
    + driver->ttys[idx] = tty;
    + return 0;
    + }
    + return -ENOMEM;
    }

    /**
    @@ -1327,9 +1373,7 @@ static int tty_reopen(struct tty_struct *tty)
    struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
    int first_ok)
    {
    - struct tty_struct *tty, *o_tty;
    - struct ktermios *tp, **tp_loc, *o_tp, **o_tp_loc;
    - struct ktermios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc;
    + struct tty_struct *tty;
    int retval;

    /* check whether we're reopening an existing tty */
    @@ -1361,118 +1405,17 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
    if (!try_module_get(driver->owner))
    return ERR_PTR(-ENODEV);

    - o_tty = NULL;
    - tp = o_tp = NULL;
    - ltp = o_ltp = NULL;
    -
    tty = alloc_tty_struct();
    if (!tty)
    goto fail_no_mem;
    - initialize_tty_struct(tty);
    - tty->driver = driver;
    - tty->ops = driver->ops;
    - tty->index = idx;
    - tty_line_name(driver, idx, tty->name);
    -
    - if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
    - tp_loc = &tty->termios;
    - ltp_loc = &tty->termios_locked;
    - } else {
    - tp_loc = &driver->termios[idx];
    - ltp_loc = &driver->termios_locked[idx];
    - }
    -
    - if (!*tp_loc) {
    - tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
    - if (!tp)
    - goto free_mem_out;
    - *tp = driver->init_termios;
    - }
    -
    - if (!*ltp_loc) {
    - ltp = kzalloc(sizeof(struct ktermios), GFP_KERNEL);
    - if (!ltp)
    - goto free_mem_out;
    - }
    -
    - if (driver->type == TTY_DRIVER_TYPE_PTY) {
    - o_tty = alloc_tty_struct();
    - if (!o_tty)
    - goto free_mem_out;
    - if (!try_module_get(driver->other->owner)) {
    - /* This cannot in fact currently happen */
    - free_tty_struct(o_tty);
    - o_tty = NULL;
    - goto free_mem_out;
    - }
    - initialize_tty_struct(o_tty);
    - o_tty->driver = driver->other;
    - o_tty->ops = driver->ops;
    - o_tty->index = idx;
    - tty_line_name(driver->other, idx, o_tty->name);
    -
    - if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
    - o_tp_loc = &o_tty->termios;
    - o_ltp_loc = &o_tty->termios_locked;
    - } else {
    - o_tp_loc = &driver->other->termios[idx];
    - o_ltp_loc = &driver->other->termios_locked[idx];
    - }
    -
    - if (!*o_tp_loc) {
    - o_tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
    - if (!o_tp)
    - goto free_mem_out;
    - *o_tp = driver->other->init_termios;
    - }
    -
    - if (!*o_ltp_loc) {
    - o_ltp = kzalloc(sizeof(struct ktermios), GFP_KERNEL);
    - if (!o_ltp)
    - goto free_mem_out;
    - }
    -
    - /*
    - * Everything allocated ... set up the o_tty structure.
    - */
    - if (!(driver->other->flags & TTY_DRIVER_DEVPTS_MEM))
    - driver->other->ttys[idx] = o_tty;
    - if (!*o_tp_loc)
    - *o_tp_loc = o_tp;
    - if (!*o_ltp_loc)
    - *o_ltp_loc = o_ltp;
    - o_tty->termios = *o_tp_loc;
    - o_tty->termios_locked = *o_ltp_loc;
    - 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.
    - */
    -
    - if (!*tp_loc)
    - *tp_loc = tp;
    - if (!*ltp_loc)
    - *ltp_loc = ltp;
    - tty->termios = *tp_loc;
    - tty->termios_locked = *ltp_loc;
    - /* Compatibility until drivers always set this */
    - tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
    - tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
    - tty_driver_kref_get(driver);
    - tty->count++;
    + initialize_tty_struct(tty, driver, idx);

    retval = tty_driver_install_tty(driver, tty);
    - if (retval < 0)
    - goto release_mem_out;
    + if (retval < 0) {
    + free_tty_struct(tty);
    + module_put(driver->owner);
    + return ERR_PTR(retval);
    + }

    /*
    * Structures all installed ... call the ldisc open routines.
    @@ -1480,22 +1423,11 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
    * to decrement the use counts, as release_tty doesn't care.
    */

    - retval = tty_ldisc_setup(tty, o_tty);
    + retval = tty_ldisc_setup(tty, tty->link);
    if (retval)
    goto release_mem_out;
    return tty;

    - /* Release locally allocated memory ... nothing placed in slots */
    -free_mem_out:
    - kfree(o_tp);
    - if (o_tty) {
    - module_put(o_tty->driver->owner);
    - free_tty_struct(o_tty);
    - }
    - kfree(ltp);
    - kfree(tp);
    - free_tty_struct(tty);
    -
    fail_no_mem:
    module_put(driver->owner);
    return ERR_PTR(-ENOMEM);
    @@ -2852,7 +2784,8 @@ EXPORT_SYMBOL(do_SAK);
    * Locking: none - tty in question must not be exposed at this point
    */

    -static void initialize_tty_struct(struct tty_struct *tty)
    +void initialize_tty_struct(struct tty_struct *tty,
    + struct tty_driver *driver, int idx)
    {
    memset(tty, 0, sizeof(struct tty_struct));
    kref_init(&tty->kref);
    @@ -2873,6 +2806,11 @@ static void initialize_tty_struct(struct tty_struct *tty)
    spin_lock_init(&tty->ctrl_lock);
    INIT_LIST_HEAD(&tty->tty_files);
    INIT_WORK(&tty->SAK_work, do_SAK_work);
    +
    + tty->driver = driver;
    + tty->ops = driver->ops;
    + tty->index = idx;
    + tty_line_name(driver, idx, tty->name);
    }

    /**
    diff --git a/include/linux/tty.h b/include/linux/tty.h
    index 54523a3..3c7c757 100644
    --- a/include/linux/tty.h
    +++ b/include/linux/tty.h
    @@ -401,9 +401,14 @@ extern dev_t tty_devnum(struct tty_struct *tty);
    extern void proc_clear_tty(struct task_struct *p);
    extern struct tty_struct *get_current_tty(void);
    extern void tty_default_fops(struct file_operations *fops);
    +extern struct tty_struct *alloc_tty_struct(void);
    +extern void free_tty_struct(struct tty_struct *tty);
    +extern void initialize_tty_struct(struct tty_struct *tty,
    + struct tty_driver *driver, int idx);
    extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
    int first_ok);
    extern void tty_release_dev(struct file *filp);
    +extern int tty_init_termios(struct tty_struct *tty);

    extern struct mutex tty_mutex;


    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  15. [PATCH 55/80] tty: Move parts of tty_init_dev into new functions

    From: Sukadev Bhattiprolu

    Move the 'find-tty' and 'fast-track-open' parts of init_dev() to
    separate functions.

    Signed-off-by: Sukadev Bhattiprolu
    Signed-off-by: Alan Cox
    ---

    drivers/char/tty_io.c | 139 +++++++++++++++++++++++++++++++------------------
    1 files changed, 87 insertions(+), 52 deletions(-)


    diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
    index fdcc43c..a540849 100644
    --- a/drivers/char/tty_io.c
    +++ b/drivers/char/tty_io.c
    @@ -1204,6 +1204,80 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p)
    sprintf(p, "%s%d", driver->name, index + driver->name_base);
    }

    +/*
    + * find_tty() - find an existing tty, if any
    + * @driver: the driver for the tty
    + * @idx: the minor number
    + *
    + * Return the tty, if found or ERR_PTR() otherwise.
    + *
    + * Locking: tty_mutex must be held. If tty is found, the mutex must
    + * be held until the 'fast-open' is also done.
    + */
    +struct tty_struct *find_tty(struct tty_driver *driver, int idx)
    +{
    + struct tty_struct *tty;
    +
    + /* check whether we're reopening an existing tty */
    + if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
    + tty = devpts_get_tty(idx);
    + /*
    + * If we don't have a tty here on a slave open, it's because
    + * the master already started the close process and there's
    + * no relation between devpts file and tty anymore.
    + */
    + if (!tty && driver->subtype == PTY_TYPE_SLAVE)
    + return ERR_PTR(-EIO);
    +
    + /*
    + * tty is safe on because we are called with tty_mutex held
    + * and release_dev() won't change tty->count or tty->flags
    + * without grabbing tty_mutex.
    + */
    + if (tty && driver->subtype == PTY_TYPE_MASTER)
    + tty = tty->link;
    + } else
    + tty = driver->ttys[idx];
    + return tty;
    +}
    +
    +/*
    + * fast_tty_open() - fast re-open of an open tty
    + * @tty - the tty to open
    + *
    + * Return 0 on success, -errno on error.
    + *
    + * Locking: tty_mutex must be held from the time the tty was found
    + * till this open completes.
    + */
    +static int fast_tty_open(struct tty_struct *tty)
    +{
    + struct tty_driver *driver = tty->driver;
    +
    + if (test_bit(TTY_CLOSING, &tty->flags))
    + return -EIO;
    +
    + if (driver->type == TTY_DRIVER_TYPE_PTY &&
    + driver->subtype == PTY_TYPE_MASTER) {
    + /*
    + * special case for PTY masters: only one open permitted,
    + * and the slave side open count is incremented as well.
    + */
    + if (tty->count)
    + return -EIO;
    +
    + tty->link->count++;
    + }
    + tty->count++;
    + tty->driver = driver; /* N.B. why do this every time?? */
    +
    + /* FIXME */
    + if (!test_bit(TTY_LDISC, &tty->flags))
    + printk(KERN_ERR "fast_tty_open: no ldisc\n");
    +
    + return 0;
    +}
    +
    /**
    * tty_init_dev - initialise a tty device
    * @driver: tty driver we are opening a device on
    @@ -1238,29 +1312,21 @@ int tty_init_dev(struct tty_driver *driver, int idx,
    int retval = 0;

    /* check whether we're reopening an existing tty */
    - if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
    - tty = devpts_get_tty(idx);
    - /*
    - * If we don't have a tty here on a slave open, it's because
    - * the master already started the close process and there's
    - * no relation between devpts file and tty anymore.
    - */
    - if (!tty && driver->subtype == PTY_TYPE_SLAVE) {
    - retval = -EIO;
    - goto end_init;
    - }
    - /*
    - * It's safe from now on because tty_init_dev() is called with
    - * tty_mutex held and tty_release_dev() won't change tty->count
    - * or tty->flags without having to grab tty_mutex
    - */
    - if (tty && driver->subtype == PTY_TYPE_MASTER)
    - tty = tty->link;
    - } else {
    - tty = driver->ttys[idx];
    + tty = find_tty(driver, idx);
    + if (IS_ERR(tty)) {
    + retval = PTR_ERR(tty);
    + goto end_init;
    + }
    +
    + if (tty) {
    + retval = fast_tty_open(tty);
    + if (retval)
    + return retval;
    + *ret_tty = tty;
    + return 0;
    }
    - if (tty) goto fast_track;

    + /* Check if pty master is being opened multiple times */
    if (driver->subtype == PTY_TYPE_MASTER &&
    (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) {
    retval = -EIO;
    @@ -1400,37 +1466,6 @@ int tty_init_dev(struct tty_driver *driver, int idx,

    if (retval)
    goto release_mem_out;
    - goto success;
    -
    - /*
    - * This fast open can be used if the tty is already open.
    - * No memory is allocated, and the only failures are from
    - * attempting to open a closing tty or attempting multiple
    - * opens on a pty master.
    - */
    -fast_track:
    - if (test_bit(TTY_CLOSING, &tty->flags)) {
    - retval = -EIO;
    - goto end_init;
    - }
    - if (driver->type == TTY_DRIVER_TYPE_PTY &&
    - driver->subtype == PTY_TYPE_MASTER) {
    - /*
    - * special case for PTY masters: only one open permitted,
    - * and the slave side open count is incremented as well.
    - */
    - if (tty->count) {
    - retval = -EIO;
    - goto end_init;
    - }
    - tty->link->count++;
    - }
    - tty->count++;
    - tty->driver = driver; /* N.B. why do this every time?? */
    -
    - /* FIXME */
    - if (!test_bit(TTY_LDISC, &tty->flags))
    - printk(KERN_ERR "tty_init_dev but no ldisc\n");
    success:
    *ret_tty = tty;


    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  16. [PATCH 61/80] Move tty lookup/reopen to caller

    From: Sukadev Bhattiprolu

    Move tty_driver_lookup_tty() and tty_reopen() from tty_init_dev()
    into tty_open() (one of the two callers of tty_init_dev()). These
    calls are not really required in ptmx_open(), the other caller,
    since ptmx_open() would be setting up a new tty.

    Changelog[v2]:
    - remove the lookup and reopen calls from ptmx_open
    - merge with recent changes to ttydev tree

    Signed-off-by: Sukadev Bhattiprolu
    Signed-off-by: Alan Cox
    ---

    drivers/char/tty_io.c | 31 ++++++++++++++++---------------
    1 files changed, 16 insertions(+), 15 deletions(-)


    diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
    index e881e9e..36098ee 100644
    --- a/drivers/char/tty_io.c
    +++ b/drivers/char/tty_io.c
    @@ -1376,19 +1376,6 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
    struct tty_struct *tty;
    int retval;

    - /* check whether we're reopening an existing tty */
    - tty = tty_driver_lookup_tty(driver, idx);
    -
    - if (IS_ERR(tty))
    - return tty;
    -
    - if (tty) {
    - retval = tty_reopen(tty);
    - if (retval)
    - return ERR_PTR(retval);
    - return tty;
    - }
    -
    /* Check if pty master is being opened multiple times */
    if (driver->subtype == PTY_TYPE_MASTER &&
    (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok)
    @@ -1790,7 +1777,7 @@ void tty_release_dev(struct file *filp)

    static int __tty_open(struct inode *inode, struct file *filp)
    {
    - struct tty_struct *tty;
    + struct tty_struct *tty = NULL;
    int noctty, retval;
    struct tty_driver *driver;
    int index;
    @@ -1847,7 +1834,21 @@ retry_open:
    return -ENODEV;
    }
    got_driver:
    - tty = tty_init_dev(driver, index, 0);
    + if (!tty) {
    + /* check whether we're reopening an existing tty */
    + tty = tty_driver_lookup_tty(driver, index);
    +
    + if (IS_ERR(tty))
    + return PTR_ERR(tty);
    + }
    +
    + if (tty) {
    + retval = tty_reopen(tty);
    + if (retval)
    + tty = ERR_PTR(retval);
    + } else
    + tty = tty_init_dev(driver, index, 0);
    +
    mutex_unlock(&tty_mutex);
    tty_driver_kref_put(driver);
    if (IS_ERR(tty))

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  17. [PATCH 57/80] tty: kref the tty driver object

    From: Alan Cox

    Signed-off-by: Alan Cox
    ---

    drivers/char/ip2/ip2main.c | 6 +-
    drivers/char/pty.c | 5 ++
    drivers/char/tty_io.c | 110 ++++++++++++++++++++++++--------------------
    drivers/net/wan/Kconfig | 2 -
    include/linux/tty_driver.h | 15 ++++--
    5 files changed, 80 insertions(+), 58 deletions(-)


    diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
    index 66f52a2..6774572 100644
    --- a/drivers/char/ip2/ip2main.c
    +++ b/drivers/char/ip2/ip2main.c
    @@ -264,8 +264,8 @@ static int tracewrap;
    /**********/

    #if defined(MODULE) && defined(IP2DEBUG_OPEN)
    -#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] refc=%d, ttyc=%d, modc=%x -> %s\n", \
    - tty->name,(pCh->flags),ip2_tty_driver->refcount, \
    +#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] ttyc=%d, modc=%x -> %s\n", \
    + tty->name,(pCh->flags), \
    tty->count,/*GET_USE_COUNT(module)*/0,s)
    #else
    #define DBG_CNT(s)
    @@ -2893,7 +2893,7 @@ ip2_ipl_ioctl (struct file *pFile, UINT cmd, ULONG arg )
    case 13:
    switch ( cmd ) {
    case 64: /* Driver - ip2stat */
    - rc = put_user(ip2_tty_driver->refcount, pIndex++ );
    + rc = put_user(-1, pIndex++ );
    rc = put_user(irq_counter, pIndex++ );
    rc = put_user(bh_counter, pIndex++ );
    break;
    diff --git a/drivers/char/pty.c b/drivers/char/pty.c
    index 6e148ad..0fdfa05 100644
    --- a/drivers/char/pty.c
    +++ b/drivers/char/pty.c
    @@ -571,8 +571,11 @@ static void __init unix98_pty_init(void)
    if (tty_register_driver(pts_driver))
    panic("Couldn't register Unix98 pts driver");

    + /* FIXME: WTF */
    +#if 0
    pty_table[1].data = &ptm_driver->refcount;
    - register_sysctl_table(pty_root_table);
    +#endif
    + register_sysctl_table(pty_root_table);

    /* Now create the /dev/ptmx special device */
    tty_default_fops(&ptmx_fops);
    diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
    index ac41af8..47aa437 100644
    --- a/drivers/char/tty_io.c
    +++ b/drivers/char/tty_io.c
    @@ -276,7 +276,7 @@ static struct tty_driver *get_tty_driver(dev_t device, int *index)
    if (device < base || device >= base + p->num)
    continue;
    *index = device - base;
    - return p;
    + return tty_driver_kref_get(p);
    }
    return NULL;
    }
    @@ -320,7 +320,7 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)

    if (tty_line >= 0 && tty_line <= p->num && p->ops &&
    p->ops->poll_init && !p->ops->poll_init(p, tty_line, str)) {
    - res = p;
    + res = tty_driver_kref_get(p);
    *line = tty_line;
    break;
    }
    @@ -1410,7 +1410,7 @@ int tty_init_dev(struct tty_driver *driver, int idx,
    *o_ltp_loc = o_ltp;
    o_tty->termios = *o_tp_loc;
    o_tty->termios_locked = *o_ltp_loc;
    - driver->other->refcount++;
    + tty_driver_kref_get(driver->other);
    if (driver->subtype == PTY_TYPE_MASTER)
    o_tty->count++;

    @@ -1438,7 +1438,7 @@ int tty_init_dev(struct tty_driver *driver, int idx,
    /* Compatibility until drivers always set this */
    tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
    tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
    - driver->refcount++;
    + tty_driver_kref_get(driver);
    tty->count++;

    /*
    @@ -1530,8 +1530,7 @@ static void release_one_tty(struct kref *kref)
    else
    tty_shutdown(tty);
    tty->magic = 0;
    - /* FIXME: locking on tty->driver->refcount */
    - tty->driver->refcount--;
    + tty_driver_kref_put(driver);
    module_put(driver->owner);

    file_list_lock();
    @@ -1854,7 +1853,7 @@ retry_open:
    mutex_unlock(&tty_mutex);
    return -ENXIO;
    }
    - driver = tty->driver;
    + driver = tty_driver_kref_get(tty->driver);
    index = tty->index;
    filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
    /* noctty = 1; */
    @@ -1865,14 +1864,14 @@ retry_open:
    #ifdef CONFIG_VT
    if (device == MKDEV(TTY_MAJOR, 0)) {
    extern struct tty_driver *console_driver;
    - driver = console_driver;
    + driver = tty_driver_kref_get(console_driver);
    index = fg_console;
    noctty = 1;
    goto got_driver;
    }
    #endif
    if (device == MKDEV(TTYAUX_MAJOR, 1)) {
    - driver = console_device(&index);
    + driver = tty_driver_kref_get(console_device(&index));
    if (driver) {
    /* Don't let /dev/console block */
    filp->f_flags |= O_NONBLOCK;
    @@ -1891,6 +1890,7 @@ retry_open:
    got_driver:
    retval = tty_init_dev(driver, index, &tty, 0);
    mutex_unlock(&tty_mutex);
    + tty_driver_kref_put(driver);
    if (retval)
    return retval;

    @@ -2866,7 +2866,6 @@ int tty_put_char(struct tty_struct *tty, unsigned char ch)
    return tty->ops->put_char(tty, ch);
    return tty->ops->write(tty, &ch, 1);
    }
    -
    EXPORT_SYMBOL_GPL(tty_put_char);

    struct class *tty_class;
    @@ -2909,6 +2908,7 @@ struct device *tty_register_device(struct tty_driver *driver, unsigned index,

    return device_create_drvdata(tty_class, device, dev, NULL, name);
    }
    +EXPORT_SYMBOL(tty_register_device);

    /**
    * tty_unregister_device - unregister a tty device
    @@ -2926,8 +2926,6 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index)
    device_destroy(tty_class,
    MKDEV(driver->major, driver->minor_start) + index);
    }
    -
    -EXPORT_SYMBOL(tty_register_device);
    EXPORT_SYMBOL(tty_unregister_device);

    struct tty_driver *alloc_tty_driver(int lines)
    @@ -2936,27 +2934,70 @@ struct tty_driver *alloc_tty_driver(int lines)

    driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
    if (driver) {
    + kref_init(&driver->kref);
    driver->magic = TTY_DRIVER_MAGIC;
    driver->num = lines;
    /* later we'll move allocation of tables here */
    }
    return driver;
    }
    +EXPORT_SYMBOL(alloc_tty_driver);

    -void put_tty_driver(struct tty_driver *driver)
    +static void destruct_tty_driver(struct kref *kref)
    {
    + struct tty_driver *driver = container_of(kref, struct tty_driver, kref);
    + int i;
    + struct ktermios *tp;
    + void *p;
    +
    + if (driver->flags & TTY_DRIVER_INSTALLED) {
    + /*
    + * Free the termios and termios_locked structures because
    + * we don't want to get memory leaks when modular tty
    + * drivers are removed from the kernel.
    + */
    + for (i = 0; i < driver->num; i++) {
    + tp = driver->termios[i];
    + if (tp) {
    + driver->termios[i] = NULL;
    + kfree(tp);
    + }
    + tp = driver->termios_locked[i];
    + if (tp) {
    + driver->termios_locked[i] = NULL;
    + kfree(tp);
    + }
    + if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
    + tty_unregister_device(driver, i);
    + }
    + p = driver->ttys;
    + proc_tty_unregister_driver(driver);
    + driver->ttys = NULL;
    + driver->termios = driver->termios_locked = NULL;
    + kfree(p);
    + cdev_del(&driver->cdev);
    + }
    kfree(driver);
    }

    +void tty_driver_kref_put(struct tty_driver *driver)
    +{
    + kref_put(&driver->kref, destruct_tty_driver);
    +}
    +EXPORT_SYMBOL(tty_driver_kref_put);
    +
    void tty_set_operations(struct tty_driver *driver,
    const struct tty_operations *op)
    {
    driver->ops = op;
    };
    +EXPORT_SYMBOL(tty_set_operations);

    -EXPORT_SYMBOL(alloc_tty_driver);
    +void put_tty_driver(struct tty_driver *d)
    +{
    + tty_driver_kref_put(d);
    +}
    EXPORT_SYMBOL(put_tty_driver);
    -EXPORT_SYMBOL(tty_set_operations);

    /*
    * Called by a tty driver to register itself.
    @@ -2968,9 +3009,6 @@ int tty_register_driver(struct tty_driver *driver)
    dev_t dev;
    void **p = NULL;

    - if (driver->flags & TTY_DRIVER_INSTALLED)
    - return 0;
    -
    if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
    p = kzalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL);
    if (!p)
    @@ -3024,6 +3062,7 @@ int tty_register_driver(struct tty_driver *driver)
    tty_register_device(driver, i, NULL);
    }
    proc_tty_register_driver(driver);
    + driver->flags |= TTY_DRIVER_INSTALLED;
    return 0;
    }

    @@ -3034,46 +3073,19 @@ EXPORT_SYMBOL(tty_register_driver);
    */
    int tty_unregister_driver(struct tty_driver *driver)
    {
    - int i;
    - struct ktermios *tp;
    - void *p;
    -
    +#if 0
    + /* FIXME */
    if (driver->refcount)
    return -EBUSY;
    -
    +#endif
    unregister_chrdev_region(MKDEV(driver->major, driver->minor_start),
    driver->num);
    mutex_lock(&tty_mutex);
    list_del(&driver->tty_drivers);
    mutex_unlock(&tty_mutex);
    -
    - /*
    - * Free the termios and termios_locked structures because
    - * we don't want to get memory leaks when modular tty
    - * drivers are removed from the kernel.
    - */
    - for (i = 0; i < driver->num; i++) {
    - tp = driver->termios[i];
    - if (tp) {
    - driver->termios[i] = NULL;
    - kfree(tp);
    - }
    - tp = driver->termios_locked[i];
    - if (tp) {
    - driver->termios_locked[i] = NULL;
    - kfree(tp);
    - }
    - if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
    - tty_unregister_device(driver, i);
    - }
    - p = driver->ttys;
    - proc_tty_unregister_driver(driver);
    - driver->ttys = NULL;
    - driver->termios = driver->termios_locked = NULL;
    - kfree(p);
    - cdev_del(&driver->cdev);
    return 0;
    }
    +
    EXPORT_SYMBOL(tty_unregister_driver);

    dev_t tty_devnum(struct tty_struct *tty)
    diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
    index 2ae2ec4..21efd99 100644
    --- a/drivers/net/wan/Kconfig
    +++ b/drivers/net/wan/Kconfig
    @@ -205,7 +205,7 @@ config WANXL_BUILD_FIRMWARE

    config PC300
    tristate "Cyclades-PC300 support (RS-232/V.35, X.21, T1/E1 boards)"
    - depends on HDLC && PCI
    + depends on HDLC && PCI && BROKEN
    ---help---
    Driver for the Cyclades-PC300 synchronous communication boards.

    diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
    index 2c5c35c..ba891dd 100644
    --- a/include/linux/tty_driver.h
    +++ b/include/linux/tty_driver.h
    @@ -253,6 +253,7 @@ struct tty_operations {

    struct tty_driver {
    int magic; /* magic number for this structure */
    + struct kref kref; /* Reference management */
    struct cdev cdev;
    struct module *owner;
    const char *driver_name;
    @@ -266,7 +267,6 @@ struct tty_driver {
    short subtype; /* subtype of tty driver */
    struct ktermios init_termios; /* Initial termios */
    int flags; /* tty driver flags */
    - int refcount; /* for loadable tty drivers */
    struct proc_dir_entry *proc_entry; /* /proc fs entry */
    struct tty_driver *other; /* only used for the PTY driver */

    @@ -288,12 +288,19 @@ struct tty_driver {

    extern struct list_head tty_drivers;

    -struct tty_driver *alloc_tty_driver(int lines);
    -void put_tty_driver(struct tty_driver *driver);
    -void tty_set_operations(struct tty_driver *driver,
    +extern struct tty_driver *alloc_tty_driver(int lines);
    +extern void put_tty_driver(struct tty_driver *driver);
    +extern void tty_set_operations(struct tty_driver *driver,
    const struct tty_operations *op);
    extern struct tty_driver *tty_find_polling_driver(char *name, int *line);

    +extern void tty_driver_kref_put(struct tty_driver *driver);
    +extern inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d)
    +{
    + kref_get(&d->kref);
    + return d;
    +}
    +
    /* tty driver magic number */
    #define TTY_DRIVER_MAGIC 0x5402


    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  18. [PATCH 49/80] tty: Redo current tty locking

    From: Alan Cox

    Currently it is sometimes locked by the tty mutex and sometimes by the
    sighand lock. The latter is in fact correct and now we can hand back referenced
    objects we can fix this up without problems around sleeping functions.

    Signed-off-by: Alan Cox
    ---

    drivers/char/tty_io.c | 18 ++++--------------
    drivers/s390/char/fs3270.c | 1 +
    fs/dquot.c | 2 --
    security/selinux/hooks.c | 2 --
    4 files changed, 5 insertions(+), 18 deletions(-)


    diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
    index b5f57d0..f40298e 100644
    --- a/drivers/char/tty_io.c
    +++ b/drivers/char/tty_io.c
    @@ -739,13 +739,11 @@ void tty_vhangup_self(void)
    {
    struct tty_struct *tty;

    - mutex_lock(&tty_mutex);
    tty = get_current_tty();
    if (tty) {
    tty_vhangup(tty);
    tty_kref_put(tty);
    }
    - mutex_unlock(&tty_mutex);
    }

    /**
    @@ -801,11 +799,9 @@ void disassociate_ctty(int on_exit)
    struct pid *tty_pgrp = NULL;


    - mutex_lock(&tty_mutex);
    tty = get_current_tty();
    if (tty) {
    tty_pgrp = get_pid(tty->pgrp);
    - mutex_unlock(&tty_mutex);
    lock_kernel();
    if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY)
    tty_vhangup(tty);
    @@ -822,7 +818,6 @@ void disassociate_ctty(int on_exit)
    kill_pgrp(old_pgrp, SIGCONT, on_exit);
    put_pid(old_pgrp);
    }
    - mutex_unlock(&tty_mutex);
    return;
    }
    if (tty_pgrp) {
    @@ -837,7 +832,6 @@ void disassociate_ctty(int on_exit)
    current->signal->tty_old_pgrp = NULL;
    spin_unlock_irq(&current->sighand->siglock);

    - mutex_lock(&tty_mutex);
    tty = get_current_tty();
    if (tty) {
    unsigned long flags;
    @@ -854,7 +848,6 @@ void disassociate_ctty(int on_exit)
    " = NULL", tty);
    #endif
    }
    - mutex_unlock(&tty_mutex);

    /* Now clear signal->tty under the lock */
    read_lock(&tasklist_lock);
    @@ -3180,14 +3173,11 @@ static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
    struct tty_struct *get_current_tty(void)
    {
    struct tty_struct *tty;
    - WARN_ON_ONCE(!mutex_is_locked(&tty_mutex));
    + unsigned long flags;
    +
    + spin_lock_irqsave(&current->sighand->siglock, flags);
    tty = tty_kref_get(current->signal->tty);
    - /*
    - * session->tty can be changed/cleared from under us, make sure we
    - * issue the load. The obtained pointer, when not NULL, is valid as
    - * long as we hold tty_mutex.
    - */
    - barrier();
    + spin_unlock_irqrestore(&current->sighand->siglock, flags);
    return tty;
    }
    EXPORT_SYMBOL_GPL(get_current_tty);
    diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c
    index 3ef5425..84fbc90 100644
    --- a/drivers/s390/char/fs3270.c
    +++ b/drivers/s390/char/fs3270.c
    @@ -431,6 +431,7 @@ fs3270_open(struct inode *inode, struct file *filp)
    tty = get_current_tty();
    if (!tty || tty->driver->major != IBM_TTY3270_MAJOR) {
    tty_kref_put(tty);
    + mutex_unlock(&tty_mutex);
    rc = -ENODEV;
    goto out;
    }
    diff --git a/fs/dquot.c b/fs/dquot.c
    index 7417a6c..ad7e590 100644
    --- a/fs/dquot.c
    +++ b/fs/dquot.c
    @@ -895,9 +895,7 @@ static void print_warning(struct dquot *dquot, const int warntype)
    warntype == QUOTA_NL_BSOFTBELOW || !need_print_warning(dquot))
    return;

    - mutex_lock(&tty_mutex);
    tty = get_current_tty();
    - mutex_unlock(&tty_mutex);
    if (!tty)
    return;
    tty_write_message(tty, dquot->dq_sb->s_id);
    diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
    index 089d61a..4888139 100644
    --- a/security/selinux/hooks.c
    +++ b/security/selinux/hooks.c
    @@ -2121,9 +2121,7 @@ static inline void flush_unauthorized_files(struct files_struct *files)
    long j = -1;
    int drop_tty = 0;

    - mutex_lock(&tty_mutex);
    tty = get_current_tty();
    - mutex_unlock(&tty_mutex);
    if (tty) {
    file_list_lock();
    file = list_entry(tty->tty_files.next, typeof(*file), f_u.fu_list);

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  19. [PATCH 45/80] tty: kref usage for isicom and moxa

    From: Alan Cox

    Rather than blindly keep taking krefs we reorder the code in a few places
    to pass the tty down to the right place (which is important as from the user
    side it is not the case that tty == port->tty in all situations). For the irq
    and related paths use the krefs to stop the tty being freed under us.

    Signed-off-by: Alan Cox
    ---

    drivers/char/isicom.c | 61 +++++++++++++++++++++++++------------------------
    drivers/char/moxa.c | 61 +++++++++++++++++++++++++++++++------------------
    2 files changed, 69 insertions(+), 53 deletions(-)


    diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
    index 8f7cc19..7d30ee1 100644
    --- a/drivers/char/isicom.c
    +++ b/drivers/char/isicom.c
    @@ -421,17 +421,16 @@ static void isicom_tx(unsigned long _data)
    if (retries >= 100)
    goto unlock;

    + tty = tty_port_tty_get(&port->port);
    + if (tty == NULL)
    + goto put_unlock;
    +
    for (; count > 0; count--, port++) {
    /* port not active or tx disabled to force flow control */
    if (!(port->port.flags & ASYNC_INITIALIZED) ||
    !(port->status & ISI_TXOK))
    continue;

    - tty = port->port.tty;
    -
    - if (tty == NULL)
    - continue;
    -
    txcount = min_t(short, TX_SIZE, port->xmit_cnt);
    if (txcount <= 0 || tty->stopped || tty->hw_stopped)
    continue;
    @@ -489,6 +488,8 @@ static void isicom_tx(unsigned long _data)
    tty_wakeup(tty);
    }

    +put_unlock:
    + tty_kref_put(tty);
    unlock:
    spin_unlock_irqrestore(&isi_card[card].card_lock, flags);
    /* schedule another tx for hopefully in about 10ms */
    @@ -547,7 +548,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
    return IRQ_HANDLED;
    }

    - tty = port->port.tty;
    + tty = tty_port_tty_get(&port->port);
    if (tty == NULL) {
    word_count = byte_count >> 1;
    while (byte_count > 1) {
    @@ -588,7 +589,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
    }

    if (port->port.flags & ASYNC_CTS_FLOW) {
    - if (port->port.tty->hw_stopped) {
    + if (tty->hw_stopped) {
    if (header & ISI_CTS) {
    port->port.tty->hw_stopped = 0;
    /* start tx ing */
    @@ -597,7 +598,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
    tty_wakeup(tty);
    }
    } else if (!(header & ISI_CTS)) {
    - port->port.tty->hw_stopped = 1;
    + tty->hw_stopped = 1;
    /* stop tx ing */
    port->status &= ~(ISI_TXOK | ISI_CTS);
    }
    @@ -660,24 +661,21 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
    }
    outw(0x0000, base+0x04); /* enable interrupts */
    spin_unlock(&card->card_lock);
    + tty_kref_put(tty);

    return IRQ_HANDLED;
    }

    -static void isicom_config_port(struct isi_port *port)
    +static void isicom_config_port(struct tty_struct *tty)
    {
    + struct isi_port *port = tty->driver_data;
    struct isi_board *card = port->card;
    - struct tty_struct *tty;
    unsigned long baud;
    unsigned long base = card->base;
    u16 channel_setup, channel = port->channel,
    shift_count = card->shift_count;
    unsigned char flow_ctrl;

    - tty = port->port.tty;
    -
    - if (tty == NULL)
    - return;
    /* FIXME: Switch to new tty baud API */
    baud = C_BAUD(tty);
    if (baud & CBAUDEX) {
    @@ -690,7 +688,7 @@ static void isicom_config_port(struct isi_port *port)

    /* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */
    if (baud < 1 || baud > 4)
    - port->port.tty->termios->c_cflag &= ~CBAUDEX;
    + tty->termios->c_cflag &= ~CBAUDEX;
    else
    baud += 15;
    }
    @@ -797,8 +795,9 @@ static inline void isicom_setup_board(struct isi_board *bp)
    spin_unlock_irqrestore(&bp->card_lock, flags);
    }

    -static int isicom_setup_port(struct isi_port *port)
    +static int isicom_setup_port(struct tty_struct *tty)
    {
    + struct isi_port *port = tty->driver_data;
    struct isi_board *card = port->card;
    unsigned long flags;

    @@ -808,8 +807,7 @@ static int isicom_setup_port(struct isi_port *port)
    return -ENOMEM;

    spin_lock_irqsave(&card->card_lock, flags);
    - if (port->port.tty)
    - clear_bit(TTY_IO_ERROR, &port->port.tty->flags);
    + clear_bit(TTY_IO_ERROR, &tty->flags);
    if (port->port.count == 1)
    card->count++;

    @@ -823,7 +821,7 @@ static int isicom_setup_port(struct isi_port *port)
    InterruptTheCard(card->base);
    }

    - isicom_config_port(port);
    + isicom_config_port(tty);
    port->port.flags |= ASYNC_INITIALIZED;
    spin_unlock_irqrestore(&card->card_lock, flags);

    @@ -934,8 +932,8 @@ static int isicom_open(struct tty_struct *tty, struct file *filp)

    port->port.count++;
    tty->driver_data = port;
    - port->port.tty = tty;
    - error = isicom_setup_port(port);
    + tty_port_tty_set(&port->port, tty);
    + error = isicom_setup_port(tty);
    if (error == 0)
    error = block_til_ready(tty, filp, port);
    return error;
    @@ -955,15 +953,17 @@ static void isicom_shutdown_port(struct isi_port *port)
    struct isi_board *card = port->card;
    struct tty_struct *tty;

    - tty = port->port.tty;
    + tty = tty_port_tty_get(&port->port);

    - if (!(port->port.flags & ASYNC_INITIALIZED))
    + if (!(port->port.flags & ASYNC_INITIALIZED)) {
    + tty_kref_put(tty);
    return;
    + }

    tty_port_free_xmit_buf(&port->port);
    port->port.flags &= ~ASYNC_INITIALIZED;
    /* 3rd October 2000 : Vinayak P Risbud */
    - port->port.tty = NULL;
    + tty_port_tty_set(&port->port, NULL);

    /*Fix done by Anil .S on 30-04-2001
    remote login through isi port has dtr toggle problem
    @@ -1243,9 +1243,10 @@ static int isicom_tiocmset(struct tty_struct *tty, struct file *file,
    return 0;
    }

    -static int isicom_set_serial_info(struct isi_port *port,
    - struct serial_struct __user *info)
    +static int isicom_set_serial_info(struct tty_struct *tty,
    + struct serial_struct __user *info)
    {
    + struct isi_port *port = tty->driver_data;
    struct serial_struct newinfo;
    int reconfig_port;

    @@ -1276,7 +1277,7 @@ static int isicom_set_serial_info(struct isi_port *port,
    if (reconfig_port) {
    unsigned long flags;
    spin_lock_irqsave(&port->card->card_lock, flags);
    - isicom_config_port(port);
    + isicom_config_port(tty);
    spin_unlock_irqrestore(&port->card->card_lock, flags);
    }
    unlock_kernel();
    @@ -1318,7 +1319,7 @@ static int isicom_ioctl(struct tty_struct *tty, struct file *filp,
    return isicom_get_serial_info(port, argp);

    case TIOCSSERIAL:
    - return isicom_set_serial_info(port, argp);
    + return isicom_set_serial_info(tty, argp);

    default:
    return -ENOIOCTLCMD;
    @@ -1341,7 +1342,7 @@ static void isicom_set_termios(struct tty_struct *tty,
    return;

    spin_lock_irqsave(&port->card->card_lock, flags);
    - isicom_config_port(port);
    + isicom_config_port(tty);
    spin_unlock_irqrestore(&port->card->card_lock, flags);

    if ((old_termios->c_cflag & CRTSCTS) &&
    @@ -1419,7 +1420,7 @@ static void isicom_hangup(struct tty_struct *tty)

    port->port.count = 0;
    port->port.flags &= ~ASYNC_NORMAL_ACTIVE;
    - port->port.tty = NULL;
    + tty_port_tty_set(&port->port, NULL);
    wake_up_interruptible(&port->port.open_wait);
    }

    diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
    index d3d7864..5df4003 100644
    --- a/drivers/char/moxa.c
    +++ b/drivers/char/moxa.c
    @@ -205,7 +205,7 @@ static int moxa_tiocmset(struct tty_struct *tty, struct file *file,
    static void moxa_poll(unsigned long);
    static void moxa_set_tty_param(struct tty_struct *, struct ktermios *);
    static void moxa_setup_empty_event(struct tty_struct *);
    -static void moxa_shut_down(struct moxa_port *);
    +static void moxa_shut_down(struct tty_struct *);
    /*
    * moxa board interface functions:
    */
    @@ -217,7 +217,7 @@ static void MoxaPortLineCtrl(struct moxa_port *, int, int);
    static void MoxaPortFlowCtrl(struct moxa_port *, int, int, int, int, int);
    static int MoxaPortLineStatus(struct moxa_port *);
    static void MoxaPortFlushData(struct moxa_port *, int);
    -static int MoxaPortWriteData(struct moxa_port *, const unsigned char *, int);
    +static int MoxaPortWriteData(struct tty_struct *, const unsigned char *, int);
    static int MoxaPortReadData(struct moxa_port *);
    static int MoxaPortTxQueue(struct moxa_port *);
    static int MoxaPortRxQueue(struct moxa_port *);
    @@ -332,6 +332,7 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file,
    for (i = 0; i < MAX_BOARDS; i++) {
    p = moxa_boards[i].ports;
    for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
    + struct tty_struct *ttyp;
    memset(&tmp, 0, sizeof(tmp));
    if (!moxa_boards[i].ready)
    goto copy;
    @@ -344,10 +345,12 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file,
    if (status & 4)
    tmp.dcd = 1;

    - if (!p->port.tty || !p->port.tty->termios)
    + ttyp = tty_port_tty_get(&p->port);
    + if (!ttyp || !ttyp->termios)
    tmp.cflag = p->cflag;
    else
    - tmp.cflag = p->port.tty->termios->c_cflag;
    + tmp.cflag = ttyp->termios->c_cflag;
    + tty_kref_put(tty);
    copy:
    if (copy_to_user(argm, &tmp, sizeof(tmp))) {
    mutex_unlock(&moxa_openlock);
    @@ -880,8 +883,14 @@ static void moxa_board_deinit(struct moxa_board_conf *brd)

    /* pci hot-un-plug support */
    for (a = 0; a < brd->numPorts; a++)
    - if (brd->ports[a].port.flags & ASYNC_INITIALIZED)
    - tty_hangup(brd->ports[a].port.tty);
    + if (brd->ports[a].port.flags & ASYNC_INITIALIZED) {
    + struct tty_struct *tty = tty_port_tty_get(
    + &brd->ports[a].port);
    + if (tty) {
    + tty_hangup(tty);
    + tty_kref_put(tty);
    + }
    + }
    while (1) {
    opened = 0;
    for (a = 0; a < brd->numPorts; a++)
    @@ -1096,13 +1105,14 @@ static void __exit moxa_exit(void)
    module_init(moxa_init);
    module_exit(moxa_exit);

    -static void moxa_close_port(struct moxa_port *ch)
    +static void moxa_close_port(struct tty_struct *tty)
    {
    - moxa_shut_down(ch);
    + struct moxa_port *ch = tty->driver_data;
    + moxa_shut_down(tty);
    MoxaPortFlushData(ch, 2);
    ch->port.flags &= ~ASYNC_NORMAL_ACTIVE;
    - ch->port.tty->driver_data = NULL;
    - ch->port.tty = NULL;
    + tty->driver_data = NULL;
    + tty_port_tty_set(&ch->port, NULL);
    }

    static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
    @@ -1161,7 +1171,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
    ch = &brd->ports[port % MAX_PORTS_PER_BOARD];
    ch->port.count++;
    tty->driver_data = ch;
    - ch->port.tty = tty;
    + tty_port_tty_set(&ch->port, tty);
    if (!(ch->port.flags & ASYNC_INITIALIZED)) {
    ch->statusflags = 0;
    moxa_set_tty_param(tty, tty->termios);
    @@ -1179,7 +1189,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
    if (retval) {
    if (ch->port.count) /* 0 means already hung up... */
    if (--ch->port.count == 0)
    - moxa_close_port(ch);
    + moxa_close_port(tty);
    } else
    ch->port.flags |= ASYNC_NORMAL_ACTIVE;
    mutex_unlock(&moxa_openlock);
    @@ -1219,7 +1229,7 @@ static void moxa_close(struct tty_struct *tty, struct file *filp)
    tty_wait_until_sent(tty, 30 * HZ); /* 30 seconds timeout */
    }

    - moxa_close_port(ch);
    + moxa_close_port(tty);
    unlock:
    mutex_unlock(&moxa_openlock);
    }
    @@ -1234,7 +1244,7 @@ static int moxa_write(struct tty_struct *tty,
    return 0;

    spin_lock_bh(&moxa_lock);
    - len = MoxaPortWriteData(ch, buf, count);
    + len = MoxaPortWriteData(tty, buf, count);
    spin_unlock_bh(&moxa_lock);

    ch->statusflags |= LOWWAIT;
    @@ -1409,7 +1419,7 @@ static void moxa_hangup(struct tty_struct *tty)
    return;
    }
    ch->port.count = 0;
    - moxa_close_port(ch);
    + moxa_close_port(tty);
    mutex_unlock(&moxa_openlock);

    wake_up_interruptible(&ch->port.open_wait);
    @@ -1417,11 +1427,14 @@ static void moxa_hangup(struct tty_struct *tty)

    static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
    {
    + struct tty_struct *tty;
    dcd = !!dcd;

    - if (dcd != p->DCDState && p->port.tty && C_CLOCAL(p->port.tty)) {
    - if (!dcd)
    - tty_hangup(p->port.tty);
    + if (dcd != p->DCDState) {
    + tty = tty_port_tty_get(&p->port);
    + if (tty && C_CLOCAL(tty) && !dcd)
    + tty_hangup(tty);
    + tty_kref_put(tty);
    }
    p->DCDState = dcd;
    }
    @@ -1429,7 +1442,7 @@ static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
    static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
    u16 __iomem *ip)
    {
    - struct tty_struct *tty = p->port.tty;
    + struct tty_struct *tty = tty_port_tty_get(&p->port);
    void __iomem *ofsAddr;
    unsigned int inited = p->port.flags & ASYNC_INITIALIZED;
    u16 intr;
    @@ -1476,6 +1489,7 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
    tty_insert_flip_char(tty, 0, TTY_BREAK);
    tty_schedule_flip(tty);
    }
    + tty_kref_put(tty);

    if (intr & IntrLine)
    moxa_new_dcdstate(p, readb(ofsAddr + FlagStat) & DCD_state);
    @@ -1560,9 +1574,9 @@ static void moxa_setup_empty_event(struct tty_struct *tty)
    spin_unlock_bh(&moxa_lock);
    }

    -static void moxa_shut_down(struct moxa_port *ch)
    +static void moxa_shut_down(struct tty_struct *tty)
    {
    - struct tty_struct *tp = ch->port.tty;
    + struct moxa_port *ch = tty->driver_data;

    if (!(ch->port.flags & ASYNC_INITIALIZED))
    return;
    @@ -1572,7 +1586,7 @@ static void moxa_shut_down(struct moxa_port *ch)
    /*
    * If we're a modem control device and HUPCL is on, drop RTS & DTR.
    */
    - if (C_HUPCL(tp))
    + if (C_HUPCL(tty))
    MoxaPortLineCtrl(ch, 0, 0);

    spin_lock_bh(&moxa_lock);
    @@ -1953,9 +1967,10 @@ static int MoxaPortLineStatus(struct moxa_port *port)
    return val;
    }

    -static int MoxaPortWriteData(struct moxa_port *port,
    +static int MoxaPortWriteData(struct tty_struct *tty,
    const unsigned char *buffer, int len)
    {
    + struct moxa_port *port = tty->driver_data;
    void __iomem *baseAddr, *ofsAddr, *ofs;
    unsigned int c, total;
    u16 head, tail, tx_mask, spage, epage;

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  20. [PATCH 50/80] tty: Fix abusers of current->sighand->tty

    From: Alan Cox

    Various people outside the tty layer still stick their noses in behind the
    scenes. We need to make sure they also obey the locking and referencing rules.

    Signed-off-by: Alan Cox
    ---

    kernel/acct.c | 2 +-
    kernel/auditsc.c | 9 ++++-----
    2 files changed, 5 insertions(+), 6 deletions(-)


    diff --git a/kernel/acct.c b/kernel/acct.c
    index dd68b90..f6006a6 100644
    --- a/kernel/acct.c
    +++ b/kernel/acct.c
    @@ -548,7 +548,7 @@ static void do_acct_process(struct bsd_acct_struct *acct,
    #endif

    spin_lock_irq(&current->sighand->siglock);
    - tty = current->signal->tty;
    + tty = current->signal->tty; /* Safe as we hold the siglock */
    ac.ac_tty = tty ? old_encode_dev(tty_devnum(tty)) : 0;
    ac.ac_utime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pa cct->ac_utime)));
    ac.ac_stime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pa cct->ac_stime)));
    diff --git a/kernel/auditsc.c b/kernel/auditsc.c
    index 59cedfb..cf5bc2f 100644
    --- a/kernel/auditsc.c
    +++ b/kernel/auditsc.c
    @@ -246,8 +246,8 @@ static int audit_match_perm(struct audit_context *ctx, int mask)
    unsigned n;
    if (unlikely(!ctx))
    return 0;
    -
    n = ctx->major;
    +
    switch (audit_classify_syscall(ctx->arch, n)) {
    case 0: /* native */
    if ((mask & AUDIT_PERM_WRITE) &&
    @@ -1204,13 +1204,13 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
    (context->return_valid==AUDITSC_SUCCESS)?"yes":"no",
    context->return_code);

    - mutex_lock(&tty_mutex);
    - read_lock(&tasklist_lock);
    + spin_lock_irq(&tsk->sighand->siglock);
    if (tsk->signal && tsk->signal->tty && tsk->signal->tty->name)
    tty = tsk->signal->tty->name;
    else
    tty = "(none)";
    - read_unlock(&tasklist_lock);
    + spin_unlock_irq(&tsk->sighand->siglock);
    +
    audit_log_format(ab,
    " a0=%lx a1=%lx a2=%lx a3=%lx items=%d"
    " ppid=%d pid=%d auid=%u uid=%u gid=%u"
    @@ -1230,7 +1230,6 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
    context->egid, context->sgid, context->fsgid, tty,
    tsk->sessionid);

    - mutex_unlock(&tty_mutex);

    audit_log_task_info(ab, tsk);
    if (context->filterkey) {

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

+ Reply to Thread
Page 2 of 4 FirstFirst 1 2 3 4 LastLast