Merge 3.2-rc3 into tty-next to handle merge conflict in tty_ldisc.c
[deliverable/linux.git] / drivers / tty / tty_ldisc.c
index 174db3b0c09e634ec42a8d4747ac83bb99640062..24b95db75d84f8d6f42705bdfb57b622abcce322 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/bitops.h>
 #include <linux/seq_file.h>
 #include <linux/uaccess.h>
+#include <linux/ratelimit.h>
 
 /*
  *     This guards the refcounted line discipline lists. The lock
@@ -529,15 +530,16 @@ static void tty_ldisc_flush_works(struct tty_struct *tty)
 /**
  *     tty_ldisc_wait_idle     -       wait for the ldisc to become idle
  *     @tty: tty to wait for
+ *     @timeout: for how long to wait at most
  *
  *     Wait for the line discipline to become idle. The discipline must
  *     have been halted for this to guarantee it remains idle.
  */
-static int tty_ldisc_wait_idle(struct tty_struct *tty)
+static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout)
 {
-       int ret;
+       long ret;
        ret = wait_event_timeout(tty_ldisc_idle,
-                       atomic_read(&tty->ldisc->users) == 1, 5 * HZ);
+                       atomic_read(&tty->ldisc->users) == 1, timeout);
        return ret > 0 ? 0 : -EBUSY;
 }
 
@@ -645,7 +647,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 
        tty_ldisc_flush_works(tty);
 
-       retval = tty_ldisc_wait_idle(tty);
+       retval = tty_ldisc_wait_idle(tty, 5 * HZ);
 
        tty_lock();
        mutex_lock(&tty->ldisc_mutex);
@@ -742,8 +744,6 @@ static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
        if (IS_ERR(ld))
                return -1;
 
-       WARN_ON_ONCE(tty_ldisc_wait_idle(tty));
-
        tty_ldisc_close(tty, tty->ldisc);
        tty_ldisc_put(tty->ldisc);
        tty->ldisc = NULL;
@@ -818,7 +818,7 @@ void tty_ldisc_hangup(struct tty_struct *tty)
        tty_unlock();
        cancel_work_sync(&tty->buf.work);
        mutex_unlock(&tty->ldisc_mutex);
-
+retry:
        tty_lock();
        mutex_lock(&tty->ldisc_mutex);
 
@@ -827,6 +827,22 @@ void tty_ldisc_hangup(struct tty_struct *tty)
           it means auditing a lot of other paths so this is
           a FIXME */
        if (tty->ldisc) {       /* Not yet closed */
+               if (atomic_read(&tty->ldisc->users) != 1) {
+                       char cur_n[TASK_COMM_LEN], tty_n[64];
+                       long timeout = 3 * HZ;
+                       tty_unlock();
+
+                       while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) {
+                               timeout = MAX_SCHEDULE_TIMEOUT;
+                               printk_ratelimited(KERN_WARNING
+                                       "%s: waiting (%s) for %s took too long, but we keep waiting...\n",
+                                       __func__, get_task_comm(cur_n, current),
+                                       tty_name(tty, tty_n));
+                       }
+                       mutex_unlock(&tty->ldisc_mutex);
+                       goto retry;
+               }
+
                if (reset == 0) {
 
                        if (!tty_ldisc_reinit(tty, tty->termios->c_line))
This page took 0.030667 seconds and 5 git commands to generate.