diff options
Diffstat (limited to 'arch/um')
-rw-r--r-- | arch/um/drivers/chan_user.c | 70 | ||||
-rw-r--r-- | arch/um/drivers/line.c | 60 | ||||
-rw-r--r-- | arch/um/include/chan_user.h | 3 | ||||
-rw-r--r-- | arch/um/os-Linux/skas/process.c | 2 |
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 | ||
69 | static void winch_handler(int sig) | 71 | static 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 | ||
140 | static int winch_tramp(int fd, struct tty_struct *tty, int *fd_out) | 144 | static 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 | ||
188 | void register_winch(int fd, struct tty_struct *tty) | 194 | void 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 | ||
755 | static 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 | |||
754 | static irqreturn_t winch_interrupt(int irq, void *data) | 770 | static 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 | ||
788 | void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty) | 805 | void 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 | |||
814 | static 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 | ||
827 | static void unregister_winch(struct tty_struct *tty) | 845 | static 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 | ||
43 | struct tty_struct; | 43 | struct tty_struct; |
44 | extern void register_winch(int fd, struct tty_struct *tty); | 44 | extern void register_winch(int fd, struct tty_struct *tty); |
45 | extern void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty); | 45 | extern 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 | ||