aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/tty_ldisc.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2009-08-12 20:44:53 -0400
committerDavid S. Miller <davem@davemloft.net>2009-08-12 20:44:53 -0400
commitaa11d958d1a6572eda08214d7c6a735804fe48a5 (patch)
treed025b05270ad1e010660d17eeadc6ac3c1abbd7d /drivers/char/tty_ldisc.c
parent07f6642ee9418e962e54cbc07471cfe2e559c568 (diff)
parent9799218ae36910af50f002a5db1802d576fffb43 (diff)
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
Conflicts: arch/microblaze/include/asm/socket.h
Diffstat (limited to 'drivers/char/tty_ldisc.c')
-rw-r--r--drivers/char/tty_ldisc.c176
1 files changed, 67 insertions, 109 deletions
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c
index 913aa8d3f1c5..1733d3439ad2 100644
--- a/drivers/char/tty_ldisc.c
+++ b/drivers/char/tty_ldisc.c
@@ -21,7 +21,6 @@
21#include <linux/proc_fs.h> 21#include <linux/proc_fs.h>
22#include <linux/init.h> 22#include <linux/init.h>
23#include <linux/module.h> 23#include <linux/module.h>
24#include <linux/smp_lock.h>
25#include <linux/device.h> 24#include <linux/device.h>
26#include <linux/wait.h> 25#include <linux/wait.h>
27#include <linux/bitops.h> 26#include <linux/bitops.h>
@@ -49,6 +48,41 @@ static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
49/* Line disc dispatch table */ 48/* Line disc dispatch table */
50static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS]; 49static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
51 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
52/** 86/**
53 * tty_register_ldisc - install a line discipline 87 * tty_register_ldisc - install a line discipline
54 * @disc: ldisc number 88 * @disc: ldisc number
@@ -143,7 +177,7 @@ static struct tty_ldisc *tty_ldisc_try_get(int disc)
143 /* lock it */ 177 /* lock it */
144 ldops->refcount++; 178 ldops->refcount++;
145 ld->ops = ldops; 179 ld->ops = ldops;
146 ld->refcount = 0; 180 atomic_set(&ld->users, 1);
147 err = 0; 181 err = 0;
148 } 182 }
149 } 183 }
@@ -182,35 +216,6 @@ static struct tty_ldisc *tty_ldisc_get(int disc)
182 return ld; 216 return ld;
183} 217}
184 218
185/**
186 * tty_ldisc_put - drop ldisc reference
187 * @ld: ldisc
188 *
189 * Drop a reference to a line discipline. Manage refcounts and
190 * module usage counts. Free the ldisc once the recount hits zero.
191 *
192 * Locking:
193 * takes tty_ldisc_lock to guard against ldisc races
194 */
195
196static void tty_ldisc_put(struct tty_ldisc *ld)
197{
198 unsigned long flags;
199 int disc = ld->ops->num;
200 struct tty_ldisc_ops *ldo;
201
202 BUG_ON(disc < N_TTY || disc >= NR_LDISCS);
203
204 spin_lock_irqsave(&tty_ldisc_lock, flags);
205 ldo = tty_ldiscs[disc];
206 BUG_ON(ldo->refcount == 0);
207 ldo->refcount--;
208 module_put(ldo->owner);
209 spin_unlock_irqrestore(&tty_ldisc_lock, flags);
210 WARN_ON(ld->refcount);
211 kfree(ld);
212}
213
214static 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)
215{ 220{
216 return (*pos < NR_LDISCS) ? pos : NULL; 221 return (*pos < NR_LDISCS) ? pos : NULL;
@@ -235,7 +240,7 @@ static int tty_ldiscs_seq_show(struct seq_file *m, void *v)
235 if (IS_ERR(ld)) 240 if (IS_ERR(ld))
236 return 0; 241 return 0;
237 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);
238 tty_ldisc_put(ld); 243 put_ldisc(ld);
239 return 0; 244 return 0;
240} 245}
241 246
@@ -289,20 +294,17 @@ static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
289 * Locking: takes tty_ldisc_lock 294 * Locking: takes tty_ldisc_lock
290 */ 295 */
291 296
292static int tty_ldisc_try(struct tty_struct *tty) 297static struct tty_ldisc *tty_ldisc_try(struct tty_struct *tty)
293{ 298{
294 unsigned long flags; 299 unsigned long flags;
295 struct tty_ldisc *ld; 300 struct tty_ldisc *ld;
296 int ret = 0;
297 301
298 spin_lock_irqsave(&tty_ldisc_lock, flags); 302 spin_lock_irqsave(&tty_ldisc_lock, flags);
299 ld = tty->ldisc; 303 ld = NULL;
300 if (test_bit(TTY_LDISC, &tty->flags)) { 304 if (test_bit(TTY_LDISC, &tty->flags))
301 ld->refcount++; 305 ld = get_ldisc(tty->ldisc);
302 ret = 1;
303 }
304 spin_unlock_irqrestore(&tty_ldisc_lock, flags); 306 spin_unlock_irqrestore(&tty_ldisc_lock, flags);
305 return ret; 307 return ld;
306} 308}
307 309
308/** 310/**
@@ -323,10 +325,11 @@ static int tty_ldisc_try(struct tty_struct *tty)
323 325
324struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty) 326struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
325{ 327{
328 struct tty_ldisc *ld;
329
326 /* wait_event is a macro */ 330 /* wait_event is a macro */
327 wait_event(tty_ldisc_wait, tty_ldisc_try(tty)); 331 wait_event(tty_ldisc_wait, (ld = tty_ldisc_try(tty)) != NULL);
328 WARN_ON(tty->ldisc->refcount == 0); 332 return ld;
329 return tty->ldisc;
330} 333}
331EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); 334EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
332 335
@@ -343,9 +346,7 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
343 346
344struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty) 347struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty)
345{ 348{
346 if (tty_ldisc_try(tty)) 349 return tty_ldisc_try(tty);
347 return tty->ldisc;
348 return NULL;
349} 350}
350EXPORT_SYMBOL_GPL(tty_ldisc_ref); 351EXPORT_SYMBOL_GPL(tty_ldisc_ref);
351 352
@@ -361,21 +362,15 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref);
361 362
362void tty_ldisc_deref(struct tty_ldisc *ld) 363void tty_ldisc_deref(struct tty_ldisc *ld)
363{ 364{
364 unsigned long flags; 365 put_ldisc(ld);
365
366 BUG_ON(ld == NULL);
367
368 spin_lock_irqsave(&tty_ldisc_lock, flags);
369 if (ld->refcount == 0)
370 printk(KERN_ERR "tty_ldisc_deref: no references.\n");
371 else
372 ld->refcount--;
373 if (ld->refcount == 0)
374 wake_up(&tty_ldisc_wait);
375 spin_unlock_irqrestore(&tty_ldisc_lock, flags);
376} 366}
377EXPORT_SYMBOL_GPL(tty_ldisc_deref); 367EXPORT_SYMBOL_GPL(tty_ldisc_deref);
378 368
369static inline void tty_ldisc_put(struct tty_ldisc *ld)
370{
371 put_ldisc(ld);
372}
373
379/** 374/**
380 * tty_ldisc_enable - allow ldisc use 375 * tty_ldisc_enable - allow ldisc use
381 * @tty: terminal to activate ldisc on 376 * @tty: terminal to activate ldisc on
@@ -524,31 +519,6 @@ static int tty_ldisc_halt(struct tty_struct *tty)
524} 519}
525 520
526/** 521/**
527 * tty_ldisc_wait_idle - wait for the ldisc to become idle
528 * @tty: tty to wait for
529 *
530 * Wait for the line discipline to become idle. The discipline must
531 * have been halted for this to guarantee it remains idle.
532 *
533 * tty_ldisc_lock protects the ref counts currently.
534 */
535
536static int tty_ldisc_wait_idle(struct tty_struct *tty)
537{
538 unsigned long flags;
539 spin_lock_irqsave(&tty_ldisc_lock, flags);
540 while (tty->ldisc->refcount) {
541 spin_unlock_irqrestore(&tty_ldisc_lock, flags);
542 if (wait_event_timeout(tty_ldisc_wait,
543 tty->ldisc->refcount == 0, 5 * HZ) == 0)
544 return -EBUSY;
545 spin_lock_irqsave(&tty_ldisc_lock, flags);
546 }
547 spin_unlock_irqrestore(&tty_ldisc_lock, flags);
548 return 0;
549}
550
551/**
552 * tty_set_ldisc - set line discipline 522 * tty_set_ldisc - set line discipline
553 * @tty: the terminal to set 523 * @tty: the terminal to set
554 * @ldisc: the line discipline 524 * @ldisc: the line discipline
@@ -643,14 +613,6 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
643 613
644 flush_scheduled_work(); 614 flush_scheduled_work();
645 615
646 /* Let any existing reference holders finish */
647 retval = tty_ldisc_wait_idle(tty);
648 if (retval < 0) {
649 clear_bit(TTY_LDISC_CHANGING, &tty->flags);
650 tty_ldisc_put(new_ldisc);
651 return retval;
652 }
653
654 mutex_lock(&tty->ldisc_mutex); 616 mutex_lock(&tty->ldisc_mutex);
655 if (test_bit(TTY_HUPPED, &tty->flags)) { 617 if (test_bit(TTY_HUPPED, &tty->flags)) {
656 /* We were raced by the hangup method. It will have stomped 618 /* We were raced by the hangup method. It will have stomped
@@ -791,17 +753,19 @@ void tty_ldisc_hangup(struct tty_struct *tty)
791 * N_TTY. 753 * N_TTY.
792 */ 754 */
793 if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { 755 if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
794 /* Avoid racing set_ldisc */ 756 /* Avoid racing set_ldisc or tty_ldisc_release */
795 mutex_lock(&tty->ldisc_mutex); 757 mutex_lock(&tty->ldisc_mutex);
796 /* Switch back to N_TTY */ 758 if (tty->ldisc) { /* Not yet closed */
797 tty_ldisc_halt(tty); 759 /* Switch back to N_TTY */
798 tty_ldisc_wait_idle(tty); 760 tty_ldisc_halt(tty);
799 tty_ldisc_reinit(tty); 761 tty_ldisc_reinit(tty);
800 /* 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
801 reopen it. We could defer this to the next open but 763 reopen it. We could defer this to the next open but
802 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
803 WARN_ON(tty_ldisc_open(tty, tty->ldisc)); 765 a FIXME */
804 tty_ldisc_enable(tty); 766 WARN_ON(tty_ldisc_open(tty, tty->ldisc));
767 tty_ldisc_enable(tty);
768 }
805 mutex_unlock(&tty->ldisc_mutex); 769 mutex_unlock(&tty->ldisc_mutex);
806 tty_reset_termios(tty); 770 tty_reset_termios(tty);
807 } 771 }
@@ -858,14 +822,7 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
858 tty_ldisc_halt(tty); 822 tty_ldisc_halt(tty);
859 flush_scheduled_work(); 823 flush_scheduled_work();
860 824
861 /* 825 mutex_lock(&tty->ldisc_mutex);
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 /* 826 /*
870 * Now kill off the ldisc 827 * Now kill off the ldisc
871 */ 828 */
@@ -876,6 +833,7 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
876 833
877 /* Ensure the next open requests the N_TTY ldisc */ 834 /* Ensure the next open requests the N_TTY ldisc */
878 tty_set_termios_ldisc(tty, N_TTY); 835 tty_set_termios_ldisc(tty, N_TTY);
836 mutex_unlock(&tty->ldisc_mutex);
879 837
880 /* This will need doing differently if we need to lock */ 838 /* This will need doing differently if we need to lock */
881 if (o_tty) 839 if (o_tty)