aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um
diff options
context:
space:
mode:
authorJeff Dike <jdike@addtoit.com>2007-07-16 02:38:55 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-16 12:05:38 -0400
commit42a359e31a0e438b5b978a8f0fecdbd3c86bb033 (patch)
treefc6a6a11e1187e163ba694bf4ab5cf48aa528f34 /arch/um
parentd14ad81f800a57d3f21f8e98556c728968883e9a (diff)
uml: SIGIO support cleanup
Cleanup of the SIGWINCH support. Some code and comment reformatting. The stack used for SIGWINCH threads was leaked. This is now fixed by storing it with the pid and other information, and freeing it when the thread is killed. If something goes wrong with a WIGWINCH thread, and this is discovered in the interrupt handler, the winch record would leak. It is now freed, except that the IRQ isn't freed. This is hard to do from interrupt context. This has the side-effect that the IRQ system maintains a reference to the freed structure, but that shouldn't cause a problem since the descriptor is disabled. register_winch_irq is now much better about cleaning up after an initialization failure. Signed-off-by: Jeff Dike <jdike@linux.intel.com> Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/um')
-rw-r--r--arch/um/drivers/chan_user.c70
-rw-r--r--arch/um/drivers/line.c60
-rw-r--r--arch/um/include/chan_user.h3
-rw-r--r--arch/um/os-Linux/skas/process.c2
4 files changed, 80 insertions, 55 deletions
diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c
index 5d1289d33410..8b81bd5f20f2 100644
--- a/arch/um/drivers/chan_user.c
+++ b/arch/um/drivers/chan_user.c
@@ -51,19 +51,21 @@ error:
51/* 51/*
52 * UML SIGWINCH handling 52 * UML SIGWINCH handling
53 * 53 *
54 * The point of this is to handle SIGWINCH on consoles which have host ttys and 54 * The point of this is to handle SIGWINCH on consoles which have host
55 * relay them inside UML to whatever might be running on the console and cares 55 * ttys and relay them inside UML to whatever might be running on the
56 * about the window size (since SIGWINCH notifies about terminal size changes). 56 * console and cares about the window size (since SIGWINCH notifies
57 * about terminal size changes).
57 * 58 *
58 * So, we have a separate thread for each host tty attached to a UML device 59 * So, we have a separate thread for each host tty attached to a UML
59 * (side-issue - I'm annoyed that one thread can't have multiple controlling 60 * device (side-issue - I'm annoyed that one thread can't have
60 * ttys for purposed of handling SIGWINCH, but I imagine there are other reasons 61 * multiple controlling ttys for the purpose of handling SIGWINCH, but
61 * that doesn't make any sense). 62 * I imagine there are other reasons that doesn't make any sense).
62 * 63 *
63 * SIGWINCH can't be received synchronously, so you have to set up to receive it 64 * SIGWINCH can't be received synchronously, so you have to set up to
64 * as a signal. That being the case, if you are going to wait for it, it is 65 * receive it as a signal. That being the case, if you are going to
65 * convenient to sit in sigsuspend() and wait for the signal to bounce you out of 66 * wait for it, it is convenient to sit in sigsuspend() and wait for
66 * it (see below for how we make sure to exit only on SIGWINCH). 67 * the signal to bounce you out of it (see below for how we make sure
68 * to exit only on SIGWINCH).
67 */ 69 */
68 70
69static void winch_handler(int sig) 71static void winch_handler(int sig)
@@ -112,7 +114,8 @@ static int winch_thread(void *arg)
112 114
113 err = os_new_tty_pgrp(pty_fd, os_getpid()); 115 err = os_new_tty_pgrp(pty_fd, os_getpid());
114 if(err < 0){ 116 if(err < 0){
115 printk("winch_thread : new_tty_pgrp failed, err = %d\n", -err); 117 printk("winch_thread : new_tty_pgrp failed on fd %d, "
118 "err = %d\n", pty_fd, -err);
116 exit(1); 119 exit(1);
117 } 120 }
118 121
@@ -126,8 +129,9 @@ static int winch_thread(void *arg)
126 "err = %d\n", -count); 129 "err = %d\n", -count);
127 130
128 while(1){ 131 while(1){
129 /* This will be interrupted by SIGWINCH only, since other signals 132 /* This will be interrupted by SIGWINCH only, since
130 * are blocked.*/ 133 * other signals are blocked.
134 */
131 sigsuspend(&sigs); 135 sigsuspend(&sigs);
132 136
133 count = os_write_file(pipe_fd, &c, sizeof(c)); 137 count = os_write_file(pipe_fd, &c, sizeof(c));
@@ -137,10 +141,10 @@ static int winch_thread(void *arg)
137 } 141 }
138} 142}
139 143
140static int winch_tramp(int fd, struct tty_struct *tty, int *fd_out) 144static int winch_tramp(int fd, struct tty_struct *tty, int *fd_out,
145 unsigned long *stack_out)
141{ 146{
142 struct winch_data data; 147 struct winch_data data;
143 unsigned long stack;
144 int fds[2], n, err; 148 int fds[2], n, err;
145 char c; 149 char c;
146 150
@@ -153,9 +157,11 @@ static int winch_tramp(int fd, struct tty_struct *tty, int *fd_out)
153 data = ((struct winch_data) { .pty_fd = fd, 157 data = ((struct winch_data) { .pty_fd = fd,
154 .pipe_fd = fds[1] } ); 158 .pipe_fd = fds[1] } );
155 /* CLONE_FILES so this thread doesn't hold open files which are open 159 /* CLONE_FILES so this thread doesn't hold open files which are open
156 * now, but later closed. This is a problem with /dev/net/tun. 160 * now, but later closed in a different thread. This is a
161 * problem with /dev/net/tun, which if held open by this
162 * thread, prevents the TUN/TAP device from being reused.
157 */ 163 */
158 err = run_helper_thread(winch_thread, &data, CLONE_FILES, &stack, 0); 164 err = run_helper_thread(winch_thread, &data, CLONE_FILES, stack_out, 0);
159 if(err < 0){ 165 if(err < 0){
160 printk("fork of winch_thread failed - errno = %d\n", -err); 166 printk("fork of winch_thread failed - errno = %d\n", -err);
161 goto out_close; 167 goto out_close;
@@ -187,25 +193,25 @@ static int winch_tramp(int fd, struct tty_struct *tty, int *fd_out)
187 193
188void register_winch(int fd, struct tty_struct *tty) 194void register_winch(int fd, struct tty_struct *tty)
189{ 195{
190 int pid, thread, thread_fd = -1; 196 unsigned long stack;
191 int count; 197 int pid, thread, count, thread_fd = -1;
192 char c = 1; 198 char c = 1;
193 199
194 if(!isatty(fd)) 200 if(!isatty(fd))
195 return; 201 return;
196 202
197 pid = tcgetpgrp(fd); 203 pid = tcgetpgrp(fd);
198 if(!CHOOSE_MODE_PROC(is_tracer_winch, is_skas_winch, pid, fd, 204 if (!CHOOSE_MODE_PROC(is_tracer_winch, is_skas_winch, pid, fd, tty) &&
199 tty) && (pid == -1)){ 205 (pid == -1)) {
200 thread = winch_tramp(fd, tty, &thread_fd); 206 thread = winch_tramp(fd, tty, &thread_fd, &stack);
201 if(thread > 0){ 207 if (thread < 0)
202 register_winch_irq(thread_fd, fd, thread, tty); 208 return;
203 209
204 count = os_write_file(thread_fd, &c, sizeof(c)); 210 register_winch_irq(thread_fd, fd, thread, tty, stack);
205 if(count != sizeof(c)) 211
206 printk("register_winch : failed to write " 212 count = os_write_file(thread_fd, &c, sizeof(c));
207 "synchronization byte, err = %d\n", 213 if(count != sizeof(c))
208 -count); 214 printk("register_winch : failed to write "
209 } 215 "synchronization byte, err = %d\n", -count);
210 } 216 }
211} 217}
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index 1fb3e51108b9..3e0b68e297f2 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -749,8 +749,24 @@ struct winch {
749 int tty_fd; 749 int tty_fd;
750 int pid; 750 int pid;
751 struct tty_struct *tty; 751 struct tty_struct *tty;
752 unsigned long stack;
752}; 753};
753 754
755static void free_winch(struct winch *winch, int free_irq_ok)
756{
757 list_del(&winch->list);
758
759 if (winch->pid != -1)
760 os_kill_process(winch->pid, 1);
761 if (winch->fd != -1)
762 os_close_file(winch->fd);
763 if (winch->stack != 0)
764 free_stack(winch->stack, 0);
765 if (free_irq_ok)
766 free_irq(WINCH_IRQ, winch);
767 kfree(winch);
768}
769
754static irqreturn_t winch_interrupt(int irq, void *data) 770static irqreturn_t winch_interrupt(int irq, void *data)
755{ 771{
756 struct winch *winch = data; 772 struct winch *winch = data;
@@ -767,12 +783,13 @@ static irqreturn_t winch_interrupt(int irq, void *data)
767 "errno = %d\n", -err); 783 "errno = %d\n", -err);
768 printk("fd %d is losing SIGWINCH support\n", 784 printk("fd %d is losing SIGWINCH support\n",
769 winch->tty_fd); 785 winch->tty_fd);
786 free_winch(winch, 0);
770 return IRQ_HANDLED; 787 return IRQ_HANDLED;
771 } 788 }
772 goto out; 789 goto out;
773 } 790 }
774 } 791 }
775 tty = winch->tty; 792 tty = winch->tty;
776 if (tty != NULL) { 793 if (tty != NULL) {
777 line = tty->driver_data; 794 line = tty->driver_data;
778 chan_window_size(&line->chan_list, &tty->winsize.ws_row, 795 chan_window_size(&line->chan_list, &tty->winsize.ws_row,
@@ -785,43 +802,44 @@ static irqreturn_t winch_interrupt(int irq, void *data)
785 return IRQ_HANDLED; 802 return IRQ_HANDLED;
786} 803}
787 804
788void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty) 805void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty,
806 unsigned long stack)
789{ 807{
790 struct winch *winch; 808 struct winch *winch;
791 809
792 winch = kmalloc(sizeof(*winch), GFP_KERNEL); 810 winch = kmalloc(sizeof(*winch), GFP_KERNEL);
793 if (winch == NULL) { 811 if (winch == NULL) {
794 printk("register_winch_irq - kmalloc failed\n"); 812 printk("register_winch_irq - kmalloc failed\n");
795 return; 813 goto cleanup;
796 } 814 }
797 815
798 *winch = ((struct winch) { .list = LIST_HEAD_INIT(winch->list), 816 *winch = ((struct winch) { .list = LIST_HEAD_INIT(winch->list),
799 .fd = fd, 817 .fd = fd,
800 .tty_fd = tty_fd, 818 .tty_fd = tty_fd,
801 .pid = pid, 819 .pid = pid,
802 .tty = tty }); 820 .tty = tty,
821 .stack = stack });
822
823 if (um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt,
824 IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM,
825 "winch", winch) < 0) {
826 printk("register_winch_irq - failed to register IRQ\n");
827 goto out_free;
828 }
803 829
804 spin_lock(&winch_handler_lock); 830 spin_lock(&winch_handler_lock);
805 list_add(&winch->list, &winch_handlers); 831 list_add(&winch->list, &winch_handlers);
806 spin_unlock(&winch_handler_lock); 832 spin_unlock(&winch_handler_lock);
807 833
808 if(um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt, 834 return;
809 IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM,
810 "winch", winch) < 0)
811 printk("register_winch_irq - failed to register IRQ\n");
812}
813
814static void free_winch(struct winch *winch)
815{
816 list_del(&winch->list);
817
818 if(winch->pid != -1)
819 os_kill_process(winch->pid, 1);
820 if(winch->fd != -1)
821 os_close_file(winch->fd);
822 835
823 free_irq(WINCH_IRQ, winch); 836 out_free:
824 kfree(winch); 837 kfree(winch);
838 cleanup:
839 os_kill_process(pid, 1);
840 os_close_file(fd);
841 if (stack != 0)
842 free_stack(stack, 0);
825} 843}
826 844
827static void unregister_winch(struct tty_struct *tty) 845static void unregister_winch(struct tty_struct *tty)
@@ -834,7 +852,7 @@ static void unregister_winch(struct tty_struct *tty)
834 list_for_each(ele, &winch_handlers){ 852 list_for_each(ele, &winch_handlers){
835 winch = list_entry(ele, struct winch, list); 853 winch = list_entry(ele, struct winch, list);
836 if(winch->tty == tty){ 854 if(winch->tty == tty){
837 free_winch(winch); 855 free_winch(winch, 1);
838 break; 856 break;
839 } 857 }
840 } 858 }
@@ -850,7 +868,7 @@ static void winch_cleanup(void)
850 868
851 list_for_each_safe(ele, next, &winch_handlers){ 869 list_for_each_safe(ele, next, &winch_handlers){
852 winch = list_entry(ele, struct winch, list); 870 winch = list_entry(ele, struct winch, list);
853 free_winch(winch); 871 free_winch(winch, 1);
854 } 872 }
855 873
856 spin_unlock(&winch_handler_lock); 874 spin_unlock(&winch_handler_lock);
diff --git a/arch/um/include/chan_user.h b/arch/um/include/chan_user.h
index 714b713e2e72..5a2263e05bb2 100644
--- a/arch/um/include/chan_user.h
+++ b/arch/um/include/chan_user.h
@@ -42,7 +42,8 @@ extern void generic_free(void *data);
42 42
43struct tty_struct; 43struct tty_struct;
44extern void register_winch(int fd, struct tty_struct *tty); 44extern void register_winch(int fd, struct tty_struct *tty);
45extern void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty); 45extern void register_winch_irq(int fd, int tty_fd, int pid,
46 struct tty_struct *tty, unsigned long stack);
46 47
47#define __channel_help(fn, prefix) \ 48#define __channel_help(fn, prefix) \
48__uml_help(fn, prefix "[0-9]*=<channel description>\n" \ 49__uml_help(fn, prefix "[0-9]*=<channel description>\n" \
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c
index 46c00cc429bc..ba9af8d62055 100644
--- a/arch/um/os-Linux/skas/process.c
+++ b/arch/um/os-Linux/skas/process.c
@@ -41,7 +41,7 @@ int is_skas_winch(int pid, int fd, void *data)
41 if(pid != os_getpgrp()) 41 if(pid != os_getpgrp())
42 return(0); 42 return(0);
43 43
44 register_winch_irq(-1, fd, -1, data); 44 register_winch_irq(-1, fd, -1, data, 0);
45 return(1); 45 return(1);
46} 46}
47 47