[Devel] [PATCH rh7] ve: console -- Enhance container console to support per VE ops

Cyrill Gorcunov gorcunov at virtuozzo.com
Fri Jun 19 08:01:11 PDT 2015


Currently in dummy console (84364c191199c50f1bc6fbf7d5f121750c5a1f66)
there is a single character device for all containers, and due to
simplicity sake the driver doesn't support multiple VE working at
same time, which lead that agetty service from container poke same
console from various VE making it stuck eventually.

So I've had to enhance console to generate one device per VE
so that every container grab own instance of a virtual console.

Note the console is still dump and doesn't provide a way to
fetch data written yet, this gonna be addressed in next
patches. Meanwhile this should prevent containers from
stucks.

https://jira.sw.ru/browse/PSBM-34357

Signed-off-by: Cyrill Gorcunov <gorcunov at virtuozzo.com>
CC: Andrey Vagin <avagin at virtuozzo.com>
CC: Vladimir Davydov <vdavydov at virtuozzo.com>
CC: Konstantin Khorenko <khorenko at virtuozzo.com>
CC: Pavel Emelyanov <xemul at virtuozzo.com>
---

I tested it locally on a few containers running simultaneously
but as you may note the code simply has a scaffolds for
"read" side which gonna be addressed soon.

 drivers/tty/tty_io.c |   11 ++
 include/linux/ve.h   |    4 
 kernel/ve/console.c  |  264 ++++++++++++++++++++++++++++++++++++---------------
 3 files changed, 203 insertions(+), 76 deletions(-)

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
@@ -3605,6 +3605,10 @@ static ssize_t show_cons_active(struct d
 static DEVICE_ATTR(active, S_IRUGO, show_cons_active, NULL);
 
 #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();
@@ -3621,6 +3625,7 @@ 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)
@@ -3642,9 +3647,15 @@ 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/ve.h
===================================================================
--- linux-pcs7.git.orig/include/linux/ve.h
+++ linux-pcs7.git/include/linux/ve.h
@@ -66,8 +66,8 @@ struct ve_struct {
 	struct binfmt_misc	*binfmt_misc;
 #endif
 
-#define	MAX_NR_VTTY		12
-	struct tty_struct	*vtty[MAX_NR_VTTY];
+	struct tty_struct	*vz_tty_conm;
+	struct tty_struct	*vz_tty_cons;
 
 #ifdef CONFIG_LEGACY_PTYS
 	struct tty_driver	*pty_driver, *pty_slave_driver;
Index: linux-pcs7.git/kernel/ve/console.c
===================================================================
--- linux-pcs7.git.orig/kernel/ve/console.c
+++ linux-pcs7.git/kernel/ve/console.c
@@ -2,71 +2,96 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
 #include <linux/init.h>
 
-#include <linux/console.h>
-#include <linux/anon_inodes.h>
-#include <linux/file.h>
 #include <linux/tty.h>
+#include <linux/tty_flip.h>
+
 #include <linux/ve.h>
 
-static struct tty_driver *vz_con_driver;
+#define VZ_CON_INDEX		(0)
+#define VZ_CON_SLAVE_NAME	"vzcons"
+
+static struct tty_driver *vz_conm_driver;
+static struct tty_driver *vz_cons_driver;
+
+static char *vzcon_devnode(struct device *dev, umode_t *mode)
+{
+	if (mode)
+		*mode = 0600;
+	return NULL;
+}
 
-struct vz_tty_priv {
-	struct tty_port		port;
-	struct ve_struct	*owner_ve;
+static struct class vz_con_class_base = {
+	.name		= "vzcon",
+	.devnode	= vzcon_devnode,
+	.ns_type	= &ve_ns_type_operations,
+	.namespace	= ve_namespace,
+	.owner		= THIS_MODULE,
 };
 
+static struct class *vz_con_class = &vz_con_class_base;
+
+static struct tty_struct *vz_tty_lookup(struct tty_driver *driver,
+					struct inode *inode, int idx)
+{
+	struct ve_struct *ve = get_exec_env();
+
+	BUG_ON(driver != vz_conm_driver &&
+	       driver != vz_cons_driver);
+
+	if (idx != VZ_CON_INDEX || driver == vz_cons_driver)
+		return ERR_PTR(-EIO);
+
+	return ve->vz_tty_conm;
+}
+
 static int vz_tty_install(struct tty_driver *driver, struct tty_struct *tty)
 {
-	static const struct tty_port_operations vz_tty_port_ops;
-	struct vz_tty_priv *priv;
-	int ret;
+	struct ve_struct *ve = get_exec_env();
 
-	BUG_ON(tty->index != 0);
+	BUG_ON(driver != vz_conm_driver);
 
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-	if (!priv)
+	tty->port = kzalloc(sizeof(*tty->port), GFP_KERNEL);
+	if (!tty->port)
 		return -ENOMEM;
+	tty_port_init(tty->port);
+	tty->termios = driver->init_termios;
 
-	priv->owner_ve = get_exec_env();
-	tty_port_init(&priv->port);
-	priv->port.ops = &vz_tty_port_ops;
-	tty->driver_data = priv;
-
-	ret = tty_port_install(&priv->port, driver, tty);
-	if (ret) {
-		pr_err("Can't install tty port: %d\n", ret);
-		goto err;
-	}
+	ve->vz_tty_conm = tty;
 
+	tty_driver_kref_get(driver);
+	tty->count++;
 	return 0;
-err:
-	tty_port_destroy(&priv->port);
-	kfree(priv);
-	return ret;
+}
+
+static void vz_tty_remove(struct tty_driver *driver, struct tty_struct *tty)
+{
+	struct ve_struct *ve = get_exec_env();
+
+	BUG_ON(driver != vz_conm_driver);
+	ve->vz_tty_conm = NULL;
 }
 
 static int vz_tty_open(struct tty_struct *tty, struct file *filp)
 {
-	struct vz_tty_priv *priv = tty->driver_data;
-	return tty_port_open(&priv->port, tty, filp);
+	set_bit(TTY_THROTTLED, &tty->flags);
+	return 0;
 }
 
 static void vz_tty_close(struct tty_struct *tty, struct file *filp)
 {
-	struct vz_tty_priv *priv = tty->driver_data;
-	tty_port_close(&priv->port, tty, filp);
 }
 
-static void vz_tty_cleanup(struct tty_struct *tty)
+static void vz_tty_shutdown(struct tty_struct *tty)
 {
-	struct vz_tty_priv *priv = tty->driver_data;
+}
 
-	tty->driver_data = NULL;
-	priv->owner_ve = NULL;
-	tty_port_destroy(&priv->port);
-	kfree(priv);
+static void vz_tty_cleanup(struct tty_struct *tty)
+{
+	tty_port_put(tty->port);
 }
 
 static int vz_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
@@ -79,68 +104,159 @@ static int vz_tty_write_room(struct tty_
 	return 4096;
 }
 
-static void vz_tty_hangup(struct tty_struct *tty)
+static void vz_tty_unthrottle(struct tty_struct *tty)
 {
-	struct vz_tty_priv *priv = tty->driver_data;
-	tty_port_hangup(&priv->port);
+	set_bit(TTY_THROTTLED, &tty->flags);
 }
 
 static const struct tty_operations vz_tty_fops = {
+	.lookup		= vz_tty_lookup,
 	.install	= vz_tty_install,
+	.remove		= vz_tty_remove,
 	.open		= vz_tty_open,
 	.close		= vz_tty_close,
+	.shutdown	= vz_tty_shutdown,
 	.cleanup	= vz_tty_cleanup,
 	.write		= vz_tty_write,
 	.write_room	= vz_tty_write_room,
-	.hangup		= vz_tty_hangup,
+	.unthrottle	= vz_tty_unthrottle,
 };
 
-static void __exit vz_exit(void)
+static int __vz_con_ve_init(struct ve_struct *ve)
 {
-	put_tty_driver(vz_con_driver);
+	struct device *d;
+	dev_t dev;
+
+	dev = MKDEV(vz_cons_driver->major, vz_cons_driver->minor_start);
+	d = device_create(vz_con_class, NULL, dev, ve, VZ_CON_SLAVE_NAME);
+
+	return IS_ERR(d) ? PTR_ERR(d) : 0;
 }
-module_exit(vz_exit)
 
-static int __init init(void)
+int vz_con_ve_init(struct ve_struct *ve)
 {
-	int ret = 0;
+	if (ve != get_ve0())
+		return __vz_con_ve_init(ve);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(vz_con_ve_init);
+
+static void __vz_con_ve_fini(struct ve_struct *ve)
+{
+	dev_t dev = MKDEV(vz_cons_driver->major, vz_cons_driver->minor_start);
+	device_destroy_namespace(vz_con_class, dev, ve);
+}
 
-	vz_con_driver = tty_alloc_driver(1,
-					 TTY_DRIVER_REAL_RAW		|
-					 TTY_DRIVER_RESET_TERMIOS	|
-					 TTY_DRIVER_CONTAINERIZED);
-	if (IS_ERR(vz_con_driver)) {
-		pr_err("Couldn't allocate vzcon driver\n");
-		return PTR_ERR(vz_con_driver);
-	}
-
-	vz_con_driver->driver_name	= "vzcon driver";
-	vz_con_driver->name		= "vzcon";
-	vz_con_driver->name_base	= 1;
-	vz_con_driver->major		= 0;
-	vz_con_driver->minor_start	= 1;
-	vz_con_driver->type		= TTY_DRIVER_TYPE_CONSOLE;
-	vz_con_driver->init_termios	= tty_std_termios;
-	vz_con_driver->ve		= get_ve0();
-	tty_set_operations(vz_con_driver, &vz_tty_fops);
+void vz_con_ve_fini(struct ve_struct *ve)
+{
+	if (ve != get_ve0())
+		return __vz_con_ve_fini(ve);
+}
+EXPORT_SYMBOL_GPL(vz_con_ve_fini);
+
+static int __init vz_con_init(void)
+{
+#define TTY_DRIVER_ALLOC_FLAGS			\
+	(TTY_DRIVER_REAL_RAW		|	\
+	 TTY_DRIVER_RESET_TERMIOS	|	\
+	 TTY_DRIVER_UNNUMBERED_NODE	|	\
+	 TTY_DRIVER_DEVPTS_MEM		|	\
+	 TTY_DRIVER_DYNAMIC_ALLOC	|	\
+	 TTY_DRIVER_DYNAMIC_DEV		|	\
+	 TTY_DRIVER_CONTAINERIZED)
 
-	ret = tty_register_driver(vz_con_driver);
+	int ret = 0;
+
+	ret = class_register(&vz_con_class_base);
 	if (ret) {
-		pr_err("Couldn't register vzcon driver\n");
-		put_tty_driver(vz_con_driver);
+		pr_err("Can't register vzcon class\n");
 		return ret;
 	}
 
+	vz_conm_driver = tty_alloc_driver(1, TTY_DRIVER_ALLOC_FLAGS);
+	if (IS_ERR(vz_conm_driver)) {
+		ret = PTR_ERR(vz_conm_driver);
+		pr_err("Can't allocate vzcon master driver\n");
+		goto err_class_unregister;
+	}
+
+	vz_cons_driver = tty_alloc_driver(1, TTY_DRIVER_ALLOC_FLAGS);
+	if (IS_ERR(vz_cons_driver)) {
+		ret = PTR_ERR(vz_cons_driver);
+		pr_err("Can't allocate vzcon slave driver\n");
+		goto err_put_master;
+	}
+
+	vz_conm_driver->driver_name	= "vzcon_master";
+	vz_conm_driver->name		= "vzconm";
+	vz_conm_driver->name_base	= 1;
+	vz_conm_driver->major		= 0;
+	vz_conm_driver->minor_start	= 1;
+	vz_conm_driver->type		= TTY_DRIVER_TYPE_CONSOLE;
+	vz_conm_driver->subtype		= PTY_TYPE_MASTER;
+	vz_conm_driver->init_termios	= tty_std_termios;
+	vz_conm_driver->ve		= get_ve0();
+	tty_set_operations(vz_conm_driver, &vz_tty_fops);
+
+	vz_cons_driver->driver_name	= "vzcon_slave";
+	vz_cons_driver->name		= "vzcons";
+	vz_cons_driver->name_base	= 1;
+	vz_cons_driver->major		= 0;
+	vz_cons_driver->minor_start	= 1;
+	vz_cons_driver->type		= TTY_DRIVER_TYPE_CONSOLE;
+	vz_conm_driver->subtype		= PTY_TYPE_SLAVE;
+	vz_cons_driver->init_termios	= tty_std_termios;
+	vz_cons_driver->ve		= get_ve0();
+	tty_set_operations(vz_cons_driver, &vz_tty_fops);
+
+	ret = tty_register_driver(vz_conm_driver);
+	if (ret) {
+		pr_err("Can't register vzcon master driver\n");
+		goto err_put_slave;
+	}
+	ret = tty_register_driver(vz_cons_driver);
+	if (ret) {
+		pr_err("Can't register vzcon slave driver\n");
+		goto err_unregister_master;
+	}
+
+	ret = __vz_con_ve_init(get_ve0());
+	if (ret) {
+		pr_err("Can't init for node\n");
+		goto err_unregister_slave;
+	}
+
 	return 0;
+
+err_unregister_slave:
+	tty_unregister_driver(vz_cons_driver);
+err_unregister_master:
+	tty_unregister_driver(vz_conm_driver);
+err_put_slave:
+	put_tty_driver(vz_cons_driver);
+err_put_master:
+	put_tty_driver(vz_conm_driver);
+err_class_unregister:
+	class_unregister(&vz_con_class_base);
+	return ret;
+#undef TTY_DRIVER_ALLOC_FLAGS
 }
-module_init(init);
+module_init(vz_con_init);
 
-struct tty_driver *vz_console_device(int *index)
+static void __exit vz_con_exit(void)
 {
-	*index = 0;
-	return vz_con_driver;
+	__vz_con_ve_fini(get_ve0());
+	tty_unregister_driver(vz_conm_driver);
+	tty_unregister_driver(vz_cons_driver);
+	put_tty_driver(vz_conm_driver);
+	put_tty_driver(vz_cons_driver);
+	class_unregister(&vz_con_class_base);
 }
-EXPORT_SYMBOL(vz_console_device);
+module_exit(vz_con_exit)
 
-MODULE_DESCRIPTION("Virtuozzo Container console");
-MODULE_LICENSE("GPL v2");
+struct tty_driver *vz_console_device(int *index)
+{
+	*index = VZ_CON_INDEX;
+	return vz_conm_driver;
+}
+EXPORT_SYMBOL_GPL(vz_console_device);



More information about the Devel mailing list