2005-04-17 05:20:36 +07:00
|
|
|
/*
|
|
|
|
* Copyright (C) 1991, 1992 Linus Torvalds
|
|
|
|
*
|
|
|
|
* Added support for a Unix98-style ptmx device.
|
|
|
|
* -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2008-10-13 16:43:38 +07:00
|
|
|
#include <linux/module.h>
|
2005-04-17 05:20:36 +07:00
|
|
|
#include <linux/errno.h>
|
|
|
|
#include <linux/interrupt.h>
|
|
|
|
#include <linux/tty.h>
|
|
|
|
#include <linux/tty_flip.h>
|
|
|
|
#include <linux/fcntl.h>
|
2017-02-09 00:51:30 +07:00
|
|
|
#include <linux/sched/signal.h>
|
2005-04-17 05:20:36 +07:00
|
|
|
#include <linux/string.h>
|
|
|
|
#include <linux/major.h>
|
|
|
|
#include <linux/mm.h>
|
|
|
|
#include <linux/init.h>
|
2008-10-13 16:41:42 +07:00
|
|
|
#include <linux/device.h>
|
2008-10-13 16:43:38 +07:00
|
|
|
#include <linux/uaccess.h>
|
2005-04-17 05:20:36 +07:00
|
|
|
#include <linux/bitops.h>
|
|
|
|
#include <linux/devpts_fs.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 15:04:11 +07:00
|
|
|
#include <linux/slab.h>
|
2012-05-04 04:22:09 +07:00
|
|
|
#include <linux/mutex.h>
|
2014-09-11 02:06:32 +07:00
|
|
|
#include <linux/poll.h>
|
2017-06-03 21:15:15 +07:00
|
|
|
#include <linux/mount.h>
|
|
|
|
#include <linux/file.h>
|
|
|
|
#include <linux/ioctl.h>
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2015-07-13 09:49:13 +07:00
|
|
|
#undef TTY_DEBUG_HANGUP
|
|
|
|
#ifdef TTY_DEBUG_HANGUP
|
|
|
|
# define tty_debug_hangup(tty, f, args...) tty_debug(tty, f, ##args)
|
|
|
|
#else
|
|
|
|
# define tty_debug_hangup(tty, f, args...) do {} while (0)
|
|
|
|
#endif
|
2008-10-13 16:43:38 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
#ifdef CONFIG_UNIX98_PTYS
|
2009-01-08 09:09:15 +07:00
|
|
|
static struct tty_driver *ptm_driver;
|
2005-04-17 05:20:36 +07:00
|
|
|
static struct tty_driver *pts_driver;
|
2012-05-04 04:22:09 +07:00
|
|
|
static DEFINE_MUTEX(devpts_mutex);
|
2005-04-17 05:20:36 +07:00
|
|
|
#endif
|
|
|
|
|
2008-10-13 16:43:38 +07:00
|
|
|
static void pty_close(struct tty_struct *tty, struct file *filp)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2008-10-13 16:43:38 +07:00
|
|
|
BUG_ON(!tty);
|
|
|
|
if (tty->driver->subtype == PTY_TYPE_MASTER)
|
|
|
|
WARN_ON(tty->count > 1);
|
|
|
|
else {
|
2016-04-10 07:06:48 +07:00
|
|
|
if (tty_io_error(tty))
|
2013-01-31 00:43:50 +07:00
|
|
|
return;
|
2005-04-17 05:20:36 +07:00
|
|
|
if (tty->count > 2)
|
|
|
|
return;
|
|
|
|
}
|
2013-01-31 00:43:50 +07:00
|
|
|
set_bit(TTY_IO_ERROR, &tty->flags);
|
2005-04-17 05:20:36 +07:00
|
|
|
wake_up_interruptible(&tty->read_wait);
|
|
|
|
wake_up_interruptible(&tty->write_wait);
|
2014-10-17 02:33:28 +07:00
|
|
|
spin_lock_irq(&tty->ctrl_lock);
|
2005-04-17 05:20:36 +07:00
|
|
|
tty->packet = 0;
|
2014-10-17 02:33:28 +07:00
|
|
|
spin_unlock_irq(&tty->ctrl_lock);
|
2012-08-08 22:30:13 +07:00
|
|
|
/* Review - krefs on tty_link ?? */
|
2005-04-17 05:20:36 +07:00
|
|
|
if (!tty->link)
|
|
|
|
return;
|
|
|
|
set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
|
2016-03-07 04:16:30 +07:00
|
|
|
wake_up_interruptible(&tty->link->read_wait);
|
2005-04-17 05:20:36 +07:00
|
|
|
wake_up_interruptible(&tty->link->write_wait);
|
|
|
|
if (tty->driver->subtype == PTY_TYPE_MASTER) {
|
|
|
|
set_bit(TTY_OTHER_CLOSED, &tty->flags);
|
2012-02-25 04:56:36 +07:00
|
|
|
#ifdef CONFIG_UNIX98_PTYS
|
2012-05-04 04:22:09 +07:00
|
|
|
if (tty->driver == ptm_driver) {
|
2013-01-12 11:01:22 +07:00
|
|
|
mutex_lock(&devpts_mutex);
|
2017-06-03 21:15:15 +07:00
|
|
|
if (tty->link->driver_data) {
|
|
|
|
struct path *path = tty->link->driver_data;
|
|
|
|
|
|
|
|
devpts_pty_kill(path->dentry);
|
|
|
|
path_put(path);
|
|
|
|
kfree(path);
|
|
|
|
}
|
2013-01-12 11:01:22 +07:00
|
|
|
mutex_unlock(&devpts_mutex);
|
2012-05-04 04:22:09 +07:00
|
|
|
}
|
2012-02-25 04:56:36 +07:00
|
|
|
#endif
|
2010-06-18 19:58:07 +07:00
|
|
|
tty_vhangup(tty->link);
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The unthrottle routine is called by the line discipline to signal
|
|
|
|
* that it can receive more characters. For PTY's, the TTY_THROTTLED
|
|
|
|
* flag is always set, to force the line discipline to always call the
|
2008-10-13 16:43:38 +07:00
|
|
|
* unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE
|
2005-04-17 05:20:36 +07:00
|
|
|
* characters in the queue. This is necessary since each time this
|
|
|
|
* happens, we need to wake up any sleeping processes that could be
|
|
|
|
* (1) trying to send data to the pty, or (2) waiting in wait_until_sent()
|
|
|
|
* for the pty buffer to be drained.
|
|
|
|
*/
|
2008-10-13 16:43:38 +07:00
|
|
|
static void pty_unthrottle(struct tty_struct *tty)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2009-07-07 22:39:41 +07:00
|
|
|
tty_wakeup(tty->link);
|
2005-04-17 05:20:36 +07:00
|
|
|
set_bit(TTY_THROTTLED, &tty->flags);
|
|
|
|
}
|
|
|
|
|
2009-07-07 22:39:41 +07:00
|
|
|
/**
|
|
|
|
* pty_write - write to a pty
|
|
|
|
* @tty: the tty we write from
|
|
|
|
* @buf: kernel buffer of data
|
|
|
|
* @count: bytes to write
|
2009-06-16 23:01:13 +07:00
|
|
|
*
|
2009-07-07 22:39:41 +07:00
|
|
|
* Our "hardware" write method. Data is coming from the ldisc which
|
|
|
|
* may be in a non sleeping state. We simply throw this at the other
|
|
|
|
* end of the link as if we were an IRQ handler receiving stuff for
|
|
|
|
* the other side of the pty/tty pair.
|
2005-04-17 05:20:36 +07:00
|
|
|
*/
|
2009-07-07 22:39:41 +07:00
|
|
|
|
2009-09-06 03:27:10 +07:00
|
|
|
static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
struct tty_struct *to = tty->link;
|
|
|
|
|
2009-07-07 22:39:41 +07:00
|
|
|
if (tty->stopped)
|
2005-04-17 05:20:36 +07:00
|
|
|
return 0;
|
2009-07-07 22:39:41 +07:00
|
|
|
|
|
|
|
if (c > 0) {
|
|
|
|
/* Stuff the data into the input queue of the other end */
|
2013-01-03 21:53:04 +07:00
|
|
|
c = tty_insert_flip_string(to->port, buf, c);
|
2009-07-07 22:39:41 +07:00
|
|
|
/* And shovel */
|
2013-07-24 19:29:57 +07:00
|
|
|
if (c)
|
2013-01-03 21:53:06 +07:00
|
|
|
tty_flip_buffer_push(to->port);
|
2009-06-16 23:01:13 +07:00
|
|
|
}
|
2005-04-17 05:20:36 +07:00
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
2009-07-07 22:39:41 +07:00
|
|
|
/**
|
|
|
|
* pty_write_room - write space
|
|
|
|
* @tty: tty we are writing from
|
|
|
|
*
|
|
|
|
* Report how many bytes the ldisc can send into the queue for
|
|
|
|
* the other device.
|
|
|
|
*/
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
static int pty_write_room(struct tty_struct *tty)
|
|
|
|
{
|
2009-08-11 03:21:19 +07:00
|
|
|
if (tty->stopped)
|
|
|
|
return 0;
|
2015-01-17 03:22:14 +07:00
|
|
|
return tty_buffer_space_avail(tty->link->port);
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
2009-07-07 22:39:41 +07:00
|
|
|
/**
|
|
|
|
* pty_chars_in_buffer - characters currently in our tx queue
|
|
|
|
* @tty: our tty
|
2008-10-13 16:43:38 +07:00
|
|
|
*
|
2009-07-07 22:39:41 +07:00
|
|
|
* Report how much we have in the transmit queue. As everything is
|
|
|
|
* instantly at the other end this is easy to implement.
|
2005-04-17 05:20:36 +07:00
|
|
|
*/
|
2009-07-07 22:39:41 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
static int pty_chars_in_buffer(struct tty_struct *tty)
|
|
|
|
{
|
2009-07-07 22:39:41 +07:00
|
|
|
return 0;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the lock flag on a pty */
|
2008-10-13 16:43:38 +07:00
|
|
|
static int pty_set_lock(struct tty_struct *tty, int __user *arg)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
int val;
|
2008-10-13 16:43:38 +07:00
|
|
|
if (get_user(val, arg))
|
2005-04-17 05:20:36 +07:00
|
|
|
return -EFAULT;
|
|
|
|
if (val)
|
|
|
|
set_bit(TTY_PTY_LOCK, &tty->flags);
|
|
|
|
else
|
|
|
|
clear_bit(TTY_PTY_LOCK, &tty->flags);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-10-25 02:43:22 +07:00
|
|
|
static int pty_get_lock(struct tty_struct *tty, int __user *arg)
|
|
|
|
{
|
|
|
|
int locked = test_bit(TTY_PTY_LOCK, &tty->flags);
|
|
|
|
return put_user(locked, arg);
|
|
|
|
}
|
|
|
|
|
2012-10-25 02:43:20 +07:00
|
|
|
/* Set the packet mode on a pty */
|
|
|
|
static int pty_set_pktmode(struct tty_struct *tty, int __user *arg)
|
|
|
|
{
|
|
|
|
int pktmode;
|
|
|
|
|
|
|
|
if (get_user(pktmode, arg))
|
|
|
|
return -EFAULT;
|
|
|
|
|
2014-10-17 02:33:25 +07:00
|
|
|
spin_lock_irq(&tty->ctrl_lock);
|
2012-10-25 02:43:20 +07:00
|
|
|
if (pktmode) {
|
|
|
|
if (!tty->packet) {
|
|
|
|
tty->link->ctrl_status = 0;
|
2014-10-17 02:33:27 +07:00
|
|
|
smp_mb();
|
|
|
|
tty->packet = 1;
|
2012-10-25 02:43:20 +07:00
|
|
|
}
|
|
|
|
} else
|
|
|
|
tty->packet = 0;
|
2014-10-17 02:33:25 +07:00
|
|
|
spin_unlock_irq(&tty->ctrl_lock);
|
2012-10-25 02:43:20 +07:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-10-25 02:43:22 +07:00
|
|
|
/* Get the packet mode of a pty */
|
|
|
|
static int pty_get_pktmode(struct tty_struct *tty, int __user *arg)
|
|
|
|
{
|
|
|
|
int pktmode = tty->packet;
|
|
|
|
return put_user(pktmode, arg);
|
|
|
|
}
|
|
|
|
|
tty: Add EXTPROC support for LINEMODE
This patch is against the 2.6.34 source.
Paraphrased from the 1989 BSD patch by David Borman @ cray.com:
These are the changes needed for the kernel to support
LINEMODE in the server.
There is a new bit in the termios local flag word, EXTPROC.
When this bit is set, several aspects of the terminal driver
are disabled. Input line editing, character echo, and mapping
of signals are all disabled. This allows the telnetd to turn
off these functions when in linemode, but still keep track of
what state the user wants the terminal to be in.
New ioctl:
TIOCSIG Generate a signal to processes in the
current process group of the pty.
There is a new mode for packet driver, the TIOCPKT_IOCTL bit.
When packet mode is turned on in the pty, and the EXTPROC bit
is set, then whenever the state of the pty is changed, the
next read on the master side of the pty will have the TIOCPKT_IOCTL
bit set. This allows the process on the server side of the pty
to know when the state of the terminal has changed; it can then
issue the appropriate ioctl to retrieve the new state.
Since the original BSD patches accompanied the source code for telnet
I've left that reference here, but obviously the feature is useful for
any remote terminal protocol, including ssh.
The corresponding feature has existed in the BSD tty driver since 1989.
For historical reference, a good copy of the relevant files can be found
here:
http://anonsvn.mit.edu/viewvc/krb5/trunk/src/appl/telnet/?pathrev=17741
Signed-off-by: Howard Chu <hyc@symas.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-06-23 00:14:49 +07:00
|
|
|
/* Send a signal to the slave */
|
|
|
|
static int pty_signal(struct tty_struct *tty, int sig)
|
|
|
|
{
|
|
|
|
struct pid *pgrp;
|
|
|
|
|
2015-01-20 01:05:03 +07:00
|
|
|
if (sig != SIGINT && sig != SIGQUIT && sig != SIGTSTP)
|
|
|
|
return -EINVAL;
|
|
|
|
|
tty: Add EXTPROC support for LINEMODE
This patch is against the 2.6.34 source.
Paraphrased from the 1989 BSD patch by David Borman @ cray.com:
These are the changes needed for the kernel to support
LINEMODE in the server.
There is a new bit in the termios local flag word, EXTPROC.
When this bit is set, several aspects of the terminal driver
are disabled. Input line editing, character echo, and mapping
of signals are all disabled. This allows the telnetd to turn
off these functions when in linemode, but still keep track of
what state the user wants the terminal to be in.
New ioctl:
TIOCSIG Generate a signal to processes in the
current process group of the pty.
There is a new mode for packet driver, the TIOCPKT_IOCTL bit.
When packet mode is turned on in the pty, and the EXTPROC bit
is set, then whenever the state of the pty is changed, the
next read on the master side of the pty will have the TIOCPKT_IOCTL
bit set. This allows the process on the server side of the pty
to know when the state of the terminal has changed; it can then
issue the appropriate ioctl to retrieve the new state.
Since the original BSD patches accompanied the source code for telnet
I've left that reference here, but obviously the feature is useful for
any remote terminal protocol, including ssh.
The corresponding feature has existed in the BSD tty driver since 1989.
For historical reference, a good copy of the relevant files can be found
here:
http://anonsvn.mit.edu/viewvc/krb5/trunk/src/appl/telnet/?pathrev=17741
Signed-off-by: Howard Chu <hyc@symas.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-06-23 00:14:49 +07:00
|
|
|
if (tty->link) {
|
2014-10-17 01:59:45 +07:00
|
|
|
pgrp = tty_get_pgrp(tty->link);
|
|
|
|
if (pgrp)
|
|
|
|
kill_pgrp(pgrp, sig, 1);
|
tty: Add EXTPROC support for LINEMODE
This patch is against the 2.6.34 source.
Paraphrased from the 1989 BSD patch by David Borman @ cray.com:
These are the changes needed for the kernel to support
LINEMODE in the server.
There is a new bit in the termios local flag word, EXTPROC.
When this bit is set, several aspects of the terminal driver
are disabled. Input line editing, character echo, and mapping
of signals are all disabled. This allows the telnetd to turn
off these functions when in linemode, but still keep track of
what state the user wants the terminal to be in.
New ioctl:
TIOCSIG Generate a signal to processes in the
current process group of the pty.
There is a new mode for packet driver, the TIOCPKT_IOCTL bit.
When packet mode is turned on in the pty, and the EXTPROC bit
is set, then whenever the state of the pty is changed, the
next read on the master side of the pty will have the TIOCPKT_IOCTL
bit set. This allows the process on the server side of the pty
to know when the state of the terminal has changed; it can then
issue the appropriate ioctl to retrieve the new state.
Since the original BSD patches accompanied the source code for telnet
I've left that reference here, but obviously the feature is useful for
any remote terminal protocol, including ssh.
The corresponding feature has existed in the BSD tty driver since 1989.
For historical reference, a good copy of the relevant files can be found
here:
http://anonsvn.mit.edu/viewvc/krb5/trunk/src/appl/telnet/?pathrev=17741
Signed-off-by: Howard Chu <hyc@symas.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-06-23 00:14:49 +07:00
|
|
|
put_pid(pgrp);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
static void pty_flush_buffer(struct tty_struct *tty)
|
|
|
|
{
|
|
|
|
struct tty_struct *to = tty->link;
|
2008-10-13 16:43:38 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
if (!to)
|
|
|
|
return;
|
2015-01-18 03:42:05 +07:00
|
|
|
|
tty: pty: Fix ldisc flush after userspace become aware of the data already
While using emacs, cat or others' commands in konsole with recent
kernels, I have met many times that CTRL-C freeze konsole. After
konsole freeze I can't type anything, then I have to open a new one,
it is very annoying.
See bug report:
https://bugs.kde.org/show_bug.cgi?id=175283
The platform in that bug report is Solaris, but now the pty in linux
has the same problem or the same behavior as Solaris :)
It has high possibility to trigger the problem follow steps below:
Note: In my test, BigFile is a text file whose size is bigger than 1G
1:open konsole
1:cat BigFile
2:CTRL-C
After some digging, I find out the reason is that commit 1d1d14da12e7
("pty: Fix buffer flush deadlock") changes the behavior of pty_flush_buffer.
Thread A Thread B
-------- --------
1:n_tty_poll return POLLIN
2:CTRL-C trigger pty_flush_buffer
tty_buffer_flush
n_tty_flush_buffer
3:attempt to check count of chars:
ioctl(fd, TIOCINQ, &available)
available is equal to 0
4:read(fd, buffer, avaiable)
return 0
5:konsole close fd
Yes, I know we could use the same patch included in the BUG report as
a workaround for linux platform too. But I think the data in ldisc is
belong to application of another side, we shouldn't clear it when we
want to flush write buffer of this side in pty_flush_buffer. So I think
it is better to disable ldisc flush in pty_flush_buffer, because its new
hehavior bring no benefit except that it mess up the behavior between
POLLIN, and TIOCINQ or FIONREAD.
Also I find no flush_buffer function in others' tty driver has the
same behavior as current pty_flush_buffer.
Fixes: 1d1d14da12e7 ("pty: Fix buffer flush deadlock")
CC: stable@vger.kernel.org # v4.0+
Signed-off-by: Wang YanQing <udknight@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2017-02-22 18:37:08 +07:00
|
|
|
tty_buffer_flush(to, NULL);
|
2005-04-17 05:20:36 +07:00
|
|
|
if (to->packet) {
|
2014-10-17 02:33:25 +07:00
|
|
|
spin_lock_irq(&tty->ctrl_lock);
|
2005-04-17 05:20:36 +07:00
|
|
|
tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
|
|
|
|
wake_up_interruptible(&to->read_wait);
|
2014-10-17 02:33:25 +07:00
|
|
|
spin_unlock_irq(&tty->ctrl_lock);
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-13 16:43:38 +07:00
|
|
|
static int pty_open(struct tty_struct *tty, struct file *filp)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
if (!tty || !tty->link)
|
2013-06-14 02:56:37 +07:00
|
|
|
return -ENODEV;
|
2013-01-31 00:43:50 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
|
|
|
|
goto out;
|
|
|
|
if (test_bit(TTY_PTY_LOCK, &tty->link->flags))
|
|
|
|
goto out;
|
2013-01-31 00:43:52 +07:00
|
|
|
if (tty->driver->subtype == PTY_TYPE_SLAVE && tty->link->count != 1)
|
2005-04-17 05:20:36 +07:00
|
|
|
goto out;
|
|
|
|
|
2013-01-31 00:43:50 +07:00
|
|
|
clear_bit(TTY_IO_ERROR, &tty->flags);
|
2005-04-17 05:20:36 +07:00
|
|
|
clear_bit(TTY_OTHER_CLOSED, &tty->link->flags);
|
|
|
|
set_bit(TTY_THROTTLED, &tty->flags);
|
2013-06-14 02:56:37 +07:00
|
|
|
return 0;
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
out:
|
2013-06-14 02:56:37 +07:00
|
|
|
set_bit(TTY_IO_ERROR, &tty->flags);
|
|
|
|
return -EIO;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
2008-10-13 16:43:38 +07:00
|
|
|
static void pty_set_termios(struct tty_struct *tty,
|
|
|
|
struct ktermios *old_termios)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2014-10-17 02:33:23 +07:00
|
|
|
/* See if packet mode change of state. */
|
|
|
|
if (tty->link && tty->link->packet) {
|
2016-01-11 11:36:15 +07:00
|
|
|
int extproc = (old_termios->c_lflag & EXTPROC) | L_EXTPROC(tty);
|
2014-10-17 02:33:23 +07:00
|
|
|
int old_flow = ((old_termios->c_iflag & IXON) &&
|
|
|
|
(old_termios->c_cc[VSTOP] == '\023') &&
|
|
|
|
(old_termios->c_cc[VSTART] == '\021'));
|
|
|
|
int new_flow = (I_IXON(tty) &&
|
|
|
|
STOP_CHAR(tty) == '\023' &&
|
|
|
|
START_CHAR(tty) == '\021');
|
|
|
|
if ((old_flow != new_flow) || extproc) {
|
2014-10-17 02:33:24 +07:00
|
|
|
spin_lock_irq(&tty->ctrl_lock);
|
2014-10-17 02:33:23 +07:00
|
|
|
if (old_flow != new_flow) {
|
|
|
|
tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
|
|
|
|
if (new_flow)
|
|
|
|
tty->ctrl_status |= TIOCPKT_DOSTOP;
|
|
|
|
else
|
|
|
|
tty->ctrl_status |= TIOCPKT_NOSTOP;
|
|
|
|
}
|
|
|
|
if (extproc)
|
|
|
|
tty->ctrl_status |= TIOCPKT_IOCTL;
|
2014-10-17 02:33:24 +07:00
|
|
|
spin_unlock_irq(&tty->ctrl_lock);
|
2014-10-17 02:33:23 +07:00
|
|
|
wake_up_interruptible(&tty->link->read_wait);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-14 21:31:47 +07:00
|
|
|
tty->termios.c_cflag &= ~(CSIZE | PARENB);
|
|
|
|
tty->termios.c_cflag |= (CS8 | CREAD);
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
2009-01-02 20:43:17 +07:00
|
|
|
/**
|
|
|
|
* pty_do_resize - resize event
|
|
|
|
* @tty: tty being resized
|
2009-01-12 02:46:49 +07:00
|
|
|
* @ws: window size being set.
|
2009-01-02 20:43:17 +07:00
|
|
|
*
|
tree-wide: Assorted spelling fixes
In particular, several occurances of funny versions of 'success',
'unknown', 'therefore', 'acknowledge', 'argument', 'achieve', 'address',
'beginning', 'desirable', 'separate' and 'necessary' are fixed.
Signed-off-by: Daniel Mack <daniel@caiaq.de>
Cc: Joe Perches <joe@perches.com>
Cc: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
2010-02-03 07:01:28 +07:00
|
|
|
* Update the termios variables and send the necessary signals to
|
2009-01-02 20:43:17 +07:00
|
|
|
* peform a terminal resize correctly
|
|
|
|
*/
|
|
|
|
|
2012-11-19 12:27:40 +07:00
|
|
|
static int pty_resize(struct tty_struct *tty, struct winsize *ws)
|
2009-01-02 20:43:17 +07:00
|
|
|
{
|
|
|
|
struct pid *pgrp, *rpgrp;
|
|
|
|
struct tty_struct *pty = tty->link;
|
|
|
|
|
|
|
|
/* For a PTY we need to lock the tty side */
|
tty: Fix lock order in tty_do_resize()
Commits 6a1c0680cf3ba94356ecd58833e1540c93472a57 and
9356b535fcb71db494fc434acceb79f56d15bda2, respectively
'tty: Convert termios_mutex to termios_rwsem' and
'n_tty: Access termios values safely'
introduced a circular lock dependency with console_lock and
termios_rwsem.
The lockdep report [1] shows that n_tty_write() will attempt
to claim console_lock while holding the termios_rwsem, whereas
tty_do_resize() may already hold the console_lock while
claiming the termios_rwsem.
Since n_tty_write() and tty_do_resize() do not contend
over the same data -- the tty->winsize structure -- correct
the lock dependency by introducing a new lock which
specifically serializes access to tty->winsize only.
[1] Lockdep report
======================================================
[ INFO: possible circular locking dependency detected ]
3.10.0-0+tip-xeon+lockdep #0+tip Not tainted
-------------------------------------------------------
modprobe/277 is trying to acquire lock:
(&tty->termios_rwsem){++++..}, at: [<ffffffff81452656>] tty_do_resize+0x36/0xe0
but task is already holding lock:
((fb_notifier_list).rwsem){.+.+.+}, at: [<ffffffff8107aac6>] __blocking_notifier_call_chain+0x56/0xc0
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #2 ((fb_notifier_list).rwsem){.+.+.+}:
[<ffffffff810b6d62>] lock_acquire+0x92/0x1f0
[<ffffffff8175b797>] down_read+0x47/0x5c
[<ffffffff8107aac6>] __blocking_notifier_call_chain+0x56/0xc0
[<ffffffff8107ab46>] blocking_notifier_call_chain+0x16/0x20
[<ffffffff813d7c0b>] fb_notifier_call_chain+0x1b/0x20
[<ffffffff813d95b2>] register_framebuffer+0x1e2/0x320
[<ffffffffa01043e1>] drm_fb_helper_initial_config+0x371/0x540 [drm_kms_helper]
[<ffffffffa01bcb05>] nouveau_fbcon_init+0x105/0x140 [nouveau]
[<ffffffffa01ad0af>] nouveau_drm_load+0x43f/0x610 [nouveau]
[<ffffffffa008a79e>] drm_get_pci_dev+0x17e/0x2a0 [drm]
[<ffffffffa01ad4da>] nouveau_drm_probe+0x25a/0x2a0 [nouveau]
[<ffffffff813b13db>] local_pci_probe+0x4b/0x80
[<ffffffff813b1701>] pci_device_probe+0x111/0x120
[<ffffffff814977eb>] driver_probe_device+0x8b/0x3a0
[<ffffffff81497bab>] __driver_attach+0xab/0xb0
[<ffffffff814956ad>] bus_for_each_dev+0x5d/0xa0
[<ffffffff814971fe>] driver_attach+0x1e/0x20
[<ffffffff81496cc1>] bus_add_driver+0x111/0x290
[<ffffffff814982b7>] driver_register+0x77/0x170
[<ffffffff813b0454>] __pci_register_driver+0x64/0x70
[<ffffffffa008a9da>] drm_pci_init+0x11a/0x130 [drm]
[<ffffffffa022a04d>] nouveau_drm_init+0x4d/0x1000 [nouveau]
[<ffffffff810002ea>] do_one_initcall+0xea/0x1a0
[<ffffffff810c54cb>] load_module+0x123b/0x1bf0
[<ffffffff810c5f57>] SyS_init_module+0xd7/0x120
[<ffffffff817677c2>] system_call_fastpath+0x16/0x1b
-> #1 (console_lock){+.+.+.}:
[<ffffffff810b6d62>] lock_acquire+0x92/0x1f0
[<ffffffff810430a7>] console_lock+0x77/0x80
[<ffffffff8146b2a1>] con_flush_chars+0x31/0x50
[<ffffffff8145780c>] n_tty_write+0x1ec/0x4d0
[<ffffffff814541b9>] tty_write+0x159/0x2e0
[<ffffffff814543f5>] redirected_tty_write+0xb5/0xc0
[<ffffffff811ab9d5>] vfs_write+0xc5/0x1f0
[<ffffffff811abec5>] SyS_write+0x55/0xa0
[<ffffffff817677c2>] system_call_fastpath+0x16/0x1b
-> #0 (&tty->termios_rwsem){++++..}:
[<ffffffff810b65c3>] __lock_acquire+0x1c43/0x1d30
[<ffffffff810b6d62>] lock_acquire+0x92/0x1f0
[<ffffffff8175b724>] down_write+0x44/0x70
[<ffffffff81452656>] tty_do_resize+0x36/0xe0
[<ffffffff8146c841>] vc_do_resize+0x3e1/0x4c0
[<ffffffff8146c99f>] vc_resize+0x1f/0x30
[<ffffffff813e4535>] fbcon_init+0x385/0x5a0
[<ffffffff8146a4bc>] visual_init+0xbc/0x120
[<ffffffff8146cd13>] do_bind_con_driver+0x163/0x320
[<ffffffff8146cfa1>] do_take_over_console+0x61/0x70
[<ffffffff813e2b93>] do_fbcon_takeover+0x63/0xc0
[<ffffffff813e67a5>] fbcon_event_notify+0x715/0x820
[<ffffffff81762f9d>] notifier_call_chain+0x5d/0x110
[<ffffffff8107aadc>] __blocking_notifier_call_chain+0x6c/0xc0
[<ffffffff8107ab46>] blocking_notifier_call_chain+0x16/0x20
[<ffffffff813d7c0b>] fb_notifier_call_chain+0x1b/0x20
[<ffffffff813d95b2>] register_framebuffer+0x1e2/0x320
[<ffffffffa01043e1>] drm_fb_helper_initial_config+0x371/0x540 [drm_kms_helper]
[<ffffffffa01bcb05>] nouveau_fbcon_init+0x105/0x140 [nouveau]
[<ffffffffa01ad0af>] nouveau_drm_load+0x43f/0x610 [nouveau]
[<ffffffffa008a79e>] drm_get_pci_dev+0x17e/0x2a0 [drm]
[<ffffffffa01ad4da>] nouveau_drm_probe+0x25a/0x2a0 [nouveau]
[<ffffffff813b13db>] local_pci_probe+0x4b/0x80
[<ffffffff813b1701>] pci_device_probe+0x111/0x120
[<ffffffff814977eb>] driver_probe_device+0x8b/0x3a0
[<ffffffff81497bab>] __driver_attach+0xab/0xb0
[<ffffffff814956ad>] bus_for_each_dev+0x5d/0xa0
[<ffffffff814971fe>] driver_attach+0x1e/0x20
[<ffffffff81496cc1>] bus_add_driver+0x111/0x290
[<ffffffff814982b7>] driver_register+0x77/0x170
[<ffffffff813b0454>] __pci_register_driver+0x64/0x70
[<ffffffffa008a9da>] drm_pci_init+0x11a/0x130 [drm]
[<ffffffffa022a04d>] nouveau_drm_init+0x4d/0x1000 [nouveau]
[<ffffffff810002ea>] do_one_initcall+0xea/0x1a0
[<ffffffff810c54cb>] load_module+0x123b/0x1bf0
[<ffffffff810c5f57>] SyS_init_module+0xd7/0x120
[<ffffffff817677c2>] system_call_fastpath+0x16/0x1b
other info that might help us debug this:
Chain exists of:
&tty->termios_rwsem --> console_lock --> (fb_notifier_list).rwsem
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
lock((fb_notifier_list).rwsem);
lock(console_lock);
lock((fb_notifier_list).rwsem);
lock(&tty->termios_rwsem);
*** DEADLOCK ***
7 locks held by modprobe/277:
#0: (&__lockdep_no_validate__){......}, at: [<ffffffff81497b5b>] __driver_attach+0x5b/0xb0
#1: (&__lockdep_no_validate__){......}, at: [<ffffffff81497b69>] __driver_attach+0x69/0xb0
#2: (drm_global_mutex){+.+.+.}, at: [<ffffffffa008a6dd>] drm_get_pci_dev+0xbd/0x2a0 [drm]
#3: (registration_lock){+.+.+.}, at: [<ffffffff813d93f5>] register_framebuffer+0x25/0x320
#4: (&fb_info->lock){+.+.+.}, at: [<ffffffff813d8116>] lock_fb_info+0x26/0x60
#5: (console_lock){+.+.+.}, at: [<ffffffff813d95a4>] register_framebuffer+0x1d4/0x320
#6: ((fb_notifier_list).rwsem){.+.+.+}, at: [<ffffffff8107aac6>] __blocking_notifier_call_chain+0x56/0xc0
stack backtrace:
CPU: 0 PID: 277 Comm: modprobe Not tainted 3.10.0-0+tip-xeon+lockdep #0+tip
Hardware name: Dell Inc. Precision WorkStation T5400 /0RW203, BIOS A11 04/30/2012
ffffffff8213e5e0 ffff8802aa2fb298 ffffffff81755f19 ffff8802aa2fb2e8
ffffffff8174f506 ffff8802aa2fa000 ffff8802aa2fb378 ffff8802aa2ea8e8
ffff8802aa2ea910 ffff8802aa2ea8e8 0000000000000006 0000000000000007
Call Trace:
[<ffffffff81755f19>] dump_stack+0x19/0x1b
[<ffffffff8174f506>] print_circular_bug+0x1fb/0x20c
[<ffffffff810b65c3>] __lock_acquire+0x1c43/0x1d30
[<ffffffff810b775e>] ? mark_held_locks+0xae/0x120
[<ffffffff810b78d5>] ? trace_hardirqs_on_caller+0x105/0x1d0
[<ffffffff810b6d62>] lock_acquire+0x92/0x1f0
[<ffffffff81452656>] ? tty_do_resize+0x36/0xe0
[<ffffffff8175b724>] down_write+0x44/0x70
[<ffffffff81452656>] ? tty_do_resize+0x36/0xe0
[<ffffffff81452656>] tty_do_resize+0x36/0xe0
[<ffffffff8146c841>] vc_do_resize+0x3e1/0x4c0
[<ffffffff8146c99f>] vc_resize+0x1f/0x30
[<ffffffff813e4535>] fbcon_init+0x385/0x5a0
[<ffffffff8146a4bc>] visual_init+0xbc/0x120
[<ffffffff8146cd13>] do_bind_con_driver+0x163/0x320
[<ffffffff8146cfa1>] do_take_over_console+0x61/0x70
[<ffffffff813e2b93>] do_fbcon_takeover+0x63/0xc0
[<ffffffff813e67a5>] fbcon_event_notify+0x715/0x820
[<ffffffff81762f9d>] notifier_call_chain+0x5d/0x110
[<ffffffff8107aadc>] __blocking_notifier_call_chain+0x6c/0xc0
[<ffffffff8107ab46>] blocking_notifier_call_chain+0x16/0x20
[<ffffffff813d7c0b>] fb_notifier_call_chain+0x1b/0x20
[<ffffffff813d95b2>] register_framebuffer+0x1e2/0x320
[<ffffffffa01043e1>] drm_fb_helper_initial_config+0x371/0x540 [drm_kms_helper]
[<ffffffff8173cbcb>] ? kmemleak_alloc+0x5b/0xc0
[<ffffffff81198874>] ? kmem_cache_alloc_trace+0x104/0x290
[<ffffffffa01035e1>] ? drm_fb_helper_single_add_all_connectors+0x81/0xf0 [drm_kms_helper]
[<ffffffffa01bcb05>] nouveau_fbcon_init+0x105/0x140 [nouveau]
[<ffffffffa01ad0af>] nouveau_drm_load+0x43f/0x610 [nouveau]
[<ffffffffa008a79e>] drm_get_pci_dev+0x17e/0x2a0 [drm]
[<ffffffffa01ad4da>] nouveau_drm_probe+0x25a/0x2a0 [nouveau]
[<ffffffff8175f162>] ? _raw_spin_unlock_irqrestore+0x42/0x80
[<ffffffff813b13db>] local_pci_probe+0x4b/0x80
[<ffffffff813b1701>] pci_device_probe+0x111/0x120
[<ffffffff814977eb>] driver_probe_device+0x8b/0x3a0
[<ffffffff81497bab>] __driver_attach+0xab/0xb0
[<ffffffff81497b00>] ? driver_probe_device+0x3a0/0x3a0
[<ffffffff814956ad>] bus_for_each_dev+0x5d/0xa0
[<ffffffff814971fe>] driver_attach+0x1e/0x20
[<ffffffff81496cc1>] bus_add_driver+0x111/0x290
[<ffffffffa022a000>] ? 0xffffffffa0229fff
[<ffffffff814982b7>] driver_register+0x77/0x170
[<ffffffffa022a000>] ? 0xffffffffa0229fff
[<ffffffff813b0454>] __pci_register_driver+0x64/0x70
[<ffffffffa008a9da>] drm_pci_init+0x11a/0x130 [drm]
[<ffffffffa022a000>] ? 0xffffffffa0229fff
[<ffffffffa022a000>] ? 0xffffffffa0229fff
[<ffffffffa022a04d>] nouveau_drm_init+0x4d/0x1000 [nouveau]
[<ffffffff810002ea>] do_one_initcall+0xea/0x1a0
[<ffffffff810c54cb>] load_module+0x123b/0x1bf0
[<ffffffff81399a50>] ? ddebug_proc_open+0xb0/0xb0
[<ffffffff813855ae>] ? trace_hardirqs_on_thunk+0x3a/0x3f
[<ffffffff810c5f57>] SyS_init_module+0xd7/0x120
[<ffffffff817677c2>] system_call_fastpath+0x16/0x1b
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-07-25 03:43:51 +07:00
|
|
|
mutex_lock(&tty->winsize_mutex);
|
2009-01-02 20:43:17 +07:00
|
|
|
if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
|
|
|
|
goto done;
|
|
|
|
|
2014-10-17 01:59:45 +07:00
|
|
|
/* Signal the foreground process group of both ptys */
|
|
|
|
pgrp = tty_get_pgrp(tty);
|
|
|
|
rpgrp = tty_get_pgrp(pty);
|
2009-01-02 20:43:17 +07:00
|
|
|
|
|
|
|
if (pgrp)
|
|
|
|
kill_pgrp(pgrp, SIGWINCH, 1);
|
|
|
|
if (rpgrp != pgrp && rpgrp)
|
|
|
|
kill_pgrp(rpgrp, SIGWINCH, 1);
|
|
|
|
|
|
|
|
put_pid(pgrp);
|
|
|
|
put_pid(rpgrp);
|
|
|
|
|
|
|
|
tty->winsize = *ws;
|
|
|
|
pty->winsize = *ws; /* Never used so will go away soon */
|
|
|
|
done:
|
tty: Fix lock order in tty_do_resize()
Commits 6a1c0680cf3ba94356ecd58833e1540c93472a57 and
9356b535fcb71db494fc434acceb79f56d15bda2, respectively
'tty: Convert termios_mutex to termios_rwsem' and
'n_tty: Access termios values safely'
introduced a circular lock dependency with console_lock and
termios_rwsem.
The lockdep report [1] shows that n_tty_write() will attempt
to claim console_lock while holding the termios_rwsem, whereas
tty_do_resize() may already hold the console_lock while
claiming the termios_rwsem.
Since n_tty_write() and tty_do_resize() do not contend
over the same data -- the tty->winsize structure -- correct
the lock dependency by introducing a new lock which
specifically serializes access to tty->winsize only.
[1] Lockdep report
======================================================
[ INFO: possible circular locking dependency detected ]
3.10.0-0+tip-xeon+lockdep #0+tip Not tainted
-------------------------------------------------------
modprobe/277 is trying to acquire lock:
(&tty->termios_rwsem){++++..}, at: [<ffffffff81452656>] tty_do_resize+0x36/0xe0
but task is already holding lock:
((fb_notifier_list).rwsem){.+.+.+}, at: [<ffffffff8107aac6>] __blocking_notifier_call_chain+0x56/0xc0
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #2 ((fb_notifier_list).rwsem){.+.+.+}:
[<ffffffff810b6d62>] lock_acquire+0x92/0x1f0
[<ffffffff8175b797>] down_read+0x47/0x5c
[<ffffffff8107aac6>] __blocking_notifier_call_chain+0x56/0xc0
[<ffffffff8107ab46>] blocking_notifier_call_chain+0x16/0x20
[<ffffffff813d7c0b>] fb_notifier_call_chain+0x1b/0x20
[<ffffffff813d95b2>] register_framebuffer+0x1e2/0x320
[<ffffffffa01043e1>] drm_fb_helper_initial_config+0x371/0x540 [drm_kms_helper]
[<ffffffffa01bcb05>] nouveau_fbcon_init+0x105/0x140 [nouveau]
[<ffffffffa01ad0af>] nouveau_drm_load+0x43f/0x610 [nouveau]
[<ffffffffa008a79e>] drm_get_pci_dev+0x17e/0x2a0 [drm]
[<ffffffffa01ad4da>] nouveau_drm_probe+0x25a/0x2a0 [nouveau]
[<ffffffff813b13db>] local_pci_probe+0x4b/0x80
[<ffffffff813b1701>] pci_device_probe+0x111/0x120
[<ffffffff814977eb>] driver_probe_device+0x8b/0x3a0
[<ffffffff81497bab>] __driver_attach+0xab/0xb0
[<ffffffff814956ad>] bus_for_each_dev+0x5d/0xa0
[<ffffffff814971fe>] driver_attach+0x1e/0x20
[<ffffffff81496cc1>] bus_add_driver+0x111/0x290
[<ffffffff814982b7>] driver_register+0x77/0x170
[<ffffffff813b0454>] __pci_register_driver+0x64/0x70
[<ffffffffa008a9da>] drm_pci_init+0x11a/0x130 [drm]
[<ffffffffa022a04d>] nouveau_drm_init+0x4d/0x1000 [nouveau]
[<ffffffff810002ea>] do_one_initcall+0xea/0x1a0
[<ffffffff810c54cb>] load_module+0x123b/0x1bf0
[<ffffffff810c5f57>] SyS_init_module+0xd7/0x120
[<ffffffff817677c2>] system_call_fastpath+0x16/0x1b
-> #1 (console_lock){+.+.+.}:
[<ffffffff810b6d62>] lock_acquire+0x92/0x1f0
[<ffffffff810430a7>] console_lock+0x77/0x80
[<ffffffff8146b2a1>] con_flush_chars+0x31/0x50
[<ffffffff8145780c>] n_tty_write+0x1ec/0x4d0
[<ffffffff814541b9>] tty_write+0x159/0x2e0
[<ffffffff814543f5>] redirected_tty_write+0xb5/0xc0
[<ffffffff811ab9d5>] vfs_write+0xc5/0x1f0
[<ffffffff811abec5>] SyS_write+0x55/0xa0
[<ffffffff817677c2>] system_call_fastpath+0x16/0x1b
-> #0 (&tty->termios_rwsem){++++..}:
[<ffffffff810b65c3>] __lock_acquire+0x1c43/0x1d30
[<ffffffff810b6d62>] lock_acquire+0x92/0x1f0
[<ffffffff8175b724>] down_write+0x44/0x70
[<ffffffff81452656>] tty_do_resize+0x36/0xe0
[<ffffffff8146c841>] vc_do_resize+0x3e1/0x4c0
[<ffffffff8146c99f>] vc_resize+0x1f/0x30
[<ffffffff813e4535>] fbcon_init+0x385/0x5a0
[<ffffffff8146a4bc>] visual_init+0xbc/0x120
[<ffffffff8146cd13>] do_bind_con_driver+0x163/0x320
[<ffffffff8146cfa1>] do_take_over_console+0x61/0x70
[<ffffffff813e2b93>] do_fbcon_takeover+0x63/0xc0
[<ffffffff813e67a5>] fbcon_event_notify+0x715/0x820
[<ffffffff81762f9d>] notifier_call_chain+0x5d/0x110
[<ffffffff8107aadc>] __blocking_notifier_call_chain+0x6c/0xc0
[<ffffffff8107ab46>] blocking_notifier_call_chain+0x16/0x20
[<ffffffff813d7c0b>] fb_notifier_call_chain+0x1b/0x20
[<ffffffff813d95b2>] register_framebuffer+0x1e2/0x320
[<ffffffffa01043e1>] drm_fb_helper_initial_config+0x371/0x540 [drm_kms_helper]
[<ffffffffa01bcb05>] nouveau_fbcon_init+0x105/0x140 [nouveau]
[<ffffffffa01ad0af>] nouveau_drm_load+0x43f/0x610 [nouveau]
[<ffffffffa008a79e>] drm_get_pci_dev+0x17e/0x2a0 [drm]
[<ffffffffa01ad4da>] nouveau_drm_probe+0x25a/0x2a0 [nouveau]
[<ffffffff813b13db>] local_pci_probe+0x4b/0x80
[<ffffffff813b1701>] pci_device_probe+0x111/0x120
[<ffffffff814977eb>] driver_probe_device+0x8b/0x3a0
[<ffffffff81497bab>] __driver_attach+0xab/0xb0
[<ffffffff814956ad>] bus_for_each_dev+0x5d/0xa0
[<ffffffff814971fe>] driver_attach+0x1e/0x20
[<ffffffff81496cc1>] bus_add_driver+0x111/0x290
[<ffffffff814982b7>] driver_register+0x77/0x170
[<ffffffff813b0454>] __pci_register_driver+0x64/0x70
[<ffffffffa008a9da>] drm_pci_init+0x11a/0x130 [drm]
[<ffffffffa022a04d>] nouveau_drm_init+0x4d/0x1000 [nouveau]
[<ffffffff810002ea>] do_one_initcall+0xea/0x1a0
[<ffffffff810c54cb>] load_module+0x123b/0x1bf0
[<ffffffff810c5f57>] SyS_init_module+0xd7/0x120
[<ffffffff817677c2>] system_call_fastpath+0x16/0x1b
other info that might help us debug this:
Chain exists of:
&tty->termios_rwsem --> console_lock --> (fb_notifier_list).rwsem
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
lock((fb_notifier_list).rwsem);
lock(console_lock);
lock((fb_notifier_list).rwsem);
lock(&tty->termios_rwsem);
*** DEADLOCK ***
7 locks held by modprobe/277:
#0: (&__lockdep_no_validate__){......}, at: [<ffffffff81497b5b>] __driver_attach+0x5b/0xb0
#1: (&__lockdep_no_validate__){......}, at: [<ffffffff81497b69>] __driver_attach+0x69/0xb0
#2: (drm_global_mutex){+.+.+.}, at: [<ffffffffa008a6dd>] drm_get_pci_dev+0xbd/0x2a0 [drm]
#3: (registration_lock){+.+.+.}, at: [<ffffffff813d93f5>] register_framebuffer+0x25/0x320
#4: (&fb_info->lock){+.+.+.}, at: [<ffffffff813d8116>] lock_fb_info+0x26/0x60
#5: (console_lock){+.+.+.}, at: [<ffffffff813d95a4>] register_framebuffer+0x1d4/0x320
#6: ((fb_notifier_list).rwsem){.+.+.+}, at: [<ffffffff8107aac6>] __blocking_notifier_call_chain+0x56/0xc0
stack backtrace:
CPU: 0 PID: 277 Comm: modprobe Not tainted 3.10.0-0+tip-xeon+lockdep #0+tip
Hardware name: Dell Inc. Precision WorkStation T5400 /0RW203, BIOS A11 04/30/2012
ffffffff8213e5e0 ffff8802aa2fb298 ffffffff81755f19 ffff8802aa2fb2e8
ffffffff8174f506 ffff8802aa2fa000 ffff8802aa2fb378 ffff8802aa2ea8e8
ffff8802aa2ea910 ffff8802aa2ea8e8 0000000000000006 0000000000000007
Call Trace:
[<ffffffff81755f19>] dump_stack+0x19/0x1b
[<ffffffff8174f506>] print_circular_bug+0x1fb/0x20c
[<ffffffff810b65c3>] __lock_acquire+0x1c43/0x1d30
[<ffffffff810b775e>] ? mark_held_locks+0xae/0x120
[<ffffffff810b78d5>] ? trace_hardirqs_on_caller+0x105/0x1d0
[<ffffffff810b6d62>] lock_acquire+0x92/0x1f0
[<ffffffff81452656>] ? tty_do_resize+0x36/0xe0
[<ffffffff8175b724>] down_write+0x44/0x70
[<ffffffff81452656>] ? tty_do_resize+0x36/0xe0
[<ffffffff81452656>] tty_do_resize+0x36/0xe0
[<ffffffff8146c841>] vc_do_resize+0x3e1/0x4c0
[<ffffffff8146c99f>] vc_resize+0x1f/0x30
[<ffffffff813e4535>] fbcon_init+0x385/0x5a0
[<ffffffff8146a4bc>] visual_init+0xbc/0x120
[<ffffffff8146cd13>] do_bind_con_driver+0x163/0x320
[<ffffffff8146cfa1>] do_take_over_console+0x61/0x70
[<ffffffff813e2b93>] do_fbcon_takeover+0x63/0xc0
[<ffffffff813e67a5>] fbcon_event_notify+0x715/0x820
[<ffffffff81762f9d>] notifier_call_chain+0x5d/0x110
[<ffffffff8107aadc>] __blocking_notifier_call_chain+0x6c/0xc0
[<ffffffff8107ab46>] blocking_notifier_call_chain+0x16/0x20
[<ffffffff813d7c0b>] fb_notifier_call_chain+0x1b/0x20
[<ffffffff813d95b2>] register_framebuffer+0x1e2/0x320
[<ffffffffa01043e1>] drm_fb_helper_initial_config+0x371/0x540 [drm_kms_helper]
[<ffffffff8173cbcb>] ? kmemleak_alloc+0x5b/0xc0
[<ffffffff81198874>] ? kmem_cache_alloc_trace+0x104/0x290
[<ffffffffa01035e1>] ? drm_fb_helper_single_add_all_connectors+0x81/0xf0 [drm_kms_helper]
[<ffffffffa01bcb05>] nouveau_fbcon_init+0x105/0x140 [nouveau]
[<ffffffffa01ad0af>] nouveau_drm_load+0x43f/0x610 [nouveau]
[<ffffffffa008a79e>] drm_get_pci_dev+0x17e/0x2a0 [drm]
[<ffffffffa01ad4da>] nouveau_drm_probe+0x25a/0x2a0 [nouveau]
[<ffffffff8175f162>] ? _raw_spin_unlock_irqrestore+0x42/0x80
[<ffffffff813b13db>] local_pci_probe+0x4b/0x80
[<ffffffff813b1701>] pci_device_probe+0x111/0x120
[<ffffffff814977eb>] driver_probe_device+0x8b/0x3a0
[<ffffffff81497bab>] __driver_attach+0xab/0xb0
[<ffffffff81497b00>] ? driver_probe_device+0x3a0/0x3a0
[<ffffffff814956ad>] bus_for_each_dev+0x5d/0xa0
[<ffffffff814971fe>] driver_attach+0x1e/0x20
[<ffffffff81496cc1>] bus_add_driver+0x111/0x290
[<ffffffffa022a000>] ? 0xffffffffa0229fff
[<ffffffff814982b7>] driver_register+0x77/0x170
[<ffffffffa022a000>] ? 0xffffffffa0229fff
[<ffffffff813b0454>] __pci_register_driver+0x64/0x70
[<ffffffffa008a9da>] drm_pci_init+0x11a/0x130 [drm]
[<ffffffffa022a000>] ? 0xffffffffa0229fff
[<ffffffffa022a000>] ? 0xffffffffa0229fff
[<ffffffffa022a04d>] nouveau_drm_init+0x4d/0x1000 [nouveau]
[<ffffffff810002ea>] do_one_initcall+0xea/0x1a0
[<ffffffff810c54cb>] load_module+0x123b/0x1bf0
[<ffffffff81399a50>] ? ddebug_proc_open+0xb0/0xb0
[<ffffffff813855ae>] ? trace_hardirqs_on_thunk+0x3a/0x3f
[<ffffffff810c5f57>] SyS_init_module+0xd7/0x120
[<ffffffff817677c2>] system_call_fastpath+0x16/0x1b
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-07-25 03:43:51 +07:00
|
|
|
mutex_unlock(&tty->winsize_mutex);
|
2009-01-02 20:43:17 +07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-09-11 02:06:32 +07:00
|
|
|
/**
|
|
|
|
* pty_start - start() handler
|
|
|
|
* pty_stop - stop() handler
|
|
|
|
* @tty: tty being flow-controlled
|
|
|
|
*
|
|
|
|
* Propagates the TIOCPKT status to the master pty.
|
|
|
|
*
|
|
|
|
* NB: only the master pty can be in packet mode so only the slave
|
|
|
|
* needs start()/stop() handlers
|
|
|
|
*/
|
|
|
|
static void pty_start(struct tty_struct *tty)
|
|
|
|
{
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
if (tty->link && tty->link->packet) {
|
2014-10-17 02:33:26 +07:00
|
|
|
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
2014-09-11 02:06:32 +07:00
|
|
|
tty->ctrl_status &= ~TIOCPKT_STOP;
|
|
|
|
tty->ctrl_status |= TIOCPKT_START;
|
2014-10-17 02:33:26 +07:00
|
|
|
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
2014-09-11 02:06:32 +07:00
|
|
|
wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pty_stop(struct tty_struct *tty)
|
|
|
|
{
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
if (tty->link && tty->link->packet) {
|
2014-10-17 02:33:26 +07:00
|
|
|
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
2014-09-11 02:06:32 +07:00
|
|
|
tty->ctrl_status &= ~TIOCPKT_START;
|
|
|
|
tty->ctrl_status |= TIOCPKT_STOP;
|
2014-10-17 02:33:26 +07:00
|
|
|
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
2014-09-11 02:06:32 +07:00
|
|
|
wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-28 00:02:54 +07:00
|
|
|
/**
|
|
|
|
* pty_common_install - set up the pty pair
|
|
|
|
* @driver: the pty driver
|
|
|
|
* @tty: the tty being instantiated
|
2014-07-11 02:01:22 +07:00
|
|
|
* @legacy: true if this is BSD style
|
2012-07-28 00:02:54 +07:00
|
|
|
*
|
|
|
|
* Perform the initial set up for the tty/pty pair. Called from the
|
|
|
|
* tty layer when the port is first opened.
|
|
|
|
*
|
|
|
|
* Locking: the caller must hold the tty_mutex
|
|
|
|
*/
|
2012-06-04 18:35:29 +07:00
|
|
|
static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
|
|
|
|
bool legacy)
|
2008-10-13 16:42:39 +07:00
|
|
|
{
|
|
|
|
struct tty_struct *o_tty;
|
2012-06-04 18:35:30 +07:00
|
|
|
struct tty_port *ports[2];
|
2008-10-13 16:42:39 +07:00
|
|
|
int idx = tty->index;
|
2012-06-04 18:35:29 +07:00
|
|
|
int retval = -ENOMEM;
|
2008-10-13 16:42:39 +07:00
|
|
|
|
2014-11-06 00:12:49 +07:00
|
|
|
/* Opening the slave first has always returned -EIO */
|
|
|
|
if (driver->subtype != PTY_TYPE_MASTER)
|
|
|
|
return -EIO;
|
|
|
|
|
2012-06-04 18:35:30 +07:00
|
|
|
ports[0] = kmalloc(sizeof **ports, GFP_KERNEL);
|
|
|
|
ports[1] = kmalloc(sizeof **ports, GFP_KERNEL);
|
2012-08-08 02:47:26 +07:00
|
|
|
if (!ports[0] || !ports[1])
|
2014-07-11 02:01:22 +07:00
|
|
|
goto err;
|
2008-10-13 16:42:39 +07:00
|
|
|
if (!try_module_get(driver->other->owner)) {
|
|
|
|
/* This cannot in fact currently happen */
|
2014-07-11 02:01:22 +07:00
|
|
|
goto err;
|
2008-10-13 16:42:39 +07:00
|
|
|
}
|
2014-07-11 02:01:22 +07:00
|
|
|
o_tty = alloc_tty_struct(driver->other, idx);
|
|
|
|
if (!o_tty)
|
|
|
|
goto err_put_module;
|
2008-10-13 16:42:39 +07:00
|
|
|
|
2014-11-06 00:13:02 +07:00
|
|
|
tty_set_lock_subclass(o_tty);
|
2015-01-18 03:42:06 +07:00
|
|
|
lockdep_set_subclass(&o_tty->termios_rwsem, TTY_LOCK_SLAVE);
|
2014-11-06 00:13:02 +07:00
|
|
|
|
2012-06-04 18:35:29 +07:00
|
|
|
if (legacy) {
|
|
|
|
/* We always use new tty termios data so we can do this
|
|
|
|
the easy way .. */
|
2016-01-10 12:13:48 +07:00
|
|
|
tty_init_termios(tty);
|
|
|
|
tty_init_termios(o_tty);
|
2012-06-04 18:35:29 +07:00
|
|
|
|
|
|
|
driver->other->ttys[idx] = o_tty;
|
|
|
|
driver->ttys[idx] = tty;
|
|
|
|
} else {
|
2012-07-14 21:31:47 +07:00
|
|
|
memset(&tty->termios_locked, 0, sizeof(tty->termios_locked));
|
|
|
|
tty->termios = driver->init_termios;
|
|
|
|
memset(&o_tty->termios_locked, 0, sizeof(tty->termios_locked));
|
|
|
|
o_tty->termios = driver->other->init_termios;
|
2012-06-04 18:35:29 +07:00
|
|
|
}
|
2008-10-13 16:43:38 +07:00
|
|
|
|
2008-10-13 16:42:39 +07:00
|
|
|
/*
|
|
|
|
* Everything allocated ... set up the o_tty structure.
|
|
|
|
*/
|
|
|
|
tty_driver_kref_get(driver->other);
|
|
|
|
/* Establish the links in both directions */
|
|
|
|
tty->link = o_tty;
|
|
|
|
o_tty->link = tty;
|
2012-06-04 18:35:30 +07:00
|
|
|
tty_port_init(ports[0]);
|
|
|
|
tty_port_init(ports[1]);
|
2015-01-17 03:22:14 +07:00
|
|
|
tty_buffer_set_limit(ports[0], 8192);
|
|
|
|
tty_buffer_set_limit(ports[1], 8192);
|
2012-06-04 18:35:30 +07:00
|
|
|
o_tty->port = ports[0];
|
|
|
|
tty->port = ports[1];
|
2012-10-19 03:26:46 +07:00
|
|
|
o_tty->port->itty = o_tty;
|
2008-10-13 16:42:39 +07:00
|
|
|
|
2015-01-18 03:42:05 +07:00
|
|
|
tty_buffer_set_lock_subclass(o_tty->port);
|
|
|
|
|
2008-10-13 16:42:39 +07:00
|
|
|
tty_driver_kref_get(driver);
|
|
|
|
tty->count++;
|
2014-11-06 00:12:49 +07:00
|
|
|
o_tty->count++;
|
2008-10-13 16:42:39 +07:00
|
|
|
return 0;
|
2016-01-10 12:13:48 +07:00
|
|
|
|
2014-07-11 02:01:22 +07:00
|
|
|
err_put_module:
|
2014-07-13 06:44:00 +07:00
|
|
|
module_put(driver->other->owner);
|
2014-07-11 02:01:22 +07:00
|
|
|
err:
|
2012-06-04 18:35:30 +07:00
|
|
|
kfree(ports[0]);
|
|
|
|
kfree(ports[1]);
|
2011-03-23 16:48:33 +07:00
|
|
|
return retval;
|
2008-10-13 16:42:39 +07:00
|
|
|
}
|
|
|
|
|
2012-06-04 18:35:30 +07:00
|
|
|
static void pty_cleanup(struct tty_struct *tty)
|
|
|
|
{
|
2012-11-15 15:49:49 +07:00
|
|
|
tty_port_put(tty->port);
|
2012-06-04 18:35:30 +07:00
|
|
|
}
|
|
|
|
|
2012-06-04 18:35:29 +07:00
|
|
|
/* Traditional BSD devices */
|
|
|
|
#ifdef CONFIG_LEGACY_PTYS
|
|
|
|
|
|
|
|
static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
|
|
|
|
{
|
|
|
|
return pty_common_install(driver, tty, true);
|
|
|
|
}
|
|
|
|
|
2012-07-28 00:02:54 +07:00
|
|
|
static void pty_remove(struct tty_driver *driver, struct tty_struct *tty)
|
|
|
|
{
|
|
|
|
struct tty_struct *pair = tty->link;
|
|
|
|
driver->ttys[tty->index] = NULL;
|
|
|
|
if (pair)
|
|
|
|
pair->driver->ttys[pair->index] = NULL;
|
|
|
|
}
|
|
|
|
|
2011-02-14 23:27:22 +07:00
|
|
|
static int pty_bsd_ioctl(struct tty_struct *tty,
|
2005-04-17 05:20:36 +07:00
|
|
|
unsigned int cmd, unsigned long arg)
|
|
|
|
{
|
|
|
|
switch (cmd) {
|
|
|
|
case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
|
|
|
|
return pty_set_lock(tty, (int __user *) arg);
|
2012-10-25 02:43:22 +07:00
|
|
|
case TIOCGPTLCK: /* Get PT Lock status */
|
|
|
|
return pty_get_lock(tty, (int __user *)arg);
|
2012-10-25 02:43:20 +07:00
|
|
|
case TIOCPKT: /* Set PT packet mode */
|
|
|
|
return pty_set_pktmode(tty, (int __user *)arg);
|
2012-10-25 02:43:22 +07:00
|
|
|
case TIOCGPKT: /* Get PT packet mode */
|
|
|
|
return pty_get_pktmode(tty, (int __user *)arg);
|
tty: Add EXTPROC support for LINEMODE
This patch is against the 2.6.34 source.
Paraphrased from the 1989 BSD patch by David Borman @ cray.com:
These are the changes needed for the kernel to support
LINEMODE in the server.
There is a new bit in the termios local flag word, EXTPROC.
When this bit is set, several aspects of the terminal driver
are disabled. Input line editing, character echo, and mapping
of signals are all disabled. This allows the telnetd to turn
off these functions when in linemode, but still keep track of
what state the user wants the terminal to be in.
New ioctl:
TIOCSIG Generate a signal to processes in the
current process group of the pty.
There is a new mode for packet driver, the TIOCPKT_IOCTL bit.
When packet mode is turned on in the pty, and the EXTPROC bit
is set, then whenever the state of the pty is changed, the
next read on the master side of the pty will have the TIOCPKT_IOCTL
bit set. This allows the process on the server side of the pty
to know when the state of the terminal has changed; it can then
issue the appropriate ioctl to retrieve the new state.
Since the original BSD patches accompanied the source code for telnet
I've left that reference here, but obviously the feature is useful for
any remote terminal protocol, including ssh.
The corresponding feature has existed in the BSD tty driver since 1989.
For historical reference, a good copy of the relevant files can be found
here:
http://anonsvn.mit.edu/viewvc/krb5/trunk/src/appl/telnet/?pathrev=17741
Signed-off-by: Howard Chu <hyc@symas.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-06-23 00:14:49 +07:00
|
|
|
case TIOCSIG: /* Send signal to other side of pty */
|
|
|
|
return pty_signal(tty, (int) arg);
|
2013-01-11 18:06:27 +07:00
|
|
|
case TIOCGPTN: /* TTY returns ENOTTY, but glibc expects EINVAL here */
|
|
|
|
return -EINVAL;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
return -ENOIOCTLCMD;
|
|
|
|
}
|
|
|
|
|
2017-06-03 21:15:14 +07:00
|
|
|
static long pty_bsd_compat_ioctl(struct tty_struct *tty,
|
|
|
|
unsigned int cmd, unsigned long arg)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* PTY ioctls don't require any special translation between 32-bit and
|
|
|
|
* 64-bit userspace, they are already compatible.
|
|
|
|
*/
|
|
|
|
return pty_bsd_ioctl(tty, cmd, arg);
|
|
|
|
}
|
|
|
|
|
2007-08-15 17:25:38 +07:00
|
|
|
static int legacy_count = CONFIG_LEGACY_PTY_COUNT;
|
2015-08-20 04:48:05 +07:00
|
|
|
/*
|
|
|
|
* not really modular, but the easiest way to keep compat with existing
|
|
|
|
* bootargs behaviour is to continue using module_param here.
|
|
|
|
*/
|
2007-08-15 17:25:38 +07:00
|
|
|
module_param(legacy_count, int, 0);
|
|
|
|
|
2009-09-30 21:49:40 +07:00
|
|
|
/*
|
|
|
|
* The master side of a pty can do TIOCSPTLCK and thus
|
|
|
|
* has pty_bsd_ioctl.
|
|
|
|
*/
|
|
|
|
static const struct tty_operations master_pty_ops_bsd = {
|
|
|
|
.install = pty_install,
|
2008-04-30 14:54:10 +07:00
|
|
|
.open = pty_open,
|
|
|
|
.close = pty_close,
|
|
|
|
.write = pty_write,
|
|
|
|
.write_room = pty_write_room,
|
|
|
|
.flush_buffer = pty_flush_buffer,
|
|
|
|
.chars_in_buffer = pty_chars_in_buffer,
|
|
|
|
.unthrottle = pty_unthrottle,
|
|
|
|
.ioctl = pty_bsd_ioctl,
|
2017-06-03 21:15:14 +07:00
|
|
|
.compat_ioctl = pty_bsd_compat_ioctl,
|
2012-06-04 18:35:30 +07:00
|
|
|
.cleanup = pty_cleanup,
|
2012-07-28 00:02:54 +07:00
|
|
|
.resize = pty_resize,
|
|
|
|
.remove = pty_remove
|
2008-04-30 14:54:10 +07:00
|
|
|
};
|
|
|
|
|
2009-09-30 21:49:40 +07:00
|
|
|
static const struct tty_operations slave_pty_ops_bsd = {
|
|
|
|
.install = pty_install,
|
|
|
|
.open = pty_open,
|
|
|
|
.close = pty_close,
|
|
|
|
.write = pty_write,
|
|
|
|
.write_room = pty_write_room,
|
|
|
|
.flush_buffer = pty_flush_buffer,
|
|
|
|
.chars_in_buffer = pty_chars_in_buffer,
|
|
|
|
.unthrottle = pty_unthrottle,
|
|
|
|
.set_termios = pty_set_termios,
|
2012-06-04 18:35:30 +07:00
|
|
|
.cleanup = pty_cleanup,
|
2012-07-28 00:02:54 +07:00
|
|
|
.resize = pty_resize,
|
2014-09-11 02:06:32 +07:00
|
|
|
.start = pty_start,
|
|
|
|
.stop = pty_stop,
|
2012-07-28 00:02:54 +07:00
|
|
|
.remove = pty_remove
|
2009-09-30 21:49:40 +07:00
|
|
|
};
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
static void __init legacy_pty_init(void)
|
|
|
|
{
|
2009-09-30 21:49:40 +07:00
|
|
|
struct tty_driver *pty_driver, *pty_slave_driver;
|
|
|
|
|
2007-08-15 17:25:38 +07:00
|
|
|
if (legacy_count <= 0)
|
|
|
|
return;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2012-08-09 03:26:41 +07:00
|
|
|
pty_driver = tty_alloc_driver(legacy_count,
|
|
|
|
TTY_DRIVER_RESET_TERMIOS |
|
|
|
|
TTY_DRIVER_REAL_RAW |
|
|
|
|
TTY_DRIVER_DYNAMIC_ALLOC);
|
2012-08-16 20:16:56 +07:00
|
|
|
if (IS_ERR(pty_driver))
|
2005-04-17 05:20:36 +07:00
|
|
|
panic("Couldn't allocate pty driver");
|
|
|
|
|
2012-08-09 03:26:41 +07:00
|
|
|
pty_slave_driver = tty_alloc_driver(legacy_count,
|
|
|
|
TTY_DRIVER_RESET_TERMIOS |
|
|
|
|
TTY_DRIVER_REAL_RAW |
|
|
|
|
TTY_DRIVER_DYNAMIC_ALLOC);
|
2012-08-16 20:16:56 +07:00
|
|
|
if (IS_ERR(pty_slave_driver))
|
2005-04-17 05:20:36 +07:00
|
|
|
panic("Couldn't allocate pty slave driver");
|
|
|
|
|
|
|
|
pty_driver->driver_name = "pty_master";
|
|
|
|
pty_driver->name = "pty";
|
|
|
|
pty_driver->major = PTY_MASTER_MAJOR;
|
|
|
|
pty_driver->minor_start = 0;
|
|
|
|
pty_driver->type = TTY_DRIVER_TYPE_PTY;
|
|
|
|
pty_driver->subtype = PTY_TYPE_MASTER;
|
|
|
|
pty_driver->init_termios = tty_std_termios;
|
|
|
|
pty_driver->init_termios.c_iflag = 0;
|
|
|
|
pty_driver->init_termios.c_oflag = 0;
|
|
|
|
pty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
|
|
|
|
pty_driver->init_termios.c_lflag = 0;
|
2006-12-08 17:38:45 +07:00
|
|
|
pty_driver->init_termios.c_ispeed = 38400;
|
|
|
|
pty_driver->init_termios.c_ospeed = 38400;
|
2005-04-17 05:20:36 +07:00
|
|
|
pty_driver->other = pty_slave_driver;
|
2009-09-30 21:49:40 +07:00
|
|
|
tty_set_operations(pty_driver, &master_pty_ops_bsd);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
pty_slave_driver->driver_name = "pty_slave";
|
|
|
|
pty_slave_driver->name = "ttyp";
|
|
|
|
pty_slave_driver->major = PTY_SLAVE_MAJOR;
|
|
|
|
pty_slave_driver->minor_start = 0;
|
|
|
|
pty_slave_driver->type = TTY_DRIVER_TYPE_PTY;
|
|
|
|
pty_slave_driver->subtype = PTY_TYPE_SLAVE;
|
|
|
|
pty_slave_driver->init_termios = tty_std_termios;
|
|
|
|
pty_slave_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
|
2006-12-08 17:38:45 +07:00
|
|
|
pty_slave_driver->init_termios.c_ispeed = 38400;
|
|
|
|
pty_slave_driver->init_termios.c_ospeed = 38400;
|
2005-04-17 05:20:36 +07:00
|
|
|
pty_slave_driver->other = pty_driver;
|
2009-09-30 21:49:40 +07:00
|
|
|
tty_set_operations(pty_slave_driver, &slave_pty_ops_bsd);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
if (tty_register_driver(pty_driver))
|
|
|
|
panic("Couldn't register pty driver");
|
|
|
|
if (tty_register_driver(pty_slave_driver))
|
|
|
|
panic("Couldn't register pty slave driver");
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static inline void legacy_pty_init(void) { }
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Unix98 devices */
|
|
|
|
#ifdef CONFIG_UNIX98_PTYS
|
2008-10-13 16:41:42 +07:00
|
|
|
static struct cdev ptmx_cdev;
|
|
|
|
|
2017-06-21 03:34:13 +07:00
|
|
|
/**
|
|
|
|
* pty_open_peer - open the peer of a pty
|
|
|
|
* @tty: the peer of the pty being opened
|
|
|
|
*
|
|
|
|
* Open the cached dentry in tty->link, providing a safe way for userspace
|
|
|
|
* to get the slave end of a pty (where they have the master fd and cannot
|
|
|
|
* access or trust the mount namespace /dev/pts was mounted inside).
|
|
|
|
*/
|
|
|
|
static struct file *pty_open_peer(struct tty_struct *tty, int flags)
|
|
|
|
{
|
|
|
|
if (tty->driver->subtype != PTY_TYPE_MASTER)
|
|
|
|
return ERR_PTR(-EIO);
|
|
|
|
return dentry_open(tty->link->driver_data, flags, current_cred());
|
|
|
|
}
|
|
|
|
|
|
|
|
static int pty_get_peer(struct tty_struct *tty, int flags)
|
|
|
|
{
|
|
|
|
int fd = -1;
|
|
|
|
struct file *filp = NULL;
|
|
|
|
int retval = -EINVAL;
|
|
|
|
|
|
|
|
fd = get_unused_fd_flags(0);
|
|
|
|
if (fd < 0) {
|
|
|
|
retval = fd;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
filp = pty_open_peer(tty, flags);
|
|
|
|
if (IS_ERR(filp)) {
|
|
|
|
retval = PTR_ERR(filp);
|
|
|
|
goto err_put;
|
|
|
|
}
|
|
|
|
|
|
|
|
fd_install(fd, filp);
|
|
|
|
return fd;
|
|
|
|
|
|
|
|
err_put:
|
|
|
|
put_unused_fd(fd);
|
|
|
|
err:
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2011-02-14 23:27:22 +07:00
|
|
|
static int pty_unix98_ioctl(struct tty_struct *tty,
|
2005-04-17 05:20:36 +07:00
|
|
|
unsigned int cmd, unsigned long arg)
|
|
|
|
{
|
|
|
|
switch (cmd) {
|
|
|
|
case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
|
|
|
|
return pty_set_lock(tty, (int __user *)arg);
|
2012-10-25 02:43:22 +07:00
|
|
|
case TIOCGPTLCK: /* Get PT Lock status */
|
|
|
|
return pty_get_lock(tty, (int __user *)arg);
|
2012-10-25 02:43:20 +07:00
|
|
|
case TIOCPKT: /* Set PT packet mode */
|
|
|
|
return pty_set_pktmode(tty, (int __user *)arg);
|
2012-10-25 02:43:22 +07:00
|
|
|
case TIOCGPKT: /* Get PT packet mode */
|
|
|
|
return pty_get_pktmode(tty, (int __user *)arg);
|
2005-04-17 05:20:36 +07:00
|
|
|
case TIOCGPTN: /* Get PT Number */
|
|
|
|
return put_user(tty->index, (unsigned int __user *)arg);
|
2017-06-03 21:15:15 +07:00
|
|
|
case TIOCGPTPEER: /* Open the other end */
|
|
|
|
return pty_get_peer(tty, (int) arg);
|
tty: Add EXTPROC support for LINEMODE
This patch is against the 2.6.34 source.
Paraphrased from the 1989 BSD patch by David Borman @ cray.com:
These are the changes needed for the kernel to support
LINEMODE in the server.
There is a new bit in the termios local flag word, EXTPROC.
When this bit is set, several aspects of the terminal driver
are disabled. Input line editing, character echo, and mapping
of signals are all disabled. This allows the telnetd to turn
off these functions when in linemode, but still keep track of
what state the user wants the terminal to be in.
New ioctl:
TIOCSIG Generate a signal to processes in the
current process group of the pty.
There is a new mode for packet driver, the TIOCPKT_IOCTL bit.
When packet mode is turned on in the pty, and the EXTPROC bit
is set, then whenever the state of the pty is changed, the
next read on the master side of the pty will have the TIOCPKT_IOCTL
bit set. This allows the process on the server side of the pty
to know when the state of the terminal has changed; it can then
issue the appropriate ioctl to retrieve the new state.
Since the original BSD patches accompanied the source code for telnet
I've left that reference here, but obviously the feature is useful for
any remote terminal protocol, including ssh.
The corresponding feature has existed in the BSD tty driver since 1989.
For historical reference, a good copy of the relevant files can be found
here:
http://anonsvn.mit.edu/viewvc/krb5/trunk/src/appl/telnet/?pathrev=17741
Signed-off-by: Howard Chu <hyc@symas.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-06-23 00:14:49 +07:00
|
|
|
case TIOCSIG: /* Send signal to other side of pty */
|
|
|
|
return pty_signal(tty, (int) arg);
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
return -ENOIOCTLCMD;
|
|
|
|
}
|
|
|
|
|
2017-06-03 21:15:14 +07:00
|
|
|
static long pty_unix98_compat_ioctl(struct tty_struct *tty,
|
|
|
|
unsigned int cmd, unsigned long arg)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* PTY ioctls don't require any special translation between 32-bit and
|
|
|
|
* 64-bit userspace, they are already compatible.
|
|
|
|
*/
|
|
|
|
return pty_unix98_ioctl(tty, cmd, arg);
|
|
|
|
}
|
|
|
|
|
2008-10-13 16:42:00 +07:00
|
|
|
/**
|
|
|
|
* ptm_unix98_lookup - find a pty master
|
|
|
|
* @driver: ptm driver
|
|
|
|
* @idx: tty index
|
|
|
|
*
|
|
|
|
* Look up a pty master device. Called under the tty_mutex for now.
|
|
|
|
* This provides our locking.
|
|
|
|
*/
|
|
|
|
|
2008-10-13 16:42:59 +07:00
|
|
|
static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
|
2016-04-26 10:04:08 +07:00
|
|
|
struct file *file, int idx)
|
2008-10-13 16:42:00 +07:00
|
|
|
{
|
2012-01-05 16:04:21 +07:00
|
|
|
/* Master must be open via /dev/ptmx */
|
|
|
|
return ERR_PTR(-EIO);
|
2008-10-13 16:42:00 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* pts_unix98_lookup - find a pty slave
|
|
|
|
* @driver: pts driver
|
|
|
|
* @idx: tty index
|
|
|
|
*
|
|
|
|
* Look up a pty master device. Called under the tty_mutex for now.
|
2012-05-04 04:22:09 +07:00
|
|
|
* This provides our locking for the tty pointer.
|
2008-10-13 16:42:00 +07:00
|
|
|
*/
|
|
|
|
|
2008-10-13 16:42:59 +07:00
|
|
|
static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
|
2016-04-26 10:04:08 +07:00
|
|
|
struct file *file, int idx)
|
2008-10-13 16:42:00 +07:00
|
|
|
{
|
2012-05-04 04:22:09 +07:00
|
|
|
struct tty_struct *tty;
|
|
|
|
|
|
|
|
mutex_lock(&devpts_mutex);
|
2016-04-26 10:04:08 +07:00
|
|
|
tty = devpts_get_priv(file->f_path.dentry);
|
2012-05-04 04:22:09 +07:00
|
|
|
mutex_unlock(&devpts_mutex);
|
2008-10-13 16:42:00 +07:00
|
|
|
/* Master must be open before slave */
|
|
|
|
if (!tty)
|
|
|
|
return ERR_PTR(-EIO);
|
|
|
|
return tty;
|
|
|
|
}
|
|
|
|
|
2008-10-13 16:42:39 +07:00
|
|
|
static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
|
2008-10-13 16:42:19 +07:00
|
|
|
{
|
2012-06-04 18:35:29 +07:00
|
|
|
return pty_common_install(driver, tty, false);
|
2008-10-13 16:42:19 +07:00
|
|
|
}
|
|
|
|
|
2013-04-15 12:52:05 +07:00
|
|
|
/* this is called once with whichever end is closed last */
|
2016-01-10 12:13:50 +07:00
|
|
|
static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
|
2013-04-15 12:52:05 +07:00
|
|
|
{
|
devpts: clean up interface to pty drivers
This gets rid of the horrible notion of having that
struct inode *ptmx_inode
be the linchpin of the interface between the pty code and devpts.
By de-emphasizing the ptmx inode, a lot of things actually get cleaner,
and we will have a much saner way forward. In particular, this will
allow us to associate with any particular devpts instance at open-time,
and not be artificially tied to one particular ptmx inode.
The patch itself is actually fairly straightforward, and apart from some
locking and return path cleanups it's pretty mechanical:
- the interfaces that devpts exposes all take "struct pts_fs_info *"
instead of "struct inode *ptmx_inode" now.
NOTE! The "struct pts_fs_info" thing is a completely opaque structure
as far as the pty driver is concerned: it's still declared entirely
internally to devpts. So the pty code can't actually access it in any
way, just pass it as a "cookie" to the devpts code.
- the "look up the pts fs info" is now a single clear operation, that
also does the reference count increment on the pts superblock.
So "devpts_add/del_ref()" is gone, and replaced by a "lookup and get
ref" operation (devpts_get_ref(inode)), along with a "put ref" op
(devpts_put_ref()).
- the pty master "tty->driver_data" field now contains the pts_fs_info,
not the ptmx inode.
- because we don't care about the ptmx inode any more as some kind of
base index, the ref counting can now drop the inode games - it just
gets the ref on the superblock.
- the pts_fs_info now has a back-pointer to the super_block. That's so
that we can easily look up the information we actually need. Although
quite often, the pts fs info was actually all we wanted, and not having
to look it up based on some magical inode makes things more
straightforward.
In particular, now that "devpts_get_ref(inode)" operation should really
be the *only* place we need to look up what devpts instance we're
associated with, and we do it exactly once, at ptmx_open() time.
The other side of this is that one ptmx node could now be associated
with multiple different devpts instances - you could have a single
/dev/ptmx node, and then have multiple mount namespaces with their own
instances of devpts mounted on /dev/pts/. And that's all perfectly sane
in a model where we just look up the pts instance at open time.
This will eventually allow us to get rid of our odd single-vs-multiple
pts instance model, but this patch in itself changes no semantics, only
an internal binding model.
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Peter Anvin <hpa@zytor.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Peter Hurley <peter@hurleysoftware.com>
Cc: Serge Hallyn <serge.hallyn@ubuntu.com>
Cc: Willy Tarreau <w@1wt.eu>
Cc: Aurelien Jarno <aurelien@aurel32.net>
Cc: Alan Cox <gnomes@lxorguk.ukuu.org.uk>
Cc: Jann Horn <jann@thejh.net>
Cc: Greg KH <greg@kroah.com>
Cc: Jiri Slaby <jslaby@suse.com>
Cc: Florian Weimer <fw@deneb.enyo.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-17 05:16:07 +07:00
|
|
|
struct pts_fs_info *fsi;
|
2016-01-11 21:07:43 +07:00
|
|
|
|
|
|
|
if (tty->driver->subtype == PTY_TYPE_MASTER)
|
devpts: clean up interface to pty drivers
This gets rid of the horrible notion of having that
struct inode *ptmx_inode
be the linchpin of the interface between the pty code and devpts.
By de-emphasizing the ptmx inode, a lot of things actually get cleaner,
and we will have a much saner way forward. In particular, this will
allow us to associate with any particular devpts instance at open-time,
and not be artificially tied to one particular ptmx inode.
The patch itself is actually fairly straightforward, and apart from some
locking and return path cleanups it's pretty mechanical:
- the interfaces that devpts exposes all take "struct pts_fs_info *"
instead of "struct inode *ptmx_inode" now.
NOTE! The "struct pts_fs_info" thing is a completely opaque structure
as far as the pty driver is concerned: it's still declared entirely
internally to devpts. So the pty code can't actually access it in any
way, just pass it as a "cookie" to the devpts code.
- the "look up the pts fs info" is now a single clear operation, that
also does the reference count increment on the pts superblock.
So "devpts_add/del_ref()" is gone, and replaced by a "lookup and get
ref" operation (devpts_get_ref(inode)), along with a "put ref" op
(devpts_put_ref()).
- the pty master "tty->driver_data" field now contains the pts_fs_info,
not the ptmx inode.
- because we don't care about the ptmx inode any more as some kind of
base index, the ref counting can now drop the inode games - it just
gets the ref on the superblock.
- the pts_fs_info now has a back-pointer to the super_block. That's so
that we can easily look up the information we actually need. Although
quite often, the pts fs info was actually all we wanted, and not having
to look it up based on some magical inode makes things more
straightforward.
In particular, now that "devpts_get_ref(inode)" operation should really
be the *only* place we need to look up what devpts instance we're
associated with, and we do it exactly once, at ptmx_open() time.
The other side of this is that one ptmx node could now be associated
with multiple different devpts instances - you could have a single
/dev/ptmx node, and then have multiple mount namespaces with their own
instances of devpts mounted on /dev/pts/. And that's all perfectly sane
in a model where we just look up the pts instance at open time.
This will eventually allow us to get rid of our odd single-vs-multiple
pts instance model, but this patch in itself changes no semantics, only
an internal binding model.
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Peter Anvin <hpa@zytor.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Peter Hurley <peter@hurleysoftware.com>
Cc: Serge Hallyn <serge.hallyn@ubuntu.com>
Cc: Willy Tarreau <w@1wt.eu>
Cc: Aurelien Jarno <aurelien@aurel32.net>
Cc: Alan Cox <gnomes@lxorguk.ukuu.org.uk>
Cc: Jann Horn <jann@thejh.net>
Cc: Greg KH <greg@kroah.com>
Cc: Jiri Slaby <jslaby@suse.com>
Cc: Florian Weimer <fw@deneb.enyo.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-17 05:16:07 +07:00
|
|
|
fsi = tty->driver_data;
|
2016-01-11 21:07:43 +07:00
|
|
|
else
|
devpts: clean up interface to pty drivers
This gets rid of the horrible notion of having that
struct inode *ptmx_inode
be the linchpin of the interface between the pty code and devpts.
By de-emphasizing the ptmx inode, a lot of things actually get cleaner,
and we will have a much saner way forward. In particular, this will
allow us to associate with any particular devpts instance at open-time,
and not be artificially tied to one particular ptmx inode.
The patch itself is actually fairly straightforward, and apart from some
locking and return path cleanups it's pretty mechanical:
- the interfaces that devpts exposes all take "struct pts_fs_info *"
instead of "struct inode *ptmx_inode" now.
NOTE! The "struct pts_fs_info" thing is a completely opaque structure
as far as the pty driver is concerned: it's still declared entirely
internally to devpts. So the pty code can't actually access it in any
way, just pass it as a "cookie" to the devpts code.
- the "look up the pts fs info" is now a single clear operation, that
also does the reference count increment on the pts superblock.
So "devpts_add/del_ref()" is gone, and replaced by a "lookup and get
ref" operation (devpts_get_ref(inode)), along with a "put ref" op
(devpts_put_ref()).
- the pty master "tty->driver_data" field now contains the pts_fs_info,
not the ptmx inode.
- because we don't care about the ptmx inode any more as some kind of
base index, the ref counting can now drop the inode games - it just
gets the ref on the superblock.
- the pts_fs_info now has a back-pointer to the super_block. That's so
that we can easily look up the information we actually need. Although
quite often, the pts fs info was actually all we wanted, and not having
to look it up based on some magical inode makes things more
straightforward.
In particular, now that "devpts_get_ref(inode)" operation should really
be the *only* place we need to look up what devpts instance we're
associated with, and we do it exactly once, at ptmx_open() time.
The other side of this is that one ptmx node could now be associated
with multiple different devpts instances - you could have a single
/dev/ptmx node, and then have multiple mount namespaces with their own
instances of devpts mounted on /dev/pts/. And that's all perfectly sane
in a model where we just look up the pts instance at open time.
This will eventually allow us to get rid of our odd single-vs-multiple
pts instance model, but this patch in itself changes no semantics, only
an internal binding model.
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Peter Anvin <hpa@zytor.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Peter Hurley <peter@hurleysoftware.com>
Cc: Serge Hallyn <serge.hallyn@ubuntu.com>
Cc: Willy Tarreau <w@1wt.eu>
Cc: Aurelien Jarno <aurelien@aurel32.net>
Cc: Alan Cox <gnomes@lxorguk.ukuu.org.uk>
Cc: Jann Horn <jann@thejh.net>
Cc: Greg KH <greg@kroah.com>
Cc: Jiri Slaby <jslaby@suse.com>
Cc: Florian Weimer <fw@deneb.enyo.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-17 05:16:07 +07:00
|
|
|
fsi = tty->link->driver_data;
|
2016-06-20 21:40:27 +07:00
|
|
|
|
|
|
|
if (fsi) {
|
|
|
|
devpts_kill_index(fsi, tty->index);
|
|
|
|
devpts_release(fsi);
|
|
|
|
}
|
2013-04-15 12:52:05 +07:00
|
|
|
}
|
|
|
|
|
2008-10-13 16:41:30 +07:00
|
|
|
static const struct tty_operations ptm_unix98_ops = {
|
2008-10-13 16:42:00 +07:00
|
|
|
.lookup = ptm_unix98_lookup,
|
2008-10-13 16:42:39 +07:00
|
|
|
.install = pty_unix98_install,
|
2012-06-04 18:35:28 +07:00
|
|
|
.remove = pty_unix98_remove,
|
2008-04-30 14:54:10 +07:00
|
|
|
.open = pty_open,
|
|
|
|
.close = pty_close,
|
|
|
|
.write = pty_write,
|
|
|
|
.write_room = pty_write_room,
|
|
|
|
.flush_buffer = pty_flush_buffer,
|
|
|
|
.chars_in_buffer = pty_chars_in_buffer,
|
|
|
|
.unthrottle = pty_unthrottle,
|
2008-10-13 16:41:30 +07:00
|
|
|
.ioctl = pty_unix98_ioctl,
|
2017-06-03 21:15:14 +07:00
|
|
|
.compat_ioctl = pty_unix98_compat_ioctl,
|
2012-07-17 23:06:57 +07:00
|
|
|
.resize = pty_resize,
|
|
|
|
.cleanup = pty_cleanup
|
2008-04-30 14:54:10 +07:00
|
|
|
};
|
|
|
|
|
2008-10-13 16:42:00 +07:00
|
|
|
static const struct tty_operations pty_unix98_ops = {
|
|
|
|
.lookup = pts_unix98_lookup,
|
2008-10-13 16:42:39 +07:00
|
|
|
.install = pty_unix98_install,
|
2012-06-04 18:35:28 +07:00
|
|
|
.remove = pty_unix98_remove,
|
2008-10-13 16:42:00 +07:00
|
|
|
.open = pty_open,
|
|
|
|
.close = pty_close,
|
|
|
|
.write = pty_write,
|
|
|
|
.write_room = pty_write_room,
|
|
|
|
.flush_buffer = pty_flush_buffer,
|
|
|
|
.chars_in_buffer = pty_chars_in_buffer,
|
|
|
|
.unthrottle = pty_unthrottle,
|
|
|
|
.set_termios = pty_set_termios,
|
2014-09-11 02:06:32 +07:00
|
|
|
.start = pty_start,
|
|
|
|
.stop = pty_stop,
|
2012-06-04 18:35:30 +07:00
|
|
|
.cleanup = pty_cleanup,
|
2008-10-13 16:42:00 +07:00
|
|
|
};
|
2008-10-13 16:41:42 +07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* ptmx_open - open a unix 98 pty master
|
|
|
|
* @inode: inode of device file
|
|
|
|
* @filp: file pointer to tty
|
|
|
|
*
|
|
|
|
* Allocate a unix98 pty master device from the ptmx driver.
|
|
|
|
*
|
|
|
|
* Locking: tty_mutex protects the init_dev work. tty->count should
|
2013-01-12 11:01:22 +07:00
|
|
|
* protect the rest.
|
2008-10-13 16:41:42 +07:00
|
|
|
* allocated_ptys_lock handles the list of free pty numbers
|
|
|
|
*/
|
|
|
|
|
2010-06-02 03:53:02 +07:00
|
|
|
static int ptmx_open(struct inode *inode, struct file *filp)
|
2008-10-13 16:41:42 +07:00
|
|
|
{
|
devpts: clean up interface to pty drivers
This gets rid of the horrible notion of having that
struct inode *ptmx_inode
be the linchpin of the interface between the pty code and devpts.
By de-emphasizing the ptmx inode, a lot of things actually get cleaner,
and we will have a much saner way forward. In particular, this will
allow us to associate with any particular devpts instance at open-time,
and not be artificially tied to one particular ptmx inode.
The patch itself is actually fairly straightforward, and apart from some
locking and return path cleanups it's pretty mechanical:
- the interfaces that devpts exposes all take "struct pts_fs_info *"
instead of "struct inode *ptmx_inode" now.
NOTE! The "struct pts_fs_info" thing is a completely opaque structure
as far as the pty driver is concerned: it's still declared entirely
internally to devpts. So the pty code can't actually access it in any
way, just pass it as a "cookie" to the devpts code.
- the "look up the pts fs info" is now a single clear operation, that
also does the reference count increment on the pts superblock.
So "devpts_add/del_ref()" is gone, and replaced by a "lookup and get
ref" operation (devpts_get_ref(inode)), along with a "put ref" op
(devpts_put_ref()).
- the pty master "tty->driver_data" field now contains the pts_fs_info,
not the ptmx inode.
- because we don't care about the ptmx inode any more as some kind of
base index, the ref counting can now drop the inode games - it just
gets the ref on the superblock.
- the pts_fs_info now has a back-pointer to the super_block. That's so
that we can easily look up the information we actually need. Although
quite often, the pts fs info was actually all we wanted, and not having
to look it up based on some magical inode makes things more
straightforward.
In particular, now that "devpts_get_ref(inode)" operation should really
be the *only* place we need to look up what devpts instance we're
associated with, and we do it exactly once, at ptmx_open() time.
The other side of this is that one ptmx node could now be associated
with multiple different devpts instances - you could have a single
/dev/ptmx node, and then have multiple mount namespaces with their own
instances of devpts mounted on /dev/pts/. And that's all perfectly sane
in a model where we just look up the pts instance at open time.
This will eventually allow us to get rid of our odd single-vs-multiple
pts instance model, but this patch in itself changes no semantics, only
an internal binding model.
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Peter Anvin <hpa@zytor.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Peter Hurley <peter@hurleysoftware.com>
Cc: Serge Hallyn <serge.hallyn@ubuntu.com>
Cc: Willy Tarreau <w@1wt.eu>
Cc: Aurelien Jarno <aurelien@aurel32.net>
Cc: Alan Cox <gnomes@lxorguk.ukuu.org.uk>
Cc: Jann Horn <jann@thejh.net>
Cc: Greg KH <greg@kroah.com>
Cc: Jiri Slaby <jslaby@suse.com>
Cc: Florian Weimer <fw@deneb.enyo.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-17 05:16:07 +07:00
|
|
|
struct pts_fs_info *fsi;
|
2008-10-13 16:41:42 +07:00
|
|
|
struct tty_struct *tty;
|
2017-06-03 21:15:15 +07:00
|
|
|
struct path *pts_path;
|
2016-04-26 10:04:08 +07:00
|
|
|
struct dentry *dentry;
|
pty: fix the cached path of the pty slave file descriptor in the master
Christian Brauner reported that if you use the TIOCGPTPEER ioctl() to
get a slave pty file descriptor, the resulting file descriptor doesn't
look right in /proc/<pid>/fd/<fd>. In particular, he wanted to use
readlink() on /proc/self/fd/<fd> to get the pathname of the slave pty
(basically implementing "ptsname{_r}()").
The reason for that was that we had generated the wrong 'struct path'
when we create the pty in ptmx_open().
In particular, the dentry was correct, but the vfsmount pointed to the
mount of the ptmx node. That _can_ be correct - in case you use
"/dev/pts/ptmx" to open the master - but usually is not. The normal
case is to use /dev/ptmx, which then looks up the pts/ directory, and
then the vfsmount of the ptmx node is obviously the /dev directory, not
the /dev/pts/ directory.
We actually did have the right vfsmount available, but in the wrong
place (it gets looked up in 'devpts_acquire()' when we get a reference
to the pts filesystem), and so ptmx_open() used the wrong mnt pointer.
The end result of this confusion was that the pty worked fine, but when
if you did TIOCGPTPEER to get the slave side of the pty, end end result
would also work, but have that dodgy 'struct path'.
And then when doing "d_path()" on to get the pathname, the vfsmount
would not match the root of the pts directory, and d_path() would return
an empty pathname thinking that the entry had escaped a bind mount into
another mount.
This fixes the problem by making devpts_acquire() return the vfsmount
for the pts filesystem, allowing ptmx_open() to trivially just use the
right mount for the pts dentry, and create the proper 'struct path'.
Reported-by: Christian Brauner <christian.brauner@ubuntu.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Acked-by: Eric Biederman <ebiederm@xmission.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2017-08-17 07:08:07 +07:00
|
|
|
struct vfsmount *mnt;
|
2008-10-13 16:41:42 +07:00
|
|
|
int retval;
|
|
|
|
int index;
|
|
|
|
|
|
|
|
nonseekable_open(inode, filp);
|
|
|
|
|
2013-05-01 21:32:21 +07:00
|
|
|
/* We refuse fsnotify events on ptmx, since it's a shared resource */
|
|
|
|
filp->f_mode |= FMODE_NONOTIFY;
|
|
|
|
|
2011-10-12 16:32:43 +07:00
|
|
|
retval = tty_alloc_file(filp);
|
|
|
|
if (retval)
|
|
|
|
return retval;
|
|
|
|
|
pty: fix the cached path of the pty slave file descriptor in the master
Christian Brauner reported that if you use the TIOCGPTPEER ioctl() to
get a slave pty file descriptor, the resulting file descriptor doesn't
look right in /proc/<pid>/fd/<fd>. In particular, he wanted to use
readlink() on /proc/self/fd/<fd> to get the pathname of the slave pty
(basically implementing "ptsname{_r}()").
The reason for that was that we had generated the wrong 'struct path'
when we create the pty in ptmx_open().
In particular, the dentry was correct, but the vfsmount pointed to the
mount of the ptmx node. That _can_ be correct - in case you use
"/dev/pts/ptmx" to open the master - but usually is not. The normal
case is to use /dev/ptmx, which then looks up the pts/ directory, and
then the vfsmount of the ptmx node is obviously the /dev directory, not
the /dev/pts/ directory.
We actually did have the right vfsmount available, but in the wrong
place (it gets looked up in 'devpts_acquire()' when we get a reference
to the pts filesystem), and so ptmx_open() used the wrong mnt pointer.
The end result of this confusion was that the pty worked fine, but when
if you did TIOCGPTPEER to get the slave side of the pty, end end result
would also work, but have that dodgy 'struct path'.
And then when doing "d_path()" on to get the pathname, the vfsmount
would not match the root of the pts directory, and d_path() would return
an empty pathname thinking that the entry had escaped a bind mount into
another mount.
This fixes the problem by making devpts_acquire() return the vfsmount
for the pts filesystem, allowing ptmx_open() to trivially just use the
right mount for the pts dentry, and create the proper 'struct path'.
Reported-by: Christian Brauner <christian.brauner@ubuntu.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Acked-by: Eric Biederman <ebiederm@xmission.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2017-08-17 07:08:07 +07:00
|
|
|
fsi = devpts_acquire(filp, &mnt);
|
devpts: Make each mount of devpts an independent filesystem.
The /dev/ptmx device node is changed to lookup the directory entry "pts"
in the same directory as the /dev/ptmx device node was opened in. If
there is a "pts" entry and that entry is a devpts filesystem /dev/ptmx
uses that filesystem. Otherwise the open of /dev/ptmx fails.
The DEVPTS_MULTIPLE_INSTANCES configuration option is removed, so that
userspace can now safely depend on each mount of devpts creating a new
instance of the filesystem.
Each mount of devpts is now a separate and equal filesystem.
Reserved ttys are now available to all instances of devpts where the
mounter is in the initial mount namespace.
A new vfs helper path_pts is introduced that finds a directory entry
named "pts" in the directory of the passed in path, and changes the
passed in path to point to it. The helper path_pts uses a function
path_parent_directory that was factored out of follow_dotdot.
In the implementation of devpts:
- devpts_mnt is killed as it is no longer meaningful if all mounts of
devpts are equal.
- pts_sb_from_inode is replaced by just inode->i_sb as all cached
inodes in the tty layer are now from the devpts filesystem.
- devpts_add_ref is rolled into the new function devpts_ptmx. And the
unnecessary inode hold is removed.
- devpts_del_ref is renamed devpts_release and reduced to just a
deacrivate_super.
- The newinstance mount option continues to be accepted but is now
ignored.
In devpts_fs.h definitions for when !CONFIG_UNIX98_PTYS are removed as
they are never used.
Documentation/filesystems/devices.txt is updated to describe the current
situation.
This has been verified to work properly on openwrt-15.05, centos5,
centos6, centos7, debian-6.0.2, debian-7.9, debian-8.2, ubuntu-14.04.3,
ubuntu-15.10, fedora23, magia-5, mint-17.3, opensuse-42.1,
slackware-14.1, gentoo-20151225 (13.0?), archlinux-2015-12-01. With the
caveat that on centos6 and on slackware-14.1 that there wind up being
two instances of the devpts filesystem mounted on /dev/pts, the lower
copy does not end up getting used.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Greg KH <greg@kroah.com>
Cc: Peter Hurley <peter@hurleysoftware.com>
Cc: Peter Anvin <hpa@zytor.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Serge Hallyn <serge.hallyn@ubuntu.com>
Cc: Willy Tarreau <w@1wt.eu>
Cc: Aurelien Jarno <aurelien@aurel32.net>
Cc: One Thousand Gnomes <gnomes@lxorguk.ukuu.org.uk>
Cc: Jann Horn <jann@thejh.net>
Cc: Jiri Slaby <jslaby@suse.com>
Cc: Florian Weimer <fw@deneb.enyo.de>
Cc: Konstantin Khlebnikov <koct9i@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-06-02 22:29:47 +07:00
|
|
|
if (IS_ERR(fsi)) {
|
|
|
|
retval = PTR_ERR(fsi);
|
devpts: clean up interface to pty drivers
This gets rid of the horrible notion of having that
struct inode *ptmx_inode
be the linchpin of the interface between the pty code and devpts.
By de-emphasizing the ptmx inode, a lot of things actually get cleaner,
and we will have a much saner way forward. In particular, this will
allow us to associate with any particular devpts instance at open-time,
and not be artificially tied to one particular ptmx inode.
The patch itself is actually fairly straightforward, and apart from some
locking and return path cleanups it's pretty mechanical:
- the interfaces that devpts exposes all take "struct pts_fs_info *"
instead of "struct inode *ptmx_inode" now.
NOTE! The "struct pts_fs_info" thing is a completely opaque structure
as far as the pty driver is concerned: it's still declared entirely
internally to devpts. So the pty code can't actually access it in any
way, just pass it as a "cookie" to the devpts code.
- the "look up the pts fs info" is now a single clear operation, that
also does the reference count increment on the pts superblock.
So "devpts_add/del_ref()" is gone, and replaced by a "lookup and get
ref" operation (devpts_get_ref(inode)), along with a "put ref" op
(devpts_put_ref()).
- the pty master "tty->driver_data" field now contains the pts_fs_info,
not the ptmx inode.
- because we don't care about the ptmx inode any more as some kind of
base index, the ref counting can now drop the inode games - it just
gets the ref on the superblock.
- the pts_fs_info now has a back-pointer to the super_block. That's so
that we can easily look up the information we actually need. Although
quite often, the pts fs info was actually all we wanted, and not having
to look it up based on some magical inode makes things more
straightforward.
In particular, now that "devpts_get_ref(inode)" operation should really
be the *only* place we need to look up what devpts instance we're
associated with, and we do it exactly once, at ptmx_open() time.
The other side of this is that one ptmx node could now be associated
with multiple different devpts instances - you could have a single
/dev/ptmx node, and then have multiple mount namespaces with their own
instances of devpts mounted on /dev/pts/. And that's all perfectly sane
in a model where we just look up the pts instance at open time.
This will eventually allow us to get rid of our odd single-vs-multiple
pts instance model, but this patch in itself changes no semantics, only
an internal binding model.
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Peter Anvin <hpa@zytor.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Peter Hurley <peter@hurleysoftware.com>
Cc: Serge Hallyn <serge.hallyn@ubuntu.com>
Cc: Willy Tarreau <w@1wt.eu>
Cc: Aurelien Jarno <aurelien@aurel32.net>
Cc: Alan Cox <gnomes@lxorguk.ukuu.org.uk>
Cc: Jann Horn <jann@thejh.net>
Cc: Greg KH <greg@kroah.com>
Cc: Jiri Slaby <jslaby@suse.com>
Cc: Florian Weimer <fw@deneb.enyo.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-17 05:16:07 +07:00
|
|
|
goto out_free_file;
|
devpts: Make each mount of devpts an independent filesystem.
The /dev/ptmx device node is changed to lookup the directory entry "pts"
in the same directory as the /dev/ptmx device node was opened in. If
there is a "pts" entry and that entry is a devpts filesystem /dev/ptmx
uses that filesystem. Otherwise the open of /dev/ptmx fails.
The DEVPTS_MULTIPLE_INSTANCES configuration option is removed, so that
userspace can now safely depend on each mount of devpts creating a new
instance of the filesystem.
Each mount of devpts is now a separate and equal filesystem.
Reserved ttys are now available to all instances of devpts where the
mounter is in the initial mount namespace.
A new vfs helper path_pts is introduced that finds a directory entry
named "pts" in the directory of the passed in path, and changes the
passed in path to point to it. The helper path_pts uses a function
path_parent_directory that was factored out of follow_dotdot.
In the implementation of devpts:
- devpts_mnt is killed as it is no longer meaningful if all mounts of
devpts are equal.
- pts_sb_from_inode is replaced by just inode->i_sb as all cached
inodes in the tty layer are now from the devpts filesystem.
- devpts_add_ref is rolled into the new function devpts_ptmx. And the
unnecessary inode hold is removed.
- devpts_del_ref is renamed devpts_release and reduced to just a
deacrivate_super.
- The newinstance mount option continues to be accepted but is now
ignored.
In devpts_fs.h definitions for when !CONFIG_UNIX98_PTYS are removed as
they are never used.
Documentation/filesystems/devices.txt is updated to describe the current
situation.
This has been verified to work properly on openwrt-15.05, centos5,
centos6, centos7, debian-6.0.2, debian-7.9, debian-8.2, ubuntu-14.04.3,
ubuntu-15.10, fedora23, magia-5, mint-17.3, opensuse-42.1,
slackware-14.1, gentoo-20151225 (13.0?), archlinux-2015-12-01. With the
caveat that on centos6 and on slackware-14.1 that there wind up being
two instances of the devpts filesystem mounted on /dev/pts, the lower
copy does not end up getting used.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Greg KH <greg@kroah.com>
Cc: Peter Hurley <peter@hurleysoftware.com>
Cc: Peter Anvin <hpa@zytor.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Serge Hallyn <serge.hallyn@ubuntu.com>
Cc: Willy Tarreau <w@1wt.eu>
Cc: Aurelien Jarno <aurelien@aurel32.net>
Cc: One Thousand Gnomes <gnomes@lxorguk.ukuu.org.uk>
Cc: Jann Horn <jann@thejh.net>
Cc: Jiri Slaby <jslaby@suse.com>
Cc: Florian Weimer <fw@deneb.enyo.de>
Cc: Konstantin Khlebnikov <koct9i@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-06-02 22:29:47 +07:00
|
|
|
}
|
devpts: clean up interface to pty drivers
This gets rid of the horrible notion of having that
struct inode *ptmx_inode
be the linchpin of the interface between the pty code and devpts.
By de-emphasizing the ptmx inode, a lot of things actually get cleaner,
and we will have a much saner way forward. In particular, this will
allow us to associate with any particular devpts instance at open-time,
and not be artificially tied to one particular ptmx inode.
The patch itself is actually fairly straightforward, and apart from some
locking and return path cleanups it's pretty mechanical:
- the interfaces that devpts exposes all take "struct pts_fs_info *"
instead of "struct inode *ptmx_inode" now.
NOTE! The "struct pts_fs_info" thing is a completely opaque structure
as far as the pty driver is concerned: it's still declared entirely
internally to devpts. So the pty code can't actually access it in any
way, just pass it as a "cookie" to the devpts code.
- the "look up the pts fs info" is now a single clear operation, that
also does the reference count increment on the pts superblock.
So "devpts_add/del_ref()" is gone, and replaced by a "lookup and get
ref" operation (devpts_get_ref(inode)), along with a "put ref" op
(devpts_put_ref()).
- the pty master "tty->driver_data" field now contains the pts_fs_info,
not the ptmx inode.
- because we don't care about the ptmx inode any more as some kind of
base index, the ref counting can now drop the inode games - it just
gets the ref on the superblock.
- the pts_fs_info now has a back-pointer to the super_block. That's so
that we can easily look up the information we actually need. Although
quite often, the pts fs info was actually all we wanted, and not having
to look it up based on some magical inode makes things more
straightforward.
In particular, now that "devpts_get_ref(inode)" operation should really
be the *only* place we need to look up what devpts instance we're
associated with, and we do it exactly once, at ptmx_open() time.
The other side of this is that one ptmx node could now be associated
with multiple different devpts instances - you could have a single
/dev/ptmx node, and then have multiple mount namespaces with their own
instances of devpts mounted on /dev/pts/. And that's all perfectly sane
in a model where we just look up the pts instance at open time.
This will eventually allow us to get rid of our odd single-vs-multiple
pts instance model, but this patch in itself changes no semantics, only
an internal binding model.
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Peter Anvin <hpa@zytor.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Peter Hurley <peter@hurleysoftware.com>
Cc: Serge Hallyn <serge.hallyn@ubuntu.com>
Cc: Willy Tarreau <w@1wt.eu>
Cc: Aurelien Jarno <aurelien@aurel32.net>
Cc: Alan Cox <gnomes@lxorguk.ukuu.org.uk>
Cc: Jann Horn <jann@thejh.net>
Cc: Greg KH <greg@kroah.com>
Cc: Jiri Slaby <jslaby@suse.com>
Cc: Florian Weimer <fw@deneb.enyo.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-17 05:16:07 +07:00
|
|
|
|
2008-10-13 16:41:42 +07:00
|
|
|
/* find a device that is not in use. */
|
2012-08-08 22:30:13 +07:00
|
|
|
mutex_lock(&devpts_mutex);
|
devpts: clean up interface to pty drivers
This gets rid of the horrible notion of having that
struct inode *ptmx_inode
be the linchpin of the interface between the pty code and devpts.
By de-emphasizing the ptmx inode, a lot of things actually get cleaner,
and we will have a much saner way forward. In particular, this will
allow us to associate with any particular devpts instance at open-time,
and not be artificially tied to one particular ptmx inode.
The patch itself is actually fairly straightforward, and apart from some
locking and return path cleanups it's pretty mechanical:
- the interfaces that devpts exposes all take "struct pts_fs_info *"
instead of "struct inode *ptmx_inode" now.
NOTE! The "struct pts_fs_info" thing is a completely opaque structure
as far as the pty driver is concerned: it's still declared entirely
internally to devpts. So the pty code can't actually access it in any
way, just pass it as a "cookie" to the devpts code.
- the "look up the pts fs info" is now a single clear operation, that
also does the reference count increment on the pts superblock.
So "devpts_add/del_ref()" is gone, and replaced by a "lookup and get
ref" operation (devpts_get_ref(inode)), along with a "put ref" op
(devpts_put_ref()).
- the pty master "tty->driver_data" field now contains the pts_fs_info,
not the ptmx inode.
- because we don't care about the ptmx inode any more as some kind of
base index, the ref counting can now drop the inode games - it just
gets the ref on the superblock.
- the pts_fs_info now has a back-pointer to the super_block. That's so
that we can easily look up the information we actually need. Although
quite often, the pts fs info was actually all we wanted, and not having
to look it up based on some magical inode makes things more
straightforward.
In particular, now that "devpts_get_ref(inode)" operation should really
be the *only* place we need to look up what devpts instance we're
associated with, and we do it exactly once, at ptmx_open() time.
The other side of this is that one ptmx node could now be associated
with multiple different devpts instances - you could have a single
/dev/ptmx node, and then have multiple mount namespaces with their own
instances of devpts mounted on /dev/pts/. And that's all perfectly sane
in a model where we just look up the pts instance at open time.
This will eventually allow us to get rid of our odd single-vs-multiple
pts instance model, but this patch in itself changes no semantics, only
an internal binding model.
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Peter Anvin <hpa@zytor.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Peter Hurley <peter@hurleysoftware.com>
Cc: Serge Hallyn <serge.hallyn@ubuntu.com>
Cc: Willy Tarreau <w@1wt.eu>
Cc: Aurelien Jarno <aurelien@aurel32.net>
Cc: Alan Cox <gnomes@lxorguk.ukuu.org.uk>
Cc: Jann Horn <jann@thejh.net>
Cc: Greg KH <greg@kroah.com>
Cc: Jiri Slaby <jslaby@suse.com>
Cc: Florian Weimer <fw@deneb.enyo.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-17 05:16:07 +07:00
|
|
|
index = devpts_new_index(fsi);
|
2012-08-08 22:30:13 +07:00
|
|
|
mutex_unlock(&devpts_mutex);
|
|
|
|
|
devpts: clean up interface to pty drivers
This gets rid of the horrible notion of having that
struct inode *ptmx_inode
be the linchpin of the interface between the pty code and devpts.
By de-emphasizing the ptmx inode, a lot of things actually get cleaner,
and we will have a much saner way forward. In particular, this will
allow us to associate with any particular devpts instance at open-time,
and not be artificially tied to one particular ptmx inode.
The patch itself is actually fairly straightforward, and apart from some
locking and return path cleanups it's pretty mechanical:
- the interfaces that devpts exposes all take "struct pts_fs_info *"
instead of "struct inode *ptmx_inode" now.
NOTE! The "struct pts_fs_info" thing is a completely opaque structure
as far as the pty driver is concerned: it's still declared entirely
internally to devpts. So the pty code can't actually access it in any
way, just pass it as a "cookie" to the devpts code.
- the "look up the pts fs info" is now a single clear operation, that
also does the reference count increment on the pts superblock.
So "devpts_add/del_ref()" is gone, and replaced by a "lookup and get
ref" operation (devpts_get_ref(inode)), along with a "put ref" op
(devpts_put_ref()).
- the pty master "tty->driver_data" field now contains the pts_fs_info,
not the ptmx inode.
- because we don't care about the ptmx inode any more as some kind of
base index, the ref counting can now drop the inode games - it just
gets the ref on the superblock.
- the pts_fs_info now has a back-pointer to the super_block. That's so
that we can easily look up the information we actually need. Although
quite often, the pts fs info was actually all we wanted, and not having
to look it up based on some magical inode makes things more
straightforward.
In particular, now that "devpts_get_ref(inode)" operation should really
be the *only* place we need to look up what devpts instance we're
associated with, and we do it exactly once, at ptmx_open() time.
The other side of this is that one ptmx node could now be associated
with multiple different devpts instances - you could have a single
/dev/ptmx node, and then have multiple mount namespaces with their own
instances of devpts mounted on /dev/pts/. And that's all perfectly sane
in a model where we just look up the pts instance at open time.
This will eventually allow us to get rid of our odd single-vs-multiple
pts instance model, but this patch in itself changes no semantics, only
an internal binding model.
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Peter Anvin <hpa@zytor.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Peter Hurley <peter@hurleysoftware.com>
Cc: Serge Hallyn <serge.hallyn@ubuntu.com>
Cc: Willy Tarreau <w@1wt.eu>
Cc: Aurelien Jarno <aurelien@aurel32.net>
Cc: Alan Cox <gnomes@lxorguk.ukuu.org.uk>
Cc: Jann Horn <jann@thejh.net>
Cc: Greg KH <greg@kroah.com>
Cc: Jiri Slaby <jslaby@suse.com>
Cc: Florian Weimer <fw@deneb.enyo.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-17 05:16:07 +07:00
|
|
|
retval = index;
|
|
|
|
if (index < 0)
|
devpts: Make each mount of devpts an independent filesystem.
The /dev/ptmx device node is changed to lookup the directory entry "pts"
in the same directory as the /dev/ptmx device node was opened in. If
there is a "pts" entry and that entry is a devpts filesystem /dev/ptmx
uses that filesystem. Otherwise the open of /dev/ptmx fails.
The DEVPTS_MULTIPLE_INSTANCES configuration option is removed, so that
userspace can now safely depend on each mount of devpts creating a new
instance of the filesystem.
Each mount of devpts is now a separate and equal filesystem.
Reserved ttys are now available to all instances of devpts where the
mounter is in the initial mount namespace.
A new vfs helper path_pts is introduced that finds a directory entry
named "pts" in the directory of the passed in path, and changes the
passed in path to point to it. The helper path_pts uses a function
path_parent_directory that was factored out of follow_dotdot.
In the implementation of devpts:
- devpts_mnt is killed as it is no longer meaningful if all mounts of
devpts are equal.
- pts_sb_from_inode is replaced by just inode->i_sb as all cached
inodes in the tty layer are now from the devpts filesystem.
- devpts_add_ref is rolled into the new function devpts_ptmx. And the
unnecessary inode hold is removed.
- devpts_del_ref is renamed devpts_release and reduced to just a
deacrivate_super.
- The newinstance mount option continues to be accepted but is now
ignored.
In devpts_fs.h definitions for when !CONFIG_UNIX98_PTYS are removed as
they are never used.
Documentation/filesystems/devices.txt is updated to describe the current
situation.
This has been verified to work properly on openwrt-15.05, centos5,
centos6, centos7, debian-6.0.2, debian-7.9, debian-8.2, ubuntu-14.04.3,
ubuntu-15.10, fedora23, magia-5, mint-17.3, opensuse-42.1,
slackware-14.1, gentoo-20151225 (13.0?), archlinux-2015-12-01. With the
caveat that on centos6 and on slackware-14.1 that there wind up being
two instances of the devpts filesystem mounted on /dev/pts, the lower
copy does not end up getting used.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Greg KH <greg@kroah.com>
Cc: Peter Hurley <peter@hurleysoftware.com>
Cc: Peter Anvin <hpa@zytor.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Serge Hallyn <serge.hallyn@ubuntu.com>
Cc: Willy Tarreau <w@1wt.eu>
Cc: Aurelien Jarno <aurelien@aurel32.net>
Cc: One Thousand Gnomes <gnomes@lxorguk.ukuu.org.uk>
Cc: Jann Horn <jann@thejh.net>
Cc: Jiri Slaby <jslaby@suse.com>
Cc: Florian Weimer <fw@deneb.enyo.de>
Cc: Konstantin Khlebnikov <koct9i@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-06-02 22:29:47 +07:00
|
|
|
goto out_put_fsi;
|
2008-10-13 16:41:42 +07:00
|
|
|
|
|
|
|
|
devpts: clean up interface to pty drivers
This gets rid of the horrible notion of having that
struct inode *ptmx_inode
be the linchpin of the interface between the pty code and devpts.
By de-emphasizing the ptmx inode, a lot of things actually get cleaner,
and we will have a much saner way forward. In particular, this will
allow us to associate with any particular devpts instance at open-time,
and not be artificially tied to one particular ptmx inode.
The patch itself is actually fairly straightforward, and apart from some
locking and return path cleanups it's pretty mechanical:
- the interfaces that devpts exposes all take "struct pts_fs_info *"
instead of "struct inode *ptmx_inode" now.
NOTE! The "struct pts_fs_info" thing is a completely opaque structure
as far as the pty driver is concerned: it's still declared entirely
internally to devpts. So the pty code can't actually access it in any
way, just pass it as a "cookie" to the devpts code.
- the "look up the pts fs info" is now a single clear operation, that
also does the reference count increment on the pts superblock.
So "devpts_add/del_ref()" is gone, and replaced by a "lookup and get
ref" operation (devpts_get_ref(inode)), along with a "put ref" op
(devpts_put_ref()).
- the pty master "tty->driver_data" field now contains the pts_fs_info,
not the ptmx inode.
- because we don't care about the ptmx inode any more as some kind of
base index, the ref counting can now drop the inode games - it just
gets the ref on the superblock.
- the pts_fs_info now has a back-pointer to the super_block. That's so
that we can easily look up the information we actually need. Although
quite often, the pts fs info was actually all we wanted, and not having
to look it up based on some magical inode makes things more
straightforward.
In particular, now that "devpts_get_ref(inode)" operation should really
be the *only* place we need to look up what devpts instance we're
associated with, and we do it exactly once, at ptmx_open() time.
The other side of this is that one ptmx node could now be associated
with multiple different devpts instances - you could have a single
/dev/ptmx node, and then have multiple mount namespaces with their own
instances of devpts mounted on /dev/pts/. And that's all perfectly sane
in a model where we just look up the pts instance at open time.
This will eventually allow us to get rid of our odd single-vs-multiple
pts instance model, but this patch in itself changes no semantics, only
an internal binding model.
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Peter Anvin <hpa@zytor.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Peter Hurley <peter@hurleysoftware.com>
Cc: Serge Hallyn <serge.hallyn@ubuntu.com>
Cc: Willy Tarreau <w@1wt.eu>
Cc: Aurelien Jarno <aurelien@aurel32.net>
Cc: Alan Cox <gnomes@lxorguk.ukuu.org.uk>
Cc: Jann Horn <jann@thejh.net>
Cc: Greg KH <greg@kroah.com>
Cc: Jiri Slaby <jslaby@suse.com>
Cc: Florian Weimer <fw@deneb.enyo.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-17 05:16:07 +07:00
|
|
|
mutex_lock(&tty_mutex);
|
|
|
|
tty = tty_init_dev(ptm_driver, index);
|
2012-08-08 22:30:13 +07:00
|
|
|
/* The tty returned here is locked so we can safely
|
|
|
|
drop the mutex */
|
|
|
|
mutex_unlock(&tty_mutex);
|
|
|
|
|
devpts: clean up interface to pty drivers
This gets rid of the horrible notion of having that
struct inode *ptmx_inode
be the linchpin of the interface between the pty code and devpts.
By de-emphasizing the ptmx inode, a lot of things actually get cleaner,
and we will have a much saner way forward. In particular, this will
allow us to associate with any particular devpts instance at open-time,
and not be artificially tied to one particular ptmx inode.
The patch itself is actually fairly straightforward, and apart from some
locking and return path cleanups it's pretty mechanical:
- the interfaces that devpts exposes all take "struct pts_fs_info *"
instead of "struct inode *ptmx_inode" now.
NOTE! The "struct pts_fs_info" thing is a completely opaque structure
as far as the pty driver is concerned: it's still declared entirely
internally to devpts. So the pty code can't actually access it in any
way, just pass it as a "cookie" to the devpts code.
- the "look up the pts fs info" is now a single clear operation, that
also does the reference count increment on the pts superblock.
So "devpts_add/del_ref()" is gone, and replaced by a "lookup and get
ref" operation (devpts_get_ref(inode)), along with a "put ref" op
(devpts_put_ref()).
- the pty master "tty->driver_data" field now contains the pts_fs_info,
not the ptmx inode.
- because we don't care about the ptmx inode any more as some kind of
base index, the ref counting can now drop the inode games - it just
gets the ref on the superblock.
- the pts_fs_info now has a back-pointer to the super_block. That's so
that we can easily look up the information we actually need. Although
quite often, the pts fs info was actually all we wanted, and not having
to look it up based on some magical inode makes things more
straightforward.
In particular, now that "devpts_get_ref(inode)" operation should really
be the *only* place we need to look up what devpts instance we're
associated with, and we do it exactly once, at ptmx_open() time.
The other side of this is that one ptmx node could now be associated
with multiple different devpts instances - you could have a single
/dev/ptmx node, and then have multiple mount namespaces with their own
instances of devpts mounted on /dev/pts/. And that's all perfectly sane
in a model where we just look up the pts instance at open time.
This will eventually allow us to get rid of our odd single-vs-multiple
pts instance model, but this patch in itself changes no semantics, only
an internal binding model.
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Peter Anvin <hpa@zytor.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Peter Hurley <peter@hurleysoftware.com>
Cc: Serge Hallyn <serge.hallyn@ubuntu.com>
Cc: Willy Tarreau <w@1wt.eu>
Cc: Aurelien Jarno <aurelien@aurel32.net>
Cc: Alan Cox <gnomes@lxorguk.ukuu.org.uk>
Cc: Jann Horn <jann@thejh.net>
Cc: Greg KH <greg@kroah.com>
Cc: Jiri Slaby <jslaby@suse.com>
Cc: Florian Weimer <fw@deneb.enyo.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-17 05:16:07 +07:00
|
|
|
retval = PTR_ERR(tty);
|
|
|
|
if (IS_ERR(tty))
|
|
|
|
goto out;
|
2010-08-18 01:37:35 +07:00
|
|
|
|
2016-01-11 21:07:43 +07:00
|
|
|
/*
|
devpts: clean up interface to pty drivers
This gets rid of the horrible notion of having that
struct inode *ptmx_inode
be the linchpin of the interface between the pty code and devpts.
By de-emphasizing the ptmx inode, a lot of things actually get cleaner,
and we will have a much saner way forward. In particular, this will
allow us to associate with any particular devpts instance at open-time,
and not be artificially tied to one particular ptmx inode.
The patch itself is actually fairly straightforward, and apart from some
locking and return path cleanups it's pretty mechanical:
- the interfaces that devpts exposes all take "struct pts_fs_info *"
instead of "struct inode *ptmx_inode" now.
NOTE! The "struct pts_fs_info" thing is a completely opaque structure
as far as the pty driver is concerned: it's still declared entirely
internally to devpts. So the pty code can't actually access it in any
way, just pass it as a "cookie" to the devpts code.
- the "look up the pts fs info" is now a single clear operation, that
also does the reference count increment on the pts superblock.
So "devpts_add/del_ref()" is gone, and replaced by a "lookup and get
ref" operation (devpts_get_ref(inode)), along with a "put ref" op
(devpts_put_ref()).
- the pty master "tty->driver_data" field now contains the pts_fs_info,
not the ptmx inode.
- because we don't care about the ptmx inode any more as some kind of
base index, the ref counting can now drop the inode games - it just
gets the ref on the superblock.
- the pts_fs_info now has a back-pointer to the super_block. That's so
that we can easily look up the information we actually need. Although
quite often, the pts fs info was actually all we wanted, and not having
to look it up based on some magical inode makes things more
straightforward.
In particular, now that "devpts_get_ref(inode)" operation should really
be the *only* place we need to look up what devpts instance we're
associated with, and we do it exactly once, at ptmx_open() time.
The other side of this is that one ptmx node could now be associated
with multiple different devpts instances - you could have a single
/dev/ptmx node, and then have multiple mount namespaces with their own
instances of devpts mounted on /dev/pts/. And that's all perfectly sane
in a model where we just look up the pts instance at open time.
This will eventually allow us to get rid of our odd single-vs-multiple
pts instance model, but this patch in itself changes no semantics, only
an internal binding model.
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Peter Anvin <hpa@zytor.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Peter Hurley <peter@hurleysoftware.com>
Cc: Serge Hallyn <serge.hallyn@ubuntu.com>
Cc: Willy Tarreau <w@1wt.eu>
Cc: Aurelien Jarno <aurelien@aurel32.net>
Cc: Alan Cox <gnomes@lxorguk.ukuu.org.uk>
Cc: Jann Horn <jann@thejh.net>
Cc: Greg KH <greg@kroah.com>
Cc: Jiri Slaby <jslaby@suse.com>
Cc: Florian Weimer <fw@deneb.enyo.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-17 05:16:07 +07:00
|
|
|
* From here on out, the tty is "live", and the index and
|
|
|
|
* fsi will be killed/put by the tty_release()
|
2016-01-11 21:07:43 +07:00
|
|
|
*/
|
devpts: clean up interface to pty drivers
This gets rid of the horrible notion of having that
struct inode *ptmx_inode
be the linchpin of the interface between the pty code and devpts.
By de-emphasizing the ptmx inode, a lot of things actually get cleaner,
and we will have a much saner way forward. In particular, this will
allow us to associate with any particular devpts instance at open-time,
and not be artificially tied to one particular ptmx inode.
The patch itself is actually fairly straightforward, and apart from some
locking and return path cleanups it's pretty mechanical:
- the interfaces that devpts exposes all take "struct pts_fs_info *"
instead of "struct inode *ptmx_inode" now.
NOTE! The "struct pts_fs_info" thing is a completely opaque structure
as far as the pty driver is concerned: it's still declared entirely
internally to devpts. So the pty code can't actually access it in any
way, just pass it as a "cookie" to the devpts code.
- the "look up the pts fs info" is now a single clear operation, that
also does the reference count increment on the pts superblock.
So "devpts_add/del_ref()" is gone, and replaced by a "lookup and get
ref" operation (devpts_get_ref(inode)), along with a "put ref" op
(devpts_put_ref()).
- the pty master "tty->driver_data" field now contains the pts_fs_info,
not the ptmx inode.
- because we don't care about the ptmx inode any more as some kind of
base index, the ref counting can now drop the inode games - it just
gets the ref on the superblock.
- the pts_fs_info now has a back-pointer to the super_block. That's so
that we can easily look up the information we actually need. Although
quite often, the pts fs info was actually all we wanted, and not having
to look it up based on some magical inode makes things more
straightforward.
In particular, now that "devpts_get_ref(inode)" operation should really
be the *only* place we need to look up what devpts instance we're
associated with, and we do it exactly once, at ptmx_open() time.
The other side of this is that one ptmx node could now be associated
with multiple different devpts instances - you could have a single
/dev/ptmx node, and then have multiple mount namespaces with their own
instances of devpts mounted on /dev/pts/. And that's all perfectly sane
in a model where we just look up the pts instance at open time.
This will eventually allow us to get rid of our odd single-vs-multiple
pts instance model, but this patch in itself changes no semantics, only
an internal binding model.
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Peter Anvin <hpa@zytor.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Peter Hurley <peter@hurleysoftware.com>
Cc: Serge Hallyn <serge.hallyn@ubuntu.com>
Cc: Willy Tarreau <w@1wt.eu>
Cc: Aurelien Jarno <aurelien@aurel32.net>
Cc: Alan Cox <gnomes@lxorguk.ukuu.org.uk>
Cc: Jann Horn <jann@thejh.net>
Cc: Greg KH <greg@kroah.com>
Cc: Jiri Slaby <jslaby@suse.com>
Cc: Florian Weimer <fw@deneb.enyo.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-17 05:16:07 +07:00
|
|
|
set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
|
|
|
|
tty->driver_data = fsi;
|
2016-01-11 21:07:43 +07:00
|
|
|
|
2011-10-12 16:32:43 +07:00
|
|
|
tty_add_file(tty, filp);
|
2008-10-13 16:41:42 +07:00
|
|
|
|
2016-04-26 10:04:08 +07:00
|
|
|
dentry = devpts_pty_new(fsi, index, tty->link);
|
|
|
|
if (IS_ERR(dentry)) {
|
|
|
|
retval = PTR_ERR(dentry);
|
2011-10-12 16:32:44 +07:00
|
|
|
goto err_release;
|
2012-10-19 03:26:28 +07:00
|
|
|
}
|
2017-06-03 21:15:15 +07:00
|
|
|
/* We need to cache a fake path for TIOCGPTPEER. */
|
|
|
|
pts_path = kmalloc(sizeof(struct path), GFP_KERNEL);
|
|
|
|
if (!pts_path)
|
|
|
|
goto err_release;
|
pty: fix the cached path of the pty slave file descriptor in the master
Christian Brauner reported that if you use the TIOCGPTPEER ioctl() to
get a slave pty file descriptor, the resulting file descriptor doesn't
look right in /proc/<pid>/fd/<fd>. In particular, he wanted to use
readlink() on /proc/self/fd/<fd> to get the pathname of the slave pty
(basically implementing "ptsname{_r}()").
The reason for that was that we had generated the wrong 'struct path'
when we create the pty in ptmx_open().
In particular, the dentry was correct, but the vfsmount pointed to the
mount of the ptmx node. That _can_ be correct - in case you use
"/dev/pts/ptmx" to open the master - but usually is not. The normal
case is to use /dev/ptmx, which then looks up the pts/ directory, and
then the vfsmount of the ptmx node is obviously the /dev directory, not
the /dev/pts/ directory.
We actually did have the right vfsmount available, but in the wrong
place (it gets looked up in 'devpts_acquire()' when we get a reference
to the pts filesystem), and so ptmx_open() used the wrong mnt pointer.
The end result of this confusion was that the pty worked fine, but when
if you did TIOCGPTPEER to get the slave side of the pty, end end result
would also work, but have that dodgy 'struct path'.
And then when doing "d_path()" on to get the pathname, the vfsmount
would not match the root of the pts directory, and d_path() would return
an empty pathname thinking that the entry had escaped a bind mount into
another mount.
This fixes the problem by making devpts_acquire() return the vfsmount
for the pts filesystem, allowing ptmx_open() to trivially just use the
right mount for the pts dentry, and create the proper 'struct path'.
Reported-by: Christian Brauner <christian.brauner@ubuntu.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Acked-by: Eric Biederman <ebiederm@xmission.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2017-08-17 07:08:07 +07:00
|
|
|
pts_path->mnt = mnt;
|
2017-06-03 21:15:15 +07:00
|
|
|
pts_path->dentry = dentry;
|
|
|
|
path_get(pts_path);
|
|
|
|
tty->link->driver_data = pts_path;
|
2008-10-13 16:41:42 +07:00
|
|
|
|
|
|
|
retval = ptm_driver->ops->open(tty, filp);
|
2010-06-02 03:53:02 +07:00
|
|
|
if (retval)
|
2017-06-03 21:15:15 +07:00
|
|
|
goto err_path_put;
|
2011-10-12 16:32:44 +07:00
|
|
|
|
2015-11-09 01:01:19 +07:00
|
|
|
tty_debug_hangup(tty, "opening (count=%d)\n", tty->count);
|
2015-07-13 09:49:13 +07:00
|
|
|
|
2012-08-08 22:30:13 +07:00
|
|
|
tty_unlock(tty);
|
2011-10-12 16:32:44 +07:00
|
|
|
return 0;
|
2017-06-03 21:15:15 +07:00
|
|
|
err_path_put:
|
|
|
|
path_put(pts_path);
|
|
|
|
kfree(pts_path);
|
2011-10-12 16:32:44 +07:00
|
|
|
err_release:
|
pty: fix the cached path of the pty slave file descriptor in the master
Christian Brauner reported that if you use the TIOCGPTPEER ioctl() to
get a slave pty file descriptor, the resulting file descriptor doesn't
look right in /proc/<pid>/fd/<fd>. In particular, he wanted to use
readlink() on /proc/self/fd/<fd> to get the pathname of the slave pty
(basically implementing "ptsname{_r}()").
The reason for that was that we had generated the wrong 'struct path'
when we create the pty in ptmx_open().
In particular, the dentry was correct, but the vfsmount pointed to the
mount of the ptmx node. That _can_ be correct - in case you use
"/dev/pts/ptmx" to open the master - but usually is not. The normal
case is to use /dev/ptmx, which then looks up the pts/ directory, and
then the vfsmount of the ptmx node is obviously the /dev directory, not
the /dev/pts/ directory.
We actually did have the right vfsmount available, but in the wrong
place (it gets looked up in 'devpts_acquire()' when we get a reference
to the pts filesystem), and so ptmx_open() used the wrong mnt pointer.
The end result of this confusion was that the pty worked fine, but when
if you did TIOCGPTPEER to get the slave side of the pty, end end result
would also work, but have that dodgy 'struct path'.
And then when doing "d_path()" on to get the pathname, the vfsmount
would not match the root of the pts directory, and d_path() would return
an empty pathname thinking that the entry had escaped a bind mount into
another mount.
This fixes the problem by making devpts_acquire() return the vfsmount
for the pts filesystem, allowing ptmx_open() to trivially just use the
right mount for the pts dentry, and create the proper 'struct path'.
Reported-by: Christian Brauner <christian.brauner@ubuntu.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Acked-by: Eric Biederman <ebiederm@xmission.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2017-08-17 07:08:07 +07:00
|
|
|
mntput(mnt);
|
2012-08-08 22:30:13 +07:00
|
|
|
tty_unlock(tty);
|
devpts: clean up interface to pty drivers
This gets rid of the horrible notion of having that
struct inode *ptmx_inode
be the linchpin of the interface between the pty code and devpts.
By de-emphasizing the ptmx inode, a lot of things actually get cleaner,
and we will have a much saner way forward. In particular, this will
allow us to associate with any particular devpts instance at open-time,
and not be artificially tied to one particular ptmx inode.
The patch itself is actually fairly straightforward, and apart from some
locking and return path cleanups it's pretty mechanical:
- the interfaces that devpts exposes all take "struct pts_fs_info *"
instead of "struct inode *ptmx_inode" now.
NOTE! The "struct pts_fs_info" thing is a completely opaque structure
as far as the pty driver is concerned: it's still declared entirely
internally to devpts. So the pty code can't actually access it in any
way, just pass it as a "cookie" to the devpts code.
- the "look up the pts fs info" is now a single clear operation, that
also does the reference count increment on the pts superblock.
So "devpts_add/del_ref()" is gone, and replaced by a "lookup and get
ref" operation (devpts_get_ref(inode)), along with a "put ref" op
(devpts_put_ref()).
- the pty master "tty->driver_data" field now contains the pts_fs_info,
not the ptmx inode.
- because we don't care about the ptmx inode any more as some kind of
base index, the ref counting can now drop the inode games - it just
gets the ref on the superblock.
- the pts_fs_info now has a back-pointer to the super_block. That's so
that we can easily look up the information we actually need. Although
quite often, the pts fs info was actually all we wanted, and not having
to look it up based on some magical inode makes things more
straightforward.
In particular, now that "devpts_get_ref(inode)" operation should really
be the *only* place we need to look up what devpts instance we're
associated with, and we do it exactly once, at ptmx_open() time.
The other side of this is that one ptmx node could now be associated
with multiple different devpts instances - you could have a single
/dev/ptmx node, and then have multiple mount namespaces with their own
instances of devpts mounted on /dev/pts/. And that's all perfectly sane
in a model where we just look up the pts instance at open time.
This will eventually allow us to get rid of our odd single-vs-multiple
pts instance model, but this patch in itself changes no semantics, only
an internal binding model.
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Peter Anvin <hpa@zytor.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Peter Hurley <peter@hurleysoftware.com>
Cc: Serge Hallyn <serge.hallyn@ubuntu.com>
Cc: Willy Tarreau <w@1wt.eu>
Cc: Aurelien Jarno <aurelien@aurel32.net>
Cc: Alan Cox <gnomes@lxorguk.ukuu.org.uk>
Cc: Jann Horn <jann@thejh.net>
Cc: Greg KH <greg@kroah.com>
Cc: Jiri Slaby <jslaby@suse.com>
Cc: Florian Weimer <fw@deneb.enyo.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-17 05:16:07 +07:00
|
|
|
// This will also put-ref the fsi
|
2009-11-30 20:18:29 +07:00
|
|
|
tty_release(inode, filp);
|
2008-10-13 16:41:42 +07:00
|
|
|
return retval;
|
|
|
|
out:
|
devpts: clean up interface to pty drivers
This gets rid of the horrible notion of having that
struct inode *ptmx_inode
be the linchpin of the interface between the pty code and devpts.
By de-emphasizing the ptmx inode, a lot of things actually get cleaner,
and we will have a much saner way forward. In particular, this will
allow us to associate with any particular devpts instance at open-time,
and not be artificially tied to one particular ptmx inode.
The patch itself is actually fairly straightforward, and apart from some
locking and return path cleanups it's pretty mechanical:
- the interfaces that devpts exposes all take "struct pts_fs_info *"
instead of "struct inode *ptmx_inode" now.
NOTE! The "struct pts_fs_info" thing is a completely opaque structure
as far as the pty driver is concerned: it's still declared entirely
internally to devpts. So the pty code can't actually access it in any
way, just pass it as a "cookie" to the devpts code.
- the "look up the pts fs info" is now a single clear operation, that
also does the reference count increment on the pts superblock.
So "devpts_add/del_ref()" is gone, and replaced by a "lookup and get
ref" operation (devpts_get_ref(inode)), along with a "put ref" op
(devpts_put_ref()).
- the pty master "tty->driver_data" field now contains the pts_fs_info,
not the ptmx inode.
- because we don't care about the ptmx inode any more as some kind of
base index, the ref counting can now drop the inode games - it just
gets the ref on the superblock.
- the pts_fs_info now has a back-pointer to the super_block. That's so
that we can easily look up the information we actually need. Although
quite often, the pts fs info was actually all we wanted, and not having
to look it up based on some magical inode makes things more
straightforward.
In particular, now that "devpts_get_ref(inode)" operation should really
be the *only* place we need to look up what devpts instance we're
associated with, and we do it exactly once, at ptmx_open() time.
The other side of this is that one ptmx node could now be associated
with multiple different devpts instances - you could have a single
/dev/ptmx node, and then have multiple mount namespaces with their own
instances of devpts mounted on /dev/pts/. And that's all perfectly sane
in a model where we just look up the pts instance at open time.
This will eventually allow us to get rid of our odd single-vs-multiple
pts instance model, but this patch in itself changes no semantics, only
an internal binding model.
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Peter Anvin <hpa@zytor.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Peter Hurley <peter@hurleysoftware.com>
Cc: Serge Hallyn <serge.hallyn@ubuntu.com>
Cc: Willy Tarreau <w@1wt.eu>
Cc: Aurelien Jarno <aurelien@aurel32.net>
Cc: Alan Cox <gnomes@lxorguk.ukuu.org.uk>
Cc: Jann Horn <jann@thejh.net>
Cc: Greg KH <greg@kroah.com>
Cc: Jiri Slaby <jslaby@suse.com>
Cc: Florian Weimer <fw@deneb.enyo.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-17 05:16:07 +07:00
|
|
|
devpts_kill_index(fsi, index);
|
devpts: Make each mount of devpts an independent filesystem.
The /dev/ptmx device node is changed to lookup the directory entry "pts"
in the same directory as the /dev/ptmx device node was opened in. If
there is a "pts" entry and that entry is a devpts filesystem /dev/ptmx
uses that filesystem. Otherwise the open of /dev/ptmx fails.
The DEVPTS_MULTIPLE_INSTANCES configuration option is removed, so that
userspace can now safely depend on each mount of devpts creating a new
instance of the filesystem.
Each mount of devpts is now a separate and equal filesystem.
Reserved ttys are now available to all instances of devpts where the
mounter is in the initial mount namespace.
A new vfs helper path_pts is introduced that finds a directory entry
named "pts" in the directory of the passed in path, and changes the
passed in path to point to it. The helper path_pts uses a function
path_parent_directory that was factored out of follow_dotdot.
In the implementation of devpts:
- devpts_mnt is killed as it is no longer meaningful if all mounts of
devpts are equal.
- pts_sb_from_inode is replaced by just inode->i_sb as all cached
inodes in the tty layer are now from the devpts filesystem.
- devpts_add_ref is rolled into the new function devpts_ptmx. And the
unnecessary inode hold is removed.
- devpts_del_ref is renamed devpts_release and reduced to just a
deacrivate_super.
- The newinstance mount option continues to be accepted but is now
ignored.
In devpts_fs.h definitions for when !CONFIG_UNIX98_PTYS are removed as
they are never used.
Documentation/filesystems/devices.txt is updated to describe the current
situation.
This has been verified to work properly on openwrt-15.05, centos5,
centos6, centos7, debian-6.0.2, debian-7.9, debian-8.2, ubuntu-14.04.3,
ubuntu-15.10, fedora23, magia-5, mint-17.3, opensuse-42.1,
slackware-14.1, gentoo-20151225 (13.0?), archlinux-2015-12-01. With the
caveat that on centos6 and on slackware-14.1 that there wind up being
two instances of the devpts filesystem mounted on /dev/pts, the lower
copy does not end up getting used.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Greg KH <greg@kroah.com>
Cc: Peter Hurley <peter@hurleysoftware.com>
Cc: Peter Anvin <hpa@zytor.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Serge Hallyn <serge.hallyn@ubuntu.com>
Cc: Willy Tarreau <w@1wt.eu>
Cc: Aurelien Jarno <aurelien@aurel32.net>
Cc: One Thousand Gnomes <gnomes@lxorguk.ukuu.org.uk>
Cc: Jann Horn <jann@thejh.net>
Cc: Jiri Slaby <jslaby@suse.com>
Cc: Florian Weimer <fw@deneb.enyo.de>
Cc: Konstantin Khlebnikov <koct9i@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-06-02 22:29:47 +07:00
|
|
|
out_put_fsi:
|
|
|
|
devpts_release(fsi);
|
pty: fix the cached path of the pty slave file descriptor in the master
Christian Brauner reported that if you use the TIOCGPTPEER ioctl() to
get a slave pty file descriptor, the resulting file descriptor doesn't
look right in /proc/<pid>/fd/<fd>. In particular, he wanted to use
readlink() on /proc/self/fd/<fd> to get the pathname of the slave pty
(basically implementing "ptsname{_r}()").
The reason for that was that we had generated the wrong 'struct path'
when we create the pty in ptmx_open().
In particular, the dentry was correct, but the vfsmount pointed to the
mount of the ptmx node. That _can_ be correct - in case you use
"/dev/pts/ptmx" to open the master - but usually is not. The normal
case is to use /dev/ptmx, which then looks up the pts/ directory, and
then the vfsmount of the ptmx node is obviously the /dev directory, not
the /dev/pts/ directory.
We actually did have the right vfsmount available, but in the wrong
place (it gets looked up in 'devpts_acquire()' when we get a reference
to the pts filesystem), and so ptmx_open() used the wrong mnt pointer.
The end result of this confusion was that the pty worked fine, but when
if you did TIOCGPTPEER to get the slave side of the pty, end end result
would also work, but have that dodgy 'struct path'.
And then when doing "d_path()" on to get the pathname, the vfsmount
would not match the root of the pts directory, and d_path() would return
an empty pathname thinking that the entry had escaped a bind mount into
another mount.
This fixes the problem by making devpts_acquire() return the vfsmount
for the pts filesystem, allowing ptmx_open() to trivially just use the
right mount for the pts dentry, and create the proper 'struct path'.
Reported-by: Christian Brauner <christian.brauner@ubuntu.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Acked-by: Eric Biederman <ebiederm@xmission.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2017-08-17 07:08:07 +07:00
|
|
|
mntput(mnt);
|
devpts: clean up interface to pty drivers
This gets rid of the horrible notion of having that
struct inode *ptmx_inode
be the linchpin of the interface between the pty code and devpts.
By de-emphasizing the ptmx inode, a lot of things actually get cleaner,
and we will have a much saner way forward. In particular, this will
allow us to associate with any particular devpts instance at open-time,
and not be artificially tied to one particular ptmx inode.
The patch itself is actually fairly straightforward, and apart from some
locking and return path cleanups it's pretty mechanical:
- the interfaces that devpts exposes all take "struct pts_fs_info *"
instead of "struct inode *ptmx_inode" now.
NOTE! The "struct pts_fs_info" thing is a completely opaque structure
as far as the pty driver is concerned: it's still declared entirely
internally to devpts. So the pty code can't actually access it in any
way, just pass it as a "cookie" to the devpts code.
- the "look up the pts fs info" is now a single clear operation, that
also does the reference count increment on the pts superblock.
So "devpts_add/del_ref()" is gone, and replaced by a "lookup and get
ref" operation (devpts_get_ref(inode)), along with a "put ref" op
(devpts_put_ref()).
- the pty master "tty->driver_data" field now contains the pts_fs_info,
not the ptmx inode.
- because we don't care about the ptmx inode any more as some kind of
base index, the ref counting can now drop the inode games - it just
gets the ref on the superblock.
- the pts_fs_info now has a back-pointer to the super_block. That's so
that we can easily look up the information we actually need. Although
quite often, the pts fs info was actually all we wanted, and not having
to look it up based on some magical inode makes things more
straightforward.
In particular, now that "devpts_get_ref(inode)" operation should really
be the *only* place we need to look up what devpts instance we're
associated with, and we do it exactly once, at ptmx_open() time.
The other side of this is that one ptmx node could now be associated
with multiple different devpts instances - you could have a single
/dev/ptmx node, and then have multiple mount namespaces with their own
instances of devpts mounted on /dev/pts/. And that's all perfectly sane
in a model where we just look up the pts instance at open time.
This will eventually allow us to get rid of our odd single-vs-multiple
pts instance model, but this patch in itself changes no semantics, only
an internal binding model.
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Peter Anvin <hpa@zytor.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Peter Hurley <peter@hurleysoftware.com>
Cc: Serge Hallyn <serge.hallyn@ubuntu.com>
Cc: Willy Tarreau <w@1wt.eu>
Cc: Aurelien Jarno <aurelien@aurel32.net>
Cc: Alan Cox <gnomes@lxorguk.ukuu.org.uk>
Cc: Jann Horn <jann@thejh.net>
Cc: Greg KH <greg@kroah.com>
Cc: Jiri Slaby <jslaby@suse.com>
Cc: Florian Weimer <fw@deneb.enyo.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-17 05:16:07 +07:00
|
|
|
out_free_file:
|
2011-10-12 16:32:43 +07:00
|
|
|
tty_free_file(filp);
|
2010-06-02 03:53:02 +07:00
|
|
|
return retval;
|
2008-10-13 16:41:42 +07:00
|
|
|
}
|
|
|
|
|
2016-09-09 05:35:59 +07:00
|
|
|
static struct file_operations ptmx_fops __ro_after_init;
|
2008-10-13 16:41:42 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
static void __init unix98_pty_init(void)
|
|
|
|
{
|
2012-08-09 03:26:41 +07:00
|
|
|
ptm_driver = tty_alloc_driver(NR_UNIX98_PTY_MAX,
|
|
|
|
TTY_DRIVER_RESET_TERMIOS |
|
|
|
|
TTY_DRIVER_REAL_RAW |
|
|
|
|
TTY_DRIVER_DYNAMIC_DEV |
|
|
|
|
TTY_DRIVER_DEVPTS_MEM |
|
|
|
|
TTY_DRIVER_DYNAMIC_ALLOC);
|
2012-08-16 20:16:56 +07:00
|
|
|
if (IS_ERR(ptm_driver))
|
2005-04-17 05:20:36 +07:00
|
|
|
panic("Couldn't allocate Unix98 ptm driver");
|
2012-08-09 03:26:41 +07:00
|
|
|
pts_driver = tty_alloc_driver(NR_UNIX98_PTY_MAX,
|
|
|
|
TTY_DRIVER_RESET_TERMIOS |
|
|
|
|
TTY_DRIVER_REAL_RAW |
|
|
|
|
TTY_DRIVER_DYNAMIC_DEV |
|
|
|
|
TTY_DRIVER_DEVPTS_MEM |
|
|
|
|
TTY_DRIVER_DYNAMIC_ALLOC);
|
2012-08-16 20:16:56 +07:00
|
|
|
if (IS_ERR(pts_driver))
|
2005-04-17 05:20:36 +07:00
|
|
|
panic("Couldn't allocate Unix98 pts driver");
|
|
|
|
|
|
|
|
ptm_driver->driver_name = "pty_master";
|
|
|
|
ptm_driver->name = "ptm";
|
|
|
|
ptm_driver->major = UNIX98_PTY_MASTER_MAJOR;
|
|
|
|
ptm_driver->minor_start = 0;
|
|
|
|
ptm_driver->type = TTY_DRIVER_TYPE_PTY;
|
|
|
|
ptm_driver->subtype = PTY_TYPE_MASTER;
|
|
|
|
ptm_driver->init_termios = tty_std_termios;
|
|
|
|
ptm_driver->init_termios.c_iflag = 0;
|
|
|
|
ptm_driver->init_termios.c_oflag = 0;
|
|
|
|
ptm_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
|
|
|
|
ptm_driver->init_termios.c_lflag = 0;
|
2006-12-08 17:38:45 +07:00
|
|
|
ptm_driver->init_termios.c_ispeed = 38400;
|
|
|
|
ptm_driver->init_termios.c_ospeed = 38400;
|
2005-04-17 05:20:36 +07:00
|
|
|
ptm_driver->other = pts_driver;
|
2008-10-13 16:41:30 +07:00
|
|
|
tty_set_operations(ptm_driver, &ptm_unix98_ops);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
pts_driver->driver_name = "pty_slave";
|
|
|
|
pts_driver->name = "pts";
|
|
|
|
pts_driver->major = UNIX98_PTY_SLAVE_MAJOR;
|
|
|
|
pts_driver->minor_start = 0;
|
|
|
|
pts_driver->type = TTY_DRIVER_TYPE_PTY;
|
|
|
|
pts_driver->subtype = PTY_TYPE_SLAVE;
|
|
|
|
pts_driver->init_termios = tty_std_termios;
|
|
|
|
pts_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
|
2006-12-08 17:38:45 +07:00
|
|
|
pts_driver->init_termios.c_ispeed = 38400;
|
|
|
|
pts_driver->init_termios.c_ospeed = 38400;
|
2005-04-17 05:20:36 +07:00
|
|
|
pts_driver->other = ptm_driver;
|
2008-10-13 16:42:00 +07:00
|
|
|
tty_set_operations(pts_driver, &pty_unix98_ops);
|
2008-10-13 16:43:38 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
if (tty_register_driver(ptm_driver))
|
|
|
|
panic("Couldn't register Unix98 ptm driver");
|
|
|
|
if (tty_register_driver(pts_driver))
|
|
|
|
panic("Couldn't register Unix98 pts driver");
|
|
|
|
|
2008-10-13 16:41:42 +07:00
|
|
|
/* Now create the /dev/ptmx special device */
|
|
|
|
tty_default_fops(&ptmx_fops);
|
|
|
|
ptmx_fops.open = ptmx_open;
|
|
|
|
|
|
|
|
cdev_init(&ptmx_cdev, &ptmx_fops);
|
|
|
|
if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) ||
|
|
|
|
register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
|
2013-01-12 11:01:21 +07:00
|
|
|
panic("Couldn't register /dev/ptmx driver");
|
2008-10-13 16:41:42 +07:00
|
|
|
device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
2008-10-13 16:41:42 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
#else
|
|
|
|
static inline void unix98_pty_init(void) { }
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int __init pty_init(void)
|
|
|
|
{
|
|
|
|
legacy_pty_init();
|
|
|
|
unix98_pty_init();
|
|
|
|
return 0;
|
|
|
|
}
|
2015-08-20 04:48:05 +07:00
|
|
|
device_initcall(pty_init);
|