[libvirt] [libvirt-glib 1/2] Rely on libvirt API to detect transient domains

From: "Zeeshan Ali (Khattak)" <zeeshanak@gnome.org> --- libvirt-gobject/libvirt-gobject-connection.c | 6 +----- 1 files changed, 1 insertions(+), 5 deletions(-) diff --git a/libvirt-gobject/libvirt-gobject-connection.c b/libvirt-gobject/libvirt-gobject-connection.c index c9985b2..b647bfa 100644 --- a/libvirt-gobject/libvirt-gobject-connection.c +++ b/libvirt-gobject/libvirt-gobject-connection.c @@ -260,7 +260,6 @@ static int domain_event_cb(virConnectPtr conn G_GNUC_UNUSED, GVirConnection *gconn = opaque; GVirDomain *gdom; GVirConnectionPrivate *priv = gconn->priv; - gboolean was_unknown = FALSE; if (virDomainGetUUIDString(dom, uuid) < 0) { g_warning("Failed to get domain UUID on %p", dom); @@ -279,8 +278,6 @@ static int domain_event_cb(virConnectPtr conn G_GNUC_UNUSED, g_mutex_lock(priv->lock); g_hash_table_insert(priv->domains, (gpointer)gvir_domain_get_uuid(gdom), gdom); g_mutex_unlock(priv->lock); - - was_unknown = TRUE; } switch (event) { @@ -307,8 +304,7 @@ static int domain_event_cb(virConnectPtr conn G_GNUC_UNUSED, case VIR_DOMAIN_EVENT_STARTED: if (detail == VIR_DOMAIN_EVENT_STARTED_BOOTED) { - if (was_unknown) - /* Most probably a transient domain */ + if (!virDomainIsPersistent(dom)) g_signal_emit(gconn, signals[VIR_DOMAIN_ADDED], 0, gdom); g_signal_emit_by_name(gdom, "started::booted"); } else if (detail == VIR_DOMAIN_EVENT_STARTED_MIGRATED) -- 1.7.7.3

From: "Zeeshan Ali (Khattak)" <zeeshanak@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; default: -- 1.7.7.3

On Tue, Nov 29, 2011 at 05:00:54PM +0200, Zeeshan Ali (Khattak) wrote:
From: "Zeeshan Ali (Khattak)" <zeeshanak@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. Christophe

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@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; } Christophe

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@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 :|

On Tue, Nov 29, 2011 at 05:00:53PM +0200, Zeeshan Ali (Khattak) wrote:
From: "Zeeshan Ali (Khattak)" <zeeshanak@gnome.org>
--- libvirt-gobject/libvirt-gobject-connection.c | 6 +----- 1 files changed, 1 insertions(+), 5 deletions(-)
diff --git a/libvirt-gobject/libvirt-gobject-connection.c b/libvirt-gobject/libvirt-gobject-connection.c index c9985b2..b647bfa 100644 --- a/libvirt-gobject/libvirt-gobject-connection.c +++ b/libvirt-gobject/libvirt-gobject-connection.c @@ -260,7 +260,6 @@ static int domain_event_cb(virConnectPtr conn G_GNUC_UNUSED, GVirConnection *gconn = opaque; GVirDomain *gdom; GVirConnectionPrivate *priv = gconn->priv; - gboolean was_unknown = FALSE;
if (virDomainGetUUIDString(dom, uuid) < 0) { g_warning("Failed to get domain UUID on %p", dom); @@ -279,8 +278,6 @@ static int domain_event_cb(virConnectPtr conn G_GNUC_UNUSED, g_mutex_lock(priv->lock); g_hash_table_insert(priv->domains, (gpointer)gvir_domain_get_uuid(gdom), gdom); g_mutex_unlock(priv->lock); - - was_unknown = TRUE; }
switch (event) { @@ -307,8 +304,7 @@ static int domain_event_cb(virConnectPtr conn G_GNUC_UNUSED,
case VIR_DOMAIN_EVENT_STARTED: if (detail == VIR_DOMAIN_EVENT_STARTED_BOOTED) { - if (was_unknown) - /* Most probably a transient domain */ + if (!virDomainIsPersistent(dom)) g_signal_emit(gconn, signals[VIR_DOMAIN_ADDED], 0, gdom); g_signal_emit_by_name(gdom, "started::booted"); } else if (detail == VIR_DOMAIN_EVENT_STARTED_MIGRATED)
ACK 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 :|
participants (3)
-
Christophe Fergeau
-
Daniel P. Berrange
-
Zeeshan Ali (Khattak)