diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2014-07-15 11:53:12 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2014-07-28 04:02:39 -0400 |
commit | 26d766c60f4ea08cd14f0f3435a6db3d6cc2ae96 (patch) | |
tree | ae07e275a923cb86018da35c1cb0ef984bfb4a00 /drivers/s390 | |
parent | e2213e04c1b1e44a09a9d05b79809b7e63c9217e (diff) |
s390/3215: fix hanging console issue
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>
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/char/con3215.c | 32 |
1 files changed, 17 insertions, 15 deletions
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 5af7f0bd6125..a6d47e5eee9e 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c | |||
@@ -288,12 +288,16 @@ static void raw3215_timeout(unsigned long __data) | |||
288 | unsigned long flags; | 288 | unsigned long flags; |
289 | 289 | ||
290 | spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); | 290 | spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); |
291 | if (raw->flags & RAW3215_TIMER_RUNS) { | 291 | raw->flags &= ~RAW3215_TIMER_RUNS; |
292 | del_timer(&raw->timer); | 292 | if (!(raw->port.flags & ASYNC_SUSPENDED)) { |
293 | raw->flags &= ~RAW3215_TIMER_RUNS; | 293 | raw3215_mk_write_req(raw); |
294 | if (!(raw->port.flags & ASYNC_SUSPENDED)) { | 294 | raw3215_start_io(raw); |
295 | raw3215_mk_write_req(raw); | 295 | if ((raw->queued_read || raw->queued_write) && |
296 | raw3215_start_io(raw); | 296 | !(raw->flags & RAW3215_WORKING) && |
297 | !(raw->flags & RAW3215_TIMER_RUNS)) { | ||
298 | raw->timer.expires = RAW3215_TIMEOUT + jiffies; | ||
299 | add_timer(&raw->timer); | ||
300 | raw->flags |= RAW3215_TIMER_RUNS; | ||
297 | } | 301 | } |
298 | } | 302 | } |
299 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); | 303 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); |
@@ -317,17 +321,15 @@ static inline void raw3215_try_io(struct raw3215_info *raw) | |||
317 | (raw->flags & RAW3215_FLUSHING)) { | 321 | (raw->flags & RAW3215_FLUSHING)) { |
318 | /* execute write requests bigger than minimum size */ | 322 | /* execute write requests bigger than minimum size */ |
319 | raw3215_start_io(raw); | 323 | raw3215_start_io(raw); |
320 | if (raw->flags & RAW3215_TIMER_RUNS) { | ||
321 | del_timer(&raw->timer); | ||
322 | raw->flags &= ~RAW3215_TIMER_RUNS; | ||
323 | } | ||
324 | } else if (!(raw->flags & RAW3215_TIMER_RUNS)) { | ||
325 | /* delay small writes */ | ||
326 | raw->timer.expires = RAW3215_TIMEOUT + jiffies; | ||
327 | add_timer(&raw->timer); | ||
328 | raw->flags |= RAW3215_TIMER_RUNS; | ||
329 | } | 324 | } |
330 | } | 325 | } |
326 | if ((raw->queued_read || raw->queued_write) && | ||
327 | !(raw->flags & RAW3215_WORKING) && | ||
328 | !(raw->flags & RAW3215_TIMER_RUNS)) { | ||
329 | raw->timer.expires = RAW3215_TIMEOUT + jiffies; | ||
330 | add_timer(&raw->timer); | ||
331 | raw->flags |= RAW3215_TIMER_RUNS; | ||
332 | } | ||
331 | } | 333 | } |
332 | 334 | ||
333 | /* | 335 | /* |