aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/tty_ldisc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/tty_ldisc.c')
-rw-r--r--drivers/char/tty_ldisc.c175
1 files changed, 67 insertions, 108 deletions
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c
index 0ef0dc97ba20..1733d3439ad2 100644
--- a/drivers/char/tty_ldisc.c
+++ b/drivers/char/tty_ldisc.c
@@ -48,6 +48,41 @@ static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
48/* Line disc dispatch table */ 48/* Line disc dispatch table */
49static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS]; 49static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
50 50
51static inline struct tty_ldisc *get_ldisc(struct tty_ldisc *ld)
52{
53 if (ld)
54 atomic_inc(&ld->users);
55 return ld;
56}
57
58static void put_ldisc(struct tty_ldisc *ld)
59{
60 unsigned long flags;
61
62 if (WARN_ON_ONCE(!ld))
63 return;
64
65 /*
66 * If this is the last user, free the ldisc, and
67 * release the ldisc ops.
68 *
69 * We really want an "atomic_dec_and_lock_irqsave()",
70 * but we don't have it, so this does it by hand.
71 */
72 local_irq_save(flags);
73 if (atomic_dec_and_lock(&ld->users, &tty_ldisc_lock)) {
74 struct tty_ldisc_ops *ldo = ld->ops;
75
76 ldo->refcount--;
77 module_put(ldo->owner);
78 spin_unlock_irqrestore(&tty_ldisc_lock, flags);
79
80 kfree(ld);
81 return;
82 }
83 local_irq_restore(flags);
84}
85
51/** 86/**
52 * tty_register_ldisc - install a line discipline 87 * tty_register_ldisc - install a line discipline
53 * @disc: ldisc number 88 * @disc: ldisc number
@@ -142,7 +177,7 @@ static struct tty_ldisc *tty_ldisc_try_get(int disc)
142 /* lock it */ 177 /* lock it */
143 ldops->refcount++; 178 ldops->refcount++;
144 ld->ops = ldops; 179 ld->ops = ldops;
145 ld->refcount = 0; 180 atomic_set(&ld->users, 1);
146 err = 0; 181 err = 0;
147 } 182 }
148 } 183 }
@@ -181,35 +216,6 @@ static struct tty_ldisc *tty_ldisc_get(int disc)
181 return ld; 216 return ld;
182} 217}
183 218
184/**
185 * tty_ldisc_put - drop ldisc reference
186 * @ld: ldisc
187 *
188 * Drop a reference to a line discipline. Manage refcounts and
189 * module usage counts. Free the ldisc once the recount hits zero.
190 *
191 * Locking:
192 * takes tty_ldisc_lock to guard against ldisc races
193 */
194
195static void tty_ldisc_put(struct tty_ldisc *ld)
196{
197 unsigned long flags;
198 int disc = ld->ops->num;
199 struct tty_ldisc_ops *ldo;
200
201 BUG_ON(disc < N_TTY || disc >= NR_LDISCS);
202
203 spin_lock_irqsave(&tty_ldisc_lock, flags);
204 ldo = tty_ldiscs[disc];
205 BUG_ON(ldo->refcount == 0);
206 ldo->refcount--;
207 module_put(ldo->owner);
208 spin_unlock_irqrestore(&tty_ldisc_lock, flags);
209 WARN_ON(ld->refcount);
210 kfree(ld);
211}
212
213static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos) 219static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
214{ 220{
215 return (*pos < NR_LDISCS) ? pos : NULL; 221 return (*pos < NR_LDISCS) ? pos : NULL;
@@ -234,7 +240,7 @@ static int tty_ldiscs_seq_show(struct seq_file *m, void *v)
234 if (IS_ERR(ld)) 240 if (IS_ERR(ld))
235 return 0; 241 return 0;
236 seq_printf(m, "%-10s %2d\n", ld->ops->name ? ld->ops->name : "???", i); 242 seq_printf(m, "%-10s %2d\n", ld->ops->name ? ld->ops->name : "???", i);
237 tty_ldisc_put(ld); 243 put_ldisc(ld);
238 return 0; 244 return 0;
239} 245}
240 246
@@ -288,20 +294,17 @@ static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
288 * Locking: takes tty_ldisc_lock 294 * Locking: takes tty_ldisc_lock
289 */ 295 */
290 296
291static int tty_ldisc_try(struct tty_struct *tty) 297static struct tty_ldisc *tty_ldisc_try(struct tty_struct *tty)
292{ 298{
293 unsigned long flags; 299 unsigned long flags;
294 struct tty_ldisc *ld; 300 struct tty_ldisc *ld;
295 int ret = 0;
296 301
297 spin_lock_irqsave(&tty_ldisc_lock, flags); 302 spin_lock_irqsave(&tty_ldisc_lock, flags);
298 ld = tty->ldisc; 303 ld = NULL;
299 if (test_bit(TTY_LDISC, &tty->flags)) { 304 if (test_bit(TTY_LDISC, &tty->flags))
300 ld->refcount++; 305 ld = get_ldisc(tty->ldisc);
301 ret = 1;
302 }
303 spin_unlock_irqrestore(&tty_ldisc_lock, flags); 306 spin_unlock_irqrestore(&tty_ldisc_lock, flags);
304 return ret; 307 return ld;
305} 308}
306 309
307/** 310/**
@@ -322,10 +325,11 @@ static int tty_ldisc_try(struct tty_struct *tty)
322 325
323struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty) 326struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
324{ 327{
328 struct tty_ldisc *ld;
329
325 /* wait_event is a macro */ 330 /* wait_event is a macro */
326 wait_event(tty_ldisc_wait, tty_ldisc_try(tty)); 331 wait_event(tty_ldisc_wait, (ld = tty_ldisc_try(tty)) != NULL);
327 WARN_ON(tty->ldisc->refcount == 0); 332 return ld;
328 return tty->ldisc;
329} 333}
330EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); 334EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
331 335
@@ -342,9 +346,7 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
342 346
343struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty) 347struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty)
344{ 348{
345 if (tty_ldisc_try(tty)) 349 return tty_ldisc_try(tty);
346 return tty->ldisc;
347 return NULL;
348} 350}
349EXPORT_SYMBOL_GPL(tty_ldisc_ref); 351EXPORT_SYMBOL_GPL(tty_ldisc_ref);
350 352
@@ -360,21 +362,15 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref);
360 362
361void tty_ldisc_deref(struct tty_ldisc *ld) 363void tty_ldisc_deref(struct tty_ldisc *ld)
362{ 364{
363 unsigned long flags; 365 put_ldisc(ld);
364
365 BUG_ON(ld == NULL);
366
367 spin_lock_irqsave(&tty_ldisc_lock, flags);
368 if (ld->refcount == 0)
369 printk(KERN_ERR "tty_ldisc_deref: no references.\n");
370 else
371 ld->refcount--;
372 if (ld->refcount == 0)
373 wake_up(&tty_ldisc_wait);
374 spin_unlock_irqrestore(&tty_ldisc_lock, flags);
375} 366}
376EXPORT_SYMBOL_GPL(tty_ldisc_deref); 367EXPORT_SYMBOL_GPL(tty_ldisc_deref);
377 368
369static inline void tty_ldisc_put(struct tty_ldisc *ld)
370{
371 put_ldisc(ld);
372}
373
378/** 374/**
379 * tty_ldisc_enable - allow ldisc use 375 * tty_ldisc_enable - allow ldisc use
380 * @tty: terminal to activate ldisc on 376 * @tty: terminal to activate ldisc on
@@ -523,31 +519,6 @@ static int tty_ldisc_halt(struct tty_struct *tty)
523} 519}
524 520
525/** 521/**
526 * tty_ldisc_wait_idle - wait for the ldisc to become idle
527 * @tty: tty to wait for
528 *
529 * Wait for the line discipline to become idle. The discipline must
530 * have been halted for this to guarantee it remains idle.
531 *
532 * tty_ldisc_lock protects the ref counts currently.
533 */
534
535static int tty_ldisc_wait_idle(struct tty_struct *tty)
536{
537 unsigned long flags;
538 spin_lock_irqsave(&tty_ldisc_lock, flags);
539 while (tty->ldisc->refcount) {
540 spin_unlock_irqrestore(&tty_ldisc_lock, flags);
541 if (wait_event_timeout(tty_ldisc_wait,
542 tty->ldisc->refcount == 0, 5 * HZ) == 0)
543 return -EBUSY;
544 spin_lock_irqsave(&tty_ldisc_lock, flags);
545 }
546 spin_unlock_irqrestore(&tty_ldisc_lock, flags);
547 return 0;
548}
549
550/**
551 * tty_set_ldisc - set line discipline 522 * tty_set_ldisc - set line discipline
552 * @tty: the terminal to set 523 * @tty: the terminal to set
553 * @ldisc: the line discipline 524 * @ldisc: the line discipline
@@ -642,14 +613,6 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
642 613
643 flush_scheduled_work(); 614 flush_scheduled_work();
644 615
645 /* Let any existing reference holders finish */
646 retval = tty_ldisc_wait_idle(tty);
647 if (retval < 0) {
648 clear_bit(TTY_LDISC_CHANGING, &tty->flags);
649 tty_ldisc_put(new_ldisc);
650 return retval;
651 }
652
653 mutex_lock(&tty->ldisc_mutex); 616 mutex_lock(&tty->ldisc_mutex);
654 if (test_bit(TTY_HUPPED, &tty->flags)) { 617 if (test_bit(TTY_HUPPED, &tty->flags)) {
655 /* We were raced by the hangup method. It will have stomped 618 /* We were raced by the hangup method. It will have stomped
@@ -790,17 +753,19 @@ void tty_ldisc_hangup(struct tty_struct *tty)
790 * N_TTY. 753 * N_TTY.
791 */ 754 */
792 if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { 755 if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
793 /* Avoid racing set_ldisc */ 756 /* Avoid racing set_ldisc or tty_ldisc_release */
794 mutex_lock(&tty->ldisc_mutex); 757 mutex_lock(&tty->ldisc_mutex);
795 /* Switch back to N_TTY */ 758 if (tty->ldisc) { /* Not yet closed */
796 tty_ldisc_halt(tty); 759 /* Switch back to N_TTY */
797 tty_ldisc_wait_idle(tty); 760 tty_ldisc_halt(tty);
798 tty_ldisc_reinit(tty); 761 tty_ldisc_reinit(tty);
799 /* At this point we have a closed ldisc and we want to 762 /* At this point we have a closed ldisc and we want to
800 reopen it. We could defer this to the next open but 763 reopen it. We could defer this to the next open but
801 it means auditing a lot of other paths so this is a FIXME */ 764 it means auditing a lot of other paths so this is
802 WARN_ON(tty_ldisc_open(tty, tty->ldisc)); 765 a FIXME */
803 tty_ldisc_enable(tty); 766 WARN_ON(tty_ldisc_open(tty, tty->ldisc));
767 tty_ldisc_enable(tty);
768 }
804 mutex_unlock(&tty->ldisc_mutex); 769 mutex_unlock(&tty->ldisc_mutex);
805 tty_reset_termios(tty); 770 tty_reset_termios(tty);
806 } 771 }
@@ -857,14 +822,7 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
857 tty_ldisc_halt(tty); 822 tty_ldisc_halt(tty);
858 flush_scheduled_work(); 823 flush_scheduled_work();
859 824
860 /* 825 mutex_lock(&tty->ldisc_mutex);
861 * Wait for any short term users (we know they are just driver
862 * side waiters as the file is closing so user count on the file
863 * side is zero.
864 */
865
866 tty_ldisc_wait_idle(tty);
867
868 /* 826 /*
869 * Now kill off the ldisc 827 * Now kill off the ldisc
870 */ 828 */
@@ -875,6 +833,7 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
875 833
876 /* Ensure the next open requests the N_TTY ldisc */ 834 /* Ensure the next open requests the N_TTY ldisc */
877 tty_set_termios_ldisc(tty, N_TTY); 835 tty_set_termios_ldisc(tty, N_TTY);
836 mutex_unlock(&tty->ldisc_mutex);
878 837
879 /* This will need doing differently if we need to lock */ 838 /* This will need doing differently if we need to lock */
880 if (o_tty) 839 if (o_tty)