diff options
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/pty.c | 57 | ||||
-rw-r--r-- | drivers/char/tty_io.c | 2 | ||||
-rw-r--r-- | drivers/char/tty_ioctl.c | 5 | ||||
-rw-r--r-- | drivers/char/tty_ldisc.c | 3 |
4 files changed, 50 insertions, 17 deletions
diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 3910ce112a95..daebe1ba43d4 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c | |||
@@ -95,23 +95,34 @@ static void pty_unthrottle(struct tty_struct *tty) | |||
95 | * a count. | 95 | * a count. |
96 | * | 96 | * |
97 | * FIXME: Our pty_write method is called with our ldisc lock held but | 97 | * FIXME: Our pty_write method is called with our ldisc lock held but |
98 | * not our partners. We can't just take the other one blindly without | 98 | * not our partners. We can't just wait on the other one blindly without |
99 | * risking deadlocks. | 99 | * risking deadlocks. At some point when everything has settled down we need |
100 | * to look into making pty_write at least able to sleep over an ldisc change. | ||
101 | * | ||
102 | * The return on no ldisc is a bit counter intuitive but the logic works | ||
103 | * like this. During an ldisc change the other end will flush its buffers. We | ||
104 | * thus return the full length which is identical to the case where we had | ||
105 | * proper locking and happened to queue the bytes just before the flush during | ||
106 | * the ldisc change. | ||
100 | */ | 107 | */ |
101 | static int pty_write(struct tty_struct *tty, const unsigned char *buf, | 108 | static int pty_write(struct tty_struct *tty, const unsigned char *buf, |
102 | int count) | 109 | int count) |
103 | { | 110 | { |
104 | struct tty_struct *to = tty->link; | 111 | struct tty_struct *to = tty->link; |
105 | int c; | 112 | struct tty_ldisc *ld; |
113 | int c = count; | ||
106 | 114 | ||
107 | if (!to || !to->ldisc || tty->stopped) | 115 | if (!to || tty->stopped) |
108 | return 0; | 116 | return 0; |
109 | 117 | ld = tty_ldisc_ref(to); | |
110 | c = to->receive_room; | 118 | |
111 | if (c > count) | 119 | if (ld) { |
112 | c = count; | 120 | c = to->receive_room; |
113 | to->ldisc->ops->receive_buf(to, buf, NULL, c); | 121 | if (c > count) |
114 | 122 | c = count; | |
123 | ld->ops->receive_buf(to, buf, NULL, c); | ||
124 | tty_ldisc_deref(ld); | ||
125 | } | ||
115 | return c; | 126 | return c; |
116 | } | 127 | } |
117 | 128 | ||
@@ -145,14 +156,23 @@ static int pty_write_room(struct tty_struct *tty) | |||
145 | static int pty_chars_in_buffer(struct tty_struct *tty) | 156 | static int pty_chars_in_buffer(struct tty_struct *tty) |
146 | { | 157 | { |
147 | struct tty_struct *to = tty->link; | 158 | struct tty_struct *to = tty->link; |
148 | int count; | 159 | struct tty_ldisc *ld; |
160 | int count = 0; | ||
149 | 161 | ||
150 | /* We should get the line discipline lock for "tty->link" */ | 162 | /* We should get the line discipline lock for "tty->link" */ |
151 | if (!to || !to->ldisc || !to->ldisc->ops->chars_in_buffer) | 163 | if (!to) |
164 | return 0; | ||
165 | /* We cannot take a sleeping reference here without deadlocking with | ||
166 | an ldisc change - but it doesn't really matter */ | ||
167 | ld = tty_ldisc_ref(to); | ||
168 | if (ld == NULL) | ||
152 | return 0; | 169 | return 0; |
153 | 170 | ||
154 | /* The ldisc must report 0 if no characters available to be read */ | 171 | /* The ldisc must report 0 if no characters available to be read */ |
155 | count = to->ldisc->ops->chars_in_buffer(to); | 172 | if (ld->ops->chars_in_buffer) |
173 | count = ld->ops->chars_in_buffer(to); | ||
174 | |||
175 | tty_ldisc_deref(ld); | ||
156 | 176 | ||
157 | if (tty->driver->subtype == PTY_TYPE_SLAVE) | 177 | if (tty->driver->subtype == PTY_TYPE_SLAVE) |
158 | return count; | 178 | return count; |
@@ -182,12 +202,19 @@ static void pty_flush_buffer(struct tty_struct *tty) | |||
182 | { | 202 | { |
183 | struct tty_struct *to = tty->link; | 203 | struct tty_struct *to = tty->link; |
184 | unsigned long flags; | 204 | unsigned long flags; |
205 | struct tty_ldisc *ld; | ||
206 | |||
207 | if (!to) | ||
208 | return; | ||
209 | ld = tty_ldisc_ref(to); | ||
185 | 210 | ||
186 | if (!to || !to->ldisc) | 211 | /* The other end is changing discipline */ |
212 | if (!ld) | ||
187 | return; | 213 | return; |
188 | 214 | ||
189 | if (to->ldisc->ops->flush_buffer) | 215 | if (ld->ops->flush_buffer) |
190 | to->ldisc->ops->flush_buffer(to); | 216 | to->ldisc->ops->flush_buffer(to); |
217 | tty_ldisc_deref(ld); | ||
191 | 218 | ||
192 | if (to->packet) { | 219 | if (to->packet) { |
193 | spin_lock_irqsave(&tty->ctrl_lock, flags); | 220 | spin_lock_irqsave(&tty->ctrl_lock, flags); |
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 939e198d7670..a3afa0c387cd 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c | |||
@@ -1263,7 +1263,9 @@ static int tty_reopen(struct tty_struct *tty) | |||
1263 | tty->count++; | 1263 | tty->count++; |
1264 | tty->driver = driver; /* N.B. why do this every time?? */ | 1264 | tty->driver = driver; /* N.B. why do this every time?? */ |
1265 | 1265 | ||
1266 | mutex_lock(&tty->ldisc_mutex); | ||
1266 | WARN_ON(!test_bit(TTY_LDISC, &tty->flags)); | 1267 | WARN_ON(!test_bit(TTY_LDISC, &tty->flags)); |
1268 | mutex_unlock(&tty->ldisc_mutex); | ||
1267 | 1269 | ||
1268 | return 0; | 1270 | return 0; |
1269 | } | 1271 | } |
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index 8116bb1c8f80..b24f6c6a1ea3 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c | |||
@@ -947,7 +947,6 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, | |||
947 | void __user *p = (void __user *)arg; | 947 | void __user *p = (void __user *)arg; |
948 | int ret = 0; | 948 | int ret = 0; |
949 | struct ktermios kterm; | 949 | struct ktermios kterm; |
950 | struct termiox ktermx; | ||
951 | 950 | ||
952 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && | 951 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && |
953 | tty->driver->subtype == PTY_TYPE_MASTER) | 952 | tty->driver->subtype == PTY_TYPE_MASTER) |
@@ -1049,7 +1048,8 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, | |||
1049 | return ret; | 1048 | return ret; |
1050 | #endif | 1049 | #endif |
1051 | #ifdef TCGETX | 1050 | #ifdef TCGETX |
1052 | case TCGETX: | 1051 | case TCGETX: { |
1052 | struct termiox ktermx; | ||
1053 | if (real_tty->termiox == NULL) | 1053 | if (real_tty->termiox == NULL) |
1054 | return -EINVAL; | 1054 | return -EINVAL; |
1055 | mutex_lock(&real_tty->termios_mutex); | 1055 | mutex_lock(&real_tty->termios_mutex); |
@@ -1058,6 +1058,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, | |||
1058 | if (copy_to_user(p, &ktermx, sizeof(struct termiox))) | 1058 | if (copy_to_user(p, &ktermx, sizeof(struct termiox))) |
1059 | ret = -EFAULT; | 1059 | ret = -EFAULT; |
1060 | return ret; | 1060 | return ret; |
1061 | } | ||
1061 | case TCSETX: | 1062 | case TCSETX: |
1062 | return set_termiox(real_tty, p, 0); | 1063 | return set_termiox(real_tty, p, 0); |
1063 | case TCSETXW: | 1064 | case TCSETXW: |
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c index 94b3e06d73ec..a19e935847b0 100644 --- a/drivers/char/tty_ldisc.c +++ b/drivers/char/tty_ldisc.c | |||
@@ -207,6 +207,7 @@ static void tty_ldisc_put(struct tty_ldisc *ld) | |||
207 | ldo->refcount--; | 207 | ldo->refcount--; |
208 | module_put(ldo->owner); | 208 | module_put(ldo->owner); |
209 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); | 209 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); |
210 | WARN_ON(ld->refcount); | ||
210 | kfree(ld); | 211 | kfree(ld); |
211 | } | 212 | } |
212 | 213 | ||
@@ -793,6 +794,8 @@ void tty_ldisc_hangup(struct tty_struct *tty) | |||
793 | /* Avoid racing set_ldisc */ | 794 | /* Avoid racing set_ldisc */ |
794 | mutex_lock(&tty->ldisc_mutex); | 795 | mutex_lock(&tty->ldisc_mutex); |
795 | /* Switch back to N_TTY */ | 796 | /* Switch back to N_TTY */ |
797 | tty_ldisc_halt(tty); | ||
798 | tty_ldisc_wait_idle(tty); | ||
796 | tty_ldisc_reinit(tty); | 799 | tty_ldisc_reinit(tty); |
797 | /* At this point we have a closed ldisc and we want to | 800 | /* At this point we have a closed ldisc and we want to |
798 | reopen it. We could defer this to the next open but | 801 | reopen it. We could defer this to the next open but |