2005-04-17 06:20:36 +08: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 17:43:38 +08:00
|
|
|
#include <linux/module.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <linux/errno.h>
|
|
|
|
#include <linux/interrupt.h>
|
|
|
|
#include <linux/tty.h>
|
|
|
|
#include <linux/tty_flip.h>
|
|
|
|
#include <linux/fcntl.h>
|
2009-10-07 21:09:06 +08:00
|
|
|
#include <linux/sched.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <linux/string.h>
|
|
|
|
#include <linux/major.h>
|
|
|
|
#include <linux/mm.h>
|
|
|
|
#include <linux/init.h>
|
2008-10-13 17:41:42 +08:00
|
|
|
#include <linux/device.h>
|
2008-10-13 17:43:38 +08:00
|
|
|
#include <linux/uaccess.h>
|
2005-04-17 06:20:36 +08: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 16:04:11 +08:00
|
|
|
#include <linux/slab.h>
|
2012-05-04 05:22:09 +08:00
|
|
|
#include <linux/mutex.h>
|
2014-09-11 03:06:32 +08:00
|
|
|
#include <linux/poll.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-07-13 10:49:13 +08: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 17:43:38 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
#ifdef CONFIG_UNIX98_PTYS
|
2009-01-08 10:09:15 +08:00
|
|
|
static struct tty_driver *ptm_driver;
|
2005-04-17 06:20:36 +08:00
|
|
|
static struct tty_driver *pts_driver;
|
2012-05-04 05:22:09 +08:00
|
|
|
static DEFINE_MUTEX(devpts_mutex);
|
2005-04-17 06:20:36 +08:00
|
|
|
#endif
|
|
|
|
|
2008-10-13 17:43:38 +08:00
|
|
|
static void pty_close(struct tty_struct *tty, struct file *filp)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2008-10-13 17:43:38 +08:00
|
|
|
BUG_ON(!tty);
|
|
|
|
if (tty->driver->subtype == PTY_TYPE_MASTER)
|
|
|
|
WARN_ON(tty->count > 1);
|
|
|
|
else {
|
2013-01-31 01:43:50 +08:00
|
|
|
if (test_bit(TTY_IO_ERROR, &tty->flags))
|
|
|
|
return;
|
2005-04-17 06:20:36 +08:00
|
|
|
if (tty->count > 2)
|
|
|
|
return;
|
|
|
|
}
|
2013-01-31 01:43:50 +08:00
|
|
|
set_bit(TTY_IO_ERROR, &tty->flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
wake_up_interruptible(&tty->read_wait);
|
|
|
|
wake_up_interruptible(&tty->write_wait);
|
2014-10-17 03:33:28 +08:00
|
|
|
spin_lock_irq(&tty->ctrl_lock);
|
2005-04-17 06:20:36 +08:00
|
|
|
tty->packet = 0;
|
2014-10-17 03:33:28 +08:00
|
|
|
spin_unlock_irq(&tty->ctrl_lock);
|
2012-08-08 23:30:13 +08:00
|
|
|
/* Review - krefs on tty_link ?? */
|
2005-04-17 06:20:36 +08:00
|
|
|
if (!tty->link)
|
|
|
|
return;
|
|
|
|
set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
|
2015-04-14 01:24:34 +08:00
|
|
|
tty_flip_buffer_push(tty->link->port);
|
2005-04-17 06:20:36 +08: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 05:56:36 +08:00
|
|
|
#ifdef CONFIG_UNIX98_PTYS
|
2012-05-04 05:22:09 +08:00
|
|
|
if (tty->driver == ptm_driver) {
|
2013-01-12 12:01:22 +08:00
|
|
|
mutex_lock(&devpts_mutex);
|
pty: Fix BUG()s when ptmx_open() errors out
If pmtx_open() fails to get a slave inode or fails the pty_open(),
the tty is released as part of the error cleanup. As evidenced by the
first BUG stacktrace below, pty_close() assumes that the linked pty has
a valid, initialized inode* stored in driver_data.
Also, as evidenced by the second BUG stacktrace below, pty_unix98_shutdown()
assumes that the master pty's driver_data has been initialized.
1) Fix the invalid assumption in pty_close().
2) Initialize driver_data immediately so proper devpts fs cleanup occurs.
Fixes this BUG:
[ 815.868844] BUG: unable to handle kernel NULL pointer dereference at 0000000000000028
[ 815.869018] IP: [<ffffffff81207bcc>] devpts_pty_kill+0x1c/0xa0
[ 815.869190] PGD 7c775067 PUD 79deb067 PMD 0
[ 815.869315] Oops: 0000 [#1] PREEMPT SMP
[ 815.869443] Modules linked in: kvm_intel kvm snd_hda_intel snd_hda_codec snd_hwdep snd_pcm snd_seq_midi microcode snd_rawmidi psmouse serio_raw snd_seq_midi_event snd_seq snd_timer$
[ 815.870025] CPU 0
[ 815.870143] Pid: 27819, comm: stress_test_tty Tainted: G W 3.8.0-next-20130125+ttypatch-2-xeon #2 Bochs Bochs
[ 815.870386] RIP: 0010:[<ffffffff81207bcc>] [<ffffffff81207bcc>] devpts_pty_kill+0x1c/0xa0
[ 815.870540] RSP: 0018:ffff88007d3e1ac8 EFLAGS: 00010282
[ 815.870661] RAX: ffff880079c20800 RBX: 0000000000000000 RCX: 0000000000000000
[ 815.870804] RDX: ffff880079c209a8 RSI: 0000000000000286 RDI: 0000000000000000
[ 815.870933] RBP: ffff88007d3e1ae8 R08: 0000000000000000 R09: 0000000000000000
[ 815.871078] R10: 0000000000000000 R11: 0000000000000001 R12: ffff88007bfb7e00
[ 815.871209] R13: 0000000000000005 R14: ffff880079c20c00 R15: ffff880079c20c00
[ 815.871343] FS: 00007f2e86206700(0000) GS:ffff88007fc00000(0000) knlGS:0000000000000000
[ 815.871495] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b
[ 815.871617] CR2: 0000000000000028 CR3: 000000007ae56000 CR4: 00000000000006f0
[ 815.871752] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[ 815.871902] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
[ 815.872012] Process stress_test_tty (pid: 27819, threadinfo ffff88007d3e0000, task ffff88007c874530)
[ 815.872012] Stack:
[ 815.872012] ffff88007bfb7e00 ffff880079c20c00 ffff88007bfb7e00 0000000000000005
[ 815.872012] ffff88007d3e1b08 ffffffff81417be7 ffff88007caa9bd8 ffff880079c20800
[ 815.872012] ffff88007d3e1bc8 ffffffff8140e5f8 0000000000000000 0000000000000000
[ 815.872012] Call Trace:
[ 815.872012] [<ffffffff81417be7>] pty_close+0x157/0x170
[ 815.872012] [<ffffffff8140e5f8>] tty_release+0x138/0x580
[ 815.872012] [<ffffffff816d29f3>] ? _raw_spin_lock+0x23/0x30
[ 815.872012] [<ffffffff816d267a>] ? _raw_spin_unlock+0x1a/0x40
[ 815.872012] [<ffffffff816d0178>] ? __mutex_unlock_slowpath+0x48/0x60
[ 815.872012] [<ffffffff81417dff>] ptmx_open+0x11f/0x180
[ 815.872012] [<ffffffff8119394b>] chrdev_open+0x9b/0x1c0
[ 815.872012] [<ffffffff8118d643>] do_dentry_open+0x203/0x290
[ 815.872012] [<ffffffff811938b0>] ? cdev_put+0x30/0x30
[ 815.872012] [<ffffffff8118d705>] finish_open+0x35/0x50
[ 815.872012] [<ffffffff8119dcce>] do_last+0x6fe/0xe90
[ 815.872012] [<ffffffff8119a7af>] ? link_path_walk+0x7f/0x880
[ 815.872012] [<ffffffff810909d5>] ? cpuacct_charge+0x75/0x80
[ 815.872012] [<ffffffff8119e51c>] path_openat+0xbc/0x4e0
[ 815.872012] [<ffffffff816d0fd0>] ? __schedule+0x400/0x7f0
[ 815.872012] [<ffffffff8140e956>] ? tty_release+0x496/0x580
[ 815.872012] [<ffffffff8119ec11>] do_filp_open+0x41/0xa0
[ 815.872012] [<ffffffff816d267a>] ? _raw_spin_unlock+0x1a/0x40
[ 815.872012] [<ffffffff811abe39>] ? __alloc_fd+0xe9/0x140
[ 815.872012] [<ffffffff8118ea44>] do_sys_open+0xf4/0x1e0
[ 815.872012] [<ffffffff8118eb51>] sys_open+0x21/0x30
[ 815.872012] [<ffffffff816da499>] system_call_fastpath+0x16/0x1b
[ 815.872012] Code: 0f 1f 80 00 00 00 00 45 31 e4 eb d7 0f 0b 90 0f 1f 44 00 00 55 48 89 e5 48 83 ec 20 48 89 5d e8 48 89 fb 4c 89 65 f0 4c 89 6d f8 <48> 8b 47 28 48 81 78 58 d1 1c 0$
[ 815.872012] RIP [<ffffffff81207bcc>] devpts_pty_kill+0x1c/0xa0
[ 815.872012] RSP <ffff88007d3e1ac8>
[ 815.872012] CR2: 0000000000000028
[ 815.897036] ---[ end trace eadf50b7f34e47d5 ]---
Fixes this BUG also:
[ 608.366836] BUG: unable to handle kernel NULL pointer dereference at 0000000000000028
[ 608.366948] IP: [<ffffffff812078d8>] devpts_kill_index+0x18/0x70
[ 608.367050] PGD 7c75b067 PUD 7b919067 PMD 0
[ 608.367135] Oops: 0000 [#1] PREEMPT SMP
[ 608.367201] Modules linked in: kvm_intel kvm snd_hda_intel snd_hda_codec snd_hwdep snd_pcm snd_seq_midi snd_rawmidi snd_seq_midi_event microcode snd_seq psmouse snd_timer snd_seq_device serio_raw snd mac_hid soundcore snd_page_alloc rfcomm virtio_balloon parport_pc bnep bluetooth ppdev i2c_piix4 lp parport floppy
[ 608.367617] CPU 2
[ 608.367669] Pid: 1918, comm: stress_test_tty Tainted: G W 3.8.0-next-20130125+ttypatch-2-xeon #2 Bochs Bochs
[ 608.367796] RIP: 0010:[<ffffffff812078d8>] [<ffffffff812078d8>] devpts_kill_index+0x18/0x70
[ 608.367885] RSP: 0018:ffff88007ae41a88 EFLAGS: 00010286
[ 608.367951] RAX: ffffffff81417e80 RBX: ffff880036472400 RCX: 0000000180400028
[ 608.368010] RDX: ffff880036470004 RSI: 0000000000000004 RDI: 0000000000000000
[ 608.368010] RBP: ffff88007ae41a98 R08: 0000000000000000 R09: 0000000000000001
[ 608.368010] R10: ffffea0001f22e40 R11: ffffffff814151d5 R12: 0000000000000004
[ 608.368010] R13: ffff880036470000 R14: 0000000000000004 R15: ffff880036472400
[ 608.368010] FS: 00007ff7a5268700(0000) GS:ffff88007fd00000(0000) knlGS:0000000000000000
[ 608.368010] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b
[ 608.368010] CR2: 0000000000000028 CR3: 000000007a0fd000 CR4: 00000000000006e0
[ 608.368010] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[ 608.368010] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
[ 608.368010] Process stress_test_tty (pid: 1918, threadinfo ffff88007ae40000, task ffff88003688dc40)
[ 608.368010] Stack:
[ 608.368010] ffff880036472400 0000000000000001 ffff88007ae41aa8 ffffffff81417e98
[ 608.368010] ffff88007ae41ac8 ffffffff8140c42b ffff88007ac73100 ffff88007ac73100
[ 608.368010] ffff88007ae41b98 ffffffff8140ead5 ffff88007ae41b38 ffff88007ca40e40
[ 608.368010] Call Trace:
[ 608.368010] [<ffffffff81417e98>] pty_unix98_shutdown+0x18/0x20
[ 608.368010] [<ffffffff8140c42b>] release_tty+0x3b/0xe0
[ 608.368010] [<ffffffff8140ead5>] __tty_release+0x575/0x5d0
[ 608.368010] [<ffffffff816d2c63>] ? _raw_spin_lock+0x23/0x30
[ 608.368010] [<ffffffff816d28ea>] ? _raw_spin_unlock+0x1a/0x40
[ 608.368010] [<ffffffff816d03e8>] ? __mutex_unlock_slowpath+0x48/0x60
[ 608.368010] [<ffffffff8140ef79>] tty_open+0x449/0x5f0
[ 608.368010] [<ffffffff8119394b>] chrdev_open+0x9b/0x1c0
[ 608.368010] [<ffffffff8118d643>] do_dentry_open+0x203/0x290
[ 608.368010] [<ffffffff811938b0>] ? cdev_put+0x30/0x30
[ 608.368010] [<ffffffff8118d705>] finish_open+0x35/0x50
[ 608.368010] [<ffffffff8119dcce>] do_last+0x6fe/0xe90
[ 608.368010] [<ffffffff8119a7af>] ? link_path_walk+0x7f/0x880
[ 608.368010] [<ffffffff8119e51c>] path_openat+0xbc/0x4e0
[ 608.368010] [<ffffffff8119ec11>] do_filp_open+0x41/0xa0
[ 608.368010] [<ffffffff816d28ea>] ? _raw_spin_unlock+0x1a/0x40
[ 608.368010] [<ffffffff811abe39>] ? __alloc_fd+0xe9/0x140
[ 608.368010] [<ffffffff8118ea44>] do_sys_open+0xf4/0x1e0
[ 608.368010] [<ffffffff816d2c63>] ? _raw_spin_lock+0x23/0x30
[ 608.368010] [<ffffffff8118eb51>] sys_open+0x21/0x30
[ 608.368010] [<ffffffff816da719>] system_call_fastpath+0x16/0x1b
[ 608.368010] Code: ec 48 83 c4 10 5b 41 5c 5d c3 66 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 55 48 89 e5 48 83 ec 10 4c 89 65 f8 41 89 f4 48 89 5d f0 <48> 8b 47 28 48 81 78 58 d1 1c 00 00 74 0b 48 8b 05 4b 66 cf 00
[ 608.368010] RIP [<ffffffff812078d8>] devpts_kill_index+0x18/0x70
[ 608.368010] RSP <ffff88007ae41a88>
[ 608.368010] CR2: 0000000000000028
[ 608.394153] ---[ end trace afe83b0fb5fbda93 ]---
Reported-by: Ilya Zykov <ilya@ilyx.ru>
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-01-31 01:43:49 +08:00
|
|
|
if (tty->link->driver_data)
|
|
|
|
devpts_pty_kill(tty->link->driver_data);
|
2013-01-12 12:01:22 +08:00
|
|
|
mutex_unlock(&devpts_mutex);
|
2012-05-04 05:22:09 +08:00
|
|
|
}
|
2012-02-25 05:56:36 +08:00
|
|
|
#endif
|
2010-06-18 20:58:07 +08:00
|
|
|
tty_vhangup(tty->link);
|
2005-04-17 06:20:36 +08: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 17:43:38 +08:00
|
|
|
* unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE
|
2005-04-17 06:20:36 +08: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 17:43:38 +08:00
|
|
|
static void pty_unthrottle(struct tty_struct *tty)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2009-07-07 23:39:41 +08:00
|
|
|
tty_wakeup(tty->link);
|
2005-04-17 06:20:36 +08:00
|
|
|
set_bit(TTY_THROTTLED, &tty->flags);
|
|
|
|
}
|
|
|
|
|
2009-07-07 23:39:41 +08:00
|
|
|
/**
|
|
|
|
* pty_write - write to a pty
|
|
|
|
* @tty: the tty we write from
|
|
|
|
* @buf: kernel buffer of data
|
|
|
|
* @count: bytes to write
|
2009-06-17 00:01:13 +08:00
|
|
|
*
|
2009-07-07 23:39:41 +08: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 06:20:36 +08:00
|
|
|
*/
|
2009-07-07 23:39:41 +08:00
|
|
|
|
2009-09-06 04:27:10 +08:00
|
|
|
static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct tty_struct *to = tty->link;
|
|
|
|
|
2009-07-07 23:39:41 +08:00
|
|
|
if (tty->stopped)
|
2005-04-17 06:20:36 +08:00
|
|
|
return 0;
|
2009-07-07 23:39:41 +08:00
|
|
|
|
|
|
|
if (c > 0) {
|
|
|
|
/* Stuff the data into the input queue of the other end */
|
2013-01-03 22:53:04 +08:00
|
|
|
c = tty_insert_flip_string(to->port, buf, c);
|
2009-07-07 23:39:41 +08:00
|
|
|
/* And shovel */
|
2013-07-24 20:29:57 +08:00
|
|
|
if (c)
|
2013-01-03 22:53:06 +08:00
|
|
|
tty_flip_buffer_push(to->port);
|
2009-06-17 00:01:13 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
2009-07-07 23:39:41 +08: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 06:20:36 +08:00
|
|
|
static int pty_write_room(struct tty_struct *tty)
|
|
|
|
{
|
2009-08-11 04:21:19 +08:00
|
|
|
if (tty->stopped)
|
|
|
|
return 0;
|
2015-01-17 04:22:14 +08:00
|
|
|
return tty_buffer_space_avail(tty->link->port);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2009-07-07 23:39:41 +08:00
|
|
|
/**
|
|
|
|
* pty_chars_in_buffer - characters currently in our tx queue
|
|
|
|
* @tty: our tty
|
2008-10-13 17:43:38 +08:00
|
|
|
*
|
2009-07-07 23:39:41 +08: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 06:20:36 +08:00
|
|
|
*/
|
2009-07-07 23:39:41 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
static int pty_chars_in_buffer(struct tty_struct *tty)
|
|
|
|
{
|
2009-07-07 23:39:41 +08:00
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the lock flag on a pty */
|
2008-10-13 17:43:38 +08:00
|
|
|
static int pty_set_lock(struct tty_struct *tty, int __user *arg)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
int val;
|
2008-10-13 17:43:38 +08:00
|
|
|
if (get_user(val, arg))
|
2005-04-17 06:20:36 +08: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 03:43:22 +08: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 03:43:20 +08: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 03:33:25 +08:00
|
|
|
spin_lock_irq(&tty->ctrl_lock);
|
2012-10-25 03:43:20 +08:00
|
|
|
if (pktmode) {
|
|
|
|
if (!tty->packet) {
|
|
|
|
tty->link->ctrl_status = 0;
|
2014-10-17 03:33:27 +08:00
|
|
|
smp_mb();
|
|
|
|
tty->packet = 1;
|
2012-10-25 03:43:20 +08:00
|
|
|
}
|
|
|
|
} else
|
|
|
|
tty->packet = 0;
|
2014-10-17 03:33:25 +08:00
|
|
|
spin_unlock_irq(&tty->ctrl_lock);
|
2012-10-25 03:43:20 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-10-25 03:43:22 +08: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 01:14:49 +08:00
|
|
|
/* Send a signal to the slave */
|
|
|
|
static int pty_signal(struct tty_struct *tty, int sig)
|
|
|
|
{
|
|
|
|
struct pid *pgrp;
|
|
|
|
|
2015-01-20 02:05:03 +08: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 01:14:49 +08:00
|
|
|
if (tty->link) {
|
2014-10-17 02:59:45 +08: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 01:14:49 +08:00
|
|
|
put_pid(pgrp);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
static void pty_flush_buffer(struct tty_struct *tty)
|
|
|
|
{
|
|
|
|
struct tty_struct *to = tty->link;
|
2015-01-18 04:42:05 +08:00
|
|
|
struct tty_ldisc *ld;
|
2008-10-13 17:43:38 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if (!to)
|
|
|
|
return;
|
2015-01-18 04:42:05 +08:00
|
|
|
|
|
|
|
ld = tty_ldisc_ref(to);
|
|
|
|
tty_buffer_flush(to, ld);
|
|
|
|
if (ld)
|
|
|
|
tty_ldisc_deref(ld);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if (to->packet) {
|
2014-10-17 03:33:25 +08:00
|
|
|
spin_lock_irq(&tty->ctrl_lock);
|
2005-04-17 06:20:36 +08:00
|
|
|
tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
|
|
|
|
wake_up_interruptible(&to->read_wait);
|
2014-10-17 03:33:25 +08:00
|
|
|
spin_unlock_irq(&tty->ctrl_lock);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-13 17:43:38 +08:00
|
|
|
static int pty_open(struct tty_struct *tty, struct file *filp)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
if (!tty || !tty->link)
|
2013-06-14 03:56:37 +08:00
|
|
|
return -ENODEV;
|
2013-01-31 01:43:50 +08:00
|
|
|
|
2005-04-17 06:20:36 +08: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 01:43:52 +08:00
|
|
|
if (tty->driver->subtype == PTY_TYPE_SLAVE && tty->link->count != 1)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto out;
|
|
|
|
|
2013-01-31 01:43:50 +08:00
|
|
|
clear_bit(TTY_IO_ERROR, &tty->flags);
|
2015-04-14 01:24:34 +08:00
|
|
|
/* TTY_OTHER_CLOSED must be cleared before TTY_OTHER_DONE */
|
2005-04-17 06:20:36 +08:00
|
|
|
clear_bit(TTY_OTHER_CLOSED, &tty->link->flags);
|
2015-04-14 01:24:34 +08:00
|
|
|
clear_bit(TTY_OTHER_DONE, &tty->link->flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
set_bit(TTY_THROTTLED, &tty->flags);
|
2013-06-14 03:56:37 +08:00
|
|
|
return 0;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
out:
|
2013-06-14 03:56:37 +08:00
|
|
|
set_bit(TTY_IO_ERROR, &tty->flags);
|
|
|
|
return -EIO;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2008-10-13 17:43:38 +08:00
|
|
|
static void pty_set_termios(struct tty_struct *tty,
|
|
|
|
struct ktermios *old_termios)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2014-10-17 03:33:23 +08:00
|
|
|
/* See if packet mode change of state. */
|
|
|
|
if (tty->link && tty->link->packet) {
|
2016-01-11 12:36:15 +08:00
|
|
|
int extproc = (old_termios->c_lflag & EXTPROC) | L_EXTPROC(tty);
|
2014-10-17 03:33:23 +08: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 03:33:24 +08:00
|
|
|
spin_lock_irq(&tty->ctrl_lock);
|
2014-10-17 03:33:23 +08: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 03:33:24 +08:00
|
|
|
spin_unlock_irq(&tty->ctrl_lock);
|
2014-10-17 03:33:23 +08:00
|
|
|
wake_up_interruptible(&tty->link->read_wait);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-14 22:31:47 +08:00
|
|
|
tty->termios.c_cflag &= ~(CSIZE | PARENB);
|
|
|
|
tty->termios.c_cflag |= (CS8 | CREAD);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2009-01-02 21:43:17 +08:00
|
|
|
/**
|
|
|
|
* pty_do_resize - resize event
|
|
|
|
* @tty: tty being resized
|
2009-01-12 03:46:49 +08:00
|
|
|
* @ws: window size being set.
|
2009-01-02 21:43:17 +08: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 08:01:28 +08:00
|
|
|
* Update the termios variables and send the necessary signals to
|
2009-01-02 21:43:17 +08:00
|
|
|
* peform a terminal resize correctly
|
|
|
|
*/
|
|
|
|
|
2012-11-19 13:27:40 +08:00
|
|
|
static int pty_resize(struct tty_struct *tty, struct winsize *ws)
|
2009-01-02 21:43:17 +08: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 04:43:51 +08:00
|
|
|
mutex_lock(&tty->winsize_mutex);
|
2009-01-02 21:43:17 +08:00
|
|
|
if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
|
|
|
|
goto done;
|
|
|
|
|
2014-10-17 02:59:45 +08:00
|
|
|
/* Signal the foreground process group of both ptys */
|
|
|
|
pgrp = tty_get_pgrp(tty);
|
|
|
|
rpgrp = tty_get_pgrp(pty);
|
2009-01-02 21:43:17 +08: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 04:43:51 +08:00
|
|
|
mutex_unlock(&tty->winsize_mutex);
|
2009-01-02 21:43:17 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-09-11 03:06:32 +08: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 03:33:26 +08:00
|
|
|
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
2014-09-11 03:06:32 +08:00
|
|
|
tty->ctrl_status &= ~TIOCPKT_STOP;
|
|
|
|
tty->ctrl_status |= TIOCPKT_START;
|
2014-10-17 03:33:26 +08:00
|
|
|
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
2014-09-11 03:06:32 +08: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 03:33:26 +08:00
|
|
|
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
2014-09-11 03:06:32 +08:00
|
|
|
tty->ctrl_status &= ~TIOCPKT_START;
|
|
|
|
tty->ctrl_status |= TIOCPKT_STOP;
|
2014-10-17 03:33:26 +08:00
|
|
|
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
2014-09-11 03:06:32 +08:00
|
|
|
wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-28 01:02:54 +08:00
|
|
|
/**
|
|
|
|
* pty_common_install - set up the pty pair
|
|
|
|
* @driver: the pty driver
|
|
|
|
* @tty: the tty being instantiated
|
2014-07-11 03:01:22 +08:00
|
|
|
* @legacy: true if this is BSD style
|
2012-07-28 01:02:54 +08: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 19:35:29 +08:00
|
|
|
static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
|
|
|
|
bool legacy)
|
2008-10-13 17:42:39 +08:00
|
|
|
{
|
|
|
|
struct tty_struct *o_tty;
|
2012-06-04 19:35:30 +08:00
|
|
|
struct tty_port *ports[2];
|
2008-10-13 17:42:39 +08:00
|
|
|
int idx = tty->index;
|
2012-06-04 19:35:29 +08:00
|
|
|
int retval = -ENOMEM;
|
2008-10-13 17:42:39 +08:00
|
|
|
|
2014-11-06 01:12:49 +08:00
|
|
|
/* Opening the slave first has always returned -EIO */
|
|
|
|
if (driver->subtype != PTY_TYPE_MASTER)
|
|
|
|
return -EIO;
|
|
|
|
|
2012-06-04 19:35:30 +08:00
|
|
|
ports[0] = kmalloc(sizeof **ports, GFP_KERNEL);
|
|
|
|
ports[1] = kmalloc(sizeof **ports, GFP_KERNEL);
|
2012-08-08 03:47:26 +08:00
|
|
|
if (!ports[0] || !ports[1])
|
2014-07-11 03:01:22 +08:00
|
|
|
goto err;
|
2008-10-13 17:42:39 +08:00
|
|
|
if (!try_module_get(driver->other->owner)) {
|
|
|
|
/* This cannot in fact currently happen */
|
2014-07-11 03:01:22 +08:00
|
|
|
goto err;
|
2008-10-13 17:42:39 +08:00
|
|
|
}
|
2014-07-11 03:01:22 +08:00
|
|
|
o_tty = alloc_tty_struct(driver->other, idx);
|
|
|
|
if (!o_tty)
|
|
|
|
goto err_put_module;
|
2008-10-13 17:42:39 +08:00
|
|
|
|
2014-11-06 01:13:02 +08:00
|
|
|
tty_set_lock_subclass(o_tty);
|
2015-01-18 04:42:06 +08:00
|
|
|
lockdep_set_subclass(&o_tty->termios_rwsem, TTY_LOCK_SLAVE);
|
2014-11-06 01:13:02 +08:00
|
|
|
|
2012-06-04 19:35:29 +08:00
|
|
|
if (legacy) {
|
|
|
|
/* We always use new tty termios data so we can do this
|
|
|
|
the easy way .. */
|
2016-01-10 13:13:48 +08:00
|
|
|
tty_init_termios(tty);
|
|
|
|
tty_init_termios(o_tty);
|
2012-06-04 19:35:29 +08:00
|
|
|
|
|
|
|
driver->other->ttys[idx] = o_tty;
|
|
|
|
driver->ttys[idx] = tty;
|
|
|
|
} else {
|
2012-07-14 22:31:47 +08: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 19:35:29 +08:00
|
|
|
}
|
2008-10-13 17:43:38 +08:00
|
|
|
|
2008-10-13 17:42:39 +08: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 19:35:30 +08:00
|
|
|
tty_port_init(ports[0]);
|
|
|
|
tty_port_init(ports[1]);
|
2015-01-17 04:22:14 +08:00
|
|
|
tty_buffer_set_limit(ports[0], 8192);
|
|
|
|
tty_buffer_set_limit(ports[1], 8192);
|
2012-06-04 19:35:30 +08:00
|
|
|
o_tty->port = ports[0];
|
|
|
|
tty->port = ports[1];
|
2012-10-19 04:26:46 +08:00
|
|
|
o_tty->port->itty = o_tty;
|
2008-10-13 17:42:39 +08:00
|
|
|
|
2015-01-18 04:42:05 +08:00
|
|
|
tty_buffer_set_lock_subclass(o_tty->port);
|
|
|
|
|
2008-10-13 17:42:39 +08:00
|
|
|
tty_driver_kref_get(driver);
|
|
|
|
tty->count++;
|
2014-11-06 01:12:49 +08:00
|
|
|
o_tty->count++;
|
2008-10-13 17:42:39 +08:00
|
|
|
return 0;
|
2016-01-10 13:13:48 +08:00
|
|
|
|
2014-07-11 03:01:22 +08:00
|
|
|
err_put_module:
|
2014-07-13 07:44:00 +08:00
|
|
|
module_put(driver->other->owner);
|
2014-07-11 03:01:22 +08:00
|
|
|
err:
|
2012-06-04 19:35:30 +08:00
|
|
|
kfree(ports[0]);
|
|
|
|
kfree(ports[1]);
|
2011-03-23 17:48:33 +08:00
|
|
|
return retval;
|
2008-10-13 17:42:39 +08:00
|
|
|
}
|
|
|
|
|
2012-06-04 19:35:30 +08:00
|
|
|
static void pty_cleanup(struct tty_struct *tty)
|
|
|
|
{
|
2012-11-15 16:49:49 +08:00
|
|
|
tty_port_put(tty->port);
|
2012-06-04 19:35:30 +08:00
|
|
|
}
|
|
|
|
|
2012-06-04 19:35:29 +08: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 01:02:54 +08: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-15 00:27:22 +08:00
|
|
|
static int pty_bsd_ioctl(struct tty_struct *tty,
|
2005-04-17 06:20:36 +08: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 03:43:22 +08:00
|
|
|
case TIOCGPTLCK: /* Get PT Lock status */
|
|
|
|
return pty_get_lock(tty, (int __user *)arg);
|
2012-10-25 03:43:20 +08:00
|
|
|
case TIOCPKT: /* Set PT packet mode */
|
|
|
|
return pty_set_pktmode(tty, (int __user *)arg);
|
2012-10-25 03:43:22 +08: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 01:14:49 +08:00
|
|
|
case TIOCSIG: /* Send signal to other side of pty */
|
|
|
|
return pty_signal(tty, (int) arg);
|
2013-01-11 19:06:27 +08:00
|
|
|
case TIOCGPTN: /* TTY returns ENOTTY, but glibc expects EINVAL here */
|
|
|
|
return -EINVAL;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
return -ENOIOCTLCMD;
|
|
|
|
}
|
|
|
|
|
2007-08-15 18:25:38 +08:00
|
|
|
static int legacy_count = CONFIG_LEGACY_PTY_COUNT;
|
2015-08-20 05:48:05 +08: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 18:25:38 +08:00
|
|
|
module_param(legacy_count, int, 0);
|
|
|
|
|
2009-09-30 22:49:40 +08: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 15:54:10 +08: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,
|
2012-06-04 19:35:30 +08:00
|
|
|
.cleanup = pty_cleanup,
|
2012-07-28 01:02:54 +08:00
|
|
|
.resize = pty_resize,
|
|
|
|
.remove = pty_remove
|
2008-04-30 15:54:10 +08:00
|
|
|
};
|
|
|
|
|
2009-09-30 22:49:40 +08: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 19:35:30 +08:00
|
|
|
.cleanup = pty_cleanup,
|
2012-07-28 01:02:54 +08:00
|
|
|
.resize = pty_resize,
|
2014-09-11 03:06:32 +08:00
|
|
|
.start = pty_start,
|
|
|
|
.stop = pty_stop,
|
2012-07-28 01:02:54 +08:00
|
|
|
.remove = pty_remove
|
2009-09-30 22:49:40 +08:00
|
|
|
};
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
static void __init legacy_pty_init(void)
|
|
|
|
{
|
2009-09-30 22:49:40 +08:00
|
|
|
struct tty_driver *pty_driver, *pty_slave_driver;
|
|
|
|
|
2007-08-15 18:25:38 +08:00
|
|
|
if (legacy_count <= 0)
|
|
|
|
return;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2012-08-09 04:26:41 +08:00
|
|
|
pty_driver = tty_alloc_driver(legacy_count,
|
|
|
|
TTY_DRIVER_RESET_TERMIOS |
|
|
|
|
TTY_DRIVER_REAL_RAW |
|
|
|
|
TTY_DRIVER_DYNAMIC_ALLOC);
|
2012-08-16 21:16:56 +08:00
|
|
|
if (IS_ERR(pty_driver))
|
2005-04-17 06:20:36 +08:00
|
|
|
panic("Couldn't allocate pty driver");
|
|
|
|
|
2012-08-09 04:26:41 +08:00
|
|
|
pty_slave_driver = tty_alloc_driver(legacy_count,
|
|
|
|
TTY_DRIVER_RESET_TERMIOS |
|
|
|
|
TTY_DRIVER_REAL_RAW |
|
|
|
|
TTY_DRIVER_DYNAMIC_ALLOC);
|
2012-08-16 21:16:56 +08:00
|
|
|
if (IS_ERR(pty_slave_driver))
|
2005-04-17 06:20:36 +08: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 18:38:45 +08:00
|
|
|
pty_driver->init_termios.c_ispeed = 38400;
|
|
|
|
pty_driver->init_termios.c_ospeed = 38400;
|
2005-04-17 06:20:36 +08:00
|
|
|
pty_driver->other = pty_slave_driver;
|
2009-09-30 22:49:40 +08:00
|
|
|
tty_set_operations(pty_driver, &master_pty_ops_bsd);
|
2005-04-17 06:20:36 +08: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 18:38:45 +08:00
|
|
|
pty_slave_driver->init_termios.c_ispeed = 38400;
|
|
|
|
pty_slave_driver->init_termios.c_ospeed = 38400;
|
2005-04-17 06:20:36 +08:00
|
|
|
pty_slave_driver->other = pty_driver;
|
2009-09-30 22:49:40 +08:00
|
|
|
tty_set_operations(pty_slave_driver, &slave_pty_ops_bsd);
|
2005-04-17 06:20:36 +08: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 17:41:42 +08:00
|
|
|
static struct cdev ptmx_cdev;
|
|
|
|
|
2011-02-15 00:27:22 +08:00
|
|
|
static int pty_unix98_ioctl(struct tty_struct *tty,
|
2005-04-17 06:20:36 +08: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 03:43:22 +08:00
|
|
|
case TIOCGPTLCK: /* Get PT Lock status */
|
|
|
|
return pty_get_lock(tty, (int __user *)arg);
|
2012-10-25 03:43:20 +08:00
|
|
|
case TIOCPKT: /* Set PT packet mode */
|
|
|
|
return pty_set_pktmode(tty, (int __user *)arg);
|
2012-10-25 03:43:22 +08:00
|
|
|
case TIOCGPKT: /* Get PT packet mode */
|
|
|
|
return pty_get_pktmode(tty, (int __user *)arg);
|
2005-04-17 06:20:36 +08:00
|
|
|
case TIOCGPTN: /* Get PT Number */
|
|
|
|
return put_user(tty->index, (unsigned 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 01:14:49 +08:00
|
|
|
case TIOCSIG: /* Send signal to other side of pty */
|
|
|
|
return pty_signal(tty, (int) arg);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return -ENOIOCTLCMD;
|
|
|
|
}
|
|
|
|
|
2008-10-13 17:42:00 +08: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 17:42:59 +08:00
|
|
|
static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
|
|
|
|
struct inode *ptm_inode, int idx)
|
2008-10-13 17:42:00 +08:00
|
|
|
{
|
2012-01-05 17:04:21 +08:00
|
|
|
/* Master must be open via /dev/ptmx */
|
|
|
|
return ERR_PTR(-EIO);
|
2008-10-13 17:42:00 +08: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 05:22:09 +08:00
|
|
|
* This provides our locking for the tty pointer.
|
2008-10-13 17:42:00 +08:00
|
|
|
*/
|
|
|
|
|
2008-10-13 17:42:59 +08:00
|
|
|
static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
|
|
|
|
struct inode *pts_inode, int idx)
|
2008-10-13 17:42:00 +08:00
|
|
|
{
|
2012-05-04 05:22:09 +08:00
|
|
|
struct tty_struct *tty;
|
|
|
|
|
|
|
|
mutex_lock(&devpts_mutex);
|
2012-10-19 04:26:27 +08:00
|
|
|
tty = devpts_get_priv(pts_inode);
|
2012-05-04 05:22:09 +08:00
|
|
|
mutex_unlock(&devpts_mutex);
|
2008-10-13 17:42:00 +08:00
|
|
|
/* Master must be open before slave */
|
|
|
|
if (!tty)
|
|
|
|
return ERR_PTR(-EIO);
|
|
|
|
return tty;
|
|
|
|
}
|
|
|
|
|
2008-10-13 17:42:39 +08:00
|
|
|
static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
|
2008-10-13 17:42:19 +08:00
|
|
|
{
|
2012-06-04 19:35:29 +08:00
|
|
|
return pty_common_install(driver, tty, false);
|
2008-10-13 17:42:19 +08:00
|
|
|
}
|
|
|
|
|
2013-04-15 13:52:05 +08:00
|
|
|
/* this is called once with whichever end is closed last */
|
2016-01-10 13:13:50 +08:00
|
|
|
static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
|
2013-04-15 13:52:05 +08: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 06:16:07 +08:00
|
|
|
struct pts_fs_info *fsi;
|
2016-01-11 22:07:43 +08: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 06:16:07 +08:00
|
|
|
fsi = tty->driver_data;
|
2016-01-11 22:07:43 +08: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 06:16:07 +08:00
|
|
|
fsi = tty->link->driver_data;
|
|
|
|
devpts_kill_index(fsi, tty->index);
|
|
|
|
devpts_put_ref(fsi);
|
2013-04-15 13:52:05 +08:00
|
|
|
}
|
|
|
|
|
2008-10-13 17:41:30 +08:00
|
|
|
static const struct tty_operations ptm_unix98_ops = {
|
2008-10-13 17:42:00 +08:00
|
|
|
.lookup = ptm_unix98_lookup,
|
2008-10-13 17:42:39 +08:00
|
|
|
.install = pty_unix98_install,
|
2012-06-04 19:35:28 +08:00
|
|
|
.remove = pty_unix98_remove,
|
2008-04-30 15:54:10 +08: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 17:41:30 +08:00
|
|
|
.ioctl = pty_unix98_ioctl,
|
2012-07-18 00:06:57 +08:00
|
|
|
.resize = pty_resize,
|
|
|
|
.cleanup = pty_cleanup
|
2008-04-30 15:54:10 +08:00
|
|
|
};
|
|
|
|
|
2008-10-13 17:42:00 +08:00
|
|
|
static const struct tty_operations pty_unix98_ops = {
|
|
|
|
.lookup = pts_unix98_lookup,
|
2008-10-13 17:42:39 +08:00
|
|
|
.install = pty_unix98_install,
|
2012-06-04 19:35:28 +08:00
|
|
|
.remove = pty_unix98_remove,
|
2008-10-13 17:42:00 +08: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 03:06:32 +08:00
|
|
|
.start = pty_start,
|
|
|
|
.stop = pty_stop,
|
2012-06-04 19:35:30 +08:00
|
|
|
.cleanup = pty_cleanup,
|
2008-10-13 17:42:00 +08:00
|
|
|
};
|
2008-10-13 17:41:42 +08: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 12:01:22 +08:00
|
|
|
* protect the rest.
|
2008-10-13 17:41:42 +08:00
|
|
|
* allocated_ptys_lock handles the list of free pty numbers
|
|
|
|
*/
|
|
|
|
|
2010-06-02 04:53:02 +08:00
|
|
|
static int ptmx_open(struct inode *inode, struct file *filp)
|
2008-10-13 17:41:42 +08: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 06:16:07 +08:00
|
|
|
struct pts_fs_info *fsi;
|
2008-10-13 17:41:42 +08:00
|
|
|
struct tty_struct *tty;
|
2012-10-19 04:26:28 +08:00
|
|
|
struct inode *slave_inode;
|
2008-10-13 17:41:42 +08:00
|
|
|
int retval;
|
|
|
|
int index;
|
|
|
|
|
|
|
|
nonseekable_open(inode, filp);
|
|
|
|
|
2013-05-01 22:32:21 +08:00
|
|
|
/* We refuse fsnotify events on ptmx, since it's a shared resource */
|
|
|
|
filp->f_mode |= FMODE_NONOTIFY;
|
|
|
|
|
2011-10-12 17:32:43 +08:00
|
|
|
retval = tty_alloc_file(filp);
|
|
|
|
if (retval)
|
|
|
|
return retval;
|
|
|
|
|
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 06:16:07 +08:00
|
|
|
fsi = devpts_get_ref(inode, filp);
|
|
|
|
retval = -ENODEV;
|
|
|
|
if (!fsi)
|
|
|
|
goto out_free_file;
|
|
|
|
|
2008-10-13 17:41:42 +08:00
|
|
|
/* find a device that is not in use. */
|
2012-08-08 23:30:13 +08: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 06:16:07 +08:00
|
|
|
index = devpts_new_index(fsi);
|
2012-08-08 23:30:13 +08: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 06:16:07 +08:00
|
|
|
retval = index;
|
|
|
|
if (index < 0)
|
|
|
|
goto out_put_ref;
|
2008-10-13 17:41:42 +08: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 06:16:07 +08:00
|
|
|
mutex_lock(&tty_mutex);
|
|
|
|
tty = tty_init_dev(ptm_driver, index);
|
2012-08-08 23:30:13 +08: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 06:16:07 +08:00
|
|
|
retval = PTR_ERR(tty);
|
|
|
|
if (IS_ERR(tty))
|
|
|
|
goto out;
|
2010-08-18 02:37:35 +08:00
|
|
|
|
2016-01-11 22:07:43 +08: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 06:16:07 +08: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 22:07:43 +08: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 06:16:07 +08:00
|
|
|
set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
|
|
|
|
tty->driver_data = fsi;
|
2016-01-11 22:07:43 +08:00
|
|
|
|
2011-10-12 17:32:43 +08:00
|
|
|
tty_add_file(tty, filp);
|
2008-10-13 17:41:42 +08: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 06:16:07 +08:00
|
|
|
slave_inode = devpts_pty_new(fsi,
|
2012-10-19 04:26:29 +08:00
|
|
|
MKDEV(UNIX98_PTY_SLAVE_MAJOR, index), index,
|
|
|
|
tty->link);
|
2012-10-19 04:26:28 +08:00
|
|
|
if (IS_ERR(slave_inode)) {
|
|
|
|
retval = PTR_ERR(slave_inode);
|
2011-10-12 17:32:44 +08:00
|
|
|
goto err_release;
|
2012-10-19 04:26:28 +08:00
|
|
|
}
|
pty: Fix BUG()s when ptmx_open() errors out
If pmtx_open() fails to get a slave inode or fails the pty_open(),
the tty is released as part of the error cleanup. As evidenced by the
first BUG stacktrace below, pty_close() assumes that the linked pty has
a valid, initialized inode* stored in driver_data.
Also, as evidenced by the second BUG stacktrace below, pty_unix98_shutdown()
assumes that the master pty's driver_data has been initialized.
1) Fix the invalid assumption in pty_close().
2) Initialize driver_data immediately so proper devpts fs cleanup occurs.
Fixes this BUG:
[ 815.868844] BUG: unable to handle kernel NULL pointer dereference at 0000000000000028
[ 815.869018] IP: [<ffffffff81207bcc>] devpts_pty_kill+0x1c/0xa0
[ 815.869190] PGD 7c775067 PUD 79deb067 PMD 0
[ 815.869315] Oops: 0000 [#1] PREEMPT SMP
[ 815.869443] Modules linked in: kvm_intel kvm snd_hda_intel snd_hda_codec snd_hwdep snd_pcm snd_seq_midi microcode snd_rawmidi psmouse serio_raw snd_seq_midi_event snd_seq snd_timer$
[ 815.870025] CPU 0
[ 815.870143] Pid: 27819, comm: stress_test_tty Tainted: G W 3.8.0-next-20130125+ttypatch-2-xeon #2 Bochs Bochs
[ 815.870386] RIP: 0010:[<ffffffff81207bcc>] [<ffffffff81207bcc>] devpts_pty_kill+0x1c/0xa0
[ 815.870540] RSP: 0018:ffff88007d3e1ac8 EFLAGS: 00010282
[ 815.870661] RAX: ffff880079c20800 RBX: 0000000000000000 RCX: 0000000000000000
[ 815.870804] RDX: ffff880079c209a8 RSI: 0000000000000286 RDI: 0000000000000000
[ 815.870933] RBP: ffff88007d3e1ae8 R08: 0000000000000000 R09: 0000000000000000
[ 815.871078] R10: 0000000000000000 R11: 0000000000000001 R12: ffff88007bfb7e00
[ 815.871209] R13: 0000000000000005 R14: ffff880079c20c00 R15: ffff880079c20c00
[ 815.871343] FS: 00007f2e86206700(0000) GS:ffff88007fc00000(0000) knlGS:0000000000000000
[ 815.871495] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b
[ 815.871617] CR2: 0000000000000028 CR3: 000000007ae56000 CR4: 00000000000006f0
[ 815.871752] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[ 815.871902] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
[ 815.872012] Process stress_test_tty (pid: 27819, threadinfo ffff88007d3e0000, task ffff88007c874530)
[ 815.872012] Stack:
[ 815.872012] ffff88007bfb7e00 ffff880079c20c00 ffff88007bfb7e00 0000000000000005
[ 815.872012] ffff88007d3e1b08 ffffffff81417be7 ffff88007caa9bd8 ffff880079c20800
[ 815.872012] ffff88007d3e1bc8 ffffffff8140e5f8 0000000000000000 0000000000000000
[ 815.872012] Call Trace:
[ 815.872012] [<ffffffff81417be7>] pty_close+0x157/0x170
[ 815.872012] [<ffffffff8140e5f8>] tty_release+0x138/0x580
[ 815.872012] [<ffffffff816d29f3>] ? _raw_spin_lock+0x23/0x30
[ 815.872012] [<ffffffff816d267a>] ? _raw_spin_unlock+0x1a/0x40
[ 815.872012] [<ffffffff816d0178>] ? __mutex_unlock_slowpath+0x48/0x60
[ 815.872012] [<ffffffff81417dff>] ptmx_open+0x11f/0x180
[ 815.872012] [<ffffffff8119394b>] chrdev_open+0x9b/0x1c0
[ 815.872012] [<ffffffff8118d643>] do_dentry_open+0x203/0x290
[ 815.872012] [<ffffffff811938b0>] ? cdev_put+0x30/0x30
[ 815.872012] [<ffffffff8118d705>] finish_open+0x35/0x50
[ 815.872012] [<ffffffff8119dcce>] do_last+0x6fe/0xe90
[ 815.872012] [<ffffffff8119a7af>] ? link_path_walk+0x7f/0x880
[ 815.872012] [<ffffffff810909d5>] ? cpuacct_charge+0x75/0x80
[ 815.872012] [<ffffffff8119e51c>] path_openat+0xbc/0x4e0
[ 815.872012] [<ffffffff816d0fd0>] ? __schedule+0x400/0x7f0
[ 815.872012] [<ffffffff8140e956>] ? tty_release+0x496/0x580
[ 815.872012] [<ffffffff8119ec11>] do_filp_open+0x41/0xa0
[ 815.872012] [<ffffffff816d267a>] ? _raw_spin_unlock+0x1a/0x40
[ 815.872012] [<ffffffff811abe39>] ? __alloc_fd+0xe9/0x140
[ 815.872012] [<ffffffff8118ea44>] do_sys_open+0xf4/0x1e0
[ 815.872012] [<ffffffff8118eb51>] sys_open+0x21/0x30
[ 815.872012] [<ffffffff816da499>] system_call_fastpath+0x16/0x1b
[ 815.872012] Code: 0f 1f 80 00 00 00 00 45 31 e4 eb d7 0f 0b 90 0f 1f 44 00 00 55 48 89 e5 48 83 ec 20 48 89 5d e8 48 89 fb 4c 89 65 f0 4c 89 6d f8 <48> 8b 47 28 48 81 78 58 d1 1c 0$
[ 815.872012] RIP [<ffffffff81207bcc>] devpts_pty_kill+0x1c/0xa0
[ 815.872012] RSP <ffff88007d3e1ac8>
[ 815.872012] CR2: 0000000000000028
[ 815.897036] ---[ end trace eadf50b7f34e47d5 ]---
Fixes this BUG also:
[ 608.366836] BUG: unable to handle kernel NULL pointer dereference at 0000000000000028
[ 608.366948] IP: [<ffffffff812078d8>] devpts_kill_index+0x18/0x70
[ 608.367050] PGD 7c75b067 PUD 7b919067 PMD 0
[ 608.367135] Oops: 0000 [#1] PREEMPT SMP
[ 608.367201] Modules linked in: kvm_intel kvm snd_hda_intel snd_hda_codec snd_hwdep snd_pcm snd_seq_midi snd_rawmidi snd_seq_midi_event microcode snd_seq psmouse snd_timer snd_seq_device serio_raw snd mac_hid soundcore snd_page_alloc rfcomm virtio_balloon parport_pc bnep bluetooth ppdev i2c_piix4 lp parport floppy
[ 608.367617] CPU 2
[ 608.367669] Pid: 1918, comm: stress_test_tty Tainted: G W 3.8.0-next-20130125+ttypatch-2-xeon #2 Bochs Bochs
[ 608.367796] RIP: 0010:[<ffffffff812078d8>] [<ffffffff812078d8>] devpts_kill_index+0x18/0x70
[ 608.367885] RSP: 0018:ffff88007ae41a88 EFLAGS: 00010286
[ 608.367951] RAX: ffffffff81417e80 RBX: ffff880036472400 RCX: 0000000180400028
[ 608.368010] RDX: ffff880036470004 RSI: 0000000000000004 RDI: 0000000000000000
[ 608.368010] RBP: ffff88007ae41a98 R08: 0000000000000000 R09: 0000000000000001
[ 608.368010] R10: ffffea0001f22e40 R11: ffffffff814151d5 R12: 0000000000000004
[ 608.368010] R13: ffff880036470000 R14: 0000000000000004 R15: ffff880036472400
[ 608.368010] FS: 00007ff7a5268700(0000) GS:ffff88007fd00000(0000) knlGS:0000000000000000
[ 608.368010] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b
[ 608.368010] CR2: 0000000000000028 CR3: 000000007a0fd000 CR4: 00000000000006e0
[ 608.368010] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[ 608.368010] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
[ 608.368010] Process stress_test_tty (pid: 1918, threadinfo ffff88007ae40000, task ffff88003688dc40)
[ 608.368010] Stack:
[ 608.368010] ffff880036472400 0000000000000001 ffff88007ae41aa8 ffffffff81417e98
[ 608.368010] ffff88007ae41ac8 ffffffff8140c42b ffff88007ac73100 ffff88007ac73100
[ 608.368010] ffff88007ae41b98 ffffffff8140ead5 ffff88007ae41b38 ffff88007ca40e40
[ 608.368010] Call Trace:
[ 608.368010] [<ffffffff81417e98>] pty_unix98_shutdown+0x18/0x20
[ 608.368010] [<ffffffff8140c42b>] release_tty+0x3b/0xe0
[ 608.368010] [<ffffffff8140ead5>] __tty_release+0x575/0x5d0
[ 608.368010] [<ffffffff816d2c63>] ? _raw_spin_lock+0x23/0x30
[ 608.368010] [<ffffffff816d28ea>] ? _raw_spin_unlock+0x1a/0x40
[ 608.368010] [<ffffffff816d03e8>] ? __mutex_unlock_slowpath+0x48/0x60
[ 608.368010] [<ffffffff8140ef79>] tty_open+0x449/0x5f0
[ 608.368010] [<ffffffff8119394b>] chrdev_open+0x9b/0x1c0
[ 608.368010] [<ffffffff8118d643>] do_dentry_open+0x203/0x290
[ 608.368010] [<ffffffff811938b0>] ? cdev_put+0x30/0x30
[ 608.368010] [<ffffffff8118d705>] finish_open+0x35/0x50
[ 608.368010] [<ffffffff8119dcce>] do_last+0x6fe/0xe90
[ 608.368010] [<ffffffff8119a7af>] ? link_path_walk+0x7f/0x880
[ 608.368010] [<ffffffff8119e51c>] path_openat+0xbc/0x4e0
[ 608.368010] [<ffffffff8119ec11>] do_filp_open+0x41/0xa0
[ 608.368010] [<ffffffff816d28ea>] ? _raw_spin_unlock+0x1a/0x40
[ 608.368010] [<ffffffff811abe39>] ? __alloc_fd+0xe9/0x140
[ 608.368010] [<ffffffff8118ea44>] do_sys_open+0xf4/0x1e0
[ 608.368010] [<ffffffff816d2c63>] ? _raw_spin_lock+0x23/0x30
[ 608.368010] [<ffffffff8118eb51>] sys_open+0x21/0x30
[ 608.368010] [<ffffffff816da719>] system_call_fastpath+0x16/0x1b
[ 608.368010] Code: ec 48 83 c4 10 5b 41 5c 5d c3 66 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 55 48 89 e5 48 83 ec 10 4c 89 65 f8 41 89 f4 48 89 5d f0 <48> 8b 47 28 48 81 78 58 d1 1c 00 00 74 0b 48 8b 05 4b 66 cf 00
[ 608.368010] RIP [<ffffffff812078d8>] devpts_kill_index+0x18/0x70
[ 608.368010] RSP <ffff88007ae41a88>
[ 608.368010] CR2: 0000000000000028
[ 608.394153] ---[ end trace afe83b0fb5fbda93 ]---
Reported-by: Ilya Zykov <ilya@ilyx.ru>
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-01-31 01:43:49 +08:00
|
|
|
tty->link->driver_data = slave_inode;
|
2008-10-13 17:41:42 +08:00
|
|
|
|
|
|
|
retval = ptm_driver->ops->open(tty, filp);
|
2010-06-02 04:53:02 +08:00
|
|
|
if (retval)
|
2011-10-12 17:32:44 +08:00
|
|
|
goto err_release;
|
|
|
|
|
2015-11-09 02:01:19 +08:00
|
|
|
tty_debug_hangup(tty, "opening (count=%d)\n", tty->count);
|
2015-07-13 10:49:13 +08:00
|
|
|
|
2012-08-08 23:30:13 +08:00
|
|
|
tty_unlock(tty);
|
2011-10-12 17:32:44 +08:00
|
|
|
return 0;
|
|
|
|
err_release:
|
2012-08-08 23:30:13 +08: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 06:16:07 +08:00
|
|
|
// This will also put-ref the fsi
|
2009-11-30 21:18:29 +08:00
|
|
|
tty_release(inode, filp);
|
2008-10-13 17:41:42 +08: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 06:16:07 +08:00
|
|
|
devpts_kill_index(fsi, index);
|
|
|
|
out_put_ref:
|
|
|
|
devpts_put_ref(fsi);
|
|
|
|
out_free_file:
|
2011-10-12 17:32:43 +08:00
|
|
|
tty_free_file(filp);
|
2010-06-02 04:53:02 +08:00
|
|
|
return retval;
|
2008-10-13 17:41:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct file_operations ptmx_fops;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
static void __init unix98_pty_init(void)
|
|
|
|
{
|
2012-08-09 04:26:41 +08: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 21:16:56 +08:00
|
|
|
if (IS_ERR(ptm_driver))
|
2005-04-17 06:20:36 +08:00
|
|
|
panic("Couldn't allocate Unix98 ptm driver");
|
2012-08-09 04:26:41 +08: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 21:16:56 +08:00
|
|
|
if (IS_ERR(pts_driver))
|
2005-04-17 06:20:36 +08: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 18:38:45 +08:00
|
|
|
ptm_driver->init_termios.c_ispeed = 38400;
|
|
|
|
ptm_driver->init_termios.c_ospeed = 38400;
|
2005-04-17 06:20:36 +08:00
|
|
|
ptm_driver->other = pts_driver;
|
2008-10-13 17:41:30 +08:00
|
|
|
tty_set_operations(ptm_driver, &ptm_unix98_ops);
|
2005-04-17 06:20:36 +08: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 18:38:45 +08:00
|
|
|
pts_driver->init_termios.c_ispeed = 38400;
|
|
|
|
pts_driver->init_termios.c_ospeed = 38400;
|
2005-04-17 06:20:36 +08:00
|
|
|
pts_driver->other = ptm_driver;
|
2008-10-13 17:42:00 +08:00
|
|
|
tty_set_operations(pts_driver, &pty_unix98_ops);
|
2008-10-13 17:43:38 +08:00
|
|
|
|
2005-04-17 06:20:36 +08: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 17:41:42 +08: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 12:01:21 +08:00
|
|
|
panic("Couldn't register /dev/ptmx driver");
|
2008-10-13 17:41:42 +08:00
|
|
|
device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2008-10-13 17:41:42 +08:00
|
|
|
|
2005-04-17 06:20:36 +08: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 05:48:05 +08:00
|
|
|
device_initcall(pty_init);
|