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");
> 
_______________________________________________
Devel mailing list
[email protected]
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to