s390/3215: fix hanging console issue
authorMartin Schwidefsky <schwidefsky@de.ibm.com>
Tue, 15 Jul 2014 15:53:12 +0000 (17:53 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 28 Jul 2014 08:02:39 +0000 (10:02 +0200)
The ccw_device_start in raw3215_start_io can fail. raw3215_try_io
does not check if the request could be started and removes any
pending timer. This can leave the system in a hanging state.
Check for pending request after raw3215_start_io and start a
timer if necessary.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
drivers/s390/char/con3215.c

index 5af7f0bd6125702358cb1fbab5830c5a77506e7b..a6d47e5eee9e0add1485533915832107659d2df6 100644 (file)
@@ -288,12 +288,16 @@ static void raw3215_timeout(unsigned long __data)
        unsigned long flags;
 
        spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
-       if (raw->flags & RAW3215_TIMER_RUNS) {
-               del_timer(&raw->timer);
-               raw->flags &= ~RAW3215_TIMER_RUNS;
-               if (!(raw->port.flags & ASYNC_SUSPENDED)) {
-                       raw3215_mk_write_req(raw);
-                       raw3215_start_io(raw);
+       raw->flags &= ~RAW3215_TIMER_RUNS;
+       if (!(raw->port.flags & ASYNC_SUSPENDED)) {
+               raw3215_mk_write_req(raw);
+               raw3215_start_io(raw);
+               if ((raw->queued_read || raw->queued_write) &&
+                   !(raw->flags & RAW3215_WORKING) &&
+                   !(raw->flags & RAW3215_TIMER_RUNS)) {
+                       raw->timer.expires = RAW3215_TIMEOUT + jiffies;
+                       add_timer(&raw->timer);
+                       raw->flags |= RAW3215_TIMER_RUNS;
                }
        }
        spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
@@ -317,17 +321,15 @@ static inline void raw3215_try_io(struct raw3215_info *raw)
                    (raw->flags & RAW3215_FLUSHING)) {
                        /* execute write requests bigger than minimum size */
                        raw3215_start_io(raw);
-                       if (raw->flags & RAW3215_TIMER_RUNS) {
-                               del_timer(&raw->timer);
-                               raw->flags &= ~RAW3215_TIMER_RUNS;
-                       }
-               } else if (!(raw->flags & RAW3215_TIMER_RUNS)) {
-                       /* delay small writes */
-                       raw->timer.expires = RAW3215_TIMEOUT + jiffies;
-                       add_timer(&raw->timer);
-                       raw->flags |= RAW3215_TIMER_RUNS;
                }
        }
+       if ((raw->queued_read || raw->queued_write) &&
+           !(raw->flags & RAW3215_WORKING) &&
+           !(raw->flags & RAW3215_TIMER_RUNS)) {
+               raw->timer.expires = RAW3215_TIMEOUT + jiffies;
+               add_timer(&raw->timer);
+               raw->flags |= RAW3215_TIMER_RUNS;
+       }
 }
 
 /*
This page took 0.026788 seconds and 5 git commands to generate.