[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 Original suggestion and proposal from Sukadev Bhattiprolu. Signed-off-by: Alan Cox --- drivers/char/pty.c | 6 ++++-- drivers/char/tty_io.c | 52 ++++++++++++++++++++----------------------------- include/linux/tty.h | 4 ++-- 3 files changed, 27 insertions(+), 35 deletions(-) diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 4e6490b..c984500 100644 ...

+ Reply to Thread
Page 3 of 4 FirstFirst 1 2 3 4 LastLast
Results 41 to 60 of 70

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

  1. [PATCH 59/80] tty: Finish fixing up the init_dev interface to use ERR_PTR

    From: Alan Cox

    Original suggestion and proposal from Sukadev Bhattiprolu.

    Signed-off-by: Alan Cox
    ---

    drivers/char/pty.c | 6 ++++--
    drivers/char/tty_io.c | 52 ++++++++++++++++++++-----------------------------
    include/linux/tty.h | 4 ++--
    3 files changed, 27 insertions(+), 35 deletions(-)


    diff --git a/drivers/char/pty.c b/drivers/char/pty.c
    index 4e6490b..c984500 100644
    --- a/drivers/char/pty.c
    +++ b/drivers/char/pty.c
    @@ -501,11 +501,13 @@ static int __ptmx_open(struct inode *inode, struct file *filp)
    return index;

    mutex_lock(&tty_mutex);
    - retval = tty_init_dev(ptm_driver, index, &tty, 1);
    + tty = tty_init_dev(ptm_driver, index, 1);
    mutex_unlock(&tty_mutex);

    - if (retval)
    + if (IS_ERR(tty)) {
    + retval = PTR_ERR(tty);
    goto out;
    + }

    set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
    filp->private_data = tty;
    diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
    index 888380f..b0ad488 100644
    --- a/drivers/char/tty_io.c
    +++ b/drivers/char/tty_io.c
    @@ -1324,35 +1324,32 @@ static int tty_reopen(struct tty_struct *tty)
    * relaxed for the (most common) case of reopening a tty.
    */

    -int tty_init_dev(struct tty_driver *driver, int idx,
    - struct tty_struct **ret_tty, int first_ok)
    +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;
    - int retval = 0;
    + int retval;

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

    if (tty) {
    retval = tty_reopen(tty);
    if (retval)
    - return retval;
    - *ret_tty = tty;
    - return 0;
    + 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) {
    - retval = -EIO;
    - goto end_init;
    - }
    + (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok)
    + return ERR_PTR(-EIO);
    +
    /*
    * First time open is complex, especially for PTY devices.
    * This code guarantees that either everything succeeds and the
    @@ -1361,10 +1358,8 @@ int tty_init_dev(struct tty_driver *driver, int idx,
    * and locked termios may be retained.)
    */

    - if (!try_module_get(driver->owner)) {
    - retval = -ENODEV;
    - goto end_init;
    - }
    + if (!try_module_get(driver->owner))
    + return ERR_PTR(-ENODEV);

    o_tty = NULL;
    tp = o_tp = NULL;
    @@ -1475,7 +1470,8 @@ int tty_init_dev(struct tty_driver *driver, int idx,
    tty_driver_kref_get(driver);
    tty->count++;

    - if (tty_driver_install_tty(driver, tty) < 0)
    + retval = tty_driver_install_tty(driver, tty);
    + if (retval < 0)
    goto release_mem_out;

    /*
    @@ -1485,14 +1481,9 @@ int tty_init_dev(struct tty_driver *driver, int idx,
    */

    retval = tty_ldisc_setup(tty, o_tty);
    -
    if (retval)
    goto release_mem_out;
    -
    - *ret_tty = tty;
    - /* All paths come through here to release the mutex */
    -end_init:
    - return retval;
    + return tty;

    /* Release locally allocated memory ... nothing placed in slots */
    free_mem_out:
    @@ -1507,8 +1498,7 @@ free_mem_out:

    fail_no_mem:
    module_put(driver->owner);
    - retval = -ENOMEM;
    - goto end_init;
    + return ERR_PTR(-ENOMEM);

    /* call the tty release_tty routine to clean out this slot */
    release_mem_out:
    @@ -1516,7 +1506,7 @@ release_mem_out:
    printk(KERN_INFO "tty_init_dev: ldisc open failed, "
    "clearing slot %d\n", idx);
    release_tty(tty, idx);
    - goto end_init;
    + return ERR_PTR(retval);
    }

    void tty_free_termios(struct tty_struct *tty)
    @@ -1925,11 +1915,11 @@ retry_open:
    return -ENODEV;
    }
    got_driver:
    - retval = tty_init_dev(driver, index, &tty, 0);
    + tty = tty_init_dev(driver, index, 0);
    mutex_unlock(&tty_mutex);
    tty_driver_kref_put(driver);
    - if (retval)
    - return retval;
    + if (IS_ERR(tty))
    + return PTR_ERR(tty);

    filp->private_data = tty;
    file_move(filp, &tty->tty_files);
    diff --git a/include/linux/tty.h b/include/linux/tty.h
    index 6cc7ccc..54523a3 100644
    --- a/include/linux/tty.h
    +++ b/include/linux/tty.h
    @@ -401,8 +401,8 @@ 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 int tty_init_dev(struct tty_driver *driver, int idx,
    - struct tty_struct **ret_tty, int first_ok);
    +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 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/

  2. [PATCH 62/80] Add an instance parameter devpts interfaces

    From: Sukadev Bhattiprolu

    Pass-in 'inode' or 'tty' parameter to devpts interfaces. With multiple
    devpts instances, these parameters will be used in subsequent patches
    to identify the instance of devpts mounted. The parameters also help
    simplify devpts implementation.

    Changelog[v3]:
    - minor changes due to merge with ttydev updates
    - rename parameters to emphasize they are ptmx or pts inodes
    - pass-in tty_struct * to devpts_pty_kill() (this will help
    cleanup the get_node() call in a subsequent patch)

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

    drivers/char/pty.c | 18 ++++++++++--------
    drivers/char/tty_io.c | 14 ++++++++------
    fs/devpts/inode.c | 11 ++++++-----
    include/linux/devpts_fs.h | 31 +++++++++++++++++++++----------
    include/linux/tty_driver.h | 3 ++-
    5 files changed, 47 insertions(+), 30 deletions(-)


    diff --git a/drivers/char/pty.c b/drivers/char/pty.c
    index c5a192d..a391bad 100644
    --- a/drivers/char/pty.c
    +++ b/drivers/char/pty.c
    @@ -60,7 +60,7 @@ static void pty_close(struct tty_struct * tty, struct file * filp)
    set_bit(TTY_OTHER_CLOSED, &tty->flags);
    #ifdef CONFIG_UNIX98_PTYS
    if (tty->driver == ptm_driver)
    - devpts_pty_kill(tty->index);
    + devpts_pty_kill(tty->link);
    #endif
    tty_vhangup(tty->link);
    }
    @@ -453,9 +453,10 @@ static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file,
    * This provides our locking.
    */

    -static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver, int idx)
    +static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
    + struct inode *ptm_inode, int idx)
    {
    - struct tty_struct *tty = devpts_get_tty(idx);
    + struct tty_struct *tty = devpts_get_tty(ptm_inode, idx);
    if (tty)
    tty = tty->link;
    return tty;
    @@ -470,9 +471,10 @@ static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver, int idx)
    * This provides our locking.
    */

    -static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver, int idx)
    +static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
    + struct inode *pts_inode, int idx)
    {
    - struct tty_struct *tty = devpts_get_tty(idx);
    + struct tty_struct *tty = devpts_get_tty(pts_inode, idx);
    /* Master must be open before slave */
    if (!tty)
    return ERR_PTR(-EIO);
    @@ -602,7 +604,7 @@ static int __ptmx_open(struct inode *inode, struct file *filp)
    nonseekable_open(inode, filp);

    /* find a device that is not in use. */
    - index = devpts_new_index();
    + index = devpts_new_index(inode);
    if (index < 0)
    return index;

    @@ -619,7 +621,7 @@ static int __ptmx_open(struct inode *inode, struct file *filp)
    filp->private_data = tty;
    file_move(filp, &tty->tty_files);

    - retval = devpts_pty_new(tty->link);
    + retval = devpts_pty_new(inode, tty->link);
    if (retval)
    goto out1;

    @@ -630,7 +632,7 @@ out1:
    tty_release_dev(filp);
    return retval;
    out:
    - devpts_kill_index(index);
    + devpts_kill_index(inode, index);
    return retval;
    }

    diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
    index 36098ee..9590839 100644
    --- a/drivers/char/tty_io.c
    +++ b/drivers/char/tty_io.c
    @@ -1213,12 +1213,13 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p)
    * 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 *tty_driver_lookup_tty(struct tty_driver *driver, int idx)
    +struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
    + struct inode *inode, int idx)
    {
    struct tty_struct *tty;

    if (driver->ops->lookup)
    - return driver->ops->lookup(driver, idx);
    + return driver->ops->lookup(driver, inode, idx);

    tty = driver->ttys[idx];
    return tty;
    @@ -1539,10 +1540,11 @@ void tty_release_dev(struct file *filp)
    int devpts;
    int idx;
    char buf[64];
    + struct inode *inode;

    + inode = filp->f_path.dentry->d_inode;
    tty = (struct tty_struct *)filp->private_data;
    - if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode,
    - "tty_release_dev"))
    + if (tty_paranoia_check(tty, inode, "tty_release_dev"))
    return;

    check_tty_count(tty, "tty_release_dev");
    @@ -1751,7 +1753,7 @@ void tty_release_dev(struct file *filp)

    /* Make this pty number available for reallocation */
    if (devpts)
    - devpts_kill_index(idx);
    + devpts_kill_index(inode, idx);
    }

    /**
    @@ -1836,7 +1838,7 @@ retry_open:
    got_driver:
    if (!tty) {
    /* check whether we're reopening an existing tty */
    - tty = tty_driver_lookup_tty(driver, index);
    + tty = tty_driver_lookup_tty(driver, inode, index);

    if (IS_ERR(tty))
    return PTR_ERR(tty);
    diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
    index 488eb42..638db9b 100644
    --- a/fs/devpts/inode.c
    +++ b/fs/devpts/inode.c
    @@ -177,7 +177,7 @@ static struct dentry *get_node(int num)
    return lookup_one_len(s, root, sprintf(s, "%d", num));
    }

    -int devpts_new_index(void)
    +int devpts_new_index(struct inode *ptmx_inode)
    {
    int index;
    int ida_ret;
    @@ -205,14 +205,14 @@ retry:
    return index;
    }

    -void devpts_kill_index(int idx)
    +void devpts_kill_index(struct inode *ptmx_inode, int idx)
    {
    mutex_lock(&allocated_ptys_lock);
    ida_remove(&allocated_ptys, idx);
    mutex_unlock(&allocated_ptys_lock);
    }

    -int devpts_pty_new(struct tty_struct *tty)
    +int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty)
    {
    int number = tty->index; /* tty layer puts index from devpts_new_index() in here */
    struct tty_driver *driver = tty->driver;
    @@ -245,7 +245,7 @@ int devpts_pty_new(struct tty_struct *tty)
    return 0;
    }

    -struct tty_struct *devpts_get_tty(int number)
    +struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number)
    {
    struct dentry *dentry = get_node(number);
    struct tty_struct *tty;
    @@ -262,8 +262,9 @@ struct tty_struct *devpts_get_tty(int number)
    return tty;
    }

    -void devpts_pty_kill(int number)
    +void devpts_pty_kill(struct tty_struct *tty)
    {
    + int number = tty->index;
    struct dentry *dentry = get_node(number);

    if (!IS_ERR(dentry)) {
    diff --git a/include/linux/devpts_fs.h b/include/linux/devpts_fs.h
    index 154769c..5ce0e5f 100644
    --- a/include/linux/devpts_fs.h
    +++ b/include/linux/devpts_fs.h
    @@ -17,20 +17,31 @@

    #ifdef CONFIG_UNIX98_PTYS

    -int devpts_new_index(void);
    -void devpts_kill_index(int idx);
    -int devpts_pty_new(struct tty_struct *tty); /* mknod in devpts */
    -struct tty_struct *devpts_get_tty(int number); /* get tty structure */
    -void devpts_pty_kill(int number); /* unlink */
    +int devpts_new_index(struct inode *ptmx_inode);
    +void devpts_kill_index(struct inode *ptmx_inode, int idx);
    +/* mknod in devpts */
    +int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty);
    +/* get tty structure */
    +struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number);
    +/* unlink */
    +void devpts_pty_kill(struct tty_struct *tty);

    #else

    /* Dummy stubs in the no-pty case */
    -static inline int devpts_new_index(void) { return -EINVAL; }
    -static inline void devpts_kill_index(int idx) { }
    -static inline int devpts_pty_new(struct tty_struct *tty) { return -EINVAL; }
    -static inline struct tty_struct *devpts_get_tty(int number) { return NULL; }
    -static inline void devpts_pty_kill(int number) { }
    +static inline int devpts_new_index(struct inode *ptmx_inode) { return -EINVAL; }
    +static inline void devpts_kill_index(struct inode *ptmx_inode, int idx) { }
    +static inline int devpts_pty_new(struct inode *ptmx_inode,
    + struct tty_struct *tty)
    +{
    + return -EINVAL;
    +}
    +static inline struct tty_struct *devpts_get_tty(struct inode *pts_inode,
    + int number)
    +{
    + return NULL;
    +}
    +static inline void devpts_pty_kill(struct tty_struct *tty) { }

    #endif

    diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
    index 005d06a..78416b9 100644
    --- a/include/linux/tty_driver.h
    +++ b/include/linux/tty_driver.h
    @@ -225,7 +225,8 @@ struct tty_struct;
    struct tty_driver;

    struct tty_operations {
    - struct tty_struct * (*lookup)(struct tty_driver *driver, int idx);
    + struct tty_struct * (*lookup)(struct tty_driver *driver,
    + struct inode *inode, int idx);
    int (*install)(struct tty_driver *driver, struct tty_struct *tty);
    void (*remove)(struct tty_driver *driver, struct tty_struct *tty);
    int (*open)(struct tty_struct * tty, struct file * filp);

    --
    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 48/80] tty: the vhangup syscall is racy

    From: Alan Cox

    We now have the infrastructure to sort this out but rather than teaching
    the syscall tty lock rules we move the hard work into a tty helper

    Signed-off-by: Alan Cox
    ---

    drivers/char/tty_io.c | 19 +++++++++++++++++++
    fs/open.c | 3 +--
    include/linux/tty.h | 1 +
    3 files changed, 21 insertions(+), 2 deletions(-)


    diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
    index 913b502..b5f57d0 100644
    --- a/drivers/char/tty_io.c
    +++ b/drivers/char/tty_io.c
    @@ -730,6 +730,25 @@ void tty_vhangup(struct tty_struct *tty)
    EXPORT_SYMBOL(tty_vhangup);

    /**
    + * tty_vhangup_self - process vhangup for own ctty
    + *
    + * Perform a vhangup on the current controlling tty
    + */
    +
    +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);
    +}
    +
    +/**
    * tty_hung_up_p - was tty hung up
    * @filp: file pointer of tty
    *
    diff --git a/fs/open.c b/fs/open.c
    index 07da935..5596049 100644
    --- a/fs/open.c
    +++ b/fs/open.c
    @@ -1141,8 +1141,7 @@ EXPORT_SYMBOL(sys_close);
    asmlinkage long sys_vhangup(void)
    {
    if (capable(CAP_SYS_TTY_CONFIG)) {
    - /* XXX: this needs locking */
    - tty_vhangup(current->signal->tty);
    + tty_vhangup_self();
    return 0;
    }
    return -EPERM;
    diff --git a/include/linux/tty.h b/include/linux/tty.h
    index c30ed8d..e00393a 100644
    --- a/include/linux/tty.h
    +++ b/include/linux/tty.h
    @@ -361,6 +361,7 @@ extern int is_ignored(int sig);
    extern int tty_signal(int sig, struct tty_struct *tty);
    extern void tty_hangup(struct tty_struct *tty);
    extern void tty_vhangup(struct tty_struct *tty);
    +extern void tty_vhangup_self(void);
    extern void tty_unhangup(struct file *filp);
    extern int tty_hung_up_p(struct file *filp);
    extern void do_SAK(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/

  4. [PATCH 63/80] Simplify devpts_get_tty()

    From: Sukadev Bhattiprolu

    As pointed out by H. Peter Anvin, since the inode for the pty is known,
    we don't need to look it up.

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

    fs/devpts/inode.c | 17 +++++------------
    1 files changed, 5 insertions(+), 12 deletions(-)


    diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
    index 638db9b..b292ed7 100644
    --- a/fs/devpts/inode.c
    +++ b/fs/devpts/inode.c
    @@ -27,6 +27,7 @@
    #define DEVPTS_SUPER_MAGIC 0x1cd1

    #define DEVPTS_DEFAULT_MODE 0600
    +#define PTMX_MINOR 2

    extern int pty_limit; /* Config limit on Unix98 ptys */
    static DEFINE_IDA(allocated_ptys);
    @@ -247,19 +248,11 @@ int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty)

    struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number)
    {
    - struct dentry *dentry = get_node(number);
    - struct tty_struct *tty;
    -
    - tty = NULL;
    - if (!IS_ERR(dentry)) {
    - if (dentry->d_inode)
    - tty = dentry->d_inode->i_private;
    - dput(dentry);
    - }
    -
    - mutex_unlock(&devpts_root->d_inode->i_mutex);
    + BUG_ON(pts_inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR));

    - return tty;
    + if (pts_inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC)
    + return (struct tty_struct *)pts_inode->i_private;
    + return NULL;
    }

    void devpts_pty_kill(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/

  5. [PATCH 58/80] tty: More driver operations

    From: Alan Cox

    We have the lookup operation abstracted which is nice for pty cleanup but
    we really want to abstract the add/remove entries as well so that we can
    pull the pty code out of the tty core and create a clear defined interface
    for the tty driver table.

    Signed-off-by: Alan Cox
    ---

    drivers/char/pty.c | 16 ++++++++++++
    drivers/char/tty_io.c | 57 ++++++++++++++++++++++++++++++++++++--------
    include/linux/tty_driver.h | 16 ++++++++++++
    3 files changed, 79 insertions(+), 10 deletions(-)


    diff --git a/drivers/char/pty.c b/drivers/char/pty.c
    index 0fdfa05..4e6490b 100644
    --- a/drivers/char/pty.c
    +++ b/drivers/char/pty.c
    @@ -433,8 +433,22 @@ static void pty_shutdown(struct tty_struct *tty)
    kfree(tty->termios_locked);
    }

    +/* 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)
    +{
    + return 0;
    +}
    +
    +static void pty_remove(struct tty_driver *driver, struct tty_struct *tty)
    +{
    +}
    +
    static const struct tty_operations ptm_unix98_ops = {
    .lookup = ptm_unix98_lookup,
    + .install = pty_install,
    + .remove = pty_remove,
    .open = pty_open,
    .close = pty_close,
    .write = pty_write,
    @@ -449,6 +463,8 @@ static const struct tty_operations ptm_unix98_ops = {

    static const struct tty_operations pty_unix98_ops = {
    .lookup = pts_unix98_lookup,
    + .install = pty_install,
    + .remove = pty_remove,
    .open = pty_open,
    .close = pty_close,
    .write = pty_write,
    diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
    index 47aa437..888380f 100644
    --- a/drivers/char/tty_io.c
    +++ b/drivers/char/tty_io.c
    @@ -1189,7 +1189,7 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p)
    }

    /**
    - * pty_line_name - generate name for a tty
    + * tty_line_name - generate name for a tty
    * @driver: the tty driver in use
    * @index: the minor number
    * @p: output buffer of at least 7 bytes
    @@ -1222,13 +1222,51 @@ struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver, int idx)
    if (driver->ops->lookup)
    return driver->ops->lookup(driver, idx);

    - tty = driver->ttys[idx];
    + tty = driver->ttys[idx];
    return tty;
    }

    /**
    - * tty_reopen() - fast re-open of an open tty
    - * @tty - the tty to open
    + * 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.
    + *
    + * Locking: tty_mutex for now
    + */
    +static int tty_driver_install_tty(struct tty_driver *driver,
    + struct tty_struct *tty)
    +{
    + if (driver->ops->install)
    + return driver->ops->install(driver, tty);
    + driver->ttys[tty->index] = tty;
    + return 0;
    +}
    +
    +/**
    + * tty_driver_remove_tty() - remove a tty from the driver tables
    + * @driver: the driver for the tty
    + * @idx: the minor number
    + *
    + * Remvoe a tty object from the driver tables. The tty->index field
    + * will be set by the time this is called.
    + *
    + * Locking: tty_mutex for now
    + */
    +static void tty_driver_remove_tty(struct tty_driver *driver,
    + struct tty_struct *tty)
    +{
    + if (driver->ops->remove)
    + driver->ops->remove(driver, tty);
    + else
    + driver->ttys[tty->index] = NULL;
    +}
    +
    +/*
    + * tty_reopen() - fast re-open of an open tty
    + * @tty - the tty to open
    *
    * Return 0 on success, -errno on error.
    *
    @@ -1423,11 +1461,7 @@ 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;

    if (!*tp_loc)
    *tp_loc = tp;
    @@ -1441,6 +1475,9 @@ int tty_init_dev(struct tty_driver *driver, int idx,
    tty_driver_kref_get(driver);
    tty->count++;

    + if (tty_driver_install_tty(driver, tty) < 0)
    + goto release_mem_out;
    +
    /*
    * Structures all installed ... call the ldisc open routines.
    * If we fail here just call release_tty to clean up. No need
    @@ -1502,7 +1539,7 @@ EXPORT_SYMBOL(tty_free_termios);

    void tty_shutdown(struct tty_struct *tty)
    {
    - tty->driver->ttys[tty->index] = NULL;
    + tty_driver_remove_tty(tty->driver, tty);
    tty_free_termios(tty);
    }
    EXPORT_SYMBOL(tty_shutdown);
    @@ -1615,7 +1652,7 @@ void tty_release_dev(struct file *filp)
    "free (%s)\n", tty->name);
    return;
    }
    - if (!(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
    + if (!devpts) {
    if (tty != tty->driver->ttys[idx]) {
    printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty "
    "for (%s)\n", idx, tty->name);
    diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
    index ba891dd..005d06a 100644
    --- a/include/linux/tty_driver.h
    +++ b/include/linux/tty_driver.h
    @@ -15,6 +15,20 @@
    *
    * Optional method. Default behaviour is to use the ttys array
    *
    + * int (*install)(struct tty_driver *self, struct tty_struct *tty)
    + *
    + * Install a new tty into the tty driver internal tables. Used in
    + * conjunction with lookup and remove methods.
    + *
    + * Optional method. Default behaviour is to use the ttys array
    + *
    + * void (*remove)(struct tty_driver *self, struct tty_struct *tty)
    + *
    + * Remove a closed tty from the tty driver internal tables. Used in
    + * conjunction with lookup and remove methods.
    + *
    + * 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.
    @@ -212,6 +226,8 @@ struct tty_driver;

    struct tty_operations {
    struct tty_struct * (*lookup)(struct tty_driver *driver, int idx);
    + int (*install)(struct tty_driver *driver, struct tty_struct *tty);
    + void (*remove)(struct tty_driver *driver, struct tty_struct *tty);
    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/

  6. [PATCH 51/80] pty: If the administrator creates a device for a ptmx slave we should not error

    From: Alan Cox

    The open path for ptmx slaves is via the ptmx device. Opening them any
    other way is not allowed. Vegard Nossum found that previously this was not
    the case and mknod foo c 128 42; cat foo would produce nasty diagnostics

    Signed-off-by: Alan Cox
    ---

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


    diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
    index f40298e..2e96ce0 100644
    --- a/drivers/char/tty_io.c
    +++ b/drivers/char/tty_io.c
    @@ -1227,7 +1227,8 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p)
    * init_dev - initialise a tty device
    * @driver: tty driver we are opening a device on
    * @idx: device index
    - * @tty: returned tty structure
    + * @ret_tty: returned tty structure
    + * @first_ok: ok to open a new device (used by ptmx)
    *
    * Prepare a tty device. This may not be a "new" clean device but
    * could also be an active device. The pty drivers require special
    @@ -1248,7 +1249,7 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p)
    */

    static int init_dev(struct tty_driver *driver, int idx,
    - struct tty_struct **ret_tty)
    + struct tty_struct **ret_tty, int first_ok)
    {
    struct tty_struct *tty, *o_tty;
    struct ktermios *tp, **tp_loc, *o_tp, **o_tp_loc;
    @@ -1279,6 +1280,11 @@ static int init_dev(struct tty_driver *driver, int idx,
    }
    if (tty) goto fast_track;

    + if (driver->subtype == PTY_TYPE_MASTER &&
    + (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) {
    + retval = -EIO;
    + goto end_init;
    + }
    /*
    * First time open is complex, especially for PTY devices.
    * This code guarantees that either everything succeeds and the
    @@ -1413,7 +1419,7 @@ static int init_dev(struct tty_driver *driver, int idx,

    if (retval)
    goto release_mem_out;
    - goto success;
    + goto success;

    /*
    * This fast open can be used if the tty is already open.
    @@ -1795,7 +1801,7 @@ static void release_dev(struct file *filp)
    }

    /**
    - * tty_open - open a tty device
    + * __tty_open - open a tty device
    * @inode: inode of device file
    * @filp: file pointer to tty
    *
    @@ -1874,7 +1880,7 @@ retry_open:
    return -ENODEV;
    }
    got_driver:
    - retval = init_dev(driver, index, &tty);
    + retval = init_dev(driver, index, &tty, 0);
    mutex_unlock(&tty_mutex);
    if (retval)
    return retval;
    @@ -1971,7 +1977,7 @@ static int __ptmx_open(struct inode *inode, struct file *filp)
    return index;

    mutex_lock(&tty_mutex);
    - retval = init_dev(ptm_driver, index, &tty);
    + retval = init_dev(ptm_driver, index, &tty, 1);
    mutex_unlock(&tty_mutex);

    if (retval)

    --
    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 54/80] tty: Remove more special casing and out of place code

    From: Alan Cox

    Carry on pushing code out of tty_io when it belongs to other drivers. I'm
    not 100% happy with some of this and it will be worth revisiting some of the
    exports later when the restructuring work is done.

    Signed-off-by: Alan Cox
    ---

    drivers/char/pty.c | 78 +++++++++++++++++++++
    drivers/char/tty_io.c | 169 ++++++++++------------------------------------
    drivers/char/tty_ioctl.c | 66 ++++++++++++++++--
    drivers/char/vt.c | 30 ++++----
    include/linux/tty.h | 6 ++
    include/linux/vt_kern.h | 2 -
    6 files changed, 195 insertions(+), 156 deletions(-)


    diff --git a/drivers/char/pty.c b/drivers/char/pty.c
    index ec09c1c..328e8ac 100644
    --- a/drivers/char/pty.c
    +++ b/drivers/char/pty.c
    @@ -23,6 +23,7 @@
    #include
    #include
    #include
    +#include

    #include
    #include
    @@ -332,6 +333,8 @@ int pty_limit = NR_UNIX98_PTY_DEFAULT;
    static int pty_limit_min = 0;
    static int pty_limit_max = NR_UNIX98_PTY_MAX;

    +static struct cdev ptmx_cdev;
    +
    static struct ctl_table pty_table[] = {
    {
    .ctl_name = PTY_MAX,
    @@ -408,6 +411,70 @@ static const struct tty_operations ptm_unix98_ops = {
    .shutdown = pty_shutdown
    };

    +
    +/**
    + * ptmx_open - open a unix 98 pty master
    + * @inode: inode of device file
    + * @filp: file pointer to tty
    + *
    + * Allocate a unix98 pty master device from the ptmx driver.
    + *
    + * Locking: tty_mutex protects the init_dev work. tty->count should
    + * protect the rest.
    + * allocated_ptys_lock handles the list of free pty numbers
    + */
    +
    +static int __ptmx_open(struct inode *inode, struct file *filp)
    +{
    + struct tty_struct *tty;
    + int retval;
    + int index;
    +
    + nonseekable_open(inode, filp);
    +
    + /* find a device that is not in use. */
    + index = devpts_new_index();
    + if (index < 0)
    + return index;
    +
    + mutex_lock(&tty_mutex);
    + retval = tty_init_dev(ptm_driver, index, &tty, 1);
    + mutex_unlock(&tty_mutex);
    +
    + if (retval)
    + goto out;
    +
    + set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
    + filp->private_data = tty;
    + file_move(filp, &tty->tty_files);
    +
    + retval = devpts_pty_new(tty->link);
    + if (retval)
    + goto out1;
    +
    + retval = ptm_driver->ops->open(tty, filp);
    + if (!retval)
    + return 0;
    +out1:
    + tty_release_dev(filp);
    + return retval;
    +out:
    + devpts_kill_index(index);
    + return retval;
    +}
    +
    +static int ptmx_open(struct inode *inode, struct file *filp)
    +{
    + int ret;
    +
    + lock_kernel();
    + ret = __ptmx_open(inode, filp);
    + unlock_kernel();
    + return ret;
    +}
    +
    +static struct file_operations ptmx_fops;
    +
    static void __init unix98_pty_init(void)
    {
    ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
    @@ -459,7 +526,18 @@ static void __init unix98_pty_init(void)

    pty_table[1].data = &ptm_driver->refcount;
    register_sysctl_table(pty_root_table);
    +
    + /* Now create the /dev/ptmx special device */
    + tty_default_fops(&ptmx_fops);
    + ptmx_fops.open = ptmx_open;
    +
    + cdev_init(&ptmx_cdev, &ptmx_fops);
    + if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) ||
    + register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
    + panic("Couldn't register /dev/ptmx driver\n");
    + device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
    }
    +
    #else
    static inline void unix98_pty_init(void) { }
    #endif
    diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
    index f91704d..fdcc43c 100644
    --- a/drivers/char/tty_io.c
    +++ b/drivers/char/tty_io.c
    @@ -49,7 +49,7 @@
    * implement CONFIG_VT and generalize console device interface.
    * -- Marko Kohtala , March 97
    *
    - * Rewrote init_dev and release_dev to eliminate races.
    + * Rewrote tty_init_dev and tty_release_dev to eliminate races.
    * -- Bill Hawes , June 97
    *
    * Added devfs support.
    @@ -136,11 +136,6 @@ LIST_HEAD(tty_drivers); /* linked list of tty drivers */
    DEFINE_MUTEX(tty_mutex);
    EXPORT_SYMBOL(tty_mutex);

    -#ifdef CONFIG_UNIX98_PTYS
    -extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */
    -static int ptmx_open(struct inode *, struct file *);
    -#endif
    -
    static void initialize_tty_struct(struct tty_struct *tty);

    static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *);
    @@ -425,20 +420,6 @@ static const struct file_operations tty_fops = {
    .fasync = tty_fasync,
    };

    -#ifdef CONFIG_UNIX98_PTYS
    -static const struct file_operations ptmx_fops = {
    - .llseek = no_llseek,
    - .read = tty_read,
    - .write = tty_write,
    - .poll = tty_poll,
    - .unlocked_ioctl = tty_ioctl,
    - .compat_ioctl = tty_compat_ioctl,
    - .open = ptmx_open,
    - .release = tty_release,
    - .fasync = tty_fasync,
    -};
    -#endif
    -
    static const struct file_operations console_fops = {
    .llseek = no_llseek,
    .read = tty_read,
    @@ -1224,7 +1205,7 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p)
    }

    /**
    - * init_dev - initialise a tty device
    + * tty_init_dev - initialise a tty device
    * @driver: tty driver we are opening a device on
    * @idx: device index
    * @ret_tty: returned tty structure
    @@ -1248,7 +1229,7 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p)
    * relaxed for the (most common) case of reopening a tty.
    */

    -static int init_dev(struct tty_driver *driver, int idx,
    +int tty_init_dev(struct tty_driver *driver, int idx,
    struct tty_struct **ret_tty, int first_ok)
    {
    struct tty_struct *tty, *o_tty;
    @@ -1269,8 +1250,8 @@ static int init_dev(struct tty_driver *driver, int idx,
    goto end_init;
    }
    /*
    - * It's safe from now on because init_dev() is called with
    - * tty_mutex held and release_dev() won't change tty->count
    + * 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)
    @@ -1449,7 +1430,7 @@ fast_track:

    /* FIXME */
    if (!test_bit(TTY_LDISC, &tty->flags))
    - printk(KERN_ERR "init_dev but no ldisc\n");
    + printk(KERN_ERR "tty_init_dev but no ldisc\n");
    success:
    *ret_tty = tty;

    @@ -1476,7 +1457,7 @@ fail_no_mem:
    /* call the tty release_tty routine to clean out this slot */
    release_mem_out:
    if (printk_ratelimit())
    - printk(KERN_INFO "init_dev: ldisc open failed, "
    + printk(KERN_INFO "tty_init_dev: ldisc open failed, "
    "clearing slot %d\n", idx);
    release_tty(tty, idx);
    goto end_init;
    @@ -1587,7 +1568,7 @@ static void release_tty(struct tty_struct *tty, int idx)
    * WSH 09/09/97: rewritten to avoid some nasty race conditions that could
    * lead to double frees or releasing memory still in use.
    */
    -static void release_dev(struct file *filp)
    +void tty_release_dev(struct file *filp)
    {
    struct tty_struct *tty, *o_tty;
    int pty_master, tty_closing, o_tty_closing, do_sleep;
    @@ -1597,10 +1578,10 @@ static void release_dev(struct file *filp)

    tty = (struct tty_struct *)filp->private_data;
    if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode,
    - "release_dev"))
    + "tty_release_dev"))
    return;

    - check_tty_count(tty, "release_dev");
    + check_tty_count(tty, "tty_release_dev");

    tty_fasync(-1, filp, 0);

    @@ -1612,24 +1593,24 @@ static void release_dev(struct file *filp)

    #ifdef TTY_PARANOIA_CHECK
    if (idx < 0 || idx >= tty->driver->num) {
    - printk(KERN_DEBUG "release_dev: bad idx when trying to "
    + printk(KERN_DEBUG "tty_release_dev: bad idx when trying to "
    "free (%s)\n", tty->name);
    return;
    }
    if (!(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
    if (tty != tty->driver->ttys[idx]) {
    - printk(KERN_DEBUG "release_dev: driver.table[%d] not tty "
    + printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty "
    "for (%s)\n", idx, tty->name);
    return;
    }
    if (tty->termios != tty->driver->termios[idx]) {
    - printk(KERN_DEBUG "release_dev: driver.termios[%d] not termios "
    + printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios "
    "for (%s)\n",
    idx, tty->name);
    return;
    }
    if (tty->termios_locked != tty->driver->termios_locked[idx]) {
    - printk(KERN_DEBUG "release_dev: driver.termios_locked[%d] not "
    + printk(KERN_DEBUG "tty_release_dev: driver.termios_locked[%d] not "
    "termios_locked for (%s)\n",
    idx, tty->name);
    return;
    @@ -1638,7 +1619,7 @@ static void release_dev(struct file *filp)
    #endif

    #ifdef TTY_DEBUG_HANGUP
    - printk(KERN_DEBUG "release_dev of %s (tty count=%d)...",
    + printk(KERN_DEBUG "tty_release_dev of %s (tty count=%d)...",
    tty_name(tty, buf), tty->count);
    #endif

    @@ -1646,26 +1627,26 @@ static void release_dev(struct file *filp)
    if (tty->driver->other &&
    !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
    if (o_tty != tty->driver->other->ttys[idx]) {
    - printk(KERN_DEBUG "release_dev: other->table[%d] "
    + printk(KERN_DEBUG "tty_release_dev: other->table[%d] "
    "not o_tty for (%s)\n",
    idx, tty->name);
    return;
    }
    if (o_tty->termios != tty->driver->other->termios[idx]) {
    - printk(KERN_DEBUG "release_dev: other->termios[%d] "
    + printk(KERN_DEBUG "tty_release_dev: other->termios[%d] "
    "not o_termios for (%s)\n",
    idx, tty->name);
    return;
    }
    if (o_tty->termios_locked !=
    tty->driver->other->termios_locked[idx]) {
    - printk(KERN_DEBUG "release_dev: other->termios_locked["
    + printk(KERN_DEBUG "tty_release_dev: other->termios_locked["
    "%d] not o_termios_locked for (%s)\n",
    idx, tty->name);
    return;
    }
    if (o_tty->link != tty) {
    - printk(KERN_DEBUG "release_dev: bad pty pointers\n");
    + printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
    return;
    }
    }
    @@ -1723,7 +1704,7 @@ static void release_dev(struct file *filp)
    if (!do_sleep)
    break;

    - printk(KERN_WARNING "release_dev: %s: read/write wait queue "
    + printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue "
    "active!\n", tty_name(tty, buf));
    mutex_unlock(&tty_mutex);
    schedule();
    @@ -1736,14 +1717,14 @@ static void release_dev(struct file *filp)
    */
    if (pty_master) {
    if (--o_tty->count < 0) {
    - printk(KERN_WARNING "release_dev: bad pty slave count "
    + printk(KERN_WARNING "tty_release_dev: bad pty slave count "
    "(%d) for %s\n",
    o_tty->count, tty_name(o_tty, buf));
    o_tty->count = 0;
    }
    }
    if (--tty->count < 0) {
    - printk(KERN_WARNING "release_dev: bad tty->count (%d) for %s\n",
    + printk(KERN_WARNING "tty_release_dev: bad tty->count (%d) for %s\n",
    tty->count, tty_name(tty, buf));
    tty->count = 0;
    }
    @@ -1825,7 +1806,7 @@ static void release_dev(struct file *filp)
    * The termios state of a pty is reset on first open so that
    * settings don't persist across reuse.
    *
    - * Locking: tty_mutex protects tty, get_tty_driver and init_dev work.
    + * Locking: tty_mutex protects tty, get_tty_driver and tty_init_dev work.
    * tty->count should protect the rest.
    * ->siglock protects ->signal/->sighand
    */
    @@ -1889,7 +1870,7 @@ retry_open:
    return -ENODEV;
    }
    got_driver:
    - retval = init_dev(driver, index, &tty, 0);
    + retval = tty_init_dev(driver, index, &tty, 0);
    mutex_unlock(&tty_mutex);
    if (retval)
    return retval;
    @@ -1920,7 +1901,7 @@ got_driver:
    printk(KERN_DEBUG "error %d in opening %s...", retval,
    tty->name);
    #endif
    - release_dev(filp);
    + tty_release_dev(filp);
    if (retval != -ERESTARTSYS)
    return retval;
    if (signal_pending(current))
    @@ -1959,69 +1940,6 @@ static int tty_open(struct inode *inode, struct file *filp)



    -#ifdef CONFIG_UNIX98_PTYS
    -/**
    - * ptmx_open - open a unix 98 pty master
    - * @inode: inode of device file
    - * @filp: file pointer to tty
    - *
    - * Allocate a unix98 pty master device from the ptmx driver.
    - *
    - * Locking: tty_mutex protects theinit_dev work. tty->count should
    - * protect the rest.
    - * allocated_ptys_lock handles the list of free pty numbers
    - */
    -
    -static int __ptmx_open(struct inode *inode, struct file *filp)
    -{
    - struct tty_struct *tty;
    - int retval;
    - int index;
    -
    - nonseekable_open(inode, filp);
    -
    - /* find a device that is not in use. */
    - index = devpts_new_index();
    - if (index < 0)
    - return index;
    -
    - mutex_lock(&tty_mutex);
    - retval = init_dev(ptm_driver, index, &tty, 1);
    - mutex_unlock(&tty_mutex);
    -
    - if (retval)
    - goto out;
    -
    - set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
    - filp->private_data = tty;
    - file_move(filp, &tty->tty_files);
    -
    - retval = devpts_pty_new(tty->link);
    - if (retval)
    - goto out1;
    -
    - check_tty_count(tty, "ptmx_open");
    - retval = ptm_driver->ops->open(tty, filp);
    - if (!retval)
    - return 0;
    -out1:
    - release_dev(filp);
    - return retval;
    -out:
    - devpts_kill_index(index);
    - return retval;
    -}
    -
    -static int ptmx_open(struct inode *inode, struct file *filp)
    -{
    - int ret;
    -
    - lock_kernel();
    - ret = __ptmx_open(inode, filp);
    - unlock_kernel();
    - return ret;
    -}
    -#endif

    /**
    * tty_release - vfs callback for close
    @@ -2032,13 +1950,13 @@ static int ptmx_open(struct inode *inode, struct file *filp)
    * this tty. There may however be several such references.
    *
    * Locking:
    - * Takes bkl. See release_dev
    + * Takes bkl. See tty_release_dev
    */

    static int tty_release(struct inode *inode, struct file *filp)
    {
    lock_kernel();
    - release_dev(filp);
    + tty_release_dev(filp);
    unlock_kernel();
    return 0;
    }
    @@ -2932,7 +2850,7 @@ int tty_put_char(struct tty_struct *tty, unsigned char ch)

    EXPORT_SYMBOL_GPL(tty_put_char);

    -static struct class *tty_class;
    +struct class *tty_class;

    /**
    * tty_register_device - register a tty device
    @@ -3197,6 +3115,11 @@ struct tty_struct *get_current_tty(void)
    }
    EXPORT_SYMBOL_GPL(get_current_tty);

    +void tty_default_fops(struct file_operations *fops)
    +{
    + *fops = tty_fops;
    +}
    +
    /*
    * Initialize the console device. This is called *early*, so
    * we can't necessarily depend on lots of kernel help here.
    @@ -3234,12 +3157,6 @@ postcore_initcall(tty_class_init);
    /* 3/2004 jmc: why do these devices exist? */

    static struct cdev tty_cdev, console_cdev;
    -#ifdef CONFIG_UNIX98_PTYS
    -static struct cdev ptmx_cdev;
    -#endif
    -#ifdef CONFIG_VT
    -static struct cdev vc0_cdev;
    -#endif

    /*
    * Ok, now we can initialize the rest of the tty devices and can count
    @@ -3251,32 +3168,18 @@ static int __init tty_init(void)
    if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
    register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)
    panic("Couldn't register /dev/tty driver\n");
    - device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL,
    + device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL,
    "tty");

    cdev_init(&console_cdev, &console_fops);
    if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
    register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)
    panic("Couldn't register /dev/console driver\n");
    - device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
    + device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
    "console");

    -#ifdef CONFIG_UNIX98_PTYS
    - cdev_init(&ptmx_cdev, &ptmx_fops);
    - if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) ||
    - register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
    - panic("Couldn't register /dev/ptmx driver\n");
    - device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
    -#endif
    -
    #ifdef CONFIG_VT
    - cdev_init(&vc0_cdev, &console_fops);
    - if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
    - register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
    - panic("Couldn't register /dev/tty0 driver\n");
    - device_create_drvdata(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
    -
    - vty_init();
    + vty_init(&console_fops);
    #endif
    return 0;
    }
    diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
    index 3067085..14cc19c 100644
    --- a/drivers/char/tty_ioctl.c
    +++ b/drivers/char/tty_ioctl.c
    @@ -40,6 +40,15 @@
    #define TERMIOS_OLD 8


    +/**
    + * tty_chars_in_buffer - characters pending
    + * @tty: terminal
    + *
    + * Return the number of bytes of data in the device private
    + * output queue. If no private method is supplied there is assumed
    + * to be no queue on the device.
    + */
    +
    int tty_chars_in_buffer(struct tty_struct *tty)
    {
    if (tty->ops->chars_in_buffer)
    @@ -47,26 +56,49 @@ int tty_chars_in_buffer(struct tty_struct *tty)
    else
    return 0;
    }
    -
    EXPORT_SYMBOL(tty_chars_in_buffer);

    +/**
    + * tty_write_room - write queue space
    + * @tty: terminal
    + *
    + * Return the number of bytes that can be queued to this device
    + * at the present time. The result should be treated as a guarantee
    + * and the driver cannot offer a value it later shrinks by more than
    + * the number of bytes written. If no method is provided 2K is always
    + * returned and data may be lost as there will be no flow control.
    + */
    +
    int tty_write_room(struct tty_struct *tty)
    {
    if (tty->ops->write_room)
    return tty->ops->write_room(tty);
    return 2048;
    }
    -
    EXPORT_SYMBOL(tty_write_room);

    +/**
    + * tty_driver_flush_buffer - discard internal buffer
    + * @tty: terminal
    + *
    + * Discard the internal output buffer for this device. If no method
    + * is provided then either the buffer cannot be hardware flushed or
    + * there is no buffer driver side.
    + */
    void tty_driver_flush_buffer(struct tty_struct *tty)
    {
    if (tty->ops->flush_buffer)
    tty->ops->flush_buffer(tty);
    }
    -
    EXPORT_SYMBOL(tty_driver_flush_buffer);

    +/**
    + * tty_throttle - flow control
    + * @tty: terminal
    + *
    + * Indicate that a tty should stop transmitting data down the stack.
    + */
    +
    void tty_throttle(struct tty_struct *tty)
    {
    /* check TTY_THROTTLED first so it indicates our state */
    @@ -76,6 +108,13 @@ void tty_throttle(struct tty_struct *tty)
    }
    EXPORT_SYMBOL(tty_throttle);

    +/**
    + * tty_unthrottle - flow control
    + * @tty: terminal
    + *
    + * Indicate that a tty may continue transmitting data down the stack.
    + */
    +
    void tty_unthrottle(struct tty_struct *tty)
    {
    if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
    @@ -112,6 +151,11 @@ void tty_wait_until_sent(struct tty_struct *tty, long timeout)
    }
    EXPORT_SYMBOL(tty_wait_until_sent);

    +
    +/*
    + * Termios Helper Methods
    + */
    +
    static void unset_locked_termios(struct ktermios *termios,
    struct ktermios *old,
    struct ktermios *locked)
    @@ -346,6 +390,16 @@ void tty_termios_encode_baud_rate(struct ktermios *termios,
    }
    EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);

    +/**
    + * tty_encode_baud_rate - set baud rate of the tty
    + * @ibaud: input baud rate
    + * @obad: output baud rate
    + *
    + * Update the current termios data for the tty with the new speed
    + * settings. The caller must hold the termios_mutex for the tty in
    + * question.
    + */
    +
    void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
    {
    tty_termios_encode_baud_rate(tty->termios, ibaud, obaud);
    @@ -430,7 +484,7 @@ EXPORT_SYMBOL(tty_termios_hw_change);
    * is a bit of layering violation here with n_tty in terms of the
    * internal knowledge of this function.
    *
    - * Locking: termios_sem
    + * Locking: termios_mutex
    */

    static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
    @@ -508,7 +562,7 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
    * functions before using change_termios to do the actual changes.
    *
    * Locking:
    - * Called functions take ldisc and termios_sem locks
    + * Called functions take ldisc and termios_mutex locks
    */

    static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
    @@ -715,7 +769,7 @@ static void set_sgflags(struct ktermios *termios, int flags)
    * Updates a terminal from the legacy BSD style terminal information
    * structure.
    *
    - * Locking: termios_sem
    + * Locking: termios_mutex
    */

    static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
    diff --git a/drivers/char/vt.c b/drivers/char/vt.c
    index 37a45db..57029fe 100644
    --- a/drivers/char/vt.c
    +++ b/drivers/char/vt.c
    @@ -100,10 +100,10 @@
    #include
    #include
    #include
    -
    -#include
    +#include
    +#include
    #include
    -#include
    +#include

    #define MAX_NR_CON_DRIVER 16

    @@ -2352,8 +2352,6 @@ rescan_last_byte:
    FLUSH
    console_conditional_schedule();
    release_console_sem();
    -
    -out:
    notify_update(vc);
    return n;
    #undef FLUSH
    @@ -2784,13 +2782,6 @@ static int con_open(struct tty_struct *tty, struct file *filp)
    return ret;
    }

    -/*
    - * We take tty_mutex in here to prevent another thread from coming in via init_dev
    - * and taking a ref against the tty while we're in the process of forgetting
    - * about it and cleaning things up.
    - *
    - * This is because vcs_remove_sysfs() can sleep and will drop the BKL.
    - */
    static void con_close(struct tty_struct *tty, struct file *filp)
    {
    /* Nothing to do - we defer to shutdown */
    @@ -2932,8 +2923,16 @@ static const struct tty_operations con_ops = {
    .shutdown = con_shutdown
    };

    -int __init vty_init(void)
    +static struct cdev vc0_cdev;
    +
    +int __init vty_init(const struct file_operations *console_fops)
    {
    + cdev_init(&vc0_cdev, console_fops);
    + if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
    + register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
    + panic("Couldn't register /dev/tty0 driver\n");
    + device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
    +
    vcs_init();

    console_driver = alloc_tty_driver(MAX_NR_CONSOLES);
    @@ -2952,7 +2951,6 @@ int __init vty_init(void)
    tty_set_operations(console_driver, &con_ops);
    if (tty_register_driver(console_driver))
    panic("Couldn't register console driver\n");
    -
    kbd_init();
    console_map_init();
    #ifdef CONFIG_PROM_CONSOLE
    @@ -3446,7 +3444,7 @@ int register_con_driver(const struct consw *csw, int first, int last)
    if (retval)
    goto err;

    - con_driver->dev = device_create_drvdata(vtconsole_class, NULL,
    + con_driver->dev = device_create(vtconsole_class, NULL,
    MKDEV(0, con_driver->node),
    NULL, "vtcon%i",
    con_driver->node);
    @@ -3557,7 +3555,7 @@ static int __init vtconsole_class_init(void)
    struct con_driver *con = &registered_con_driver[i];

    if (con->con && !con->dev) {
    - con->dev = device_create_drvdata(vtconsole_class, NULL,
    + con->dev = device_create(vtconsole_class, NULL,
    MKDEV(0, con->node),
    NULL, "vtcon%i",
    con->node);
    diff --git a/include/linux/tty.h b/include/linux/tty.h
    index 6e39c70..6cc7ccc 100644
    --- a/include/linux/tty.h
    +++ b/include/linux/tty.h
    @@ -314,6 +314,8 @@ extern int kmsg_redirect;
    extern void console_init(void);
    extern int vcs_init(void);

    +extern struct class *tty_class;
    +
    /**
    * tty_kref_get - get a tty reference
    * @tty: tty device
    @@ -398,6 +400,10 @@ extern int tty_perform_flush(struct tty_struct *tty, unsigned long arg);
    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 int tty_init_dev(struct tty_driver *driver, int idx,
    + struct tty_struct **ret_tty, int first_ok);
    +extern void tty_release_dev(struct file *filp);

    extern struct mutex tty_mutex;

    diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h
    index 1cbd0a7..2f11134 100644
    --- a/include/linux/vt_kern.h
    +++ b/include/linux/vt_kern.h
    @@ -96,7 +96,7 @@ void change_console(struct vc_data *new_vc);
    void reset_vc(struct vc_data *vc);
    extern int unbind_con_driver(const struct consw *csw, int first, int last,
    int deflt);
    -int vty_init(void);
    +int vty_init(const struct file_operations *console_fops);

    /*
    * vc_screen.c shares this temporary buffer with the console write code so that

    --
    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 44/80] tty: usb-serial krefs

    From: Alan Cox

    Use kref in the USB serial drivers so that we don't free tty structures
    from under the URB receive handlers as has historically been the case if
    you were unlucky. This also gives us a framework for general tty drivers to
    use tty_port objects and refcount.

    Contains two err->dev_err changes merged together to fix clashes in the
    -next tree.

    Signed-off-by: Alan Cox
    ---

    drivers/char/tty_port.c | 41 ++++++++++++++++++
    drivers/usb/serial/aircable.c | 15 ++++--
    drivers/usb/serial/belkin_sa.c | 3 +
    drivers/usb/serial/console.c | 8 ++-
    drivers/usb/serial/cyberjack.c | 3 +
    drivers/usb/serial/cypress_m8.c | 5 +-
    drivers/usb/serial/digi_acceleport.c | 19 ++++++--
    drivers/usb/serial/empeg.c | 8 ++-
    drivers/usb/serial/ftdi_sio.c | 19 +++++---
    drivers/usb/serial/garmin_gps.c | 3 +
    drivers/usb/serial/generic.c | 3 +
    drivers/usb/serial/io_edgeport.c | 43 ++++++++++++------
    drivers/usb/serial/io_ti.c | 26 ++++++++---
    drivers/usb/serial/ipaq.c | 3 +
    drivers/usb/serial/ipw.c | 3 +
    drivers/usb/serial/ir-usb.c | 3 +
    drivers/usb/serial/iuu_phoenix.c | 3 +
    drivers/usb/serial/keyspan.c | 77 +++++++++++++++++----------------
    drivers/usb/serial/keyspan_pda.c | 16 ++++---
    drivers/usb/serial/kl5kusb105.c | 3 +
    drivers/usb/serial/kobil_sct.c | 3 +
    drivers/usb/serial/mct_u232.c | 6 ++-
    drivers/usb/serial/mos7720.c | 36 ++-------------
    drivers/usb/serial/mos7840.c | 7 ++-
    drivers/usb/serial/navman.c | 3 +
    drivers/usb/serial/omninet.c | 10 +++-
    drivers/usb/serial/option.c | 18 +++++---
    drivers/usb/serial/oti6858.c | 3 +
    drivers/usb/serial/pl2303.c | 4 +-
    drivers/usb/serial/safe_serial.c | 11 +++--
    drivers/usb/serial/sierra.c | 16 ++++---
    drivers/usb/serial/spcp8x5.c | 3 +
    drivers/usb/serial/ti_usb_3410_5052.c | 44 ++++++++++---------
    drivers/usb/serial/usb-serial.c | 24 ++++++----
    drivers/usb/serial/visor.c | 18 +++++---
    drivers/usb/serial/whiteheat.c | 8 ++-
    include/linux/tty.h | 3 +
    37 files changed, 313 insertions(+), 208 deletions(-)


    diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c
    index 6fadb19..553b0e9 100644
    --- a/drivers/char/tty_port.c
    +++ b/drivers/char/tty_port.c
    @@ -23,6 +23,7 @@ void tty_port_init(struct tty_port *port)
    init_waitqueue_head(&port->open_wait);
    init_waitqueue_head(&port->close_wait);
    mutex_init(&port->mutex);
    + spin_lock_init(&port->lock);
    port->close_delay = (50 * HZ) / 100;
    port->closing_wait = (3000 * HZ) / 100;
    }
    @@ -53,3 +54,43 @@ void tty_port_free_xmit_buf(struct tty_port *port)
    EXPORT_SYMBOL(tty_port_free_xmit_buf);


    +/**
    + * tty_port_tty_get - get a tty reference
    + * @port: tty port
    + *
    + * Return a refcount protected tty instance or NULL if the port is not
    + * associated with a tty (eg due to close or hangup)
    + */
    +
    +struct tty_struct *tty_port_tty_get(struct tty_port *port)
    +{
    + unsigned long flags;
    + struct tty_struct *tty;
    +
    + spin_lock_irqsave(&port->lock, flags);
    + tty = tty_kref_get(port->tty);
    + spin_unlock_irqrestore(&port->lock, flags);
    + return tty;
    +}
    +EXPORT_SYMBOL(tty_port_tty_get);
    +
    +/**
    + * tty_port_tty_set - set the tty of a port
    + * @port: tty port
    + * @tty: the tty
    + *
    + * Associate the port and tty pair. Manages any internal refcounts.
    + * Pass NULL to deassociate a port
    + */
    +
    +void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
    +{
    + unsigned long flags;
    +
    + spin_lock_irqsave(&port->lock, flags);
    + if (port->tty)
    + tty_kref_put(port->tty);
    + port->tty = tty;
    + spin_unlock_irqrestore(&port->lock, flags);
    +}
    +EXPORT_SYMBOL(tty_port_tty_set);
    diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
    index 79ea98c..99fb7dc 100644
    --- a/drivers/usb/serial/aircable.c
    +++ b/drivers/usb/serial/aircable.c
    @@ -272,7 +272,7 @@ static void aircable_read(struct work_struct *work)
    * 64 bytes, to ensure I do not get throttled.
    * Ask USB mailing list for better aproach.
    */
    - tty = port->port.tty;
    + tty = tty_port_tty_get(&port->port);

    if (!tty) {
    schedule_work(&priv->rx_work);
    @@ -283,12 +283,13 @@ static void aircable_read(struct work_struct *work)
    count = min(64, serial_buf_data_avail(priv->rx_buf));

    if (count <= 0)
    - return; /* We have finished sending everything. */
    + goto out; /* We have finished sending everything. */

    tty_prepare_flip_string(tty, &data, count);
    if (!data) {
    - err("%s- kzalloc(%d) failed.", __func__, count);
    - return;
    + dev_err(&port->dev, "%s- kzalloc(%d) failed.",
    + __func__, count);
    + goto out;
    }

    serial_buf_get(priv->rx_buf, data, count);
    @@ -297,7 +298,8 @@ static void aircable_read(struct work_struct *work)

    if (serial_buf_data_avail(priv->rx_buf))
    schedule_work(&priv->rx_work);
    -
    +out:
    + tty_kref_put(tty);
    return;
    }
    /* End of private methods */
    @@ -495,7 +497,7 @@ static void aircable_read_bulk_callback(struct urb *urb)
    usb_serial_debug_data(debug, &port->dev, __func__,
    urb->actual_length, urb->transfer_buffer);

    - tty = port->port.tty;
    + tty = tty_port_tty_get(&port->port);
    if (tty && urb->actual_length) {
    if (urb->actual_length <= 2) {
    /* This is an incomplete package */
    @@ -527,6 +529,7 @@ static void aircable_read_bulk_callback(struct urb *urb)
    }
    aircable_read(&priv->rx_work);
    }
    + tty_kref_put(tty);

    /* Schedule the next read _if_ we are still open */
    if (port->port.count) {
    diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
    index 2ebe06c..1913bc7 100644
    --- a/drivers/usb/serial/belkin_sa.c
    +++ b/drivers/usb/serial/belkin_sa.c
    @@ -322,7 +322,7 @@ static void belkin_sa_read_int_callback(struct urb *urb)
    * to look in to this before committing any code.
    */
    if (priv->last_lsr & BELKIN_SA_LSR_ERR) {
    - tty = port->port.tty;
    + tty = tty_port_tty_get(&port->port);
    /* Overrun Error */
    if (priv->last_lsr & BELKIN_SA_LSR_OE) {
    }
    @@ -335,6 +335,7 @@ static void belkin_sa_read_int_callback(struct urb *urb)
    /* Break Indicator */
    if (priv->last_lsr & BELKIN_SA_LSR_BI) {
    }
    + tty_kref_put(tty);
    }
    #endif
    spin_unlock_irqrestore(&priv->lock, flags);
    diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
    index e980766..5b20de1 100644
    --- a/drivers/usb/serial/console.c
    +++ b/drivers/usb/serial/console.c
    @@ -117,7 +117,7 @@ static int usb_console_setup(struct console *co, char *options)
    }

    port = serial->port[0];
    - port->port.tty = NULL;
    + tty_port_tty_set(&port->port, NULL);

    info->port = port;

    @@ -143,7 +143,7 @@ static int usb_console_setup(struct console *co, char *options)
    }
    memset(&dummy, 0, sizeof(struct ktermios));
    tty->termios = termios;
    - port->port.tty = tty;
    + tty_port_tty_set(&port->port, tty);
    }

    /* only call the device specific open if this
    @@ -163,7 +163,7 @@ static int usb_console_setup(struct console *co, char *options)
    tty_termios_encode_baud_rate(termios, baud, baud);
    serial->type->set_termios(tty, port, &dummy);

    - port->port.tty = NULL;
    + tty_port_tty_set(&port->port, NULL);
    kfree(termios);
    kfree(tty);
    }
    @@ -176,7 +176,7 @@ out:
    return retval;
    free_termios:
    kfree(termios);
    - port->port.tty = NULL;
    + tty_port_tty_set(&port->port, NULL);
    free_tty:
    kfree(tty);
    reset_open_count:
    diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
    index b4d7235..94ef36c 100644
    --- a/drivers/usb/serial/cyberjack.c
    +++ b/drivers/usb/serial/cyberjack.c
    @@ -384,7 +384,7 @@ static void cyberjack_read_bulk_callback(struct urb *urb)
    return;
    }

    - tty = port->port.tty;
    + tty = tty_port_tty_get(&port->port);
    if (!tty) {
    dbg("%s - ignoring since device not open\n", __func__);
    return;
    @@ -394,6 +394,7 @@ static void cyberjack_read_bulk_callback(struct urb *urb)
    tty_insert_flip_string(tty, data, urb->actual_length);
    tty_flip_buffer_push(tty);
    }
    + tty_kref_put(tty);

    spin_lock(&priv->lock);

    diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
    index 22837a3..f3514a9 100644
    --- a/drivers/usb/serial/cypress_m8.c
    +++ b/drivers/usb/serial/cypress_m8.c
    @@ -1286,7 +1286,7 @@ static void cypress_read_int_callback(struct urb *urb)
    }
    spin_unlock_irqrestore(&priv->lock, flags);

    - tty = port->port.tty;
    + tty = tty_port_tty_get(&port->port);
    if (!tty) {
    dbg("%s - bad tty pointer - exiting", __func__);
    return;
    @@ -1362,7 +1362,7 @@ static void cypress_read_int_callback(struct urb *urb)
    data[i]);
    tty_insert_flip_char(tty, data[i], tty_flag);
    }
    - tty_flip_buffer_push(port->port.tty);
    + tty_flip_buffer_push(tty);
    }

    spin_lock_irqsave(&priv->lock, flags);
    @@ -1371,6 +1371,7 @@ static void cypress_read_int_callback(struct urb *urb)
    spin_unlock_irqrestore(&priv->lock, flags);

    continue_read:
    + tty_kref_put(tty);

    /* Continue trying to always read... unless the port has closed. */

    diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
    index 240aad1..5756ac6 100644
    --- a/drivers/usb/serial/digi_acceleport.c
    +++ b/drivers/usb/serial/digi_acceleport.c
    @@ -604,7 +604,9 @@ static void digi_wakeup_write_lock(struct work_struct *work)

    static void digi_wakeup_write(struct usb_serial_port *port)
    {
    - tty_wakeup(port->port.tty);
    + struct tty_struct *tty = tty_port_tty_get(&port->port);
    + tty_wakeup(tty);
    + tty_kref_put(tty);
    }


    @@ -1668,7 +1670,7 @@ static int digi_read_inb_callback(struct urb *urb)
    {

    struct usb_serial_port *port = urb->context;
    - struct tty_struct *tty = port->port.tty;
    + struct tty_struct *tty;
    struct digi_port *priv = usb_get_serial_port_data(port);
    int opcode = ((unsigned char *)urb->transfer_buffer)[0];
    int len = ((unsigned char *)urb->transfer_buffer)[1];
    @@ -1692,6 +1694,7 @@ static int digi_read_inb_callback(struct urb *urb)
    return -1;
    }

    + tty = tty_port_tty_get(&port->port);
    spin_lock(&priv->dp_port_lock);

    /* check for throttle; if set, do not resubmit read urb */
    @@ -1735,6 +1738,7 @@ static int digi_read_inb_callback(struct urb *urb)
    }
    }
    spin_unlock(&priv->dp_port_lock);
    + tty_kref_put(tty);

    if (opcode == DIGI_CMD_RECEIVE_DISABLE)
    dbg("%s: got RECEIVE_DISABLE", __func__);
    @@ -1760,6 +1764,7 @@ static int digi_read_oob_callback(struct urb *urb)

    struct usb_serial_port *port = urb->context;
    struct usb_serial *serial = port->serial;
    + struct tty_struct *tty;
    struct digi_port *priv = usb_get_serial_port_data(port);
    int opcode, line, status, val;
    int i;
    @@ -1787,10 +1792,11 @@ static int digi_read_oob_callback(struct urb *urb)
    if (priv == NULL)
    return -1;

    + tty = tty_port_tty_get(&port->port);
    rts = 0;
    if (port->port.count)
    - rts = port->port.tty->termios->c_cflag & CRTSCTS;
    -
    + rts = tty->termios->c_cflag & CRTSCTS;
    +
    if (opcode == DIGI_CMD_READ_INPUT_SIGNALS) {
    spin_lock(&priv->dp_port_lock);
    /* convert from digi flags to termiox flags */
    @@ -1798,14 +1804,14 @@ static int digi_read_oob_callback(struct urb *urb)
    priv->dp_modem_signals |= TIOCM_CTS;
    /* port must be open to use tty struct */
    if (rts) {
    - port->port.tty->hw_stopped = 0;
    + tty->hw_stopped = 0;
    digi_wakeup_write(port);
    }
    } else {
    priv->dp_modem_signals &= ~TIOCM_CTS;
    /* port must be open to use tty struct */
    if (rts)
    - port->port.tty->hw_stopped = 1;
    + tty->hw_stopped = 1;
    }
    if (val & DIGI_READ_INPUT_SIGNALS_DSR)
    priv->dp_modem_signals |= TIOCM_DSR;
    @@ -1830,6 +1836,7 @@ static int digi_read_oob_callback(struct urb *urb)
    } else if (opcode == DIGI_CMD_IFLUSH_FIFO) {
    wake_up_interruptible(&priv->dp_flush_wait);
    }
    + tty_kref_put(tty);
    }
    return 0;

    diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
    index a6ab5b5..1072e84 100644
    --- a/drivers/usb/serial/empeg.c
    +++ b/drivers/usb/serial/empeg.c
    @@ -33,9 +33,8 @@
    * Moved MOD_DEC_USE_COUNT to end of empeg_close().
    *
    * (12/03/2000) gb
    - * Added port->port.tty->ldisc.set_termios(port->port.tty, NULL) to
    - * empeg_open(). This notifies the tty driver that the termios have
    - * changed.
    + * Added tty->ldisc.set_termios(port, tty, NULL) to empeg_open().
    + * This notifies the tty driver that the termios have changed.
    *
    * (11/13/2000) gb
    * Moved tty->low_latency = 1 from empeg_read_bulk_callback() to
    @@ -354,7 +353,7 @@ static void empeg_read_bulk_callback(struct urb *urb)

    usb_serial_debug_data(debug, &port->dev, __func__,
    urb->actual_length, data);
    - tty = port->port.tty;
    + tty = tty_port_tty_get(&port->port);

    if (urb->actual_length) {
    tty_buffer_request_room(tty, urb->actual_length);
    @@ -362,6 +361,7 @@ static void empeg_read_bulk_callback(struct urb *urb)
    tty_flip_buffer_push(tty);
    bytes_in += urb->actual_length;
    }
    + tty_kref_put(tty);

    /* Continue trying to always read */
    usb_fill_bulk_urb(
    diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
    index 1ac7e80..c2ac129 100644
    --- a/drivers/usb/serial/ftdi_sio.c
    +++ b/drivers/usb/serial/ftdi_sio.c
    @@ -1808,7 +1808,7 @@ static void ftdi_read_bulk_callback(struct urb *urb)
    if (port->port.count <= 0)
    return;

    - tty = port->port.tty;
    + tty = tty_port_tty_get(&port->port);
    if (!tty) {
    dbg("%s - bad tty pointer - exiting", __func__);
    return;
    @@ -1817,7 +1817,7 @@ static void ftdi_read_bulk_callback(struct urb *urb)
    priv = usb_get_serial_port_data(port);
    if (!priv) {
    dbg("%s - bad port private data pointer - exiting", __func__);
    - return;
    + goto out;
    }

    if (urb != port->read_urb)
    @@ -1827,7 +1827,7 @@ static void ftdi_read_bulk_callback(struct urb *urb)
    /* This will happen at close every time so it is a dbg not an
    err */
    dbg("(this is ok on close) nonzero read bulk status received: %d", status);
    - return;
    + goto out;
    }

    /* count data bytes, but not status bytes */
    @@ -1838,7 +1838,8 @@ static void ftdi_read_bulk_callback(struct urb *urb)
    spin_unlock_irqrestore(&priv->rx_lock, flags);

    ftdi_process_read(&priv->rx_work.work);
    -
    +out:
    + tty_kref_put(tty);
    } /* ftdi_read_bulk_callback */


    @@ -1863,7 +1864,7 @@ static void ftdi_process_read(struct work_struct *work)
    if (port->port.count <= 0)
    return;

    - tty = port->port.tty;
    + tty = tty_port_tty_get(&port->port);
    if (!tty) {
    dbg("%s - bad tty pointer - exiting", __func__);
    return;
    @@ -1872,13 +1873,13 @@ static void ftdi_process_read(struct work_struct *work)
    priv = usb_get_serial_port_data(port);
    if (!priv) {
    dbg("%s - bad port private data pointer - exiting", __func__);
    - return;
    + goto out;
    }

    urb = port->read_urb;
    if (!urb) {
    dbg("%s - bad read_urb pointer - exiting", __func__);
    - return;
    + goto out;
    }

    data = urb->transfer_buffer;
    @@ -2020,7 +2021,7 @@ static void ftdi_process_read(struct work_struct *work)
    schedule_delayed_work(&priv->rx_work, 1);
    else
    dbg("%s - port is closed", __func__);
    - return;
    + goto out;
    }

    /* urb is completely processed */
    @@ -2041,6 +2042,8 @@ static void ftdi_process_read(struct work_struct *work)
    err("%s - failed resubmitting read urb, error %d",
    __func__, result);
    }
    +out:
    + tty_kref_put(tty);
    } /* ftdi_process_read */


    diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
    index d953820..2ad0569 100644
    --- a/drivers/usb/serial/garmin_gps.c
    +++ b/drivers/usb/serial/garmin_gps.c
    @@ -276,7 +276,7 @@ static inline int isAbortTrfCmnd(const unsigned char *buf)
    static void send_to_tty(struct usb_serial_port *port,
    char *data, unsigned int actual_length)
    {
    - struct tty_struct *tty = port->port.tty;
    + struct tty_struct *tty = tty_port_tty_get(&port->port);

    if (tty && actual_length) {

    @@ -287,6 +287,7 @@ static void send_to_tty(struct usb_serial_port *port,
    tty_insert_flip_string(tty, data, actual_length);
    tty_flip_buffer_push(tty);
    }
    + tty_kref_put(tty);
    }


    diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
    index fe84c88..814909f 100644
    --- a/drivers/usb/serial/generic.c
    +++ b/drivers/usb/serial/generic.c
    @@ -330,7 +330,7 @@ static void resubmit_read_urb(struct usb_serial_port *port, gfp_t mem_flags)
    static void flush_and_resubmit_read_urb(struct usb_serial_port *port)
    {
    struct urb *urb = port->read_urb;
    - struct tty_struct *tty = port->port.tty;
    + struct tty_struct *tty = tty_port_tty_get(&port->port);
    int room;

    /* Push data to tty */
    @@ -341,6 +341,7 @@ static void flush_and_resubmit_read_urb(struct usb_serial_port *port)
    tty_flip_buffer_push(tty);
    }
    }
    + tty_kref_put(tty);

    resubmit_read_urb(port, GFP_ATOMIC);
    }
    diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
    index bfa508d..611f97f 100644
    --- a/drivers/usb/serial/io_edgeport.c
    +++ b/drivers/usb/serial/io_edgeport.c
    @@ -600,6 +600,7 @@ static void edge_interrupt_callback(struct urb *urb)
    struct edgeport_serial *edge_serial = urb->context;
    struct edgeport_port *edge_port;
    struct usb_serial_port *port;
    + struct tty_struct *tty;
    unsigned char *data = urb->transfer_buffer;
    int length = urb->actual_length;
    int bytes_avail;
    @@ -675,9 +676,12 @@ static void edge_interrupt_callback(struct urb *urb)

    /* tell the tty driver that something
    has changed */
    - if (edge_port->port->port.tty)
    - tty_wakeup(edge_port->port->port.tty);
    -
    + tty = tty_port_tty_get(
    + &edge_port->port->port);
    + if (tty) {
    + tty_wakeup(tty);
    + tty_kref_put(tty);
    + }
    /* Since we have more credit, check
    if more data can be sent */
    send_more_port_data(edge_serial,
    @@ -778,13 +782,14 @@ static void edge_bulk_out_data_callback(struct urb *urb)
    __func__, status);
    }

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

    if (tty && edge_port->open) {
    /* let the tty driver wakeup if it has a special
    write_wakeup function */
    tty_wakeup(tty);
    }
    + tty_kref_put(tty);

    /* Release the Write URB */
    edge_port->write_in_progress = false;
    @@ -826,11 +831,12 @@ static void edge_bulk_out_cmd_callback(struct urb *urb)
    }

    /* Get pointer to tty */
    - tty = edge_port->port->port.tty;
    + tty = tty_port_tty_get(&edge_port->port->port);

    /* tell the tty driver that something has changed */
    if (tty && edge_port->open)
    tty_wakeup(tty);
    + tty_kref_put(tty);

    /* we have completed the command */
    edge_port->commandPending = false;
    @@ -1932,11 +1938,13 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial,
    edge_serial->rxPort];
    edge_port = usb_get_serial_port_data(port);
    if (edge_port->open) {
    - tty = edge_port->port->port.tty;
    + tty = tty_port_tty_get(
    + &edge_port->port->port);
    if (tty) {
    dbg("%s - Sending %d bytes to TTY for port %d",
    __func__, rxLen, edge_serial->rxPort);
    edge_tty_recv(&edge_serial->serial->dev->dev, tty, buffer, rxLen);
    + tty_kref_put(tty);
    }
    edge_port->icount.rx += rxLen;
    }
    @@ -1971,6 +1979,7 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial,
    {
    struct usb_serial_port *port;
    struct edgeport_port *edge_port;
    + struct tty_struct *tty;
    __u8 code = edge_serial->rxStatusCode;

    /* switch the port pointer to the one being currently talked about */
    @@ -2020,10 +2029,12 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial,

    /* send the current line settings to the port so we are
    in sync with any further termios calls */
    - /* FIXME: locking on tty */
    - if (edge_port->port->port.tty)
    - change_port_settings(edge_port->port->port.tty,
    - edge_port, edge_port->port->port.tty->termios);
    + tty = tty_port_tty_get(&edge_port->port->port);
    + if (tty) {
    + change_port_settings(tty,
    + edge_port, tty->termios);
    + tty_kref_put(tty);
    + }

    /* we have completed the open */
    edge_port->openPending = false;
    @@ -2163,10 +2174,14 @@ static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData,
    }

    /* Place LSR data byte into Rx buffer */
    - if (lsrData && edge_port->port->port.tty)
    - edge_tty_recv(&edge_port->port->dev,
    - edge_port->port->port.tty, &data, 1);
    -
    + if (lsrData) {
    + struct tty_struct *tty =
    + tty_port_tty_get(&edge_port->port->port);
    + if (tty) {
    + edge_tty_recv(&edge_port->port->dev, tty, &data, 1);
    + tty_kref_put(tty);
    + }
    + }
    /* update input line counters */
    icount = &edge_port->icount;
    if (newLsr & LSR_BREAK)
    diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
    index cb4c543..541dd8e 100644
    --- a/drivers/usb/serial/io_ti.c
    +++ b/drivers/usb/serial/io_ti.c
    @@ -572,7 +572,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout,
    int flush)
    {
    int baud_rate;
    - struct tty_struct *tty = port->port->port.tty;
    + struct tty_struct *tty = tty_port_tty_get(&port->port->port);
    wait_queue_t wait;
    unsigned long flags;

    @@ -599,6 +599,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout,
    if (flush)
    edge_buf_clear(port->ep_out_buf);
    spin_unlock_irqrestore(&port->ep_lock, flags);
    + tty_kref_put(tty);

    /* wait for data to drain from the device */
    timeout += jiffies;
    @@ -1554,7 +1555,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr)
    /* Save the new modem status */
    edge_port->shadow_msr = msr & 0xf0;

    - tty = edge_port->port->port.tty;
    + tty = tty_port_tty_get(&edge_port->port->port);
    /* handle CTS flow control */
    if (tty && C_CRTSCTS(tty)) {
    if (msr & EDGEPORT_MSR_CTS) {
    @@ -1564,6 +1565,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr)
    tty->hw_stopped = 1;
    }
    }
    + tty_kref_put(tty);

    return;
    }
    @@ -1574,6 +1576,7 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data,
    struct async_icount *icount;
    __u8 new_lsr = (__u8)(lsr & (__u8)(LSR_OVER_ERR | LSR_PAR_ERR |
    LSR_FRM_ERR | LSR_BREAK));
    + struct tty_struct *tty;

    dbg("%s - %02x", __func__, new_lsr);

    @@ -1587,8 +1590,13 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data,
    new_lsr &= (__u8)(LSR_OVER_ERR | LSR_BREAK);

    /* Place LSR data byte into Rx buffer */
    - if (lsr_data && edge_port->port->port.tty)
    - edge_tty_recv(&edge_port->port->dev, edge_port->port->port.tty, &data, 1);
    + if (lsr_data) {
    + tty = tty_port_tty_get(&edge_port->port->port);
    + if (tty) {
    + edge_tty_recv(&edge_port->port->dev, tty, &data, 1);
    + tty_kref_put(tty);
    + }
    + }

    /* update input line counters */
    icount = &edge_port->icount;
    @@ -1749,7 +1757,7 @@ static void edge_bulk_in_callback(struct urb *urb)
    ++data;
    }

    - tty = edge_port->port->port.tty;
    + tty = tty_port_tty_get(&edge_port->port->port);
    if (tty && urb->actual_length) {
    usb_serial_debug_data(debug, &edge_port->port->dev,
    __func__, urb->actual_length, data);
    @@ -1761,6 +1769,7 @@ static void edge_bulk_in_callback(struct urb *urb)
    urb->actual_length);
    edge_port->icount.rx += urb->actual_length;
    }
    + tty_kref_put(tty);

    exit:
    /* continue read unless stopped */
    @@ -1796,6 +1805,7 @@ static void edge_bulk_out_callback(struct urb *urb)
    struct usb_serial_port *port = urb->context;
    struct edgeport_port *edge_port = usb_get_serial_port_data(port);
    int status = urb->status;
    + struct tty_struct *tty;

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

    @@ -1818,7 +1828,9 @@ static void edge_bulk_out_callback(struct urb *urb)
    }

    /* send any buffered data */
    - edge_send(port->port.tty);
    + tty = tty_port_tty_get(&port->port);
    + edge_send(tty);
    + tty_kref_put(tty);
    }

    static int edge_open(struct tty_struct *tty,
    @@ -1876,7 +1888,7 @@ static int edge_open(struct tty_struct *tty,

    /* set up the port settings */
    if (tty)
    - edge_set_termios(tty, port, port->port.tty->termios);
    + edge_set_termios(tty, port, tty->termios);

    /* open up the port */

    diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
    index cd9a2e1..2affa9c 100644
    --- a/drivers/usb/serial/ipaq.c
    +++ b/drivers/usb/serial/ipaq.c
    @@ -764,13 +764,14 @@ static void ipaq_read_bulk_callback(struct urb *urb)
    usb_serial_debug_data(debug, &port->dev, __func__,
    urb->actual_length, data);

    - tty = port->port.tty;
    + tty = tty_port_tty_get(&port->port);
    if (tty && urb->actual_length) {
    tty_buffer_request_room(tty, urb->actual_length);
    tty_insert_flip_string(tty, data, urb->actual_length);
    tty_flip_buffer_push(tty);
    bytes_in += urb->actual_length;
    }
    + tty_kref_put(tty);

    /* Continue trying to always read */
    usb_fill_bulk_urb(port->read_urb, port->serial->dev,
    diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
    index a842025..480cac2 100644
    --- a/drivers/usb/serial/ipw.c
    +++ b/drivers/usb/serial/ipw.c
    @@ -170,12 +170,13 @@ static void ipw_read_bulk_callback(struct urb *urb)
    usb_serial_debug_data(debug, &port->dev, __func__,
    urb->actual_length, data);

    - tty = port->port.tty;
    + tty = tty_port_tty_get(&port->port);
    if (tty && urb->actual_length) {
    tty_buffer_request_room(tty, urb->actual_length);
    tty_insert_flip_string(tty, data, urb->actual_length);
    tty_flip_buffer_push(tty);
    }
    + tty_kref_put(tty);

    /* Continue trying to always read */
    usb_fill_bulk_urb(port->read_urb, port->serial->dev,
    diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
    index e59155c..45d4043 100644
    --- a/drivers/usb/serial/ir-usb.c
    +++ b/drivers/usb/serial/ir-usb.c
    @@ -465,11 +465,12 @@ static void ir_read_bulk_callback(struct urb *urb)
    ir_baud = *data & 0x0f;
    usb_serial_debug_data(debug, &port->dev, __func__,
    urb->actual_length, data);
    - tty = port->port.tty;
    + tty = tty_port_tty_get(&port->port);
    if (tty_buffer_request_room(tty, urb->actual_length - 1)) {
    tty_insert_flip_string(tty, data+1, urb->actual_length - 1);
    tty_flip_buffer_push(tty);
    }
    + tty_kref_put(tty);

    /*
    * No break here.
    diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
    index ddff37f..53710aa 100644
    --- a/drivers/usb/serial/iuu_phoenix.c
    +++ b/drivers/usb/serial/iuu_phoenix.c
    @@ -629,13 +629,14 @@ static void read_buf_callback(struct urb *urb)
    }

    dbg("%s - %i chars to write", __func__, urb->actual_length);
    - tty = port->port.tty;
    + tty = tty_port_tty_get(&port->port);
    if (data == NULL)
    dbg("%s - data is NULL !!!", __func__);
    if (tty && urb->actual_length && data) {
    tty_insert_flip_string(tty, data, urb->actual_length);
    tty_flip_buffer_push(tty);
    }
    + tty_kref_put(tty);
    iuu_led_activity_on(urb);
    }

    diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
    index 704716f..15447af 100644
    --- a/drivers/usb/serial/keyspan.c
    +++ b/drivers/usb/serial/keyspan.c
    @@ -430,7 +430,7 @@ static void usa26_indat_callback(struct urb *urb)
    }

    port = urb->context;
    - tty = port->port.tty;
    + tty = tty_port_tty_get(&port->port);
    if (tty && urb->actual_length) {
    /* 0x80 bit is error flag */
    if ((data[0] & 0x80) == 0) {
    @@ -459,6 +459,7 @@ static void usa26_indat_callback(struct urb *urb)
    }
    tty_flip_buffer_push(tty);
    }
    + tty_kref_put(tty);

    /* Resubmit urb so we continue receiving */
    urb->dev = port->serial->dev;
    @@ -513,6 +514,7 @@ static void usa26_instat_callback(struct urb *urb)
    struct usb_serial *serial;
    struct usb_serial_port *port;
    struct keyspan_port_private *p_priv;
    + struct tty_struct *tty;
    int old_dcd_state, err;
    int status = urb->status;

    @@ -553,12 +555,11 @@ static void usa26_instat_callback(struct urb *urb)
    p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
    p_priv->ri_state = ((msg->ri) ? 1 : 0);

    - if (port->port.tty && !C_CLOCAL(port->port.tty)
    - && old_dcd_state != p_priv->dcd_state) {
    - if (old_dcd_state)
    - tty_hangup(port->port.tty);
    - /* else */
    - /* wake_up_interruptible(&p_priv->open_wait); */
    + if (old_dcd_state != p_priv->dcd_state) {
    + tty = tty_port_tty_get(&port->port);
    + if (tty && !C_CLOCAL(tty))
    + tty_hangup(tty);
    + tty_kref_put(tty);
    }

    /* Resubmit urb so we continue receiving */
    @@ -604,11 +605,12 @@ static void usa28_indat_callback(struct urb *urb)
    p_priv = usb_get_serial_port_data(port);
    data = urb->transfer_buffer;

    - tty = port->port.tty;
    - if (urb->actual_length) {
    + tty =tty_port_tty_get(&port->port);
    + if (tty && urb->actual_length) {
    tty_insert_flip_string(tty, data, urb->actual_length);
    tty_flip_buffer_push(tty);
    }
    + tty_kref_put(tty);

    /* Resubmit urb so we continue receiving */
    urb->dev = port->serial->dev;
    @@ -652,6 +654,7 @@ static void usa28_instat_callback(struct urb *urb)
    struct usb_serial *serial;
    struct usb_serial_port *port;
    struct keyspan_port_private *p_priv;
    + struct tty_struct *tty;
    int old_dcd_state;
    int status = urb->status;

    @@ -689,12 +692,11 @@ static void usa28_instat_callback(struct urb *urb)
    p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
    p_priv->ri_state = ((msg->ri) ? 1 : 0);

    - if (port->port.tty && !C_CLOCAL(port->port.tty)
    - && old_dcd_state != p_priv->dcd_state) {
    - if (old_dcd_state)
    - tty_hangup(port->port.tty);
    - /* else */
    - /* wake_up_interruptible(&p_priv->open_wait); */
    + if( old_dcd_state != p_priv->dcd_state && old_dcd_state) {
    + tty = tty_port_tty_get(&port->port);
    + if (tty && !C_CLOCAL(tty))
    + tty_hangup(tty);
    + tty_kref_put(tty);
    }

    /* Resubmit urb so we continue receiving */
    @@ -785,12 +787,11 @@ static void usa49_instat_callback(struct urb *urb)
    p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
    p_priv->ri_state = ((msg->ri) ? 1 : 0);

    - if (port->port.tty && !C_CLOCAL(port->port.tty)
    - && old_dcd_state != p_priv->dcd_state) {
    - if (old_dcd_state)
    - tty_hangup(port->port.tty);
    - /* else */
    - /* wake_up_interruptible(&p_priv->open_wait); */
    + if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
    + struct tty_struct *tty = tty_port_tty_get(&port->port);
    + if (tty && !C_CLOCAL(tty))
    + tty_hangup(tty);
    + tty_kref_put(tty);
    }

    /* Resubmit urb so we continue receiving */
    @@ -827,7 +828,7 @@ static void usa49_indat_callback(struct urb *urb)
    }

    port = urb->context;
    - tty = port->port.tty;
    + tty = tty_port_tty_get(&port->port);
    if (tty && urb->actual_length) {
    /* 0x80 bit is error flag */
    if ((data[0] & 0x80) == 0) {
    @@ -850,6 +851,7 @@ static void usa49_indat_callback(struct urb *urb)
    }
    tty_flip_buffer_push(tty);
    }
    + tty_kref_put(tty);

    /* Resubmit urb so we continue receiving */
    urb->dev = port->serial->dev;
    @@ -893,7 +895,7 @@ static void usa49wg_indat_callback(struct urb *urb)
    return;
    }
    port = serial->port[data[i++]];
    - tty = port->port.tty;
    + tty = tty_port_tty_get(&port->port);
    len = data[i++];

    /* 0x80 bit is error flag */
    @@ -927,6 +929,7 @@ static void usa49wg_indat_callback(struct urb *urb)
    }
    if (port->port.count)
    tty_flip_buffer_push(tty);
    + tty_kref_put(tty);
    }
    }

    @@ -967,8 +970,8 @@ static void usa90_indat_callback(struct urb *urb)
    port = urb->context;
    p_priv = usb_get_serial_port_data(port);

    - tty = port->port.tty;
    if (urb->actual_length) {
    + tty = tty_port_tty_get(&port->port);
    /* if current mode is DMA, looks like usa28 format
    otherwise looks like usa26 data format */

    @@ -1004,6 +1007,7 @@ static void usa90_indat_callback(struct urb *urb)
    }
    }
    tty_flip_buffer_push(tty);
    + tty_kref_put(tty);
    }

    /* Resubmit urb so we continue receiving */
    @@ -1025,6 +1029,7 @@ static void usa90_instat_callback(struct urb *urb)
    struct usb_serial *serial;
    struct usb_serial_port *port;
    struct keyspan_port_private *p_priv;
    + struct tty_struct *tty;
    int old_dcd_state, err;
    int status = urb->status;

    @@ -1053,12 +1058,11 @@ static void usa90_instat_callback(struct urb *urb)
    p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
    p_priv->ri_state = ((msg->ri) ? 1 : 0);

    - if (port->port.tty && !C_CLOCAL(port->port.tty)
    - && old_dcd_state != p_priv->dcd_state) {
    - if (old_dcd_state)
    - tty_hangup(port->port.tty);
    - /* else */
    - /* wake_up_interruptible(&p_priv->open_wait); */
    + if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
    + tty = tty_port_tty_get(&port->port);
    + if (tty && !C_CLOCAL(tty))
    + tty_hangup(tty);
    + tty_kref_put(tty);
    }

    /* Resubmit urb so we continue receiving */
    @@ -1130,12 +1134,11 @@ static void usa67_instat_callback(struct urb *urb)
    p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
    p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);

    - if (port->port.tty && !C_CLOCAL(port->port.tty)
    - && old_dcd_state != p_priv->dcd_state) {
    - if (old_dcd_state)
    - tty_hangup(port->port.tty);
    - /* else */
    - /* wake_up_interruptible(&p_priv->open_wait); */
    + if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
    + struct tty_struct *tty = tty_port_tty_get(&port->port);
    + if (tty && !C_CLOCAL(tty))
    + tty_hangup(tty);
    + tty_kref_put(tty);
    }

    /* Resubmit urb so we continue receiving */
    @@ -1332,7 +1335,7 @@ static void keyspan_close(struct tty_struct *tty,
    stop_urb(p_priv->out_urbs[i]);
    }
    }
    - port->port.tty = NULL;
    + tty_port_tty_set(&port->port, NULL);
    }

    /* download the firmware to a pre-renumeration device */
    diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
    index 040040a..99e9a14 100644
    --- a/drivers/usb/serial/keyspan_pda.c
    +++ b/drivers/usb/serial/keyspan_pda.c
    @@ -172,8 +172,9 @@ static void keyspan_pda_wakeup_write(struct work_struct *work)
    struct keyspan_pda_private *priv =
    container_of(work, struct keyspan_pda_private, wakeup_work);
    struct usb_serial_port *port = priv->port;
    -
    - tty_wakeup(port->port.tty);
    + struct tty_struct *tty = tty_port_tty_get(&port->port);
    + tty_wakeup(tty);
    + tty_kref_put(tty);
    }

    static void keyspan_pda_request_unthrottle(struct work_struct *work)
    @@ -205,7 +206,7 @@ static void keyspan_pda_request_unthrottle(struct work_struct *work)
    static void keyspan_pda_rx_interrupt(struct urb *urb)
    {
    struct usb_serial_port *port = urb->context;
    - struct tty_struct *tty = port->port.tty;
    + struct tty_struct *tty = tty_port_tty_get(&port->port);
    unsigned char *data = urb->transfer_buffer;
    int retval;
    int status = urb->status;
    @@ -222,7 +223,7 @@ static void keyspan_pda_rx_interrupt(struct urb *urb)
    /* this urb is terminated, clean up */
    dbg("%s - urb shutting down with status: %d",
    __func__, status);
    - return;
    + goto out;
    default:
    dbg("%s - nonzero urb status received: %d",
    __func__, status);
    @@ -261,8 +262,11 @@ static void keyspan_pda_rx_interrupt(struct urb *urb)
    exit:
    retval = usb_submit_urb(urb, GFP_ATOMIC);
    if (retval)
    - err("%s - usb_submit_urb failed with result %d",
    - __func__, retval);
    + dev_err(&port->dev,
    + "%s - usb_submit_urb failed with result %d",
    + __func__, retval);
    +out:
    + tty_kref_put(tty);
    }


    diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
    index b84dddc..ff3a07f 100644
    --- a/drivers/usb/serial/kl5kusb105.c
    +++ b/drivers/usb/serial/kl5kusb105.c
    @@ -658,7 +658,7 @@ static void klsi_105_read_bulk_callback(struct urb *urb)
    } else {
    int bytes_sent = ((__u8 *) data)[0] +
    ((unsigned int) ((__u8 *) data)[1] << 8);
    - tty = port->port.tty;
    + tty = tty_port_tty_get(&port->port);
    /* we should immediately resubmit the URB, before attempting
    * to pass the data on to the tty layer. But that needs locking
    * against re-entry an then mixed-up data because of
    @@ -679,6 +679,7 @@ static void klsi_105_read_bulk_callback(struct urb *urb)
    tty_buffer_request_room(tty, bytes_sent);
    tty_insert_flip_string(tty, data + 2, bytes_sent);
    tty_flip_buffer_push(tty);
    + tty_kref_put(tty);

    /* again lockless, but debug info only */
    priv->bytes_in += bytes_sent;
    diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
    index deba28e..cfcf37c 100644
    --- a/drivers/usb/serial/kobil_sct.c
    +++ b/drivers/usb/serial/kobil_sct.c
    @@ -383,7 +383,7 @@ static void kobil_read_int_callback(struct urb *urb)
    return;
    }

    - tty = port->port.tty;
    + tty = tty_port_tty_get(&port->port);
    if (urb->actual_length) {

    /* BEGIN DEBUG */
    @@ -405,6 +405,7 @@ static void kobil_read_int_callback(struct urb *urb)
    tty_insert_flip_string(tty, data, urb->actual_length);
    tty_flip_buffer_push(tty);
    }
    + tty_kref_put(tty);
    /* someone sets the dev to 0 if the close method has been called */
    port->interrupt_in_urb->dev = port->serial->dev;

    diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
    index 0ded8bd..9b2cef8 100644
    --- a/drivers/usb/serial/mct_u232.c
    +++ b/drivers/usb/serial/mct_u232.c
    @@ -563,10 +563,11 @@ static void mct_u232_read_int_callback(struct urb *urb)
    * Work-a-round: handle the 'usual' bulk-in pipe here
    */
    if (urb->transfer_buffer_length > 2) {
    - tty = port->port.tty;
    + tty = tty_port_tty_get(&port->port);
    if (urb->actual_length) {
    tty_insert_flip_string(tty, data, urb->actual_length);
    tty_flip_buffer_push(tty);
    + tty_kref_put(tty);
    }
    goto exit;
    }
    @@ -591,7 +592,7 @@ static void mct_u232_read_int_callback(struct urb *urb)
    * to look in to this before committing any code.
    */
    if (priv->last_lsr & MCT_U232_LSR_ERR) {
    - tty = port->port.tty;
    + tty = tty_port_tty_get(&port->port);
    /* Overrun Error */
    if (priv->last_lsr & MCT_U232_LSR_OE) {
    }
    @@ -604,6 +605,7 @@ static void mct_u232_read_int_callback(struct urb *urb)
    /* Break Indicator */
    if (priv->last_lsr & MCT_U232_LSR_BI) {
    }
    + tty_kref_put(tty);
    }
    #endif
    spin_unlock_irqrestore(&priv->lock, flags);
    diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
    index 7c4917d..7b538ca 100644
    --- a/drivers/usb/serial/mos7720.c
    +++ b/drivers/usb/serial/mos7720.c
    @@ -216,12 +216,13 @@ static void mos7720_bulk_in_callback(struct urb *urb)

    data = urb->transfer_buffer;

    - tty = port->port.tty;
    + tty = tty_port_tty_get(&port->port);
    if (tty && urb->actual_length) {
    tty_buffer_request_room(tty, urb->actual_length);
    tty_insert_flip_string(tty, data, urb->actual_length);
    tty_flip_buffer_push(tty);
    }
    + tty_kref_put(tty);

    if (!port->read_urb) {
    dbg("URB KILLED !!!");
    @@ -262,10 +263,11 @@ static void mos7720_bulk_out_data_callback(struct urb *urb)

    dbg("Entering .........");

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

    if (tty && mos7720_port->open)
    tty_wakeup(tty);
    + tty_kref_put(tty);
    }

    /*
    @@ -1267,29 +1269,6 @@ static int get_lsr_info(struct tty_struct *tty,
    return 0;
    }

    -/*
    - * get_number_bytes_avail - get number of bytes available
    - *
    - * Purpose: Let user call ioctl to get the count of number of bytes available.
    - */
    -static int get_number_bytes_avail(struct moschip_port *mos7720_port,
    - unsigned int __user *value)
    -{
    - unsigned int result = 0;
    - struct tty_struct *tty = mos7720_port->port->port.tty;
    -
    - if (!tty)
    - return -ENOIOCTLCMD;
    -
    - result = tty->read_cnt;
    -
    - dbg("%s(%d) = %d", __func__, mos7720_port->port->number, result);
    - if (copy_to_user(value, &result, sizeof(int)))
    - return -EFAULT;
    -
    - return -ENOIOCTLCMD;
    -}
    -
    static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd,
    unsigned int __user *value)
    {
    @@ -1409,13 +1388,6 @@ static int mos7720_ioctl(struct tty_struct *tty, struct file *file,
    dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd);

    switch (cmd) {
    - case TIOCINQ:
    - /* return number of bytes available */
    - dbg("%s (%d) TIOCINQ", __func__, port->number);
    - return get_number_bytes_avail(mos7720_port,
    - (unsigned int __user *)arg);
    - break;
    -
    case TIOCSERGETLSR:
    dbg("%s (%d) TIOCSERGETLSR", __func__, port->number);
    return get_lsr_info(tty, mos7720_port,
    diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
    index 09d8206..60543d7 100644
    --- a/drivers/usb/serial/mos7840.c
    +++ b/drivers/usb/serial/mos7840.c
    @@ -709,12 +709,13 @@ static void mos7840_bulk_in_callback(struct urb *urb)
    dbg("%s", "Entering ........... \n");

    if (urb->actual_length) {
    - tty = mos7840_port->port->port.tty;
    + tty = tty_port_tty_get(&mos7840_port->port->port);
    if (tty) {
    tty_buffer_request_room(tty, urb->actual_length);
    tty_insert_flip_string(tty, data, urb->actual_length);
    dbg(" %s \n", data);
    tty_flip_buffer_push(tty);
    + tty_kref_put(tty);
    }
    mos7840_port->icount.rx += urb->actual_length;
    smp_wmb();
    @@ -773,10 +774,10 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)

    dbg("%s \n", "Entering .........");

    - tty = mos7840_port->port->port.tty;
    -
    + tty = tty_port_tty_get(&mos7840_port->port->port);
    if (tty && mos7840_port->open)
    tty_wakeup(tty);
    + tty_kref_put(tty);

    }

    diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c
    index d673653..bcdcbb8 100644
    --- a/drivers/usb/serial/navman.c
    +++ b/drivers/usb/serial/navman.c
    @@ -64,12 +64,13 @@ static void navman_read_int_callback(struct urb *urb)
    usb_serial_debug_data(debug, &port->dev, __func__,
    urb->actual_length, data);

    - tty = port->port.tty;
    + tty = tty_port_tty_get(&port->port);
    if (tty && urb->actual_length) {
    tty_buffer_request_room(tty, urb->actual_length);
    tty_insert_flip_string(tty, data, urb->actual_length);
    tty_flip_buffer_push(tty);
    }
    + tty_kref_put(tty);

    exit:
    result = usb_submit_urb(urb, GFP_ATOMIC);
    diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
    index ae8e227..c4d70b0 100644
    --- a/drivers/usb/serial/omninet.c
    +++ b/drivers/usb/serial/omninet.c
    @@ -172,7 +172,7 @@ static int omninet_open(struct tty_struct *tty,
    dbg("%s - port %d", __func__, port->number);

    wport = serial->port[1];
    - wport->port.tty = tty; /* FIXME */
    + tty_port_tty_set(&wport->port, tty);

    /* Start reading from the device */
    usb_fill_bulk_urb(port->read_urb, serial->dev,
    @@ -229,9 +229,11 @@ static void omninet_read_bulk_callback(struct urb *urb)
    }

    if (urb->actual_length && header->oh_len) {
    - tty_insert_flip_string(port->port.tty,
    - data + OMNINET_DATAOFFSET, header->oh_len);
    - tty_flip_buffer_push(port->port.tty);
    + struct tty_struct *tty = tty_port_tty_get(&port->port);
    + tty_insert_flip_string(tty, data + OMNINET_DATAOFFSET,
    + header->oh_len);
    + tty_flip_buffer_push(tty);
    + tty_kref_put(tty);
    }

    /* Continue trying to always read */
    diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
    index 73f8277..6b1727e 100644
    --- a/drivers/usb/serial/option.c
    +++ b/drivers/usb/serial/option.c
    @@ -571,14 +571,14 @@ static void option_indat_callback(struct urb *urb)
    dbg("%s: nonzero status: %d on endpoint %02x.",
    __func__, status, endpoint);
    } else {
    - tty = port->port.tty;
    + tty = tty_port_tty_get(&port->port);
    if (urb->actual_length) {
    tty_buffer_request_room(tty, urb->actual_length);
    tty_insert_flip_string(tty, data, urb->actual_length);
    tty_flip_buffer_push(tty);
    - } else {
    + } else
    dbg("%s: empty read urb received", __func__);
    - }
    + tty_kref_put(tty);

    /* Resubmit urb so we continue receiving */
    if (port->port.count && status != -ESHUTDOWN) {
    @@ -647,9 +647,13 @@ static void option_instat_callback(struct urb *urb)
    portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
    portdata->ri_state = ((signals & 0x08) ? 1 : 0);

    - if (port->port.tty && !C_CLOCAL(port->port.tty) &&
    - old_dcd_state && !portdata->dcd_state)
    - tty_hangup(port->port.tty);
    + if (old_dcd_state && !portdata->dcd_state) {
    + struct tty_struct *tty =
    + tty_port_tty_get(&port->port);
    + if (tty && !C_CLOCAL(tty))
    + tty_hangup(tty);
    + tty_kref_put(tty);
    + }
    } else {
    dbg("%s: type %x req %x", __func__,
    req_pkt->bRequestType, req_pkt->bRequest);
    @@ -793,7 +797,7 @@ static void option_close(struct tty_struct *tty,
    for (i = 0; i < N_OUT_URB; i++)
    usb_kill_urb(portdata->out_urbs[i]);
    }
    - port->port.tty = NULL; /* FIXME */
    + tty_port_tty_set(&port->port, NULL);
    }

    /* Helper functions used by option_setup_urbs */
    diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
    index 42f9281..ba551f0 100644
    --- a/drivers/usb/serial/oti6858.c
    +++ b/drivers/usb/serial/oti6858.c
    @@ -998,11 +998,12 @@ static void oti6858_read_bulk_callback(struct urb *urb)
    return;
    }

    - tty = port->port.tty;
    + tty = tty_port_tty_get(&port->port);
    if (tty != NULL && urb->actual_length > 0) {
    tty_insert_flip_string(tty, data, urb->actual_length);
    tty_flip_buffer_push(tty);
    }
    + tty_kref_put(tty);

    /* schedule the interrupt urb if we are still open */
    if (port->port.count != 0) {
    diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
    index 8d60068..9084378 100644
    --- a/drivers/usb/serial/pl2303.c
    +++ b/drivers/usb/serial/pl2303.c
    @@ -1046,7 +1046,7 @@ static void pl2303_read_bulk_callback(struct urb *urb)
    tty_flag = TTY_FRAME;
    dbg("%s - tty_flag = %d", __func__, tty_flag);

    - tty = port->port.tty;
    + tty = tty_port_tty_get(&port->port);
    if (tty && urb->actual_length) {
    tty_buffer_request_room(tty, urb->actual_length + 1);
    /* overrun is special, not associated with a char */
    @@ -1056,7 +1056,7 @@ static void pl2303_read_bulk_callback(struct urb *urb)
    tty_insert_flip_char(tty, data[i], tty_flag);
    tty_flip_buffer_push(tty);
    }
    -
    + tty_kref_put(tty);
    /* Schedule the next read _if_ we are still open */
    if (port->port.count) {
    urb->dev = port->serial->dev;
    diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
    index def52d0..72903ac 100644
    --- a/drivers/usb/serial/safe_serial.c
    +++ b/drivers/usb/serial/safe_serial.c
    @@ -217,6 +217,7 @@ static void safe_read_bulk_callback(struct urb *urb)
    struct usb_serial_port *port = urb->context;
    unsigned char *data = urb->transfer_buffer;
    unsigned char length = urb->actual_length;
    + struct tty_struct *tty;
    int result;
    int status = urb->status;

    @@ -242,6 +243,7 @@ static void safe_read_bulk_callback(struct urb *urb)
    printk("\n");
    }
    #endif
    + tty = tty_port_tty_get(&port->port);
    if (safe) {
    __u16 fcs;
    fcs = fcs_compute10(data, length, CRC10_INITFCS);
    @@ -250,9 +252,9 @@ static void safe_read_bulk_callback(struct urb *urb)
    if (actual_length <= (length - 2)) {
    info("%s - actual: %d", __func__,
    actual_length);
    - tty_insert_flip_string(port->port.tty,
    + tty_insert_flip_string(tty,
    data, actual_length);
    - tty_flip_buffer_push(port->port.tty);
    + tty_flip_buffer_push(tty);
    } else {
    err("%s - inconsistent lengths %d:%d",
    __func__, actual_length, length);
    @@ -261,9 +263,10 @@ static void safe_read_bulk_callback(struct urb *urb)
    err("%s - bad CRC %x", __func__, fcs);
    }
    } else {
    - tty_insert_flip_string(port->port.tty, data, length);
    - tty_flip_buffer_push(port->port.tty);
    + tty_insert_flip_string(tty, data, length);
    + tty_flip_buffer_push(tty);
    }
    + tty_kref_put(tty);

    /* Continue trying to always read */
    usb_fill_bulk_urb(urb, port->serial->dev,
    diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
    index ea1a103..8b9eaf3 100644
    --- a/drivers/usb/serial/sierra.c
    +++ b/drivers/usb/serial/sierra.c
    @@ -440,14 +440,14 @@ static void sierra_indat_callback(struct urb *urb)
    dbg("%s: nonzero status: %d on endpoint %02x.",
    __func__, status, endpoint);
    } else {
    - tty = port->port.tty;
    if (urb->actual_length) {
    + tty = tty_port_tty_get(&port->port);
    tty_buffer_request_room(tty, urb->actual_length);
    tty_insert_flip_string(tty, data, urb->actual_length);
    tty_flip_buffer_push(tty);
    - } else {
    + tty_kref_put(tty);
    + } else
    dbg("%s: empty read urb received", __func__);
    - }

    /* Resubmit urb so we continue receiving */
    if (port->port.count && status != -ESHUTDOWN) {
    @@ -485,6 +485,7 @@ static void sierra_instat_callback(struct urb *urb)
    unsigned char signals = *((unsigned char *)
    urb->transfer_buffer +
    sizeof(struct usb_ctrlrequest));
    + struct tty_struct *tty;

    dbg("%s: signal x%x", __func__, signals);

    @@ -494,9 +495,11 @@ static void sierra_instat_callback(struct urb *urb)
    portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
    portdata->ri_state = ((signals & 0x08) ? 1 : 0);

    - if (port->port.tty && !C_CLOCAL(port->port.tty) &&
    + tty = tty_port_tty_get(&port->port);
    + if (tty && !C_CLOCAL(tty) &&
    old_dcd_state && !portdata->dcd_state)
    - tty_hangup(port->port.tty);
    + tty_hangup(tty);
    + tty_kref_put(tty);
    } else {
    dbg("%s: type %x req %x", __func__,
    req_pkt->bRequestType, req_pkt->bRequest);
    @@ -616,8 +619,7 @@ static void sierra_close(struct tty_struct *tty,
    }

    usb_kill_urb(port->interrupt_in_urb);
    -
    - port->port.tty = NULL; /* FIXME */
    + tty_port_tty_set(&port->port, NULL);
    }

    static int sierra_startup(struct usb_serial *serial)
    diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
    index 283cf6b..1533d6e 100644
    --- a/drivers/usb/serial/spcp8x5.c
    +++ b/drivers/usb/serial/spcp8x5.c
    @@ -755,7 +755,7 @@ static void spcp8x5_read_bulk_callback(struct urb *urb)
    tty_flag = TTY_FRAME;
    dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag);

    - tty = port->port.tty;
    + tty = tty_port_tty_get(&port->port);
    if (tty && urb->actual_length) {
    tty_buffer_request_room(tty, urb->actual_length + 1);
    /* overrun is special, not associated with a char */
    @@ -765,6 +765,7 @@ static void spcp8x5_read_bulk_callback(struct urb *urb)
    tty_insert_flip_char(tty, data[i], tty_flag);
    tty_flip_buffer_push(tty);
    }
    + tty_kref_put(tty);

    /* Schedule the next read _if_ we are still open */
    if (port->port.count) {
    diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
    index 9a3e495..c90237d 100644
    --- a/drivers/usb/serial/ti_usb_3410_5052.c
    +++ b/drivers/usb/serial/ti_usb_3410_5052.c
    @@ -179,7 +179,7 @@ static int ti_set_mcr(struct ti_port *tport, unsigned int mcr);
    static int ti_get_lsr(struct ti_port *tport);
    static int ti_get_serial_info(struct ti_port *tport,
    struct serial_struct __user *ret_arg);
    -static int ti_set_serial_info(struct ti_port *tport,
    +static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport,
    struct serial_struct __user *new_arg);
    static void ti_handle_new_msr(struct ti_port *tport, __u8 msr);

    @@ -857,8 +857,8 @@ static int ti_ioctl(struct tty_struct *tty, struct file *file,
    (struct serial_struct __user *)arg);
    case TIOCSSERIAL:
    dbg("%s - (%d) TIOCSSERIAL", __func__, port->number);
    - return ti_set_serial_info(tport,
    - (struct serial_struct __user *)arg);
    + return ti_set_serial_info(tty, tport,
    + (struct serial_struct __user *)arg);
    case TIOCMIWAIT:
    dbg("%s - (%d) TIOCMIWAIT", __func__, port->number);
    cprev = tport->tp_icount;
    @@ -1211,6 +1211,7 @@ static void ti_bulk_in_callback(struct urb *urb)
    struct device *dev = &urb->dev->dev;
    int status = urb->status;
    int retval = 0;
    + struct tty_struct *tty;

    dbg("%s", __func__);

    @@ -1239,20 +1240,22 @@ static void ti_bulk_in_callback(struct urb *urb)
    return;
    }

    - if (port->port.tty && urb->actual_length) {
    + tty = tty_port_tty_get(&port->port);
    + if (tty && urb->actual_length) {
    usb_serial_debug_data(debug, dev, __func__,
    urb->actual_length, urb->transfer_buffer);

    if (!tport->tp_is_open)
    dbg("%s - port closed, dropping data", __func__);
    else
    - ti_recv(&urb->dev->dev, port->port.tty,
    + ti_recv(&urb->dev->dev, tty,
    urb->transfer_buffer,
    urb->actual_length);

    spin_lock(&tport->tp_lock);
    tport->tp_icount.rx += urb->actual_length;
    spin_unlock(&tport->tp_lock);
    + tty_kref_put(tty);
    }

    exit:
    @@ -1330,7 +1333,7 @@ static void ti_send(struct ti_port *tport)
    {
    int count, result;
    struct usb_serial_port *port = tport->tp_port;
    - struct tty_struct *tty = port->port.tty; /* FIXME */
    + struct tty_struct *tty = tty_port_tty_get(&port->port); /* FIXME */
    unsigned long flags;


    @@ -1338,19 +1341,15 @@ static void ti_send(struct ti_port *tport)

    spin_lock_irqsave(&tport->tp_lock, flags);

    - if (tport->tp_write_urb_in_use) {
    - spin_unlock_irqrestore(&tport->tp_lock, flags);
    - return;
    - }
    + if (tport->tp_write_urb_in_use)
    + goto unlock;

    count = ti_buf_get(tport->tp_write_buf,
    port->write_urb->transfer_buffer,
    port->bulk_out_size);

    - if (count == 0) {
    - spin_unlock_irqrestore(&tport->tp_lock, flags);
    - return;
    - }
    + if (count == 0)
    + goto unlock;

    tport->tp_write_urb_in_use = 1;

    @@ -1380,7 +1379,13 @@ static void ti_send(struct ti_port *tport)
    /* more room in the buffer for new writes, wakeup */
    if (tty)
    tty_wakeup(tty);
    + tty_kref_put(tty);
    wake_up_interruptible(&tport->tp_write_wait);
    + return;
    +unlock:
    + spin_unlock_irqrestore(&tport->tp_lock, flags);
    + tty_kref_put(tty);
    + return;
    }


    @@ -1464,20 +1469,16 @@ static int ti_get_serial_info(struct ti_port *tport,
    }


    -static int ti_set_serial_info(struct ti_port *tport,
    +static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport,
    struct serial_struct __user *new_arg)
    {
    - struct usb_serial_port *port = tport->tp_port;
    struct serial_struct new_serial;

    if (copy_from_user(&new_serial, new_arg, sizeof(new_serial)))
    return -EFAULT;

    tport->tp_flags = new_serial.flags & TI_SET_SERIAL_FLAGS;
    - /* FIXME */
    - if (port->port.tty)
    - port->port.tty->low_latency =
    - (tport->tp_flags & ASYNC_LOW_LATENCY) ? 1 : 0;
    + tty->low_latency = (tport->tp_flags & ASYNC_LOW_LATENCY) ? 1 : 0;
    tport->tp_closing_wait = new_serial.closing_wait;

    return 0;
    @@ -1510,7 +1511,7 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr)
    tport->tp_msr = msr & TI_MSR_MASK;

    /* handle CTS flow control */
    - tty = tport->tp_port->port.tty;
    + tty = tty_port_tty_get(&tport->tp_port->port);
    if (tty && C_CRTSCTS(tty)) {
    if (msr & TI_MSR_CTS) {
    tty->hw_stopped = 0;
    @@ -1519,6 +1520,7 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr)
    tty->hw_stopped = 1;
    }
    }
    + tty_kref_put(tty);
    }


    diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
    index 4f7f9e3..e7d4246 100644
    --- a/drivers/usb/serial/usb-serial.c
    +++ b/drivers/usb/serial/usb-serial.c
    @@ -214,7 +214,7 @@ static int serial_open (struct tty_struct *tty, struct file *filp)
    /* set up our port structure making the tty driver
    * remember our port object, and us it */
    tty->driver_data = port;
    - port->port.tty = tty;
    + tty_port_tty_set(&port->port, tty);

    if (port->port.count == 1) {

    @@ -246,7 +246,7 @@ bailout_module_put:
    bailout_mutex_unlock:
    port->port.count = 0;
    tty->driver_data = NULL;
    - port->port.tty = NULL;
    + tty_port_tty_set(&port->port, NULL);
    mutex_unlock(&port->mutex);
    bailout_kref_put:
    usb_serial_put(serial);
    @@ -276,10 +276,11 @@ static void serial_close(struct tty_struct *tty, struct file *filp)
    port->serial->type->close(tty, port, filp);

    if (port->port.count == (port->console? 1 : 0)) {
    - if (port->port.tty) {
    - if (port->port.tty->driver_data)
    - port->port.tty->driver_data = NULL;
    - port->port.tty = NULL;
    + struct tty_struct *tty = tty_port_tty_get(&port->port);
    + if (tty) {
    + if (tty->driver_data)
    + tty->driver_data = NULL;
    + tty_port_tty_set(&port->port, NULL);
    }
    }

    @@ -508,11 +509,12 @@ static void usb_serial_port_work(struct work_struct *work)
    if (!port)
    return;

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

    tty_wakeup(tty);
    + tty_kref_put(tty);
    }

    static void port_release(struct device *dev)
    @@ -819,6 +821,7 @@ int usb_serial_probe(struct usb_interface *interface,
    port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
    if (!port)
    goto probe_error;
    + tty_port_init(&port->port);
    port->serial = serial;
    spin_lock_init(&port->lock);
    mutex_init(&port->mutex);
    @@ -1040,8 +1043,11 @@ void usb_serial_disconnect(struct usb_interface *interface)
    for (i = 0; i < serial->num_ports; ++i) {
    port = serial->port[i];
    if (port) {
    - if (port->port.tty)
    - tty_hangup(port->port.tty);
    + struct tty_struct *tty = tty_port_tty_get(&port->port);
    + if (tty) {
    + tty_hangup(tty);
    + tty_kref_put(tty);
    + }
    kill_traffic(port);
    }
    }
    diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
    index cf8924f..a6d1c75 100644
    --- a/drivers/usb/serial/visor.c
    +++ b/drivers/usb/serial/visor.c
    @@ -499,7 +499,7 @@ static void visor_read_bulk_callback(struct urb *urb)
    int status = urb->status;
    struct tty_struct *tty;
    int result;
    - int available_room;
    + int available_room = 0;

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

    @@ -512,13 +512,17 @@ static void visor_read_bulk_callback(struct urb *urb)
    usb_serial_debug_data(debug, &port->dev, __func__,
    urb->actual_length, data);

    - tty = port->port.tty;
    - if (tty && urb->actual_length) {
    - available_room = tty_buffer_request_room(tty,
    + if (urb->actual_length) {
    + tty = tty_port_tty_get(&port->port);
    + if (tty) {
    + available_room = tty_buffer_request_room(tty,
    urb->actual_length);
    - if (available_room) {
    - tty_insert_flip_string(tty, data, available_room);
    - tty_flip_buffer_push(tty);
    + if (available_room) {
    + tty_insert_flip_string(tty, data,
    + available_room);
    + tty_flip_buffer_push(tty);
    + }
    + tty_kref_put(tty);
    }
    spin_lock(&priv->lock);
    priv->bytes_in += available_room;
    diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
    index 3a9d143..11c8b97 100644
    --- a/drivers/usb/serial/whiteheat.c
    +++ b/drivers/usb/serial/whiteheat.c
    @@ -1481,7 +1481,7 @@ static void rx_data_softint(struct work_struct *work)
    struct whiteheat_private *info =
    container_of(work, struct whiteheat_private, rx_work);
    struct usb_serial_port *port = info->port;
    - struct tty_struct *tty = port->port.tty;
    + struct tty_struct *tty = tty_port_tty_get(&port->port);
    struct whiteheat_urb_wrap *wrap;
    struct urb *urb;
    unsigned long flags;
    @@ -1493,7 +1493,7 @@ static void rx_data_softint(struct work_struct *work)
    spin_lock_irqsave(&info->lock, flags);
    if (info->flags & THROTTLED) {
    spin_unlock_irqrestore(&info->lock, flags);
    - return;
    + goto out;
    }

    list_for_each_safe(tmp, tmp2, &info->rx_urb_q) {
    @@ -1513,7 +1513,7 @@ static void rx_data_softint(struct work_struct *work)
    spin_unlock_irqrestore(&info->lock, flags);
    tty_flip_buffer_push(tty);
    schedule_work(&info->rx_work);
    - return;
    + goto out;
    }
    tty_insert_flip_string(tty, urb->transfer_buffer, len);
    sent += len;
    @@ -1536,6 +1536,8 @@ static void rx_data_softint(struct work_struct *work)

    if (sent)
    tty_flip_buffer_push(tty);
    +out:
    + tty_kref_put(tty);
    }


    diff --git a/include/linux/tty.h b/include/linux/tty.h
    index b64d10b..c30ed8d 100644
    --- a/include/linux/tty.h
    +++ b/include/linux/tty.h
    @@ -182,6 +182,7 @@ struct signal_struct;

    struct tty_port {
    struct tty_struct *tty; /* Back pointer */
    + spinlock_t lock; /* Lock protecting tty field */
    int blocked_open; /* Waiting to open */
    int count; /* Usage count */
    wait_queue_head_t open_wait; /* Open waiters */
    @@ -405,6 +406,8 @@ extern int tty_write_lock(struct tty_struct *tty, int ndelay);
    extern void tty_port_init(struct tty_port *port);
    extern int tty_port_alloc_xmit_buf(struct tty_port *port);
    extern void tty_port_free_xmit_buf(struct tty_port *port);
    +extern struct tty_struct *tty_port_tty_get(struct tty_port *port);
    +extern void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty);

    extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc);
    extern int tty_unregister_ldisc(int disc);

    --
    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 53/80] tty: shutdown method

    From: Alan Cox

    Right now there are various drivers that try to use tty->count to know when
    they get the final close. Aristeau Rozanski showed while debugging the vt
    sysfs race that this isn't entirely safe.

    Instead of driver side tricks to work around this introduce a shutdown which
    is called when the tty is being destructed. This also means that the shutdown
    method is tied into the refcounting.

    Use this to rework the console close/sysfs logic.

    Remove lots of special case code from the tty core code. The pty code can now
    have a shutdown() method that replaces the special case hackery in the tree
    free up paths.

    Signed-off-by: Alan Cox
    ---

    drivers/char/pty.c | 15 ++++++++++---
    drivers/char/tty_io.c | 49 ++++++++++++++++++++++++++------------------
    drivers/char/vt.c | 34 +++++++++++++++----------------
    include/linux/tty.h | 3 ++-
    include/linux/tty_driver.h | 6 +++++
    5 files changed, 65 insertions(+), 42 deletions(-)


    diff --git a/drivers/char/pty.c b/drivers/char/pty.c
    index 76b2793..ec09c1c 100644
    --- a/drivers/char/pty.c
    +++ b/drivers/char/pty.c
    @@ -388,7 +388,14 @@ static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file,
    return -ENOIOCTLCMD;
    }

    -static const struct tty_operations pty_unix98_ops = {
    +static void pty_shutdown(struct tty_struct *tty)
    +{
    + /* We have our own method as we don't use the tty index */
    + kfree(tty->termios);
    + kfree(tty->termios_locked);
    +}
    +
    +static const struct tty_operations ptm_unix98_ops = {
    .open = pty_open,
    .close = pty_close,
    .write = pty_write,
    @@ -397,10 +404,10 @@ static const struct tty_operations pty_unix98_ops = {
    .chars_in_buffer = pty_chars_in_buffer,
    .unthrottle = pty_unthrottle,
    .set_termios = pty_set_termios,
    - .ioctl = pty_unix98_ioctl
    + .ioctl = pty_unix98_ioctl,
    + .shutdown = pty_shutdown
    };

    -
    static void __init unix98_pty_init(void)
    {
    ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
    @@ -427,7 +434,7 @@ static void __init unix98_pty_init(void)
    ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
    TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
    ptm_driver->other = pts_driver;
    - tty_set_operations(ptm_driver, &pty_unix98_ops);
    + tty_set_operations(ptm_driver, &ptm_unix98_ops);

    pts_driver->owner = THIS_MODULE;
    pts_driver->driver_name = "pty_slave";
    diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
    index 2e96ce0..f91704d 100644
    --- a/drivers/char/tty_io.c
    +++ b/drivers/char/tty_io.c
    @@ -1482,6 +1482,31 @@ release_mem_out:
    goto end_init;
    }

    +void tty_free_termios(struct tty_struct *tty)
    +{
    + struct ktermios *tp;
    + int idx = tty->index;
    + /* Kill this flag and push into drivers for locking etc */
    + if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
    + /* FIXME: Locking on ->termios array */
    + tp = tty->termios;
    + tty->driver->termios[idx] = NULL;
    + kfree(tp);
    +
    + tp = tty->termios_locked;
    + tty->driver->termios_locked[idx] = NULL;
    + kfree(tp);
    + }
    +}
    +EXPORT_SYMBOL(tty_free_termios);
    +
    +void tty_shutdown(struct tty_struct *tty)
    +{
    + tty->driver->ttys[tty->index] = NULL;
    + tty_free_termios(tty);
    +}
    +EXPORT_SYMBOL(tty_shutdown);
    +
    /**
    * release_one_tty - release tty structure memory
    * @kref: kref of tty we are obliterating
    @@ -1499,27 +1524,11 @@ 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;
    -
    - if (!devpts)
    - tty->driver->ttys[idx] = NULL;
    -
    - if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
    - /* FIXME: Locking on ->termios array */
    - tp = tty->termios;
    - if (!devpts)
    - tty->driver->termios[idx] = NULL;
    - kfree(tp);
    -
    - tp = tty->termios_locked;
    - if (!devpts)
    - tty->driver->termios_locked[idx] = NULL;
    - kfree(tp);
    - }
    -

    + if (tty->ops->shutdown)
    + tty->ops->shutdown(tty);
    + else
    + tty_shutdown(tty);
    tty->magic = 0;
    /* FIXME: locking on tty->driver->refcount */
    tty->driver->refcount--;
    diff --git a/drivers/char/vt.c b/drivers/char/vt.c
    index ec94521..37a45db 100644
    --- a/drivers/char/vt.c
    +++ b/drivers/char/vt.c
    @@ -2758,6 +2758,12 @@ static int con_open(struct tty_struct *tty, struct file *filp)
    ret = vc_allocate(currcons);
    if (ret == 0) {
    struct vc_data *vc = vc_cons[currcons].d;
    +
    + /* Still being freed */
    + if (vc->vc_tty) {
    + release_console_sem();
    + return -ERESTARTSYS;
    + }
    tty->driver_data = vc;
    vc->vc_tty = tty;

    @@ -2787,25 +2793,18 @@ static int con_open(struct tty_struct *tty, struct file *filp)
    */
    static void con_close(struct tty_struct *tty, struct file *filp)
    {
    - mutex_lock(&tty_mutex);
    - acquire_console_sem();
    - if (tty && tty->count == 1) {
    - struct vc_data *vc = tty->driver_data;
    + /* Nothing to do - we defer to shutdown */
    +}

    - if (vc)
    - vc->vc_tty = NULL;
    - tty->driver_data = NULL;
    - vcs_remove_sysfs(tty);
    - release_console_sem();
    - mutex_unlock(&tty_mutex);
    - /*
    - * tty_mutex is released, but we still hold BKL, so there is
    - * still exclusion against init_dev()
    - */
    - return;
    - }
    +static void con_shutdown(struct tty_struct *tty)
    +{
    + struct vc_data *vc = tty->driver_data;
    + BUG_ON(vc == NULL);
    + acquire_console_sem();
    + vc->vc_tty = NULL;
    + vcs_remove_sysfs(tty);
    release_console_sem();
    - mutex_unlock(&tty_mutex);
    + tty_shutdown(tty);
    }

    static int default_italic_color = 2; // green (ASCII)
    @@ -2930,6 +2929,7 @@ static const struct tty_operations con_ops = {
    .throttle = con_throttle,
    .unthrottle = con_unthrottle,
    .resize = vt_resize,
    + .shutdown = con_shutdown
    };

    int __init vty_init(void)
    diff --git a/include/linux/tty.h b/include/linux/tty.h
    index e00393a..6e39c70 100644
    --- a/include/linux/tty.h
    +++ b/include/linux/tty.h
    @@ -354,7 +354,8 @@ extern void tty_throttle(struct tty_struct *tty);
    extern void tty_unthrottle(struct tty_struct *tty);
    extern int tty_do_resize(struct tty_struct *tty, struct tty_struct *real_tty,
    struct winsize *ws);
    -
    +extern void tty_shutdown(struct tty_struct *tty);
    +extern void tty_free_termios(struct tty_struct *tty);
    extern int is_current_pgrp_orphaned(void);
    extern struct pid *tty_get_pgrp(struct tty_struct *tty);
    extern int is_ignored(int sig);
    diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
    index ac6e58e..2322313 100644
    --- a/include/linux/tty_driver.h
    +++ b/include/linux/tty_driver.h
    @@ -21,6 +21,11 @@
    *
    * Required method.
    *
    + * void (*shutdown)(struct tty_struct * tty);
    + *
    + * This routine is called when a particular tty device is closed for
    + * the last time freeing up the resources.
    + *
    * int (*write)(struct tty_struct * tty,
    * const unsigned char *buf, int count);
    *
    @@ -200,6 +205,7 @@ struct tty_driver;
    struct tty_operations {
    int (*open)(struct tty_struct * tty, struct file * filp);
    void (*close)(struct tty_struct * tty, struct file * filp);
    + void (*shutdown)(struct tty_struct *tty);
    int (*write)(struct tty_struct * tty,
    const unsigned char *buf, int count);
    int (*put_char)(struct tty_struct *tty, unsigned char ch);

    --
    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 52/80] vt: remove bogus lock dropping

    From: Alan Cox

    For hysterical raisins the vt layer drops and retakes locks in the write
    method. This is a left over from the days when user/kernel data was passed
    directly to the tty not pre-buffered.

    Signed-off-by: Alan Cox
    ---

    drivers/char/vt.c | 18 ------------------
    1 files changed, 0 insertions(+), 18 deletions(-)


    diff --git a/drivers/char/vt.c b/drivers/char/vt.c
    index 05ca1c5..ec94521 100644
    --- a/drivers/char/vt.c
    +++ b/drivers/char/vt.c
    @@ -2136,27 +2136,9 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
    release_console_sem();
    return 0;
    }
    - release_console_sem();
    -
    orig_buf = buf;
    orig_count = count;

    - /* At this point 'buf' is guaranteed to be a kernel buffer
    - * and therefore no access to userspace (and therefore sleeping)
    - * will be needed. The con_buf_mtx serializes all tty based
    - * console rendering and vcs write/read operations. We hold
    - * the console spinlock during the entire write.
    - */
    -
    - acquire_console_sem();
    -
    - vc = tty->driver_data;
    - if (vc == NULL) {
    - printk(KERN_ERR "vt: argh, driver_data _became_ NULL !\n");
    - release_console_sem();
    - goto out;
    - }
    -
    himask = vc->vc_hi_font_mask;
    charmask = himask ? 0x1ff : 0xff;


    --
    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 65/80] Simplify devpts_pty_kill

    From: Sukadev Bhattiprolu

    When creating a new pty, save the pty's inode in the tty->driver_data.
    Use this inode in pty_kill() to identify the devpts instance. Since
    we now have the inode for the pty, we can skip get_node() lookup and
    remove the unused get_node().

    TODO:
    - check if the mutex_lock is needed in pty_kill().

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

    fs/devpts/inode.c | 29 ++++++++++++-----------------
    1 files changed, 12 insertions(+), 17 deletions(-)


    diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
    index 50e885f..a70d5d0 100644
    --- a/fs/devpts/inode.c
    +++ b/fs/devpts/inode.c
    @@ -170,14 +170,6 @@ static struct file_system_type devpts_fs_type = {
    * to the System V naming convention
    */

    -static struct dentry *get_node(int num)
    -{
    - char s[12];
    - struct dentry *root = devpts_root;
    - mutex_lock(&root->d_inode->i_mutex);
    - return lookup_one_len(s, root, sprintf(s, "%d", num));
    -}
    -
    int devpts_new_index(struct inode *ptmx_inode)
    {
    int index;
    @@ -235,6 +227,7 @@ int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty)
    inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
    init_special_inode(inode, S_IFCHR|config.mode, device);
    inode->i_private = tty;
    + tty->driver_data = inode;

    sprintf(s, "%d", number);

    @@ -262,18 +255,20 @@ struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number)

    void devpts_pty_kill(struct tty_struct *tty)
    {
    - int number = tty->index;
    - struct dentry *dentry = get_node(number);
    + struct inode *inode = tty->driver_data;
    + struct dentry *dentry;

    - if (!IS_ERR(dentry)) {
    - struct inode *inode = dentry->d_inode;
    - if (inode) {
    - inode->i_nlink--;
    - d_delete(dentry);
    - dput(dentry);
    - }
    + BUG_ON(inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR));
    +
    + mutex_lock(&devpts_root->d_inode->i_mutex);
    +
    + dentry = d_find_alias(inode);
    + if (dentry && !IS_ERR(dentry)) {
    + inode->i_nlink--;
    + d_delete(dentry);
    dput(dentry);
    }
    +
    mutex_unlock(&devpts_root->d_inode->i_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/

  12. [PATCH 72/80] tty: fix up gigaset a bit

    From: Alan Cox

    Stephen's fixes reminded me that gigaset is still rather broken so fix it up
    a bit

    Signed-off-by: Alan Cox
    ---

    drivers/isdn/gigaset/ser-gigaset.c | 27 ++++++++++++---------------
    1 files changed, 12 insertions(+), 15 deletions(-)


    diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c
    index cc4f4e4..07052ed 100644
    --- a/drivers/isdn/gigaset/ser-gigaset.c
    +++ b/drivers/isdn/gigaset/ser-gigaset.c
    @@ -571,6 +571,7 @@ gigaset_tty_close(struct tty_struct *tty)
    }

    /* prevent other callers from entering ldisc methods */
    + /* FIXME: should use the tty state flags */
    tty->disc_data = NULL;

    if (!cs->hw.ser)
    @@ -642,10 +643,11 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file,
    return -ENXIO;

    switch (cmd) {
    - case TCGETS:
    - case TCGETA:
    - /* pass through to underlying serial device */
    - rc = n_tty_ioctl_helper(tty, file, cmd, arg);
    +
    + case FIONREAD:
    + /* unused, always return zero */
    + val = 0;
    + rc = put_user(val, p);
    break;

    case TCFLSH:
    @@ -659,20 +661,13 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file,
    flush_send_queue(cs);
    break;
    }
    - /* flush the serial port's buffer */
    - rc = n_tty_ioctl_helper(tty, file, cmd, arg);
    - break;
    -
    - case FIONREAD:
    - /* unused, always return zero */
    - val = 0;
    - rc = put_user(val, p);
    - break;
    + /* Pass through */

    default:
    - rc = -ENOIOCTLCMD;
    + /* pass through to underlying serial device */
    + rc = n_tty_ioctl_helper(tty, file, cmd, arg);
    + break;
    }
    -
    cs_put(cs);
    return rc;
    }
    @@ -680,6 +675,8 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file,
    /*
    * Poll on the tty.
    * Unused, always return zero.
    + *
    + * FIXME: should probably return an exception - especially on hangup
    */
    static unsigned int
    gigaset_tty_poll(struct tty_struct *tty, struct file *file, poll_table *wait)

    --
    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 66/80] pty: Coding style and polish

    From: Alan Cox

    We've done the heavy lifting now its time to mop up a bit

    Signed-off-by: Alan Cox
    ---

    drivers/char/pty.c | 86 +++++++++++++++++++++++++++-------------------------
    1 files changed, 44 insertions(+), 42 deletions(-)


    diff --git a/drivers/char/pty.c b/drivers/char/pty.c
    index a391bad..c3ab8c3 100644
    --- a/drivers/char/pty.c
    +++ b/drivers/char/pty.c
    @@ -8,10 +8,12 @@
    * Added TTY_DO_WRITE_WAKEUP to enable n_tty to send POLL_OUT to
    * waiting writers -- Sapan Bhatia
    *
    - *
    + * When reading this code see also fs/devpts. In particular note that the
    + * driver_data field is used by the devpts side as a binding to the devpts
    + * inode.
    */

    -#include /* For EXPORT_SYMBOL */
    +#include

    #include
    #include
    @@ -24,26 +26,24 @@
    #include
    #include
    #include
    -
    -#include
    -#include
    +#include
    #include
    #include

    +#include
    +
    /* These are global because they are accessed in tty_io.c */
    #ifdef CONFIG_UNIX98_PTYS
    struct tty_driver *ptm_driver;
    static struct tty_driver *pts_driver;
    #endif

    -static void pty_close(struct tty_struct * tty, struct file * filp)
    +static void pty_close(struct tty_struct *tty, struct file *filp)
    {
    - if (!tty)
    - return;
    - if (tty->driver->subtype == PTY_TYPE_MASTER) {
    - if (tty->count > 1)
    - printk("master pty_close: count = %d!!\n", tty->count);
    - } else {
    + BUG_ON(!tty);
    + if (tty->driver->subtype == PTY_TYPE_MASTER)
    + WARN_ON(tty->count > 1);
    + else {
    if (tty->count > 2)
    return;
    }
    @@ -70,13 +70,13 @@ static void pty_close(struct tty_struct * tty, struct file * filp)
    * The unthrottle routine is called by the line discipline to signal
    * that it can receive more characters. For PTY's, the TTY_THROTTLED
    * flag is always set, to force the line discipline to always call the
    - * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE
    + * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE
    * characters in the queue. This is necessary since each time this
    * happens, we need to wake up any sleeping processes that could be
    * (1) trying to send data to the pty, or (2) waiting in wait_until_sent()
    * for the pty buffer to be drained.
    */
    -static void pty_unthrottle(struct tty_struct * tty)
    +static void pty_unthrottle(struct tty_struct *tty)
    {
    struct tty_struct *o_tty = tty->link;

    @@ -88,7 +88,7 @@ static void pty_unthrottle(struct tty_struct * tty)
    }

    /*
    - * WSH 05/24/97: modified to
    + * WSH 05/24/97: modified to
    * (1) use space in tty->flip instead of a shared temp buffer
    * The flip buffers aren't being used for a pty, so there's lots
    * of space available. The buffer is protected by a per-pty
    @@ -101,7 +101,8 @@ static void pty_unthrottle(struct tty_struct * tty)
    * not our partners. We can't just take the other one blindly without
    * risking deadlocks.
    */
    -static int pty_write(struct tty_struct * tty, const unsigned char *buf, int count)
    +static int pty_write(struct tty_struct *tty, const unsigned char *buf,
    + int count)
    {
    struct tty_struct *to = tty->link;
    int c;
    @@ -113,7 +114,7 @@ static int pty_write(struct tty_struct * tty, const unsigned char *buf, int coun
    if (c > count)
    c = count;
    to->ldisc.ops->receive_buf(to, buf, NULL, c);
    -
    +
    return c;
    }

    @@ -129,17 +130,17 @@ static int pty_write_room(struct tty_struct *tty)

    /*
    * WSH 05/24/97: Modified for asymmetric MASTER/SLAVE behavior
    - * The chars_in_buffer() value is used by the ldisc select() function
    + * The chars_in_buffer() value is used by the ldisc select() function
    * to hold off writing when chars_in_buffer > WAKEUP_CHARS (== 256).
    * The pty driver chars_in_buffer() Master/Slave must behave differently:
    *
    * The Master side needs to allow typed-ahead commands to accumulate
    * while being canonicalized, so we report "our buffer" as empty until
    * some threshold is reached, and then report the count. (Any count >
    - * WAKEUP_CHARS is regarded by select() as "full".) To avoid deadlock
    - * the count returned must be 0 if no canonical data is available to be
    + * WAKEUP_CHARS is regarded by select() as "full".) To avoid deadlock
    + * the count returned must be 0 if no canonical data is available to be
    * read. (The N_TTY ldisc.chars_in_buffer now knows this.)
    - *
    + *
    * The Slave side passes all characters in raw mode to the Master side's
    * buffer where they can be read immediately, so in this case we can
    * return the true count in the buffer.
    @@ -156,21 +157,22 @@ static int pty_chars_in_buffer(struct tty_struct *tty)
    /* The ldisc must report 0 if no characters available to be read */
    count = to->ldisc.ops->chars_in_buffer(to);

    - if (tty->driver->subtype == PTY_TYPE_SLAVE) return count;
    + if (tty->driver->subtype == PTY_TYPE_SLAVE)
    + return count;

    - /* Master side driver ... if the other side's read buffer is less than
    + /* Master side driver ... if the other side's read buffer is less than
    * half full, return 0 to allow writers to proceed; otherwise return
    - * the count. This leaves a comfortable margin to avoid overflow,
    + * the count. This leaves a comfortable margin to avoid overflow,
    * and still allows half a buffer's worth of typed-ahead commands.
    */
    - return ((count < N_TTY_BUF_SIZE/2) ? 0 : count);
    + return (count < N_TTY_BUF_SIZE/2) ? 0 : count;
    }

    /* Set the lock flag on a pty */
    -static int pty_set_lock(struct tty_struct *tty, int __user * arg)
    +static int pty_set_lock(struct tty_struct *tty, int __user *arg)
    {
    int val;
    - if (get_user(val,arg))
    + if (get_user(val, arg))
    return -EFAULT;
    if (val)
    set_bit(TTY_PTY_LOCK, &tty->flags);
    @@ -183,13 +185,13 @@ static void pty_flush_buffer(struct tty_struct *tty)
    {
    struct tty_struct *to = tty->link;
    unsigned long flags;
    -
    +
    if (!to)
    return;
    -
    +
    if (to->ldisc.ops->flush_buffer)
    to->ldisc.ops->flush_buffer(to);
    -
    +
    if (to->packet) {
    spin_lock_irqsave(&tty->ctrl_lock, flags);
    tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
    @@ -198,7 +200,7 @@ static void pty_flush_buffer(struct tty_struct *tty)
    }
    }

    -static int pty_open(struct tty_struct *tty, struct file * filp)
    +static int pty_open(struct tty_struct *tty, struct file *filp)
    {
    int retval = -ENODEV;

    @@ -221,10 +223,11 @@ out:
    return retval;
    }

    -static void pty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
    +static void pty_set_termios(struct tty_struct *tty,
    + struct ktermios *old_termios)
    {
    - tty->termios->c_cflag &= ~(CSIZE | PARENB);
    - tty->termios->c_cflag |= (CS8 | CREAD);
    + tty->termios->c_cflag &= ~(CSIZE | PARENB);
    + tty->termios->c_cflag |= (CS8 | CREAD);
    }

    static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
    @@ -254,7 +257,7 @@ static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
    tty_free_termios(tty);
    goto free_mem_out;
    }
    -
    +
    /*
    * Everything allocated ... set up the o_tty structure.
    */
    @@ -381,9 +384,9 @@ static inline void legacy_pty_init(void) { }
    * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly.
    */
    int pty_limit = NR_UNIX98_PTY_DEFAULT;
    -static int pty_limit_min = 0;
    +static int pty_limit_min;
    static int pty_limit_max = NR_UNIX98_PTY_MAX;
    -static int pty_count = 0;
    +static int pty_count;

    static struct cdev ptmx_cdev;

    @@ -537,11 +540,10 @@ static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
    pty_count++;
    return 0;
    free_mem_out:
    - kfree(o_tty->termios);
    + pty_unix98_shutdown(o_tty);
    module_put(o_tty->driver->owner);
    free_tty_struct(o_tty);
    - kfree(tty->termios_locked);
    - kfree(tty->termios);
    + pty_unix98_shutdown(tty);
    free_tty_struct(tty);
    module_put(driver->owner);
    return -ENOMEM;
    @@ -691,13 +693,13 @@ static void __init unix98_pty_init(void)
    TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
    pts_driver->other = ptm_driver;
    tty_set_operations(pts_driver, &pty_unix98_ops);
    -
    +
    if (tty_register_driver(ptm_driver))
    panic("Couldn't register Unix98 ptm driver");
    if (tty_register_driver(pts_driver))
    panic("Couldn't register Unix98 pts driver");

    - register_sysctl_table(pty_root_table);
    + register_sysctl_table(pty_root_table);

    /* Now create the /dev/ptmx special device */
    tty_default_fops(&ptmx_fops);

    --
    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 77/80] tty: tty_io.c shadows sparse fix

    From: Jason Wessel

    drivers/char/tty_io.c:1413:17: warning: symbol 'buf' shadows an earlier one
    drivers/char/tty_io.c:1379:20: originally declared here

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

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


    diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
    index 502cad6..7053d63 100644
    --- a/drivers/char/tty_io.c
    +++ b/drivers/char/tty_io.c
    @@ -1026,19 +1026,19 @@ static inline ssize_t do_tty_write(

    /* write_buf/write_cnt is protected by the atomic_write_lock mutex */
    if (tty->write_cnt < chunk) {
    - unsigned char *buf;
    + unsigned char *buf_chunk;

    if (chunk < 1024)
    chunk = 1024;

    - buf = kmalloc(chunk, GFP_KERNEL);
    - if (!buf) {
    + buf_chunk = kmalloc(chunk, GFP_KERNEL);
    + if (!buf_chunk) {
    ret = -ENOMEM;
    goto out;
    }
    kfree(tty->write_buf);
    tty->write_cnt = chunk;
    - tty->write_buf = buf;
    + tty->write_buf = buf_chunk;
    }

    /* Do the write .. */

    --
    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 76/80] serial: fix device name reporting when minor space is shared between drivers

    From: David S. Miller

    The multiple drivers share the minor space occupied by a particular major
    number, the actual index within the device name's space is indicated by
    the tty_driver->name_base + uart_port->line

    Another usable formula is (uart_driver->minor - MINOR_BASE) + port->line

    Use those to print the device names properly in such situations in
    serial_core.c and 8250.c

    Signed-off-by: David S. Miller
    Signed-off-by: Andrew Morton
    Signed-off-by: Alan Cox
    ---

    drivers/serial/8250.c | 22 +++++++++++++++-------
    drivers/serial/serial_core.c | 7 +++++--
    2 files changed, 20 insertions(+), 9 deletions(-)


    diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
    index db2cdc1..d4104a3 100644
    --- a/drivers/serial/8250.c
    +++ b/drivers/serial/8250.c
    @@ -57,6 +57,13 @@ static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;

    static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS;

    +static struct uart_driver serial8250_reg;
    +
    +static int serial_index(struct uart_port *port)
    +{
    + return (serial8250_reg.minor - 64) + port->line;
    +}
    +
    /*
    * Debugging.
    */
    @@ -997,7 +1004,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
    return;

    DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04x, 0x%p): ",
    - up->port.line, up->port.iobase, up->port.membase);
    + serial_index(&up->port), up->port.iobase, up->port.membase);

    /*
    * We really do need global IRQs disabled here - we're going to
    @@ -1132,8 +1139,8 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
    if (up->capabilities != uart_config[up->port.type].flags) {
    printk(KERN_WARNING
    "ttyS%d: detected caps %08x should be %08x\n",
    - up->port.line, up->capabilities,
    - uart_config[up->port.type].flags);
    + serial_index(&up->port), up->capabilities,
    + uart_config[up->port.type].flags);
    }

    up->port.fifosize = uart_config[up->port.type].fifo_size;
    @@ -1857,7 +1864,8 @@ static int serial8250_startup(struct uart_port *port)
    */
    if (!(up->port.flags & UPF_BUGGY_UART) &&
    (serial_inp(up, UART_LSR) == 0xff)) {
    - printk("ttyS%d: LSR safety check engaged!\n", up->port.line);
    + printk(KERN_INFO "ttyS%d: LSR safety check engaged!\n",
    + serial_index(&up->port));
    return -ENODEV;
    }

    @@ -1912,7 +1920,8 @@ static int serial8250_startup(struct uart_port *port)
    */
    if (!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) {
    up->bugs |= UART_BUG_THRE;
    - pr_debug("ttyS%d - using backup timer\n", port->line);
    + pr_debug("ttyS%d - using backup timer\n",
    + serial_index(port));
    }
    }

    @@ -1972,7 +1981,7 @@ static int serial8250_startup(struct uart_port *port)
    if (!(up->bugs & UART_BUG_TXEN)) {
    up->bugs |= UART_BUG_TXEN;
    pr_debug("ttyS%d - enabling bad tx status workarounds\n",
    - port->line);
    + serial_index(port));
    }
    } else {
    up->bugs &= ~UART_BUG_TXEN;
    @@ -2633,7 +2642,6 @@ static int serial8250_console_early_setup(void)
    return serial8250_find_port_for_earlycon();
    }

    -static struct uart_driver serial8250_reg;
    static struct console serial8250_console = {
    .name = "ttyS",
    .write = serial8250_console_write,
    diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
    index 308588e..6bdf336 100644
    --- a/drivers/serial/serial_core.c
    +++ b/drivers/serial/serial_core.c
    @@ -2051,7 +2051,8 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
    "transmitter\n",
    port->dev ? port->dev->bus_id : "",
    port->dev ? ": " : "",
    - drv->dev_name, port->line);
    + drv->dev_name,
    + drv->tty_driver->name_base + port->line);

    ops->shutdown(port);
    }
    @@ -2176,7 +2177,9 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
    printk(KERN_INFO "%s%s%s%d at %s (irq = %d) is a %s\n",
    port->dev ? port->dev->bus_id : "",
    port->dev ? ": " : "",
    - drv->dev_name, port->line, address, port->irq, uart_type(port));
    + drv->dev_name,
    + drv->tty_driver->name_base + port->line,
    + address, port->irq, uart_type(port));
    }

    static void

    --
    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 71/80] tty: Fallout from tty-move-canon-specials

    From: Stephen Rothwell

    Hi Alan,

    Today's linux-next build (x86_64 allmodconfig) failed like this:

    /drivers/char/tty_ioctl.c: In function 'change_termios':
    drivers/isdn/capi/capi.c:1234: error: implicit declaration of function 'n_tty_ioctl'
    drivers/isdn/gigaset/ser-gigaset.c: In function 'gigaset_tty_ioctl':
    drivers/isdn/gigaset/ser-gigaset.c:648: error: implicit declaration of function 'n_tty_ioctl'

    Introduced by commit 686b5e4aea05a80e370dc931b7f4a8d03c80da54
    ("tty-move-canon-specials"). I added the following patch (which may not
    be correct).

    --
    Cheers,
    Stephen Rothwell sfr@canb.auug.org.au
    http://www.canb.auug.org.au/~sfr/

    Signed-off-by: Stephen Rothwell
    Signed-off-by: Alan Cox
    ---

    drivers/isdn/capi/capi.c | 2 +-
    drivers/isdn/gigaset/ser-gigaset.c | 4 ++--
    2 files changed, 3 insertions(+), 3 deletions(-)


    diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
    index 871b0cb..798d7f3 100644
    --- a/drivers/isdn/capi/capi.c
    +++ b/drivers/isdn/capi/capi.c
    @@ -1231,7 +1231,7 @@ static int capinc_tty_ioctl(struct tty_struct *tty, struct file * file,
    int error = 0;
    switch (cmd) {
    default:
    - error = n_tty_ioctl (tty, file, cmd, arg);
    + error = n_tty_ioctl_helper(tty, file, cmd, arg);
    break;
    }
    return error;
    diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c
    index 5e89fa1..cc4f4e4 100644
    --- a/drivers/isdn/gigaset/ser-gigaset.c
    +++ b/drivers/isdn/gigaset/ser-gigaset.c
    @@ -645,7 +645,7 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file,
    case TCGETS:
    case TCGETA:
    /* pass through to underlying serial device */
    - rc = n_tty_ioctl(tty, file, cmd, arg);
    + rc = n_tty_ioctl_helper(tty, file, cmd, arg);
    break;

    case TCFLSH:
    @@ -660,7 +660,7 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file,
    break;
    }
    /* flush the serial port's buffer */
    - rc = n_tty_ioctl(tty, file, cmd, arg);
    + rc = n_tty_ioctl_helper(tty, file, cmd, arg);
    break;

    case FIONREAD:

    --
    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 69/80] tty: simplify ktermios allocation

    From: Alan Cox

    Copy the simplification from the pty unix98 special case to the generic one.
    This allows us to kill off driver->termios_locked entirely which is nice. We
    have to whack bits of the cris driver as it meddles in places it shouldn't
    providing its own arrays that were never used anyway.

    Signed-off-by: Alan Cox
    ---

    drivers/char/tty_io.c | 46 +++++++---------------------------------------
    drivers/serial/crisv10.c | 3 ---
    2 files changed, 7 insertions(+), 42 deletions(-)


    diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
    index 9590839..502cad6 100644
    --- a/drivers/char/tty_io.c
    +++ b/drivers/char/tty_io.c
    @@ -1235,27 +1235,20 @@ struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,

    int tty_init_termios(struct tty_struct *tty)
    {
    - struct ktermios *tp, *ltp;
    + struct ktermios *tp;
    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);
    + tp = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
    + if (tp == NULL)
    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;
    + tty->termios_locked = tp + 1;

    /* Compatibility until drivers always set this */
    tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
    @@ -1439,10 +1432,6 @@ void tty_free_termios(struct tty_struct *tty)
    tp = tty->termios;
    tty->driver->termios[idx] = NULL;
    kfree(tp);
    -
    - tp = tty->termios_locked;
    - tty->driver->termios_locked[idx] = NULL;
    - kfree(tp);
    }
    }
    EXPORT_SYMBOL(tty_free_termios);
    @@ -1575,12 +1564,6 @@ void tty_release_dev(struct file *filp)
    idx, tty->name);
    return;
    }
    - if (tty->termios_locked != tty->driver->termios_locked[idx]) {
    - printk(KERN_DEBUG "tty_release_dev: driver.termios_locked[%d] not "
    - "termios_locked for (%s)\n",
    - idx, tty->name);
    - return;
    - }
    }
    #endif

    @@ -1604,13 +1587,6 @@ void tty_release_dev(struct file *filp)
    idx, tty->name);
    return;
    }
    - if (o_tty->termios_locked !=
    - tty->driver->other->termios_locked[idx]) {
    - printk(KERN_DEBUG "tty_release_dev: other->termios_locked["
    - "%d] not o_termios_locked for (%s)\n",
    - idx, tty->name);
    - return;
    - }
    if (o_tty->link != tty) {
    printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
    return;
    @@ -2930,18 +2906,13 @@ static void destruct_tty_driver(struct kref *kref)
    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;
    + driver->termios = NULL;
    kfree(p);
    cdev_del(&driver->cdev);
    }
    @@ -2978,7 +2949,7 @@ int tty_register_driver(struct tty_driver *driver)
    void **p = NULL;

    if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
    - p = kzalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL);
    + p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);
    if (!p)
    return -ENOMEM;
    }
    @@ -3002,12 +2973,9 @@ int tty_register_driver(struct tty_driver *driver)
    if (p) {
    driver->ttys = (struct tty_struct **)p;
    driver->termios = (struct ktermios **)(p + driver->num);
    - driver->termios_locked = (struct ktermios **)
    - (p + driver->num * 2);
    } else {
    driver->ttys = NULL;
    driver->termios = NULL;
    - driver->termios_locked = NULL;
    }

    cdev_init(&driver->cdev, &tty_fops);
    @@ -3016,7 +2984,7 @@ int tty_register_driver(struct tty_driver *driver)
    if (error) {
    unregister_chrdev_region(dev, driver->num);
    driver->ttys = NULL;
    - driver->termios = driver->termios_locked = NULL;
    + driver->termios = NULL;
    kfree(p);
    return error;
    }
    diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c
    index a467c77..211c217 100644
    --- a/drivers/serial/crisv10.c
    +++ b/drivers/serial/crisv10.c
    @@ -457,7 +457,6 @@ static struct e100_serial rs_table[] = {
    #define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial))

    static struct ktermios *serial_termios[NR_PORTS];
    -static struct ktermios *serial_termios_locked[NR_PORTS];
    #ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
    static struct fast_timer fast_timers[NR_PORTS];
    #endif
    @@ -4448,8 +4447,6 @@ rs_init(void)
    driver->init_termios.c_ispeed = 115200;
    driver->init_termios.c_ospeed = 115200;
    driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
    - driver->termios = serial_termios;
    - driver->termios_locked = serial_termios_locked;

    tty_set_operations(driver, &rs_ops);
    serial_driver = driver;

    --
    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 67/80] pty: Fix allocation failure double free

    From: Alan Cox

    The updating and moving around of the pty code added a bug where both the
    helper and caller free the main tty struct (the pty driver must free the
    o_tty pair itself however).

    Signed-off-by: Alan Cox
    ---

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


    diff --git a/drivers/char/pty.c b/drivers/char/pty.c
    index c3ab8c3..3c6b791 100644
    --- a/drivers/char/pty.c
    +++ b/drivers/char/pty.c
    @@ -544,8 +544,6 @@ free_mem_out:
    module_put(o_tty->driver->owner);
    free_tty_struct(o_tty);
    pty_unix98_shutdown(tty);
    - free_tty_struct(tty);
    - module_put(driver->owner);
    return -ENOMEM;
    }


    --
    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 73/80] tty: Remove lots of NULL checks

    From: Alan Cox

    Many tty drivers contain 'can't happen' checks against NULL pointers passed
    in by the tty layer. These have never been possible to occur. Even more
    importantly if they ever do occur we want to know as it would be a serious
    bug.

    Signed-off-by: Alan Cox
    ---

    drivers/char/amiserial.c | 6 ------
    drivers/char/generic_serial.c | 21 ---------------------
    drivers/char/istallion.c | 6 ------
    drivers/char/mxser.c | 5 -----
    drivers/char/n_r3964.c | 8 +-------
    drivers/char/stallion.c | 34 ----------------------------------
    6 files changed, 1 insertions(+), 79 deletions(-)


    diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
    index 6e763e3..98821f9 100644
    --- a/drivers/char/amiserial.c
    +++ b/drivers/char/amiserial.c
    @@ -837,9 +837,6 @@ static int rs_put_char(struct tty_struct *tty, unsigned char ch)
    struct async_struct *info;
    unsigned long flags;

    - if (!tty)
    - return 0;
    -
    info = tty->driver_data;

    if (serial_paranoia_check(info, tty->name, "rs_put_char"))
    @@ -892,9 +889,6 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count
    struct async_struct *info;
    unsigned long flags;

    - if (!tty)
    - return 0;
    -
    info = tty->driver_data;

    if (serial_paranoia_check(info, tty->name, "rs_write"))
    diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c
    index 19d3afb..c6090f8 100644
    --- a/drivers/char/generic_serial.c
    +++ b/drivers/char/generic_serial.c
    @@ -54,8 +54,6 @@ int gs_put_char(struct tty_struct * tty, unsigned char ch)

    func_enter ();

    - if (!tty) return 0;
    -
    port = tty->driver_data;

    if (!port) return 0;
    @@ -97,8 +95,6 @@ int gs_write(struct tty_struct * tty,

    func_enter ();

    - if (!tty) return 0;
    -
    port = tty->driver_data;

    if (!port) return 0;
    @@ -185,7 +181,6 @@ static int gs_real_chars_in_buffer(struct tty_struct *tty)
    struct gs_port *port;
    func_enter ();

    - if (!tty) return 0;
    port = tty->driver_data;

    if (!port->rd) return 0;
    @@ -274,8 +269,6 @@ void gs_flush_buffer(struct tty_struct *tty)

    func_enter ();

    - if (!tty) return;
    -
    port = tty->driver_data;

    if (!port) return;
    @@ -296,8 +289,6 @@ void gs_flush_chars(struct tty_struct * tty)

    func_enter ();

    - if (!tty) return;
    -
    port = tty->driver_data;

    if (!port) return;
    @@ -321,8 +312,6 @@ void gs_stop(struct tty_struct * tty)

    func_enter ();

    - if (!tty) return;
    -
    port = tty->driver_data;

    if (!port) return;
    @@ -341,8 +330,6 @@ void gs_start(struct tty_struct * tty)
    {
    struct gs_port *port;

    - if (!tty) return;
    -
    port = tty->driver_data;

    if (!port) return;
    @@ -393,8 +380,6 @@ void gs_hangup(struct tty_struct *tty)

    func_enter ();

    - if (!tty) return;
    -
    port = tty->driver_data;
    tty = port->port.tty;
    if (!tty)
    @@ -426,8 +411,6 @@ int gs_block_til_ready(void *port_, struct file * filp)

    tty = port->port.tty;

    - if (!tty) return 0;
    -
    gs_dprintk (GS_DEBUG_BTR, "Entering gs_block_till_ready.\n");
    /*
    * If the device is in the middle of being closed, then block
    @@ -523,8 +506,6 @@ void gs_close(struct tty_struct * tty, struct file * filp)

    func_enter ();

    - if (!tty) return;
    -
    port = (struct gs_port *) tty->driver_data;

    if (!port) return;
    @@ -621,8 +602,6 @@ void gs_set_termios (struct tty_struct * tty,

    func_enter();

    - if (!tty) return;
    -
    port = tty->driver_data;

    if (!port) return;
    diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
    index 96ee112..505d7a1 100644
    --- a/drivers/char/istallion.c
    +++ b/drivers/char/istallion.c
    @@ -1375,8 +1375,6 @@ static void stli_flushchars(struct tty_struct *tty)
    stli_txcookrealsize = 0;
    stli_txcooktty = NULL;

    - if (tty == NULL)
    - return;
    if (cooktty == NULL)
    return;
    if (tty != cooktty)
    @@ -1732,8 +1730,6 @@ static void stli_settermios(struct tty_struct *tty, struct ktermios *old)
    struct ktermios *tiosp;
    asyport_t aport;

    - if (tty == NULL)
    - return;
    portp = tty->driver_data;
    if (portp == NULL)
    return;
    @@ -1938,8 +1934,6 @@ static void stli_waituntilsent(struct tty_struct *tty, int timeout)
    struct stliport *portp;
    unsigned long tend;

    - if (tty == NULL)
    - return;
    portp = tty->driver_data;
    if (portp == NULL)
    return;
    diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
    index 308cb60..8beef50 100644
    --- a/drivers/char/mxser.c
    +++ b/drivers/char/mxser.c
    @@ -616,9 +616,6 @@ static int mxser_set_baud(struct tty_struct *tty, long newspd)
    int quot = 0, baud;
    unsigned char cval;

    - if (!tty->termios)
    - return -1;
    -
    if (!info->ioaddr)
    return -1;

    @@ -688,8 +685,6 @@ static int mxser_change_speed(struct tty_struct *tty,
    int ret = 0;
    unsigned char status;

    - if (!tty->termios)
    - return ret;
    cflag = tty->termios->c_cflag;
    if (!info->ioaddr)
    return ret;
    diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c
    index ae377aa..4a8215a 100644
    --- a/drivers/char/n_r3964.c
    +++ b/drivers/char/n_r3964.c
    @@ -372,14 +372,8 @@ static void remove_from_rx_queue(struct r3964_info *pInfo,
    static void put_char(struct r3964_info *pInfo, unsigned char ch)
    {
    struct tty_struct *tty = pInfo->tty;
    -
    - if (tty == NULL)
    - return;
    -
    /* FIXME: put_char should not be called from an IRQ */
    - if (tty->ops->put_char) {
    - tty->ops->put_char(tty, ch);
    - }
    + tty_put_char(tty, ch);
    pInfo->bcc ^= ch;
    }

    diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
    index 81b3234..8b8f07a 100644
    --- a/drivers/char/stallion.c
    +++ b/drivers/char/stallion.c
    @@ -849,8 +849,6 @@ static void stl_flushbuffer(struct tty_struct *tty)

    pr_debug("stl_flushbuffer(tty=%p)\n", tty);

    - if (tty == NULL)
    - return;
    portp = tty->driver_data;
    if (portp == NULL)
    return;
    @@ -868,8 +866,6 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout)

    pr_debug("stl_waituntilsent(tty=%p,timeout=%d)\n", tty, timeout);

    - if (tty == NULL)
    - return;
    portp = tty->driver_data;
    if (portp == NULL)
    return;
    @@ -1036,8 +1032,6 @@ static int stl_putchar(struct tty_struct *tty, unsigned char ch)

    pr_debug("stl_putchar(tty=%p,ch=%x)\n", tty, ch);

    - if (tty == NULL)
    - return -EINVAL;
    portp = tty->driver_data;
    if (portp == NULL)
    return -EINVAL;
    @@ -1073,8 +1067,6 @@ static void stl_flushchars(struct tty_struct *tty)

    pr_debug("stl_flushchars(tty=%p)\n", tty);

    - if (tty == NULL)
    - return;
    portp = tty->driver_data;
    if (portp == NULL)
    return;
    @@ -1093,8 +1085,6 @@ static int stl_writeroom(struct tty_struct *tty)

    pr_debug("stl_writeroom(tty=%p)\n", tty);

    - if (tty == NULL)
    - return 0;
    portp = tty->driver_data;
    if (portp == NULL)
    return 0;
    @@ -1125,8 +1115,6 @@ static int stl_charsinbuffer(struct tty_struct *tty)

    pr_debug("stl_charsinbuffer(tty=%p)\n", tty);

    - if (tty == NULL)
    - return 0;
    portp = tty->driver_data;
    if (portp == NULL)
    return 0;
    @@ -1219,8 +1207,6 @@ static int stl_tiocmget(struct tty_struct *tty, struct file *file)
    {
    struct stlport *portp;

    - if (tty == NULL)
    - return -ENODEV;
    portp = tty->driver_data;
    if (portp == NULL)
    return -ENODEV;
    @@ -1236,8 +1222,6 @@ static int stl_tiocmset(struct tty_struct *tty, struct file *file,
    struct stlport *portp;
    int rts = -1, dtr = -1;

    - if (tty == NULL)
    - return -ENODEV;
    portp = tty->driver_data;
    if (portp == NULL)
    return -ENODEV;
    @@ -1266,8 +1250,6 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd
    pr_debug("stl_ioctl(tty=%p,file=%p,cmd=%x,arg=%lx)\n", tty, file, cmd,
    arg);

    - if (tty == NULL)
    - return -ENODEV;
    portp = tty->driver_data;
    if (portp == NULL)
    return -ENODEV;
    @@ -1321,8 +1303,6 @@ static void stl_start(struct tty_struct *tty)

    pr_debug("stl_start(tty=%p)\n", tty);

    - if (tty == NULL)
    - return;
    portp = tty->driver_data;
    if (portp == NULL)
    return;
    @@ -1338,8 +1318,6 @@ static void stl_settermios(struct tty_struct *tty, struct ktermios *old)

    pr_debug("stl_settermios(tty=%p,old=%p)\n", tty, old);

    - if (tty == NULL)
    - return;
    portp = tty->driver_data;
    if (portp == NULL)
    return;
    @@ -1373,8 +1351,6 @@ static void stl_throttle(struct tty_struct *tty)

    pr_debug("stl_throttle(tty=%p)\n", tty);

    - if (tty == NULL)
    - return;
    portp = tty->driver_data;
    if (portp == NULL)
    return;
    @@ -1393,8 +1369,6 @@ static void stl_unthrottle(struct tty_struct *tty)

    pr_debug("stl_unthrottle(tty=%p)\n", tty);

    - if (tty == NULL)
    - return;
    portp = tty->driver_data;
    if (portp == NULL)
    return;
    @@ -1414,8 +1388,6 @@ static void stl_stop(struct tty_struct *tty)

    pr_debug("stl_stop(tty=%p)\n", tty);

    - if (tty == NULL)
    - return;
    portp = tty->driver_data;
    if (portp == NULL)
    return;
    @@ -1436,8 +1408,6 @@ static void stl_hangup(struct tty_struct *tty)

    pr_debug("stl_hangup(tty=%p)\n", tty);

    - if (tty == NULL)
    - return;
    portp = tty->driver_data;
    if (portp == NULL)
    return;
    @@ -1470,8 +1440,6 @@ static int stl_breakctl(struct tty_struct *tty, int state)

    pr_debug("stl_breakctl(tty=%p,state=%d)\n", tty, state);

    - if (tty == NULL)
    - return -EINVAL;
    portp = tty->driver_data;
    if (portp == NULL)
    return -EINVAL;
    @@ -1488,8 +1456,6 @@ static void stl_sendxchar(struct tty_struct *tty, char ch)

    pr_debug("stl_sendxchar(tty=%p,ch=%x)\n", tty, ch);

    - if (tty == NULL)
    - return;
    portp = tty->driver_data;
    if (portp == NULL)
    return;

    --
    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 75/80] applicom: Fix an unchecked user ioctl range and an error return

    From: Alan Cox

    Closes bug #11408 by checking the card index range for command 0
    Fixes the ioctl to return ENOTTY which is correct for unknown ioctls

    Signed-off-by: Alan Cox
    ---

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


    diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
    index 31d08b6..b899d91 100644
    --- a/drivers/char/applicom.c
    +++ b/drivers/char/applicom.c
    @@ -712,8 +712,7 @@ static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un

    IndexCard = adgl->num_card-1;

    - if(cmd != 0 && cmd != 6 &&
    - ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) {
    + if(cmd != 6 && ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) {
    static int warncount = 10;
    if (warncount) {
    printk( KERN_WARNING "APPLICOM driver IOCTL, bad board number %d\n",(int)IndexCard+1);
    @@ -832,8 +831,7 @@ static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
    }
    break;
    default:
    - printk(KERN_INFO "APPLICOM driver ioctl, unknown function code %d\n",cmd) ;
    - ret = -EINVAL;
    + ret = -ENOTTY;
    break;
    }
    Dummy = readb(apbs[IndexCard].RamIO + VERS);

    --
    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 3 of 4 FirstFirst 1 2 3 4 LastLast