aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/drivers
diff options
context:
space:
mode:
authorAl Viro <viro@ftp.linux.org.uk>2011-09-14 19:21:31 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-09-14 21:09:37 -0400
commit7cf3cf21aac7d75d27e8e7cd039bd33d19fb300d (patch)
tree49cad391c87a4aec5f6941b4d93b2cccb94bc230 /arch/um/drivers
parent45cd5e2d4e632f55af1d6131f33b554c98f8b929 (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.c38
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
726static void free_winch(struct winch *winch, int free_irq_ok) 727static 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
739static 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
744static irqreturn_t winch_interrupt(int irq, void *data) 749static 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);