[Devel] [RFC rh7 v7] ve/tty: vt -- Implement per VE support for console and terminals

Cyrill Gorcunov gorcunov at virtuozzo.com
Tue Sep 1 02:50:16 PDT 2015


Previously in commit 8674c044330fad1458bd59b02f9037fb97e8b7af stubs for
virtual terminals have been added, they support writes from kernel side
which simply drops into the void.

In the patch the code has been moved from kernel/ve/console.c
to drivers/tty/pty.c to reuse a couple of pty helpers.

Now we support up to MAX_NR_VTTY_CONSOLES virtual consoles inside container.
For /dev/console we reserve the first virtual terminal.

Some details on the driver itself:

 - The drivers carries per-VE tty instances in @vtty_idr map, once
   VE tries to open a terminal we allocate tty map internally and
   keep it intact until VE destructed, this allow us to not bind
   into device namespaces (ie not rely on tty_class);

 - Unlike buffered IO to unix98 driver once internal port buffer
   get full we don't block write operations if there is no reader
   assigned yet but zap them. This is done intentionally to behave
   closely to native consoles;

 - The kernel choose which VE request terminal using get_exec_env
   helper, but for opening master peer from the nodes ve0 it uses
   vtty_set_context/vtty_get_context/vtty_drop_context to notify
   tty layer which @vtty_idr to use instead of get_exec_env.

https://jira.sw.ru/browse/PSBM-34533
https://jira.sw.ru/browse/PSBM-34532
https://jira.sw.ru/browse/PSBM-34107
https://jira.sw.ru/browse/PSBM-32686
https://jira.sw.ru/browse/PSBM-32685

v2:
 - Rename terminals from vtz to vtty
 - Merge code into /drivers/tty/pty.c to reuse some of
   pty functionality
 - Get rid of two array of indices, use one for master
   peers and fetch slaves via @link
 - Drop TTY_VT_OPEN and wait() on it
 - Add vtty_open_slave helper

v3:
 - Reverse the scheme, the peers opened from inside of
   container are the slave peers as it were in pcs6
 - Add vtty_set_context/vtty_drop_context/vtty_get_context
   to open needed tty from ve0 context
 - In vtty_open_master reuse existing vtty_lookup, vtty_open
   helpers
 - In ve_vtty_fini zap active tty tracking, such ttys are
   sitting here because the node has been opening the console
   and didn't release file descriptors yet with tty associated.
   The kernel will clean them up once they are closed but the
   tacking map pointer should be zapped to escape nil dereference

v4:
 - Use lockdep_assert_held in vtty @map operations to make sure
   we're under @tty_mutex
 - vtty_install now requests for port memory earlier for vtty_install_peer
   simplification
 - Drop tty_vhangup call from vtty_close, as been found it doesn't
   bring any benefit
 - Drop TTY_BUFFER_PAGE and fix typo in vtty_write_room
 - Rework tty counting to be the same as in pcs6: drivers
   became TTY_DRIVER_TYPE_PTY and @count adjusted accordingly

v5:
 - Treat zero as unused flag in vtty_get_context
 - vtty_printk helpers are dropped off
 - Don't test for exit state in lookup procedure: the kernel
   will do that on its own when slave is opened from inside
   of a container and for ioctl call we do such test explicitly
 - When pair is to open from the node and the existing peer is
   exiting we're allocating new pair early removin old one from
   per-VE ttys map, this is done to speedup open from the node
 - vtty_match is no longer exported into the rest of the tty code
 - When peer is to be closed we use own per-VE spinlock to read
   and modify own and peer counters, this is because the general
   tty->close routine is called without tty-mutex held and only
   one peer is locked thus such modifications are unsafe if do
   them locklessly. In current vanilla kernel there is no need
   for such lock if Unix ptys are used because master peers are
   always opened first and always get closed in constrast to the
   our driver where any peer end may be opened sole

v6:
 - Reworked tty counting: no need for extra reference but make
   it close to how native Unix98 ptys are working: once master
   is opened it takes new TTY_PINNED flags and when it getting
   closed with active slave peer we defer tty destruction until
   both ends are spare.

