diff options
author | Peter Hurley <peter@hurleysoftware.com> | 2013-06-15 07:04:47 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-07-23 19:38:34 -0400 |
commit | d2c438905f9f718b3d9f5d89ce163fc22bd33995 (patch) | |
tree | 60ff9ab6543fe72fb1225e660a53dc2f147faecb /drivers/tty/tty_ldisc.c | |
parent | 137084bbaddf4f6dde948ef3a14e18ba0754cc0d (diff) |
tty: Add lock/unlock ldisc pair functions
Just as the tty pair must be locked in a stable sequence
(ie, independent of which is consider the 'other' tty), so must
the ldisc pair be locked in a stable sequence as well.
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/tty_ldisc.c')
-rw-r--r-- | drivers/tty/tty_ldisc.c | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 8166260aa839..418c9f64a9fd 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c | |||
@@ -31,6 +31,13 @@ | |||
31 | #define tty_ldisc_debug(tty, f, args...) | 31 | #define tty_ldisc_debug(tty, f, args...) |
32 | #endif | 32 | #endif |
33 | 33 | ||
34 | /* lockdep nested classes for tty->ldisc_sem */ | ||
35 | enum { | ||
36 | LDISC_SEM_NORMAL, | ||
37 | LDISC_SEM_OTHER, | ||
38 | }; | ||
39 | |||
40 | |||
34 | /* | 41 | /* |
35 | * This guards the refcounted line discipline lists. The lock | 42 | * This guards the refcounted line discipline lists. The lock |
36 | * must be taken with irqs off because there are hangup path | 43 | * must be taken with irqs off because there are hangup path |
@@ -351,6 +358,86 @@ void tty_ldisc_deref(struct tty_ldisc *ld) | |||
351 | } | 358 | } |
352 | EXPORT_SYMBOL_GPL(tty_ldisc_deref); | 359 | EXPORT_SYMBOL_GPL(tty_ldisc_deref); |
353 | 360 | ||
361 | |||
362 | static inline int __lockfunc | ||
363 | tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout) | ||
364 | { | ||
365 | return ldsem_down_write(&tty->ldisc_sem, timeout); | ||
366 | } | ||
367 | |||
368 | static inline int __lockfunc | ||
369 | tty_ldisc_lock_nested(struct tty_struct *tty, unsigned long timeout) | ||
370 | { | ||
371 | return ldsem_down_write_nested(&tty->ldisc_sem, | ||
372 | LDISC_SEM_OTHER, timeout); | ||
373 | } | ||
374 | |||
375 | static inline void tty_ldisc_unlock(struct tty_struct *tty) | ||
376 | { | ||
377 | return ldsem_up_write(&tty->ldisc_sem); | ||
378 | } | ||
379 | |||
380 | static int __lockfunc | ||
381 | tty_ldisc_lock_pair_timeout(struct tty_struct *tty, struct tty_struct *tty2, | ||
382 | unsigned long timeout) | ||
383 | { | ||
384 | int ret; | ||
385 | |||
386 | if (tty < tty2) { | ||
387 | ret = tty_ldisc_lock(tty, timeout); | ||
388 | if (ret) { | ||
389 | ret = tty_ldisc_lock_nested(tty2, timeout); | ||
390 | if (!ret) | ||
391 | tty_ldisc_unlock(tty); | ||
392 | } | ||
393 | } else { | ||
394 | /* if this is possible, it has lots of implications */ | ||
395 | WARN_ON_ONCE(tty == tty2); | ||
396 | if (tty2 && tty != tty2) { | ||
397 | ret = tty_ldisc_lock(tty2, timeout); | ||
398 | if (ret) { | ||
399 | ret = tty_ldisc_lock_nested(tty, timeout); | ||
400 | if (!ret) | ||
401 | tty_ldisc_unlock(tty2); | ||
402 | } | ||
403 | } else | ||
404 | ret = tty_ldisc_lock(tty, timeout); | ||
405 | } | ||
406 | |||
407 | if (!ret) | ||
408 | return -EBUSY; | ||
409 | |||
410 | set_bit(TTY_LDISC_HALTED, &tty->flags); | ||
411 | if (tty2) | ||
412 | set_bit(TTY_LDISC_HALTED, &tty2->flags); | ||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | static void __lockfunc | ||
417 | tty_ldisc_lock_pair(struct tty_struct *tty, struct tty_struct *tty2) | ||
418 | { | ||
419 | tty_ldisc_lock_pair_timeout(tty, tty2, MAX_SCHEDULE_TIMEOUT); | ||
420 | } | ||
421 | |||
422 | static void __lockfunc tty_ldisc_unlock_pair(struct tty_struct *tty, | ||
423 | struct tty_struct *tty2) | ||
424 | { | ||
425 | tty_ldisc_unlock(tty); | ||
426 | if (tty2) | ||
427 | tty_ldisc_unlock(tty2); | ||
428 | } | ||
429 | |||
430 | static void __lockfunc tty_ldisc_enable_pair(struct tty_struct *tty, | ||
431 | struct tty_struct *tty2) | ||
432 | { | ||
433 | clear_bit(TTY_LDISC_HALTED, &tty->flags); | ||
434 | if (tty2) | ||
435 | clear_bit(TTY_LDISC_HALTED, &tty2->flags); | ||
436 | |||
437 | tty_ldisc_unlock_pair(tty, tty2); | ||
438 | } | ||
439 | |||
440 | |||
354 | /** | 441 | /** |
355 | * tty_ldisc_enable - allow ldisc use | 442 | * tty_ldisc_enable - allow ldisc use |
356 | * @tty: terminal to activate ldisc on | 443 | * @tty: terminal to activate ldisc on |