[Devel] [RFC rh7 v2] ve/tty: vt -- Implement per VE support for virtual consoles
Vladimir Davydov
vdavydov at parallels.com
Fri Jul 31 03:51:32 PDT 2015
On Fri, Jul 31, 2015 at 12:54:42PM +0300, Cyrill Gorcunov wrote:
> > > > > +#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?
> > >
> > > Because it's right thing, ptmx called this way simply for hist
> > > reasons and didn't exported for the same. But for our driver
> > > I think it's a good habit to show what's the names we're
> > > exporting via kernel header, instead of hardcoding it into
> > > the kernel. Same applies to MAX_NR_VZT_CONSOLES.
> >
> > None of tty drivers exports names to userspace. Are they all wrong?
>
> They all export it, implicitly. Any change in naming will break
> every userspace tool with works with them. For example ipwireless
It'd break them anyway (need recompilation).
> tty module carries IPWIRELESS_PCCARD_NAME in header. Yes, it's
> not exported into userspace but I'm pretty sure it's a bad practice.
If you think so, please fix it upstream ;-)
> We have (have we?) to export number of consoles, and exporting consoles names
> is good choise as well I think. That said, if you still prefer
> to hide them I will do (moreover, I think there would be no much
> sense in this header at all because exporting only a number of
> consoles won't make situation anyhow better).
Please.
> > > > > +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.
> > >
> > > It's used for locking purpose and doesn't have any
> > > memory barries, so at least smp_ barries needed because
> > > cleanup can be called in any order (for master and
> >
> > Please explain me what can go wrong if you remove
> > smp_mb__before_clear_bit.
>
> /**
> * clear_bit - Clears a bit in memory
> * @nr: Bit to clear
> * @addr: Address to start counting from
> *
> * clear_bit() is atomic and may not be reordered. However, it does
> * not contain a memory barrier, so if it is used for locking purposes,
> * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
> * in order to ensure changes are visible on other processors.
> */
>
> We use it as ordering point for cleanup routine, so we've
> to be sure that other cpus are seeing our changes here.
> If we don't put these routines here I dont expect any
> tragedy because due to mesi other cpus will notify the
> change in any case and waiter still run (and because master peer
> and slave peer are carrying unbound data structures which
> are gonna be freed, any delay or reorded won't hurt the only
> matter here to be sure that structures are freed),
> but I'm not that confident on other archs and this code
> is general code which supposed to work on any arch even
> if we don't build them ever.
What *exactly* can go wrong on any arch of your preference if you remove
this smp_mb__before_clear_bit?
>
> > > slave) but we need to make sure the master is closed
> > > after the slave.
> >
> > Why is that?
>
> Because you may open master and never open slave but master
> carries slave reference, so that there no tty_release ever
> been called on slave peer, but it gonna be cleaned up
> via kref decrement code.
>
> IOW, slave peer may be cleaned up via two cases: via
> explicit release on file close (if it has been opened),
> or via kref-put (if it has not been opened, but master
> slave is closing decrementing slave peer's kref and
> kernel schedule to call cleanup() on both peers but
> cleanup() routine can be called in any order, the
> kernel chooses on its own which one to clean first).
All your cleanup consists of tty_port_put. Why is it bad to call
tty_port_put for master before tty_port_put for slave? Both ttys are
already dead, so why should we care?
>
> Thus we need to bring own order here, and that's
> done via wait-bit.
> > > > > +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.
> > >
> > > ok
> >
> > Do we really need to perform flush if both master and slave are open?
>
> Yes. Open state only mean that there is a reader, but reader might not
> yet be ready to fetch all data, so the base idea is to not block inside
> write ever.
That's a wrong idea. We must block writes if there is a reader. Think
what will happen if our VNC viewer does not manage to read data in time.
>
> > >
> > > ok
> >
> > Please explain me now what "tty_is_master(tty) ? 1 : 2" means.
>
> I'll add a comment. In short -- master peer always carry an
> aditional count reference on the peer, so the kernel wont
> free slave peer structure until it's explicitly done on
> master peer release.
I think we should drop data only if we write to master and there is no
slave, i.e. if peer->count < 2.
>
> > > > > +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?
> > >
> > > I don't think so. I tried all my best to make this module as a separate
> > > one, previous vtty code is really-really hard to support. I'll rather
> > > add comments here why these bits are present. OK?
> >
> > I don't ask you to hack into the pty code. You just place your code
> > wrapped in CONFIG_VE in drivers/char/pty.c and reuse only those pty
> > functions that do not need modification, like set_termios. Why is that
> > worse than copy-n-pasting?
>
> Simply because I didn't use much code from pty. The only real copy
> is set termios. I really don't wanna uglify pty.c with our CONFIG_VE
> just for this piece.
Why "uglify"? I said you don't mess with pty code. You only add your
code in this file accurately wrapped in CONFIG_VE. Why do you think it's
ugly?
Seriously, pty and vtty look alike. IMO it's better to keep them
together.
>
> > > > > +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.
> > >
> > > You know, this map keeps only ~196 bytes and at first I thought about
> > > keeping it inside ve structure, but then thought it gonna be a bad
> > > idea that such data lives outside of the module code. IOW I didn't
> > > want to free it at all at first ;) Adding ref only make code more
> > > complex I think (and make it very close to venet accounting :)
> > > Lets better stick with simplier?
> >
> > I have a bad feeling about it. What if tty slave is still open? Panic?
>
> On exit files are closed before the ve get vanished as far as I remember,
> so slave peer get released before we free the map.
>
OK, I surrender this point for now.
More information about the Devel
mailing list