Merge tag 'iwlwifi-next-for-kalle-2014-12-30' of https://git.kernel.org/pub/scm/linux...
[cascardo/linux.git] / drivers / tty / tty_ldisc.c
index 1c4d7b6..3737f55 100644 (file)
@@ -308,23 +308,41 @@ EXPORT_SYMBOL_GPL(tty_ldisc_deref);
 
 
 static inline int __lockfunc
-tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout)
+__tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout)
 {
        return ldsem_down_write(&tty->ldisc_sem, timeout);
 }
 
 static inline int __lockfunc
-tty_ldisc_lock_nested(struct tty_struct *tty, unsigned long timeout)
+__tty_ldisc_lock_nested(struct tty_struct *tty, unsigned long timeout)
 {
        return ldsem_down_write_nested(&tty->ldisc_sem,
                                       LDISC_SEM_OTHER, timeout);
 }
 
-static inline void tty_ldisc_unlock(struct tty_struct *tty)
+static inline void __tty_ldisc_unlock(struct tty_struct *tty)
 {
        return ldsem_up_write(&tty->ldisc_sem);
 }
 
+static int __lockfunc
+tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout)
+{
+       int ret;
+
+       ret = __tty_ldisc_lock(tty, timeout);
+       if (!ret)
+               return -EBUSY;
+       set_bit(TTY_LDISC_HALTED, &tty->flags);
+       return 0;
+}
+
+static void tty_ldisc_unlock(struct tty_struct *tty)
+{
+       clear_bit(TTY_LDISC_HALTED, &tty->flags);
+       __tty_ldisc_unlock(tty);
+}
+
 static int __lockfunc
 tty_ldisc_lock_pair_timeout(struct tty_struct *tty, struct tty_struct *tty2,
                            unsigned long timeout)
