[PATCH] uml: Fix SIGWINCH relaying

This makes SIGWINCH work again, and fixes a couple of SIGWINCH-associated
crashes.  First, the sigio thread disables SIGWINCH because all hell breaks
loose if it ever gets one and tries to call the signal handling code.  Second,
there was a problem with deferencing tty structs after they were freed.  The
SIGWINCH support for a tty wasn't being turned off or freed after the tty went
away.

Signed-off-by: Jeff Dike <jdike@addtoit.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index d0f9712..025d3be 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -462,12 +462,15 @@
 	return err;
 }
 
+static void unregister_winch(struct tty_struct *tty);
+
 void line_close(struct tty_struct *tty, struct file * filp)
 {
 	struct line *line = tty->driver_data;
 
-	/* XXX: I assume this should be called in process context, not with interrupt
-	 * disabled!*/
+	/* XXX: I assume this should be called in process context, not with
+         *  interrupts disabled!
+         */
 	spin_lock_irq(&line->lock);
 
 	/* We ignore the error anyway! */
@@ -478,6 +481,12 @@
 		line_disable(tty, -1);
 		tty->driver_data = NULL;
 	}
+
+        if((line->count == 0) && line->sigio){
+                unregister_winch(tty);
+                line->sigio = 0;
+        }
+
 	spin_unlock_irq(&line->lock);
 }
 
@@ -729,6 +738,34 @@
 	up(&winch_handler_sem);
 }
 
+static void unregister_winch(struct tty_struct *tty)
+{
+	struct list_head *ele;
+	struct winch *winch, *found = NULL;
+
+	down(&winch_handler_sem);
+	list_for_each(ele, &winch_handlers){
+		winch = list_entry(ele, struct winch, list);
+                if(winch->tty == tty){
+                        found = winch;
+                        break;
+                }
+        }
+
+        if(found == NULL)
+                goto out;
+
+        if(winch->pid != -1)
+                os_kill_process(winch->pid, 1);
+
+        free_irq_by_irq_and_dev(WINCH_IRQ, winch);
+        free_irq(WINCH_IRQ, winch);
+        list_del(&winch->list);
+        kfree(winch);
+ out:
+	up(&winch_handler_sem);
+}
+
 static void winch_cleanup(void)
 {
 	struct list_head *ele;