diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/bluetooth/hci_ldisc.c | 4 | ||||
-rw-r--r-- | drivers/char/cyclades.c | 2 | ||||
-rw-r--r-- | drivers/char/epca.c | 4 | ||||
-rw-r--r-- | drivers/char/ip2/i2lib.c | 4 | ||||
-rw-r--r-- | drivers/char/ip2/ip2main.c | 4 | ||||
-rw-r--r-- | drivers/char/n_hdlc.c | 4 | ||||
-rw-r--r-- | drivers/char/pty.c | 10 | ||||
-rw-r--r-- | drivers/char/selection.c | 2 | ||||
-rw-r--r-- | drivers/char/tty_io.c | 64 | ||||
-rw-r--r-- | drivers/char/tty_ldisc.c | 477 |
10 files changed, 323 insertions, 252 deletions
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index af761dc434f6..688015128594 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c | |||
@@ -277,8 +277,8 @@ static int hci_uart_tty_open(struct tty_struct *tty) | |||
277 | /* FIXME: why is this needed. Note don't use ldisc_ref here as the | 277 | /* FIXME: why is this needed. Note don't use ldisc_ref here as the |
278 | open path is before the ldisc is referencable */ | 278 | open path is before the ldisc is referencable */ |
279 | 279 | ||
280 | if (tty->ldisc.ops->flush_buffer) | 280 | if (tty->ldisc->ops->flush_buffer) |
281 | tty->ldisc.ops->flush_buffer(tty); | 281 | tty->ldisc->ops->flush_buffer(tty); |
282 | tty_driver_flush_buffer(tty); | 282 | tty_driver_flush_buffer(tty); |
283 | 283 | ||
284 | return 0; | 284 | return 0; |
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index 456019051742..f3366d3f06cf 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c | |||
@@ -5200,7 +5200,7 @@ static int cyclades_proc_show(struct seq_file *m, void *v) | |||
5200 | (cur_jifs - info->idle_stats.recv_idle)/ | 5200 | (cur_jifs - info->idle_stats.recv_idle)/ |
5201 | HZ, info->idle_stats.overruns, | 5201 | HZ, info->idle_stats.overruns, |
5202 | /* FIXME: double check locking */ | 5202 | /* FIXME: double check locking */ |
5203 | (long)info->port.tty->ldisc.ops->num); | 5203 | (long)info->port.tty->ldisc->ops->num); |
5204 | else | 5204 | else |
5205 | seq_printf(m, "%3d %8lu %10lu %8lu " | 5205 | seq_printf(m, "%3d %8lu %10lu %8lu " |
5206 | "%10lu %8lu %9lu %6ld\n", | 5206 | "%10lu %8lu %9lu %6ld\n", |
diff --git a/drivers/char/epca.c b/drivers/char/epca.c index 710ee9333057..abef1f7d84fe 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c | |||
@@ -2114,8 +2114,8 @@ static int pc_ioctl(struct tty_struct *tty, struct file *file, | |||
2114 | tty_wait_until_sent(tty, 0); | 2114 | tty_wait_until_sent(tty, 0); |
2115 | } else { | 2115 | } else { |
2116 | /* ldisc lock already held in ioctl */ | 2116 | /* ldisc lock already held in ioctl */ |
2117 | if (tty->ldisc.ops->flush_buffer) | 2117 | if (tty->ldisc->ops->flush_buffer) |
2118 | tty->ldisc.ops->flush_buffer(tty); | 2118 | tty->ldisc->ops->flush_buffer(tty); |
2119 | } | 2119 | } |
2120 | unlock_kernel(); | 2120 | unlock_kernel(); |
2121 | /* Fall Thru */ | 2121 | /* Fall Thru */ |
diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c index 0061e18aff60..0d10b89218ed 100644 --- a/drivers/char/ip2/i2lib.c +++ b/drivers/char/ip2/i2lib.c | |||
@@ -868,11 +868,11 @@ i2Input(i2ChanStrPtr pCh) | |||
868 | amountToMove = count; | 868 | amountToMove = count; |
869 | } | 869 | } |
870 | // Move the first block | 870 | // Move the first block |
871 | pCh->pTTY->ldisc.ops->receive_buf( pCh->pTTY, | 871 | pCh->pTTY->ldisc->ops->receive_buf( pCh->pTTY, |
872 | &(pCh->Ibuf[stripIndex]), NULL, amountToMove ); | 872 | &(pCh->Ibuf[stripIndex]), NULL, amountToMove ); |
873 | // If we needed to wrap, do the second data move | 873 | // If we needed to wrap, do the second data move |
874 | if (count > amountToMove) { | 874 | if (count > amountToMove) { |
875 | pCh->pTTY->ldisc.ops->receive_buf( pCh->pTTY, | 875 | pCh->pTTY->ldisc->ops->receive_buf( pCh->pTTY, |
876 | pCh->Ibuf, NULL, count - amountToMove ); | 876 | pCh->Ibuf, NULL, count - amountToMove ); |
877 | } | 877 | } |
878 | // Bump and wrap the stripIndex all at once by the amount of data read. This | 878 | // Bump and wrap the stripIndex all at once by the amount of data read. This |
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index afd9247cf082..517271c762e6 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c | |||
@@ -1315,8 +1315,8 @@ static inline void isig(int sig, struct tty_struct *tty, int flush) | |||
1315 | if (tty->pgrp) | 1315 | if (tty->pgrp) |
1316 | kill_pgrp(tty->pgrp, sig, 1); | 1316 | kill_pgrp(tty->pgrp, sig, 1); |
1317 | if (flush || !L_NOFLSH(tty)) { | 1317 | if (flush || !L_NOFLSH(tty)) { |
1318 | if ( tty->ldisc.ops->flush_buffer ) | 1318 | if ( tty->ldisc->ops->flush_buffer ) |
1319 | tty->ldisc.ops->flush_buffer(tty); | 1319 | tty->ldisc->ops->flush_buffer(tty); |
1320 | i2InputFlush( tty->driver_data ); | 1320 | i2InputFlush( tty->driver_data ); |
1321 | } | 1321 | } |
1322 | } | 1322 | } |
diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c index bacb3e2872ae..461ece591a5b 100644 --- a/drivers/char/n_hdlc.c +++ b/drivers/char/n_hdlc.c | |||
@@ -342,8 +342,8 @@ static int n_hdlc_tty_open (struct tty_struct *tty) | |||
342 | #endif | 342 | #endif |
343 | 343 | ||
344 | /* Flush any pending characters in the driver and discipline. */ | 344 | /* Flush any pending characters in the driver and discipline. */ |
345 | if (tty->ldisc.ops->flush_buffer) | 345 | if (tty->ldisc->ops->flush_buffer) |
346 | tty->ldisc.ops->flush_buffer(tty); | 346 | tty->ldisc->ops->flush_buffer(tty); |
347 | 347 | ||
348 | tty_driver_flush_buffer(tty); | 348 | tty_driver_flush_buffer(tty); |
349 | 349 | ||
diff --git a/drivers/char/pty.c b/drivers/char/pty.c index da2cb8c70c11..5acd29e6e043 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c | |||
@@ -110,7 +110,7 @@ static int pty_write(struct tty_struct *tty, const unsigned char *buf, | |||
110 | c = to->receive_room; | 110 | c = to->receive_room; |
111 | if (c > count) | 111 | if (c > count) |
112 | c = count; | 112 | c = count; |
113 | to->ldisc.ops->receive_buf(to, buf, NULL, c); | 113 | to->ldisc->ops->receive_buf(to, buf, NULL, c); |
114 | 114 | ||
115 | return c; | 115 | return c; |
116 | } | 116 | } |
@@ -148,11 +148,11 @@ static int pty_chars_in_buffer(struct tty_struct *tty) | |||
148 | int count; | 148 | int count; |
149 | 149 | ||
150 | /* We should get the line discipline lock for "tty->link" */ | 150 | /* We should get the line discipline lock for "tty->link" */ |
151 | if (!to || !to->ldisc.ops->chars_in_buffer) | 151 | if (!to || !to->ldisc->ops->chars_in_buffer) |
152 | return 0; | 152 | return 0; |
153 | 153 | ||
154 | /* The ldisc must report 0 if no characters available to be read */ | 154 | /* The ldisc must report 0 if no characters available to be read */ |
155 | count = to->ldisc.ops->chars_in_buffer(to); | 155 | count = to->ldisc->ops->chars_in_buffer(to); |
156 | 156 | ||
157 | if (tty->driver->subtype == PTY_TYPE_SLAVE) | 157 | if (tty->driver->subtype == PTY_TYPE_SLAVE) |
158 | return count; | 158 | return count; |
@@ -186,8 +186,8 @@ static void pty_flush_buffer(struct tty_struct *tty) | |||
186 | if (!to) | 186 | if (!to) |
187 | return; | 187 | return; |
188 | 188 | ||
189 | if (to->ldisc.ops->flush_buffer) | 189 | if (to->ldisc->ops->flush_buffer) |
190 | to->ldisc.ops->flush_buffer(to); | 190 | to->ldisc->ops->flush_buffer(to); |
191 | 191 | ||
192 | if (to->packet) { | 192 | if (to->packet) { |
193 | spin_lock_irqsave(&tty->ctrl_lock, flags); | 193 | spin_lock_irqsave(&tty->ctrl_lock, flags); |
diff --git a/drivers/char/selection.c b/drivers/char/selection.c index cb8ca5698963..f97b9e848064 100644 --- a/drivers/char/selection.c +++ b/drivers/char/selection.c | |||
@@ -327,7 +327,7 @@ int paste_selection(struct tty_struct *tty) | |||
327 | } | 327 | } |
328 | count = sel_buffer_lth - pasted; | 328 | count = sel_buffer_lth - pasted; |
329 | count = min(count, tty->receive_room); | 329 | count = min(count, tty->receive_room); |
330 | tty->ldisc.ops->receive_buf(tty, sel_buffer + pasted, | 330 | tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted, |
331 | NULL, count); | 331 | NULL, count); |
332 | pasted += count; | 332 | pasted += count; |
333 | } | 333 | } |
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index be49d0730bb9..2f44b0b241c3 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c | |||
@@ -492,22 +492,6 @@ void tty_ldisc_flush(struct tty_struct *tty) | |||
492 | EXPORT_SYMBOL_GPL(tty_ldisc_flush); | 492 | EXPORT_SYMBOL_GPL(tty_ldisc_flush); |
493 | 493 | ||
494 | /** | 494 | /** |
495 | * tty_reset_termios - reset terminal state | ||
496 | * @tty: tty to reset | ||
497 | * | ||
498 | * Restore a terminal to the driver default state | ||
499 | */ | ||
500 | |||
501 | static void tty_reset_termios(struct tty_struct *tty) | ||
502 | { | ||
503 | mutex_lock(&tty->termios_mutex); | ||
504 | *tty->termios = tty->driver->init_termios; | ||
505 | tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios); | ||
506 | tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios); | ||
507 | mutex_unlock(&tty->termios_mutex); | ||
508 | } | ||
509 | |||
510 | /** | ||
511 | * do_tty_hangup - actual handler for hangup events | 495 | * do_tty_hangup - actual handler for hangup events |
512 | * @work: tty device | 496 | * @work: tty device |
513 | * | 497 | * |
@@ -536,7 +520,6 @@ static void do_tty_hangup(struct work_struct *work) | |||
536 | struct file *cons_filp = NULL; | 520 | struct file *cons_filp = NULL; |
537 | struct file *filp, *f = NULL; | 521 | struct file *filp, *f = NULL; |
538 | struct task_struct *p; | 522 | struct task_struct *p; |
539 | struct tty_ldisc *ld; | ||
540 | int closecount = 0, n; | 523 | int closecount = 0, n; |
541 | unsigned long flags; | 524 | unsigned long flags; |
542 | int refs = 0; | 525 | int refs = 0; |
@@ -567,40 +550,8 @@ static void do_tty_hangup(struct work_struct *work) | |||
567 | filp->f_op = &hung_up_tty_fops; | 550 | filp->f_op = &hung_up_tty_fops; |
568 | } | 551 | } |
569 | file_list_unlock(); | 552 | file_list_unlock(); |
570 | /* | ||
571 | * FIXME! What are the locking issues here? This may me overdoing | ||
572 | * things... This question is especially important now that we've | ||
573 | * removed the irqlock. | ||
574 | */ | ||
575 | ld = tty_ldisc_ref(tty); | ||
576 | if (ld != NULL) { | ||
577 | /* We may have no line discipline at this point */ | ||
578 | if (ld->ops->flush_buffer) | ||
579 | ld->ops->flush_buffer(tty); | ||
580 | tty_driver_flush_buffer(tty); | ||
581 | if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && | ||
582 | ld->ops->write_wakeup) | ||
583 | ld->ops->write_wakeup(tty); | ||
584 | if (ld->ops->hangup) | ||
585 | ld->ops->hangup(tty); | ||
586 | } | ||
587 | /* | ||
588 | * FIXME: Once we trust the LDISC code better we can wait here for | ||
589 | * ldisc completion and fix the driver call race | ||
590 | */ | ||
591 | wake_up_interruptible_poll(&tty->write_wait, POLLOUT); | ||
592 | wake_up_interruptible_poll(&tty->read_wait, POLLIN); | ||
593 | /* | ||
594 | * Shutdown the current line discipline, and reset it to | ||
595 | * N_TTY. | ||
596 | */ | ||
597 | if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) | ||
598 | tty_reset_termios(tty); | ||
599 | /* Defer ldisc switch */ | ||
600 | /* tty_deferred_ldisc_switch(N_TTY); | ||
601 | 553 | ||
602 | This should get done automatically when the port closes and | 554 | tty_ldisc_hangup(tty); |
603 | tty_release is called */ | ||
604 | 555 | ||
605 | read_lock(&tasklist_lock); | 556 | read_lock(&tasklist_lock); |
606 | if (tty->session) { | 557 | if (tty->session) { |
@@ -629,12 +580,15 @@ static void do_tty_hangup(struct work_struct *work) | |||
629 | read_unlock(&tasklist_lock); | 580 | read_unlock(&tasklist_lock); |
630 | 581 | ||
631 | spin_lock_irqsave(&tty->ctrl_lock, flags); | 582 | spin_lock_irqsave(&tty->ctrl_lock, flags); |
632 | tty->flags = 0; | 583 | clear_bit(TTY_THROTTLED, &tty->flags); |
584 | clear_bit(TTY_PUSH, &tty->flags); | ||
585 | clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); | ||
633 | put_pid(tty->session); | 586 | put_pid(tty->session); |
634 | put_pid(tty->pgrp); | 587 | put_pid(tty->pgrp); |
635 | tty->session = NULL; | 588 | tty->session = NULL; |
636 | tty->pgrp = NULL; | 589 | tty->pgrp = NULL; |
637 | tty->ctrl_status = 0; | 590 | tty->ctrl_status = 0; |
591 | set_bit(TTY_HUPPED, &tty->flags); | ||
638 | spin_unlock_irqrestore(&tty->ctrl_lock, flags); | 592 | spin_unlock_irqrestore(&tty->ctrl_lock, flags); |
639 | 593 | ||
640 | /* Account for the p->signal references we killed */ | 594 | /* Account for the p->signal references we killed */ |
@@ -660,10 +614,7 @@ static void do_tty_hangup(struct work_struct *work) | |||
660 | * can't yet guarantee all that. | 614 | * can't yet guarantee all that. |
661 | */ | 615 | */ |
662 | set_bit(TTY_HUPPED, &tty->flags); | 616 | set_bit(TTY_HUPPED, &tty->flags); |
663 | if (ld) { | 617 | tty_ldisc_enable(tty); |
664 | tty_ldisc_enable(tty); | ||
665 | tty_ldisc_deref(ld); | ||
666 | } | ||
667 | unlock_kernel(); | 618 | unlock_kernel(); |
668 | if (f) | 619 | if (f) |
669 | fput(f); | 620 | fput(f); |
@@ -2570,7 +2521,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
2570 | case TIOCGSID: | 2521 | case TIOCGSID: |
2571 | return tiocgsid(tty, real_tty, p); | 2522 | return tiocgsid(tty, real_tty, p); |
2572 | case TIOCGETD: | 2523 | case TIOCGETD: |
2573 | return put_user(tty->ldisc.ops->num, (int __user *)p); | 2524 | return put_user(tty->ldisc->ops->num, (int __user *)p); |
2574 | case TIOCSETD: | 2525 | case TIOCSETD: |
2575 | return tiocsetd(tty, p); | 2526 | return tiocsetd(tty, p); |
2576 | /* | 2527 | /* |
@@ -2785,6 +2736,7 @@ void initialize_tty_struct(struct tty_struct *tty, | |||
2785 | tty->buf.head = tty->buf.tail = NULL; | 2736 | tty->buf.head = tty->buf.tail = NULL; |
2786 | tty_buffer_init(tty); | 2737 | tty_buffer_init(tty); |
2787 | mutex_init(&tty->termios_mutex); | 2738 | mutex_init(&tty->termios_mutex); |
2739 | mutex_init(&tty->ldisc_mutex); | ||
2788 | init_waitqueue_head(&tty->write_wait); | 2740 | init_waitqueue_head(&tty->write_wait); |
2789 | init_waitqueue_head(&tty->read_wait); | 2741 | init_waitqueue_head(&tty->read_wait); |
2790 | INIT_WORK(&tty->hangup_work, do_tty_hangup); | 2742 | INIT_WORK(&tty->hangup_work, do_tty_hangup); |
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c index e3c6416aa86d..a58a19a6a5e1 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,44 +166,46 @@ 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) |
@@ -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,8 +322,8 @@ 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 | 328 | ||
322 | EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); | 329 | EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); |
@@ -335,7 +342,7 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); | |||
335 | struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty) | 342 | struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty) |
336 | { | 343 | { |
337 | if (tty_ldisc_try(tty)) | 344 | if (tty_ldisc_try(tty)) |
338 | return &tty->ldisc; | 345 | return tty->ldisc; |
339 | return NULL; | 346 | return NULL; |
340 | } | 347 | } |
341 | 348 | ||
@@ -407,6 +414,39 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num) | |||
407 | mutex_unlock(&tty->termios_mutex); | 414 | mutex_unlock(&tty->termios_mutex); |
408 | } | 415 | } |
409 | 416 | ||
417 | /** | ||
418 | * tty_ldisc_open - open a line discipline | ||
419 | * @tty: tty we are opening the ldisc on | ||
420 | * @ld: discipline to open | ||
421 | * | ||
422 | * A helper opening method. Also a convenient debugging and check | ||
423 | * point. | ||
424 | */ | ||
425 | |||
426 | static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld) | ||
427 | { | ||
428 | WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags)); | ||
429 | if (ld->ops->open) | ||
430 | return ld->ops->open(tty); | ||
431 | return 0; | ||
432 | } | ||
433 | |||
434 | /** | ||
435 | * tty_ldisc_close - close a line discipline | ||
436 | * @tty: tty we are opening the ldisc on | ||
437 | * @ld: discipline to close | ||
438 | * | ||
439 | * A helper close method. Also a convenient debugging and check | ||
440 | * point. | ||
441 | */ | ||
442 | |||
443 | static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld) | ||
444 | { | ||
445 | WARN_ON(!test_bit(TTY_LDISC_OPEN, &tty->flags)); | ||
446 | clear_bit(TTY_LDISC_OPEN, &tty->flags); | ||
447 | if (ld->ops->close) | ||
448 | ld->ops->close(tty); | ||
449 | } | ||
410 | 450 | ||
411 | /** | 451 | /** |
412 | * tty_ldisc_restore - helper for tty ldisc change | 452 | * tty_ldisc_restore - helper for tty ldisc change |
@@ -420,31 +460,32 @@ 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) | 460 | static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) |
421 | { | 461 | { |
422 | char buf[64]; | 462 | char buf[64]; |
423 | struct tty_ldisc new_ldisc; | 463 | struct tty_ldisc *new_ldisc; |
464 | int r; | ||
424 | 465 | ||
425 | /* There is an outstanding reference here so this is safe */ | 466 | /* There is an outstanding reference here so this is safe */ |
426 | tty_ldisc_get(old->ops->num, old); | 467 | old = tty_ldisc_get(old->ops->num); |
468 | WARN_ON(IS_ERR(old)); | ||
427 | tty_ldisc_assign(tty, old); | 469 | tty_ldisc_assign(tty, old); |
428 | tty_set_termios_ldisc(tty, old->ops->num); | 470 | tty_set_termios_ldisc(tty, old->ops->num); |
429 | if (old->ops->open && (old->ops->open(tty) < 0)) { | 471 | if (tty_ldisc_open(tty, old) < 0) { |
430 | tty_ldisc_put(old->ops); | 472 | tty_ldisc_put(old); |
431 | /* This driver is always present */ | 473 | /* This driver is always present */ |
432 | if (tty_ldisc_get(N_TTY, &new_ldisc) < 0) | 474 | new_ldisc =tty_ldisc_get(N_TTY); |
475 | if (IS_ERR(new_ldisc)) | ||
433 | panic("n_tty: get"); | 476 | panic("n_tty: get"); |
434 | tty_ldisc_assign(tty, &new_ldisc); | 477 | tty_ldisc_assign(tty, new_ldisc); |
435 | tty_set_termios_ldisc(tty, N_TTY); | 478 | tty_set_termios_ldisc(tty, N_TTY); |
436 | if (new_ldisc.ops->open) { | 479 | r = tty_ldisc_open(tty, new_ldisc); |
437 | int r = new_ldisc.ops->open(tty); | 480 | if (r < 0) |
438 | if (r < 0) | 481 | panic("Couldn't open N_TTY ldisc for " |
439 | panic("Couldn't open N_TTY ldisc for " | 482 | "%s --- error %d.", |
440 | "%s --- error %d.", | 483 | tty_name(tty, buf), r); |
441 | tty_name(tty, buf), r); | ||
442 | } | ||
443 | } | 484 | } |
444 | } | 485 | } |
445 | 486 | ||
446 | /** | 487 | /** |
447 | * tty_ldisc_halt - shutdown the line discipline | 488 | * tty_ldisc_halt - shut down the line discipline |
448 | * @tty: tty device | 489 | * @tty: tty device |
449 | * | 490 | * |
450 | * Shut down the line discipline and work queue for this tty device. | 491 | * Shut down the line discipline and work queue for this tty device. |
@@ -456,14 +497,10 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) | |||
456 | * tty_ldisc_wait_idle. | 497 | * tty_ldisc_wait_idle. |
457 | */ | 498 | */ |
458 | 499 | ||
459 | static void tty_ldisc_halt(struct tty_struct *tty) | 500 | static int tty_ldisc_halt(struct tty_struct *tty) |
460 | { | 501 | { |
461 | clear_bit(TTY_LDISC, &tty->flags); | 502 | clear_bit(TTY_LDISC, &tty->flags); |
462 | cancel_delayed_work(&tty->buf.work); | 503 | return cancel_delayed_work(&tty->buf.work); |
463 | /* | ||
464 | * Wait for ->hangup_work and ->buf.work handlers to terminate | ||
465 | */ | ||
466 | flush_scheduled_work(); | ||
467 | } | 504 | } |
468 | 505 | ||
469 | /** | 506 | /** |
@@ -473,18 +510,22 @@ static void tty_ldisc_halt(struct tty_struct *tty) | |||
473 | * Wait for the line discipline to become idle. The discipline must | 510 | * Wait for the line discipline to become idle. The discipline must |
474 | * have been halted for this to guarantee it remains idle. | 511 | * have been halted for this to guarantee it remains idle. |
475 | * | 512 | * |
513 | * tty_ldisc_lock protects the ref counts currently. | ||
476 | */ | 514 | */ |
477 | 515 | ||
478 | static void tty_ldisc_wait_idle(struct tty_struct *tty) | 516 | static int tty_ldisc_wait_idle(struct tty_struct *tty) |
479 | { | 517 | { |
480 | unsigned long flags; | 518 | unsigned long flags; |
481 | spin_lock_irqsave(&tty_ldisc_lock, flags); | 519 | spin_lock_irqsave(&tty_ldisc_lock, flags); |
482 | while (tty->ldisc.refcount) { | 520 | while (tty->ldisc->refcount) { |
483 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); | 521 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); |
484 | wait_event(tty_ldisc_wait, tty->ldisc.refcount == 0); | 522 | if (wait_event_timeout(tty_ldisc_wait, |
523 | tty->ldisc->refcount == 0, 5 * HZ) == 0) | ||
524 | return -EBUSY; | ||
485 | spin_lock_irqsave(&tty_ldisc_lock, flags); | 525 | spin_lock_irqsave(&tty_ldisc_lock, flags); |
486 | } | 526 | } |
487 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); | 527 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); |
528 | return 0; | ||
488 | } | 529 | } |
489 | 530 | ||
490 | /** | 531 | /** |
@@ -493,39 +534,64 @@ static void tty_ldisc_wait_idle(struct tty_struct *tty) | |||
493 | * @ldisc: the line discipline | 534 | * @ldisc: the line discipline |
494 | * | 535 | * |
495 | * Set the discipline of a tty line. Must be called from a process | 536 | * Set the discipline of a tty line. Must be called from a process |
496 | * context. | 537 | * context. The ldisc change logic has to protect itself against any |
538 | * overlapping ldisc change (including on the other end of pty pairs), | ||
539 | * the close of one side of a tty/pty pair, and eventually hangup. | ||
497 | * | 540 | * |
498 | * Locking: takes tty_ldisc_lock. | 541 | * Locking: takes tty_ldisc_lock, termios_mutex |
499 | * called functions take termios_mutex | ||
500 | */ | 542 | */ |
501 | 543 | ||
502 | int tty_set_ldisc(struct tty_struct *tty, int ldisc) | 544 | int tty_set_ldisc(struct tty_struct *tty, int ldisc) |
503 | { | 545 | { |
504 | int retval; | 546 | int retval; |
505 | struct tty_ldisc o_ldisc, new_ldisc; | 547 | struct tty_ldisc *o_ldisc, *new_ldisc; |
506 | int work; | 548 | int work, o_work = 0; |
507 | unsigned long flags; | ||
508 | struct tty_struct *o_tty; | 549 | struct tty_struct *o_tty; |
509 | 550 | ||
510 | restart: | 551 | new_ldisc = tty_ldisc_get(ldisc); |
511 | /* This is a bit ugly for now but means we can break the 'ldisc | 552 | if (IS_ERR(new_ldisc)) |
512 | is part of the tty struct' assumption later */ | 553 | return PTR_ERR(new_ldisc); |
513 | retval = tty_ldisc_get(ldisc, &new_ldisc); | ||
514 | if (retval) | ||
515 | return retval; | ||
516 | 554 | ||
517 | /* | 555 | /* |
518 | * Problem: What do we do if this blocks ? | 556 | * We need to look at the tty locking here for pty/tty pairs |
557 | * when both sides try to change in parallel. | ||
519 | */ | 558 | */ |
520 | 559 | ||
521 | tty_wait_until_sent(tty, 0); | 560 | o_tty = tty->link; /* o_tty is the pty side or NULL */ |
561 | |||
522 | 562 | ||
523 | if (tty->ldisc.ops->num == ldisc) { | 563 | /* |
524 | tty_ldisc_put(new_ldisc.ops); | 564 | * Check the no-op case |
565 | */ | ||
566 | |||
567 | if (tty->ldisc->ops->num == ldisc) { | ||
568 | tty_ldisc_put(new_ldisc); | ||
525 | return 0; | 569 | return 0; |
526 | } | 570 | } |
527 | 571 | ||
528 | /* | 572 | /* |
573 | * Problem: What do we do if this blocks ? | ||
574 | * We could deadlock here | ||
575 | */ | ||
576 | |||
577 | tty_wait_until_sent(tty, 0); | ||
578 | |||
579 | mutex_lock(&tty->ldisc_mutex); | ||
580 | |||
581 | /* | ||
582 | * We could be midstream of another ldisc change which has | ||
583 | * dropped the lock during processing. If so we need to wait. | ||
584 | */ | ||
585 | |||
586 | while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) { | ||
587 | mutex_unlock(&tty->ldisc_mutex); | ||
588 | wait_event(tty_ldisc_wait, | ||
589 | test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0); | ||
590 | mutex_lock(&tty->ldisc_mutex); | ||
591 | } | ||
592 | set_bit(TTY_LDISC_CHANGING, &tty->flags); | ||
593 | |||
594 | /* | ||
529 | * No more input please, we are switching. The new ldisc | 595 | * No more input please, we are switching. The new ldisc |
530 | * will update this value in the ldisc open function | 596 | * will update this value in the ldisc open function |
531 | */ | 597 | */ |
@@ -533,8 +599,6 @@ restart: | |||
533 | tty->receive_room = 0; | 599 | tty->receive_room = 0; |
534 | 600 | ||
535 | o_ldisc = tty->ldisc; | 601 | o_ldisc = tty->ldisc; |
536 | o_tty = tty->link; | ||
537 | |||
538 | /* | 602 | /* |
539 | * Make sure we don't change while someone holds a | 603 | * Make sure we don't change while someone holds a |
540 | * reference to the line discipline. The TTY_LDISC bit | 604 | * reference to the line discipline. The TTY_LDISC bit |
@@ -545,108 +609,181 @@ restart: | |||
545 | * with a userspace app continually trying to use the tty in | 609 | * with a userspace app continually trying to use the tty in |
546 | * parallel to the change and re-referencing the tty. | 610 | * parallel to the change and re-referencing the tty. |
547 | */ | 611 | */ |
548 | clear_bit(TTY_LDISC, &tty->flags); | ||
549 | if (o_tty) | ||
550 | clear_bit(TTY_LDISC, &o_tty->flags); | ||
551 | 612 | ||
552 | spin_lock_irqsave(&tty_ldisc_lock, flags); | 613 | work = tty_ldisc_halt(tty); |
553 | if (tty->ldisc.refcount || (o_tty && o_tty->ldisc.refcount)) { | ||
554 | if (tty->ldisc.refcount) { | ||
555 | /* Free the new ldisc we grabbed. Must drop the lock | ||
556 | first. */ | ||
557 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); | ||
558 | tty_ldisc_put(o_ldisc.ops); | ||
559 | /* | ||
560 | * There are several reasons we may be busy, including | ||
561 | * random momentary I/O traffic. We must therefore | ||
562 | * retry. We could distinguish between blocking ops | ||
563 | * and retries if we made tty_ldisc_wait() smarter. | ||
564 | * That is up for discussion. | ||
565 | */ | ||
566 | if (wait_event_interruptible(tty_ldisc_wait, tty->ldisc.refcount == 0) < 0) | ||
567 | return -ERESTARTSYS; | ||
568 | goto restart; | ||
569 | } | ||
570 | if (o_tty && o_tty->ldisc.refcount) { | ||
571 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); | ||
572 | tty_ldisc_put(o_tty->ldisc.ops); | ||
573 | if (wait_event_interruptible(tty_ldisc_wait, o_tty->ldisc.refcount == 0) < 0) | ||
574 | return -ERESTARTSYS; | ||
575 | goto restart; | ||
576 | } | ||
577 | } | ||
578 | /* | ||
579 | * If the TTY_LDISC bit is set, then we are racing against | ||
580 | * another ldisc change | ||
581 | */ | ||
582 | if (test_bit(TTY_LDISC_CHANGING, &tty->flags)) { | ||
583 | struct tty_ldisc *ld; | ||
584 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); | ||
585 | tty_ldisc_put(new_ldisc.ops); | ||
586 | ld = tty_ldisc_ref_wait(tty); | ||
587 | tty_ldisc_deref(ld); | ||
588 | goto restart; | ||
589 | } | ||
590 | /* | ||
591 | * This flag is used to avoid two parallel ldisc changes. Once | ||
592 | * open and close are fine grained locked this may work better | ||
593 | * as a mutex shared with the open/close/hup paths | ||
594 | */ | ||
595 | set_bit(TTY_LDISC_CHANGING, &tty->flags); | ||
596 | if (o_tty) | 614 | if (o_tty) |
597 | set_bit(TTY_LDISC_CHANGING, &o_tty->flags); | 615 | o_work = tty_ldisc_halt(o_tty); |
598 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); | ||
599 | |||
600 | /* | ||
601 | * From this point on we know nobody has an ldisc | ||
602 | * usage reference, nor can they obtain one until | ||
603 | * we say so later on. | ||
604 | */ | ||
605 | 616 | ||
606 | work = cancel_delayed_work(&tty->buf.work); | ||
607 | /* | 617 | /* |
608 | * Wait for ->hangup_work and ->buf.work handlers to terminate | 618 | * Wait for ->hangup_work and ->buf.work handlers to terminate. |
609 | * MUST NOT hold locks here. | 619 | * We must drop the mutex here in case a hangup is also in process. |
610 | */ | 620 | */ |
621 | |||
622 | mutex_unlock(&tty->ldisc_mutex); | ||
623 | |||
611 | flush_scheduled_work(); | 624 | flush_scheduled_work(); |
625 | |||
626 | /* Let any existing reference holders finish */ | ||
627 | retval = tty_ldisc_wait_idle(tty); | ||
628 | if (retval < 0) { | ||
629 | clear_bit(TTY_LDISC_CHANGING, &tty->flags); | ||
630 | tty_ldisc_put(new_ldisc); | ||
631 | return retval; | ||
632 | } | ||
633 | |||
634 | mutex_lock(&tty->ldisc_mutex); | ||
635 | if (test_bit(TTY_HUPPED, &tty->flags)) { | ||
636 | /* We were raced by the hangup method. It will have stomped | ||
637 | the ldisc data and closed the ldisc down */ | ||
638 | clear_bit(TTY_LDISC_CHANGING, &tty->flags); | ||
639 | mutex_unlock(&tty->ldisc_mutex); | ||
640 | tty_ldisc_put(new_ldisc); | ||
641 | return -EIO; | ||
642 | } | ||
643 | |||
612 | /* Shutdown the current discipline. */ | 644 | /* Shutdown the current discipline. */ |
613 | if (o_ldisc.ops->close) | 645 | tty_ldisc_close(tty, o_ldisc); |
614 | (o_ldisc.ops->close)(tty); | ||
615 | 646 | ||
616 | /* Now set up the new line discipline. */ | 647 | /* Now set up the new line discipline. */ |
617 | tty_ldisc_assign(tty, &new_ldisc); | 648 | tty_ldisc_assign(tty, new_ldisc); |
618 | tty_set_termios_ldisc(tty, ldisc); | 649 | tty_set_termios_ldisc(tty, ldisc); |
619 | if (new_ldisc.ops->open) | 650 | |
620 | retval = (new_ldisc.ops->open)(tty); | 651 | retval = tty_ldisc_open(tty, new_ldisc); |
621 | if (retval < 0) { | 652 | if (retval < 0) { |
622 | tty_ldisc_put(new_ldisc.ops); | 653 | /* Back to the old one or N_TTY if we can't */ |
623 | tty_ldisc_restore(tty, &o_ldisc); | 654 | tty_ldisc_put(new_ldisc); |
655 | tty_ldisc_restore(tty, o_ldisc); | ||
624 | } | 656 | } |
657 | |||
625 | /* At this point we hold a reference to the new ldisc and a | 658 | /* At this point we hold a reference to the new ldisc and a |
626 | a reference to the old ldisc. If we ended up flipping back | 659 | a reference to the old ldisc. If we ended up flipping back |
627 | to the existing ldisc we have two references to it */ | 660 | to the existing ldisc we have two references to it */ |
628 | 661 | ||
629 | if (tty->ldisc.ops->num != o_ldisc.ops->num && tty->ops->set_ldisc) | 662 | if (tty->ldisc->ops->num != o_ldisc->ops->num && tty->ops->set_ldisc) |
630 | tty->ops->set_ldisc(tty); | 663 | tty->ops->set_ldisc(tty); |
631 | 664 | ||
632 | tty_ldisc_put(o_ldisc.ops); | 665 | tty_ldisc_put(o_ldisc); |
633 | 666 | ||
634 | /* | 667 | /* |
635 | * Allow ldisc referencing to occur as soon as the driver | 668 | * Allow ldisc referencing to occur again |
636 | * ldisc callback completes. | ||
637 | */ | 669 | */ |
638 | 670 | ||
639 | tty_ldisc_enable(tty); | 671 | tty_ldisc_enable(tty); |
640 | if (o_tty) | 672 | if (o_tty) |
641 | tty_ldisc_enable(o_tty); | 673 | tty_ldisc_enable(o_tty); |
642 | 674 | ||
643 | /* Restart it in case no characters kick it off. Safe if | 675 | /* Restart the work queue in case no characters kick it off. Safe if |
644 | already running */ | 676 | already running */ |
645 | if (work) | 677 | if (work) |
646 | schedule_delayed_work(&tty->buf.work, 1); | 678 | schedule_delayed_work(&tty->buf.work, 1); |
679 | if (o_work) | ||
680 | schedule_delayed_work(&o_tty->buf.work, 1); | ||
681 | mutex_unlock(&tty->ldisc_mutex); | ||
647 | return retval; | 682 | return retval; |
648 | } | 683 | } |
649 | 684 | ||
685 | /** | ||
686 | * tty_reset_termios - reset terminal state | ||
687 | * @tty: tty to reset | ||
688 | * | ||
689 | * Restore a terminal to the driver default state. | ||
690 | */ | ||
691 | |||
692 | static void tty_reset_termios(struct tty_struct *tty) | ||
693 | { | ||
694 | mutex_lock(&tty->termios_mutex); | ||
695 | *tty->termios = tty->driver->init_termios; | ||
696 | tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios); | ||
697 | tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios); | ||
698 | mutex_unlock(&tty->termios_mutex); | ||
699 | } | ||
700 | |||
701 | |||
702 | /** | ||
703 | * tty_ldisc_reinit - reinitialise the tty ldisc | ||
704 | * @tty: tty to reinit | ||
705 | * | ||
706 | * Switch the tty back to N_TTY line discipline and leave the | ||
707 | * ldisc state closed | ||
708 | */ | ||
709 | |||
710 | static void tty_ldisc_reinit(struct tty_struct *tty) | ||
711 | { | ||
712 | struct tty_ldisc *ld; | ||
713 | |||
714 | tty_ldisc_close(tty, tty->ldisc); | ||
715 | tty_ldisc_put(tty->ldisc); | ||
716 | tty->ldisc = NULL; | ||
717 | /* | ||
718 | * Switch the line discipline back | ||
719 | */ | ||
720 | ld = tty_ldisc_get(N_TTY); | ||
721 | BUG_ON(IS_ERR(ld)); | ||
722 | tty_ldisc_assign(tty, ld); | ||
723 | tty_set_termios_ldisc(tty, N_TTY); | ||
724 | } | ||
725 | |||
726 | /** | ||
727 | * tty_ldisc_hangup - hangup ldisc reset | ||
728 | * @tty: tty being hung up | ||
729 | * | ||
730 | * Some tty devices reset their termios when they receive a hangup | ||
731 | * event. In that situation we must also switch back to N_TTY properly | ||
732 | * before we reset the termios data. | ||
733 | * | ||
734 | * Locking: We can take the ldisc mutex as the rest of the code is | ||
735 | * careful to allow for this. | ||
736 | * | ||
737 | * In the pty pair case this occurs in the close() path of the | ||
738 | * tty itself so we must be careful about locking rules. | ||
739 | */ | ||
740 | |||
741 | void tty_ldisc_hangup(struct tty_struct *tty) | ||
742 | { | ||
743 | struct tty_ldisc *ld; | ||
744 | |||
745 | /* | ||
746 | * FIXME! What are the locking issues here? This may me overdoing | ||
747 | * things... This question is especially important now that we've | ||
748 | * removed the irqlock. | ||
749 | */ | ||
750 | ld = tty_ldisc_ref(tty); | ||
751 | if (ld != NULL) { | ||
752 | /* We may have no line discipline at this point */ | ||
753 | if (ld->ops->flush_buffer) | ||
754 | ld->ops->flush_buffer(tty); | ||
755 | tty_driver_flush_buffer(tty); | ||
756 | if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && | ||
757 | ld->ops->write_wakeup) | ||
758 | ld->ops->write_wakeup(tty); | ||
759 | if (ld->ops->hangup) | ||
760 | ld->ops->hangup(tty); | ||
761 | tty_ldisc_deref(ld); | ||
762 | } | ||
763 | /* | ||
764 | * FIXME: Once we trust the LDISC code better we can wait here for | ||
765 | * ldisc completion and fix the driver call race | ||
766 | */ | ||
767 | wake_up_interruptible_poll(&tty->write_wait, POLLOUT); | ||
768 | wake_up_interruptible_poll(&tty->read_wait, POLLIN); | ||
769 | /* | ||
770 | * Shutdown the current line discipline, and reset it to | ||
771 | * N_TTY. | ||
772 | */ | ||
773 | if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { | ||
774 | /* Avoid racing set_ldisc */ | ||
775 | mutex_lock(&tty->ldisc_mutex); | ||
776 | /* Switch back to N_TTY */ | ||
777 | tty_ldisc_reinit(tty); | ||
778 | /* At this point we have a closed ldisc and we want to | ||
779 | reopen it. We could defer this to the next open but | ||
780 | it means auditing a lot of other paths so this is a FIXME */ | ||
781 | WARN_ON(tty_ldisc_open(tty, tty->ldisc)); | ||
782 | tty_ldisc_enable(tty); | ||
783 | mutex_unlock(&tty->ldisc_mutex); | ||
784 | tty_reset_termios(tty); | ||
785 | } | ||
786 | } | ||
650 | 787 | ||
651 | /** | 788 | /** |
652 | * tty_ldisc_setup - open line discipline | 789 | * tty_ldisc_setup - open line discipline |
@@ -654,24 +791,23 @@ restart: | |||
654 | * @o_tty: pair tty for pty/tty pairs | 791 | * @o_tty: pair tty for pty/tty pairs |
655 | * | 792 | * |
656 | * Called during the initial open of a tty/pty pair in order to set up the | 793 | * Called during the initial open of a tty/pty pair in order to set up the |
657 | * line discplines and bind them to the tty. | 794 | * line disciplines and bind them to the tty. This has no locking issues |
795 | * as the device isn't yet active. | ||
658 | */ | 796 | */ |
659 | 797 | ||
660 | int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty) | 798 | int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty) |
661 | { | 799 | { |
662 | struct tty_ldisc *ld = &tty->ldisc; | 800 | struct tty_ldisc *ld = tty->ldisc; |
663 | int retval; | 801 | int retval; |
664 | 802 | ||
665 | if (ld->ops->open) { | 803 | retval = tty_ldisc_open(tty, ld); |
666 | retval = (ld->ops->open)(tty); | 804 | if (retval) |
667 | if (retval) | 805 | return retval; |
668 | return retval; | 806 | |
669 | } | 807 | if (o_tty) { |
670 | if (o_tty && o_tty->ldisc.ops->open) { | 808 | retval = tty_ldisc_open(o_tty, o_tty->ldisc); |
671 | retval = (o_tty->ldisc.ops->open)(o_tty); | ||
672 | if (retval) { | 809 | if (retval) { |
673 | if (ld->ops->close) | 810 | tty_ldisc_close(tty, ld); |
674 | (ld->ops->close)(tty); | ||
675 | return retval; | 811 | return retval; |
676 | } | 812 | } |
677 | tty_ldisc_enable(o_tty); | 813 | tty_ldisc_enable(o_tty); |
@@ -679,34 +815,18 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty) | |||
679 | tty_ldisc_enable(tty); | 815 | tty_ldisc_enable(tty); |
680 | return 0; | 816 | return 0; |
681 | } | 817 | } |
682 | |||
683 | static void tty_ldisc_reinit(struct tty_struct *tty) | ||
684 | { | ||
685 | struct tty_ldisc ld; | ||
686 | |||
687 | if (tty->ldisc.ops->close) | ||
688 | (tty->ldisc.ops->close)(tty); | ||
689 | tty_ldisc_put(tty->ldisc.ops); | ||
690 | /* | ||
691 | * Switch the line discipline back | ||
692 | */ | ||
693 | WARN_ON(tty_ldisc_get(N_TTY, &ld)); | ||
694 | tty_ldisc_assign(tty, &ld); | ||
695 | tty_set_termios_ldisc(tty, N_TTY); | ||
696 | } | ||
697 | |||
698 | /** | 818 | /** |
699 | * tty_ldisc_release - release line discipline | 819 | * tty_ldisc_release - release line discipline |
700 | * @tty: tty being shut down | 820 | * @tty: tty being shut down |
701 | * @o_tty: pair tty for pty/tty pairs | 821 | * @o_tty: pair tty for pty/tty pairs |
702 | * | 822 | * |
703 | * Called during the final close of a tty/pty pair in order to shut down the | 823 | * Called during the final close of a tty/pty pair in order to shut down the |
704 | * line discpline layer. | 824 | * line discpline layer. On exit the ldisc assigned is N_TTY and the |
825 | * ldisc has not been opened. | ||
705 | */ | 826 | */ |
706 | 827 | ||
707 | void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) | 828 | void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) |
708 | { | 829 | { |
709 | |||
710 | /* | 830 | /* |
711 | * Prevent flush_to_ldisc() from rescheduling the work for later. Then | 831 | * Prevent flush_to_ldisc() from rescheduling the work for later. Then |
712 | * kill any delayed work. As this is the final close it does not | 832 | * kill any delayed work. As this is the final close it does not |
@@ -714,6 +834,7 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) | |||
714 | */ | 834 | */ |
715 | 835 | ||
716 | tty_ldisc_halt(tty); | 836 | tty_ldisc_halt(tty); |
837 | flush_scheduled_work(); | ||
717 | 838 | ||
718 | /* | 839 | /* |
719 | * Wait for any short term users (we know they are just driver | 840 | * Wait for any short term users (we know they are just driver |
@@ -730,11 +851,9 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) | |||
730 | */ | 851 | */ |
731 | 852 | ||
732 | tty_ldisc_reinit(tty); | 853 | tty_ldisc_reinit(tty); |
733 | if (o_tty) { | 854 | /* This will need doing differently if we need to lock */ |
734 | /* FIXME: could o_tty be in setldisc here ? */ | 855 | if (o_tty) |
735 | clear_bit(TTY_LDISC, &o_tty->flags); | 856 | tty_ldisc_release(o_tty, NULL); |
736 | tty_ldisc_reinit(o_tty); | ||
737 | } | ||
738 | } | 857 | } |
739 | 858 | ||
740 | /** | 859 | /** |
@@ -747,10 +866,10 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) | |||
747 | 866 | ||
748 | void tty_ldisc_init(struct tty_struct *tty) | 867 | void tty_ldisc_init(struct tty_struct *tty) |
749 | { | 868 | { |
750 | struct tty_ldisc ld; | 869 | struct tty_ldisc *ld = tty_ldisc_get(N_TTY); |
751 | if (tty_ldisc_get(N_TTY, &ld) < 0) | 870 | if (IS_ERR(ld)) |
752 | panic("n_tty: init_tty"); | 871 | panic("n_tty: init_tty"); |
753 | tty_ldisc_assign(tty, &ld); | 872 | tty_ldisc_assign(tty, ld); |
754 | } | 873 | } |
755 | 874 | ||
756 | void tty_ldisc_begin(void) | 875 | void tty_ldisc_begin(void) |