All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] qemu-char: don't issue CHR_EVENT_OPEN in a BH
@ 2013-05-29 22:27 Michael Roth
  2013-05-30 16:55 ` Anthony Liguori
  0 siblings, 1 reply; 7+ messages in thread
From: Michael Roth @ 2013-05-29 22:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, s.priebe, qemu-stable, lcapitulino

When CHR_EVENT_OPEN was initially added, it was CHR_EVENT_RESET, and
it was issued as a bottom-half:

86e94dea5b740dad65446c857f6959eae43e0ba6

AFAICT the only reason this was ever done in a BH was because it was
initially used to to issue a CHR_EVENT_RESET when we initialized the
monitor, and we would in some cases modify the chr_write handler for
a new chardev backend *after* the site where we issued the reset
(see: 86e94d:qemu_chr_open_stdio())

So we executed the reset in a BH to ensure the chardev was fully
initialized before we executed the CHR_EVENT_RESET handler (which
generally involved printing out a greeting/prompt for the monitor).

At some point this event was renamed to CHR_EVENT_OPEN, and we've
maintained the use of this BH ever since.

However, due to 9f939df955a4152aad69a19a77e0898631bb2c18, we schedule
the BH via g_idle_add(), which is causing events to sometimes be
delivered after we've already begun processing data from backends,
leading to:

 known bugs:

  QMP:
    session negotation resets with OPEN event, in some cases this
    is causing new sessions to get sporadically reset

 potential bugs:

  hw/usb/redirect.c:
    can_read handler checks for dev->parser != NULL, which may be
    true if CLOSED BH has not been executed yet. In the past, OPENED
    quiesced outstanding CLOSED events prior to us reading client
    data. If it's delayed, our check may allow reads to occur even
    though we haven't processed the OPENED event yet, and when we
    do finally get the OPENED event, our state may get reset.

  qtest.c:
    can begin session before OPENED event is processed, leading to
    a spurious reset of the system and irq_levels

  gdbstub.c:
    may start a gdb session prior to the machine being paused

To fix these, let's just drop the BH.

Since the initial reasoning for using it still applies to an extent,
work around that be deferring the delivery of CHR_EVENT_OPENED until
after the chardevs have been fully initialized by setting a
'be_open_on_init' flag that gets checked toward the end of
qmp_chardev_add(). This defers delivery long enough that we can
be assured a CharDriverState is fully initialized before
CHR_EVENT_OPENED is sent.

Reported-by: Stefan Priebe <s.priebe@profihost.ag>
Cc: qemu-stable@nongnu.org
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 backends/baum.c       |    2 +-
 include/sysemu/char.h |    2 +-
 qemu-char.c           |   29 ++++++++++-------------------
 ui/console.c          |    2 +-
 ui/gtk.c              |    2 +-
 5 files changed, 14 insertions(+), 23 deletions(-)

diff --git a/backends/baum.c b/backends/baum.c
index 4cba79f..8384ef2 100644
--- a/backends/baum.c
+++ b/backends/baum.c
@@ -611,7 +611,7 @@ CharDriverState *chr_baum_init(void)
 
     qemu_set_fd_handler(baum->brlapi_fd, baum_chr_read, NULL, baum);
 
-    qemu_chr_be_generic_open(chr);
+    chr->be_open_on_init = true;
 
     return chr;
 
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 5e42c90..dc7a0d8 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -70,13 +70,13 @@ struct CharDriverState {
     void (*chr_set_echo)(struct CharDriverState *chr, bool echo);
     void (*chr_set_fe_open)(struct CharDriverState *chr, int fe_open);
     void *opaque;
-    int idle_tag;
     char *label;
     char *filename;
     int be_open;
     int fe_open;
     int explicit_fe_open;
     int avail_connections;
+    bool be_open_on_init;
     QemuOpts *opts;
     QTAILQ_ENTRY(CharDriverState) next;
 };
diff --git a/qemu-char.c b/qemu-char.c
index 4f8382e..c553fbe 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -110,19 +110,9 @@ void qemu_chr_be_event(CharDriverState *s, int event)
     s->chr_event(s->handler_opaque, event);
 }
 
-static gboolean qemu_chr_be_generic_open_bh(gpointer opaque)
-{
-    CharDriverState *s = opaque;
-    qemu_chr_be_event(s, CHR_EVENT_OPENED);
-    s->idle_tag = 0;
-    return FALSE;
-}
-
 void qemu_chr_be_generic_open(CharDriverState *s)
 {
-    if (s->idle_tag == 0) {
-        s->idle_tag = g_idle_add(qemu_chr_be_generic_open_bh, s);
-    }
+    qemu_chr_be_event(s, CHR_EVENT_OPENED);
 }
 
 int qemu_chr_fe_write(CharDriverState *s, const uint8_t *buf, int len)
@@ -505,7 +495,7 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
     chr->chr_set_fe_open = NULL;
 
     /* Muxes are always open on creation */
-    qemu_chr_be_generic_open(chr);
+    chr->be_open_on_init = true;
 
     return chr;
 }
@@ -882,8 +872,7 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out)
     chr->chr_write = fd_chr_write;
     chr->chr_update_read_handler = fd_chr_update_read_handler;
     chr->chr_close = fd_chr_close;
-
-    qemu_chr_be_generic_open(chr);
+    chr->be_open_on_init = true;
 
     return chr;
 }
@@ -1594,8 +1583,7 @@ static CharDriverState *qemu_chr_open_pp_fd(int fd)
     chr->chr_ioctl = pp_ioctl;
     chr->chr_close = pp_close;
     chr->opaque = drv;
-
-    qemu_chr_be_generic_open(chr);
+    chr->be_open_on_init = true;
 
     return chr;
 }
@@ -1880,7 +1868,7 @@ static CharDriverState *qemu_chr_open_win_path(const char *filename)
         g_free(chr);
         return NULL;
     }
-    qemu_chr_be_generic_open(chr);
+    chr->be_open_on_init = true;
     return chr;
 }
 
@@ -1980,7 +1968,7 @@ static CharDriverState *qemu_chr_open_pipe(ChardevHostdev *opts)
         g_free(chr);
         return NULL;
     }
-    qemu_chr_be_generic_open(chr);
+    chr->be_open_on_init = true;
     return chr;
 }
 
@@ -1994,7 +1982,7 @@ static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out)
     s->hcom = fd_out;
     chr->opaque = s;
     chr->chr_write = win_chr_write;
-    qemu_chr_be_generic_open(chr);
+    chr->be_open_on_init = true;
     return chr;
 }
 
@@ -3803,6 +3791,9 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
         chr->label = g_strdup(id);
         chr->avail_connections =
             (backend->kind == CHARDEV_BACKEND_KIND_MUX) ? MAX_MUX : 1;
+        if (chr->be_open_on_init) {
+            qemu_chr_be_event(chr, CHR_EVENT_OPENED);
+        }
         QTAILQ_INSERT_TAIL(&chardevs, chr, next);
         return ret;
     } else {
diff --git a/ui/console.c b/ui/console.c
index b30853f..79b5104 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1746,7 +1746,7 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
         s->t_attrib = s->t_attrib_default;
     }
 
-    qemu_chr_be_generic_open(chr);
+    chr->be_open_on_init = true;
     if (chr->init)
         chr->init(chr);
 }
diff --git a/ui/gtk.c b/ui/gtk.c
index 52c3f95..a7603da 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -1214,7 +1214,7 @@ static GSList *gd_vc_init(GtkDisplayState *s, VirtualConsole *vc, int index, GSL
 
     gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), vc->menu_item);
 
-    qemu_chr_be_generic_open(vc->chr);
+    vc->chr->be_open_on_init = true;
     if (vc->chr->init) {
         vc->chr->init(vc->chr);
     }
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [Qemu-devel] [PATCH] qemu-char: don't issue CHR_EVENT_OPEN in a BH
  2013-05-29 22:27 [Qemu-devel] [PATCH] qemu-char: don't issue CHR_EVENT_OPEN in a BH Michael Roth
@ 2013-05-30 16:55 ` Anthony Liguori
  2013-05-30 18:48   ` mdroth
  0 siblings, 1 reply; 7+ messages in thread
From: Anthony Liguori @ 2013-05-30 16:55 UTC (permalink / raw)
  To: Michael Roth, qemu-devel; +Cc: s.priebe, qemu-stable, lcapitulino

Michael Roth <mdroth@linux.vnet.ibm.com> writes:

> When CHR_EVENT_OPEN was initially added, it was CHR_EVENT_RESET, and
> it was issued as a bottom-half:
>
> 86e94dea5b740dad65446c857f6959eae43e0ba6
>
> AFAICT the only reason this was ever done in a BH was because it was
> initially used to to issue a CHR_EVENT_RESET when we initialized the
> monitor,

It was specifically added so that we could redisplay the monitor
banner.  Because the event was emitted in open(), if we tried to
redisplay the monitor banner in the callback, the device would be in a
partially initialized state and badness would ensue.  The BH was there
to ensure the CharDriverState was fully initialized before firing the
callback.

> and we would in some cases modify the chr_write handler for
> a new chardev backend *after* the site where we issued the reset
> (see: 86e94d:qemu_chr_open_stdio())
>
> So we executed the reset in a BH to ensure the chardev was fully
> initialized before we executed the CHR_EVENT_RESET handler (which
> generally involved printing out a greeting/prompt for the monitor).
>
> At some point this event was renamed to CHR_EVENT_OPEN, and we've
> maintained the use of this BH ever since.
>
> However, due to 9f939df955a4152aad69a19a77e0898631bb2c18, we schedule
> the BH via g_idle_add(), which is causing events to sometimes be
> delivered after we've already begun processing data from backends,
> leading to:
>
>  known bugs:
>
>   QMP:
>     session negotation resets with OPEN event, in some cases this
>     is causing new sessions to get sporadically reset
>
>  potential bugs:
>
>   hw/usb/redirect.c:
>     can_read handler checks for dev->parser != NULL, which may be
>     true if CLOSED BH has not been executed yet. In the past, OPENED
>     quiesced outstanding CLOSED events prior to us reading client
>     data. If it's delayed, our check may allow reads to occur even
>     though we haven't processed the OPENED event yet, and when we
>     do finally get the OPENED event, our state may get reset.
>
>   qtest.c:
>     can begin session before OPENED event is processed, leading to
>     a spurious reset of the system and irq_levels
>
>   gdbstub.c:
>     may start a gdb session prior to the machine being paused
>
> To fix these, let's just drop the BH.
>
> Since the initial reasoning for using it still applies to an extent,
> work around that be deferring the delivery of CHR_EVENT_OPENED until
> after the chardevs have been fully initialized by setting a
> 'be_open_on_init' flag that gets checked toward the end of
> qmp_chardev_add(). This defers delivery long enough that we can
> be assured a CharDriverState is fully initialized before
> CHR_EVENT_OPENED is sent.
>
> Reported-by: Stefan Priebe <s.priebe@profihost.ag>
> Cc: qemu-stable@nongnu.org
> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> ---
>  backends/baum.c       |    2 +-
>  include/sysemu/char.h |    2 +-
>  qemu-char.c           |   29 ++++++++++-------------------
>  ui/console.c          |    2 +-
>  ui/gtk.c              |    2 +-
>  5 files changed, 14 insertions(+), 23 deletions(-)
>
> diff --git a/backends/baum.c b/backends/baum.c
> index 4cba79f..8384ef2 100644

<snip>

> @@ -3803,6 +3791,9 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
>          chr->label = g_strdup(id);
>          chr->avail_connections =
>              (backend->kind == CHARDEV_BACKEND_KIND_MUX) ? MAX_MUX : 1;
> +        if (chr->be_open_on_init) {
> +            qemu_chr_be_event(chr, CHR_EVENT_OPENED);
> +        }

Why does this need to be called conditionally?  Could we drop
be_open_on_init and just call this unconditionally here?

Regards,

Anthony Liguori

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Qemu-devel] [PATCH] qemu-char: don't issue CHR_EVENT_OPEN in a BH
  2013-05-30 16:55 ` Anthony Liguori
