aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/char/tty_ldisc.c143
1 files changed, 46 insertions, 97 deletions
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c
index fd175e60aad5..be55dfcf59ac 100644
--- a/drivers/char/tty_ldisc.c
+++ b/drivers/char/tty_ldisc.c
@@ -48,6 +48,34 @@ 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 inline void put_ldisc(struct tty_ldisc *ld)
59{
60 if (WARN_ON_ONCE(!ld))
61 return;
62
63 /*
64 * If this is the last user, free the ldisc, and
65 * release the ldisc ops.
66 */
67 if (atomic_dec_and_test(&ld->users)) {
68 unsigned long flags;
69 struct tty_ldisc_ops *ldo = ld->ops;
70
71 kfree(ld);
72 spin_lock_irqsave(&tty_ldisc_lock, flags);
73 ldo->refcount--;
74 module_put(ldo->owner);
75 spin_unlock_irqrestore(&tty_ldisc_lock, flags);
76 }
77}
78
51/** 79/**
52 * tty_register_ldisc - install a line discipline 80 * tty_register_ldisc - install a line discipline
53 * @disc: ldisc number 81 * @disc: ldisc number
@@ -142,7 +170,7 @@ static struct tty_ldisc *tty_ldisc_try_get(int disc)
142 /* lock it */ 170 /* lock it */
143 ldops->refcount++; 171 ldops->refcount++;
144 ld->ops = ldops; 172 ld->ops = ldops;
145 atomic_set(&ld->users, 0); 173 atomic_set(&ld->users, 1);
146 err = 0; 174 err = 0;
147 } 175 }
148 } 176 }
@@ -181,35 +209,6 @@ static struct tty_ldisc *tty_ldisc_get(int disc)
181 return ld; 209 return ld;
182} 210}
183 211
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(atomic_read(&ld->users));
210 kfree(ld);
211}
212
213static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos) 212static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
214{ 213{
215 return (*pos < NR_LDISCS) ? pos : NULL; 214 return (*pos < NR_LDISCS) ? pos : NULL;
@@ -234,7 +233,7 @@ static int tty_ldiscs_seq_show(struct seq_file *m, void *v)
234 if (IS_ERR(ld)) 233 if (IS_ERR(ld))
235 return 0; 234 return 0;
236 seq_printf(m, "%-10s %2d\n", ld->ops->name ? ld->ops->name : "???", i); 235 seq_printf(m, "%-10s %2d\n", ld->ops->name ? ld->ops->name : "???", i);
237 tty_ldisc_put(ld); 236 put_ldisc(ld);
238 return 0; 237 return 0;
239} 238}
240 239
@@ -288,20 +287,17 @@ static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
288 * Locking: takes tty_ldisc_lock 287 * Locking: takes tty_ldisc_lock
289 */ 288 */
290 289
291static int tty_ldisc_try(struct tty_struct *tty) 290static struct tty_ldisc *tty_ldisc_try(struct tty_struct *tty)
292{ 291{
293 unsigned long flags; 292 unsigned long flags;
294 struct tty_ldisc *ld; 293 struct tty_ldisc *ld;
295 int ret = 0;
296 294
297 spin_lock_irqsave(&tty_ldisc_lock, flags); 295 spin_lock_irqsave(&tty_ldisc_lock, flags);
298 ld = tty->ldisc; 296 ld = NULL;
299 if (test_bit(TTY_LDISC, &tty->flags)) { 297 if (test_bit(TTY_LDISC, &tty->flags))
300 atomic_inc(&ld->users); 298 ld = get_ldisc(tty->ldisc);
301 ret = 1;
302 }
303 spin_unlock_irqrestore(&tty_ldisc_lock, flags); 299 spin_unlock_irqrestore(&tty_ldisc_lock, flags);
304 return ret; 300 return ld;
305} 301}
306 302
307/** 303/**
@@ -322,10 +318,11 @@ static int tty_ldisc_try(struct tty_struct *tty)
322 318
323struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty) 319struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
324{ 320{
321 struct tty_ldisc *ld;
322
325 /* wait_event is a macro */ 323 /* wait_event is a macro */
326 wait_event(tty_ldisc_wait, tty_ldisc_try(tty)); 324 wait_event(tty_ldisc_wait, (ld = tty_ldisc_try(tty)) != NULL);
327 WARN_ON(atomic_read(&tty->ldisc->users) == 0); 325 return ld;
328 return tty->ldisc;
329} 326}
330EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); 327EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
331 328
@@ -342,9 +339,7 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
342 339
343struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty) 340struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty)
344{ 341{
345 if (tty_ldisc_try(tty)) 342 return tty_ldisc_try(tty);
346 return tty->ldisc;
347 return NULL;
348} 343}
349EXPORT_SYMBOL_GPL(tty_ldisc_ref); 344EXPORT_SYMBOL_GPL(tty_ldisc_ref);
350 345
@@ -360,19 +355,15 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref);
360 355
361void tty_ldisc_deref(struct tty_ldisc *ld) 356void tty_ldisc_deref(struct tty_ldisc *ld)
362{ 357{
363 unsigned long flags; 358 put_ldisc(ld);
364
365 BUG_ON(ld == NULL);
366
367 spin_lock_irqsave(&tty_ldisc_lock, flags);
368 if (atomic_read(&ld->users) == 0)
369 printk(KERN_ERR "tty_ldisc_deref: no references.\n");
370 else if (atomic_dec_and_test(&ld->users))
371 wake_up(&tty_ldisc_wait);
372 spin_unlock_irqrestore(&tty_ldisc_lock, flags);
373} 359}
374EXPORT_SYMBOL_GPL(tty_ldisc_deref); 360EXPORT_SYMBOL_GPL(tty_ldisc_deref);
375 361
362static inline void tty_ldisc_put(struct tty_ldisc *ld)
363{
364 put_ldisc(ld);
365}
366
376/** 367/**
377 * tty_ldisc_enable - allow ldisc use 368 * tty_ldisc_enable - allow ldisc use
378 * @tty: terminal to activate ldisc on 369 * @tty: terminal to activate ldisc on
@@ -521,31 +512,6 @@ static int tty_ldisc_halt(struct tty_struct *tty)
521} 512}
522 513
523/** 514/**
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
533static int tty_ldisc_wait_idle(struct tty_struct *tty)
534{
535 unsigned long flags;
536 spin_lock_irqsave(&tty_ldisc_lock, flags);
537 while (atomic_read(&tty->ldisc->users)) {
538 spin_unlock_irqrestore(&tty_ldisc_lock, flags);
539 if (wait_event_timeout(tty_ldisc_wait,
540 atomic_read(&tty->ldisc->users) == 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/**
549 * tty_set_ldisc - set line discipline 515 * tty_set_ldisc - set line discipline
550 * @tty: the terminal to set 516 * @tty: the terminal to set
551 * @ldisc: the line discipline 517 * @ldisc: the line discipline
@@ -640,14 +606,6 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
640 606
641 flush_scheduled_work(); 607 flush_scheduled_work();
642 608
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); 609 mutex_lock(&tty->ldisc_mutex);
652 if (test_bit(TTY_HUPPED, &tty->flags)) { 610 if (test_bit(TTY_HUPPED, &tty->flags)) {
653 /* We were raced by the hangup method. It will have stomped 611 /* We were raced by the hangup method. It will have stomped
@@ -793,7 +751,6 @@ void tty_ldisc_hangup(struct tty_struct *tty)
793 if (tty->ldisc) { /* Not yet closed */ 751 if (tty->ldisc) { /* Not yet closed */
794 /* Switch back to N_TTY */ 752 /* Switch back to N_TTY */
795 tty_ldisc_halt(tty); 753 tty_ldisc_halt(tty);
796 tty_ldisc_wait_idle(tty);
797 tty_ldisc_reinit(tty); 754 tty_ldisc_reinit(tty);
798 /* At this point we have a closed ldisc and we want to 755 /* At this point we have a closed ldisc and we want to
799 reopen it. We could defer this to the next open but 756 reopen it. We could defer this to the next open but
@@ -858,14 +815,6 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
858 tty_ldisc_halt(tty); 815 tty_ldisc_halt(tty);
859 flush_scheduled_work(); 816 flush_scheduled_work();
860 817
861 /*
862 * Wait for any short term users (we know they are just driver
863 * side waiters as the file is closing so user count on the file
864 * side is zero.
865 */
866
867 tty_ldisc_wait_idle(tty);
868
869 mutex_lock(&tty->ldisc_mutex); 818 mutex_lock(&tty->ldisc_mutex);
870 /* 819 /*
871 * Now kill off the ldisc 820 * Now kill off the ldisc