v7:
 - Move MAX_NR_VTTY_CONSOLES from header into pty.c
 - Drop vtty_zap_tty_map
 - Assign @driver_data in vtty_map_set
 - Rename vtty_map_del to vtty_map_clear
 - Merge map cleaning into vtty_map_free
 - Rename @current_veid to @vtty_context_veid
 - Rename TTY_PINNED to TTY_PINNED_BY_OTHER
 - Assing TTY_PINNED_BY_OTHER early in pair creation
 - Wake both ends of a peer in vtty_close

FIXME: Once this is applied need to drop kernel/ve/coinsole.c
from the source tree, dropping it immediately ruines my queue
series, because there are other patches not yet merged but
changing kernel/ve/console.c code.

Signed-off-by: Cyrill Gorcunov <gorcunov at virtuozzo.com>
CC: Vladimir Davydov <vdavydov at virtuozzo.com>
CC: Konstantin Khorenko <khorenko at virtuozzo.com>
---
 drivers/tty/pty.c    |  510 +++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/tty/tty_io.c |   36 +--
 include/linux/tty.h  |    3 
 include/linux/ve.h   |   20 --
 kernel/ve/Makefile   |    2 
 kernel/ve/vecalls.c  |    3 
 6 files changed, 539 insertions(+), 35 deletions(-)

Index: linux-pcs7.git/drivers/tty/pty.c
===================================================================
--- linux-pcs7.git.orig/drivers/tty/pty.c
+++ linux-pcs7.git/drivers/tty/pty.c
@@ -820,10 +820,520 @@ static void __init unix98_pty_init(void)
 static inline void unix98_pty_init(void) { }
 #endif
 