@ 2013-05-30 18:48   ` mdroth
  2013-05-30 19:35     ` Anthony Liguori
  0 siblings, 1 reply; 7+ messages in thread
From: mdroth @ 2013-05-30 18:48 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: s.priebe, lcapitulino, qemu-devel, qemu-stable

On Thu, May 30, 2013 at 11:55:56AM -0500, Anthony Liguori wrote:
> Michael Roth <mdroth@linux.vnet.ibm.com> writes:
> 
> > When CHR_EVENT_OPEN was initially added, it was CHR_EVENT_RESET, and
> > it was issued as a bottom-half:
> >
> > 86e94dea5b740dad65446c857f6959eae43e0ba6
> >
> > AFAICT the only reason this was ever done in a BH was because it was
> > initially used to to issue a CHR_EVENT_RESET when we initialized the
> > monitor,
> 
> It was specifically added so that we could redisplay the monitor
> banner.  Because the event was emitted in open(), if we tried to
> redisplay the monitor banner in the callback, the device would be in a
> partially initialized state and badness would ensue.  The BH was there
> to ensure the CharDriverState was fully initialized before firing the
> callback.
> 
> > and we would in some cases modify the chr_write handler for
> > a new chardev backend *after* the site where we issued the reset
> > (see: 86e94d:qemu_chr_open_stdio())
> >
> > So we executed the reset in a BH to ensure the chardev was fully
> > initialized before we executed the CHR_EVENT_RESET handler (which
> > generally involved printing out a greeting/prompt for the monitor).
> >
> > At some point this event was renamed to CHR_EVENT_OPEN, and we've
> > maintained the use of this BH ever since.
> >
> > However, due to 9f939df955a4152aad69a19a77e0898631bb2c18, we schedule
> > the BH via g_idle_add(), which is causing events to sometimes be
> > delivered after we've already begun processing data from backends,
> > leading to:
> >
> >  known bugs:
> >
> >   QMP:
> >     session negotation resets with OPEN event, in some cases this
> >     is causing new sessions to get sporadically reset
> >
> >  potential bugs:
> >
> >   hw/usb/redirect.c:
> >     can_read handler checks for dev->parser != NULL, which may be
> >     true if CLOSED BH has not been executed yet. In the past, OPENED
> >     quiesced outstanding CLOSED events prior to us reading client
> >     data. If it's delayed, our check may allow reads to occur even
> >     though we haven't processed the OPENED event yet, and when we
> >     do finally get the OPENED event, our state may get reset.
> >
> >   qtest.c:
> >     can begin session before OPENED event is processed, leading to
> >     a spurious reset of the system and irq_levels
> >
> >   gdbstub.c:
> >     may start a gdb session prior to the machine being paused
> >
> > To fix these, let's just drop the BH.
> >
> > Since the initial reasoning for using it still applies to an extent,
> > work around that be deferring the delivery of CHR_EVENT_OPENED until
> > after the chardevs have been fully initialized by setting a
> > 'be_open_on_init' flag that gets checked toward the end of
> > qmp_chardev_add(). This defers delivery long enough that we can
> > be assured a CharDriverState is fully initialized before
> > CHR_EVENT_OPENED is sent.
> >
> > Reported-by: Stefan Priebe <s.priebe@profihost.ag>
> > Cc: qemu-stable@nongnu.org
> > Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> > ---
> >  backends/baum.c       |    2 +-
> >  include/sysemu/char.h |    2 +-
> >  qemu-char.c           |   29 ++++++++++-------------------
> >  ui/console.c          |    2 +-
> >  ui/gtk.c              |    2 +-
> >  5 files changed, 14 insertions(+), 23 deletions(-)
> >
> > diff --git a/backends/baum.c b/backends/baum.c
> > index 4cba79f..8384ef2 100644
> 
> <snip>
> 
> > @@ -3803,6 +3791,9 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
> >          chr->label = g_strdup(id);
> >          chr->avail_connections =
> >              (backend->kind == CHARDEV_BACKEND_KIND_MUX) ? MAX_MUX : 1;
> > +        if (chr->be_open_on_init) {
> > +            qemu_chr_be_event(chr, CHR_EVENT_OPENED);
> > +        }
> 
> Why does this need to be called conditionally?  Could we drop
> be_open_on_init and just call this unconditionally here?

