From cd2ee4a30cc0775d8b54e5b958613361a7cacfec Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Thu, 5 May 2005 16:15:32 -0700 Subject: [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 Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/drivers/line.c | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) (limited to 'arch/um/drivers') diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index d0f97127adf6..025d3be8aca4 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -462,12 +462,15 @@ out: 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 @@ void line_close(struct tty_struct *tty, struct file * filp) 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 @@ void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty) 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; -- cgit v1.2.3