diff options
| -rw-r--r-- | arch/um/kernel/sigio_user.c | 83 |
1 files changed, 58 insertions, 25 deletions
diff --git a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c index 62e5cfdf2188..f7b18e157d35 100644 --- a/arch/um/kernel/sigio_user.c +++ b/arch/um/kernel/sigio_user.c | |||
| @@ -337,70 +337,103 @@ int ignore_sigio_fd(int fd) | |||
| 337 | return(err); | 337 | return(err); |
| 338 | } | 338 | } |
| 339 | 339 | ||
| 340 | static int setup_initial_poll(int fd) | 340 | static struct pollfd* setup_initial_poll(int fd) |
| 341 | { | 341 | { |
| 342 | struct pollfd *p; | 342 | struct pollfd *p; |
| 343 | 343 | ||
| 344 | p = um_kmalloc_atomic(sizeof(struct pollfd)); | 344 | p = um_kmalloc(sizeof(struct pollfd)); |
| 345 | if(p == NULL){ | 345 | if (p == NULL) { |
| 346 | printk("setup_initial_poll : failed to allocate poll\n"); | 346 | printk("setup_initial_poll : failed to allocate poll\n"); |
| 347 | return(-1); | 347 | return NULL; |
| 348 | } | 348 | } |
| 349 | *p = ((struct pollfd) { .fd = fd, | 349 | *p = ((struct pollfd) { .fd = fd, |
| 350 | .events = POLLIN, | 350 | .events = POLLIN, |
| 351 | .revents = 0 }); | 351 | .revents = 0 }); |
| 352 | current_poll = ((struct pollfds) { .poll = p, | 352 | return p; |
| 353 | .used = 1, | ||
| 354 | .size = 1 }); | ||
| 355 | return(0); | ||
| 356 | } | 353 | } |
| 357 | 354 | ||
| 358 | void write_sigio_workaround(void) | 355 | void write_sigio_workaround(void) |
| 359 | { | 356 | { |
| 360 | unsigned long stack; | 357 | unsigned long stack; |
| 358 | struct pollfd *p; | ||
| 361 | int err; | 359 | int err; |
| 360 | int l_write_sigio_fds[2]; | ||
| 361 | int l_sigio_private[2]; | ||
| 362 | int l_write_sigio_pid; | ||
| 362 | 363 | ||
| 364 | /* We call this *tons* of times - and most ones we must just fail. */ | ||
| 363 | sigio_lock(); | 365 | sigio_lock(); |
| 364 | if(write_sigio_pid != -1) | 366 | l_write_sigio_pid = write_sigio_pid; |
| 365 | goto out; | 367 | sigio_unlock(); |
| 366 | 368 | ||
| 367 | err = os_pipe(write_sigio_fds, 1, 1); | 369 | if (l_write_sigio_pid != -1) |
| 370 | return; | ||
| 371 | |||
| 372 | err = os_pipe(l_write_sigio_fds, 1, 1); | ||
| 368 | if(err < 0){ | 373 | if(err < 0){ |
| 369 | printk("write_sigio_workaround - os_pipe 1 failed, " | 374 | printk("write_sigio_workaround - os_pipe 1 failed, " |
| 370 | "err = %d\n", -err); | 375 | "err = %d\n", -err); |
| 371 | goto out; | 376 | return; |
| 372 | } | 377 | } |
| 373 | err = os_pipe(sigio_private, 1, 1); | 378 | err = os_pipe(l_sigio_private, 1, 1); |
| 374 | if(err < 0){ | 379 | if(err < 0){ |
| 375 | printk("write_sigio_workaround - os_pipe 2 failed, " | 380 | printk("write_sigio_workaround - os_pipe 1 failed, " |
| 376 | "err = %d\n", -err); | 381 | "err = %d\n", -err); |
| 377 | goto out_close1; | 382 | goto out_close1; |
| 378 | } | 383 | } |
| 379 | if(setup_initial_poll(sigio_private[1])) | 384 | |
| 385 | p = setup_initial_poll(l_sigio_private[1]); | ||
| 386 | if(!p) | ||
| 380 | goto out_close2; | 387 | goto out_close2; |
| 381 | 388 | ||
| 382 | write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, | 389 | sigio_lock(); |
| 390 | |||
| 391 | /* Did we race? Don't try to optimize this, please, it's not so likely | ||
| 392 | * to happen, and no more than once at the boot. */ | ||
| 393 | if(write_sigio_pid != -1) | ||
| 394 | goto out_unlock; | ||
| 395 | |||
| 396 | write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, | ||
| 383 | CLONE_FILES | CLONE_VM, &stack, 0); | 397 | CLONE_FILES | CLONE_VM, &stack, 0); |
| 384 | 398 | ||
| 385 | if(write_sigio_pid < 0) goto out_close2; | 399 | if (write_sigio_pid < 0) |
| 400 | goto out_clear; | ||
| 386 | 401 | ||
| 387 | if(write_sigio_irq(write_sigio_fds[0])) | 402 | if (write_sigio_irq(l_write_sigio_fds[0])) |
| 388 | goto out_kill; | 403 | goto out_kill; |
| 389 | 404 | ||
| 390 | out: | 405 | /* Success, finally. */ |
| 406 | memcpy(write_sigio_fds, l_write_sigio_fds, sizeof(l_write_sigio_fds)); | ||
| 407 | memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private)); | ||
| 408 | |||
| 409 | current_poll = ((struct pollfds) { .poll = p, | ||
| 410 | .used = 1, | ||
| 411 | .size = 1 }); | ||
| 412 | |||
| 391 | sigio_unlock(); | 413 | sigio_unlock(); |
| 392 | return; | 414 | return; |
| 393 | 415 | ||
| 394 | out_kill: | 416 | out_kill: |
| 395 | os_kill_process(write_sigio_pid, 1); | 417 | l_write_sigio_pid = write_sigio_pid; |
| 396 | write_sigio_pid = -1; | 418 | write_sigio_pid = -1; |
| 419 | sigio_unlock(); | ||
| 420 | /* Going to call waitpid, avoid holding the lock. */ | ||
| 421 | os_kill_process(l_write_sigio_pid, 1); | ||
| 422 | goto out_free; | ||
| 423 | |||
| 424 | out_clear: | ||
| 425 | write_sigio_pid = -1; | ||
| 426 | out_unlock: | ||
| 427 | sigio_unlock(); | ||
| 428 | out_free: | ||
| 429 | kfree(p); | ||
| 397 | out_close2: | 430 | out_close2: |
| 398 | os_close_file(sigio_private[0]); | 431 | os_close_file(l_sigio_private[0]); |
| 399 | os_close_file(sigio_private[1]); | 432 | os_close_file(l_sigio_private[1]); |
| 400 | out_close1: | 433 | out_close1: |
| 401 | os_close_file(write_sigio_fds[0]); | 434 | os_close_file(l_write_sigio_fds[0]); |
| 402 | os_close_file(write_sigio_fds[1]); | 435 | os_close_file(l_write_sigio_fds[1]); |
| 403 | sigio_unlock(); | 436 | return; |
| 404 | } | 437 | } |
| 405 | 438 | ||
| 406 | int read_sigio_fd(int fd) | 439 | int read_sigio_fd(int fd) |
