diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-11 11:57:47 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-11 11:57:47 -0400 |
commit | 49c355617f603b8e71ec117c1f940152a998528a (patch) | |
tree | 6b5e373003371bbe8c587a9fdda7bc4f0e791b03 /drivers/char/tty_ldisc.c | |
parent | 991ec02cdca33b03a132a0cacfe6f0aa0be9aa8d (diff) | |
parent | f0e8527726b9e56649b9eafde3bc0fbc4dd2dd47 (diff) |
Merge branch 'serial-from-alan'
* serial-from-alan: (79 commits)
moxa: prevent opening unavailable ports
imx: serial: use tty_encode_baud_rate to set true rate
imx: serial: add IrDA support to serial driver
imx: serial: use rational library function
lib: isolate rational fractions helper function
imx: serial: handle initialisation failure correctly
imx: serial: be sure to stop xmit upon shutdown
imx: serial: notify higher layers in case xmit IRQ was not called
imx: serial: fix one bit field type
imx: serial: fix whitespaces (no changes in functionality)
tty: use prepare/finish_wait
tty: remove sleep_on
sierra: driver interface blacklisting
sierra: driver urb handling improvements
tty: resolve some sierra breakage
timbuart: Fix the termios logic
serial: Added Timberdale UART driver
tty: Add URL for ttydev queue
devpts: unregister the file system on error
tty: Untangle termios and mm mutex dependencies
...
Diffstat (limited to 'drivers/char/tty_ldisc.c')
-rw-r--r-- | drivers/char/tty_ldisc.c | 549 |
1 files changed, 360 insertions, 189 deletions
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c index f78f5b0127a8..39c8f86dedd4 100644 --- a/drivers/char/tty_ldisc.c +++ b/drivers/char/tty_ldisc.c | |||
@@ -115,19 +115,22 @@ EXPORT_SYMBOL(tty_unregister_ldisc); | |||
115 | /** | 115 | /** |
116 | * tty_ldisc_try_get - try and reference an ldisc | 116 | * tty_ldisc_try_get - try and reference an ldisc |
117 | * @disc: ldisc number | 117 | * @disc: ldisc number |
118 | * @ld: tty ldisc structure to complete | ||
119 | * | 118 | * |
120 | * Attempt to open and lock a line discipline into place. Return | 119 | * Attempt to open and lock a line discipline into place. Return |
121 | * the line discipline refcounted and assigned in ld. On an error | 120 | * the line discipline refcounted or an error. |
122 | * report the error code back | ||
123 | */ | 121 | */ |
124 | 122 | ||
125 | static int tty_ldisc_try_get(int disc, struct tty_ldisc *ld) | 123 | static struct tty_ldisc *tty_ldisc_try_get(int disc) |
126 | { | 124 | { |
127 | unsigned long flags; | 125 | unsigned long flags; |
126 | struct tty_ldisc *ld; | ||
128 | struct tty_ldisc_ops *ldops; | 127 | struct tty_ldisc_ops *ldops; |
129 | int err = -EINVAL; | 128 | int err = -EINVAL; |
130 | 129 | ||
130 | ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL); | ||
131 | if (ld == NULL) | ||
132 | return ERR_PTR(-ENOMEM); | ||
133 | |||
131 | spin_lock_irqsave(&tty_ldisc_lock, flags); | 134 | spin_lock_irqsave(&tty_ldisc_lock, flags); |
132 | ld->ops = NULL; | 135 | ld->ops = NULL; |
133 | ldops = tty_ldiscs[disc]; | 136 | ldops = tty_ldiscs[disc]; |
@@ -140,17 +143,19 @@ static int tty_ldisc_try_get(int disc, struct tty_ldisc *ld) | |||
140 | /* lock it */ | 143 | /* lock it */ |
141 | ldops->refcount++; | 144 | ldops->refcount++; |
142 | ld->ops = ldops; | 145 | ld->ops = ldops; |
146 | ld->refcount = 0; | ||
143 | err = 0; | 147 | err = 0; |
144 | } | 148 | } |
145 | } | 149 | } |
146 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); | 150 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); |
147 | return err; | 151 | if (err) |
152 | return ERR_PTR(err); | ||
153 | return ld; | ||
148 | } | 154 | } |
149 | 155 | ||
150 | /** | 156 | /** |
151 | * tty_ldisc_get - take a reference to an ldisc | 157 | * tty_ldisc_get - take a reference to an ldisc |
152 | * @disc: ldisc number | 158 | * @disc: ldisc number |
153 | * @ld: tty line discipline structure to use | ||
154 | * | 159 | * |
155 | * Takes a reference to a line discipline. Deals with refcounts and | 160 | * Takes a reference to a line discipline. Deals with refcounts and |
156 | * module locking counts. Returns NULL if the discipline is not available. | 161 | * module locking counts. Returns NULL if the discipline is not available. |
@@ -161,52 +166,54 @@ static int tty_ldisc_try_get(int disc, struct tty_ldisc *ld) | |||
161 | * takes tty_ldisc_lock to guard against ldisc races | 166 | * takes tty_ldisc_lock to guard against ldisc races |
162 | */ | 167 | */ |
163 | 168 | ||
164 | static int tty_ldisc_get(int disc, struct tty_ldisc *ld) | 169 | static struct tty_ldisc *tty_ldisc_get(int disc) |
165 | { | 170 | { |
166 | int err; | 171 | struct tty_ldisc *ld; |
167 | 172 | ||
168 | if (disc < N_TTY || disc >= NR_LDISCS) | 173 | if (disc < N_TTY || disc >= NR_LDISCS) |
169 | return -EINVAL; | 174 | return ERR_PTR(-EINVAL); |
170 | err = tty_ldisc_try_get(disc, ld); | 175 | ld = tty_ldisc_try_get(disc); |
171 | if (err < 0) { | 176 | if (IS_ERR(ld)) { |
172 | request_module("tty-ldisc-%d", disc); | 177 | request_module("tty-ldisc-%d", disc); |
173 | err = tty_ldisc_try_get(disc, ld); | 178 | ld = tty_ldisc_try_get(disc); |
174 | } | 179 | } |
175 | return err; | 180 | return ld; |
176 | } | 181 | } |
177 | 182 | ||
178 | /** | 183 | /** |
179 | * tty_ldisc_put - drop ldisc reference | 184 | * tty_ldisc_put - drop ldisc reference |
180 | * @disc: ldisc number | 185 | * @ld: ldisc |
181 | * | 186 | * |
182 | * Drop a reference to a line discipline. Manage refcounts and | 187 | * Drop a reference to a line discipline. Manage refcounts and |
183 | * module usage counts | 188 | * module usage counts. Free the ldisc once the recount hits zero. |
184 | * | 189 | * |
185 | * Locking: | 190 | * Locking: |
186 | * takes tty_ldisc_lock to guard against ldisc races | 191 | * takes tty_ldisc_lock to guard against ldisc races |
187 | */ | 192 | */ |
188 | 193 | ||
189 | static void tty_ldisc_put(struct tty_ldisc_ops *ld) | 194 | static void tty_ldisc_put(struct tty_ldisc *ld) |
190 | { | 195 | { |
191 | unsigned long flags; | 196 | unsigned long flags; |
192 | int disc = ld->num; | 197 | int disc = ld->ops->num; |
198 | struct tty_ldisc_ops *ldo; | ||
193 | 199 | ||
194 | BUG_ON(disc < N_TTY || disc >= NR_LDISCS); | 200 | BUG_ON(disc < N_TTY || disc >= NR_LDISCS); |
195 | 201 | ||
196 | spin_lock_irqsave(&tty_ldisc_lock, flags); | 202 | spin_lock_irqsave(&tty_ldisc_lock, flags); |
197 | ld = tty_ldiscs[disc]; | 203 | ldo = tty_ldiscs[disc]; |
198 | BUG_ON(ld->refcount == 0); | 204 | BUG_ON(ldo->refcount == 0); |
199 | ld->refcount--; | 205 | ldo->refcount--; |
200 | module_put(ld->owner); | 206 | module_put(ldo->owner); |
201 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); | 207 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); |
208 | kfree(ld); | ||
202 | } | 209 | } |
203 | 210 | ||
204 | static void * tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos) | 211 | static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos) |
205 | { | 212 | { |
206 | return (*pos < NR_LDISCS) ? pos : NULL; | 213 | return (*pos < NR_LDISCS) ? pos : NULL; |
207 | } | 214 | } |
208 | 215 | ||
209 | static void * tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos) | 216 | static void *tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos) |
210 | { | 217 | { |
211 | (*pos)++; | 218 | (*pos)++; |
212 | return (*pos < NR_LDISCS) ? pos : NULL; | 219 | return (*pos < NR_LDISCS) ? pos : NULL; |
@@ -219,12 +226,13 @@ static void tty_ldiscs_seq_stop(struct seq_file *m, void *v) | |||
219 | static int tty_ldiscs_seq_show(struct seq_file *m, void *v) | 226 | static int tty_ldiscs_seq_show(struct seq_file *m, void *v) |
220 | { | 227 | { |
221 | int i = *(loff_t *)v; | 228 | int i = *(loff_t *)v; |
222 | struct tty_ldisc ld; | 229 | struct tty_ldisc *ld; |
223 | 230 | ||
224 | if (tty_ldisc_get(i, &ld) < 0) | 231 | ld = tty_ldisc_try_get(i); |
232 | if (IS_ERR(ld)) | ||
225 | return 0; | 233 | return 0; |
226 | seq_printf(m, "%-10s %2d\n", ld.ops->name ? ld.ops->name : "???", i); | 234 | seq_printf(m, "%-10s %2d\n", ld->ops->name ? ld->ops->name : "???", i); |
227 | tty_ldisc_put(ld.ops); | 235 | tty_ldisc_put(ld); |
228 | return 0; | 236 | return 0; |
229 | } | 237 | } |
230 | 238 | ||
@@ -263,8 +271,7 @@ const struct file_operations tty_ldiscs_proc_fops = { | |||
263 | 271 | ||
264 | static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld) | 272 | static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld) |
265 | { | 273 | { |
266 | ld->refcount = 0; | 274 | tty->ldisc = ld; |
267 | tty->ldisc = *ld; | ||
268 | } | 275 | } |
269 | 276 | ||
270 | /** | 277 | /** |
@@ -286,7 +293,7 @@ static int tty_ldisc_try(struct tty_struct *tty) | |||
286 | int ret = 0; | 293 | int ret = 0; |
287 | 294 | ||
288 | spin_lock_irqsave(&tty_ldisc_lock, flags); | 295 | spin_lock_irqsave(&tty_ldisc_lock, flags); |
289 | ld = &tty->ldisc; | 296 | ld = tty->ldisc; |
290 | if (test_bit(TTY_LDISC, &tty->flags)) { | 297 | if (test_bit(TTY_LDISC, &tty->flags)) { |
291 | ld->refcount++; | 298 | ld->refcount++; |
292 | ret = 1; | 299 | ret = 1; |
@@ -315,10 +322,9 @@ struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty) | |||
315 | { | 322 | { |
316 | /* wait_event is a macro */ | 323 | /* wait_event is a macro */ |
317 | wait_event(tty_ldisc_wait, tty_ldisc_try(tty)); | 324 | wait_event(tty_ldisc_wait, tty_ldisc_try(tty)); |
318 | WARN_ON(tty->ldisc.refcount == 0); | 325 | WARN_ON(tty->ldisc->refcount == 0); |
319 | return &tty->ldisc; | 326 | return tty->ldisc; |
320 | } | 327 | } |
321 | |||
322 | EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); | 328 | EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); |
323 | 329 | ||
324 | /** | 330 | /** |
@@ -335,10 +341,9 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); | |||
335 | struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty) | 341 | struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty) |
336 | { | 342 | { |
337 | if (tty_ldisc_try(tty)) | 343 | if (tty_ldisc_try(tty)) |
338 | return &tty->ldisc; | 344 | return tty->ldisc; |
339 | return NULL; | 345 | return NULL; |
340 | } | 346 | } |
341 | |||
342 | EXPORT_SYMBOL_GPL(tty_ldisc_ref); | 347 | EXPORT_SYMBOL_GPL(tty_ldisc_ref); |
343 | 348 | ||
344 | /** | 349 | /** |
@@ -366,7 +371,6 @@ void tty_ldisc_deref(struct tty_ldisc *ld) | |||
366 | wake_up(&tty_ldisc_wait); | 371 | wake_up(&tty_ldisc_wait); |
367 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); | 372 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); |
368 | } | 373 | } |
369 | |||
370 | EXPORT_SYMBOL_GPL(tty_ldisc_deref); | 374 | EXPORT_SYMBOL_GPL(tty_ldisc_deref); |
371 | 375 | ||
372 | /** | 376 | /** |
@@ -389,6 +393,26 @@ void tty_ldisc_enable(struct tty_struct *tty) | |||
389 | } | 393 | } |
390 | 394 | ||
391 | /** | 395 | /** |
396 | * tty_ldisc_flush - flush line discipline queue | ||
397 | * @tty: tty | ||
398 | * | ||
399 | * Flush the line discipline queue (if any) for this tty. If there | ||
400 | * is no line discipline active this is a no-op. | ||
401 | */ | ||
402 | |||
403 | void tty_ldisc_flush(struct tty_struct *tty) | ||
404 | { | ||
405 | struct tty_ldisc *ld = tty_ldisc_ref(tty); | ||
406 | if (ld) { | ||
407 | if (ld->ops->flush_buffer) | ||
408 | ld->ops->flush_buffer(tty); | ||
409 | tty_ldisc_deref(ld); | ||
410 | } | ||
411 | tty_buffer_flush(tty); | ||
412 | } | ||
413 | EXPORT_SYMBOL_GPL(tty_ldisc_flush); | ||
414 | |||
415 | /** | ||
392 | * tty_set_termios_ldisc - set ldisc field | 416 | * tty_set_termios_ldisc - set ldisc field |
393 | * @tty: tty structure | 417 | * @tty: tty structure |
394 | * @num: line discipline number | 418 | * @num: line discipline number |
@@ -407,6 +431,39 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num) | |||
407 | mutex_unlock(&tty->termios_mutex); | 431 | mutex_unlock(&tty->termios_mutex); |
408 | } | 432 | } |
409 | 433 | ||
434 | /** | ||
435 | * tty_ldisc_open - open a line discipline | ||
436 | * @tty: tty we are opening the ldisc on | ||
437 | * @ld: discipline to open | ||
438 | * | ||
439 | * A helper opening method. Also a convenient debugging and check | ||
440 | * point. | ||
441 | */ | ||
442 | |||
443 | static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld) | ||
444 | { | ||
445 | WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags)); | ||
446 | if (ld->ops->open) | ||
447 | return ld->ops->open(tty); | ||
448 | return 0; | ||
449 | } | ||
450 | |||
451 | /** | ||
452 | * tty_ldisc_close - close a line discipline | ||
453 | * @tty: tty we are opening the ldisc on | ||
454 | * @ld: discipline to close | ||
455 | * | ||
456 | * A helper close method. Also a convenient debugging and check | ||
457 | * point. | ||
458 | */ | ||
459 | |||
460 | static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld) | ||
461 | { | ||
462 | WARN_ON(!test_bit(TTY_LDISC_OPEN, &tty->flags)); | ||
463 | clear_bit(TTY_LDISC_OPEN, &tty->flags); | ||
464 | if (ld->ops->close) | ||
465 | ld->ops->close(tty); | ||
466 | } | ||
410 | 467 | ||
411 | /** | 468 | /** |
412 | * tty_ldisc_restore - helper for tty ldisc change | 469 | * tty_ldisc_restore - helper for tty ldisc change |
@@ -420,66 +477,136 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num) | |||
420 | static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) | 477 | static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) |
421 | { | 478 | { |
422 | char buf[64]; | 479 | char buf[64]; |
423 | struct tty_ldisc new_ldisc; | 480 | struct tty_ldisc *new_ldisc; |
481 | int r; | ||
424 | 482 | ||
425 | /* There is an outstanding reference here so this is safe */ | 483 | /* There is an outstanding reference here so this is safe */ |
426 | tty_ldisc_get(old->ops->num, old); | 484 | old = tty_ldisc_get(old->ops->num); |
485 | WARN_ON(IS_ERR(old)); | ||
427 | tty_ldisc_assign(tty, old); | 486 | tty_ldisc_assign(tty, old); |
428 | tty_set_termios_ldisc(tty, old->ops->num); | 487 | tty_set_termios_ldisc(tty, old->ops->num); |
429 | if (old->ops->open && (old->ops->open(tty) < 0)) { | 488 | if (tty_ldisc_open(tty, old) < 0) { |
430 | tty_ldisc_put(old->ops); | 489 | tty_ldisc_put(old); |
431 | /* This driver is always present */ | 490 | /* This driver is always present */ |
432 | if (tty_ldisc_get(N_TTY, &new_ldisc) < 0) | 491 | new_ldisc = tty_ldisc_get(N_TTY); |
492 | if (IS_ERR(new_ldisc)) | ||
433 | panic("n_tty: get"); | 493 | panic("n_tty: get"); |
434 | tty_ldisc_assign(tty, &new_ldisc); | 494 | tty_ldisc_assign(tty, new_ldisc); |
435 | tty_set_termios_ldisc(tty, N_TTY); | 495 | tty_set_termios_ldisc(tty, N_TTY); |
436 | if (new_ldisc.ops->open) { | 496 | r = tty_ldisc_open(tty, new_ldisc); |
437 | int r = new_ldisc.ops->open(tty); | 497 | if (r < 0) |
438 | if (r < 0) | 498 | panic("Couldn't open N_TTY ldisc for " |
439 | panic("Couldn't open N_TTY ldisc for " | 499 | "%s --- error %d.", |
440 | "%s --- error %d.", | 500 | tty_name(tty, buf), r); |
441 | tty_name(tty, buf), r); | ||
442 | } | ||
443 | } | 501 | } |
444 | } | 502 | } |
445 | 503 | ||
446 | /** | 504 | /** |
505 | * tty_ldisc_halt - shut down the line discipline | ||
506 | * @tty: tty device | ||
507 | * | ||
508 | * Shut down the line discipline and work queue for this tty device. | ||
509 | * The TTY_LDISC flag being cleared ensures no further references can | ||
510 | * be obtained while the delayed work queue halt ensures that no more | ||
511 | * data is fed to the ldisc. | ||
512 | * | ||
513 | * In order to wait for any existing references to complete see | ||
514 | * tty_ldisc_wait_idle. | ||
515 | */ | ||
516 | |||
517 | static int tty_ldisc_halt(struct tty_struct *tty) | ||
518 | { | ||
519 | clear_bit(TTY_LDISC, &tty->flags); | ||
520 | return cancel_delayed_work(&tty->buf.work); | ||
521 | } | ||
522 | |||
523 | /** | ||
524 | * tty_ldisc_wait_idle - wait for the ldisc to become idle | ||
525 | * @tty: tty to wait for | ||
526 | * | ||
527 | * Wait for the line discipline to become idle. The discipline must | ||
528 | * have been halted for this to guarantee it remains idle. | ||
529 | * | ||
530 | * tty_ldisc_lock protects the ref counts currently. | ||
531 | */ | ||
532 | |||
533 | static int tty_ldisc_wait_idle(struct tty_struct *tty) | ||
534 | { | ||
535 | unsigned long flags; | ||
536 | spin_lock_irqsave(&tty_ldisc_lock, flags); | ||
537 | while (tty->ldisc->refcount) { | ||
538 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); | ||
539 | if (wait_event_timeout(tty_ldisc_wait, | ||
540 | tty->ldisc->refcount == 0, 5 * HZ) == 0) | ||
541 | return -EBUSY; | ||
542 | spin_lock_irqsave(&tty_ldisc_lock, flags); | ||
543 | } | ||
544 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); | ||
545 | return 0; | ||
546 | } | ||
547 | |||
548 | /** | ||
447 | * tty_set_ldisc - set line discipline | 549 | * tty_set_ldisc - set line discipline |
448 | * @tty: the terminal to set | 550 | * @tty: the terminal to set |
449 | * @ldisc: the line discipline | 551 | * @ldisc: the line discipline |
450 | * | 552 | * |
451 | * Set the discipline of a tty line. Must be called from a process | 553 | * Set the discipline of a tty line. Must be called from a process |
452 | * context. | 554 | * context. The ldisc change logic has to protect itself against any |
555 | * overlapping ldisc change (including on the other end of pty pairs), | ||
556 | * the close of one side of a tty/pty pair, and eventually hangup. | ||
453 | * | 557 | * |
454 | * Locking: takes tty_ldisc_lock. | 558 | * Locking: takes tty_ldisc_lock, termios_mutex |
455 | * called functions take termios_mutex | ||
456 | */ | 559 | */ |
457 | 560 | ||
458 | int tty_set_ldisc(struct tty_struct *tty, int ldisc) | 561 | int tty_set_ldisc(struct tty_struct *tty, int ldisc) |
459 | { | 562 | { |
460 | int retval; | 563 | int retval; |
461 | struct tty_ldisc o_ldisc, new_ldisc; | 564 | struct tty_ldisc *o_ldisc, *new_ldisc; |
462 | int work; | 565 | int work, o_work = 0; |
463 | unsigned long flags; | ||
464 | struct tty_struct *o_tty; | 566 | struct tty_struct *o_tty; |
465 | 567 | ||
466 | restart: | 568 | new_ldisc = tty_ldisc_get(ldisc); |
467 | /* This is a bit ugly for now but means we can break the 'ldisc | 569 | if (IS_ERR(new_ldisc)) |
468 | is part of the tty struct' assumption later */ | 570 | return PTR_ERR(new_ldisc); |
469 | retval = tty_ldisc_get(ldisc, &new_ldisc); | 571 | |
470 | if (retval) | 572 | /* |
471 | return retval; | 573 | * We need to look at the tty locking here for pty/tty pairs |
574 | * when both sides try to change in parallel. | ||
575 | */ | ||
576 | |||
577 | o_tty = tty->link; /* o_tty is the pty side or NULL */ | ||
578 | |||
579 | |||
580 | /* | ||
581 | * Check the no-op case | ||
582 | */ | ||
583 | |||
584 | if (tty->ldisc->ops->num == ldisc) { | ||
585 | tty_ldisc_put(new_ldisc); | ||
586 | return 0; | ||
587 | } | ||
472 | 588 | ||
473 | /* | 589 | /* |
474 | * Problem: What do we do if this blocks ? | 590 | * Problem: What do we do if this blocks ? |
591 | * We could deadlock here | ||
475 | */ | 592 | */ |
476 | 593 | ||
477 | tty_wait_until_sent(tty, 0); | 594 | tty_wait_until_sent(tty, 0); |
478 | 595 | ||
479 | if (tty->ldisc.ops->num == ldisc) { | 596 | mutex_lock(&tty->ldisc_mutex); |
480 | tty_ldisc_put(new_ldisc.ops); | 597 | |
481 | return 0; | 598 | /* |
599 | * We could be midstream of another ldisc change which has | ||
600 | * dropped the lock during processing. If so we need to wait. | ||
601 | */ | ||
602 | |||
603 | while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) { | ||
604 | mutex_unlock(&tty->ldisc_mutex); | ||
605 | wait_event(tty_ldisc_wait, | ||
606 | test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0); | ||
607 | mutex_lock(&tty->ldisc_mutex); | ||
482 | } | 608 | } |
609 | set_bit(TTY_LDISC_CHANGING, &tty->flags); | ||
483 | 610 | ||
484 | /* | 611 | /* |
485 | * No more input please, we are switching. The new ldisc | 612 | * No more input please, we are switching. The new ldisc |
@@ -489,8 +616,6 @@ restart: | |||
489 | tty->receive_room = 0; | 616 | tty->receive_room = 0; |
490 | 617 | ||
491 | o_ldisc = tty->ldisc; | 618 | o_ldisc = tty->ldisc; |
492 | o_tty = tty->link; | ||
493 | |||
494 | /* | 619 | /* |
495 | * Make sure we don't change while someone holds a | 620 | * Make sure we don't change while someone holds a |
496 | * reference to the line discipline. The TTY_LDISC bit | 621 | * reference to the line discipline. The TTY_LDISC bit |
@@ -501,108 +626,181 @@ restart: | |||
501 | * with a userspace app continually trying to use the tty in | 626 | * with a userspace app continually trying to use the tty in |
502 | * parallel to the change and re-referencing the tty. | 627 | * parallel to the change and re-referencing the tty. |
503 | */ | 628 | */ |
504 | clear_bit(TTY_LDISC, &tty->flags); | ||
505 | if (o_tty) | ||
506 | clear_bit(TTY_LDISC, &o_tty->flags); | ||
507 | 629 | ||
508 | spin_lock_irqsave(&tty_ldisc_lock, flags); | 630 | work = tty_ldisc_halt(tty); |
509 | if (tty->ldisc.refcount || (o_tty && o_tty->ldisc.refcount)) { | ||
510 | if (tty->ldisc.refcount) { | ||
511 | /* Free the new ldisc we grabbed. Must drop the lock | ||
512 | first. */ | ||
513 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); | ||
514 | tty_ldisc_put(o_ldisc.ops); | ||
515 | /* | ||
516 | * There are several reasons we may be busy, including | ||
517 | * random momentary I/O traffic. We must therefore | ||
518 | * retry. We could distinguish between blocking ops | ||
519 | * and retries if we made tty_ldisc_wait() smarter. | ||
520 | * That is up for discussion. | ||
521 | */ | ||
522 | if (wait_event_interruptible(tty_ldisc_wait, tty->ldisc.refcount == 0) < 0) | ||
523 | return -ERESTARTSYS; | ||
524 | goto restart; | ||
525 | } | ||
526 | if (o_tty && o_tty->ldisc.refcount) { | ||
527 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); | ||
528 | tty_ldisc_put(o_tty->ldisc.ops); | ||
529 | if (wait_event_interruptible(tty_ldisc_wait, o_tty->ldisc.refcount == 0) < 0) | ||
530 | return -ERESTARTSYS; | ||
531 | goto restart; | ||
532 | } | ||
533 | } | ||
534 | /* | ||
535 | * If the TTY_LDISC bit is set, then we are racing against | ||
536 | * another ldisc change | ||
537 | */ | ||
538 | if (test_bit(TTY_LDISC_CHANGING, &tty->flags)) { | ||
539 | struct tty_ldisc *ld; | ||
540 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); | ||
541 | tty_ldisc_put(new_ldisc.ops); | ||
542 | ld = tty_ldisc_ref_wait(tty); | ||
543 | tty_ldisc_deref(ld); | ||
544 | goto restart; | ||
545 | } | ||
546 | /* | ||
547 | * This flag is used to avoid two parallel ldisc changes. Once | ||
548 | * open and close are fine grained locked this may work better | ||
549 | * as a mutex shared with the open/close/hup paths | ||
550 | */ | ||
551 | set_bit(TTY_LDISC_CHANGING, &tty->flags); | ||
552 | if (o_tty) | 631 | if (o_tty) |
553 | set_bit(TTY_LDISC_CHANGING, &o_tty->flags); | 632 | o_work = tty_ldisc_halt(o_tty); |
554 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); | ||
555 | |||
556 | /* | ||
557 | * From this point on we know nobody has an ldisc | ||
558 | * usage reference, nor can they obtain one until | ||
559 | * we say so later on. | ||
560 | */ | ||
561 | 633 | ||
562 | work = cancel_delayed_work(&tty->buf.work); | ||
563 | /* | 634 | /* |
564 | * Wait for ->hangup_work and ->buf.work handlers to terminate | 635 | * Wait for ->hangup_work and ->buf.work handlers to terminate. |
565 | * MUST NOT hold locks here. | 636 | * We must drop the mutex here in case a hangup is also in process. |
566 | */ | 637 | */ |
638 | |||
639 | mutex_unlock(&tty->ldisc_mutex); | ||
640 | |||
567 | flush_scheduled_work(); | 641 | flush_scheduled_work(); |
642 | |||
643 | /* Let any existing reference holders finish */ | ||
644 | retval = tty_ldisc_wait_idle(tty); | ||
645 | if (retval < 0) { | ||
646 | clear_bit(TTY_LDISC_CHANGING, &tty->flags); | ||
647 | tty_ldisc_put(new_ldisc); | ||
648 | return retval; | ||
649 | } | ||
650 | |||
651 | mutex_lock(&tty->ldisc_mutex); | ||
652 | if (test_bit(TTY_HUPPED, &tty->flags)) { | ||
653 | /* We were raced by the hangup method. It will have stomped | ||
654 | the ldisc data and closed the ldisc down */ | ||
655 | clear_bit(TTY_LDISC_CHANGING, &tty->flags); | ||
656 | mutex_unlock(&tty->ldisc_mutex); | ||
657 | tty_ldisc_put(new_ldisc); | ||
658 | return -EIO; | ||
659 | } | ||
660 | |||
568 | /* Shutdown the current discipline. */ | 661 | /* Shutdown the current discipline. */ |
569 | if (o_ldisc.ops->close) | 662 | tty_ldisc_close(tty, o_ldisc); |
570 | (o_ldisc.ops->close)(tty); | ||
571 | 663 | ||
572 | /* Now set up the new line discipline. */ | 664 | /* Now set up the new line discipline. */ |
573 | tty_ldisc_assign(tty, &new_ldisc); | 665 | tty_ldisc_assign(tty, new_ldisc); |
574 | tty_set_termios_ldisc(tty, ldisc); | 666 | tty_set_termios_ldisc(tty, ldisc); |
575 | if (new_ldisc.ops->open) | 667 | |
576 | retval = (new_ldisc.ops->open)(tty); | 668 | retval = tty_ldisc_open(tty, new_ldisc); |
577 | if (retval < 0) { | 669 | if (retval < 0) { |
578 | tty_ldisc_put(new_ldisc.ops); | 670 | /* Back to the old one or N_TTY if we can't */ |
579 | tty_ldisc_restore(tty, &o_ldisc); | 671 | tty_ldisc_put(new_ldisc); |
672 | tty_ldisc_restore(tty, o_ldisc); | ||
580 | } | 673 | } |
674 | |||
581 | /* At this point we hold a reference to the new ldisc and a | 675 | /* At this point we hold a reference to the new ldisc and a |
582 | a reference to the old ldisc. If we ended up flipping back | 676 | a reference to the old ldisc. If we ended up flipping back |
583 | to the existing ldisc we have two references to it */ | 677 | to the existing ldisc we have two references to it */ |
584 | 678 | ||
585 | if (tty->ldisc.ops->num != o_ldisc.ops->num && tty->ops->set_ldisc) | 679 | if (tty->ldisc->ops->num != o_ldisc->ops->num && tty->ops->set_ldisc) |
586 | tty->ops->set_ldisc(tty); | 680 | tty->ops->set_ldisc(tty); |
587 | 681 | ||
588 | tty_ldisc_put(o_ldisc.ops); | 682 | tty_ldisc_put(o_ldisc); |
589 | 683 | ||
590 | /* | 684 | /* |
591 | * Allow ldisc referencing to occur as soon as the driver | 685 | * Allow ldisc referencing to occur again |
592 | * ldisc callback completes. | ||
593 | */ | 686 | */ |
594 | 687 | ||
595 | tty_ldisc_enable(tty); | 688 | tty_ldisc_enable(tty); |
596 | if (o_tty) | 689 | if (o_tty) |
597 | tty_ldisc_enable(o_tty); | 690 | tty_ldisc_enable(o_tty); |
598 | 691 | ||
599 | /* Restart it in case no characters kick it off. Safe if | 692 | /* Restart the work queue in case no characters kick it off. Safe if |
600 | already running */ | 693 | already running */ |
601 | if (work) | 694 | if (work) |
602 | schedule_delayed_work(&tty->buf.work, 1); | 695 | schedule_delayed_work(&tty->buf.work, 1); |
696 | if (o_work) | ||
697 | schedule_delayed_work(&o_tty->buf.work, 1); | ||
698 | mutex_unlock(&tty->ldisc_mutex); | ||
603 | return retval; | 699 | return retval; |
604 | } | 700 | } |
605 | 701 | ||
702 | /** | ||
703 | * tty_reset_termios - reset terminal state | ||
704 | * @tty: tty to reset | ||
705 | * | ||
706 | * Restore a terminal to the driver default state. | ||
707 | */ | ||
708 | |||
709 | static void tty_reset_termios(struct tty_struct *tty) | ||
710 | { | ||
711 | mutex_lock(&tty->termios_mutex); | ||
712 | *tty->termios = tty->driver->init_termios; | ||
713 | tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios); | ||
714 | tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios); | ||
715 | mutex_unlock(&tty->termios_mutex); | ||
716 | } | ||
717 | |||
718 | |||
719 | /** | ||
720 | * tty_ldisc_reinit - reinitialise the tty ldisc | ||
721 | * @tty: tty to reinit | ||
722 | * | ||
723 | * Switch the tty back to N_TTY line discipline and leave the | ||
724 | * ldisc state closed | ||
725 | */ | ||
726 | |||
727 | static void tty_ldisc_reinit(struct tty_struct *tty) | ||
728 | { | ||
729 | struct tty_ldisc *ld; | ||
730 | |||
731 | tty_ldisc_close(tty, tty->ldisc); | ||
732 | tty_ldisc_put(tty->ldisc); | ||
733 | tty->ldisc = NULL; | ||
734 | /* | ||
735 | * Switch the line discipline back | ||
736 | */ | ||
737 | ld = tty_ldisc_get(N_TTY); | ||
738 | BUG_ON(IS_ERR(ld)); | ||
739 | tty_ldisc_assign(tty, ld); | ||
740 | tty_set_termios_ldisc(tty, N_TTY); | ||
741 | } | ||
742 | |||
743 | /** | ||
744 | * tty_ldisc_hangup - hangup ldisc reset | ||
745 | * @tty: tty being hung up | ||
746 | * | ||
747 | * Some tty devices reset their termios when they receive a hangup | ||
748 | * event. In that situation we must also switch back to N_TTY properly | ||
749 | * before we reset the termios data. | ||
750 | * | ||
751 | * Locking: We can take the ldisc mutex as the rest of the code is | ||
752 | * careful to allow for this. | ||
753 | * | ||
754 | * In the pty pair case this occurs in the close() path of the | ||
755 | * tty itself so we must be careful about locking rules. | ||
756 | */ | ||
757 | |||
758 | void tty_ldisc_hangup(struct tty_struct *tty) | ||
759 | { | ||
760 | struct tty_ldisc *ld; | ||
761 | |||
762 | /* | ||
763 | * FIXME! What are the locking issues here? This may me overdoing | ||
764 | * things... This question is especially important now that we've | ||
765 | * removed the irqlock. | ||
766 | */ | ||
767 | ld = tty_ldisc_ref(tty); | ||
768 | if (ld != NULL) { | ||
769 | /* We may have no line discipline at this point */ | ||
770 | if (ld->ops->flush_buffer) | ||
771 | ld->ops->flush_buffer(tty); | ||
772 | tty_driver_flush_buffer(tty); | ||
773 | if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && | ||
774 | ld->ops->write_wakeup) | ||
775 | ld->ops->write_wakeup(tty); | ||
776 | if (ld->ops->hangup) | ||
777 | ld->ops->hangup(tty); | ||
778 | tty_ldisc_deref(ld); | ||
779 | } | ||
780 | /* | ||
781 | * FIXME: Once we trust the LDISC code better we can wait here for | ||
782 | * ldisc completion and fix the driver call race | ||
783 | */ | ||
784 | wake_up_interruptible_poll(&tty->write_wait, POLLOUT); | ||
785 | wake_up_interruptible_poll(&tty->read_wait, POLLIN); | ||
786 | /* | ||
787 | * Shutdown the current line discipline, and reset it to | ||
788 | * N_TTY. | ||
789 | */ | ||
790 | if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { | ||
791 | /* Avoid racing set_ldisc */ | ||
792 | mutex_lock(&tty->ldisc_mutex); | ||
793 | /* Switch back to N_TTY */ | ||
794 | tty_ldisc_reinit(tty); | ||
795 | /* At this point we have a closed ldisc and we want to | ||
796 | reopen it. We could defer this to the next open but | ||
797 | it means auditing a lot of other paths so this is a FIXME */ | ||
798 | WARN_ON(tty_ldisc_open(tty, tty->ldisc)); | ||
799 | tty_ldisc_enable(tty); | ||
800 | mutex_unlock(&tty->ldisc_mutex); | ||
801 | tty_reset_termios(tty); | ||
802 | } | ||
803 | } | ||
606 | 804 | ||
607 | /** | 805 | /** |
608 | * tty_ldisc_setup - open line discipline | 806 | * tty_ldisc_setup - open line discipline |
@@ -610,24 +808,23 @@ restart: | |||
610 | * @o_tty: pair tty for pty/tty pairs | 808 | * @o_tty: pair tty for pty/tty pairs |
611 | * | 809 | * |
612 | * Called during the initial open of a tty/pty pair in order to set up the | 810 | * Called during the initial open of a tty/pty pair in order to set up the |
613 | * line discplines and bind them to the tty. | 811 | * line disciplines and bind them to the tty. This has no locking issues |
812 | * as the device isn't yet active. | ||
614 | */ | 813 | */ |
615 | 814 | ||
616 | int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty) | 815 | int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty) |
617 | { | 816 | { |
618 | struct tty_ldisc *ld = &tty->ldisc; | 817 | struct tty_ldisc *ld = tty->ldisc; |
619 | int retval; | 818 | int retval; |
620 | 819 | ||
621 | if (ld->ops->open) { | 820 | retval = tty_ldisc_open(tty, ld); |
622 | retval = (ld->ops->open)(tty); | 821 | if (retval) |
623 | if (retval) | 822 | return retval; |
624 | return retval; | 823 | |
625 | } | 824 | if (o_tty) { |
626 | if (o_tty && o_tty->ldisc.ops->open) { | 825 | retval = tty_ldisc_open(o_tty, o_tty->ldisc); |
627 | retval = (o_tty->ldisc.ops->open)(o_tty); | ||
628 | if (retval) { | 826 | if (retval) { |
629 | if (ld->ops->close) | 827 | tty_ldisc_close(tty, ld); |
630 | (ld->ops->close)(tty); | ||
631 | return retval; | 828 | return retval; |
632 | } | 829 | } |
633 | tty_ldisc_enable(o_tty); | 830 | tty_ldisc_enable(o_tty); |
@@ -635,32 +832,25 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty) | |||
635 | tty_ldisc_enable(tty); | 832 | tty_ldisc_enable(tty); |
636 | return 0; | 833 | return 0; |
637 | } | 834 | } |
638 | |||
639 | /** | 835 | /** |
640 | * tty_ldisc_release - release line discipline | 836 | * tty_ldisc_release - release line discipline |
641 | * @tty: tty being shut down | 837 | * @tty: tty being shut down |
642 | * @o_tty: pair tty for pty/tty pairs | 838 | * @o_tty: pair tty for pty/tty pairs |
643 | * | 839 | * |
644 | * Called during the final close of a tty/pty pair in order to shut down the | 840 | * Called during the final close of a tty/pty pair in order to shut down |
645 | * line discpline layer. | 841 | * the line discpline layer. On exit the ldisc assigned is N_TTY and the |
842 | * ldisc has not been opened. | ||
646 | */ | 843 | */ |
647 | 844 | ||
648 | void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) | 845 | void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) |
649 | { | 846 | { |
650 | unsigned long flags; | ||
651 | struct tty_ldisc ld; | ||
652 | /* | 847 | /* |
653 | * Prevent flush_to_ldisc() from rescheduling the work for later. Then | 848 | * Prevent flush_to_ldisc() from rescheduling the work for later. Then |
654 | * kill any delayed work. As this is the final close it does not | 849 | * kill any delayed work. As this is the final close it does not |
655 | * race with the set_ldisc code path. | 850 | * race with the set_ldisc code path. |
656 | */ | 851 | */ |
657 | clear_bit(TTY_LDISC, &tty->flags); | ||
658 | cancel_delayed_work(&tty->buf.work); | ||
659 | |||
660 | /* | ||
661 | * Wait for ->hangup_work and ->buf.work handlers to terminate | ||
662 | */ | ||
663 | 852 | ||
853 | tty_ldisc_halt(tty); | ||
664 | flush_scheduled_work(); | 854 | flush_scheduled_work(); |
665 | 855 | ||
666 | /* | 856 | /* |
@@ -668,38 +858,19 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) | |||
668 | * side waiters as the file is closing so user count on the file | 858 | * side waiters as the file is closing so user count on the file |
669 | * side is zero. | 859 | * side is zero. |
670 | */ | 860 | */ |
671 | spin_lock_irqsave(&tty_ldisc_lock, flags); | 861 | |
672 | while (tty->ldisc.refcount) { | 862 | tty_ldisc_wait_idle(tty); |
673 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); | 863 | |
674 | wait_event(tty_ldisc_wait, tty->ldisc.refcount == 0); | ||
675 | spin_lock_irqsave(&tty_ldisc_lock, flags); | ||
676 | } | ||
677 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); | ||
678 | /* | 864 | /* |
679 | * Shutdown the current line discipline, and reset it to N_TTY. | 865 | * Shutdown the current line discipline, and reset it to N_TTY. |
680 | * | 866 | * |
681 | * FIXME: this MUST get fixed for the new reflocking | 867 | * FIXME: this MUST get fixed for the new reflocking |
682 | */ | 868 | */ |
683 | if (tty->ldisc.ops->close) | ||
684 | (tty->ldisc.ops->close)(tty); | ||
685 | tty_ldisc_put(tty->ldisc.ops); | ||
686 | 869 | ||
687 | /* | 870 | tty_ldisc_reinit(tty); |
688 | * Switch the line discipline back | 871 | /* This will need doing differently if we need to lock */ |
689 | */ | 872 | if (o_tty) |
690 | WARN_ON(tty_ldisc_get(N_TTY, &ld)); | 873 | tty_ldisc_release(o_tty, NULL); |
691 | tty_ldisc_assign(tty, &ld); | ||
692 | tty_set_termios_ldisc(tty, N_TTY); | ||
693 | if (o_tty) { | ||
694 | /* FIXME: could o_tty be in setldisc here ? */ | ||
695 | clear_bit(TTY_LDISC, &o_tty->flags); | ||
696 | if (o_tty->ldisc.ops->close) | ||
697 | (o_tty->ldisc.ops->close)(o_tty); | ||
698 | tty_ldisc_put(o_tty->ldisc.ops); | ||
699 | WARN_ON(tty_ldisc_get(N_TTY, &ld)); | ||
700 | tty_ldisc_assign(o_tty, &ld); | ||
701 | tty_set_termios_ldisc(o_tty, N_TTY); | ||
702 | } | ||
703 | } | 874 | } |
704 | 875 | ||
705 | /** | 876 | /** |
@@ -712,10 +883,10 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) | |||
712 | 883 | ||
713 | void tty_ldisc_init(struct tty_struct *tty) | 884 | void tty_ldisc_init(struct tty_struct *tty) |
714 | { | 885 | { |
715 | struct tty_ldisc ld; | 886 | struct tty_ldisc *ld = tty_ldisc_get(N_TTY); |
716 | if (tty_ldisc_get(N_TTY, &ld) < 0) | 887 | if (IS_ERR(ld)) |
717 | panic("n_tty: init_tty"); | 888 | panic("n_tty: init_tty"); |
718 | tty_ldisc_assign(tty, &ld); | 889 | tty_ldisc_assign(tty, ld); |
719 | } | 890 | } |
720 | 891 | ||
721 | void tty_ldisc_begin(void) | 892 | void tty_ldisc_begin(void) |