We have a couple instances where we don't immediately set the backend to
an open state on init. The main one is socket backends, where where we
don't send the OPENED event until a client connects.

> 
> Regards,
> 
> Anthony Liguori
> 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Qemu-devel] [PATCH] qemu-char: don't issue CHR_EVENT_OPEN in a BH
  2013-05-30 18:48   ` mdroth
@ 2013-05-30 19:35     ` Anthony Liguori
  2013-05-30 20:12       ` mdroth
  0 siblings, 1 reply; 7+ messages in thread
From: Anthony Liguori @ 2013-05-30 19:35 UTC (permalink / raw)
  To: mdroth; +Cc: qemu-stable, lcapitulino, qemu-devel, s.priebe

mdroth <mdroth@linux.vnet.ibm.com> writes:

> On Thu, May 30, 2013 at 11:55:56AM -0500, Anthony Liguori wrote:
>> Michael Roth <mdroth@linux.vnet.ibm.com> writes:
>> 
>> > When CHR_EVENT_OPEN was initially added, it was CHR_EVENT_RESET, and
>> > it was issued as a bottom-half:
>> >
>> > 86e94dea5b740dad65446c857f6959eae43e0ba6
>> >
>> > AFAICT the only reason this was ever done in a BH was because it was
>> > initially used to to issue a CHR_EVENT_RESET when we initialized the
>> > monitor,
>> 
>> It was specifically added so that we could redisplay the monitor
>> banner.  Because the event was emitted in open(), if we tried to
>> redisplay the monitor banner in the callback, the device would be in a
>> partially initialized state and badness would ensue.  The BH was there
>> to ensure the CharDriverState was fully initialized before firing the
>> callback.
>> 
>> > and we would in some cases modify the chr_write handler for
>> > a new chardev backend *after* the site where we issued the reset
>> > (see: 86e94d:qemu_chr_open_stdio())
>> >
>> > So we executed the reset in a BH to ensure the chardev was fully
>> > initialized before we executed the CHR_EVENT_RESET handler (which
>> > generally involved printing out a greeting/prompt for the monitor).
>> >
>> > At some point this event was renamed to CHR_EVENT_OPEN, and we've
>> > maintained the use of this BH ever since.
>> >
>> > However, due to 9f939df955a4152aad69a19a77e0898631bb2c18, we schedule
>> > the BH via g_idle_add(), which is causing events to sometimes be
>> > delivered after we've already begun processing data from backends,
>> > leading to:
>> >
>> >  known bugs:
>> >
>> >   QMP:
>> >     session negotation resets with OPEN event, in some cases this
>> >     is causing new sessions to get sporadically reset
>> >
>> >  potential bugs:
>> >
>> >   hw/usb/redirect.c:
>> >     can_read handler checks for dev->parser != NULL, which may be
>> >     true if CLOSED BH has not been executed yet. In the past, OPENED
>> >     quiesced outstanding CLOSED events prior to us reading client
>> >     data. If it's delayed, our check may allow reads to occur even
>> >     though we haven't processed the OPENED event yet, and when we
>> >     do finally get the OPENED event, our state may get reset.
>> >
>> >   qtest.c:
>> >     can begin session before OPENED event is processed, leading to
>> >     a spurious reset of the system and irq_levels
>> >
>> >   gdbstub.c:
>> >     may start a gdb session prior to the machine being paused
>> >
>> > To fix these, let's just drop the BH.
>> >
>> > Since the initial reasoning for using it still applies to an extent,
>> > work around that be deferring the delivery of CHR_EVENT_OPENED until
>> > after the chardevs have been fully initialized by setting a
>> > 'be_open_on_init' flag that gets checked toward the end of
>> > qmp_chardev_add(). This defers delivery long enough that we can
>> > be assured a CharDriverState is fully initialized before
>> > CHR_EVENT_OPENED is sent.
>> >
>> > Reported-by: Stefan Priebe <s.priebe@profihost.ag>
>> > Cc: qemu-stable@nongnu.org
>> > Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
>> > ---
>> >  backends/baum.c       |    2 +-
>> >  include/sysemu/char.h |    2 +-
>> >  qemu-char.c           |   29 ++++++++++-------------------
>> >  ui/console.c          |    2 +-
>> >  ui/gtk.c              |    2 +-
>> >  5 files changed, 14 insertions(+), 23 deletions(-)
>> >
>> > diff --git a/backends/baum.c b/backends/baum.c
>> > index 4cba79f..8384ef2 100644
>> 
>> <snip>
>> 
>> > @@ -3803,6 +3791,9 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
>> >          chr->label = g_strdup(id);
>> >          chr->avail_connections =
>> >              (backend->kind == CHARDEV_BACKEND_KIND_MUX) ? MAX_MUX : 1;
>> > +        if (chr->be_open_on_init) {
>> > +            qemu_chr_be_event(chr, CHR_EVENT_OPENED);
>> > +        }
>> 
>> Why does this need to be called conditionally?  Could we drop
>> be_open_on_init and just call this unconditionally here?
>
> We have a couple instances where we don't immediately set the backend to
> an open state on init.

Would it make more sense to mark those since they are less common?

Regards,

Anthony Liguori

> The main one is socket backends, where where we
> don't send the OPENED event until a client connects.
>
>> 
>> Regards,
>> 
>> Anthony Liguori
>> 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Qemu-devel] [PATCH] qemu-char: don't issue CHR_EVENT_OPEN in a BH
  2013-05-30 19:35     ` Anthony Liguori
