core/dbus: stop NMDBusManager and reject future method calls

During shutdown, we will need to still iterate the main loop
to do a coordinated shutdown. Currently we do not, and we just
exit, leaving a lot of objects hanging.

If we are going to fix that, we need during shutdown tell
NMDBusManager to reject all future operations.

Note that property getters and "GetManagerObjects" call is not
blocked. It continues to work.

Certainly for some operations, we want to allow them to be called even
during shutdown. However, these have to opt-in.

This also fixes an uglyness, where nm_dbus_manager_start() would
get the set-property-handler and the @manager as user-data. However,
NMDBusManager will always outlife NMManager, hence, after NMManager
is destroyed, the user-data would be a dangling pointer. Currently
that is not an issue, because
  - we always leak NMManager
  - we don't run the mainloop during shutdown
This commit is contained in:
Thomas Haller
2018-04-21 13:25:57 +02:00
parent 5b199b2e7d
commit 3d2da8cd05
8 changed files with 53 additions and 25 deletions

View File

@@ -443,11 +443,6 @@ done:
* it misses to update the state. */ * it misses to update the state. */
nm_manager_write_device_state (manager); nm_manager_write_device_state (manager);
/* FIXME(shutdown): we don't properly shut down on exit. That is a bug.
* NMDBusObject have an assertion that they get unexported before disposing.
* We need this workaround and disable the assertion during our leaky shutdown. */
nm_dbus_object_set_quitting ();
nm_manager_stop (manager); nm_manager_stop (manager);
nm_config_state_set (config, TRUE, TRUE); nm_config_state_set (config, TRUE, TRUE);

View File