@@ -332,24 +350,24 @@ tty_ldisc_lock_pair_timeout(struct tty_struct *tty, struct tty_struct *tty2,
        int ret;
 
        if (tty < tty2) {
-               ret = tty_ldisc_lock(tty, timeout);
+               ret = __tty_ldisc_lock(tty, timeout);
                if (ret) {
-                       ret = tty_ldisc_lock_nested(tty2, timeout);
+                       ret = __tty_ldisc_lock_nested(tty2, timeout);
                        if (!ret)
-                               tty_ldisc_unlock(tty);
+                               __tty_ldisc_unlock(tty);
                }
        } else {
                /* if this is possible, it has lots of implications */
                WARN_ON_ONCE(tty == tty2);
                if (tty2 && tty != tty2) {
-                       ret = tty_ldisc_lock(tty2, timeout);
+                       ret = __tty_ldisc_lock(tty2, timeout);
                        if (ret) {
-                               ret = tty_ldisc_lock_nested(tty, timeout);
+                               ret = __tty_ldisc_lock_nested(tty, timeout);
                                if (!ret)
-                                       tty_ldisc_unlock(tty2);
+                                       __tty_ldisc_unlock(tty2);
                        }
                } else
-                       ret = tty_ldisc_lock(tty, timeout);
+                       ret = __tty_ldisc_lock(tty, timeout);
        }
 
        if (!ret)
@@ -370,38 +388,26 @@ tty_ldisc_lock_pair(struct tty_struct *tty, struct tty_struct *tty2)
 static void __lockfunc tty_ldisc_unlock_pair(struct tty_struct *tty,
                                             struct tty_struct *tty2)
 {
-       tty_ldisc_unlock(tty);
+       __tty_ldisc_unlock(tty);
        if (tty2)
-               tty_ldisc_unlock(tty2);
-}
-
-static void __lockfunc tty_ldisc_enable_pair(struct tty_struct *tty,
-                                            struct tty_struct *tty2)
-{
-       clear_bit(TTY_LDISC_HALTED, &tty->flags);
-       if (tty2)
-               clear_bit(TTY_LDISC_HALTED, &tty2->flags);
-
-       tty_ldisc_unlock_pair(tty, tty2);
+               __tty_ldisc_unlock(tty2);
 }
 
 /**
  *     tty_ldisc_flush -       flush line discipline queue
  *     @tty: tty
  *
- *     Flush the line discipline queue (if any) for this tty. If there
- *     is no line discipline active this is a no-op.
+ *     Flush the line discipline queue (if any) and the tty flip buffers
+ *     for this tty.
  */
 
 void tty_ldisc_flush(struct tty_struct *tty)
 {
        struct tty_ldisc *ld = tty_ldisc_ref(tty);
-       if (ld) {
-               if (ld->ops->flush_buffer)
-                       ld->ops->flush_buffer(tty);
+
+       tty_buffer_flush(tty, ld);
+       if (ld)
                tty_ldisc_deref(ld);
-       }
-       tty_buffer_flush(tty);
 }
 EXPORT_SYMBOL_GPL(tty_ldisc_flush);
 
@@ -517,14 +523,13 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 {
        int retval;
        struct tty_ldisc *old_ldisc, *new_ldisc;
-       struct tty_struct *o_tty = tty->link;
 
        new_ldisc = tty_ldisc_get(tty, ldisc);
        if (IS_ERR(new_ldisc))
                return PTR_ERR(new_ldisc);
 
        tty_lock(tty);
-       retval = tty_ldisc_lock_pair_timeout(tty, o_tty, 5 * HZ);
+       retval = tty_ldisc_lock(tty, 5 * HZ);
        if (retval) {
                tty_ldisc_put(new_ldisc);
                tty_unlock(tty);
@@ -536,7 +541,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
         */
 
        if (tty->ldisc->ops->num == ldisc) {
-               tty_ldisc_enable_pair(tty, o_tty);
+               tty_ldisc_unlock(tty);
                tty_ldisc_put(new_ldisc);
                tty_unlock(tty);
                return 0;
@@ -547,7 +552,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
        if (test_bit(TTY_HUPPED, &tty->flags)) {
                /* We were raced by the hangup method. It will have stomped
                   the ldisc data and closed the ldisc down */
-               tty_ldisc_enable_pair(tty, o_tty);
+               tty_ldisc_unlock(tty);
                tty_ldisc_put(new_ldisc);
                tty_unlock(tty);
                return -EIO;
@@ -567,8 +572,11 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
                tty_ldisc_restore(tty, old_ldisc);
        }
 
-       if (tty->ldisc->ops->num != old_ldisc->ops->num && tty->ops->set_ldisc)
+       if (tty->ldisc->ops->num != old_ldisc->ops->num && tty->ops->set_ldisc) {
+               down_read(&tty->termios_rwsem);
                tty->ops->set_ldisc(tty);
+               up_read(&tty->termios_rwsem);
+       }
 
        /* At this point we hold a reference to the new ldisc and a
           reference to the old ldisc, or we hold two references to
@@ -581,13 +589,11 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
        /*
         *      Allow ldisc referencing to occur again
         */
-       tty_ldisc_enable_pair(tty, o_tty);
+       tty_ldisc_unlock(tty);
 
        /* Restart the work queue in case no characters kick it off. Safe if
           already running */
        schedule_work(&tty->port->buf.work);
-       if (o_tty)
-               schedule_work(&o_tty->port->buf.work);
 
        tty_unlock(tty);
        return retval;
@@ -682,7 +688,7 @@ void tty_ldisc_hangup(struct tty_struct *tty)
         *
         * Avoid racing set_ldisc or tty_ldisc_release
         */
-       tty_ldisc_lock_pair(tty, tty->link);
+       tty_ldisc_lock(tty, MAX_SCHEDULE_TIMEOUT);
 
        if (tty->ldisc) {
 
@@ -704,7 +710,7 @@ void tty_ldisc_hangup(struct tty_struct *tty)
                        WARN_ON(tty_ldisc_open(tty, tty->ldisc));
                }
        }
-       tty_ldisc_enable_pair(tty, tty->link);
+       tty_ldisc_unlock(tty);
        if (reset)
                tty_reset_termios(tty);