[Devel] [RFC rh7 v2] ve/tty: vt -- Implement per VE support for virtual consoles
Vladimir Davydov
vdavydov at parallels.com
Thu Jul 30 09:33:47 PDT 2015
On Thu, Jul 30, 2015 at 03:51:55PM +0300, Cyrill Gorcunov wrote:
> 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
> @@ -104,6 +104,7 @@
> #include <linux/kmod.h>
> #include <linux/nsproxy.h>
> #include <linux/ve.h>
> +#include <uapi/linux/vzt.h>
For me, vzt is inevitably associated with our test suit. A test for
testing it would be called vzt-vzt I suppose :-) May be we'd better call
it vtty to avoid confusion?
>
> #undef TTY_DEBUG_HANGUP
>
> @@ -306,6 +307,10 @@ static int check_tty_count(struct tty_st
> tty->driver->subtype == PTY_TYPE_SLAVE &&
> tty->link && tty->link->count)
> count++;
> +#ifdef CONFIG_VE
> + if (test_bit(TTY_EXTRA_REF, &tty->flags))
> + count++;
> +#endif
> if (tty->count != count) {
> printk(KERN_WARNING "Warning: dev (%s) tty->count(%d) "
> "!= #fd's(%d) in %s\n",
> @@ -1930,14 +1935,15 @@ 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));
> + struct ve_struct *ve = get_exec_env();
> +
> + if (!ve_is_super(ve) && vzt_match(device)) {
> + driver = tty_driver_kref_get(vzt_driver(device, index));
> *noctty = 1;
> return driver;
> }
> #endif
> +
> switch (device) {
> #ifdef CONFIG_VT
> case MKDEV(TTY_MAJOR, 0): {
> @@ -1951,10 +1957,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 = vzt_console_driver(index);
> #endif
> if (console_driver) {
> driver = tty_driver_kref_get(console_driver);
> @@ -3617,9 +3621,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();
> @@ -3636,7 +3637,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)
> @@ -3658,15 +3658,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
> @@ -321,6 +321,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_EXTRA_REF 24 /* Carries extra reference */
> +#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
> @@ -25,6 +25,7 @@
> #include <net/inet_frag.h>
> #include <linux/cgroup.h>
> #include <linux/kmapset.h>
> +#include <uapi/linux/vzt.h>
>
> struct tty_driver;
> struct file_system_type;
> @@ -66,13 +67,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
> Index: linux-pcs7.git/include/uapi/linux/Kbuild
> ===================================================================
> --- linux-pcs7.git.orig/include/uapi/linux/Kbuild
> +++ linux-pcs7.git/include/uapi/linux/Kbuild
> @@ -401,6 +401,7 @@ header-y += v4l2-dv-timings.h
> header-y += v4l2-mediabus.h
> header-y += v4l2-subdev.h
> header-y += veth.h
> +header-y += vzt.h
> header-y += vfio.h
> header-y += vhost.h
> header-y += videodev2.h
> Index: linux-pcs7.git/include/uapi/linux/vzt.h
> ===================================================================
> --- /dev/null
> +++ linux-pcs7.git/include/uapi/linux/vzt.h
> @@ -0,0 +1,30 @@
> +#ifndef _UAPI_LINUX_VZT_H
> +#define _UAPI_LINUX_VZT_H
> +
> +#define MAX_NR_VZT_CONSOLES (12)
> +
> +#define VZT_MASTER_DRIVER_NAME "vzt_master"
> +#define VZT_MASTER_NAME "vztm"
> +
> +#define VZT_SLAVE_DRIVER_NAME "vzt_slave"
> +#define VZT_SLAVE_NAME "vzts"
I don't think we need this in uapi. Both "ptmx" and "tty" are hardcoded,
why should we be different?
> +
> +#ifdef __KERNEL__
> +
> +struct tty_driver;
> +struct class;
> +
> +#ifdef CONFIG_TTY
> +extern int vzt_match(dev_t device);
> +extern struct tty_driver *vzt_driver(dev_t dev, int *index);
> +extern struct tty_driver *vzt_console_driver(int *index);
> +
> +#else /* CONFIG_TTY */
> +
> +static inline int vzt_match(dev_t device) { return 0; }
> +
> +#endif /* CONFIG_TTY */
> +
> +#endif /* __KERNEL__ */
> +
> +#endif /* _UAPI_LINUX_VZT_H */
> Index: linux-pcs7.git/kernel/ve/Makefile
> ===================================================================
> --- linux-pcs7.git.orig/kernel/ve/Makefile
> +++ linux-pcs7.git/kernel/ve/Makefile
> @@ -4,7 +4,10 @@
> # 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
> +ifdef CONFIG_TTY
> +obj-$(CONFIG_VE) += vzt.o
> +endif
> obj-$(CONFIG_VZ_WDOG) += vzwdog.o
> obj-$(CONFIG_VE_CALLS) += vzmon.o
>
[...]
> Index: linux-pcs7.git/kernel/ve/vzt.c
> ===================================================================
> --- /dev/null
> +++ linux-pcs7.git/kernel/ve/vzt.c
> @@ -0,0 +1,485 @@
> +#define pr_fmt(fmt) "vzt: " fmt
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/device.h>
> +#include <linux/mutex.h>
> +#include <linux/init.h>
> +
> +#include <linux/tty.h>
> +#include <linux/tty_flip.h>
> +
> +#include <linux/ve.h>
> +
> +static struct tty_driver *vztm_driver;
> +static struct tty_driver *vzts_driver;
> +static DEFINE_MUTEX(vzt_mutex);
> +static DEFINE_IDR(vzt_idr);
> +
> +#define driver_is_master(d) ((d) == vztm_driver)
> +#define driver_is_slave(d) ((d) == vzts_driver)
No need in this macro - you can use !driver_is_master instead.
> +#define tty_is_master(t) driver_is_master((t)->driver)
> +#define tty_is_slave(t) driver_is_slave((t)->driver)
ditto
> +
> +/*
> + * Reuse TTY_PTY_LOCK for own needs because we don't
> + * provide locking for these terminals.
> + */
> +#define TTY_VT_OPEN TTY_PTY_LOCK
> +
> +typedef struct {
> + envid_t veid;
> + struct tty_struct *master[MAX_NR_VZT_CONSOLES];
> + struct tty_struct *slave[MAX_NR_VZT_CONSOLES];
> +} tty_map_t;
> +
> +static tty_map_t *tty_map_lookup(envid_t veid)
> +{
> + return idr_find(&vzt_idr, veid);
> +}
> +
> +static void tty_map_remove(tty_map_t *map)
> +{
> + if (map)
> + idr_remove(&vzt_idr, map->veid);
> + kfree(map);
> +}
> +
> +static void tty_map_zap(tty_map_t *map, int index)
> +{
> + map->master[index] = map->slave[index] = NULL;
> +}
> +
> +static tty_map_t *tty_map_alloc(envid_t veid)
> +{
> + tty_map_t *map = kzalloc(sizeof(*map), GFP_KERNEL);
> +
> + if (map) {
> + map->veid = veid;
> + veid = idr_alloc(&vzt_idr, map, veid, veid + 1, GFP_KERNEL);
> + if (veid < 0) {
> + kfree(map);
> + return ERR_PTR(veid);
> + }
> + idr_replace(&vzt_idr, map, veid);
What is this for? vzt_idr[veid] must already equal map.
> + } else
> + return ERR_PTR(-ENOMEM);
> + return map;
> +}
> +
> +static inline int tty_is_exiting(struct tty_struct *tty)
> +{
> + return test_bit(TTY_CLOSING, &tty->flags) ||
> + test_bit(TTY_HUPPING, &tty->flags) ||
> + test_bit(TTY_LDISC_CHANGING, &tty->flags) ||
> + tty->count < 1;
> +}
> +
> +static struct tty_driver *vzt_other(struct tty_driver *driver)
> +{
> + return driver_is_master(driver) ? vzts_driver : vztm_driver;
> +}
> +
> +/*
> + * Creating new tty via lookup nil return is allowed for master
> + * peer only, the slave one should be opened iif master is there.
> + */
> +static struct tty_struct *vzt_tty_lookup(struct tty_driver *driver,
> + struct inode *inode, int idx)
> +{
> + tty_map_t *map = tty_map_lookup(get_exec_env()->veid);
> + struct tty_struct *tty;
> +
> + if (idx < 0 || idx >= MAX_NR_VZT_CONSOLES)
> + return ERR_PTR(-EIO);
if (!map)
return ERR_PTR(-ENXIO);
will free you from the responsibility to check if map == NULL below.
> +
> + if (driver_is_slave(driver)) {
> + struct tty_struct *peer = map ? map->master[idx] : NULL;
> + struct tty_struct *me = map ? map->slave[idx] : NULL;
> +
> + tty = (peer && !tty_is_exiting(peer)) ?
> + (me && !tty_is_exiting(me) ?
> + me : ERR_PTR(-ENXIO)) :
> + ERR_PTR(-ENXIO);
It's difficult to read. Rewrite it w/o using ?: please.
> + } else {
> + tty = map ? map->master[idx] : NULL;
> + if (tty && tty_is_exiting(tty))
if (!tty || tty_is_exiting(tty))
?
> + tty = ERR_PTR(-ENXIO);
> + }
> +
> + return tty;
> +}
> +
> +static int vzt_tty_standard_install(struct tty_driver *driver, struct tty_struct *tty)
> +{
> + tty_map_t *map = tty->driver_data;
> + int ret = tty_init_termios(tty);
> + if (ret)
> + return ret;
> +
> + tty_driver_kref_get(driver);
> + tty->count++;
> + if (driver_is_master(driver))
> + map->master[tty->index] = tty;
> + else
> + map->slave[tty->index] = tty;
> + return 0;
> +}
> +
> +static struct tty_struct *vzt_install_slave(struct tty_driver *driver_master, struct tty_struct *tty_master)
> +{
> + struct tty_driver *driver = vzt_other(driver_master);
> + int index = tty_master->index;
> + struct tty_struct *tty;
> +
> + tty = alloc_tty_struct();
> + if (!tty)
> + return ERR_PTR(-ENOMEM);
> + initialize_tty_struct(tty, driver, index);
> +
> + tty->port = kzalloc(sizeof(*tty->port), GFP_KERNEL);
> + if (!tty->port) {
> + deinitialize_tty_struct(tty);
> + free_tty_struct(tty);
> + return ERR_PTR(-ENOMEM);
> + }
> + tty->driver_data = tty_master->driver_data;
> + WARN_ON(vzt_tty_standard_install(driver, tty));
> + tty_port_init(tty->port);
> + tty->port->itty = tty;
> +
> + set_bit(TTY_EXTRA_REF, &tty->flags);
> + return tty;
> +}
> +
> +static int vzt_tty_install(struct tty_driver *driver, struct tty_struct *tty)
> +{
> + envid_t veid = get_exec_env()->veid;
> + struct tty_struct *peer;
> + tty_map_t *map;
> +
> + map = tty_map_lookup(veid);
> + if (!map) {
> + map = tty_map_alloc(veid);
> + if (IS_ERR_OR_NULL(tty))
IS_ERR(map)
?
> + return PTR_ERR(map);
> + }
> + tty->driver_data = map;
> +
> + tty->port = kzalloc(sizeof(*tty->port), GFP_KERNEL);
> + if (!tty->port)
> + return -ENOMEM;
> +
> + peer = vzt_install_slave(driver, tty);
> + if (IS_ERR(peer)) {
> + tty_map_zap(map, tty->index);
> + kfree(tty->port);
> + return PTR_ERR(peer);
> + }
> + WARN_ON(vzt_tty_standard_install(driver, tty));
> + tty_port_init(tty->port);
> + tty->port->itty = tty;
> +
> + tty->link = peer;
> + peer->link = tty;
> +
> + tty_kref_get(peer);
> + return 0;
> +}
> +
> +static void vzt_tty_remove(struct tty_driver *driver, struct tty_struct *tty)
> +{
> + tty_map_t *map = tty->driver_data;
> +
> + if (driver_is_master(driver))
> + map->master[tty->index] = NULL;
> + else
> + map->slave[tty->index] = NULL;
> +}
> +
> +static int vzt_tty_open(struct tty_struct *tty, struct file *filp)
> +{
> + if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
> + return -EIO;
> +
> + if (tty_is_slave(tty))
> + set_bit(TTY_VT_OPEN, &tty->link->flags);
> +
> + clear_bit(TTY_IO_ERROR, &tty->flags);
> + clear_bit(TTY_OTHER_CLOSED, &tty->flags);
> + clear_bit(TTY_OTHER_CLOSED, &tty->link->flags);
> + set_bit(TTY_THROTTLED, &tty->flags);
> + return 0;
> +}
> +
> +static void vzt_tty_close(struct tty_struct *tty, struct file *filp)
> +{
> + struct tty_struct *peer = tty->link;
> +
> + if (tty->count > 1)
> + return;
> +
> + if (test_bit(TTY_IO_ERROR, &tty->flags))
> + return;
> +
> + wake_up_interruptible(&tty->read_wait);
> + wake_up_interruptible(&tty->write_wait);
> +
> + wake_up_interruptible(&peer->read_wait);
> + wake_up_interruptible(&peer->write_wait);
> +
> + set_bit(TTY_IO_ERROR, &tty->flags);
> + set_bit(TTY_OTHER_CLOSED, &peer->flags);
> +
> + if (tty_is_master(tty)) {
> + clear_bit(TTY_EXTRA_REF, &peer->flags);
> + peer->count--;
> +
> + tty_unlock(tty);
> + tty_vhangup(peer);
> + tty_lock(tty);
> + }
> +}
> +
> +static int vzt_tty_sleep_fn(void *flags)
> +{
> + schedule();
> + return 0;
> +}
> +
> +static void vzt_tty_shutdown(struct tty_struct *tty)
> +{
> + mutex_lock(&vzt_mutex);
AFAIU this function is always called under tty_mutex. What's the point
in the vzt_mutex then?
> +
> + if (tty_is_slave(tty)) {
> + if (!test_bit(TTY_VT_OPEN, &tty->flags)) {
> + set_bit(TTY_VT_OPEN, &tty->flags);
> + tty_kref_put(tty);
> + }
> + } else {
> + if (!test_bit(TTY_VT_OPEN, &tty->link->flags)) {
> + set_bit(TTY_VT_OPEN, &tty->link->flags);
> + tty_kref_put(tty->link);
> + }
> + }
> +
> + tty->port->itty = NULL;
> + tty->link->port->itty = NULL;
> +
> + tty_driver_remove_tty(tty->driver, tty);
> + tty_driver_remove_tty(vzt_other(tty->driver), tty);
> +
> + mutex_unlock(&vzt_mutex);
> +}
> +
> +static void vzt_tty_cleanup(struct tty_struct *tty)
> +{
> + if (tty_is_slave(tty)) {
> + smp_mb__before_clear_bit();
Why?
And please comment what you're trying to achieve here.
> + clear_bit(TTY_VT_OPEN, &tty->link->flags);
> + smp_mb__after_clear_bit();
> + wake_up_bit(&tty->link->flags, TTY_VT_OPEN);
> +
> + tty_free_termios(tty);
> + cancel_work_sync(&tty->port->buf.work);
> + } else {
> + wait_on_bit(&tty->flags, TTY_VT_OPEN,
> + vzt_tty_sleep_fn, TASK_KILLABLE);
Why is TASK_KILLABLE safe?
> +
> + tty_free_termios(tty);
> + cancel_work_sync(&tty->port->buf.work);
> + }
> +
> + WARN_ON_ONCE(test_bit(TTY_LDISC, &tty->flags));
> + WARN_ON_ONCE(!test_bit(TTY_LDISC_HALTED, &tty->flags));
> +
> + tty_port_put(tty->port);
> +}
> +
> +static int vzt_tty_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
> + tty_perform_flush(peer, TCIFLUSH);
A comment explaining why you perform flush here would be nice to have.
> + }
> +
> + return count;
> +}
> +
> +static int vzt_tty_write_room(struct tty_struct *tty)
> +{
> + struct tty_struct *peer = tty->link;
> + int n;
> +
> + if (tty->stopped)
> + return 0;
> +
> + if (peer->count < tty_is_master(tty) ? 1 : 2)
Please add a comment explaining why you distinguish master tty.
Also, a general comment on what you're trying to achieve here would be
good.
> + return TTY_BUFFER_PAGE;
> +
> + n = TTY_BUFFER_PAGE - peer->port->buf.memory_used;
> + return n < 0 ? 0 : n;
> +}
> +
> +static void vzt_tty_set_termios(struct tty_struct *tty, struct ktermios * old)
> +{
> + tty->termios.c_cflag &= ~(CSIZE | PARENB);
> + tty->termios.c_cflag |= (CS8 | CREAD);
OK, this is copied from pty_set_termios. Please mention it here and
everywhere you copy-n-paste from pty.c. BTW, wouldn't it be better to
keep the code in pty.c in order to avoid these code duplications?
> +}
> +
> +static void vzt_tty_unthrottle(struct tty_struct *tty)
> +{
> + tty_wakeup(tty->link);
> + set_bit(TTY_THROTTLED, &tty->flags);
> +}
> +
> +static const struct tty_operations vzt_tty_fops = {
> + .lookup = vzt_tty_lookup,
> + .install = vzt_tty_install,
> + .open = vzt_tty_open,
> + .close = vzt_tty_close,
> + .shutdown = vzt_tty_shutdown,
> + .cleanup = vzt_tty_cleanup,
> + .write = vzt_tty_write,
> + .write_room = vzt_tty_write_room,
> + .set_termios = vzt_tty_set_termios,
> + .unthrottle = vzt_tty_unthrottle,
> + .remove = vzt_tty_remove,
> +};
> +
> +struct tty_driver *vzt_console_driver(int *index)
> +{
> + *index = 0;
> + return vztm_driver;
> +}
> +EXPORT_SYMBOL_GPL(vzt_console_driver);
Why do you export it?
> +
> +int vzt_match(dev_t device)
> +{
> + return MAJOR(device) == TTY_MAJOR && MINOR(device) < MAX_NR_VZT_CONSOLES;
> +}
> +EXPORT_SYMBOL_GPL(vzt_match);
ditto
> +
> +struct tty_driver *vzt_driver(dev_t dev, int *index)
> +{
> + BUG_ON(MINOR(dev) >= MAX_NR_VZT_CONSOLES);
> +
> + *index = MINOR(dev);
> + return vztm_driver;
> +}
> +EXPORT_SYMBOL_GPL(vzt_driver);
ditto
> +
> +static void ve_vzt_fini(void *data)
> +{
> + struct ve_struct *ve = data;
> + tty_map_remove(tty_map_lookup(ve->veid));
I think we'd better make tty_map_t ref-countable and free it once the
last tty using it is destroyed.
> +}
> +
> +static struct ve_hook vzt_hook = {
> + .fini = ve_vzt_fini,
> + .priority = HOOK_PRIO_DEFAULT,
> + .owner = THIS_MODULE,
> +};
> +
> +static int __init vzt_module_init(void)
> +{
> +#define TTY_DRIVER_ALLOC_FLAGS \
> + (TTY_DRIVER_REAL_RAW | \
> + TTY_DRIVER_RESET_TERMIOS | \
> + TTY_DRIVER_DEVPTS_MEM)
> +
> + int ret, i;
> +
> + vztm_driver = tty_alloc_driver(MAX_NR_VZT_CONSOLES, TTY_DRIVER_ALLOC_FLAGS);
> + if (IS_ERR(vztm_driver)) {
> + ret = PTR_ERR(vztm_driver);
> + pr_err("Can't allocate vt master driver\n");
> + return ret;
> + }
> +
> + vzts_driver = tty_alloc_driver(MAX_NR_VZT_CONSOLES, TTY_DRIVER_ALLOC_FLAGS);
> + if (IS_ERR(vzts_driver)) {
> + ret = PTR_ERR(vzts_driver);
> + pr_err("Can't allocate vt slave driver\n");
> + goto err_put_master;
> + }
> +
> + vztm_driver->driver_name = VZT_MASTER_DRIVER_NAME;
> + vztm_driver->name = VZT_MASTER_NAME;
> + vztm_driver->name_base = 0;
> + vztm_driver->major = 0;
> + vztm_driver->minor_start = 0;
> + vztm_driver->type = TTY_DRIVER_TYPE_CONSOLE;
> + vztm_driver->init_termios = tty_std_termios;
> + vztm_driver->init_termios.c_iflag = 0;
> + vztm_driver->init_termios.c_oflag = 0;
> + vztm_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
> + vztm_driver->init_termios.c_lflag = 0;
> + vztm_driver->init_termios.c_ispeed = 38400;
> + vztm_driver->init_termios.c_ospeed = 38400;
> + tty_set_operations(vztm_driver, &vzt_tty_fops);
> +
> + vzts_driver->driver_name = VZT_SLAVE_DRIVER_NAME;
> + vzts_driver->name = VZT_SLAVE_NAME;
> + vzts_driver->name_base = 0;
> + vzts_driver->major = 0;
> + vzts_driver->minor_start = 0;
> + vzts_driver->type = TTY_DRIVER_TYPE_CONSOLE;
> + vzts_driver->init_termios = tty_std_termios;
> + vzts_driver->init_termios.c_iflag = 0;
> + vzts_driver->init_termios.c_oflag = 0;
> + vzts_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
> + vzts_driver->init_termios.c_lflag = 0;
> + vzts_driver->init_termios.c_ispeed = 38400;
> + vzts_driver->init_termios.c_ospeed = 38400;
> + tty_set_operations(vzts_driver, &vzt_tty_fops);
> +
> + ret = tty_register_driver(vztm_driver);
> + if (ret) {
> + pr_err("Can't register vt master driver\n");
> + goto err_put_slave;
> + }
> +
> + ret = tty_register_driver(vzts_driver);
> + if (ret) {
> + pr_err("Can't register vt master driver\n");
> + goto err_unregister_master;
> + }
> +
> + ve_hook_register(VE_SS_CHAIN, &vzt_hook);
> + return 0;
> +
> +err_unregister_slave:
> + tty_unregister_driver(vzts_driver);
> +err_unregister_master:
> + tty_unregister_driver(vztm_driver);
> +err_put_slave:
> + put_tty_driver(vzts_driver);
> +err_put_master:
> + put_tty_driver(vztm_driver);
> + return ret;
> +#undef TTY_DRIVER_ALLOC_FLAGS
> +}
> +module_init(vzt_module_init);
> +
> +static void __exit vzt_module_fini(void)
> +{
> + ve_hook_unregister(&vzt_hook);
> + tty_unregister_driver(vzts_driver);
> + tty_unregister_driver(vztm_driver);
> + put_tty_driver(vzts_driver);
> + put_tty_driver(vztm_driver);
> +}
> +module_exit(vzt_module_fini);
It can't be a module, because tty_io.c depends on it.
> +
> +MODULE_LICENSE("GPL v2");
> +MODULE_DESCRIPTION("Virtual terminals emulation for VE environment");
>
More information about the Devel
mailing list