@ 2013-05-30 20:12       ` mdroth
  2013-05-30 20:24         ` Anthony Liguori
  0 siblings, 1 reply; 7+ messages in thread
From: mdroth @ 2013-05-30 20:12 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-stable, lcapitulino, qemu-devel, s.priebe

On Thu, May 30, 2013 at 02:35:37PM -0500, Anthony Liguori wrote:
> mdroth <mdroth@linux.vnet.ibm.com> writes:
> 
> > On Thu, May 30, 2013 at 11:55:56AM -0500, Anthony Liguori wrote:
> >> Michael Roth <mdroth@linux.vnet.ibm.com> writes:
> >> 
> >> > When CHR_EVENT_OPEN was initially added, it was CHR_EVENT_RESET, and
> >> > it was issued as a bottom-half:
> >> >
> >> > 86e94dea5b740dad65446c857f6959eae43e0ba6
> >> >
> >> > AFAICT the only reason this was ever done in a BH was because it was
> >> > initially used to to issue a CHR_EVENT_RESET when we initialized the
> >> > monitor,
> >> 
> >> It was specifically added so that we could redisplay the monitor
> >> banner.  Because the event was emitted in open(), if we tried to
> >> redisplay the monitor banner in the callback, the device would be in a
> >> partially initialized state and badness would ensue.  The BH was there
> >> to ensure the CharDriverState was fully initialized before firing the
> >> callback.
> >> 
> >> > and we would in some cases modify the chr_write handler for
> >> > a new chardev backend *after* the site where we issued the reset
> >> > (see: 86e94d:qemu_chr_open_stdio())
> >> >
> >> > So we executed the reset in a BH to ensure the chardev was fully
> >> > initialized before we executed the CHR_EVENT_RESET handler (which
> >> > generally involved printing out a greeting/prompt for the monitor).
> >> >
> >> > At some point this event was renamed to CHR_EVENT_OPEN, and we've
> >> > maintained the use of this BH ever since.
> >> >
> >> > However, due to 9f939df955a4152aad69a19a77e0898631bb2c18, we schedule
> >> > the BH via g_idle_add(), which is causing events to sometimes be
> >> > delivered after we've already begun processing data from backends,
> >> > leading to:
> >> >
> >> >  known bugs:
> >> >
> >> >   QMP:
> >> >     session negotation resets with OPEN event, in some cases this
> >> >     is causing new sessions to get sporadically reset
> >> >
> >> >  potential bugs:
> >> >
> >> >   hw/usb/redirect.c:
> >> >     can_read handler checks for dev->parser != NULL, which may be
> >> >     true if CLOSED BH has not been executed yet. In the past, OPENED
> >> >     quiesced outstanding CLOSED events prior to us reading client
> >> >     data. If it's delayed, our check may allow reads to occur even
> >> >     though we haven't processed the OPENED event yet, and when we
> >> >     do finally get the OPENED event, our state may get reset.
> >> >
> >> >   qtest.c:
> >> >     can begin session before OPENED event is processed, leading to
> >> >     a spurious reset of the system and irq_levels
> >> >
> >> >   gdbstub.c:
> >> >     may start a gdb session prior to the machine being paused
> >> >
> >> > To fix these, let's just drop the BH.
> >> >
> >> > Since the initial reasoning for using it still applies to an extent,
> >> > work around that be deferring the delivery of CHR_EVENT_OPENED until
> >> > after the chardevs have been fully initialized by setting a
> >> > 'be_open_on_init' flag that gets checked toward the end of
> >> > qmp_chardev_add(). This defers delivery long enough that we can
> >> > be assured a CharDriverState is fully initialized before
> >> > CHR_EVENT_OPENED is sent.
> >> >
> >> > Reported-by: Stefan Priebe <s.priebe@profihost.ag>
> >> > Cc: qemu-stable@nongnu.org
> >> > Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> >> > ---
> >> >  backends/baum.c       |    2 +-
> >> >  include/sysemu/char.h |    2 +-
> >> >  qemu-char.c           |   29 ++++++++++-------------------
> >> >  ui/console.c          |    2 +-
> >> >  ui/gtk.c              |    2 +-
> >> >  5 files changed, 14 insertions(+), 23 deletions(-)
> >> >
> >> > diff --git a/backends/baum.c b/backends/baum.c
> >> > index 4cba79f..8384ef2 100644
> >> 
> >> <snip>
> >> 
> >> > @@ -3803,6 +3791,9 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
> >> >          chr->label = g_strdup(id);
> >> >          chr->avail_connections =
> >> >              (backend->kind == CHARDEV_BACKEND_KIND_MUX) ? MAX_MUX : 1;
> >> > +        if (chr->be_open_on_init) {
> >> > +            qemu_chr_be_event(chr, CHR_EVENT_OPENED);
> >> > +        }
> >> 
> >> Why does this need to be called conditionally?  Could we drop
> >> be_open_on_init and just call this unconditionally here?
> >
> > We have a couple instances where we don't immediately set the backend to
> > an open state on init.
> 
> Would it make more sense to mark those since they are less common?

