mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-05-04 02:28:02 +02:00
merge: really implement DEACTIVATING state and fix re-activation crash (rh #1058843)
Really implement the DEACTIVATING state this time. This now allows easy "pre-down" hooks whenever we choose to implement that. Next, fix a crash during re-activation where a pending activation request mis-interpreted device state changes from a previous activation request that was deactivating.
This commit is contained in:
commit
53720c3837
5 changed files with 52 additions and 49 deletions
|
|
@ -229,6 +229,7 @@ typedef struct {
|
|||
|
||||
guint32 ip4_address;
|
||||
|
||||
NMActRequest * queued_act_request;
|
||||
NMActRequest * act_request;
|
||||
guint act_source_id;
|
||||
gpointer act_source_func;
|
||||
|
|
@ -4436,11 +4437,7 @@ nm_device_activate_ip6_state_in_wait (NMDevice *self)
|
|||
static void
|
||||
clear_act_request (NMDevice *self)
|
||||
{
|
||||
NMDevicePrivate * priv;
|
||||
|
||||
g_return_if_fail (self != NULL);
|
||||
|
||||
priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
|
||||
if (!priv->act_request)
|
||||
return;
|
||||
|
|
@ -4452,8 +4449,7 @@ clear_act_request (NMDevice *self)
|
|||
priv->master_ready_id = 0;
|
||||
}
|
||||
|
||||
g_object_unref (priv->act_request);
|
||||
priv->act_request = NULL;
|
||||
g_clear_object (&priv->act_request);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -4812,8 +4808,8 @@ impl_device_disconnect (NMDevice *device, DBusGMethodInvocation *context)
|
|||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
nm_device_activate (NMDevice *self, NMActRequest *req)
|
||||
static void
|
||||
_device_activate (NMDevice *self, NMActRequest *req)
|
||||
{
|
||||
NMDevicePrivate *priv;
|
||||
NMConnection *connection;
|
||||
|
|
@ -4840,16 +4836,32 @@ nm_device_activate (NMDevice *self, NMActRequest *req)
|
|||
priv->act_request = g_object_ref (req);
|
||||
g_object_notify (G_OBJECT (self), NM_DEVICE_ACTIVE_CONNECTION);
|
||||
|
||||
/* HACK: update the state a bit early to avoid a race between the
|
||||
* scheduled stage1 handler and nm_policy_device_change_check() thinking
|
||||
* that the activation request isn't deferred because the deferred bit
|
||||
* gets cleared a bit too early, when the connection becomes valid.
|
||||
*/
|
||||
nm_device_state_changed (self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE);
|
||||
|
||||
nm_device_activate_schedule_stage1_device_prepare (self);
|
||||
}
|
||||
|
||||
void
|
||||
nm_device_queue_activation (NMDevice *self, NMActRequest *req)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
|
||||
if (!priv->act_request) {
|
||||
/* Just activate immediately */
|
||||
_device_activate (self, req);
|
||||
return;
|
||||
}
|
||||
|
||||
/* supercede any already-queued request */
|
||||
g_clear_object (&priv->queued_act_request);
|
||||
priv->queued_act_request = g_object_ref (req);
|
||||
|
||||
/* Deactivate existing activation request first */
|
||||
nm_log_info (LOGD_DEVICE, "(%s): disconnecting for new activation request.",
|
||||
nm_device_get_iface (self));
|
||||
nm_device_state_changed (self,
|
||||
NM_DEVICE_STATE_DEACTIVATING,
|
||||
NM_DEVICE_STATE_REASON_NONE);
|
||||
}
|
||||
|
||||
/*
|
||||
* nm_device_is_activating
|
||||
*
|
||||
|
|
@ -5554,6 +5566,7 @@ dispose (GObject *object)
|
|||
activation_source_clear (self, TRUE, AF_INET6);
|
||||
|
||||
clear_act_request (self);
|
||||
g_clear_object (&priv->queued_act_request);
|
||||
|
||||
platform = nm_platform_get ();
|
||||
g_signal_handlers_disconnect_by_func (platform, G_CALLBACK (device_ip_changed), self);
|
||||
|
|
@ -6422,8 +6435,10 @@ nm_device_state_changed (NMDevice *device,
|
|||
/* Cache the activation request for the dispatcher */
|
||||
req = priv->act_request ? g_object_ref (priv->act_request) : NULL;
|
||||
|
||||
if (state <= NM_DEVICE_STATE_UNAVAILABLE)
|
||||
if (state <= NM_DEVICE_STATE_UNAVAILABLE) {
|
||||
_clear_available_connections (device, TRUE);
|
||||
g_clear_object (&priv->queued_act_request);
|
||||
}
|
||||
|
||||
/* Update the available connections list when a device first becomes available */
|
||||
if ( state >= NM_DEVICE_STATE_DISCONNECTED
|
||||
|
|
@ -6508,7 +6523,14 @@ nm_device_state_changed (NMDevice *device,
|
|||
nm_device_queue_state (device, NM_DEVICE_STATE_DISCONNECTED, reason);
|
||||
break;
|
||||
case NM_DEVICE_STATE_DISCONNECTED:
|
||||
if (old_state > NM_DEVICE_STATE_DISCONNECTED && priv->default_unmanaged)
|
||||
if (priv->queued_act_request) {
|
||||
NMActRequest *queued_req;
|
||||
|
||||
queued_req = priv->queued_act_request;
|
||||
priv->queued_act_request = NULL;
|
||||
_device_activate (device, queued_req);
|
||||
g_object_unref (queued_req);
|
||||
} else if (old_state > NM_DEVICE_STATE_DISCONNECTED && priv->default_unmanaged)
|
||||
nm_device_queue_state (device, NM_DEVICE_STATE_UNMANAGED, NM_DEVICE_STATE_REASON_NONE);
|
||||
break;
|
||||
case NM_DEVICE_STATE_ACTIVATED:
|
||||
|
|
|
|||
|
|
@ -314,7 +314,7 @@ void nm_device_queue_ip_config_change (NMDevice *self);
|
|||
|
||||
gboolean nm_device_get_firmware_missing (NMDevice *self);
|
||||
|
||||
void nm_device_activate (NMDevice *device, NMActRequest *req);
|
||||
void nm_device_queue_activation (NMDevice *device, NMActRequest *req);
|
||||
|
||||
void nm_device_set_connection_provider (NMDevice *device, NMConnectionProvider *provider);
|
||||
|
||||
|
|
|
|||
|
|
@ -307,6 +307,10 @@ device_state_changed (NMActiveConnection *active,
|
|||
{
|
||||
NMActiveConnectionState ac_state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN;
|
||||
|
||||
/* Ignore state changes when this activation request is not yet active */
|
||||
if (NM_ACTIVE_CONNECTION (nm_device_get_act_request (device)) != active)
|
||||
return;
|
||||
|
||||
/* Set NMActiveConnection state based on the device's state */
|
||||
switch (new_state) {
|
||||
case NM_DEVICE_STATE_PREPARE:
|
||||
|
|
|
|||
|
|
@ -325,28 +325,12 @@ device_state_changed (NMDevice *device,
|
|||
NMActiveConnection *self = NM_ACTIVE_CONNECTION (user_data);
|
||||
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
||||
|
||||
/* When already deactivated or before activation, device state changes are useless */
|
||||
if (priv->state >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATED)
|
||||
return;
|
||||
if (old_state < NM_DEVICE_STATE_DISCONNECTED)
|
||||
return;
|
||||
|
||||
if (old_state > NM_DEVICE_STATE_DISCONNECTED) {
|
||||
/* Ignore disconnects if this ActiveConnection has not yet started
|
||||
* activating. This is caused by activating a device when it's
|
||||
* already activated, which causes a deactivating of the device before
|
||||
* activating the new connection.
|
||||
*/
|
||||
if (new_state == NM_DEVICE_STATE_DISCONNECTED &&
|
||||
old_state > NM_DEVICE_STATE_DISCONNECTED &&
|
||||
priv->state == NM_ACTIVE_CONNECTION_STATE_UNKNOWN) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the device used to be active, but now is disconnected/failed, we
|
||||
* no longer care about its state.
|
||||
*/
|
||||
if (new_state <= NM_DEVICE_STATE_DISCONNECTED || new_state == NM_DEVICE_STATE_FAILED)
|
||||
g_signal_handlers_disconnect_by_func (device, G_CALLBACK (device_state_changed), self);
|
||||
}
|
||||
|
||||
/* Let subclasses handle the state change */
|
||||
if (NM_ACTIVE_CONNECTION_GET_CLASS (self)->device_state_changed)
|
||||
NM_ACTIVE_CONNECTION_GET_CLASS (self)->device_state_changed (self, device, new_state, old_state);
|
||||
|
|
@ -362,6 +346,8 @@ device_master_changed (GObject *object,
|
|||
NMActiveConnection *master;
|
||||
NMActiveConnectionState master_state;
|
||||
|
||||
if (NM_ACTIVE_CONNECTION (nm_device_get_act_request (device)) != self)
|
||||
return;
|
||||
if (!nm_device_get_master (device))
|
||||
return;
|
||||
g_signal_handlers_disconnect_by_func (device, G_CALLBACK (device_master_changed), self);
|
||||
|
|
|
|||
|
|
@ -1955,7 +1955,7 @@ add_device (NMManager *self, NMDevice *device, gboolean generate_con)
|
|||
nm_active_connection_set_assumed (active, TRUE);
|
||||
nm_active_connection_export (active);
|
||||
active_connection_add (self, active);
|
||||
nm_device_activate (device, NM_ACT_REQUEST (active));
|
||||
nm_device_queue_activation (device, NM_ACT_REQUEST (active));
|
||||
} else {
|
||||
nm_log_warn (LOGD_DEVICE, "assumed connection %s failed to activate: (%d) %s",
|
||||
nm_connection_get_path (connection),
|
||||
|
|
@ -2872,17 +2872,8 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError *
|
|||
nm_active_connection_get_path (master_ac));
|
||||
}
|
||||
|
||||
/* Tear down any existing connection */
|
||||
if (nm_device_get_act_request (device)) {
|
||||
nm_log_info (LOGD_DEVICE, "(%s): disconnecting for new activation request.",
|
||||
nm_device_get_iface (device));
|
||||
nm_device_state_changed (device,
|
||||
NM_DEVICE_STATE_DISCONNECTED,
|
||||
NM_DEVICE_STATE_REASON_NONE);
|
||||
}
|
||||
|
||||
/* Start the new activation */
|
||||
nm_device_activate (device, NM_ACT_REQUEST (active));
|
||||
nm_device_queue_activation (device, NM_ACT_REQUEST (active));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue