LCOV - code coverage report
Current view: top level - drivers/tty - tty_ldisc.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 129 237 54.4 %
Date: 2014-04-16 Functions: 22 29 75.9 %
Branches: 59 208 28.4 %

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

Generated by: LCOV version 1.9