It's less code, but emitting an event on device init seems like it
should be more of an opt-in type of thing, IMO. I'm fine with either
approach though.

> 
> Regards,
> 
> Anthony Liguori
> 
> > The main one is socket backends, where where we
> > don't send the OPENED event until a client connects.
> >
> >> 
> >> Regards,
> >> 
> >> Anthony Liguori
> >> 
> 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Qemu-devel] [PATCH] qemu-char: don't issue CHR_EVENT_OPEN in a BH
  2013-05-30 20:12       ` mdroth
@ 2013-05-30 20:24         ` Anthony Liguori
  2013-05-30 20:44           ` mdroth
  0 siblings, 1 reply; 7+ messages in thread
From: Anthony Liguori @ 2013-05-30 20:24 UTC (permalink / raw)
  To: mdroth; +Cc: qemu-devel, s.priebe, qemu-stable, lcapitulino

mdroth <mdroth@linux.vnet.ibm.com> writes:

> On Thu, May 30, 2013 at 02:35:37PM -0500, Anthony Liguori wrote:
>> mdroth <mdroth@linux.vnet.ibm.com> writes:
>> 
>> > On Thu, May 30, 2013 at 11:55:56AM -0500, Anthony Liguori wrote:
>> >> Michael Roth <mdroth@linux.vnet.ibm.com> writes:
>> >> 
>> >> > When CHR_EVENT_OPEN was initially added, it was CHR_EVENT_RESET, and
>> >> > it was issued as a bottom-half:
>> >> >
>> >> > 86e94dea5b740dad65446c857f6959eae43e0ba6
>> >> >
>> >> > AFAICT the only reason this was ever done in a BH was because it was
>> >> > initially used to to issue a CHR_EVENT_RESET when we initialized the
>> >> > monitor,
>> >> 
>> >> It was specifically added so that we could redisplay the monitor
>> >> banner.  Because the event was emitted in open(), if we tried to
>> >> redisplay the monitor banner in the callback, the device would be in a
>> >> partially initialized state and badness would ensue.  The BH was there
>> >> to ensure the CharDriverState was fully initialized before firing the
>> >> callback.
>> >> 
>> >> > and we would in some cases modify the chr_write handler for
>> >> > a new chardev backend *after* the site where we issued the reset
>> >> > (see: 86e94d:qemu_chr_open_stdio())
>> >> >
>> >> > So we executed the reset in a BH to ensure the chardev was fully
>> >> > initialized before we executed the CHR_EVENT_RESET handler (which
>> >> > generally involved printing out a greeting/prompt for the monitor).
>> >> >
>> >> > At some point this event was renamed to CHR_EVENT_OPEN, and we've
>> >> > maintained the use of this BH ever since.
>> >> >
>> >> > However, due to 9f939df955a4152aad69a19a77e0898631bb2c18, we schedule
>> >> > the BH via g_idle_add(), which is causing events to sometimes be
>> >> > delivered after we've already begun processing data from backends,
>> >> > leading to:
>> >> >
>> >> >  known bugs:
>> >> >
>> >> >   QMP:
>> >> >     session negotation resets with OPEN event, in some cases this
>> >> >     is causing new sessions to get sporadically reset
>> >> >
>> >> >  potential bugs:
>> >> >
>> >> >   hw/usb/redirect.c:
>> >> >     can_read handler checks for dev->parser != NULL, which may be
>> >> >     true if CLOSED BH has not been executed yet. In the past, OPENED
>> >> >     quiesced outstanding CLOSED events prior to us reading client
>> >> >     data. If it's delayed, our check may allow reads to occur even
>> >> >     though we haven't processed the OPENED event yet, and when we
>> >> >     do finally get the OPENED event, our state may get reset.
>> >> >
>> >> >   qtest.c:
>> >> >     can begin session before OPENED event is processed, leading to
>> >> >     a spurious reset of the system and irq_levels
>> >> >
>> >> >   gdbstub.c:
>> >> >     may start a gdb session prior to the machine being paused
>> >> >
>> >> > To fix these, let's just drop the BH.
>> >> >
>> >> > Since the initial reasoning for using it still applies to an extent,
>> >> > work around that be deferring the delivery of CHR_EVENT_OPENED until
>> >> > after the chardevs have been fully initialized by setting a
>> >> > 'be_open_on_init' flag that gets checked toward the end of
>> >> > qmp_chardev_add(). This defers delivery long enough that we can
>> >> > be assured a CharDriverState is fully initialized before
>> >> > CHR_EVENT_OPENED is sent.
>> >> >
>> >> > Reported-by: Stefan Priebe <s.priebe@profihost.ag>
>> >> > Cc: qemu-stable@nongnu.org
>> >> > Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
>> >> > ---
>> >> >  backends/baum.c       |    2 +-
>> >> >  include/sysemu/char.h |    2 +-
>> >> >  qemu-char.c           |   29 ++++++++++-------------------
>> >> >  ui/console.c          |    2 +-
>> >> >  ui/gtk.c              |    2 +-
>> >> >  5 files changed, 14 insertions(+), 23 deletions(-)
>> >> >
>> >> > diff --git a/backends/baum.c b/backends/baum.c
>> >> > index 4cba79f..8384ef2 100644
>> >> 
>> >> <snip>
>> >> 
>> >> > @@ -3803,6 +3791,9 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
>> >> >          chr->label = g_strdup(id);
>> >> >          chr->avail_connections =
>> >> >              (backend->kind == CHARDEV_BACKEND_KIND_MUX) ? MAX_MUX : 1;
>> >> > +        if (chr->be_open_on_init) {
>> >> > +            qemu_chr_be_event(chr, CHR_EVENT_OPENED);
>> >> > +        }
>> >> 
>> >> Why does this need to be called conditionally?  Could we drop
>> >> be_open_on_init and just call this unconditionally here?
>> >
>> > We have a couple instances where we don't immediately set the backend to
>> > an open state on init.
>> 
>> Would it make more sense to mark those since they are less common?
>
> It's less code, but emitting an event on device init seems like it
> should be more of an opt-in type of thing, IMO. I'm fine with either
> approach though.

I'd prefer the other way around.  There's less harm in generating an
extra event than not generating one.

Regards,

Anthony Liguori

>
>> 
>> Regards,
>> 
>> Anthony Liguori
>> 
>> > The main one is socket backends, where where we
>> > don't send the OPENED event until a client connects.
>> >
>> >> 
>> >> Regards,
>> >> 
>> >> Anthony Liguori
>> >> 
>> 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Qemu-devel] [PATCH] qemu-char: don't issue CHR_EVENT_OPEN in a BH
  2013-05-30 20:24         ` Anthony Liguori
