LCOV - code coverage report
Current view: top level - drivers/tty - tty_ldisc.c (source / functions) Hit Total Coverage
Test: Real Lines: 147 245 60.0 %
Date: 2020-10-17 15:46:43 Functions: 0 31 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

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

Generated by: LCOV version 1.14