]> Git Repo - linux.git/commitdiff
Merge tag 'tty-3.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
authorLinus Torvalds <[email protected]>
Mon, 29 Apr 2013 19:16:17 +0000 (12:16 -0700)
committerLinus Torvalds <[email protected]>
Mon, 29 Apr 2013 19:16:17 +0000 (12:16 -0700)
Pull tty/serial driver update from Greg Kroah-Hartman:
 "Here's the big tty/serial driver merge request for 3.10-rc1

  Once again, Jiri has a number of TTY driver fixes and cleanups, and
  Peter Hurley came through with a bunch of ldisc fixes that resolve a
  number of reported issues.  There are some other serial driver
  cleanups as well.

  All of these have been in the linux-next tree for a while"

* tag 'tty-3.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (117 commits)
  tty/serial/sirf: fix MODULE_DEVICE_TABLE
  serial: mxs: drop superfluous {get|put}_device
  serial: mxs: fix buffer overflow
  ARM: PL011: add support for extended FIFO-size of PL011-r1p5
  serial_core.c: add put_device() after device_find_child()
  tty: Fix unsafe bit ops in tty_throttle_safe/unthrottle_safe
  serial: sccnxp: Replace pdata.init/exit with regulator API
  serial: sccnxp: Do not override device name
  TTY: pty, fix compilation warning
  TTY: rocket, fix compilation warning
  TTY: ircomm: fix DTR being raised on hang up
  TTY: synclinkmp: fix DTR being raised on hang up
  TTY: synclink_gt: fix DTR being raised on hang up
  TTY: synclink: fix DTR being raised on hang up
  serial: 8250_dw: Fix the stub for dw8250_probe_acpi()
  serial: 8250_dw: Convert to devm_ioremap()
  serial: 8250_dw: Set port capabilities based on CPR register
  serial: 8250_dw: Let ACPI code extract the DMA client info
  serial: 8250_dw: Support clk framework also with ACPI
  serial: 8250_dw: Enable runtime PM
  ...

1  2 
drivers/staging/fwserial/fwserial.c
drivers/tty/tty_io.c

index 0263e98b445dd775e0e09545c07051847e24d532,5c64e3a35b281dad02bac6b10d68529423cfaeb2..e5818a1c22620914fb5afe279e32c657414715b3
@@@ -744,7 -744,6 +744,6 @@@ static void fwtty_tx_complete(struct fw
                              struct fwtty_transaction *txn)
  {
        struct fwtty_port *port = txn->port;
-       struct tty_struct *tty;
        int len;
  
        fwtty_dbg(port, "rcode: %d", rcode);
                port->stats.dropped += txn->dma_pended.len;
        }
  
-       if (len < WAKEUP_CHARS) {
-               tty = tty_port_tty_get(&port->port);
-               if (tty) {
-                       tty_wakeup(tty);
-                       tty_kref_put(tty);
-               }
-       }
+       if (len < WAKEUP_CHARS)
+               tty_port_tty_wakeup(&port->port);
  }
  
  static int fwtty_tx(struct fwtty_port *port, bool drain)
@@@ -1527,7 -1521,7 +1521,7 @@@ static void fwtty_debugfs_show_port(str
                   stats.watermark);
  
        if (port->port.console) {
 -              seq_printf(m, "\n    ");
 +              seq_puts(m, "\n    ");
                (*port->fwcon_ops->proc_show)(m, port->con_data);
        }
  
@@@ -1559,7 -1553,7 +1553,7 @@@ static int fwtty_proc_show(struct seq_f
                if (capable(CAP_SYS_ADMIN))
                        fwtty_proc_show_port(m, port);
                fwtty_port_put(port);
 -              seq_printf(m, "\n");
 +              seq_puts(m, "\n");
        }
        return 0;
  }
@@@ -1577,7 -1571,7 +1571,7 @@@ static int fwtty_debugfs_stats_show(str
                        fwtty_proc_show_port(m, port);
                        fwtty_debugfs_show_port(m, port);
                        fwtty_port_put(port);
 -                      seq_printf(m, "\n");
 +                      seq_puts(m, "\n");
                }
        }
        return 0;