+#if defined(CONFIG_VE)
+
+/*
+ * VTTY architecture overview.
+ *
+ * With VTTY we make /dev/console and /dev/tty[X] virtualized
+ * per container (note the real names may vary because the
+ * kernel itself uses major:minor numbers to distinguish
+ * devices and doesn't care how they are named inside /dev.
+ * /dev/console stands for TTYAUX_MAJOR:1 while /dev/tty[X]
+ * stands for TTY_MAJOR:[0:12]. That said from inside of
+ * VTTY /dev/console is the same as /dev/tty0.
+ *
+ * For every container here is a tty map represented by
+ * vtty_map_t. It carries @veid of VE and associated slave
+ * tty peers.
+ *
+ * map
+ *  veid -> CTID
+ *    vttys -> [ 0 ]
+ *               `- @slave -> link -> @master
+ *             [ 1 ]
+ *               `- @slave -> link -> @master
+ */
+
+#include <linux/ve.h>
+#include <linux/file.h>
+#include <linux/anon_inodes.h>
+
+static struct tty_driver *vttym_driver;
+static struct tty_driver *vttys_driver;
+static DEFINE_IDR(vtty_idr);
+
+static struct file_operations vtty_fops;
+
+#define MAX_NR_VTTY_CONSOLES	(12)
+#define vtty_match_index(idx)	((idx) >= 0 && (idx) < MAX_NR_VTTY_CONSOLES)
+
+typedef struct {
+	envid_t			veid;
+	struct tty_struct	*vttys[MAX_NR_VTTY_CONSOLES];
+} vtty_map_t;
+
+static vtty_map_t *vtty_map_lookup(envid_t veid)
+{
+	lockdep_assert_held(&tty_mutex);
+	return idr_find(&vtty_idr, veid);
+}
+
+static void vtty_map_set(vtty_map_t *map, struct tty_struct *tty)
+{
+	lockdep_assert_held(&tty_mutex);
+	WARN_ON(map->vttys[tty->index]);
+
+	tty->driver_data = tty->link->driver_data = map;
+	map->vttys[tty->index] = tty;
+}
+
+static void vtty_map_clear(struct tty_struct *tty)
+{
+	vtty_map_t *map = tty->driver_data;
+
+	lockdep_assert_held(&tty_mutex);
+	if (map) {
+		struct tty_struct *p = map->vttys[tty->index];
+
+		WARN_ON(p != (tty->driver == vttys_driver ? tty : tty->link));
+		map->vttys[tty->index] = NULL;
+		tty->driver_data = tty->link->driver_data = NULL;
+	}
+}
+
+static void vtty_map_free(vtty_map_t *map)
+{
+	int i;
+
+	lockdep_assert_held(&tty_mutex);
+
+	for (i = 0; i < MAX_NR_VTTY_CONSOLES; i++) {
+		struct tty_struct *tty = map->vttys[i];
+		if (!tty)
+			continue;
+		tty->driver_data = tty->link->driver_data = NULL;
+	}
+
+	idr_remove(&vtty_idr, map->veid);
+	kfree(map);
+}
+
+static vtty_map_t *vtty_map_alloc(envid_t veid)
+{
+	vtty_map_t *map = kzalloc(sizeof(*map), GFP_KERNEL);
+
+	lockdep_assert_held(&tty_mutex);
+	if (map) {
+		map->veid = veid;
+		veid = idr_alloc(&vtty_idr, map, veid, veid + 1, GFP_KERNEL);
+		if (veid < 0) {
+			kfree(map);
+			return ERR_PTR(veid);
+		}
+	} else
+		map = ERR_PTR(-ENOMEM);
+	return map;
+}
+
+/*
+ * vttys are never supposed to be opened from inside
+ * of VE0 except special ioctl call, so treat zero as
+ * "unused" sign.
+ */
+static envid_t vtty_context_veid;
+
+static void vtty_set_context(envid_t veid)
+{
+	lockdep_assert_held(&tty_mutex);
+	WARN_ON(!veid);
+	vtty_context_veid = veid;
+}
+
+static void vtty_drop_context(void)
+{
+	lockdep_assert_held(&tty_mutex);
+	vtty_context_veid = 0;
+}
+
+static envid_t vtty_get_context(void)
+{
+	lockdep_assert_held(&tty_mutex);
+	return vtty_context_veid ?: get_exec_env()->veid;
+}
+
+static struct tty_struct *vtty_lookup(struct tty_driver *driver,
+				      struct inode *inode, int idx)
+{
+	vtty_map_t *map = vtty_map_lookup(vtty_get_context());
+	struct tty_struct *tty;
+
+	if (!vtty_match_index(idx))
+		return ERR_PTR(-EIO);
+
+	/*
+	 * Nothing ever been opened yet, allocate a new
+	 * tty map together with both peers from the scratch
+	 * in install procedure.
+	 */
+	if (!map)
+		return NULL;
+
+	tty = map->vttys[idx];
+	if (tty) {
+		if (driver == vttym_driver)
+			tty = tty->link;
+		WARN_ON(!tty);
+	}
+	return tty;
+}
+
+static void vtty_standard_install(struct tty_driver *driver,
+				  struct tty_struct *tty)
+{
+	WARN_ON(tty_init_termios(tty));
+
+	tty_driver_kref_get(driver);
+	tty_port_init(tty->port);
+	tty->port->itty = tty;
+}
+
+static struct tty_struct *vtty_install_peer(struct tty_driver *driver,
+					    struct tty_port *port, int index)
+{
+	struct tty_struct *tty;
+
+	tty = alloc_tty_struct();
+	if (!tty)
+		return ERR_PTR(-ENOMEM);
+	initialize_tty_struct(tty, driver, index);
+
+	tty->port = port;
+	vtty_standard_install(driver, tty);
+	return tty;
+}
+
+static int vtty_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+	envid_t veid = vtty_get_context();
+	struct tty_port *peer_port;
+	struct tty_struct *peer;
+	vtty_map_t *map;
+	int ret;
+
+	WARN_ON_ONCE(driver != vttys_driver);
+
+	map = vtty_map_lookup(veid);
+	if (!map) {
+		map = vtty_map_alloc(veid);
+		if (IS_ERR(map))
+			return PTR_ERR(map);
+	}
+
+	tty->port = kzalloc(sizeof(*tty->port), GFP_KERNEL);
+	peer_port = kzalloc(sizeof(*peer_port), GFP_KERNEL);
+	if (!tty->port || !peer_port) {
+		ret = -ENOMEM;
+		goto err_free;
+	}
+
+	peer = vtty_install_peer(vttym_driver, peer_port, tty->index);
+	if (IS_ERR(peer)) {
+		ret = PTR_ERR(peer);
+		goto err_free;
+	}
+
+	vtty_standard_install(vttys_driver, tty);
+	tty->count++;
+
+	tty->link = peer;
+	peer->link = tty;
+
+	/*
+	 * Defer master closing if a slave peer
+	 * will be alive at this moment.
+	 */
+	set_bit(TTY_PINNED_BY_OTHER, &peer->flags);
+
+	vtty_map_set(map, tty);
+	return 0;
+
+err_free:
+	kfree(tty->port);
+	kfree(peer_port);
+	return ret;
+}
+
+static int vtty_open(struct tty_struct *tty, struct file *filp)
+{
+	set_bit(TTY_THROTTLED, &tty->flags);
+	return 0;
+}
+
+static void vtty_close(struct tty_struct *tty, struct file *filp)
+{
+	if (tty->count <= (tty->driver == vttys_driver) ? 2 : 1) {
+		wake_up_interruptible(&tty->read_wait);
+		wake_up_interruptible(&tty->write_wait);
+
+		wake_up_interruptible(&tty->link->read_wait);
+		wake_up_interruptible(&tty->link->write_wait);
+	}
+}
+
+static void vtty_shutdown(struct tty_struct *tty)
+{
+	vtty_map_clear(tty);
+}
+
+static int vtty_write(struct tty_struct *tty,
+		      const unsigned char *buf, int count)
+{
+	struct tty_struct *peer = tty->link;
+
+	if (tty->stopped)
+		return 0;
+
+	if (count > 0) {
+		count = tty_insert_flip_string(peer->port, buf, count);
+		if (count) {
+			tty_flip_buffer_push(peer->port);
+			tty_wakeup(tty);
+		} else {
+			/*
+			 * Flush the slave reader if noone
+			 * is actually hooked on. Otherwise
+			 * wait until reader fetch all data.
+			 */
+			if (peer->count <
+			    (tty->driver == vttym_driver) ? 2 : 1)
+				tty_perform_flush(peer, TCIFLUSH);
+		}
+	}
+
+	return count;
+}
+
+static int vtty_write_room(struct tty_struct *tty)
+{
+	struct tty_struct *peer = tty->link;
+
+	if (tty->stopped)
+		return 0;
+
+	if (peer->count <
+	    (tty->driver == vttym_driver) ? 2 : 1)
+		return 2048;
+
+	return pty_space(peer);
+}
+
+static void vtty_remove(struct tty_driver *driver, struct tty_struct *tty)
+{
+}
+
+static const struct tty_operations vtty_ops = {
+	.lookup		= vtty_lookup,
+	.install	= vtty_install,
+	.open		= vtty_open,
+	.close		= vtty_close,
+	.shutdown	= vtty_shutdown,
+	.cleanup	= pty_cleanup,
+	.write		= vtty_write,
+	.write_room	= vtty_write_room,
+	.set_termios	= pty_set_termios,
+	.unthrottle	= pty_unthrottle,
+	.remove		= vtty_remove,
+};
+
+struct tty_driver *vtty_console_driver(int *index)
+{
+	*index = 0;
+	return vttys_driver;
+}
+
+struct tty_driver *vtty_driver(dev_t dev, int *index)
+{
+	if (MAJOR(dev) == TTY_MAJOR &&
+	    MINOR(dev) < MAX_NR_VTTY_CONSOLES) {
+		*index = MINOR(dev);
+		return vttys_driver;
+	}
+	return NULL;
+}
+
+static void ve_vtty_fini(void *data)
+{
+	struct ve_struct *ve = data;
+	vtty_map_t *map;
+
+	mutex_lock(&tty_mutex);
+	map = vtty_map_lookup(ve->veid);
+	if (map)
+		vtty_map_free(map);
+	mutex_unlock(&tty_mutex);
+}
+
+static struct ve_hook vtty_hook = {
+	.fini           = ve_vtty_fini,
+	.priority       = HOOK_PRIO_DEFAULT,
+	.owner          = THIS_MODULE,
+};
+
+static int __init vtty_init(void)
+{
+#define VTTY_DRIVER_ALLOC_FLAGS			\
+	(TTY_DRIVER_REAL_RAW		|	\
+	 TTY_DRIVER_RESET_TERMIOS	|	\
+	 TTY_DRIVER_DYNAMIC_DEV		|	\
+	 TTY_DRIVER_INSTALLED		|	\
+	 TTY_DRIVER_DEVPTS_MEM)
+
+	vttym_driver = tty_alloc_driver(MAX_NR_VTTY_CONSOLES,
+					VTTY_DRIVER_ALLOC_FLAGS);
+	if (IS_ERR(vttym_driver))
+		panic(pr_fmt("Can't allocate master vtty driver\n"));
+
+	vttys_driver = tty_alloc_driver(MAX_NR_VTTY_CONSOLES,
+					VTTY_DRIVER_ALLOC_FLAGS);
+	if (IS_ERR(vttys_driver))
+		panic(pr_fmt("Can't allocate slave vtty driver\n"));
+
+	vttym_driver->driver_name		= "vtty_master";
+	vttym_driver->name			= "vttym";
+	vttym_driver->name_base			= 0;
+	vttym_driver->major			= 0;
+	vttym_driver->minor_start		= 0;
+	vttym_driver->type			= TTY_DRIVER_TYPE_PTY;
+	vttym_driver->subtype			= PTY_TYPE_MASTER;
+	vttym_driver->init_termios		= tty_std_termios;
+	vttym_driver->init_termios.c_iflag	= 0;
+	vttym_driver->init_termios.c_oflag	= 0;
+
+	/* 38400 boud rate, 8 bit char size, enable receiver */
+	vttym_driver->init_termios.c_cflag	= B38400 | CS8 | CREAD;
+	vttym_driver->init_termios.c_lflag	= 0;
+	vttym_driver->init_termios.c_ispeed	= 38400;
+	vttym_driver->init_termios.c_ospeed	= 38400;
+	tty_set_operations(vttym_driver, &vtty_ops);
+
+	vttys_driver->driver_name		= "vtty_slave";
+	vttys_driver->name			= "vttys";
+	vttys_driver->name_base			= 0;
+	vttys_driver->major			= 0;
+	vttys_driver->minor_start		= 0;
+	vttys_driver->type			= TTY_DRIVER_TYPE_PTY;
+	vttys_driver->subtype			= PTY_TYPE_SLAVE;
+	vttys_driver->init_termios		= tty_std_termios;
+	vttys_driver->init_termios.c_iflag	= 0;
+	vttys_driver->init_termios.c_oflag	= 0;
+	vttys_driver->init_termios.c_cflag	= B38400 | CS8 | CREAD;
+	vttys_driver->init_termios.c_lflag	= 0;
+	vttys_driver->init_termios.c_ispeed	= 38400;
+	vttys_driver->init_termios.c_ospeed	= 38400;
+	tty_set_operations(vttys_driver, &vtty_ops);
+
+	if (tty_register_driver(vttym_driver))
+		panic(pr_fmt("Can't register master vtty driver\n"));
+
+	if (tty_register_driver(vttys_driver))
+		panic(pr_fmt("Can't register slave vtty driver\n"));
+
+	ve_hook_register(VE_SS_CHAIN, &vtty_hook);
+	tty_default_fops(&vtty_fops);
+	return 0;
+}
+
+int vtty_open_master(envid_t veid, int idx)
+{
+	struct tty_struct *tty;
+	struct file *file;
+	char devname[64];
+	int fd, ret;
+
+	if (!vtty_match_index(idx))
+		return -EIO;
+
+	fd = get_unused_fd_flags(0);
+	if (fd < 0)
+		return fd;
+
+	snprintf(devname, sizeof(devname), "v%utty%d", veid, idx);
+	file = anon_inode_getfile(devname, &vtty_fops, NULL, O_RDWR);
+	if (IS_ERR(file)) {
+		ret = PTR_ERR(file);
+		goto err_put_unused_fd;
+	}
+	nonseekable_open(NULL, file);
+
+	ret = tty_alloc_file(file);
+	if (ret)
+		goto err_fput;
+
+	/*
+	 * Opening comes from ve0 context so
+	 * setup VE's context until master fetched.
+	 * This is done under @tty_mutex so noone
+	 * else would access it while we're holding
+	 * the lock.
+	 */
+	mutex_lock(&tty_mutex);
+	vtty_set_context(veid);
+
+	tty = vtty_lookup(vttym_driver, NULL, idx);
+	if (!tty ||
+	    (test_bit(TTY_CLOSING, &tty->flags) ||
+	     test_bit(TTY_CLOSING, &tty->link->flags))) {
+		/*
+		 * The previous connection is about to
+		 * be closed so drop it from the map and
+		 * allocate a new one.
+		 */
+		if (tty)
+			vtty_map_clear(tty);
+		tty = tty_init_dev(vttys_driver, idx);
+		if (IS_ERR(tty))
+			goto err_install;
+		tty->count--;
+		tty_unlock(tty);
+		tty = tty->link;
+	}
+
+	/* One master at a time */
+	if (tty->count >= 1) {
+		ret = -EBUSY;
+		goto err_install;
+	}
+
+	vtty_drop_context();
+
+	WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
+
+	/*
+	 * We're the master peer so increment
+	 * slave counter as well.
+	 */
+	tty_add_file(tty, file);
+	tty->count++;
+	tty->link->count++;
+	fd_install(fd, file);
+	vtty_open(tty, file);
+
+	mutex_unlock(&tty_mutex);
+	ret = fd;
+out:
+	return ret;
+
+err_install:
+	vtty_drop_context();
+	mutex_unlock(&tty_mutex);
+	tty_free_file(file);
+err_fput:
+	file->f_op = NULL;
+	fput(file);
+err_put_unused_fd:
+	put_unused_fd(fd);
+	goto out;
+}
+#else
+static void vtty_init(void) { };
+#endif /* CONFIG_VE */
+
 static int __init pty_init(void)
 {
 	legacy_pty_init();
 	unix98_pty_init();
+	vtty_init();
 	return 0;
 }
 module_init(pty_init);
