[S390] 3270: lock dependency fixes
authorMartin Schwidefsky <schwidefsky@de.ibm.com>
Fri, 12 Jun 2009 08:26:31 +0000 (10:26 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Fri, 12 Jun 2009 08:27:33 +0000 (10:27 +0200)
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>
drivers/s390/char/con3270.c
drivers/s390/char/tty3270.c

index d028d2ee83dd36a3dff91061fbfc8d830eca3470..ed5396dae58eef0edc2eb6f451419737c0b5dfd7 100644 (file)
@@ -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);
index aa7a114f652958a4f00d8a854e518955460e3c98..38385677c65380e45730b42b8af38d78c9f8ac50 100644 (file)
@@ -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);