diff --combined drivers/tty/tty_io.c
index b0452688308c6605bfc64168c790a442bef1407d,cbf5a5040908c62258447994204949759d79755d..97ebc8c5864e7f092e443810a53d5e42b4238501
@@@ -532,6 -532,60 +532,60 @@@ void tty_wakeup(struct tty_struct *tty
  
  EXPORT_SYMBOL_GPL(tty_wakeup);
  
+ /**
+  *    tty_signal_session_leader       - sends SIGHUP to session leader
+  *    @tty            controlling tty
+  *    @exit_session   if non-zero, signal all foreground group processes
+  *
+  *    Send SIGHUP and SIGCONT to the session leader and its process group.
+  *    Optionally, signal all processes in the foreground process group.
+  *
+  *    Returns the number of processes in the session with this tty
+  *    as their controlling terminal. This value is used to drop
+  *    tty references for those processes.
+  */
+ static int tty_signal_session_leader(struct tty_struct *tty, int exit_session)
+ {
+       struct task_struct *p;
+       int refs = 0;
+       struct pid *tty_pgrp = NULL;
+       read_lock(&tasklist_lock);
+       if (tty->session) {
+               do_each_pid_task(tty->session, PIDTYPE_SID, p) {
+                       spin_lock_irq(&p->sighand->siglock);
+                       if (p->signal->tty == tty) {
+                               p->signal->tty = NULL;
+                               /* We defer the dereferences outside fo
+                                  the tasklist lock */
+                               refs++;
+                       }
+                       if (!p->signal->leader) {
+                               spin_unlock_irq(&p->sighand->siglock);
+                               continue;
+                       }
+                       __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
+                       __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
+                       put_pid(p->signal->tty_old_pgrp);  /* A noop */
+                       spin_lock(&tty->ctrl_lock);
+                       tty_pgrp = get_pid(tty->pgrp);
+                       if (tty->pgrp)
+                               p->signal->tty_old_pgrp = get_pid(tty->pgrp);
+                       spin_unlock(&tty->ctrl_lock);
+                       spin_unlock_irq(&p->sighand->siglock);
+               } while_each_pid_task(tty->session, PIDTYPE_SID, p);
+       }
+       read_unlock(&tasklist_lock);
+       if (tty_pgrp) {
+               if (exit_session)
+                       kill_pgrp(tty_pgrp, SIGHUP, exit_session);
+               put_pid(tty_pgrp);
+       }
+       return refs;
+ }
  /**
   *    __tty_hangup            -       actual handler for hangup events
   *    @work: tty device
   *              tasklist_lock to walk task list for hangup event
   *                ->siglock to protect ->signal/->sighand
   */
- static void __tty_hangup(struct tty_struct *tty)
+ static void __tty_hangup(struct tty_struct *tty, int exit_session)
  {
        struct file *cons_filp = NULL;
        struct file *filp, *f = NULL;
-       struct task_struct *p;
        struct tty_file_private *priv;
        int    closecount = 0, n;
-       unsigned long flags;
-       int refs = 0;
+       int refs;
  
        if (!tty)
                return;
        }
        spin_unlock(&tty_files_lock);
  
+       refs = tty_signal_session_leader(tty, exit_session);
+       /* Account for the p->signal references we killed */
+       while (refs--)
+               tty_kref_put(tty);
        /*
         * it drops BTM and thus races with reopen
         * we protect the race by TTY_HUPPING
         */
        tty_ldisc_hangup(tty);
  
-       read_lock(&tasklist_lock);
-       if (tty->session) {
-               do_each_pid_task(tty->session, PIDTYPE_SID, p) {
-                       spin_lock_irq(&p->sighand->siglock);
-                       if (p->signal->tty == tty) {
-                               p->signal->tty = NULL;
-                               /* We defer the dereferences outside fo
-                                  the tasklist lock */
-                               refs++;
-                       }
-                       if (!p->signal->leader) {
-                               spin_unlock_irq(&p->sighand->siglock);
-                               continue;
-                       }
-                       __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
-                       __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
-                       put_pid(p->signal->tty_old_pgrp);  /* A noop */
-                       spin_lock_irqsave(&tty->ctrl_lock, flags);
-                       if (tty->pgrp)
-                               p->signal->tty_old_pgrp = get_pid(tty->pgrp);
-                       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-                       spin_unlock_irq(&p->sighand->siglock);
-               } while_each_pid_task(tty->session, PIDTYPE_SID, p);
-       }
-       read_unlock(&tasklist_lock);
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       spin_lock_irq(&tty->ctrl_lock);
        clear_bit(TTY_THROTTLED, &tty->flags);
        clear_bit(TTY_PUSH, &tty->flags);
        clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
        tty->session = NULL;
        tty->pgrp = NULL;
        tty->ctrl_status = 0;
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-       /* Account for the p->signal references we killed */
-       while (refs--)
-               tty_kref_put(tty);
+       spin_unlock_irq(&tty->ctrl_lock);
  
        /*
         * If one of the devices matches a console pointer, we
         */
        set_bit(TTY_HUPPED, &tty->flags);
        clear_bit(TTY_HUPPING, &tty->flags);
-       tty_ldisc_enable(tty);
  
        tty_unlock(tty);
  
@@@ -679,7 -705,7 +705,7 @@@ static void do_tty_hangup(struct work_s
        struct tty_struct *tty =
                container_of(work, struct tty_struct, hangup_work);
  
-       __tty_hangup(tty);
+       __tty_hangup(tty, 0);
  }
  
  /**
@@@ -717,7 -743,7 +743,7 @@@ void tty_vhangup(struct tty_struct *tty
  
        printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf));
  #endif
-       __tty_hangup(tty);
+       __tty_hangup(tty, 0);
  }
  
  EXPORT_SYMBOL(tty_vhangup);
@@@ -740,6 -766,27 +766,27 @@@ void tty_vhangup_self(void
        }
  }
  
+ /**
+  *    tty_vhangup_session             -       hangup session leader exit
+  *    @tty: tty to hangup
+  *
+  *    The session leader is exiting and hanging up its controlling terminal.
+  *    Every process in the foreground process group is signalled SIGHUP.
+  *
+  *    We do this synchronously so that when the syscall returns the process
+  *    is complete. That guarantee is necessary for security reasons.
+  */
+ static void tty_vhangup_session(struct tty_struct *tty)
+ {
+ #ifdef TTY_DEBUG_HANGUP
+       char    buf[64];
+       printk(KERN_DEBUG "%s vhangup session...\n", tty_name(tty, buf));
+ #endif
+       __tty_hangup(tty, 1);
+ }
  /**
   *    tty_hung_up_p           -       was tty hung up
   *    @filp: file pointer of tty
@@@ -797,18 -844,18 +844,18 @@@ void disassociate_ctty(int on_exit
  
        tty = get_current_tty();
        if (tty) {
-               struct pid *tty_pgrp = get_pid(tty->pgrp);
-               if (on_exit) {
-                       if (tty->driver->type != TTY_DRIVER_TYPE_PTY)
-                               tty_vhangup(tty);
-               }
-               tty_kref_put(tty);
-               if (tty_pgrp) {
-                       kill_pgrp(tty_pgrp, SIGHUP, on_exit);
-                       if (!on_exit)
+               if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY) {
+                       tty_vhangup_session(tty);
+               } else {
+                       struct pid *tty_pgrp = tty_get_pgrp(tty);
+                       if (tty_pgrp) {
+                               kill_pgrp(tty_pgrp, SIGHUP, on_exit);
                                kill_pgrp(tty_pgrp, SIGCONT, on_exit);
-                       put_pid(tty_pgrp);
+                               put_pid(tty_pgrp);
+                       }
                }
+               tty_kref_put(tty);
        } else if (on_exit) {
                struct pid *old_pgrp;
                spin_lock_irq(&current->sighand->siglock);
@@@ -941,14 -988,6 +988,14 @@@ void start_tty(struct tty_struct *tty
  
  EXPORT_SYMBOL(start_tty);
  
 +static void tty_update_time(struct timespec *time)
 +{
 +      unsigned long sec = get_seconds();
 +      sec -= sec % 60;
 +      if ((long)(sec - time->tv_sec) > 0)
 +              time->tv_sec = sec;
 +}
 +
  /**
   *    tty_read        -       read method for tty device files
   *    @file: pointer to tty file
@@@ -968,11 -1007,10 +1015,11 @@@ static ssize_t tty_read(struct file *fi
                        loff_t *ppos)
  {
        int i;
 +      struct inode *inode = file_inode(file);
        struct tty_struct *tty = file_tty(file);
        struct tty_ldisc *ld;
  
 -      if (tty_paranoia_check(tty, file_inode(file), "tty_read"))
 +      if (tty_paranoia_check(tty, inode, "tty_read"))
                return -EIO;
        if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))
                return -EIO;
                i = -EIO;
        tty_ldisc_deref(ld);
  
 +      if (i > 0)
 +              tty_update_time(&inode->i_atime);
 +
        return i;
  }
  
@@@ -1089,10 -1124,8 +1136,10 @@@ static inline ssize_t do_tty_write
                        break;
                cond_resched();
        }
 -      if (written)
 +      if (written) {
 +              tty_update_time(&file_inode(file)->i_mtime);
                ret = written;
 +      }
  out:
        tty_write_unlock(tty);
        return ret;
@@@ -1358,9 -1391,7 +1405,7 @@@ static int tty_reopen(struct tty_struc
        }
        tty->count++;
  
-       mutex_lock(&tty->ldisc_mutex);
        WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
-       mutex_unlock(&tty->ldisc_mutex);
  
        return 0;
  }
@@@ -1477,6 -1508,17 +1522,17 @@@ void tty_free_termios(struct tty_struc
  }
  EXPORT_SYMBOL(tty_free_termios);
  
+ /**
+  *    tty_flush_works         -       flush all works of a tty
+  *    @tty: tty device to flush works for
+  *
+  *    Sync flush all works belonging to @tty.
+  */
+ static void tty_flush_works(struct tty_struct *tty)
+ {
+       flush_work(&tty->SAK_work);
+       flush_work(&tty->hangup_work);
+ }
  
  /**
   *    release_one_tty         -       release tty structure memory
@@@ -1562,6 -1604,7 +1618,7 @@@ static void release_tty(struct tty_stru
        tty_free_termios(tty);
        tty_driver_remove_tty(tty->driver, tty);
        tty->port->itty = NULL;
+       cancel_work_sync(&tty->port->buf.work);
  
        if (tty->link)
                tty_kref_put(tty->link);
@@@ -1791,12 -1834,21 +1848,21 @@@ int tty_release(struct inode *inode, st
                return 0;
  
  #ifdef TTY_DEBUG_HANGUP
-       printk(KERN_DEBUG "%s: freeing tty structure...\n", __func__);
+       printk(KERN_DEBUG "%s: %s: final close\n", __func__, tty_name(tty, buf));
  #endif
        /*
         * Ask the line discipline code to release its structures
         */
        tty_ldisc_release(tty, o_tty);
+       /* Wait for pending work before tty destruction commmences */
+       tty_flush_works(tty);
+       if (o_tty)
+               tty_flush_works(o_tty);
+ #ifdef TTY_DEBUG_HANGUP
+       printk(KERN_DEBUG "%s: %s: freeing structure...\n", __func__, tty_name(tty, buf));
+ #endif
        /*
         * The release_tty function takes care of the details of clearing
         * the slots and preserving the termios structure. The tty_unlock_pair
This page took 0.09745 seconds and 4 git commands to generate.