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 /arch/um/drivers | |
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>
Diffstat (limited to 'arch/um/drivers')
-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); |