diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2009-06-12 04:26:31 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2009-06-12 04:27:33 -0400 |
commit | 205d7ab9c9af6847dda30650a0b8f98555a20654 (patch) | |
tree | b77071becdd91a01ba2b30b3bdd79388f738b96b /drivers/s390 | |
parent | fcf7581f7ca82e63e4e137be77c342a4e4ec8401 (diff) |
[S390] 3270: lock dependency fixes
Lockdep found a problem with the lock order of the view lock and the
ccw device lock. raw3270_activate_view/raw3270_deactivate_view first
take the ccw device lock then call the activate/deactivate functions
of the view which take view lock. The update functions of the
con3270/tty3270 view will first take the view lock, then take the
ccw device lock. To fix this the activate/deactivate functions are
changed to avoid taking the view lock by moving the functions calls
that modify the 3270 output buffer to the update function which is
called by a timer.
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/char/con3270.c | 38 | ||||
-rw-r--r-- | drivers/s390/char/tty3270.c | 42 |
2 files changed, 32 insertions, 48 deletions
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c index d028d2ee83dd..ed5396dae58e 100644 --- a/drivers/s390/char/con3270.c +++ b/drivers/s390/char/con3270.c | |||
@@ -64,7 +64,7 @@ static struct con3270 *condev; | |||
64 | #define CON_UPDATE_ERASE 1 /* Use EWRITEA instead of WRITE. */ | 64 | #define CON_UPDATE_ERASE 1 /* Use EWRITEA instead of WRITE. */ |
65 | #define CON_UPDATE_LIST 2 /* Update lines in tty3270->update. */ | 65 | #define CON_UPDATE_LIST 2 /* Update lines in tty3270->update. */ |
66 | #define CON_UPDATE_STATUS 4 /* Update status line. */ | 66 | #define CON_UPDATE_STATUS 4 /* Update status line. */ |
67 | #define CON_UPDATE_ALL 7 | 67 | #define CON_UPDATE_ALL 8 /* Recreate screen. */ |
68 | 68 | ||
69 | static void con3270_update(struct con3270 *); | 69 | static void con3270_update(struct con3270 *); |
70 | 70 | ||
@@ -73,18 +73,10 @@ static void con3270_update(struct con3270 *); | |||
73 | */ | 73 | */ |
74 | static void con3270_set_timer(struct con3270 *cp, int expires) | 74 | static void con3270_set_timer(struct con3270 *cp, int expires) |
75 | { | 75 | { |
76 | if (expires == 0) { | 76 | if (expires == 0) |
77 | if (timer_pending(&cp->timer)) | 77 | del_timer(&cp->timer); |
78 | del_timer(&cp->timer); | 78 | else |
79 | return; | 79 | mod_timer(&cp->timer, jiffies + expires); |
80 | } | ||
81 | if (timer_pending(&cp->timer) && | ||
82 | mod_timer(&cp->timer, jiffies + expires)) | ||
83 | return; | ||
84 | cp->timer.function = (void (*)(unsigned long)) con3270_update; | ||
85 | cp->timer.data = (unsigned long) cp; | ||
86 | cp->timer.expires = jiffies + expires; | ||
87 | add_timer(&cp->timer); | ||
88 | } | 80 | } |
89 | 81 | ||
90 | /* | 82 | /* |
@@ -225,6 +217,12 @@ con3270_update(struct con3270 *cp) | |||
225 | 217 | ||
226 | spin_lock_irqsave(&cp->view.lock, flags); | 218 | spin_lock_irqsave(&cp->view.lock, flags); |
227 | updated = 0; | 219 | updated = 0; |
220 | if (cp->update_flags & CON_UPDATE_ALL) { | ||
221 | con3270_rebuild_update(cp); | ||
222 | con3270_update_status(cp); | ||
223 | cp->update_flags = CON_UPDATE_ERASE | CON_UPDATE_LIST | | ||
224 | CON_UPDATE_STATUS; | ||
225 | } | ||
228 | if (cp->update_flags & CON_UPDATE_ERASE) { | 226 | if (cp->update_flags & CON_UPDATE_ERASE) { |
229 | /* Use erase write alternate to initialize display. */ | 227 | /* Use erase write alternate to initialize display. */ |
230 | raw3270_request_set_cmd(wrq, TC_EWRITEA); | 228 | raw3270_request_set_cmd(wrq, TC_EWRITEA); |
@@ -302,7 +300,6 @@ con3270_read_tasklet(struct raw3270_request *rrq) | |||
302 | deactivate = 1; | 300 | deactivate = 1; |
303 | break; | 301 | break; |
304 | case 0x6d: /* clear: start from scratch. */ | 302 | case 0x6d: /* clear: start from scratch. */ |
305 | con3270_rebuild_update(cp); | ||
306 | cp->update_flags = CON_UPDATE_ALL; | 303 | cp->update_flags = CON_UPDATE_ALL; |
307 | con3270_set_timer(cp, 1); | 304 | con3270_set_timer(cp, 1); |
308 | break; | 305 | break; |
@@ -382,30 +379,21 @@ con3270_issue_read(struct con3270 *cp) | |||
382 | static int | 379 | static int |
383 | con3270_activate(struct raw3270_view *view) | 380 | con3270_activate(struct raw3270_view *view) |
384 | { | 381 | { |
385 | unsigned long flags; | ||
386 | struct con3270 *cp; | 382 | struct con3270 *cp; |
387 | 383 | ||
388 | cp = (struct con3270 *) view; | 384 | cp = (struct con3270 *) view; |
389 | spin_lock_irqsave(&cp->view.lock, flags); | ||
390 | cp->nr_up = 0; | ||
391 | con3270_rebuild_update(cp); | ||
392 | con3270_update_status(cp); | ||
393 | cp->update_flags = CON_UPDATE_ALL; | 385 | cp->update_flags = CON_UPDATE_ALL; |
394 | con3270_set_timer(cp, 1); | 386 | con3270_set_timer(cp, 1); |
395 | spin_unlock_irqrestore(&cp->view.lock, flags); | ||
396 | return 0; | 387 | return 0; |
397 | } | 388 | } |
398 | 389 | ||
399 | static void | 390 | static void |
400 | con3270_deactivate(struct raw3270_view *view) | 391 | con3270_deactivate(struct raw3270_view *view) |
401 | { | 392 | { |
402 | unsigned long flags; | ||
403 | struct con3270 *cp; | 393 | struct con3270 *cp; |
404 | 394 | ||
405 | cp = (struct con3270 *) view; | 395 | cp = (struct con3270 *) view; |
406 | spin_lock_irqsave(&cp->view.lock, flags); | ||
407 | del_timer(&cp->timer); | 396 | del_timer(&cp->timer); |
408 | spin_unlock_irqrestore(&cp->view.lock, flags); | ||
409 | } | 397 | } |
410 | 398 | ||
411 | static int | 399 | static int |
@@ -504,6 +492,7 @@ con3270_write(struct console *co, const char *str, unsigned int count) | |||
504 | con3270_cline_end(cp); | 492 | con3270_cline_end(cp); |
505 | } | 493 | } |
506 | /* Setup timer to output current console buffer after 1/10 second */ | 494 | /* Setup timer to output current console buffer after 1/10 second */ |
495 | cp->nr_up = 0; | ||
507 | if (cp->view.dev && !timer_pending(&cp->timer)) | 496 | if (cp->view.dev && !timer_pending(&cp->timer)) |
508 | con3270_set_timer(cp, HZ/10); | 497 | con3270_set_timer(cp, HZ/10); |
509 | spin_unlock_irqrestore(&cp->view.lock,flags); | 498 | spin_unlock_irqrestore(&cp->view.lock,flags); |
@@ -624,7 +613,8 @@ con3270_init(void) | |||
624 | 613 | ||
625 | INIT_LIST_HEAD(&condev->lines); | 614 | INIT_LIST_HEAD(&condev->lines); |
626 | INIT_LIST_HEAD(&condev->update); | 615 | INIT_LIST_HEAD(&condev->update); |
627 | init_timer(&condev->timer); | 616 | setup_timer(&condev->timer, (void (*)(unsigned long)) con3270_update, |
617 | (unsigned long) condev); | ||
628 | tasklet_init(&condev->readlet, | 618 | tasklet_init(&condev->readlet, |
629 | (void (*)(unsigned long)) con3270_read_tasklet, | 619 | (void (*)(unsigned long)) con3270_read_tasklet, |
630 | (unsigned long) condev->read); | 620 | (unsigned long) condev->read); |
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index aa7a114f6529..38385677c653 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c | |||
@@ -112,7 +112,7 @@ struct tty3270 { | |||
112 | #define TTY_UPDATE_LIST 2 /* Update lines in tty3270->update. */ | 112 | #define TTY_UPDATE_LIST 2 /* Update lines in tty3270->update. */ |
113 | #define TTY_UPDATE_INPUT 4 /* Update input line. */ | 113 | #define TTY_UPDATE_INPUT 4 /* Update input line. */ |
114 | #define TTY_UPDATE_STATUS 8 /* Update status line. */ | 114 | #define TTY_UPDATE_STATUS 8 /* Update status line. */ |
115 | #define TTY_UPDATE_ALL 15 | 115 | #define TTY_UPDATE_ALL 16 /* Recreate screen. */ |
116 | 116 | ||
117 | static void tty3270_update(struct tty3270 *); | 117 | static void tty3270_update(struct tty3270 *); |
118 | 118 | ||
@@ -121,19 +121,10 @@ static void tty3270_update(struct tty3270 *); | |||
121 | */ | 121 | */ |
122 | static void tty3270_set_timer(struct tty3270 *tp, int expires) | 122 | static void tty3270_set_timer(struct tty3270 *tp, int expires) |
123 | { | 123 | { |
124 | if (expires == 0) { | 124 | if (expires == 0) |
125 | if (timer_pending(&tp->timer) && del_timer(&tp->timer)) | 125 | del_timer(&tp->timer); |
126 | raw3270_put_view(&tp->view); | 126 | else |
127 | return; | 127 | mod_timer(&tp->timer, jiffies + expires); |
128 | } | ||
129 | if (timer_pending(&tp->timer) && | ||
130 | mod_timer(&tp->timer, jiffies + expires)) | ||
131 | return; | ||
132 | raw3270_get_view(&tp->view); | ||
133 | tp->timer.function = (void (*)(unsigned long)) tty3270_update; | ||
134 | tp->timer.data = (unsigned long) tp; | ||
135 | tp->timer.expires = jiffies + expires; | ||
136 | add_timer(&tp->timer); | ||
137 | } | 128 | } |
138 | 129 | ||
139 | /* | 130 | /* |
@@ -337,7 +328,6 @@ tty3270_write_callback(struct raw3270_request *rq, void *data) | |||
337 | tp = (struct tty3270 *) rq->view; | 328 | tp = (struct tty3270 *) rq->view; |
338 | if (rq->rc != 0) { | 329 | if (rq->rc != 0) { |
339 | /* Write wasn't successfull. Refresh all. */ | 330 | /* Write wasn't successfull. Refresh all. */ |
340 | tty3270_rebuild_update(tp); | ||
341 | tp->update_flags = TTY_UPDATE_ALL; | 331 | tp->update_flags = TTY_UPDATE_ALL; |
342 | tty3270_set_timer(tp, 1); | 332 | tty3270_set_timer(tp, 1); |
343 | } | 333 | } |
@@ -366,6 +356,12 @@ tty3270_update(struct tty3270 *tp) | |||
366 | 356 | ||
367 | spin_lock(&tp->view.lock); | 357 | spin_lock(&tp->view.lock); |
368 | updated = 0; | 358 | updated = 0; |
359 | if (tp->update_flags & TTY_UPDATE_ALL) { | ||
360 | tty3270_rebuild_update(tp); | ||
361 | tty3270_update_status(tp); | ||
362 | tp->update_flags = TTY_UPDATE_ERASE | TTY_UPDATE_LIST | | ||
363 | TTY_UPDATE_INPUT | TTY_UPDATE_STATUS; | ||
364 | } | ||
369 | if (tp->update_flags & TTY_UPDATE_ERASE) { | 365 | if (tp->update_flags & TTY_UPDATE_ERASE) { |
370 | /* Use erase write alternate to erase display. */ | 366 | /* Use erase write alternate to erase display. */ |
371 | raw3270_request_set_cmd(wrq, TC_EWRITEA); | 367 | raw3270_request_set_cmd(wrq, TC_EWRITEA); |
@@ -425,7 +421,6 @@ tty3270_update(struct tty3270 *tp) | |||
425 | xchg(&tp->write, wrq); | 421 | xchg(&tp->write, wrq); |
426 | } | 422 | } |
427 | spin_unlock(&tp->view.lock); | 423 | spin_unlock(&tp->view.lock); |
428 | raw3270_put_view(&tp->view); | ||
429 | } | 424 | } |
430 | 425 | ||
431 | /* | 426 | /* |
@@ -570,7 +565,6 @@ tty3270_read_tasklet(struct raw3270_request *rrq) | |||
570 | tty3270_set_timer(tp, 1); | 565 | tty3270_set_timer(tp, 1); |
571 | } else if (tp->input->string[0] == 0x6d) { | 566 | } else if (tp->input->string[0] == 0x6d) { |
572 | /* Display has been cleared. Redraw. */ | 567 | /* Display has been cleared. Redraw. */ |
573 | tty3270_rebuild_update(tp); | ||
574 | tp->update_flags = TTY_UPDATE_ALL; | 568 | tp->update_flags = TTY_UPDATE_ALL; |
575 | tty3270_set_timer(tp, 1); | 569 | tty3270_set_timer(tp, 1); |
576 | } | 570 | } |
@@ -641,22 +635,20 @@ static int | |||
641 | tty3270_activate(struct raw3270_view *view) | 635 | tty3270_activate(struct raw3270_view *view) |
642 | { | 636 | { |
643 | struct tty3270 *tp; | 637 | struct tty3270 *tp; |
644 | unsigned long flags; | ||
645 | 638 | ||
646 | tp = (struct tty3270 *) view; | 639 | tp = (struct tty3270 *) view; |
647 | spin_lock_irqsave(&tp->view.lock, flags); | ||
648 | tp->nr_up = 0; | ||
649 | tty3270_rebuild_update(tp); | ||
650 | tty3270_update_status(tp); | ||
651 | tp->update_flags = TTY_UPDATE_ALL; | 640 | tp->update_flags = TTY_UPDATE_ALL; |
652 | tty3270_set_timer(tp, 1); | 641 | tty3270_set_timer(tp, 1); |
653 | spin_unlock_irqrestore(&tp->view.lock, flags); | ||
654 | return 0; | 642 | return 0; |
655 | } | 643 | } |
656 | 644 | ||
657 | static void | 645 | static void |
658 | tty3270_deactivate(struct raw3270_view *view) | 646 | tty3270_deactivate(struct raw3270_view *view) |
659 | { | 647 | { |
648 | struct tty3270 *tp; | ||
649 | |||
650 | tp = (struct tty3270 *) view; | ||
651 | del_timer(&tp->timer); | ||
660 | } | 652 | } |
661 | 653 | ||
662 | static int | 654 | static int |
@@ -743,6 +735,7 @@ tty3270_free_view(struct tty3270 *tp) | |||
743 | { | 735 | { |
744 | int pages; | 736 | int pages; |
745 | 737 | ||
738 | del_timer_sync(&tp->timer); | ||
746 | kbd_free(tp->kbd); | 739 | kbd_free(tp->kbd); |
747 | raw3270_request_free(tp->kreset); | 740 | raw3270_request_free(tp->kreset); |
748 | raw3270_request_free(tp->read); | 741 | raw3270_request_free(tp->read); |
@@ -889,7 +882,8 @@ tty3270_open(struct tty_struct *tty, struct file * filp) | |||
889 | INIT_LIST_HEAD(&tp->update); | 882 | INIT_LIST_HEAD(&tp->update); |
890 | INIT_LIST_HEAD(&tp->rcl_lines); | 883 | INIT_LIST_HEAD(&tp->rcl_lines); |
891 | tp->rcl_max = 20; | 884 | tp->rcl_max = 20; |
892 | init_timer(&tp->timer); | 885 | setup_timer(&tp->timer, (void (*)(unsigned long)) tty3270_update, |
886 | (unsigned long) tp); | ||
893 | tasklet_init(&tp->readlet, | 887 | tasklet_init(&tp->readlet, |
894 | (void (*)(unsigned long)) tty3270_read_tasklet, | 888 | (void (*)(unsigned long)) tty3270_read_tasklet, |
895 | (unsigned long) tp->read); | 889 | (unsigned long) tp->read); |