2017-11-06 20:11:51 +03:00
// SPDX-License-Identifier: GPL-2.0
2008-07-22 14:16:55 +04:00
# include <linux/types.h>
# include <linux/errno.h>
2011-11-16 19:27:10 +04:00
# include <linux/kmod.h>
2008-07-22 14:16:55 +04:00
# include <linux/sched.h>
# include <linux/interrupt.h>
# include <linux/tty.h>
# include <linux/tty_driver.h>
# include <linux/file.h>
# include <linux/mm.h>
# include <linux/string.h>
# include <linux/slab.h>
# include <linux/poll.h>
# include <linux/proc_fs.h>
# include <linux/module.h>
# include <linux/device.h>
# include <linux/wait.h>
# include <linux/bitops.h>
# include <linux/seq_file.h>
# include <linux/uaccess.h>
2011-11-16 19:27:09 +04:00
# include <linux/ratelimit.h>
2021-04-08 15:51:22 +03:00
# include "tty.h"
2008-07-22 14:16:55 +04:00
2013-03-12 00:44:38 +04:00
# undef LDISC_DEBUG_HANGUP
# ifdef LDISC_DEBUG_HANGUP
2015-07-13 05:49:10 +03:00
# define tty_ldisc_debug(tty, f, args...) tty_debug(tty, f, ##args)
2013-03-12 00:44:38 +04:00
# else
# define tty_ldisc_debug(tty, f, args...)
# endif
2013-06-15 15:04:47 +04:00
/* lockdep nested classes for tty->ldisc_sem */
enum {
LDISC_SEM_NORMAL ,
LDISC_SEM_OTHER ,
} ;
2008-07-22 14:16:55 +04:00
/*
* This guards the refcounted line discipline lists . The lock
* must be taken with irqs off because there are hangup path
* callers who will do ldisc lookups and cannot sleep .
*/
2013-06-15 15:04:46 +04:00
static DEFINE_RAW_SPINLOCK ( tty_ldiscs_lock ) ;
2008-07-22 14:16:55 +04:00
/* Line disc dispatch table */
static struct tty_ldisc_ops * tty_ldiscs [ NR_LDISCS ] ;
/**
2021-11-26 11:16:01 +03:00
* tty_register_ldisc - install a line discipline
* @ new_ldisc : pointer to the ldisc object
2008-07-22 14:16:55 +04:00
*
2021-11-26 11:16:01 +03:00
* Installs a new line discipline into the kernel . The discipline is set up as
* unreferenced and then made available to the kernel from this point onwards .
2008-07-22 14:16:55 +04:00
*
2021-11-26 11:16:01 +03:00
* Locking : takes % tty_ldiscs_lock to guard against ldisc races
2008-07-22 14:16:55 +04:00
*/
2021-05-05 12:19:07 +03:00
int tty_register_ldisc ( struct tty_ldisc_ops * new_ldisc )
2008-07-22 14:16:55 +04:00
{
unsigned long flags ;
2021-05-05 12:19:07 +03:00
if ( new_ldisc - > num < N_TTY | | new_ldisc - > num > = NR_LDISCS )
2008-07-22 14:16:55 +04:00
return - EINVAL ;
2013-06-15 15:04:46 +04:00
raw_spin_lock_irqsave ( & tty_ldiscs_lock , flags ) ;
2021-05-05 12:19:07 +03:00
tty_ldiscs [ new_ldisc - > num ] = new_ldisc ;
2013-06-15 15:04:46 +04:00
raw_spin_unlock_irqrestore ( & tty_ldiscs_lock , flags ) ;
2008-07-22 14:16:55 +04:00
2023-02-22 23:23:03 +03:00
return 0 ;
2008-07-22 14:16:55 +04:00
}
EXPORT_SYMBOL ( tty_register_ldisc ) ;
/**
2021-11-26 11:16:01 +03:00
* tty_unregister_ldisc - unload a line discipline
* @ ldisc : ldisc number
2008-07-22 14:16:55 +04:00
*
2021-11-26 11:16:01 +03:00
* Remove a line discipline from the kernel providing it is not currently in
* use .
2008-07-22 14:16:55 +04:00
*
2021-11-26 11:16:01 +03:00
* Locking : takes % tty_ldiscs_lock to guard against ldisc races
2008-07-22 14:16:55 +04:00
*/
2021-05-05 12:19:12 +03:00
void tty_unregister_ldisc ( struct tty_ldisc_ops * ldisc )
2008-07-22 14:16:55 +04:00
{
unsigned long flags ;
2013-06-15 15:04:46 +04:00
raw_spin_lock_irqsave ( & tty_ldiscs_lock , flags ) ;
2021-05-05 12:19:10 +03:00
tty_ldiscs [ ldisc - > num ] = NULL ;
2013-06-15 15:04:46 +04:00
raw_spin_unlock_irqrestore ( & tty_ldiscs_lock , flags ) ;
2008-07-22 14:16:55 +04:00
}
EXPORT_SYMBOL ( tty_unregister_ldisc ) ;
2009-08-04 03:00:15 +04:00
static struct tty_ldisc_ops * get_ldops ( int disc )
{
unsigned long flags ;
struct tty_ldisc_ops * ldops , * ret ;
2013-06-15 15:04:46 +04:00
raw_spin_lock_irqsave ( & tty_ldiscs_lock , flags ) ;
2009-08-04 03:00:15 +04:00
ret = ERR_PTR ( - EINVAL ) ;
ldops = tty_ldiscs [ disc ] ;
if ( ldops ) {
ret = ERR_PTR ( - EAGAIN ) ;
2021-05-05 12:19:10 +03:00
if ( try_module_get ( ldops - > owner ) )
2009-08-04 03:00:15 +04:00
ret = ldops ;
}
2013-06-15 15:04:46 +04:00
raw_spin_unlock_irqrestore ( & tty_ldiscs_lock , flags ) ;
2009-08-04 03:00:15 +04:00
return ret ;
}
static void put_ldops ( struct tty_ldisc_ops * ldops )
{
unsigned long flags ;
2013-06-15 15:04:46 +04:00
raw_spin_lock_irqsave ( & tty_ldiscs_lock , flags ) ;
2009-08-04 03:00:15 +04:00
module_put ( ldops - > owner ) ;
2013-06-15 15:04:46 +04:00
raw_spin_unlock_irqrestore ( & tty_ldiscs_lock , flags ) ;
2009-08-04 03:00:15 +04:00
}
2008-07-22 14:16:55 +04:00
2022-10-22 21:29:48 +03:00
int tty_ldisc_autoload = IS_BUILTIN ( CONFIG_LDISC_AUTOLOAD ) ;
2021-11-26 11:16:01 +03:00
2008-07-22 14:16:55 +04:00
/**
2021-11-26 11:16:01 +03:00
* tty_ldisc_get - take a reference to an ldisc
* @ tty : tty device
* @ disc : ldisc number
*
* Takes a reference to a line discipline . Deals with refcounts and module
* locking counts . If the discipline is not available , its module loaded , if
* possible .
*
* Returns :
* * - % EINVAL if the discipline index is not [ % N_TTY . . % NR_LDISCS ] or if the
* discipline is not registered
* * - % EAGAIN if request_module ( ) failed to load or register the discipline
* * - % ENOMEM if allocation failure
* * Otherwise , returns a pointer to the discipline and bumps the ref count
*
* Locking : takes % tty_ldiscs_lock to guard against ldisc races
2008-07-22 14:16:55 +04:00
*/
2013-06-15 15:04:48 +04:00
static struct tty_ldisc * tty_ldisc_get ( struct tty_struct * tty , int disc )
2008-07-22 14:16:55 +04:00
{
2009-06-11 15:50:12 +04:00
struct tty_ldisc * ld ;
2009-08-04 03:01:28 +04:00
struct tty_ldisc_ops * ldops ;
2008-07-22 14:16:55 +04:00
if ( disc < N_TTY | | disc > = NR_LDISCS )
2009-06-11 15:50:12 +04:00
return ERR_PTR ( - EINVAL ) ;
2009-08-04 03:01:28 +04:00
/*
* Get the ldisc ops - we may need to request them to be loaded
* dynamically and try again .
*/
ldops = get_ldops ( disc ) ;
if ( IS_ERR ( ldops ) ) {
2019-01-21 19:26:42 +03:00
if ( ! capable ( CAP_SYS_MODULE ) & & ! tty_ldisc_autoload )
return ERR_PTR ( - EPERM ) ;
2008-07-22 14:16:55 +04:00
request_module ( " tty-ldisc-%d " , disc ) ;
2009-08-04 03:01:28 +04:00
ldops = get_ldops ( disc ) ;
if ( IS_ERR ( ldops ) )
return ERR_CAST ( ldops ) ;
}
2018-04-25 14:12:31 +03:00
/*
* There is no way to handle allocation failure of only 16 bytes .
* Let ' s simplify error handling and save more memory .
*/
ld = kmalloc ( sizeof ( struct tty_ldisc ) , GFP_KERNEL | __GFP_NOFAIL ) ;
2009-08-04 03:01:28 +04:00
ld - > ops = ldops ;
2013-06-15 15:04:48 +04:00
ld - > tty = tty ;
2012-05-03 16:37:43 +04:00
2009-06-11 15:50:12 +04:00
return ld ;
2008-07-22 14:16:55 +04:00
}
2021-11-26 11:16:01 +03:00
/**
* tty_ldisc_put - release the ldisc
* @ ld : lisdsc to release
2013-03-12 00:44:43 +04:00
*
2021-11-26 11:16:01 +03:00
* Complement of tty_ldisc_get ( ) .
2013-03-12 00:44:43 +04:00
*/
2015-10-27 19:40:02 +03:00
static void tty_ldisc_put ( struct tty_ldisc * ld )
2013-03-12 00:44:43 +04:00
{
if ( WARN_ON_ONCE ( ! ld ) )
return ;
2013-06-15 15:04:48 +04:00
put_ldops ( ld - > ops ) ;
2013-03-12 00:44:43 +04:00
kfree ( ld ) ;
}
2009-06-11 15:51:41 +04:00
static void * tty_ldiscs_seq_start ( struct seq_file * m , loff_t * pos )
2008-07-22 14:16:55 +04:00
{
return ( * pos < NR_LDISCS ) ? pos : NULL ;
}
2009-06-11 15:51:41 +04:00
static void * tty_ldiscs_seq_next ( struct seq_file * m , void * v , loff_t * pos )
2008-07-22 14:16:55 +04:00
{
( * pos ) + + ;
return ( * pos < NR_LDISCS ) ? pos : NULL ;
}
static void tty_ldiscs_seq_stop ( struct seq_file * m , void * v )
{
}
static int tty_ldiscs_seq_show ( struct seq_file * m , void * v )
{
int i = * ( loff_t * ) v ;
2009-08-04 03:00:15 +04:00
struct tty_ldisc_ops * ldops ;
2009-06-11 15:51:41 +04:00
2009-08-04 03:00:15 +04:00
ldops = get_ldops ( i ) ;
if ( IS_ERR ( ldops ) )
2008-07-22 14:16:55 +04:00
return 0 ;
2009-08-04 03:00:15 +04:00
seq_printf ( m , " %-10s %2d \n " , ldops - > name ? ldops - > name : " ??? " , i ) ;
put_ldops ( ldops ) ;
2008-07-22 14:16:55 +04:00
return 0 ;
}
2018-04-13 20:44:18 +03:00
const struct seq_operations tty_ldiscs_seq_ops = {
2008-07-22 14:16:55 +04:00
. start = tty_ldiscs_seq_start ,
. next = tty_ldiscs_seq_next ,
. stop = tty_ldiscs_seq_stop ,
. show = tty_ldiscs_seq_show ,
} ;
/**
2021-11-26 11:16:01 +03:00
* tty_ldisc_ref_wait - wait for the tty ldisc
* @ tty : tty device
2008-07-22 14:16:55 +04:00
*
2021-11-26 11:16:01 +03:00
* Dereference the line discipline for the terminal and take a reference to it .
* If the line discipline is in flux then wait patiently until it changes .
2008-07-22 14:16:55 +04:00
*
2021-11-26 11:16:01 +03:00
* Returns : % NULL if the tty has been hungup and not re - opened with a new file
* descriptor , otherwise valid ldisc reference
tty: Destroy ldisc instance on hangup
Currently, when the tty is hungup, the ldisc is re-instanced; ie., the
current instance is destroyed and a new instance is created. The purpose
of this design was to guarantee a valid, open ldisc for the lifetime of
the tty.
However, now that tty buffers are owned by and have lifetime equivalent
to the tty_port (since v3.10), any data received immediately after the
ldisc is re-instanced may cause continued driver i/o operations
concurrently with the driver's hangup() operation. For drivers that
shutdown h/w on hangup, this is unexpected and usually bad. For example,
the serial core may free the xmit buffer page concurrently with an
in-progress write() operation (triggered by echo).
With the existing stable and robust ldisc reference handling, the
cleaned-up tty_reopen(), the straggling unsafe ldisc use cleaned up, and
the preparation to properly handle a NULL tty->ldisc, the ldisc instance
can be destroyed and only re-instanced when the tty is re-opened.
If the tty was opened as /dev/console or /dev/tty0, the original behavior
of re-instancing the ldisc is retained (the 'reinit' parameter to
tty_ldisc_hangup() is true). This is required since those file descriptors
are never hungup.
This patch has neglible impact on userspace; the tty file_operations ptr
is changed to point to the hungup file operations _before_ the ldisc
instance is destroyed, so only racing file operations might now retrieve
a NULL ldisc reference (which is simply handled as if the hungup file
operation had been called instead -- see "tty: Prepare for destroying
line discipline on hangup").
This resolves a long-standing FIXME and several crash reports.
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2016-01-11 09:41:06 +03:00
*
2021-11-26 11:16:01 +03:00
* Note 1 : Must not be called from an IRQ / timer context . The caller must also
* be careful not to hold other locks that will deadlock against a discipline
* change , such as an existing ldisc reference ( which we check for ) .
2008-07-22 14:16:55 +04:00
*
2021-11-26 11:16:01 +03:00
* Note 2 : a file_operations routine ( read / poll / write ) should use this function
* to wait for any ldisc lifetime events to finish .
2008-07-22 14:16:55 +04:00
*/
struct tty_ldisc * tty_ldisc_ref_wait ( struct tty_struct * tty )
{
2017-03-04 15:46:12 +03:00
struct tty_ldisc * ld ;
2013-06-15 15:04:48 +04:00
ldsem_down_read ( & tty - > ldisc_sem , MAX_SCHEDULE_TIMEOUT ) ;
2017-03-04 15:46:12 +03:00
ld = tty - > ldisc ;
if ( ! ld )
2016-01-11 09:41:02 +03:00
ldsem_up_read ( & tty - > ldisc_sem ) ;
2017-03-04 15:46:12 +03:00
return ld ;
2008-07-22 14:16:55 +04:00
}
EXPORT_SYMBOL_GPL ( tty_ldisc_ref_wait ) ;
/**
2021-11-26 11:16:01 +03:00
* tty_ldisc_ref - get the tty ldisc
* @ tty : tty device
2008-07-22 14:16:55 +04:00
*
2021-11-26 11:16:01 +03:00
* Dereference the line discipline for the terminal and take a reference to it .
* If the line discipline is in flux then return % NULL . Can be called from IRQ
* and timer functions .
2008-07-22 14:16:55 +04:00
*/
struct tty_ldisc * tty_ldisc_ref ( struct tty_struct * tty )
{
2013-06-15 15:04:48 +04:00
struct tty_ldisc * ld = NULL ;
if ( ldsem_down_read_trylock ( & tty - > ldisc_sem ) ) {
ld = tty - > ldisc ;
if ( ! ld )
ldsem_up_read ( & tty - > ldisc_sem ) ;
}
return ld ;
2008-07-22 14:16:55 +04:00
}
EXPORT_SYMBOL_GPL ( tty_ldisc_ref ) ;
/**
2021-11-26 11:16:01 +03:00
* tty_ldisc_deref - free a tty ldisc reference
* @ ld : reference to free up
2008-07-22 14:16:55 +04:00
*
2021-11-26 11:16:01 +03:00
* Undoes the effect of tty_ldisc_ref ( ) or tty_ldisc_ref_wait ( ) . May be called
* in IRQ context .
2008-07-22 14:16:55 +04:00
*/
void tty_ldisc_deref ( struct tty_ldisc * ld )
{
2013-06-15 15:04:48 +04:00
ldsem_up_read ( & ld - > tty - > ldisc_sem ) ;
2008-07-22 14:16:55 +04:00
}
EXPORT_SYMBOL_GPL ( tty_ldisc_deref ) ;
2013-06-15 15:04:47 +04:00
2016-01-10 08:13:51 +03:00
static inline int
2014-11-05 20:13:06 +03:00
__tty_ldisc_lock ( struct tty_struct * tty , unsigned long timeout )
2013-06-15 15:04:47 +04:00
{
return ldsem_down_write ( & tty - > ldisc_sem , timeout ) ;
}
2016-01-10 08:13:51 +03:00
static inline int
2014-11-05 20:13:06 +03:00
__tty_ldisc_lock_nested ( struct tty_struct * tty , unsigned long timeout )
2013-06-15 15:04:47 +04:00
{
return ldsem_down_write_nested ( & tty - > ldisc_sem ,
LDISC_SEM_OTHER , timeout ) ;
}
2014-11-05 20:13:06 +03:00
static inline void __tty_ldisc_unlock ( struct tty_struct * tty )
2013-06-15 15:04:47 +04:00
{
2015-10-04 22:19:18 +03:00
ldsem_up_write ( & tty - > ldisc_sem ) ;
2013-06-15 15:04:47 +04:00
}
2018-01-23 10:46:34 +03:00
int tty_ldisc_lock ( struct tty_struct * tty , unsigned long timeout )
2014-11-05 20:13:07 +03:00
{
int ret ;
2018-11-01 03:24:48 +03:00
/* Kindly asking blocked readers to release the read side */
set_bit ( TTY_LDISC_CHANGING , & tty - > flags ) ;
wake_up_interruptible_all ( & tty - > read_wait ) ;
wake_up_interruptible_all ( & tty - > write_wait ) ;
2014-11-05 20:13:07 +03:00
ret = __tty_ldisc_lock ( tty , timeout ) ;
if ( ! ret )
return - EBUSY ;
set_bit ( TTY_LDISC_HALTED , & tty - > flags ) ;
return 0 ;
}
2018-01-23 10:46:34 +03:00
void tty_ldisc_unlock ( struct tty_struct * tty )
2014-11-05 20:13:07 +03:00
{
clear_bit ( TTY_LDISC_HALTED , & tty - > flags ) ;
2018-11-01 03:24:48 +03:00
/* Can be cleared here - ldisc_unlock will wake up writers firstly */
clear_bit ( TTY_LDISC_CHANGING , & tty - > flags ) ;
2014-11-05 20:13:07 +03:00
__tty_ldisc_unlock ( tty ) ;
}
2016-01-10 08:13:51 +03:00
static int
2013-06-15 15:04:47 +04:00
tty_ldisc_lock_pair_timeout ( struct tty_struct * tty , struct tty_struct * tty2 ,
unsigned long timeout )
{
int ret ;
if ( tty < tty2 ) {
2014-11-05 20:13:06 +03:00
ret = __tty_ldisc_lock ( tty , timeout ) ;
2013-06-15 15:04:47 +04:00
if ( ret ) {
2014-11-05 20:13:06 +03:00
ret = __tty_ldisc_lock_nested ( tty2 , timeout ) ;
2013-06-15 15:04:47 +04:00
if ( ! ret )
2014-11-05 20:13:06 +03:00
__tty_ldisc_unlock ( tty ) ;
2013-06-15 15:04:47 +04:00
}
} else {
/* if this is possible, it has lots of implications */
WARN_ON_ONCE ( tty = = tty2 ) ;
if ( tty2 & & tty ! = tty2 ) {
2014-11-05 20:13:06 +03:00
ret = __tty_ldisc_lock ( tty2 , timeout ) ;
2013-06-15 15:04:47 +04:00
if ( ret ) {
2014-11-05 20:13:06 +03:00
ret = __tty_ldisc_lock_nested ( tty , timeout ) ;
2013-06-15 15:04:47 +04:00
if ( ! ret )
2014-11-05 20:13:06 +03:00
__tty_ldisc_unlock ( tty2 ) ;
2013-06-15 15:04:47 +04:00
}
} else
2014-11-05 20:13:06 +03:00
ret = __tty_ldisc_lock ( tty , timeout ) ;
2013-06-15 15:04:47 +04:00
}
if ( ! ret )
return - EBUSY ;
set_bit ( TTY_LDISC_HALTED , & tty - > flags ) ;
if ( tty2 )
set_bit ( TTY_LDISC_HALTED , & tty2 - > flags ) ;
return 0 ;
}
2016-01-10 08:13:51 +03:00
static void tty_ldisc_lock_pair ( struct tty_struct * tty , struct tty_struct * tty2 )
2013-06-15 15:04:47 +04:00
{
tty_ldisc_lock_pair_timeout ( tty , tty2 , MAX_SCHEDULE_TIMEOUT ) ;
}
2016-01-10 08:13:51 +03:00
static void tty_ldisc_unlock_pair ( struct tty_struct * tty ,
struct tty_struct * tty2 )
2013-06-15 15:04:47 +04:00
{
2014-11-05 20:13:06 +03:00
__tty_ldisc_unlock ( tty ) ;
2013-06-15 15:04:47 +04:00
if ( tty2 )
2014-11-05 20:13:06 +03:00
__tty_ldisc_unlock ( tty2 ) ;
2013-06-15 15:04:47 +04:00
}
2009-06-11 15:50:58 +04:00
/**
2021-11-26 11:16:01 +03:00
* tty_ldisc_flush - flush line discipline queue
* @ tty : tty to flush ldisc for
2009-06-11 15:50:58 +04:00
*
2021-11-26 11:16:01 +03:00
* Flush the line discipline queue ( if any ) and the tty flip buffers for this
* @ tty .
2009-06-11 15:50:58 +04:00
*/
void tty_ldisc_flush ( struct tty_struct * tty )
{
struct tty_ldisc * ld = tty_ldisc_ref ( tty ) ;
2014-11-05 20:13:09 +03:00
tty_buffer_flush ( tty , ld ) ;
if ( ld )
2009-06-11 15:50:58 +04:00
tty_ldisc_deref ( ld ) ;
}
EXPORT_SYMBOL_GPL ( tty_ldisc_flush ) ;
2008-07-22 14:16:55 +04:00
/**
2021-11-26 11:16:01 +03:00
* tty_set_termios_ldisc - set ldisc field
* @ tty : tty structure
* @ disc : line discipline number
2008-07-22 14:16:55 +04:00
*
2021-11-26 11:16:01 +03:00
* This is probably overkill for real world processors but they are not on hot
* paths so a little discipline won ' t do any harm .
2008-07-22 14:16:55 +04:00
*
2021-11-26 11:16:01 +03:00
* The line discipline - related tty_struct fields are reset to prevent the ldisc
* driver from re - using stale information for the new ldisc instance .
2015-11-27 22:30:21 +03:00
*
2021-11-26 11:16:01 +03:00
* Locking : takes termios_rwsem
2008-07-22 14:16:55 +04:00
*/
2016-01-11 09:41:04 +03:00
static void tty_set_termios_ldisc ( struct tty_struct * tty , int disc )
2008-07-22 14:16:55 +04:00
{
2013-06-15 17:14:23 +04:00
down_write ( & tty - > termios_rwsem ) ;
2016-01-11 09:41:04 +03:00
tty - > termios . c_line = disc ;
2013-06-15 17:14:23 +04:00
up_write ( & tty - > termios_rwsem ) ;
2015-11-27 22:30:21 +03:00
tty - > disc_data = NULL ;
tty - > receive_room = 0 ;
2008-07-22 14:16:55 +04:00
}
2009-06-11 15:50:12 +04:00
/**
2021-11-26 11:16:01 +03:00
* tty_ldisc_open - open a line discipline
* @ tty : tty we are opening the ldisc on
* @ ld : discipline to open
2009-06-11 15:50:12 +04:00
*
2021-11-26 11:16:01 +03:00
* A helper opening method . Also a convenient debugging and check point .
2010-06-02 00:53:01 +04:00
*
2021-11-26 11:16:01 +03:00
* Locking : always called with BTM already held .
2009-06-11 15:50:12 +04:00
*/
static int tty_ldisc_open ( struct tty_struct * tty , struct tty_ldisc * ld )
{
WARN_ON ( test_and_set_bit ( TTY_LDISC_OPEN , & tty - > flags ) ) ;
2009-11-30 16:18:35 +03:00
if ( ld - > ops - > open ) {
int ret ;
2021-04-07 10:06:46 +03:00
/* BTM here locks versus a hangup event */
2009-11-30 16:18:35 +03:00
ret = ld - > ops - > open ( tty ) ;
2010-11-25 02:27:54 +03:00
if ( ret )
clear_bit ( TTY_LDISC_OPEN , & tty - > flags ) ;
2015-07-13 05:49:12 +03:00
2016-01-11 09:41:02 +03:00
tty_ldisc_debug ( tty , " %p: opened \n " , ld ) ;
2009-11-30 16:18:35 +03:00
return ret ;
}
2009-06-11 15:50:12 +04:00
return 0 ;
}
/**
2021-11-26 11:16:01 +03:00
* tty_ldisc_close - close a line discipline
* @ tty : tty we are opening the ldisc on
* @ ld : discipline to close
2009-06-11 15:50:12 +04:00
*
2021-11-26 11:16:01 +03:00
* A helper close method . Also a convenient debugging and check point .
2009-06-11 15:50:12 +04:00
*/
static void tty_ldisc_close ( struct tty_struct * tty , struct tty_ldisc * ld )
{
2019-05-31 13:06:51 +03:00
lockdep_assert_held_write ( & tty - > ldisc_sem ) ;
2009-06-11 15:50:12 +04:00
WARN_ON ( ! test_bit ( TTY_LDISC_OPEN , & tty - > flags ) ) ;
clear_bit ( TTY_LDISC_OPEN , & tty - > flags ) ;
if ( ld - > ops - > close )
ld - > ops - > close ( tty ) ;
2016-01-11 09:41:02 +03:00
tty_ldisc_debug ( tty , " %p: closed \n " , ld ) ;
2009-06-11 15:50:12 +04:00
}
2008-07-22 14:16:55 +04:00
2017-06-02 15:49:30 +03:00
/**
2021-11-26 11:16:01 +03:00
* tty_ldisc_failto - helper for ldisc failback
* @ tty : tty to open the ldisc on
* @ ld : ldisc we are trying to fail back to
2017-06-02 15:49:30 +03:00
*
2021-11-26 11:16:01 +03:00
* Helper to try and recover a tty when switching back to the old ldisc fails
* and we need something attached .
2017-06-02 15:49:30 +03:00
*/
static int tty_ldisc_failto ( struct tty_struct * tty , int ld )
{
struct tty_ldisc * disc = tty_ldisc_get ( tty , ld ) ;
int r ;
2019-05-31 13:06:51 +03:00
lockdep_assert_held_write ( & tty - > ldisc_sem ) ;
2017-06-02 15:49:30 +03:00
if ( IS_ERR ( disc ) )
return PTR_ERR ( disc ) ;
tty - > ldisc = disc ;
tty_set_termios_ldisc ( tty , ld ) ;
2021-04-07 10:06:49 +03:00
r = tty_ldisc_open ( tty , disc ) ;
if ( r < 0 )
2017-06-02 15:49:30 +03:00
tty_ldisc_put ( disc ) ;
return r ;
}
2017-04-14 11:57:52 +03:00
/**
2021-11-26 11:16:01 +03:00
* tty_ldisc_restore - helper for tty ldisc change
* @ tty : tty to recover
* @ old : previous ldisc
2017-04-14 11:57:52 +03:00
*
2021-11-26 11:16:01 +03:00
* Restore the previous line discipline or % N_TTY when a line discipline change
* fails due to an open error
2017-04-14 11:57:52 +03:00
*/
static void tty_ldisc_restore ( struct tty_struct * tty , struct tty_ldisc * old )
{
/* There is an outstanding reference here so this is safe */
2018-04-16 14:06:34 +03:00
if ( tty_ldisc_failto ( tty , old - > ops - > num ) < 0 ) {
const char * name = tty_name ( tty ) ;
pr_warn ( " Falling back ldisc for %s. \n " , name ) ;
2021-04-07 10:06:48 +03:00
/*
* The traditional behaviour is to fall back to N_TTY , we
* want to avoid falling back to N_NULL unless we have no
* choice to avoid the risk of breaking anything
*/
2017-06-02 15:49:30 +03:00
if ( tty_ldisc_failto ( tty , N_TTY ) < 0 & &
tty_ldisc_failto ( tty , N_NULL ) < 0 )
2018-04-16 14:06:34 +03:00
panic ( " Couldn't open N_NULL ldisc for %s. " , name ) ;
2017-04-14 11:57:52 +03:00
}
}
2008-07-22 14:16:55 +04:00
/**
2021-11-26 11:16:01 +03:00
* tty_set_ldisc - set line discipline
* @ tty : the terminal to set
* @ disc : the line discipline number
*
* Set the discipline of a tty line . Must be called from a process context . The
* ldisc change logic has to protect itself against any overlapping ldisc
* change ( including on the other end of pty pairs ) , the close of one side of a
* tty / pty pair , and eventually hangup .
2008-07-22 14:16:55 +04:00
*/
2016-01-11 09:41:04 +03:00
int tty_set_ldisc ( struct tty_struct * tty , int disc )
2008-07-22 14:16:55 +04:00
{
2017-04-14 11:57:52 +03:00
int retval ;
struct tty_ldisc * old_ldisc , * new_ldisc ;
new_ldisc = tty_ldisc_get ( tty , disc ) ;
if ( IS_ERR ( new_ldisc ) )
return PTR_ERR ( new_ldisc ) ;
2008-07-22 14:16:55 +04:00
2014-11-05 20:12:45 +03:00
tty_lock ( tty ) ;
2014-11-05 20:13:08 +03:00
retval = tty_ldisc_lock ( tty , 5 * HZ ) ;
2015-11-08 17:29:38 +03:00
if ( retval )
goto err ;
2008-07-22 14:16:55 +04:00
2016-01-11 09:41:02 +03:00
if ( ! tty - > ldisc ) {
retval = - EIO ;
goto out ;
}
2015-11-08 17:29:38 +03:00
/* Check the no-op case */
2017-04-14 11:57:52 +03:00
if ( tty - > ldisc - > ops - > num = = disc )
2015-11-08 17:29:38 +03:00
goto out ;
2009-06-11 15:50:12 +04:00
2015-11-08 17:29:38 +03:00
if ( test_bit ( TTY_HUPPED , & tty - > flags ) ) {
/* We were raced by hangup */
retval = - EIO ;
goto out ;
2008-07-22 14:16:55 +04:00
}
2017-04-14 11:57:52 +03:00
old_ldisc = tty - > ldisc ;
/* Shutdown the old discipline. */
tty_ldisc_close ( tty , old_ldisc ) ;
/* Now set up the new line discipline. */
tty - > ldisc = new_ldisc ;
tty_set_termios_ldisc ( tty , disc ) ;
retval = tty_ldisc_open ( tty , new_ldisc ) ;
2008-07-22 14:16:55 +04:00
if ( retval < 0 ) {
2009-06-11 15:50:12 +04:00
/* Back to the old one or N_TTY if we can't */
2017-04-14 11:57:52 +03:00
tty_ldisc_put ( new_ldisc ) ;
tty_ldisc_restore ( tty , old_ldisc ) ;
2008-07-22 14:16:55 +04:00
}
2009-06-11 15:50:12 +04:00
2017-04-14 11:57:52 +03:00
if ( tty - > ldisc - > ops - > num ! = old_ldisc - > ops - > num & & tty - > ops - > set_ldisc ) {
2014-11-05 21:11:41 +03:00
down_read ( & tty - > termios_rwsem ) ;
2008-07-22 14:16:55 +04:00
tty - > ops - > set_ldisc ( tty ) ;
2014-11-05 21:11:41 +03:00
up_read ( & tty - > termios_rwsem ) ;
}
2008-07-22 14:16:55 +04:00
2021-04-07 10:06:48 +03:00
/*
* At this point we hold a reference to the new ldisc and a
* reference to the old ldisc , or we hold two references to
* the old ldisc ( if it was restored as part of error cleanup
* above ) . In either case , releasing a single reference from
* the old ldisc is correct .
*/
2017-04-14 11:57:52 +03:00
new_ldisc = old_ldisc ;
2015-11-08 17:29:38 +03:00
out :
2014-11-05 20:13:08 +03:00
tty_ldisc_unlock ( tty ) ;
2008-07-22 14:16:55 +04:00
2021-04-07 10:06:48 +03:00
/*
* Restart the work queue in case no characters kick it off . Safe if
* already running
*/
2015-11-08 15:53:06 +03:00
tty_buffer_restart_work ( tty - > port ) ;
2015-11-08 17:29:38 +03:00
err :
2017-04-14 11:57:52 +03:00
tty_ldisc_put ( new_ldisc ) ; /* drop the extra reference */
2012-08-08 19:30:13 +04:00
tty_unlock ( tty ) ;
2008-07-22 14:16:55 +04:00
return retval ;
}
2017-05-15 20:45:33 +03:00
EXPORT_SYMBOL_GPL ( tty_set_ldisc ) ;
2008-07-22 14:16:55 +04:00
2016-01-11 09:41:03 +03:00
/**
2021-11-26 11:16:01 +03:00
* tty_ldisc_kill - teardown ldisc
* @ tty : tty being released
2016-01-11 09:41:03 +03:00
*
2021-11-26 11:16:01 +03:00
* Perform final close of the ldisc and reset @ tty - > ldisc
2016-01-11 09:41:03 +03:00
*/
static void tty_ldisc_kill ( struct tty_struct * tty )
{
2019-05-31 13:06:51 +03:00
lockdep_assert_held_write ( & tty - > ldisc_sem ) ;
2016-01-11 09:41:03 +03:00
if ( ! tty - > ldisc )
return ;
/*
* Now kill off the ldisc
*/
tty_ldisc_close ( tty , tty - > ldisc ) ;
tty_ldisc_put ( tty - > ldisc ) ;
/* Force an oops if we mess this up */
tty - > ldisc = NULL ;
}
2009-06-11 15:50:12 +04:00
/**
2021-11-26 11:16:01 +03:00
* tty_reset_termios - reset terminal state
* @ tty : tty to reset
2009-06-11 15:50:12 +04:00
*
2021-11-26 11:16:01 +03:00
* Restore a terminal to the driver default state .
2009-06-11 15:50:12 +04:00
*/
static void tty_reset_termios ( struct tty_struct * tty )
{
2013-06-15 17:14:23 +04:00
down_write ( & tty - > termios_rwsem ) ;
2012-07-14 18:31:47 +04:00
tty - > termios = tty - > driver - > init_termios ;
tty - > termios . c_ispeed = tty_termios_input_baud_rate ( & tty - > termios ) ;
tty - > termios . c_ospeed = tty_termios_baud_rate ( & tty - > termios ) ;
2013-06-15 17:14:23 +04:00
up_write ( & tty - > termios_rwsem ) ;
2009-06-11 15:50:12 +04:00
}
/**
2021-11-26 11:16:01 +03:00
* tty_ldisc_reinit - reinitialise the tty ldisc
* @ tty : tty to reinit
* @ disc : line discipline to reinitialize
2009-06-11 15:50:12 +04:00
*
2021-11-26 11:16:01 +03:00
* Completely reinitialize the line discipline state , by closing the current
* instance , if there is one , and opening a new instance . If an error occurs
* opening the new non - % N_TTY instance , the instance is dropped and @ tty - > ldisc
* reset to % NULL . The caller can then retry with % N_TTY instead .
2016-01-11 09:41:05 +03:00
*
2021-11-26 11:16:01 +03:00
* Returns : 0 if successful , otherwise error code < 0
2009-06-11 15:50:12 +04:00
*/
tty: Destroy ldisc instance on hangup
Currently, when the tty is hungup, the ldisc is re-instanced; ie., the
current instance is destroyed and a new instance is created. The purpose
of this design was to guarantee a valid, open ldisc for the lifetime of
the tty.
However, now that tty buffers are owned by and have lifetime equivalent
to the tty_port (since v3.10), any data received immediately after the
ldisc is re-instanced may cause continued driver i/o operations
concurrently with the driver's hangup() operation. For drivers that
shutdown h/w on hangup, this is unexpected and usually bad. For example,
the serial core may free the xmit buffer page concurrently with an
in-progress write() operation (triggered by echo).
With the existing stable and robust ldisc reference handling, the
cleaned-up tty_reopen(), the straggling unsafe ldisc use cleaned up, and
the preparation to properly handle a NULL tty->ldisc, the ldisc instance
can be destroyed and only re-instanced when the tty is re-opened.
If the tty was opened as /dev/console or /dev/tty0, the original behavior
of re-instancing the ldisc is retained (the 'reinit' parameter to
tty_ldisc_hangup() is true). This is required since those file descriptors
are never hungup.
This patch has neglible impact on userspace; the tty file_operations ptr
is changed to point to the hungup file operations _before_ the ldisc
instance is destroyed, so only racing file operations might now retrieve
a NULL ldisc reference (which is simply handled as if the hungup file
operation had been called instead -- see "tty: Prepare for destroying
line discipline on hangup").
This resolves a long-standing FIXME and several crash reports.
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2016-01-11 09:41:06 +03:00
int tty_ldisc_reinit ( struct tty_struct * tty , int disc )
2009-06-11 15:50:12 +04:00
{
2016-01-11 09:41:05 +03:00
struct tty_ldisc * ld ;
int retval ;
2010-10-27 19:13:21 +04:00
2019-05-31 13:06:51 +03:00
lockdep_assert_held_write ( & tty - > ldisc_sem ) ;
2016-01-11 09:41:05 +03:00
ld = tty_ldisc_get ( tty , disc ) ;
2017-04-14 11:57:52 +03:00
if ( IS_ERR ( ld ) ) {
BUG_ON ( disc = = N_TTY ) ;
2016-01-11 09:41:05 +03:00
return PTR_ERR ( ld ) ;
2017-04-14 11:57:52 +03:00
}
2009-06-11 15:50:12 +04:00
2016-01-11 09:41:05 +03:00
if ( tty - > ldisc ) {
tty_ldisc_close ( tty , tty - > ldisc ) ;
tty_ldisc_put ( tty - > ldisc ) ;
}
/* switch the line discipline */
2013-03-12 00:44:42 +04:00
tty - > ldisc = ld ;
2016-01-11 09:41:04 +03:00
tty_set_termios_ldisc ( tty , disc ) ;
2016-01-11 09:41:05 +03:00
retval = tty_ldisc_open ( tty , tty - > ldisc ) ;
if ( retval ) {
2017-10-14 01:58:08 +03:00
tty_ldisc_put ( tty - > ldisc ) ;
tty - > ldisc = NULL ;
2016-01-11 09:41:05 +03:00
}
return retval ;
2009-06-11 15:50:12 +04:00
}
/**
2021-11-26 11:16:01 +03:00
* tty_ldisc_hangup - hangup ldisc reset
* @ tty : tty being hung up
* @ reinit : whether to re - initialise the tty
2009-06-11 15:50:12 +04:00
*
2021-11-26 11:16:01 +03:00
* Some tty devices reset their termios when they receive a hangup event . In
* that situation we must also switch back to % N_TTY properly before we reset
* the termios data .
2009-06-11 15:50:12 +04:00
*
2021-11-26 11:16:01 +03:00
* Locking : We can take the ldisc mutex as the rest of the code is careful to
* allow for this .
2009-06-11 15:50:12 +04:00
*
2021-11-26 11:16:01 +03:00
* In the pty pair case this occurs in the close ( ) path of the tty itself so we
* must be careful about locking rules .
2009-06-11 15:50:12 +04:00
*/
tty: Destroy ldisc instance on hangup
Currently, when the tty is hungup, the ldisc is re-instanced; ie., the
current instance is destroyed and a new instance is created. The purpose
of this design was to guarantee a valid, open ldisc for the lifetime of
the tty.
However, now that tty buffers are owned by and have lifetime equivalent
to the tty_port (since v3.10), any data received immediately after the
ldisc is re-instanced may cause continued driver i/o operations
concurrently with the driver's hangup() operation. For drivers that
shutdown h/w on hangup, this is unexpected and usually bad. For example,
the serial core may free the xmit buffer page concurrently with an
in-progress write() operation (triggered by echo).
With the existing stable and robust ldisc reference handling, the
cleaned-up tty_reopen(), the straggling unsafe ldisc use cleaned up, and
the preparation to properly handle a NULL tty->ldisc, the ldisc instance
can be destroyed and only re-instanced when the tty is re-opened.
If the tty was opened as /dev/console or /dev/tty0, the original behavior
of re-instancing the ldisc is retained (the 'reinit' parameter to
tty_ldisc_hangup() is true). This is required since those file descriptors
are never hungup.
This patch has neglible impact on userspace; the tty file_operations ptr
is changed to point to the hungup file operations _before_ the ldisc
instance is destroyed, so only racing file operations might now retrieve
a NULL ldisc reference (which is simply handled as if the hungup file
operation had been called instead -- see "tty: Prepare for destroying
line discipline on hangup").
This resolves a long-standing FIXME and several crash reports.
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2016-01-11 09:41:06 +03:00
void tty_ldisc_hangup ( struct tty_struct * tty , bool reinit )
2009-06-11 15:50:12 +04:00
{
struct tty_ldisc * ld ;
2016-01-11 09:41:02 +03:00
tty_ldisc_debug ( tty , " %p: hangup \n " , tty - > ldisc ) ;
2013-03-12 00:44:38 +04:00
2009-06-11 15:50:12 +04:00
ld = tty_ldisc_ref ( tty ) ;
if ( ld ! = NULL ) {
if ( ld - > ops - > flush_buffer )
ld - > ops - > flush_buffer ( tty ) ;
tty_driver_flush_buffer ( tty ) ;
if ( ( test_bit ( TTY_DO_WRITE_WAKEUP , & tty - > flags ) ) & &
ld - > ops - > write_wakeup )
ld - > ops - > write_wakeup ( tty ) ;
if ( ld - > ops - > hangup )
ld - > ops - > hangup ( tty ) ;
tty_ldisc_deref ( ld ) ;
}
2013-06-15 15:04:48 +04:00
2018-02-12 01:34:03 +03:00
wake_up_interruptible_poll ( & tty - > write_wait , EPOLLOUT ) ;
wake_up_interruptible_poll ( & tty - > read_wait , EPOLLIN ) ;
2013-06-15 15:04:48 +04:00
2009-06-11 15:50:12 +04:00
/*
* Shutdown the current line discipline , and reset it to
2010-02-08 13:09:26 +03:00
* N_TTY if need be .
*
* Avoid racing set_ldisc or tty_ldisc_release
2009-06-11 15:50:12 +04:00
*/
2014-11-05 20:13:07 +03:00
tty_ldisc_lock ( tty , MAX_SCHEDULE_TIMEOUT ) ;
2010-06-02 00:53:06 +04:00
tty: Destroy ldisc instance on hangup
Currently, when the tty is hungup, the ldisc is re-instanced; ie., the
current instance is destroyed and a new instance is created. The purpose
of this design was to guarantee a valid, open ldisc for the lifetime of
the tty.
However, now that tty buffers are owned by and have lifetime equivalent
to the tty_port (since v3.10), any data received immediately after the
ldisc is re-instanced may cause continued driver i/o operations
concurrently with the driver's hangup() operation. For drivers that
shutdown h/w on hangup, this is unexpected and usually bad. For example,
the serial core may free the xmit buffer page concurrently with an
in-progress write() operation (triggered by echo).
With the existing stable and robust ldisc reference handling, the
cleaned-up tty_reopen(), the straggling unsafe ldisc use cleaned up, and
the preparation to properly handle a NULL tty->ldisc, the ldisc instance
can be destroyed and only re-instanced when the tty is re-opened.
If the tty was opened as /dev/console or /dev/tty0, the original behavior
of re-instancing the ldisc is retained (the 'reinit' parameter to
tty_ldisc_hangup() is true). This is required since those file descriptors
are never hungup.
This patch has neglible impact on userspace; the tty file_operations ptr
is changed to point to the hungup file operations _before_ the ldisc
instance is destroyed, so only racing file operations might now retrieve
a NULL ldisc reference (which is simply handled as if the hungup file
operation had been called instead -- see "tty: Prepare for destroying
line discipline on hangup").
This resolves a long-standing FIXME and several crash reports.
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2016-01-11 09:41:06 +03:00
if ( tty - > driver - > flags & TTY_DRIVER_RESET_TERMIOS )
tty_reset_termios ( tty ) ;
2013-03-12 00:44:36 +04:00
tty: Destroy ldisc instance on hangup
Currently, when the tty is hungup, the ldisc is re-instanced; ie., the
current instance is destroyed and a new instance is created. The purpose
of this design was to guarantee a valid, open ldisc for the lifetime of
the tty.
However, now that tty buffers are owned by and have lifetime equivalent
to the tty_port (since v3.10), any data received immediately after the
ldisc is re-instanced may cause continued driver i/o operations
concurrently with the driver's hangup() operation. For drivers that
shutdown h/w on hangup, this is unexpected and usually bad. For example,
the serial core may free the xmit buffer page concurrently with an
in-progress write() operation (triggered by echo).
With the existing stable and robust ldisc reference handling, the
cleaned-up tty_reopen(), the straggling unsafe ldisc use cleaned up, and
the preparation to properly handle a NULL tty->ldisc, the ldisc instance
can be destroyed and only re-instanced when the tty is re-opened.
If the tty was opened as /dev/console or /dev/tty0, the original behavior
of re-instancing the ldisc is retained (the 'reinit' parameter to
tty_ldisc_hangup() is true). This is required since those file descriptors
are never hungup.
This patch has neglible impact on userspace; the tty file_operations ptr
is changed to point to the hungup file operations _before_ the ldisc
instance is destroyed, so only racing file operations might now retrieve
a NULL ldisc reference (which is simply handled as if the hungup file
operation had been called instead -- see "tty: Prepare for destroying
line discipline on hangup").
This resolves a long-standing FIXME and several crash reports.
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2016-01-11 09:41:06 +03:00
if ( tty - > ldisc ) {
if ( reinit ) {
2017-10-14 01:58:08 +03:00
if ( tty_ldisc_reinit ( tty , tty - > termios . c_line ) < 0 & &
tty_ldisc_reinit ( tty , N_TTY ) < 0 )
WARN_ON ( tty_ldisc_reinit ( tty , N_NULL ) < 0 ) ;
tty: Destroy ldisc instance on hangup
Currently, when the tty is hungup, the ldisc is re-instanced; ie., the
current instance is destroyed and a new instance is created. The purpose
of this design was to guarantee a valid, open ldisc for the lifetime of
the tty.
However, now that tty buffers are owned by and have lifetime equivalent
to the tty_port (since v3.10), any data received immediately after the
ldisc is re-instanced may cause continued driver i/o operations
concurrently with the driver's hangup() operation. For drivers that
shutdown h/w on hangup, this is unexpected and usually bad. For example,
the serial core may free the xmit buffer page concurrently with an
in-progress write() operation (triggered by echo).
With the existing stable and robust ldisc reference handling, the
cleaned-up tty_reopen(), the straggling unsafe ldisc use cleaned up, and
the preparation to properly handle a NULL tty->ldisc, the ldisc instance
can be destroyed and only re-instanced when the tty is re-opened.
If the tty was opened as /dev/console or /dev/tty0, the original behavior
of re-instancing the ldisc is retained (the 'reinit' parameter to
tty_ldisc_hangup() is true). This is required since those file descriptors
are never hungup.
This patch has neglible impact on userspace; the tty file_operations ptr
is changed to point to the hungup file operations _before_ the ldisc
instance is destroyed, so only racing file operations might now retrieve
a NULL ldisc reference (which is simply handled as if the hungup file
operation had been called instead -- see "tty: Prepare for destroying
line discipline on hangup").
This resolves a long-standing FIXME and several crash reports.
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2016-01-11 09:41:06 +03:00
} else
tty_ldisc_kill ( tty ) ;
2009-06-11 15:50:12 +04:00
}
2014-11-05 20:13:07 +03:00
tty_ldisc_unlock ( tty ) ;
2009-06-11 15:50:12 +04:00
}
2008-07-22 14:16:55 +04:00
/**
2021-11-26 11:16:01 +03:00
* tty_ldisc_setup - open line discipline
* @ tty : tty being shut down
* @ o_tty : pair tty for pty / tty pairs
2008-07-22 14:16:55 +04:00
*
2021-11-26 11:16:01 +03:00
* Called during the initial open of a tty / pty pair in order to set up the line
* disciplines and bind them to the @ tty . This has no locking issues as the
* device isn ' t yet active .
2008-07-22 14:16:55 +04:00
*/
int tty_ldisc_setup ( struct tty_struct * tty , struct tty_struct * o_tty )
{
2016-01-11 09:41:08 +03:00
int retval = tty_ldisc_open ( tty , tty - > ldisc ) ;
2021-04-07 10:06:47 +03:00
2009-06-11 15:50:12 +04:00
if ( retval )
return retval ;
if ( o_tty ) {
2018-11-01 03:24:51 +03:00
/*
* Called without o_tty - > ldisc_sem held , as o_tty has been
* just allocated and no one has a reference to it .
*/
2009-06-11 15:50:12 +04:00
retval = tty_ldisc_open ( o_tty , o_tty - > ldisc ) ;
2008-07-22 14:16:55 +04:00
if ( retval ) {
2016-01-11 09:41:08 +03:00
tty_ldisc_close ( tty , tty - > ldisc ) ;
2008-07-22 14:16:55 +04:00
return retval ;
}
}
return 0 ;
}
2012-08-08 19:30:13 +04:00
2008-07-22 14:16:55 +04:00
/**
2021-11-26 11:16:01 +03:00
* tty_ldisc_release - release line discipline
* @ tty : tty being shut down ( or one end of pty pair )
2014-11-05 20:12:44 +03:00
*
2021-11-26 11:16:01 +03:00
* Called during the final close of a tty or a pty pair in order to shut down
* the line discpline layer . On exit , each tty ' s ldisc is % NULL .
2008-07-22 14:16:55 +04:00
*/
2014-11-05 20:12:58 +03:00
void tty_ldisc_release ( struct tty_struct * tty )
2008-07-22 14:16:55 +04:00
{
2014-11-05 20:12:58 +03:00
struct tty_struct * o_tty = tty - > link ;
2008-07-22 14:16:55 +04:00
/*
2013-03-12 00:44:35 +04:00
* Shutdown this line discipline . As this is the final close ,
* it does not race with the set_ldisc code path .
2008-07-22 14:16:55 +04:00
*/
2013-06-15 15:04:48 +04:00
tty_ldisc_lock_pair ( tty , o_tty ) ;
2012-08-08 19:30:13 +04:00
tty_ldisc_kill ( tty ) ;
2009-06-11 15:50:12 +04:00
if ( o_tty )
2012-08-08 19:30:13 +04:00
tty_ldisc_kill ( o_tty ) ;
2013-06-15 15:04:48 +04:00
tty_ldisc_unlock_pair ( tty , o_tty ) ;
2021-04-07 10:06:48 +03:00
/*
* And the memory resources remaining ( buffers , termios ) will be
* disposed of when the kref hits zero
*/
2013-03-12 00:44:38 +04:00
2015-07-13 05:49:12 +03:00
tty_ldisc_debug ( tty , " released \n " ) ;
2008-07-22 14:16:55 +04:00
}
/**
2021-11-26 11:16:01 +03:00
* tty_ldisc_init - ldisc setup for new tty
* @ tty : tty being allocated
2008-07-22 14:16:55 +04:00
*
2021-11-26 11:16:01 +03:00
* Set up the line discipline objects for a newly allocated tty . Note that the
* tty structure is not completely set up when this call is made .
2008-07-22 14:16:55 +04:00
*/
2018-04-05 13:40:16 +03:00
int tty_ldisc_init ( struct tty_struct * tty )
2008-07-22 14:16:55 +04:00
{
2013-06-15 15:04:48 +04:00
struct tty_ldisc * ld = tty_ldisc_get ( tty , N_TTY ) ;
2021-04-07 10:06:47 +03:00
2009-06-11 15:50:12 +04:00
if ( IS_ERR ( ld ) )
2018-04-05 13:40:16 +03:00
return PTR_ERR ( ld ) ;
2013-03-12 00:44:42 +04:00
tty - > ldisc = ld ;
2018-04-05 13:40:16 +03:00
return 0 ;
2008-07-22 14:16:55 +04:00
}
2011-03-23 12:48:35 +03:00
/**
2021-11-26 11:16:01 +03:00
* tty_ldisc_deinit - ldisc cleanup for new tty
* @ tty : tty that was allocated recently
2011-03-23 12:48:35 +03:00
*
2021-11-26 11:16:01 +03:00
* The tty structure must not be completely set up ( tty_ldisc_setup ( ) ) when
* this call is made .
2011-03-23 12:48:35 +03:00
*/
void tty_ldisc_deinit ( struct tty_struct * tty )
{
2018-11-01 03:24:51 +03:00
/* no ldisc_sem, tty is being destroyed */
2016-01-10 08:13:46 +03:00
if ( tty - > ldisc )
tty_ldisc_put ( tty - > ldisc ) ;
2013-03-12 00:44:42 +04:00
tty - > ldisc = NULL ;
2011-03-23 12:48:35 +03:00
}