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