core: fix dbus-glib crash on shutdown with systemd
It's really dbus-glib's fault, but the problem seems to be that when short-lived D-Bus calls are made (with dbus_g_proxy_call_no_reply) and the service is activated, then quits immediately like the dispatcher does, there's not enough time for internal dbus-glib housekeeping. The GetNameOwner call that's kicked off when the DBusGProxy is created hasn't returned by the time the proxy is being unrefed, so the proxy doesn't end up on the unassociated_proxies list. But when the proxy is destroyed, and it destroys it's DBusGProxyManager, the manager expects that the proxy is on unassociated_proxies. Thus the crash. I'm not entirely sure why we hit this only at shutdown with systemd; it could be that systemd is killing the bus daemon at the same time as we're running the dispatcher and that's why the GetNameOwner call doesn't complete. Work around all this by expecting a message return, which works fine during normal operation, but on shutdown allows us to avoid urefing the proxy until everything in dbus-glib has been handled, which at shutdown time really just means leaking it. But then we exit, so it's cleaned up anyway.
This commit is contained in:
@@ -373,6 +373,13 @@ nm_utils_merge_ip6_config (NMIP6Config *ip6_config, NMSettingIP6Config *setting)
|
|||||||
nm_ip6_config_set_never_default (ip6_config, TRUE);
|
nm_ip6_config_set_never_default (ip6_config, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dispatcher_done_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
|
||||||
|
{
|
||||||
|
dbus_g_proxy_end_call (proxy, call, NULL, G_TYPE_INVALID);
|
||||||
|
g_object_unref (proxy);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nm_utils_call_dispatcher (const char *action,
|
nm_utils_call_dispatcher (const char *action,
|
||||||
NMConnection *connection,
|
NMConnection *connection,
|
||||||
@@ -440,18 +447,25 @@ nm_utils_call_dispatcher (const char *action,
|
|||||||
value_hash_add_object_path (device_props, NMD_DEVICE_PROPS_PATH, nm_device_get_path (device));
|
value_hash_add_object_path (device_props, NMD_DEVICE_PROPS_PATH, nm_device_get_path (device));
|
||||||
}
|
}
|
||||||
|
|
||||||
dbus_g_proxy_call_no_reply (proxy, "Action",
|
/* Do a non-blocking call, but wait for the reply, because dbus-glib
|
||||||
G_TYPE_STRING, action,
|
* sometimes needs time to complete internal housekeeping. If we use
|
||||||
DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, connection_hash,
|
* dbus_g_proxy_call_no_reply(), that housekeeping (specifically the
|
||||||
DBUS_TYPE_G_MAP_OF_VARIANT, connection_props,
|
* GetNameOwner response) doesn't complete and we run into an assert
|
||||||
DBUS_TYPE_G_MAP_OF_VARIANT, device_props,
|
* on unreffing the proxy.
|
||||||
G_TYPE_INVALID);
|
*/
|
||||||
|
dbus_g_proxy_begin_call_with_timeout (proxy, "Action",
|
||||||
g_object_unref (proxy);
|
dispatcher_done_cb,
|
||||||
|
dbus_mgr,
|
||||||
|
g_object_unref,
|
||||||
|
5000,
|
||||||
|
G_TYPE_STRING, action,
|
||||||
|
DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, connection_hash,
|
||||||
|
DBUS_TYPE_G_MAP_OF_VARIANT, connection_props,
|
||||||
|
DBUS_TYPE_G_MAP_OF_VARIANT, device_props,
|
||||||
|
G_TYPE_INVALID);
|
||||||
g_hash_table_destroy (connection_hash);
|
g_hash_table_destroy (connection_hash);
|
||||||
g_hash_table_destroy (connection_props);
|
g_hash_table_destroy (connection_props);
|
||||||
g_hash_table_destroy (device_props);
|
g_hash_table_destroy (device_props);
|
||||||
g_object_unref (dbus_mgr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
|
Reference in New Issue
Block a user