Index: linux-pcs7.git/drivers/tty/tty_io.c
===================================================================
--- linux-pcs7.git.orig/drivers/tty/tty_io.c
+++ linux-pcs7.git/drivers/tty/tty_io.c
@@ -1756,6 +1756,11 @@ int tty_release(struct inode *inode, str
 			(o_tty->count <= (pty_master ? 1 : 0));
 		do_sleep = 0;
 
+#ifdef CONFIG_VE
+		if (!o_tty_closing &&
+		    test_bit(TTY_PINNED_BY_OTHER, &tty->flags))
+			tty_closing = 0;
+#endif
 		if (tty_closing) {
 			if (waitqueue_active(&tty->read_wait)) {
 				wake_up_poll(&tty->read_wait, POLLIN);
@@ -1931,14 +1936,17 @@ static struct tty_driver *tty_lookup_dri
 	struct tty_driver *driver;
 
 #ifdef CONFIG_VE
-	extern struct tty_driver *vz_vt_device(struct ve_struct *ve, dev_t dev, int *index);
-	if (!ve_is_super(get_exec_env()) &&
-	    (MAJOR(device) == TTY_MAJOR && MINOR(device) < VZ_VT_MAX_DEVS)) {
-		driver = tty_driver_kref_get(vz_vt_device(get_exec_env(), device, index));
-		*noctty = 1;
-		return driver;
+	struct ve_struct *ve = get_exec_env();
+
+	if (!ve_is_super(ve)) {
+		driver = vtty_driver(device, index);
+		if (driver) {
+			*noctty = 1;
+			return tty_driver_kref_get(driver);
+		}
 	}
 #endif
+
 	switch (device) {
 #ifdef CONFIG_VT
 	case MKDEV(TTY_MAJOR, 0): {
@@ -1952,10 +1960,8 @@ static struct tty_driver *tty_lookup_dri
 	case MKDEV(TTYAUX_MAJOR, 1): {
 		struct tty_driver *console_driver = console_device(index);
 #ifdef CONFIG_VE
-		if (!ve_is_super(get_exec_env())) {
-			extern struct tty_driver *vz_console_device(int *index);
-			console_driver = vz_console_device(index);
-		}
+		if (!ve_is_super(ve))
+			console_driver = vtty_console_driver(index);
 #endif
 		if (console_driver) {
 			driver = tty_driver_kref_get(console_driver);
@@ -3628,9 +3634,6 @@ static DEVICE_ATTR(active, S_IRUGO, show
 
 #ifdef CONFIG_VE
 
-extern int vz_con_ve_init(struct ve_struct *ve);
-extern void vz_con_ve_fini(struct ve_struct *ve);
-
 void console_sysfs_notify(void)
 {
 	struct ve_struct *ve = get_exec_env();
@@ -3647,7 +3650,6 @@ void ve_tty_console_fini(struct ve_struc
 	device_remove_file(consdev, &dev_attr_active);
 	device_destroy_namespace(tty_class, MKDEV(TTYAUX_MAJOR, 1), ve);
 	device_destroy_namespace(tty_class, MKDEV(TTYAUX_MAJOR, 0), ve);
-	vz_con_ve_fini(ve);
 }
 
 int ve_tty_console_init(struct ve_struct *ve)
@@ -3669,15 +3671,9 @@ int ve_tty_console_init(struct ve_struct
 	if (err)
 		goto err_consfile;
 
-	err = vz_con_ve_init(ve);
-	if (err)
-		goto err_vzcon;
-
 	ve->consdev = dev;
 	return 0;
 
-err_vzcon:
-	device_remove_file(dev, &dev_attr_active);
 err_consfile:
 	device_destroy_namespace(tty_class, MKDEV(TTYAUX_MAJOR, 1), ve);
 err_consdev:
Index: linux-pcs7.git/include/linux/tty.h
===================================================================
--- linux-pcs7.git.orig/include/linux/tty.h
+++ linux-pcs7.git/include/linux/tty.h
@@ -322,6 +322,9 @@ struct tty_file_private {
 #define TTY_HUPPING 		21	/* ->hangup() in progress */
 #define TTY_LDISC_HALTED	22	/* Line discipline is halted */
 #define TTY_CHARGED		23	/* Charged as ub resource */
+#ifdef CONFIG_VE
+#define TTY_PINNED_BY_OTHER	24	/* TTY is pinned by other link end, defer closing */
+#endif
 
 #define TTY_WRITE_FLUSH(tty) tty_write_flush((tty))
 
Index: linux-pcs7.git/include/linux/ve.h
===================================================================
--- linux-pcs7.git.orig/include/linux/ve.h
+++ linux-pcs7.git/include/linux/ve.h
@@ -66,13 +66,6 @@ struct ve_struct {
 	struct binfmt_misc	*binfmt_misc;
 #endif
 
-#define VZ_VT_MAX_DEVS		12
-	struct tty_driver	*vz_vt_driver;
-	struct tty_struct	*vz_tty_vt[VZ_VT_MAX_DEVS];
-
-	struct tty_struct	*vz_tty_conm;
-	struct tty_struct	*vz_tty_cons;
-
 #ifdef CONFIG_TTY
 	struct device		*consdev;
 #endif
@@ -209,17 +202,16 @@ extern unsigned long long ve_relative_cl
 extern void monotonic_abs_to_ve(clockid_t which_clock, struct timespec *tp);
 extern void monotonic_ve_to_abs(clockid_t which_clock, struct timespec *tp);
 
-#ifdef CONFIG_VTTYS
-extern int vtty_open_master(int veid, int idx);
-extern struct tty_driver *vtty_driver;
-#else
-static inline int vtty_open_master(int veid, int idx) { return -ENODEV; }
-#endif
-
 void ve_stop_ns(struct pid_namespace *ns);
 void ve_exit_ns(struct pid_namespace *ns);
 int ve_start_container(struct ve_struct *ve);
 
+#ifdef CONFIG_TTY
+extern struct tty_driver *vtty_driver(dev_t dev, int *index);
+extern struct tty_driver *vtty_console_driver(int *index);
+extern int vtty_open_master(envid_t veid, int idx);
+#endif /* CONFIG_TTY */
+
 #else	/* CONFIG_VE */
 
 #define ve_uevent_seqnum uevent_seqnum
Index: linux-pcs7.git/kernel/ve/Makefile
===================================================================
--- linux-pcs7.git.orig/kernel/ve/Makefile
+++ linux-pcs7.git/kernel/ve/Makefile
@@ -4,7 +4,7 @@
 # Copyright (c) 2000-2015 Parallels IP Holdings GmbH
 #
 
-obj-$(CONFIG_VE) = ve.o veowner.o hooks.o vzstat_core.o ve-kobject.o console.o
+obj-$(CONFIG_VE) = ve.o veowner.o hooks.o vzstat_core.o ve-kobject.o
 obj-$(CONFIG_VZ_WDOG) += vzwdog.o
 obj-$(CONFIG_VE_CALLS) += vzmon.o
 
Index: linux-pcs7.git/kernel/ve/vecalls.c
===================================================================
--- linux-pcs7.git.orig/kernel/ve/vecalls.c
+++ linux-pcs7.git/kernel/ve/vecalls.c
@@ -998,6 +998,9 @@ static int ve_configure(envid_t veid, un
 	case VE_CONFIGURE_OS_RELEASE:
 		err = init_ve_osrelease(ve, data);
 		break;
+	case VE_CONFIGURE_OPEN_TTY:
+		err = vtty_open_master(ve->veid, val);
+		break;
 	}
 
 	put_ve(ve);



More information about the Devel mailing list