Commit cd2ee4a30cc0775d8b54e5b958613361a7cacfec
Committed by
Linus Torvalds
1 parent
c578455a3e
Exists in
master
and in
4 other branches
[PATCH] uml: Fix SIGWINCH relaying
This makes SIGWINCH work again, and fixes a couple of SIGWINCH-associated crashes. First, the sigio thread disables SIGWINCH because all hell breaks loose if it ever gets one and tries to call the signal handling code. Second, there was a problem with deferencing tty structs after they were freed. The SIGWINCH support for a tty wasn't being turned off or freed after the tty went away. Signed-off-by: Jeff Dike <jdike@addtoit.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 8 changed files with 55 additions and 7 deletions Side-by-side Diff
arch/um/drivers/line.c
| ... | ... | @@ -462,12 +462,15 @@ |
| 462 | 462 | return err; |
| 463 | 463 | } |
| 464 | 464 | |
| 465 | +static void unregister_winch(struct tty_struct *tty); | |
| 466 | + | |
| 465 | 467 | void line_close(struct tty_struct *tty, struct file * filp) |
| 466 | 468 | { |
| 467 | 469 | struct line *line = tty->driver_data; |
| 468 | 470 | |
| 469 | - /* XXX: I assume this should be called in process context, not with interrupt | |
| 470 | - * disabled!*/ | |
| 471 | + /* XXX: I assume this should be called in process context, not with | |
| 472 | + * interrupts disabled! | |
| 473 | + */ | |
| 471 | 474 | spin_lock_irq(&line->lock); |
| 472 | 475 | |
| 473 | 476 | /* We ignore the error anyway! */ |
| ... | ... | @@ -478,6 +481,12 @@ |
| 478 | 481 | line_disable(tty, -1); |
| 479 | 482 | tty->driver_data = NULL; |
| 480 | 483 | } |
| 484 | + | |
| 485 | + if((line->count == 0) && line->sigio){ | |
| 486 | + unregister_winch(tty); | |
| 487 | + line->sigio = 0; | |
| 488 | + } | |
| 489 | + | |
| 481 | 490 | spin_unlock_irq(&line->lock); |
| 482 | 491 | } |
| 483 | 492 | |
| ... | ... | @@ -725,6 +734,34 @@ |
| 725 | 734 | SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, |
| 726 | 735 | "winch", winch) < 0) |
| 727 | 736 | printk("register_winch_irq - failed to register IRQ\n"); |
| 737 | + out: | |
| 738 | + up(&winch_handler_sem); | |
| 739 | +} | |
| 740 | + | |
| 741 | +static void unregister_winch(struct tty_struct *tty) | |
| 742 | +{ | |
| 743 | + struct list_head *ele; | |
| 744 | + struct winch *winch, *found = NULL; | |
| 745 | + | |
| 746 | + down(&winch_handler_sem); | |
| 747 | + list_for_each(ele, &winch_handlers){ | |
| 748 | + winch = list_entry(ele, struct winch, list); | |
| 749 | + if(winch->tty == tty){ | |
| 750 | + found = winch; | |
| 751 | + break; | |
| 752 | + } | |
| 753 | + } | |
| 754 | + | |
| 755 | + if(found == NULL) | |
| 756 | + goto out; | |
| 757 | + | |
| 758 | + if(winch->pid != -1) | |
| 759 | + os_kill_process(winch->pid, 1); | |
| 760 | + | |
| 761 | + free_irq_by_irq_and_dev(WINCH_IRQ, winch); | |
| 762 | + free_irq(WINCH_IRQ, winch); | |
| 763 | + list_del(&winch->list); | |
| 764 | + kfree(winch); | |
| 728 | 765 | out: |
| 729 | 766 | up(&winch_handler_sem); |
| 730 | 767 | } |
arch/um/include/os.h
| ... | ... | @@ -160,6 +160,7 @@ |
| 160 | 160 | extern void os_kill_ptraced_process(int pid, int reap_child); |
| 161 | 161 | extern void os_usr1_process(int pid); |
| 162 | 162 | extern int os_getpid(void); |
| 163 | +extern int os_getpgrp(void); | |
| 163 | 164 | |
| 164 | 165 | extern int os_map_memory(void *virt, int fd, unsigned long long off, |
| 165 | 166 | unsigned long len, int r, int w, int x); |
arch/um/kernel/irq.c
arch/um/kernel/process.c
| ... | ... | @@ -65,8 +65,6 @@ |
| 65 | 65 | SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); |
| 66 | 66 | set_handler(SIGBUS, (__sighandler_t) sig_handler, flags, |
| 67 | 67 | SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); |
| 68 | - set_handler(SIGWINCH, (__sighandler_t) sig_handler, flags, | |
| 69 | - SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); | |
| 70 | 68 | set_handler(SIGUSR2, (__sighandler_t) sig_handler, |
| 71 | 69 | flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); |
| 72 | 70 | signal(SIGHUP, SIG_IGN); |
arch/um/kernel/sigio_user.c
arch/um/kernel/skas/process.c
| ... | ... | @@ -28,10 +28,11 @@ |
| 28 | 28 | #include "chan_user.h" |
| 29 | 29 | #include "signal_user.h" |
| 30 | 30 | #include "registers.h" |
| 31 | +#include "process.h" | |
| 31 | 32 | |
| 32 | 33 | int is_skas_winch(int pid, int fd, void *data) |
| 33 | 34 | { |
| 34 | - if(pid != os_getpid()) | |
| 35 | + if(pid != os_getpgrp()) | |
| 35 | 36 | return(0); |
| 36 | 37 | |
| 37 | 38 | register_winch_irq(-1, fd, -1, data); |
| ... | ... | @@ -258,6 +259,10 @@ |
| 258 | 259 | { |
| 259 | 260 | sigjmp_buf **switch_buf = switch_buf_ptr; |
| 260 | 261 | int n; |
| 262 | + | |
| 263 | + set_handler(SIGWINCH, (__sighandler_t) sig_handler, | |
| 264 | + SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGALRM, | |
| 265 | + SIGVTALRM, -1); | |
| 261 | 266 | |
| 262 | 267 | *fork_buf_ptr = &initial_jmpbuf; |
| 263 | 268 | n = sigsetjmp(initial_jmpbuf, 1); |
arch/um/kernel/tt/tracer.c
| ... | ... | @@ -26,6 +26,7 @@ |
| 26 | 26 | #include "kern_util.h" |
| 27 | 27 | #include "chan_user.h" |
| 28 | 28 | #include "ptrace_user.h" |
| 29 | +#include "irq_user.h" | |
| 29 | 30 | #include "mode.h" |
| 30 | 31 | #include "tt.h" |
| 31 | 32 | |
| ... | ... | @@ -33,7 +34,7 @@ |
| 33 | 34 | |
| 34 | 35 | int is_tracer_winch(int pid, int fd, void *data) |
| 35 | 36 | { |
| 36 | - if(pid != tracing_pid) | |
| 37 | + if(pid != os_getpgrp()) | |
| 37 | 38 | return(0); |
| 38 | 39 | |
| 39 | 40 | register_winch_irq(tracer_winch[0], fd, -1, data); |
| ... | ... | @@ -119,6 +120,7 @@ |
| 119 | 120 | signal(SIGSEGV, (__sighandler_t) sig_handler); |
| 120 | 121 | set_cmdline("(idle thread)"); |
| 121 | 122 | set_init_pid(os_getpid()); |
| 123 | + init_irq_signals(0); | |
| 122 | 124 | proc = arg; |
| 123 | 125 | return((*proc)(NULL)); |
| 124 | 126 | } |
arch/um/os-Linux/process.c