@@ -83,7 +83,8 @@ typedef struct {
GDBusConnection *connection; GDBusConnection *connection;
GDBusProxy *proxy; GDBusProxy *proxy;
guint objmgr_registration_id; guint objmgr_registration_id;
gboolean started; bool started:1;
bool shutting_down:1;
} NMDBusManagerPrivate; } NMDBusManagerPrivate;
struct _NMDBusManager { struct _NMDBusManager {
@@ -788,6 +789,8 @@ dbus_vtable_method_call (GDBusConnection *connection,
GDBusMethodInvocation *invocation, GDBusMethodInvocation *invocation,
gpointer user_data) gpointer user_data)
{ {
NMDBusManager *self;
NMDBusManagerPrivate *priv;
RegistrationData *reg_data = user_data; RegistrationData *reg_data = user_data;
NMDBusObject *obj = reg_data->obj; NMDBusObject *obj = reg_data->obj;
const NMDBusInterfaceInfoExtended *interface_info = _reg_data_get_interface_info (reg_data); const NMDBusInterfaceInfoExtended *interface_info = _reg_data_get_interface_info (reg_data);
@@ -800,13 +803,14 @@ dbus_vtable_method_call (GDBusConnection *connection,
if ( !on_same_interface if ( !on_same_interface
&& nm_streq (interface_name, DBUS_INTERFACE_PROPERTIES) && nm_streq (interface_name, DBUS_INTERFACE_PROPERTIES)
&& nm_streq (method_name, "Set")) { && nm_streq (method_name, "Set")) {
NMDBusManager *self = nm_dbus_object_get_manager (obj);
NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self);
const NMDBusPropertyInfoExtended *property_info = NULL; const NMDBusPropertyInfoExtended *property_info = NULL;
const char *property_interface; const char *property_interface;
const char *property_name; const char *property_name;
gs_unref_variant GVariant *value = NULL; gs_unref_variant GVariant *value = NULL;
self = nm_dbus_object_get_manager (obj);
priv = NM_DBUS_MANAGER_GET_PRIVATE (self);
g_variant_get (parameters, "(&s&sv)", &property_interface, &property_name, &value); g_variant_get (parameters, "(&s&sv)", &property_interface, &property_name, &value);
nm_assert (nm_streq (property_interface, interface_info->parent.name)); nm_assert (nm_streq (property_interface, interface_info->parent.name));
@@ -851,6 +855,17 @@ dbus_vtable_method_call (GDBusConnection *connection,
return; return;
} }
self = nm_dbus_object_get_manager (obj);
priv = NM_DBUS_MANAGER_GET_PRIVATE (self);
if ( priv->shutting_down
&& !method_info->allow_during_shutdown) {
g_dbus_method_invocation_return_error_literal (invocation,
G_DBUS_ERROR,
G_DBUS_ERROR_FAILED,
"NetworkManager is exiting");
return;
}
method_info->handle (reg_data->obj, method_info->handle (reg_data->obj,
interface_info, interface_info,
method_info, method_info,
@@ -1574,6 +1589,27 @@ nm_dbus_manager_acquire_bus (NMDBusManager *self)
return TRUE; return TRUE;
} }
void
nm_dbus_manager_stop (NMDBusManager *self)
{
NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self);
priv->shutting_down = TRUE;
/* during shutdown we also clear the set-property-handler. It's no longer
* possible to set a property, because doing so would require authorization,
* which is async, which is just complicated to get right. No more property
* setting from now on. */
priv->set_property_handler = NULL;
priv->set_property_handler_data = NULL;
}
gboolean
nm_dbus_manager_is_stopping (NMDBusManager *self)
{
return NM_DBUS_MANAGER_GET_PRIVATE (self)->shutting_down;
}
/*****************************************************************************/ /*****************************************************************************/
static void static void

View File

@@ -55,6 +55,10 @@ void nm_dbus_manager_start (NMDBusManager *self,
NMDBusManagerSetPropertyHandler set_property_handler, NMDBusManagerSetPropertyHandler set_property_handler,
gpointer set_property_handler_data); gpointer set_property_handler_data);
void nm_dbus_manager_stop (NMDBusManager *self);
gboolean nm_dbus_manager_is_stopping (NMDBusManager *self);
GDBusConnection *nm_dbus_manager_get_connection (NMDBusManager *self); GDBusConnection *nm_dbus_manager_get_connection (NMDBusManager *self);
NMDBusObject *nm_dbus_manager_lookup_object (NMDBusManager *self, const char *path); NMDBusObject *nm_dbus_manager_lookup_object (NMDBusManager *self, const char *path);

View File

@@ -26,17 +26,6 @@
/*****************************************************************************/ /*****************************************************************************/
static gboolean quitting = FALSE;
void
nm_dbus_object_set_quitting (void)
{
nm_assert (!quitting);
quitting = TRUE;
}
/*****************************************************************************/
enum { enum {
EXPORTED_CHANGED, EXPORTED_CHANGED,
@@ -291,7 +280,7 @@ dispose (GObject *object)
* we are quitting, where many objects stick around until exit. * we are quitting, where many objects stick around until exit.
*/ */
if (self->internal.path) { if (self->internal.path) {
if (!quitting) if (!nm_dbus_manager_is_stopping (nm_dbus_object_get_manager (self)))
g_warn_if_reached (); g_warn_if_reached ();
nm_dbus_object_unexport (self); nm_dbus_object_unexport (self);
} }

View File

@@ -28,10 +28,6 @@
/*****************************************************************************/ /*****************************************************************************/
void nm_dbus_object_set_quitting (void);
/*****************************************************************************/
typedef struct { typedef struct {
const char *path; const char *path;

View File

@@ -122,6 +122,7 @@ typedef struct _NMDBusMethodInfoExtended {
const char *sender, const char *sender,
GDBusMethodInvocation *invocation, GDBusMethodInvocation *invocation,
GVariant *parameters); GVariant *parameters);
bool allow_during_shutdown;
} NMDBusMethodInfoExtended; } NMDBusMethodInfoExtended;
#define NM_DEFINE_DBUS_METHOD_INFO_EXTENDED(parent_, ...) \ #define NM_DEFINE_DBUS_METHOD_INFO_EXTENDED(parent_, ...) \

View File

@@ -635,6 +635,12 @@ nm_dbus_manager_get (void)
return NULL; return NULL;
} }
gboolean
nm_dbus_manager_is_stopping (NMDBusManager *self)
{
return FALSE;
}
void void
_nm_dbus_manager_obj_export (NMDBusObject *obj) _nm_dbus_manager_obj_export (NMDBusObject *obj)
{ {

View File

@@ -5918,7 +5918,6 @@ nm_manager_stop (NMManager *self)
NMDevice *device; NMDevice *device;
/* FIXME(shutdown): we don't do a proper shutdown yet: /* FIXME(shutdown): we don't do a proper shutdown yet:
* - need to tell NMDBusManager that all future D-Bus requests are rejected
* - need to ensure that all pending async operations are cancelled * - need to ensure that all pending async operations are cancelled
* - e.g. operations in priv->async_op_lst_head * - e.g. operations in priv->async_op_lst_head
* - need to ensure that no more asynchronous requests are started, * - need to ensure that no more asynchronous requests are started,
@@ -5931,6 +5930,8 @@ nm_manager_stop (NMManager *self)
* - e.g. see comment at nm_auth_manager_force_shutdown() * - e.g. see comment at nm_auth_manager_force_shutdown()
*/ */
nm_dbus_manager_stop (nm_dbus_object_get_manager (NM_DBUS_OBJECT (self)));
while ((device = c_list_first_entry (&priv->devices_lst_head, NMDevice, devices_lst))) while ((device = c_list_first_entry (&priv->devices_lst_head, NMDevice, devices_lst)))
remove_device (self, device, TRUE, TRUE); remove_device (self, device, TRUE, TRUE);