LCOV - code coverage report
Current view: top level - drivers/tty - tty_ldisc.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 175 313 55.9 %
Date: 2021-04-22 12:43:58 Functions: 23 33 69.7 %

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

Generated by: LCOV version 1.14