Commit 7cf3cf21 authored by Al Viro's avatar Al Viro Committed by Linus Torvalds

um: fix free_winch() mess

while not doing free_irq() from irq handler is commendable, kfree() on the
data passed to said handler before free_irq() is Not Good(tm).  Freeing
the stack it's being run on is also not nice...  Solution: delay actually
freeing stuff.
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarRichard Weinberger <richard@nod.at>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 45cd5e2d
...@@ -721,43 +721,53 @@ struct winch { ...@@ -721,43 +721,53 @@ struct winch {
int pid; int pid;
struct tty_struct *tty; struct tty_struct *tty;
unsigned long stack; unsigned long stack;
struct work_struct work;
}; };
static void free_winch(struct winch *winch, int free_irq_ok) static void __free_winch(struct work_struct *work)
{ {
int fd = winch->fd; struct winch *winch = container_of(work, struct winch, work);
winch->fd = -1;
if (free_irq_ok)
free_irq(WINCH_IRQ, winch); free_irq(WINCH_IRQ, winch);
list_del(&winch->list);
if (winch->pid != -1) if (winch->pid != -1)
os_kill_process(winch->pid, 1); os_kill_process(winch->pid, 1);
if (fd != -1)
os_close_file(fd);
if (winch->stack != 0) if (winch->stack != 0)
free_stack(winch->stack, 0); free_stack(winch->stack, 0);
kfree(winch); kfree(winch);
} }
static void free_winch(struct winch *winch)
{
int fd = winch->fd;
winch->fd = -1;
if (fd != -1)
os_close_file(fd);
list_del(&winch->list);
__free_winch(&winch->work);
}
static irqreturn_t winch_interrupt(int irq, void *data) static irqreturn_t winch_interrupt(int irq, void *data)
{ {
struct winch *winch = data; struct winch *winch = data;
struct tty_struct *tty; struct tty_struct *tty;
struct line *line; struct line *line;
int fd = winch->fd;
int err; int err;
char c; char c;
if (winch->fd != -1) { if (fd != -1) {
err = generic_read(winch->fd, &c, NULL); err = generic_read(fd, &c, NULL);
if (err < 0) { if (err < 0) {
if (err != -EAGAIN) { if (err != -EAGAIN) {
winch->fd = -1;
list_del(&winch->list);
os_close_file(fd);
printk(KERN_ERR "winch_interrupt : " printk(KERN_ERR "winch_interrupt : "
"read failed, errno = %d\n", -err); "read failed, errno = %d\n", -err);
printk(KERN_ERR "fd %d is losing SIGWINCH " printk(KERN_ERR "fd %d is losing SIGWINCH "
"support\n", winch->tty_fd); "support\n", winch->tty_fd);
free_winch(winch, 0); INIT_WORK(&winch->work, __free_winch);
schedule_work(&winch->work);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
goto out; goto out;
...@@ -829,7 +839,7 @@ static void unregister_winch(struct tty_struct *tty) ...@@ -829,7 +839,7 @@ static void unregister_winch(struct tty_struct *tty)
list_for_each_safe(ele, next, &winch_handlers) { list_for_each_safe(ele, next, &winch_handlers) {
winch = list_entry(ele, struct winch, list); winch = list_entry(ele, struct winch, list);
if (winch->tty == tty) { if (winch->tty == tty) {
free_winch(winch, 1); free_winch(winch);
break; break;
} }
} }
...@@ -845,7 +855,7 @@ static void winch_cleanup(void) ...@@ -845,7 +855,7 @@ static void winch_cleanup(void)
list_for_each_safe(ele, next, &winch_handlers) { list_for_each_safe(ele, next, &winch_handlers) {
winch = list_entry(ele, struct winch, list); winch = list_entry(ele, struct winch, list);
free_winch(winch, 1); free_winch(winch);
} }
spin_unlock(&winch_handler_lock); spin_unlock(&winch_handler_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment