mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
[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>
This commit is contained in:
parent
fcf7581f7c
commit
205d7ab9c9
2 changed files with 32 additions and 48 deletions
|
@ -64,7 +64,7 @@ static struct con3270 *condev;
|
|||
#define CON_UPDATE_ERASE 1 /* Use EWRITEA instead of WRITE. */
|
||||
#define CON_UPDATE_LIST 2 /* Update lines in tty3270->update. */
|
||||
#define CON_UPDATE_STATUS 4 /* Update status line. */
|
||||
#define CON_UPDATE_ALL 7
|
||||
#define CON_UPDATE_ALL 8 /* Recreate screen. */
|
||||
|
||||
static void con3270_update(struct con3270 *);
|
||||
|
||||
|
@ -73,18 +73,10 @@ static void con3270_update(struct con3270 *);
|
|||
*/
|
||||
static void con3270_set_timer(struct con3270 *cp, int expires)
|
||||
{
|
||||
if (expires == 0) {
|
||||
if (timer_pending(&cp->timer))
|
||||
del_timer(&cp->timer);
|
||||
return;
|
||||
}
|
||||
if (timer_pending(&cp->timer) &&
|
||||
mod_timer(&cp->timer, jiffies + expires))
|
||||
return;
|
||||
cp->timer.function = (void (*)(unsigned long)) con3270_update;
|
||||
cp->timer.data = (unsigned long) cp;
|
||||
cp->timer.expires = jiffies + expires;
|
||||
add_timer(&cp->timer);
|
||||
if (expires == 0)
|
||||
del_timer(&cp->timer);
|
||||
else
|
||||
mod_timer(&cp->timer, jiffies + expires);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -225,6 +217,12 @@ con3270_update(struct con3270 *cp)
|
|||
|
||||
spin_lock_irqsave(&cp->view.lock, flags);
|
||||
updated = 0;
|
||||
if (cp->update_flags & CON_UPDATE_ALL) {
|
||||
con3270_rebuild_update(cp);
|
||||
con3270_update_status(cp);
|
||||
cp->update_flags = CON_UPDATE_ERASE | CON_UPDATE_LIST |
|
||||
CON_UPDATE_STATUS;
|
||||
}
|
||||
if (cp->update_flags & CON_UPDATE_ERASE) {
|
||||
/* Use erase write alternate to initialize display. */
|
||||
raw3270_request_set_cmd(wrq, TC_EWRITEA);
|
||||
|
@ -302,7 +300,6 @@ con3270_read_tasklet(struct raw3270_request *rrq)
|
|||
deactivate = 1;
|
||||
break;
|
||||
case 0x6d: /* clear: start from scratch. */
|
||||
con3270_rebuild_update(cp);
|
||||
cp->update_flags = CON_UPDATE_ALL;
|
||||
con3270_set_timer(cp, 1);
|
||||
break;
|
||||
|
@ -382,30 +379,21 @@ con3270_issue_read(struct con3270 *cp)
|
|||
static int
|
||||
con3270_activate(struct raw3270_view *view)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct con3270 *cp;
|
||||
|
||||
cp = (struct con3270 *) view;
|
||||
spin_lock_irqsave(&cp->view.lock, flags);
|
||||
cp->nr_up = 0;
|
||||
con3270_rebuild_update(cp);
|
||||
con3270_update_status(cp);
|
||||
cp->update_flags = CON_UPDATE_ALL;
|
||||
con3270_set_timer(cp, 1);
|
||||
spin_unlock_irqrestore(&cp->view.lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
con3270_deactivate(struct raw3270_view *view)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct con3270 *cp;
|
||||
|
||||
cp = (struct con3270 *) view;
|
||||
spin_lock_irqsave(&cp->view.lock, flags);
|
||||
del_timer(&cp->timer);
|
||||
spin_unlock_irqrestore(&cp->view.lock, flags);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -504,6 +492,7 @@ con3270_write(struct console *co, const char *str, unsigned int count)
|
|||
con3270_cline_end(cp);
|
||||
}
|
||||
/* Setup timer to output current console buffer after 1/10 second */
|
||||
cp->nr_up = 0;
|
||||
if (cp->view.dev && !timer_pending(&cp->timer))
|
||||
con3270_set_timer(cp, HZ/10);
|
||||
spin_unlock_irqrestore(&cp->view.lock,flags);
|
||||
|
@ -624,7 +613,8 @@ con3270_init(void)
|
|||
|
||||
INIT_LIST_HEAD(&condev->lines);
|
||||
INIT_LIST_HEAD(&condev->update);
|
||||
init_timer(&condev->timer);
|
||||
setup_timer(&condev->timer, (void (*)(unsigned long)) con3270_update,
|
||||
(unsigned long) condev);
|
||||
tasklet_init(&condev->readlet,
|
||||
(void (*)(unsigned long)) con3270_read_tasklet,
|
||||
(unsigned long) condev->read);
|
||||
|
|
|
@ -112,7 +112,7 @@ struct tty3270 {
|
|||
#define TTY_UPDATE_LIST 2 /* Update lines in tty3270->update. */
|
||||
#define TTY_UPDATE_INPUT 4 /* Update input line. */
|
||||
#define TTY_UPDATE_STATUS 8 /* Update status line. */
|
||||
#define TTY_UPDATE_ALL 15
|
||||
#define TTY_UPDATE_ALL 16 /* Recreate screen. */
|
||||
|
||||
static void tty3270_update(struct tty3270 *);
|
||||
|
||||
|
@ -121,19 +121,10 @@ static void tty3270_update(struct tty3270 *);
|
|||
*/
|
||||
static void tty3270_set_timer(struct tty3270 *tp, int expires)
|
||||
{
|
||||
if (expires == 0) {
|
||||
if (timer_pending(&tp->timer) && del_timer(&tp->timer))
|
||||
raw3270_put_view(&tp->view);
|
||||
return;
|
||||
}
|
||||
if (timer_pending(&tp->timer) &&
|
||||
mod_timer(&tp->timer, jiffies + expires))
|
||||
return;
|
||||
raw3270_get_view(&tp->view);
|
||||
tp->timer.function = (void (*)(unsigned long)) tty3270_update;
|
||||
tp->timer.data = (unsigned long) tp;
|
||||
tp->timer.expires = jiffies + expires;
|
||||
add_timer(&tp->timer);
|
||||
if (expires == 0)
|
||||
del_timer(&tp->timer);
|
||||
else
|
||||
mod_timer(&tp->timer, jiffies + expires);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -337,7 +328,6 @@ tty3270_write_callback(struct raw3270_request *rq, void *data)
|
|||
tp = (struct tty3270 *) rq->view;
|
||||
if (rq->rc != 0) {
|
||||
/* Write wasn't successfull. Refresh all. */
|
||||
tty3270_rebuild_update(tp);
|
||||
tp->update_flags = TTY_UPDATE_ALL;
|
||||
tty3270_set_timer(tp, 1);
|
||||
}
|
||||
|
@ -366,6 +356,12 @@ tty3270_update(struct tty3270 *tp)
|
|||
|
||||
spin_lock(&tp->view.lock);
|
||||
updated = 0;
|
||||
if (tp->update_flags & TTY_UPDATE_ALL) {
|
||||
tty3270_rebuild_update(tp);
|
||||
tty3270_update_status(tp);
|
||||
tp->update_flags = TTY_UPDATE_ERASE | TTY_UPDATE_LIST |
|
||||
TTY_UPDATE_INPUT | TTY_UPDATE_STATUS;
|
||||
}
|
||||
if (tp->update_flags & TTY_UPDATE_ERASE) {
|
||||
/* Use erase write alternate to erase display. */
|
||||
raw3270_request_set_cmd(wrq, TC_EWRITEA);
|
||||
|
@ -425,7 +421,6 @@ tty3270_update(struct tty3270 *tp)
|
|||
xchg(&tp->write, wrq);
|
||||
}
|
||||
spin_unlock(&tp->view.lock);
|
||||
raw3270_put_view(&tp->view);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -570,7 +565,6 @@ tty3270_read_tasklet(struct raw3270_request *rrq)
|
|||
tty3270_set_timer(tp, 1);
|
||||
} else if (tp->input->string[0] == 0x6d) {
|
||||
/* Display has been cleared. Redraw. */
|
||||
tty3270_rebuild_update(tp);
|
||||
tp->update_flags = TTY_UPDATE_ALL;
|
||||
tty3270_set_timer(tp, 1);
|
||||
}
|
||||
|
@ -641,22 +635,20 @@ static int
|
|||
tty3270_activate(struct raw3270_view *view)
|
||||
{
|
||||
struct tty3270 *tp;
|
||||
unsigned long flags;
|
||||
|
||||
tp = (struct tty3270 *) view;
|
||||
spin_lock_irqsave(&tp->view.lock, flags);
|
||||
tp->nr_up = 0;
|
||||
tty3270_rebuild_update(tp);
|
||||
tty3270_update_status(tp);
|
||||
tp->update_flags = TTY_UPDATE_ALL;
|
||||
tty3270_set_timer(tp, 1);
|
||||
spin_unlock_irqrestore(&tp->view.lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
tty3270_deactivate(struct raw3270_view *view)
|
||||
{
|
||||
struct tty3270 *tp;
|
||||
|
||||
tp = (struct tty3270 *) view;
|
||||
del_timer(&tp->timer);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -743,6 +735,7 @@ tty3270_free_view(struct tty3270 *tp)
|
|||
{
|
||||
int pages;
|
||||
|
||||
del_timer_sync(&tp->timer);
|
||||
kbd_free(tp->kbd);
|
||||
raw3270_request_free(tp->kreset);
|
||||
raw3270_request_free(tp->read);
|
||||
|
@ -889,7 +882,8 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
|
|||
INIT_LIST_HEAD(&tp->update);
|
||||
INIT_LIST_HEAD(&tp->rcl_lines);
|
||||
tp->rcl_max = 20;
|
||||
init_timer(&tp->timer);
|
||||
setup_timer(&tp->timer, (void (*)(unsigned long)) tty3270_update,
|
||||
(unsigned long) tp);
|
||||
tasklet_init(&tp->readlet,
|
||||
(void (*)(unsigned long)) tty3270_read_tasklet,
|
||||
(unsigned long) tp->read);
|
||||
|
|
Loading…
Reference in a new issue