diff options
author | Jeff Dike <jdike@addtoit.com> | 2006-03-27 04:14:40 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-27 11:44:38 -0500 |
commit | 5f4e8fd08f3993bc31a7dd91767fdb4da4fe6278 (patch) | |
tree | 8bd66ec07c3051d6f6e09fc53c7f2bde20c3c67d /arch/um/os-Linux | |
parent | 1fbbd6844e6a84e5d166ab475dc298d3b89fa4bf (diff) |
[PATCH] uml: fix thread startup race
This fixes a race in the starting of write_sigio_thread. Previously, some of
the data needed by the thread was initialized after the clone. If the thread
ran immediately, it would see the uninitialized data, including an empty
pollfds, which would cause it to hang.
We move the data initialization to before the clone, and adjust the error
paths and cleanup accordingly.
Signed-off-by: Jeff Dike <jdike@addtoit.com>
Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/um/os-Linux')
-rw-r--r-- | arch/um/os-Linux/sigio.c | 55 |
1 files changed, 27 insertions, 28 deletions
diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c index 7604c404c4c2..9ba942947146 100644 --- a/arch/um/os-Linux/sigio.c +++ b/arch/um/os-Linux/sigio.c | |||
@@ -29,8 +29,10 @@ static int write_sigio_pid = -1; | |||
29 | * the descriptors closed after it is killed. So, it can't see them change. | 29 | * the descriptors closed after it is killed. So, it can't see them change. |
30 | * On the UML side, they are changed under the sigio_lock. | 30 | * On the UML side, they are changed under the sigio_lock. |
31 | */ | 31 | */ |
32 | static int write_sigio_fds[2] = { -1, -1 }; | 32 | #define SIGIO_FDS_INIT {-1, -1} |
33 | static int sigio_private[2] = { -1, -1 }; | 33 | |
34 | static int write_sigio_fds[2] = SIGIO_FDS_INIT; | ||
35 | static int sigio_private[2] = SIGIO_FDS_INIT; | ||
34 | 36 | ||
35 | struct pollfds { | 37 | struct pollfds { |
36 | struct pollfd *poll; | 38 | struct pollfd *poll; |
@@ -270,49 +272,46 @@ void write_sigio_workaround(void) | |||
270 | /* Did we race? Don't try to optimize this, please, it's not so likely | 272 | /* Did we race? Don't try to optimize this, please, it's not so likely |
271 | * to happen, and no more than once at the boot. */ | 273 | * to happen, and no more than once at the boot. */ |
272 | if(write_sigio_pid != -1) | 274 | if(write_sigio_pid != -1) |
273 | goto out_unlock; | 275 | goto out_free; |
274 | |||
275 | write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, | ||
276 | CLONE_FILES | CLONE_VM, &stack, 0); | ||
277 | 276 | ||
278 | if (write_sigio_pid < 0) | 277 | current_poll = ((struct pollfds) { .poll = p, |
279 | goto out_clear; | 278 | .used = 1, |
279 | .size = 1 }); | ||
280 | 280 | ||
281 | if (write_sigio_irq(l_write_sigio_fds[0])) | 281 | if (write_sigio_irq(l_write_sigio_fds[0])) |
282 | goto out_kill; | 282 | goto out_clear_poll; |
283 | 283 | ||
284 | /* Success, finally. */ | ||
285 | memcpy(write_sigio_fds, l_write_sigio_fds, sizeof(l_write_sigio_fds)); | 284 | memcpy(write_sigio_fds, l_write_sigio_fds, sizeof(l_write_sigio_fds)); |
286 | memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private)); | 285 | memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private)); |
287 | 286 | ||
288 | current_poll = ((struct pollfds) { .poll = p, | 287 | write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, |
289 | .used = 1, | 288 | CLONE_FILES | CLONE_VM, &stack, 0); |
290 | .size = 1 }); | ||
291 | 289 | ||
292 | sigio_unlock(); | 290 | if (write_sigio_pid < 0) |
293 | return; | 291 | goto out_clear; |
294 | 292 | ||
295 | out_kill: | ||
296 | l_write_sigio_pid = write_sigio_pid; | ||
297 | write_sigio_pid = -1; | ||
298 | sigio_unlock(); | 293 | sigio_unlock(); |
299 | /* Going to call waitpid, avoid holding the lock. */ | 294 | return; |
300 | os_kill_process(l_write_sigio_pid, 1); | ||
301 | goto out_free; | ||
302 | 295 | ||
303 | out_clear: | 296 | out_clear: |
304 | write_sigio_pid = -1; | 297 | write_sigio_pid = -1; |
305 | out_unlock: | 298 | write_sigio_fds[0] = -1; |
306 | sigio_unlock(); | 299 | write_sigio_fds[1] = -1; |
307 | out_free: | 300 | sigio_private[0] = -1; |
301 | sigio_private[1] = -1; | ||
302 | out_clear_poll: | ||
303 | current_poll = ((struct pollfds) { .poll = NULL, | ||
304 | .size = 0, | ||
305 | .used = 0 }); | ||
306 | out_free: | ||
308 | kfree(p); | 307 | kfree(p); |
309 | out_close2: | 308 | sigio_unlock(); |
309 | out_close2: | ||
310 | close(l_sigio_private[0]); | 310 | close(l_sigio_private[0]); |
311 | close(l_sigio_private[1]); | 311 | close(l_sigio_private[1]); |
312 | out_close1: | 312 | out_close1: |
313 | close(l_write_sigio_fds[0]); | 313 | close(l_write_sigio_fds[0]); |
314 | close(l_write_sigio_fds[1]); | 314 | close(l_write_sigio_fds[1]); |
315 | return; | ||
316 | } | 315 | } |
317 | 316 | ||
318 | void sigio_cleanup(void) | 317 | void sigio_cleanup(void) |