diff options
| author | Al Viro <viro@ftp.linux.org.uk> | 2011-09-14 19:21:31 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-09-14 21:09:37 -0400 |
| commit | 7cf3cf21aac7d75d27e8e7cd039bd33d19fb300d (patch) | |
| tree | 49cad391c87a4aec5f6941b4d93b2cccb94bc230 | |
| parent | 45cd5e2d4e632f55af1d6131f33b554c98f8b929 (diff) | |
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: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Richard Weinberger <richard@nod.at>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | arch/um/drivers/line.c | 38 |
1 files changed, 24 insertions, 14 deletions
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 91bf18941ca4..364c8a15c4c3 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c | |||
| @@ -721,43 +721,53 @@ struct winch { | |||
| 721 | int pid; | 721 | int pid; |
| 722 | struct tty_struct *tty; | 722 | struct tty_struct *tty; |
| 723 | unsigned long stack; | 723 | unsigned long stack; |
| 724 | struct work_struct work; | ||
| 724 | }; | 725 | }; |
| 725 | 726 | ||
| 726 | static void free_winch(struct winch *winch, int free_irq_ok) | 727 | static void __free_winch(struct work_struct *work) |
| 727 | { | 728 | { |
| 728 | int fd = winch->fd; | 729 | struct winch *winch = container_of(work, struct winch, work); |
| 729 | winch->fd = -1; | 730 | free_irq(WINCH_IRQ, winch); |
| 730 | if (free_irq_ok) | ||
| 731 | free_irq(WINCH_IRQ, winch); | ||
| 732 | |||
| 733 | list_del(&winch->list); | ||
| 734 | 731 | ||
| 735 | if (winch->pid != -1) | 732 | if (winch->pid != -1) |
| 736 | os_kill_process(winch->pid, 1); | 733 | os_kill_process(winch->pid, 1); |
| 737 | if (fd != -1) | ||
| 738 | os_close_file(fd); | ||
| 739 | if (winch->stack != 0) | 734 | if (winch->stack != 0) |
| 740 | free_stack(winch->stack, 0); | 735 | free_stack(winch->stack, 0); |
| 741 | kfree(winch); | 736 | kfree(winch); |
| 742 | } | 737 | } |
| 743 | 738 | ||
| 739 | static void free_winch(struct winch *winch) | ||
| 740 | { | ||
| 741 | int fd = winch->fd; | ||
| 742 | winch->fd = -1; | ||
| 743 | if (fd != -1) | ||
| 744 | os_close_file(fd); | ||
| 745 | list_del(&winch->list); | ||
| 746 | __free_winch(&winch->work); | ||
| 747 | } | ||
| 748 | |||
| 744 | static irqreturn_t winch_interrupt(int irq, void *data) | 749 | static irqreturn_t winch_interrupt(int irq, void *data) |
| 745 | { | 750 | { |
| 746 | struct winch *winch = data; | 751 | struct winch *winch = data; |
| 747 | struct tty_struct *tty; | 752 | struct tty_struct *tty; |
| 748 | struct line *line; | 753 | struct line *line; |
| 754 | int fd = winch->fd; | ||
| 749 | int err; | 755 | int err; |
| 750 | char c; | 756 | char c; |
| 751 | 757 | ||
| 752 | if (winch->fd != -1) { | 758 | if (fd != -1) { |
| 753 | err = generic_read(winch->fd, &c, NULL); | 759 | err = generic_read(fd, &c, NULL); |
| 754 | if (err < 0) { | 760 | if (err < 0) { |
| 755 | if (err != -EAGAIN) { | 761 | if (err != -EAGAIN) { |
| 762 | winch->fd = -1; | ||
| 763 | list_del(&winch->list); | ||
| 764 | os_close_file(fd); | ||
| 756 | printk(KERN_ERR "winch_interrupt : " | 765 | printk(KERN_ERR "winch_interrupt : " |
| 757 | "read failed, errno = %d\n", -err); | 766 | "read failed, errno = %d\n", -err); |
| 758 | printk(KERN_ERR "fd %d is losing SIGWINCH " | 767 | printk(KERN_ERR "fd %d is losing SIGWINCH " |
| 759 | "support\n", winch->tty_fd); | 768 | "support\n", winch->tty_fd); |
| 760 | free_winch(winch, 0); | 769 | INIT_WORK(&winch->work, __free_winch); |
| 770 | schedule_work(&winch->work); | ||
| 761 | return IRQ_HANDLED; | 771 | return IRQ_HANDLED; |
| 762 | } | 772 | } |
| 763 | goto out; | 773 | goto out; |
| @@ -829,7 +839,7 @@ static void unregister_winch(struct tty_struct *tty) | |||
| 829 | list_for_each_safe(ele, next, &winch_handlers) { | 839 | list_for_each_safe(ele, next, &winch_handlers) { |
| 830 | winch = list_entry(ele, struct winch, list); | 840 | winch = list_entry(ele, struct winch, list); |
| 831 | if (winch->tty == tty) { | 841 | if (winch->tty == tty) { |
| 832 | free_winch(winch, 1); | 842 | free_winch(winch); |
| 833 | break; | 843 | break; |
| 834 | } | 844 | } |
| 835 | } | 845 | } |
| @@ -845,7 +855,7 @@ static void winch_cleanup(void) | |||
| 845 | 855 | ||
| 846 | list_for_each_safe(ele, next, &winch_handlers) { | 856 | list_for_each_safe(ele, next, &winch_handlers) { |
| 847 | winch = list_entry(ele, struct winch, list); | 857 | winch = list_entry(ele, struct winch, list); |
| 848 | free_winch(winch, 1); | 858 | free_winch(winch); |
| 849 | } | 859 | } |
| 850 | 860 | ||
| 851 | spin_unlock(&winch_handler_lock); | 861 | spin_unlock(&winch_handler_lock); |
