Branch data Line data Source code
1 : : #include <linux/types.h>
2 : : #include <linux/errno.h>
3 : : #include <linux/kmod.h>
4 : : #include <linux/sched.h>
5 : : #include <linux/interrupt.h>
6 : : #include <linux/tty.h>
7 : : #include <linux/tty_driver.h>
8 : : #include <linux/file.h>
9 : : #include <linux/mm.h>
10 : : #include <linux/string.h>
11 : : #include <linux/slab.h>
12 : : #include <linux/poll.h>
13 : : #include <linux/proc_fs.h>
14 : : #include <linux/module.h>
15 : : #include <linux/device.h>
16 : : #include <linux/wait.h>
17 : : #include <linux/bitops.h>
18 : : #include <linux/seq_file.h>
19 : : #include <linux/uaccess.h>
20 : : #include <linux/ratelimit.h>
21 : :
22 : : #undef LDISC_DEBUG_HANGUP
23 : :
24 : : #ifdef LDISC_DEBUG_HANGUP
25 : : #define tty_ldisc_debug(tty, f, args...) ({ \
26 : : char __b[64]; \
27 : : printk(KERN_DEBUG "%s: %s: " f, __func__, tty_name(tty, __b), ##args); \
28 : : })
29 : : #else
30 : : #define tty_ldisc_debug(tty, f, args...)
31 : : #endif
32 : :
33 : : /* lockdep nested classes for tty->ldisc_sem */
34 : : enum {
35 : : LDISC_SEM_NORMAL,
36 : : LDISC_SEM_OTHER,
37 : : };
38 : :
39 : :
40 : : /*
41 : : * This guards the refcounted line discipline lists. The lock
42 : : * must be taken with irqs off because there are hangup path
43 : : * callers who will do ldisc lookups and cannot sleep.
44 : : */
45 : :
46 : : static DEFINE_RAW_SPINLOCK(tty_ldiscs_lock);
47 : : /* Line disc dispatch table */
48 : : static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
49 : :
50 : : /**
51 : : * tty_register_ldisc - install a line discipline
52 : : * @disc: ldisc number
53 : : * @new_ldisc: pointer to the ldisc object
54 : : *
55 : : * Installs a new line discipline into the kernel. The discipline
56 : : * is set up as unreferenced and then made available to the kernel
57 : : * from this point onwards.
58 : : *
59 : : * Locking:
60 : : * takes tty_ldiscs_lock to guard against ldisc races
61 : : */
62 : :
63 : 0 : int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc)
64 : : {
65 : : unsigned long flags;
66 : : int ret = 0;
67 : :
68 [ # # ]: 0 : if (disc < N_TTY || disc >= NR_LDISCS)
69 : : return -EINVAL;
70 : :
71 : 0 : raw_spin_lock_irqsave(&tty_ldiscs_lock, flags);
72 : 0 : tty_ldiscs[disc] = new_ldisc;
73 : 0 : new_ldisc->num = disc;
74 : 0 : new_ldisc->refcount = 0;
75 : 0 : raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags);
76 : :
77 : 0 : return ret;
78 : : }
79 : : EXPORT_SYMBOL(tty_register_ldisc);
80 : :
81 : : /**
82 : : * tty_unregister_ldisc - unload a line discipline
83 : : * @disc: ldisc number
84 : : * @new_ldisc: pointer to the ldisc object
85 : : *
86 : : * Remove a line discipline from the kernel providing it is not
87 : : * currently in use.
88 : : *
89 : : * Locking:
90 : : * takes tty_ldiscs_lock to guard against ldisc races
91 : : */
92 : :
93 : 0 : int tty_unregister_ldisc(int disc)
94 : : {
95 : : unsigned long flags;
96 : : int ret = 0;
97 : :
98 [ # # ]: 0 : if (disc < N_TTY || disc >= NR_LDISCS)
99 : : return -EINVAL;
100 : :
101 : 0 : raw_spin_lock_irqsave(&tty_ldiscs_lock, flags);
102 [ # # ]: 0 : if (tty_ldiscs[disc]->refcount)
103 : : ret = -EBUSY;
104 : : else
105 : 0 : tty_ldiscs[disc] = NULL;
106 : 0 : raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags);
107 : :
108 : 0 : return ret;
109 : : }
110 : : EXPORT_SYMBOL(tty_unregister_ldisc);
111 : :
112 : 0 : static struct tty_ldisc_ops *get_ldops(int disc)
113 : : {
114 : : unsigned long flags;
115 : : struct tty_ldisc_ops *ldops, *ret;
116 : :
117 : 597 : raw_spin_lock_irqsave(&tty_ldiscs_lock, flags);
118 : : ret = ERR_PTR(-EINVAL);
119 : 597 : ldops = tty_ldiscs[disc];
120 [ + + ]: 597 : if (ldops) {
121 : : ret = ERR_PTR(-EAGAIN);
122 [ + - ]: 569 : if (try_module_get(ldops->owner)) {
123 : 569 : ldops->refcount++;
124 : : ret = ldops;
125 : : }
126 : : }
127 : 597 : raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags);
128 : 597 : return ret;
129 : : }
130 : :
131 : 569 : static void put_ldops(struct tty_ldisc_ops *ldops)
132 : : {
133 : : unsigned long flags;
134 : :
135 : 569 : raw_spin_lock_irqsave(&tty_ldiscs_lock, flags);
136 : 569 : ldops->refcount--;
137 : 569 : module_put(ldops->owner);
138 : 569 : raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags);
139 : 569 : }
140 : :
141 : : /**
142 : : * tty_ldisc_get - take a reference to an ldisc
143 : : * @disc: ldisc number
144 : : *
145 : : * Takes a reference to a line discipline. Deals with refcounts and
146 : : * module locking counts. Returns NULL if the discipline is not available.
147 : : * Returns a pointer to the discipline and bumps the ref count if it is
148 : : * available
149 : : *
150 : : * Locking:
151 : : * takes tty_ldiscs_lock to guard against ldisc races
152 : : */
153 : :
154 : 0 : static struct tty_ldisc *tty_ldisc_get(struct tty_struct *tty, int disc)
155 : : {
156 : : struct tty_ldisc *ld;
157 : : struct tty_ldisc_ops *ldops;
158 : :
159 [ + - ]: 567 : if (disc < N_TTY || disc >= NR_LDISCS)
160 : : return ERR_PTR(-EINVAL);
161 : :
162 : : /*
163 : : * Get the ldisc ops - we may need to request them to be loaded
164 : : * dynamically and try again.
165 : : */
166 : 567 : ldops = get_ldops(disc);
167 [ - + ]: 567 : if (IS_ERR(ldops)) {
168 : 0 : request_module("tty-ldisc-%d", disc);
169 : 0 : ldops = get_ldops(disc);
170 [ # # ]: 0 : if (IS_ERR(ldops))
171 : : return ERR_CAST(ldops);
172 : : }
173 : :
174 : : ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL);
175 [ - + ]: 1134 : if (ld == NULL) {
176 : 0 : put_ldops(ldops);
177 : 0 : return ERR_PTR(-ENOMEM);
178 : : }
179 : :
180 : 567 : ld->ops = ldops;
181 : 567 : ld->tty = tty;
182 : :
183 : 567 : return ld;
184 : : }
185 : :
186 : : /**
187 : : * tty_ldisc_put - release the ldisc
188 : : *
189 : : * Complement of tty_ldisc_get().
190 : : */
191 : : static inline void tty_ldisc_put(struct tty_ldisc *ld)
192 : : {
193 [ # # ][ # # ]: 567 : if (WARN_ON_ONCE(!ld))
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
[ # # - + ]
[ # # ][ # # ]
[ + - - + ]
[ # # ][ # # ]
[ + - ][ # # ]
[ # # ][ # # ]
[ # # # # ]
[ # # ][ # # ]
[ # # # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
194 : : return;
195 : :
196 : 567 : put_ldops(ld->ops);
197 : 567 : kfree(ld);
198 : : }
199 : :
200 : 0 : static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
201 : : {
202 [ + + ]: 2 : return (*pos < NR_LDISCS) ? pos : NULL;
203 : : }
204 : :
205 : 0 : static void *tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos)
206 : : {
207 : 30 : (*pos)++;
208 [ + + ]: 30 : return (*pos < NR_LDISCS) ? pos : NULL;
209 : : }
210 : :
211 : 0 : static void tty_ldiscs_seq_stop(struct seq_file *m, void *v)
212 : : {
213 : 2 : }
214 : :
215 : 0 : static int tty_ldiscs_seq_show(struct seq_file *m, void *v)
216 : : {
217 : 30 : int i = *(loff_t *)v;
218 : : struct tty_ldisc_ops *ldops;
219 : :
220 : 30 : ldops = get_ldops(i);
221 [ + + ]: 30 : if (IS_ERR(ldops))
222 : : return 0;
223 [ + - ]: 2 : seq_printf(m, "%-10s %2d\n", ldops->name ? ldops->name : "???", i);
224 : 2 : put_ldops(ldops);
225 : 2 : return 0;
226 : : }
227 : :
228 : : static const struct seq_operations tty_ldiscs_seq_ops = {
229 : : .start = tty_ldiscs_seq_start,
230 : : .next = tty_ldiscs_seq_next,
231 : : .stop = tty_ldiscs_seq_stop,
232 : : .show = tty_ldiscs_seq_show,
233 : : };
234 : :
235 : 0 : static int proc_tty_ldiscs_open(struct inode *inode, struct file *file)
236 : : {
237 : 1 : return seq_open(file, &tty_ldiscs_seq_ops);
238 : : }
239 : :
240 : : const struct file_operations tty_ldiscs_proc_fops = {
241 : : .owner = THIS_MODULE,
242 : : .open = proc_tty_ldiscs_open,
243 : : .read = seq_read,
244 : : .llseek = seq_lseek,
245 : : .release = seq_release,
246 : : };
247 : :
248 : : /**
249 : : * tty_ldisc_ref_wait - wait for the tty ldisc
250 : : * @tty: tty device
251 : : *
252 : : * Dereference the line discipline for the terminal and take a
253 : : * reference to it. If the line discipline is in flux then
254 : : * wait patiently until it changes.
255 : : *
256 : : * Note: Must not be called from an IRQ/timer context. The caller
257 : : * must also be careful not to hold other locks that will deadlock
258 : : * against a discipline change, such as an existing ldisc reference
259 : : * (which we check for)
260 : : *
261 : : * Note: only callable from a file_operations routine (which
262 : : * guarantees tty->ldisc != NULL when the lock is acquired).
263 : : */
264 : :
265 : 0 : struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
266 : : {
267 : 146842 : ldsem_down_read(&tty->ldisc_sem, MAX_SCHEDULE_TIMEOUT);
268 [ - + ]: 146872 : WARN_ON(!tty->ldisc);
269 : 30 : return tty->ldisc;
270 : : }
271 : : EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
272 : :
273 : : /**
274 : : * tty_ldisc_ref - get the tty ldisc
275 : : * @tty: tty device
276 : : *
277 : : * Dereference the line discipline for the terminal and take a
278 : : * reference to it. If the line discipline is in flux then
279 : : * return NULL. Can be called from IRQ and timer functions.
280 : : */
281 : :
282 : 0 : struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty)
283 : : {
284 : : struct tty_ldisc *ld = NULL;
285 : :
286 [ + - ]: 61517 : if (ldsem_down_read_trylock(&tty->ldisc_sem)) {
287 : 61517 : ld = tty->ldisc;
288 [ - + ]: 61517 : if (!ld)
289 : 0 : ldsem_up_read(&tty->ldisc_sem);
290 : : }
291 : 0 : return ld;
292 : : }
293 : : EXPORT_SYMBOL_GPL(tty_ldisc_ref);
294 : :
295 : : /**
296 : : * tty_ldisc_deref - free a tty ldisc reference
297 : : * @ld: reference to free up
298 : : *
299 : : * Undoes the effect of tty_ldisc_ref or tty_ldisc_ref_wait. May
300 : : * be called in IRQ context.
301 : : */
302 : :
303 : 0 : void tty_ldisc_deref(struct tty_ldisc *ld)
304 : : {
305 : 208315 : ldsem_up_read(&ld->tty->ldisc_sem);
306 : 208308 : }
307 : : EXPORT_SYMBOL_GPL(tty_ldisc_deref);
308 : :
309 : :
310 : : static inline int __lockfunc
311 : : tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout)
312 : : {
313 : 473 : return ldsem_down_write(&tty->ldisc_sem, timeout);
314 : : }
315 : :
316 : : static inline int __lockfunc
317 : : tty_ldisc_lock_nested(struct tty_struct *tty, unsigned long timeout)
318 : : {
319 : 188 : return ldsem_down_write_nested(&tty->ldisc_sem,
320 : : LDISC_SEM_OTHER, timeout);
321 : : }
322 : :
323 : : static inline void tty_ldisc_unlock(struct tty_struct *tty)
324 : : {
325 : 661 : return ldsem_up_write(&tty->ldisc_sem);
326 : : }
327 : :
328 : : static int __lockfunc
329 : 0 : tty_ldisc_lock_pair_timeout(struct tty_struct *tty, struct tty_struct *tty2,
330 : : unsigned long timeout)
331 : : {
332 : : int ret;
333 : :
334 [ + + ]: 473 : if (tty < tty2) {
335 : : ret = tty_ldisc_lock(tty, timeout);
336 [ + - ]: 95 : if (ret) {
337 : : ret = tty_ldisc_lock_nested(tty2, timeout);
338 [ - + ]: 95 : if (!ret)
339 : : tty_ldisc_unlock(tty);
340 : : }
341 : : } else {
342 : : /* if this is possible, it has lots of implications */
343 [ - + ][ # # ]: 378 : WARN_ON_ONCE(tty == tty2);
[ # # ]
344 [ + + ]: 378 : if (tty2 && tty != tty2) {
345 : : ret = tty_ldisc_lock(tty2, timeout);
346 [ + - ]: 93 : if (ret) {
347 : : ret = tty_ldisc_lock_nested(tty, timeout);
348 [ - + ]: 93 : if (!ret)
349 : : tty_ldisc_unlock(tty2);
350 : : }
351 : : } else
352 : : ret = tty_ldisc_lock(tty, timeout);
353 : : }
354 : :
355 [ + - ]: 473 : if (!ret)
356 : : return -EBUSY;
357 : :
358 : 473 : set_bit(TTY_LDISC_HALTED, &tty->flags);
359 [ + + ]: 473 : if (tty2)
360 : 188 : set_bit(TTY_LDISC_HALTED, &tty2->flags);
361 : : return 0;
362 : : }
363 : :
364 : : static void __lockfunc
365 : : tty_ldisc_lock_pair(struct tty_struct *tty, struct tty_struct *tty2)
366 : : {
367 : 473 : tty_ldisc_lock_pair_timeout(tty, tty2, MAX_SCHEDULE_TIMEOUT);
368 : : }
369 : :
370 : : static void __lockfunc tty_ldisc_unlock_pair(struct tty_struct *tty,
371 : : struct tty_struct *tty2)
372 : : {
373 : : tty_ldisc_unlock(tty);
374 [ + + + - ]: 473 : if (tty2)
375 : : tty_ldisc_unlock(tty2);
376 : : }
377 : :
378 : 0 : static void __lockfunc tty_ldisc_enable_pair(struct tty_struct *tty,
379 : : struct tty_struct *tty2)
380 : : {
381 : 94 : clear_bit(TTY_LDISC_HALTED, &tty->flags);
382 [ + - ]: 94 : if (tty2)
383 : 94 : clear_bit(TTY_LDISC_HALTED, &tty2->flags);
384 : :
385 : : tty_ldisc_unlock_pair(tty, tty2);
386 : 94 : }
387 : :
388 : : /**
389 : : * tty_ldisc_flush - flush line discipline queue
390 : : * @tty: tty
391 : : *
392 : : * Flush the line discipline queue (if any) for this tty. If there
393 : : * is no line discipline active this is a no-op.
394 : : */
395 : :
396 : 0 : void tty_ldisc_flush(struct tty_struct *tty)
397 : : {
398 : 0 : struct tty_ldisc *ld = tty_ldisc_ref(tty);
399 [ # # ]: 0 : if (ld) {
400 [ # # ]: 0 : if (ld->ops->flush_buffer)
401 : 0 : ld->ops->flush_buffer(tty);
402 : : tty_ldisc_deref(ld);
403 : : }
404 : 0 : tty_buffer_flush(tty);
405 : 0 : }
406 : : EXPORT_SYMBOL_GPL(tty_ldisc_flush);
407 : :
408 : : /**
409 : : * tty_set_termios_ldisc - set ldisc field
410 : : * @tty: tty structure
411 : : * @num: line discipline number
412 : : *
413 : : * This is probably overkill for real world processors but
414 : : * they are not on hot paths so a little discipline won't do
415 : : * any harm.
416 : : *
417 : : * Locking: takes termios_rwsem
418 : : */
419 : :
420 : : static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
421 : : {
422 : 567 : down_write(&tty->termios_rwsem);
423 : 567 : tty->termios.c_line = num;
424 : 567 : up_write(&tty->termios_rwsem);
425 : : }
426 : :
427 : : /**
428 : : * tty_ldisc_open - open a line discipline
429 : : * @tty: tty we are opening the ldisc on
430 : : * @ld: discipline to open
431 : : *
432 : : * A helper opening method. Also a convenient debugging and check
433 : : * point.
434 : : *
435 : : * Locking: always called with BTM already held.
436 : : */
437 : :
438 : 0 : static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)
439 : : {
440 [ - + ]: 567 : WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags));
441 [ + - ]: 567 : if (ld->ops->open) {
442 : : int ret;
443 : : /* BTM here locks versus a hangup event */
444 : 567 : ret = ld->ops->open(tty);
445 [ - + ]: 567 : if (ret)
446 : 567 : clear_bit(TTY_LDISC_OPEN, &tty->flags);
447 : : return ret;
448 : : }
449 : : return 0;
450 : : }
451 : :
452 : : /**
453 : : * tty_ldisc_close - close a line discipline
454 : : * @tty: tty we are opening the ldisc on
455 : : * @ld: discipline to close
456 : : *
457 : : * A helper close method. Also a convenient debugging and check
458 : : * point.
459 : : */
460 : :
461 : 0 : static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
462 : : {
463 [ - + ]: 567 : WARN_ON(!test_bit(TTY_LDISC_OPEN, &tty->flags));
464 : 567 : clear_bit(TTY_LDISC_OPEN, &tty->flags);
465 [ + - ]: 567 : if (ld->ops->close)
466 : 567 : ld->ops->close(tty);
467 : 567 : }
468 : :
469 : : /**
470 : : * tty_ldisc_restore - helper for tty ldisc change
471 : : * @tty: tty to recover
472 : : * @old: previous ldisc
473 : : *
474 : : * Restore the previous line discipline or N_TTY when a line discipline
475 : : * change fails due to an open error
476 : : */
477 : :
478 : 0 : static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
479 : : {
480 : : char buf[64];
481 : : struct tty_ldisc *new_ldisc;
482 : : int r;
483 : :
484 : : /* There is an outstanding reference here so this is safe */
485 : 0 : old = tty_ldisc_get(tty, old->ops->num);
486 [ # # ]: 0 : WARN_ON(IS_ERR(old));
487 : 0 : tty->ldisc = old;
488 : 0 : tty_set_termios_ldisc(tty, old->ops->num);
489 [ # # ]: 0 : if (tty_ldisc_open(tty, old) < 0) {
490 : : tty_ldisc_put(old);
491 : : /* This driver is always present */
492 : 0 : new_ldisc = tty_ldisc_get(tty, N_TTY);
493 [ # # ]: 0 : if (IS_ERR(new_ldisc))
494 : 0 : panic("n_tty: get");
495 : 0 : tty->ldisc = new_ldisc;
496 : : tty_set_termios_ldisc(tty, N_TTY);
497 : 0 : r = tty_ldisc_open(tty, new_ldisc);
498 [ # # ]: 0 : if (r < 0)
499 : 0 : panic("Couldn't open N_TTY ldisc for "
500 : : "%s --- error %d.",
501 : : tty_name(tty, buf), r);
502 : : }
503 : 0 : }
504 : :
505 : : /**
506 : : * tty_set_ldisc - set line discipline
507 : : * @tty: the terminal to set
508 : : * @ldisc: the line discipline
509 : : *
510 : : * Set the discipline of a tty line. Must be called from a process
511 : : * context. The ldisc change logic has to protect itself against any
512 : : * overlapping ldisc change (including on the other end of pty pairs),
513 : : * the close of one side of a tty/pty pair, and eventually hangup.
514 : : */
515 : :
516 : 0 : int tty_set_ldisc(struct tty_struct *tty, int ldisc)
517 : : {
518 : : int retval;
519 : 0 : struct tty_ldisc *old_ldisc, *new_ldisc;
520 : 0 : struct tty_struct *o_tty = tty->link;
521 : :
522 : 0 : new_ldisc = tty_ldisc_get(tty, ldisc);
523 [ # # ]: 0 : if (IS_ERR(new_ldisc))
524 : 0 : return PTR_ERR(new_ldisc);
525 : :
526 : 0 : retval = tty_ldisc_lock_pair_timeout(tty, o_tty, 5 * HZ);
527 [ # # ]: 0 : if (retval) {
528 : : tty_ldisc_put(new_ldisc);
529 : 0 : return retval;
530 : : }
531 : :
532 : : /*
533 : : * Check the no-op case
534 : : */
535 : :
536 [ # # ]: 0 : if (tty->ldisc->ops->num == ldisc) {
537 : 0 : tty_ldisc_enable_pair(tty, o_tty);
538 : : tty_ldisc_put(new_ldisc);
539 : : return 0;
540 : : }
541 : :
542 : : old_ldisc = tty->ldisc;
543 : 0 : tty_lock(tty);
544 : :
545 [ # # ][ # # ]: 0 : if (test_bit(TTY_HUPPING, &tty->flags) ||
546 : : test_bit(TTY_HUPPED, &tty->flags)) {
547 : : /* We were raced by the hangup method. It will have stomped
548 : : the ldisc data and closed the ldisc down */
549 : 0 : tty_ldisc_enable_pair(tty, o_tty);
550 : : tty_ldisc_put(new_ldisc);
551 : 0 : tty_unlock(tty);
552 : 0 : return -EIO;
553 : : }
554 : :
555 : : /* Shutdown the old discipline. */
556 : 0 : tty_ldisc_close(tty, old_ldisc);
557 : :
558 : : /* Now set up the new line discipline. */
559 : 0 : tty->ldisc = new_ldisc;
560 : : tty_set_termios_ldisc(tty, ldisc);
561 : :
562 : 0 : retval = tty_ldisc_open(tty, new_ldisc);
563 [ # # ]: 0 : if (retval < 0) {
564 : : /* Back to the old one or N_TTY if we can't */
565 : : tty_ldisc_put(new_ldisc);
566 : 0 : tty_ldisc_restore(tty, old_ldisc);
567 : : }
568 : :
569 [ # # ][ # # ]: 0 : if (tty->ldisc->ops->num != old_ldisc->ops->num && tty->ops->set_ldisc)
570 : 0 : tty->ops->set_ldisc(tty);
571 : :
572 : : /* At this point we hold a reference to the new ldisc and a
573 : : reference to the old ldisc, or we hold two references to
574 : : the old ldisc (if it was restored as part of error cleanup
575 : : above). In either case, releasing a single reference from
576 : : the old ldisc is correct. */
577 : :
578 : : tty_ldisc_put(old_ldisc);
579 : :
580 : : /*
581 : : * Allow ldisc referencing to occur again
582 : : */
583 : 0 : tty_ldisc_enable_pair(tty, o_tty);
584 : :
585 : : /* Restart the work queue in case no characters kick it off. Safe if
586 : : already running */
587 : 0 : schedule_work(&tty->port->buf.work);
588 [ # # ]: 0 : if (o_tty)
589 : 0 : schedule_work(&o_tty->port->buf.work);
590 : :
591 : 0 : tty_unlock(tty);
592 : 0 : return retval;
593 : : }
594 : :
595 : : /**
596 : : * tty_reset_termios - reset terminal state
597 : : * @tty: tty to reset
598 : : *
599 : : * Restore a terminal to the driver default state.
600 : : */
601 : :
602 : 0 : static void tty_reset_termios(struct tty_struct *tty)
603 : : {
604 : 94 : down_write(&tty->termios_rwsem);
605 : 94 : tty->termios = tty->driver->init_termios;
606 : 94 : tty->termios.c_ispeed = tty_termios_input_baud_rate(&tty->termios);
607 : 94 : tty->termios.c_ospeed = tty_termios_baud_rate(&tty->termios);
608 : 94 : up_write(&tty->termios_rwsem);
609 : 94 : }
610 : :
611 : :
612 : : /**
613 : : * tty_ldisc_reinit - reinitialise the tty ldisc
614 : : * @tty: tty to reinit
615 : : * @ldisc: line discipline to reinitialize
616 : : *
617 : : * Switch the tty to a line discipline and leave the ldisc
618 : : * state closed
619 : : */
620 : :
621 : 0 : static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
622 : : {
623 : 94 : struct tty_ldisc *ld = tty_ldisc_get(tty, ldisc);
624 : :
625 [ + - ]: 94 : if (IS_ERR(ld))
626 : : return -1;
627 : :
628 : 94 : tty_ldisc_close(tty, tty->ldisc);
629 : 94 : tty_ldisc_put(tty->ldisc);
630 : : /*
631 : : * Switch the line discipline back
632 : : */
633 : 94 : tty->ldisc = ld;
634 : : tty_set_termios_ldisc(tty, ldisc);
635 : :
636 : 94 : return 0;
637 : : }
638 : :
639 : : /**
640 : : * tty_ldisc_hangup - hangup ldisc reset
641 : : * @tty: tty being hung up
642 : : *
643 : : * Some tty devices reset their termios when they receive a hangup
644 : : * event. In that situation we must also switch back to N_TTY properly
645 : : * before we reset the termios data.
646 : : *
647 : : * Locking: We can take the ldisc mutex as the rest of the code is
648 : : * careful to allow for this.
649 : : *
650 : : * In the pty pair case this occurs in the close() path of the
651 : : * tty itself so we must be careful about locking rules.
652 : : */
653 : :
654 : 0 : void tty_ldisc_hangup(struct tty_struct *tty)
655 : : {
656 : : struct tty_ldisc *ld;
657 : 94 : int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS;
658 : : int err = 0;
659 : :
660 : : tty_ldisc_debug(tty, "closing ldisc: %p\n", tty->ldisc);
661 : :
662 : 94 : ld = tty_ldisc_ref(tty);
663 [ + - ]: 94 : if (ld != NULL) {
664 [ + - ]: 94 : if (ld->ops->flush_buffer)
665 : 94 : ld->ops->flush_buffer(tty);
666 : 94 : tty_driver_flush_buffer(tty);
667 [ - + ][ # # ]: 94 : if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
668 : 0 : ld->ops->write_wakeup)
669 : 0 : ld->ops->write_wakeup(tty);
670 [ - + ]: 94 : if (ld->ops->hangup)
671 : 0 : ld->ops->hangup(tty);
672 : : tty_ldisc_deref(ld);
673 : : }
674 : :
675 : 94 : wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
676 : 94 : wake_up_interruptible_poll(&tty->read_wait, POLLIN);
677 : :
678 : 94 : tty_unlock(tty);
679 : :
680 : : /*
681 : : * Shutdown the current line discipline, and reset it to
682 : : * N_TTY if need be.
683 : : *
684 : : * Avoid racing set_ldisc or tty_ldisc_release
685 : : */
686 : 94 : tty_ldisc_lock_pair(tty, tty->link);
687 : 94 : tty_lock(tty);
688 : :
689 [ + - ]: 94 : if (tty->ldisc) {
690 : :
691 : : /* At this point we have a halted ldisc; we want to close it and
692 : : reopen a new ldisc. We could defer the reopen to the next
693 : : open but it means auditing a lot of other paths so this is
694 : : a FIXME */
695 [ - + ]: 94 : if (reset == 0) {
696 : :
697 [ # # ]: 0 : if (!tty_ldisc_reinit(tty, tty->termios.c_line))
698 : 0 : err = tty_ldisc_open(tty, tty->ldisc);
699 : : else
700 : : err = 1;
701 : : }
702 : : /* If the re-open fails or we reset then go to N_TTY. The
703 : : N_TTY open cannot fail */
704 [ + - ]: 94 : if (reset || err) {
705 [ - + ]: 94 : BUG_ON(tty_ldisc_reinit(tty, N_TTY));
706 [ - + ]: 94 : WARN_ON(tty_ldisc_open(tty, tty->ldisc));
707 : : }
708 : : }
709 : 94 : tty_ldisc_enable_pair(tty, tty->link);
710 [ + - ]: 94 : if (reset)
711 : 94 : tty_reset_termios(tty);
712 : :
713 : : tty_ldisc_debug(tty, "re-opened ldisc: %p\n", tty->ldisc);
714 : 94 : }
715 : :
716 : : /**
717 : : * tty_ldisc_setup - open line discipline
718 : : * @tty: tty being shut down
719 : : * @o_tty: pair tty for pty/tty pairs
720 : : *
721 : : * Called during the initial open of a tty/pty pair in order to set up the
722 : : * line disciplines and bind them to the tty. This has no locking issues
723 : : * as the device isn't yet active.
724 : : */
725 : :
726 : 0 : int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
727 : : {
728 : 379 : struct tty_ldisc *ld = tty->ldisc;
729 : : int retval;
730 : :
731 : 379 : retval = tty_ldisc_open(tty, ld);
732 [ + - ]: 379 : if (retval)
733 : : return retval;
734 : :
735 [ + + ]: 379 : if (o_tty) {
736 : 94 : retval = tty_ldisc_open(o_tty, o_tty->ldisc);
737 [ - + ]: 94 : if (retval) {
738 : 0 : tty_ldisc_close(tty, ld);
739 : 0 : return retval;
740 : : }
741 : : }
742 : : return 0;
743 : : }
744 : :
745 : 0 : static void tty_ldisc_kill(struct tty_struct *tty)
746 : : {
747 : : /*
748 : : * Now kill off the ldisc
749 : : */
750 : 473 : tty_ldisc_close(tty, tty->ldisc);
751 : 473 : tty_ldisc_put(tty->ldisc);
752 : : /* Force an oops if we mess this up */
753 : 473 : tty->ldisc = NULL;
754 : :
755 : : /* Ensure the next open requests the N_TTY ldisc */
756 : : tty_set_termios_ldisc(tty, N_TTY);
757 : 473 : }
758 : :
759 : : /**
760 : : * tty_ldisc_release - release line discipline
761 : : * @tty: tty being shut down
762 : : * @o_tty: pair tty for pty/tty pairs
763 : : *
764 : : * Called during the final close of a tty/pty pair in order to shut down
765 : : * the line discpline layer. On exit the ldisc assigned is N_TTY and the
766 : : * ldisc has not been opened.
767 : : */
768 : :
769 : 0 : void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
770 : : {
771 : : /*
772 : : * Shutdown this line discipline. As this is the final close,
773 : : * it does not race with the set_ldisc code path.
774 : : */
775 : :
776 : : tty_ldisc_debug(tty, "closing ldisc: %p\n", tty->ldisc);
777 : :
778 : : tty_ldisc_lock_pair(tty, o_tty);
779 : 379 : tty_lock_pair(tty, o_tty);
780 : :
781 : 379 : tty_ldisc_kill(tty);
782 [ + + ]: 379 : if (o_tty)
783 : 94 : tty_ldisc_kill(o_tty);
784 : :
785 : 379 : tty_unlock_pair(tty, o_tty);
786 : : tty_ldisc_unlock_pair(tty, o_tty);
787 : :
788 : : /* And the memory resources remaining (buffers, termios) will be
789 : : disposed of when the kref hits zero */
790 : :
791 : : tty_ldisc_debug(tty, "ldisc closed\n");
792 : 379 : }
793 : :
794 : : /**
795 : : * tty_ldisc_init - ldisc setup for new tty
796 : : * @tty: tty being allocated
797 : : *
798 : : * Set up the line discipline objects for a newly allocated tty. Note that
799 : : * the tty structure is not completely set up when this call is made.
800 : : */
801 : :
802 : 0 : void tty_ldisc_init(struct tty_struct *tty)
803 : : {
804 : 473 : struct tty_ldisc *ld = tty_ldisc_get(tty, N_TTY);
805 [ - + ]: 473 : if (IS_ERR(ld))
806 : 0 : panic("n_tty: init_tty");
807 : 473 : tty->ldisc = ld;
808 : 473 : }
809 : :
810 : : /**
811 : : * tty_ldisc_init - ldisc cleanup for new tty
812 : : * @tty: tty that was allocated recently
813 : : *
814 : : * The tty structure must not becompletely set up (tty_ldisc_setup) when
815 : : * this call is made.
816 : : */
817 : 0 : void tty_ldisc_deinit(struct tty_struct *tty)
818 : : {
819 : 0 : tty_ldisc_put(tty->ldisc);
820 : 0 : tty->ldisc = NULL;
821 : 0 : }
822 : :
823 : 0 : void tty_ldisc_begin(void)
824 : : {
825 : : /* Setup the default TTY line discipline. */
826 : 0 : (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
827 : 0 : }
|