On Fri, Aug 07, 2015 at 01:04:49PM +0300, Cyrill Gorcunov wrote: > 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 > > FIXME: Once this is applied need to drop kernel/ve/console.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 <gorcu...@virtuozzo.com> > CC: Vladimir Davydov <vdavy...@virtuozzo.com> > CC: Konstantin Khorenko <khore...@virtuozzo.com> > CC: Pavel Emelyanov <xe...@virtuozzo.com> > CC: Andrey Vagin <ava...@virtuozzo.com> > CC: Igor Sukhih <i...@parallels.com> > --- > > Vladimir, take a look please, once time permit. The problems > I met which forced me to rewrite the code being far from pcs6 > variant: > - no owner_ve in tty_struct > - termios no longer dynamically allocated > - tty-write now takes dif arguments type > - can't use alloc_tty_driver anymore, since cdevs are dynamic > - tty-port no loner static > > Hope I addressed all your concerns but still might be missing > somehting since it was really huge thread. > > drivers/tty/pty.c | 580 > +++++++++++++++++++++++++++++++++++++++++++++++++++ > drivers/tty/tty_io.c | 29 -- > include/linux/tty.h | 3 > include/linux/ve.h | 28 +- > kernel/ve/Makefile | 2 > kernel/ve/vecalls.c | 3 > 6 files changed, 612 insertions(+), 33 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,590 @@ static void __init unix98_pty_init(void) > static inline void unix98_pty_init(void) { } > #endif > > +#if defined(CONFIG_VE) && defined(CONFIG_UNIX98_PTYS) > + > +/* > + * 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 > + * > + * When container is opening tty by self (init process > + * or whatever) we create @slave peer and a linked master, > + * and carry them inside map until the kernel explicitly > + * close them. > + * > + * There is one exception though: connecting into container's > + * console from the node. For such case we lookup for existing > + * slave first and if it doesn't exist we allocate a new pair. > + * The main problem is peer closing here: the container may > + * be stopped while node still carries ttys. So we zap such > + * pairs from tracking in fini() routine leaving the kernel > + */ > + > +#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);
Nit: It would be nice to have a comment explaining synchronization rules here. If vtty_idr is protected by a mutex (tty_mutex?), I would also recommend inserting lockdep_assert_held to all the helpers for accessing/modifying vtty_idr below. > + > +static struct file_operations vtty_fops; > + > +#undef VTTY_DEBUG > +#ifdef VTTY_DEBUG > +#define vtty_printk(fmt, ...) > \ > + printk("vtty: %20s: %4d: " fmt, > \ > + __func__, __LINE__, ##__VA_ARGS__) > +#define vtty_printk_one(__tty) > \ > + vtty_printk("tty %p count %4d flags 0x%-8lx\n", > \ > + (__tty), (__tty)->count, (__tty)->flags) > +#define vtty_printk_pair(__tty) > \ > + vtty_printk("tty %p count %4d flags 0x%-8lx link %p count %4d flags > 0x%-8lx\n", \ > + (__tty), (__tty)->count, (__tty)->flags, > \ > + (__tty)->link, (__tty)->link ? (__tty)->link->count : -1, > \ > + (__tty)->link ? (__tty)->link->flags : -1ul) > +#else > +#define vtty_printk(fmt, ...) > +#define vtty_printk_one(__tty) > +#define vtty_printk_pair(__tty) Nit: if (A) vtt_printk(...); won't compile if !VTTY_DEBUG. Use do { } while (0) stubs to overcome this. > +#endif > + > +#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) > +{ > + return idr_find(&vtty_idr, veid); > +} > + > +static void vtty_map_set(vtty_map_t *map, struct tty_struct *tty, int index) > +{ > + vtty_printk("map %p id %d tty %p index %d\n", map, map->veid, tty, > index); > + map->vttys[index] = tty; > +} > + > +static void vtty_map_del(vtty_map_t *map, struct tty_struct *tty, int index) > +{ > + vtty_printk("map %p id %d tty %p index %d\n", map, map ? map->veid : > -1, tty, index); > + if (map) > + map->vttys[index] = NULL; > +} > + > +static void vtty_map_free(vtty_map_t *map) > +{ > + vtty_printk("map %p id %d\n", map, map->veid); > + 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); > + > + 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); > + > + vtty_printk("map %p id %d\n", map, veid); > + return map; > +} > + > +static inline int vtty_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); > +} > + > +#define VTTY_USE_EXEC_VEID (ULONG_MAX) > +static unsigned long current_veid = VTTY_USE_EXEC_VEID; > + > +static void vtty_set_context(envid_t veid) > +{ > + WARN_ON_ONCE(!mutex_is_locked(&tty_mutex)); Nit: locked_assert_held > + current_veid = veid; > +} > + > +static void vtty_drop_context(void) > +{ > + WARN_ON_ONCE(!mutex_is_locked(&tty_mutex)); ditto > + current_veid = VTTY_USE_EXEC_VEID; > +} > + > +static envid_t vtty_get_context(void) > +{ > + BUILD_BUG_ON(sizeof(current_veid) < sizeof(envid_t)); > + WARN_ON_ONCE(!mutex_is_locked(&tty_mutex)); ditto > + > + if (likely(current_veid == VTTY_USE_EXEC_VEID)) > + return get_exec_env()->veid; > + > + return current_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; > + > + WARN_ON_ONCE((driver != vttym_driver) && > + (driver != vttys_driver)); > + > + if (!vtty_match_index(idx)) > + return ERR_PTR(-EIO); > + > + vtty_printk("driver %s index %d\n", driver->driver_name, idx); > + /* > + * Nothing ever been opened yet, allocate a new > + * tty map together with both peers from the scratch > + * in install procedure. > + */ > + if (!map) > + return NULL; > + > + /* > + * FIXME: Strictly speaking there should not Nit: s/FIXME/XXX :-) > + * be requests for master peers from > + * inside of container (ie lookup for > + * vttym_driver). Even vtty_open_master > + * may simply fetch tty->link by self > + * after lookup for slave returned valid > + * tty pointer. But I leave it this way > + * simply because not sure yet how to > + * c/r containers with live connection > + * from nodes and this provides an easier > + * way for testing. > + */ > + tty = map->vttys[idx]; > + if (tty) { > + if (vtty_is_exiting(tty) || > + vtty_is_exiting(tty->link)) > + tty = ERR_PTR(-ENXIO); > + else { > + if (driver == vttym_driver) > + tty = tty->link; > + WARN_ON(!tty); > + } > + } > + vtty_printk("tty %p count %4d\n", > + tty, IS_ERR_OR_NULL(tty) ? -1 : tty->count); > + return tty; > +} > + > +static void vtty_standard_install(vtty_map_t *map, struct tty_driver > *driver, struct tty_struct *tty) > +{ > + WARN_ON(tty_init_termios(tty)); > + > + tty_driver_kref_get(driver); > + tty->count++; > + tty->driver_data = map; > + > + tty_port_init(tty->port); > + tty->port->itty = tty; > +} > + > +static struct tty_struct *vtty_install_peer(vtty_map_t *map, struct > tty_driver *driver, int 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); Nit: Move port allocation before initialize_tty_struct and you won't have to call deinitialize_tty_struct on error path. > + free_tty_struct(tty); > + return ERR_PTR(-ENOMEM); > + } > + vtty_standard_install(map, driver, tty); > + return tty; > +} > + > +static int vtty_install(struct tty_driver *driver, struct tty_struct *tty) > +{ > + envid_t veid = vtty_get_context(); > + struct tty_struct *peer; > + vtty_map_t *map; > + > + 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); > + if (!tty->port) > + return -ENOMEM; > + > + peer = vtty_install_peer(map, vttym_driver, tty->index); > + if (IS_ERR(peer)) { > + vtty_map_del(map, tty, tty->index); > + kfree(tty->port); > + return PTR_ERR(peer); > + } > + set_bit(TTY_EXTRA_REF, &peer->flags); > + > + vtty_standard_install(map, vttys_driver, tty); > + vtty_map_set(map, tty, tty->index); > + > + tty->link = peer; > + peer->link = tty; > + tty->count++; ? > + vtty_printk_pair(tty); > + return 0; > +} > + > +static int vtty_open(struct tty_struct *tty, struct file *filp) > +{ > + if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) > + return -EIO; > + > + clear_bit(TTY_IO_ERROR, &tty->flags); > + clear_bit(TTY_OTHER_CLOSED, &tty->link->flags); > + set_bit(TTY_THROTTLED, &tty->flags); > + > + vtty_printk_pair(tty); > + return 0; > +} > + > +static void vtty_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 (test_bit(TTY_EXTRA_REF, &peer->flags)) { > + clear_bit(TTY_EXTRA_REF, &peer->flags); > + peer->count--; > + > + tty_unlock(tty); > + tty_vhangup(peer); > + tty_lock(tty); Why do you think we need to do this? > + } > + > + vtty_printk_pair(tty); > +} > + > +static void vtty_shutdown(struct tty_struct *tty) > +{ > + vtty_printk_pair(tty); > + vtty_map_del(tty->driver_data, tty, tty->index); > +} > + > +static void vtty_cleanup(struct tty_struct *tty) I'd use pty_cleanup instead. > +{ > + /* > + * Make sure line discipline is off already. > + * It is just for debug reasons. > + */ > + WARN_ON_ONCE(!test_bit(TTY_LDISC_HALTED, &tty->flags)); > + WARN_ON_ONCE(test_bit(TTY_LDISC, &tty->flags)); > + > + tty_port_put(tty->port); > + vtty_printk_one(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 < 2) I.e. we always perform flush on master to slave writes here, right? If so, this is incorrect. Missed a slave reference in tty_install? > + tty_perform_flush(peer, TCIFLUSH); > + } > + } > + > + return count; > +} > + > +static int vtty_write_room(struct tty_struct *tty) > +{ > + struct tty_struct *peer = tty->link; > + > + if (peer->stopped) tty->stopped > + return 0; > + > + if (peer->count < 2) > + return TTY_BUFFER_PAGE; TTY_BUFFER_PAGE looks confusing here, because our write_room method has nothing to do with it. Please use a numeric constant (e.g. 8192). > + > + return pty_space(peer); > +} > + > +static const struct tty_operations vtty_ops = { > + .lookup = vtty_lookup, > + .install = vtty_install, > + .open = vtty_open, > + .close = vtty_close, > + .shutdown = vtty_shutdown, > + .cleanup = vtty_cleanup, > + .write = vtty_write, > + .write_room = vtty_write_room, > + .set_termios = pty_set_termios, > + .unthrottle = pty_unthrottle, > + .remove = pty_unix98_remove, > +}; > + > +struct tty_driver *vtty_console_driver(int *index) > +{ > + *index = 0; > + return vttys_driver; > +} > + > +int vtty_match(dev_t device) > +{ > + return MAJOR(device) == TTY_MAJOR && MINOR(device) < > MAX_NR_VTTY_CONSOLES; > +} > + > +struct tty_driver *vtty_driver(dev_t dev, int *index) > +{ > + BUG_ON(MINOR(dev) >= MAX_NR_VTTY_CONSOLES); > + > + *index = MINOR(dev); > + return vttys_driver; > +} > + > +static void ve_vtty_fini(void *data) > +{ > + struct ve_struct *ve = data; > + vtty_map_t *map = vtty_map_lookup(ve->veid); > + int i; > + > + mutex_lock(&tty_mutex); > + for (i = 0; i < MAX_NR_VTTY_CONSOLES; i++) { > + struct tty_struct *tty = map->vttys[i]; > + if (!tty) > + continue; > + vtty_printk("active tty at %d\n", i); > + vtty_printk_pair(tty); > + tty->driver_data = tty->link->driver_data = NULL; > + } > + mutex_unlock(&tty_mutex); > + vtty_map_free(map); What protects vtty_idr here? > +} > + > +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_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_CONSOLE; > + 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_CONSOLE; > + 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; > + > + vtty_printk("veid %d index %d\n", (int)veid, idx); > + > + 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 hilding > + * the lock. > + */ > + mutex_lock(&tty_mutex); > + vtty_set_context(veid); > + > + tty = vtty_lookup(vttym_driver, NULL, idx); > + if (IS_ERR(tty)) { > + ret = -ENODEV; > + goto err_install; > + } else if (!tty) { > + /* > + * Allocate a new tty pair, the slave > + * won't be having @count here ecause > + * it's not opened by anyone yet. > + */ Hey, wait! It's opened by us, isn't it? Where is the reference? > + tty = tty_init_dev(vttys_driver, idx); > + if (IS_ERR(tty)) > + goto err_install; > + tty->count--; > + tty_unlock(tty); > + tty = tty->link; > + } > + > + /* > + * Make sure the slave peer won't disappear > + * while we're keeping the tty opened. > + */ > + set_bit(TTY_EXTRA_REF, &tty->link->flags); > + tty->link->count++; > + > + vtty_drop_context(); > + > + WARN_ON(!test_bit(TTY_LDISC, &tty->flags)); > + > + clear_bit(TTY_EXTRA_REF, &tty->flags); This juggling with TTY_EXTRA_REF looks suspicious. AFAIU we only need TTY_EXTRA_REF set for master, so that it won't pass away on close unless its slave is dead too, and master must always pin its slave, no? > + tty_add_file(tty, file); > + fd_install(fd, file); > + WARN_ON(vtty_open(tty, file)); > + > + mutex_unlock(&tty_mutex); > + ret = fd; > + > + vtty_printk_pair(tty); > +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 && CONFIG_UNIX98_PTYS */ > + > 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 > @@ -306,6 +306,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", > @@ -1931,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) && vtty_match(device)) { > + driver = tty_driver_kref_get(vtty_driver(device, index)); > *noctty = 1; > return driver; > } > #endif > + > switch (device) { > #ifdef CONFIG_VT > case MKDEV(TTY_MAJOR, 0): { > @@ -1952,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 = vtty_console_driver(index); > #endif > if (console_driver) { > driver = tty_driver_kref_get(console_driver); > @@ -3628,9 +3631,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 +3647,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 +3668,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_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 > @@ -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,24 @@ 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); > > +#define MAX_NR_VTTY_CONSOLES (12) > + > +#ifdef CONFIG_TTY > +extern int vtty_match(dev_t device); > +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); > +#else /* CONFIG_TTY */ > +static inline int vtty_match(dev_t device) { return 0; } > +static inline struct tty_driver *vtty_driver(dev_t dev, int *index) { return > NULL; } > +static inline struct tty_driver *vtty_console_driver(int *index) { return > NULL; } > +static inline int vtty_open_master(envid_t veid, int idx) { return -ENODEV; } > +#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); > _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel