[Devel] [RFC rh7 v2] ve/tty: vt -- Implement per VE support for virtual consoles
Vladimir Davydov
vdavydov at parallels.com
Fri Jul 31 02:04:46 PDT 2015
On Thu, Jul 30, 2015 at 08:27:21PM +0300, Cyrill Gorcunov wrote:
> On Thu, Jul 30, 2015 at 07:33:47PM +0300, Vladimir Davydov wrote:
> > 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?
>
> Whatever you like ;) I'll rename, sure.
I'd prefer to stick to names from PCS6, vtty and vttm, but it's up to
you.
>
> > > 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?
>
> 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?
> > > +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?
>
> tty_mutex locks only one peer, but we need to make shutdown
> procedure be ordered (they may start simultaneously)
I'm afraid I still don't understand what you mean.
tty's ->shutdown method is always called with the global tty_mutex held,
so what's the point in taking the vzt_mutex, which you never take
anywhere else?
>
> > > + 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.
>
> 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.
> slave) but we need to make sure the master is closed
> after the slave.
Why is that?
>
> >
> > > + 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);
BTW, do we really need to call tty_free_termios here? Isn't it freed in
release_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?
>
> I think so. In worst scenario (say slave peer never closed,
> or task killed before slave finished it work) the pair
> simply become unopenable (as far as I can say) but it
> doesn't lock the whole system. Is there something I'm missing?
>
> >
> > > +
> > > + 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.
>
> ok
Do we really need to perform flush if both master and slave are open?
>
> > > +
> > > +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.
>
> ok
Please explain me now what "tty_is_master(tty) ? 1 : 2" means.
>
> >
> > > + 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?
>
> 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?
> > > +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?
More information about the Devel
mailing list