aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/um/drivers/chan_user.c70
-rw-r--r--arch/um/drivers/line.c60
-rw-r--r--arch/um/include/chan_user.h3
-rw-r--r--arch/um/os-Linux/skas/process.c2
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
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}
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
755static 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
754static irqreturn_t winch_interrupt(int irq, void *data) 770static 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
788void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty) 805void 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
814static 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
827static void unregister_winch(struct tty_struct *tty) 845static 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
43struct tty_struct; 43struct tty_struct;
44extern void register_winch(int fd, struct tty_struct *tty); 44extern void register_winch(int fd, struct tty_struct *tty);
45extern void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty); 45extern 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