[libvirt] [libvirt-glib 2/2] Remove transient domain reference on shutdown

Daniel P. Berrange berrange at redhat.com
Wed Nov 30 13:07:54 UTC 2011


On Wed, Nov 30, 2011 at 02:03:18PM +0100, Christophe Fergeau wrote:
> On Tue, Nov 29, 2011 at 11:51:38PM +0100, Christophe Fergeau wrote:
> > On Tue, Nov 29, 2011 at 05:00:54PM +0200, Zeeshan Ali (Khattak) wrote:
> > > From: "Zeeshan Ali (Khattak)" <zeeshanak at gnome.org>
> > > 
> > > This patch doesn't work cause virDomainIsPersistent() is returning '1'
> > > on transient domain for some reason. Send it to list to get some help.
> > > ---
> > >  libvirt-gobject/libvirt-gobject-connection.c |    9 +++++++++
> > >  1 files changed, 9 insertions(+), 0 deletions(-)
> > > 
> > > diff --git a/libvirt-gobject/libvirt-gobject-connection.c b/libvirt-gobject/libvirt-gobject-connection.c
> > > index b647bfa..1b0259e 100644
> > > --- a/libvirt-gobject/libvirt-gobject-connection.c
> > > +++ b/libvirt-gobject/libvirt-gobject-connection.c
> > > @@ -362,6 +362,15 @@ static int domain_event_cb(virConnectPtr conn G_GNUC_UNUSED,
> > >                  g_signal_emit_by_name(gdom, "stopped::from-snapshot");
> > >              else
> > >                  g_warn_if_reached();
> > > +
> > > +            if (!virDomainIsPersistent(dom)) {
> > > +                g_mutex_lock(priv->lock);
> > > +                g_hash_table_steal(priv->domains, uuid);
> > > +                g_mutex_unlock(priv->lock);
> > > +
> > > +                g_signal_emit(gconn, signals[VIR_DOMAIN_REMOVED], 0, gdom);
> > > +                g_object_unref(gdom);
> > > +            }
> > >              break;
> > 
> > Not directly related to this patch since the same pattern is already
> > present in domain_event_cb, but this can race with gvir_connection_close,
> > ie gdom is looked up in domain_event_cb, gvir_connection_close frees
> > priv->domains and its content, domain_event_cb resumes and happily uses
> > gdom which it hasn't reffed and priv->domains. Something similar can also
> > happen between domain_event_cb and gvir_connection_fetch_domains.
> 
> What about something like the patch below? I'll make a proper patch and
> make sure it does not conflict with Zeeshan's patch if that looks like the
> way to go.
> 
> Christophe
> 
> 
> diff --git a/libvirt-gobject/libvirt-gobject-connection.c b/libvirt-gobject/libvirt-gobject-connection.c
> index c9985b2..e00c5bf 100644
> --- a/libvirt-gobject/libvirt-gobject-connection.c
> +++ b/libvirt-gobject/libvirt-gobject-connection.c
> @@ -261,6 +261,7 @@ static int domain_event_cb(virConnectPtr conn G_GNUC_UNUSED,
>      GVirDomain *gdom;
>      GVirConnectionPrivate *priv = gconn->priv;
>      gboolean was_unknown = FALSE;
> +    GHashTable *doms;
>  
>      if (virDomainGetUUIDString(dom, uuid) < 0) {
>          g_warning("Failed to get domain UUID on %p", dom);
> @@ -270,14 +271,17 @@ static int domain_event_cb(virConnectPtr conn G_GNUC_UNUSED,
>      g_debug("%s: %s event:%d, detail:%d", G_STRFUNC, uuid, event, detail);
>  
>      g_mutex_lock(priv->lock);
> -    gdom = g_hash_table_lookup(priv->domains, uuid);
> +    doms = g_hash_table_ref(priv->domains);
> +    gdom = g_hash_table_lookup(doms, uuid);
> +    if (gdom != NULL)
> +        g_object_ref(G_OBJECT(gdom));
>      g_mutex_unlock(priv->lock);
>  
>      if (gdom == NULL) {
>          gdom = GVIR_DOMAIN(g_object_new(GVIR_TYPE_DOMAIN, "handle", dom, NULL));
>  
>          g_mutex_lock(priv->lock);
> -        g_hash_table_insert(priv->domains, (gpointer)gvir_domain_get_uuid(gdom), gdom);
> +        g_hash_table_insert(doms, (gpointer)gvir_domain_get_uuid(gdom), gdom);
>          g_mutex_unlock(priv->lock);
>  
>          was_unknown = TRUE;
> @@ -296,11 +300,10 @@ static int domain_event_cb(virConnectPtr conn G_GNUC_UNUSED,
>          case VIR_DOMAIN_EVENT_UNDEFINED:
>              if (detail == VIR_DOMAIN_EVENT_UNDEFINED_REMOVED) {
>                  g_mutex_lock(priv->lock);
> -                g_hash_table_steal(priv->domains, uuid);
> +                g_hash_table_remove(doms, uuid);
>                  g_mutex_unlock(priv->lock);
>  
>                  g_signal_emit(gconn, signals[VIR_DOMAIN_REMOVED], 0, gdom);
> -                g_object_unref(gdom);
>              } else
>                  g_warn_if_reached();
>              break;
> @@ -372,6 +375,8 @@ static int domain_event_cb(virConnectPtr conn G_GNUC_UNUSED,
>              g_warn_if_reached();
>      }
>  
> +    g_object_unref(G_OBJECT(gdom));
> +    g_hash_table_unref(doms);
>      return 0;
>  }


Looks reasonable to me.


Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|




More information about the libvir-list mailing list