aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/drivers/chan_user.c
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/drivers/chan_user.c
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/drivers/chan_user.c')
-rw-r--r--arch/um/drivers/chan_user.c70
1 files changed, 38 insertions, 32 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}