@ 2013-05-30 20:44           ` mdroth
  0 siblings, 0 replies; 7+ messages in thread
From: mdroth @ 2013-05-30 20:44 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel, s.priebe, qemu-stable, lcapitulino

On Thu, May 30, 2013 at 03:24:14PM -0500, Anthony Liguori wrote:
> mdroth <mdroth@linux.vnet.ibm.com> writes:
> 
> > On Thu, May 30, 2013 at 02:35:37PM -0500, Anthony Liguori wrote:
> >> mdroth <mdroth@linux.vnet.ibm.com> writes:
> >> 
> >> > On Thu, May 30, 2013 at 11:55:56AM -0500, Anthony Liguori wrote:
> >> >> Michael Roth <mdroth@linux.vnet.ibm.com> writes:
> >> >> 
> >> >> > When CHR_EVENT_OPEN was initially added, it was CHR_EVENT_RESET, and
> >> >> > it was issued as a bottom-half:
> >> >> >
> >> >> > 86e94dea5b740dad65446c857f6959eae43e0ba6
> >> >> >
> >> >> > AFAICT the only reason this was ever done in a BH was because it was
> >> >> > initially used to to issue a CHR_EVENT_RESET when we initialized the
> >> >> > monitor,
> >> >> 
> >> >> It was specifically added so that we could redisplay the monitor
> >> >> banner.  Because the event was emitted in open(), if we tried to
> >> >> redisplay the monitor banner in the callback, the device would be in a
> >> >> partially initialized state and badness would ensue.  The BH was there
> >> >> to ensure the CharDriverState was fully initialized before firing the
> >> >> callback.
> >> >> 
> >> >> > and we would in some cases modify the chr_write handler for
> >> >> > a new chardev backend *after* the site where we issued the reset
> >> >> > (see: 86e94d:qemu_chr_open_stdio())
> >> >> >
> >> >> > So we executed the reset in a BH to ensure the chardev was fully
> >> >> > initialized before we executed the CHR_EVENT_RESET handler (which
> >> >> > generally involved printing out a greeting/prompt for the monitor).
> >> >> >
> >> >> > At some point this event was renamed to CHR_EVENT_OPEN, and we've
> >> >> > maintained the use of this BH ever since.
> >> >> >
> >> >> > However, due to 9f939df955a4152aad69a19a77e0898631bb2c18, we schedule
> >> >> > the BH via g_idle_add(), which is causing events to sometimes be
> >> >> > delivered after we've already begun processing data from backends,
> >> >> > leading to:
> >> >> >
> >> >> >  known bugs:
> >> >> >
> >> >> >   QMP:
> >> >> >     session negotation resets with OPEN event, in some cases this
> >> >> >     is causing new sessions to get sporadically reset
> >> >> >
> >> >> >  potential bugs:
> >> >> >
> >> >> >   hw/usb/redirect.c:
> >> >> >     can_read handler checks for dev->parser != NULL, which may be
> >> >> >     true if CLOSED BH has not been executed yet. In the past, OPENED
> >> >> >     quiesced outstanding CLOSED events prior to us reading client
> >> >> >     data. If it's delayed, our check may allow reads to occur even
> >> >> >     though we haven't processed the OPENED event yet, and when we
> >> >> >     do finally get the OPENED event, our state may get reset.
> >> >> >
> >> >> >   qtest.c:
> >> >> >     can begin session before OPENED event is processed, leading to
> >> >> >     a spurious reset of the system and irq_levels
> >> >> >
> >> >> >   gdbstub.c:
> >> >> >     may start a gdb session prior to the machine being paused
> >> >> >
> >> >> > To fix these, let's just drop the BH.
> >> >> >
> >> >> > Since the initial reasoning for using it still applies to an extent,
> >> >> > work around that be deferring the delivery of CHR_EVENT_OPENED until
> >> >> > after the chardevs have been fully initialized by setting a
> >> >> > 'be_open_on_init' flag that gets checked toward the end of
> >> >> > qmp_chardev_add(). This defers delivery long enough that we can
> >> >> > be assured a CharDriverState is fully initialized before
> >> >> > CHR_EVENT_OPENED is sent.
> >> >> >
> >> >> > Reported-by: Stefan Priebe <s.priebe@profihost.ag>
> >> >> > Cc: qemu-stable@nongnu.org
> >> >> > Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> >> >> > ---
> >> >> >  backends/baum.c       |    2 +-
> >> >> >  include/sysemu/char.h |    2 +-
> >> >> >  qemu-char.c           |   29 ++++++++++-------------------
> >> >> >  ui/console.c          |    2 +-
> >> >> >  ui/gtk.c              |    2 +-
> >> >> >  5 files changed, 14 insertions(+), 23 deletions(-)
> >> >> >
> >> >> > diff --git a/backends/baum.c b/backends/baum.c
> >> >> > index 4cba79f..8384ef2 100644
> >> >> 
> >> >> <snip>
> >> >> 
> >> >> > @@ -3803,6 +3791,9 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
> >> >> >          chr->label = g_strdup(id);
> >> >> >          chr->avail_connections =
> >> >> >              (backend->kind == CHARDEV_BACKEND_KIND_MUX) ? MAX_MUX : 1;
> >> >> > +        if (chr->be_open_on_init) {
> >> >> > +            qemu_chr_be_event(chr, CHR_EVENT_OPENED);
> >> >> > +        }
> >> >> 
> >> >> Why does this need to be called conditionally?  Could we drop
> >> >> be_open_on_init and just call this unconditionally here?
> >> >
> >> > We have a couple instances where we don't immediately set the backend to
> >> > an open state on init.
> >> 
> >> Would it make more sense to mark those since they are less common?
> >
> > It's less code, but emitting an event on device init seems like it
> > should be more of an opt-in type of thing, IMO. I'm fine with either
> > approach though.
> 
> I'd prefer the other way around.  There's less harm in generating an
> extra event than not generating one.

Ok, I'll send a v2 shortly

> 
> Regards,
> 
> Anthony Liguori
> 
> >
> >> 
> >> Regards,
> >> 
> >> Anthony Liguori
> >> 
> >> > The main one is socket backends, where where we
> >> > don't send the OPENED event until a client connects.
> >> >
> >> >> 
> >> >> Regards,
> >> >> 
> >> >> Anthony Liguori
> >> >> 
> >> 
> 

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2013-05-30 20:45 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-05-29 22:27 [Qemu-devel] [PATCH] qemu-char: don't issue CHR_EVENT_OPEN in a BH Michael Roth
2013-05-30 16:55 ` Anthony Liguori
2013-05-30 18:48   ` mdroth
2013-05-30 19:35     ` Anthony Liguori
2013-05-30 20:12       ` mdroth
2013-05-30 20:24         ` Anthony Liguori
2013-05-30 20:44           ` mdroth

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.