summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2014-02-17 17:16:08 -0600
committerDan Williams <dcbw@redhat.com>2014-02-25 18:03:02 -0600
commit4040198b47ba4291111f4444ae29ed7bdfc1eca1 (patch)
tree1333dffce272cb6f6d27b1465f83176e4c0ac09f
parent037c67f471cfff92946c86cdefe6c35892d1a9ba (diff)
downloadNetworkManager-4040198b47ba4291111f4444ae29ed7bdfc1eca1.tar.gz
core: queue re-activations to allow DEACTIVATING state
If a device is already activated, queue the new activation to allow the transition through the DEACTIVATING state. --- Also remove the "HACK" bits in nm_device_deactivate(). This hack was added on 2007-09-25 in commit 9c2848d. At the time, with user settings services, if a client created a connection and requested that NM activate it, NM may not have read the connection from the client over D-Bus yet. So NM created a "deferred" activation request which waited until the connection was read from the client, and then began activation. The Policy watched for device state changes and other events (like it does now) and activated a new device if the old one was no longer valid. It specifically checked for deferred activations and then did nothing. However, when the client's connection was read, then nm-device.c cleared the deferred activation bit, leading to a short period of time where the device was in DISCONNECTED state but there was no deferred activation, because the device only changes state to PREPARE from the idle handler for stage1. If other events happened during this time, the policy would tear down the device that was about to be activated. This early state transition to PREPARE worked around that. We need to remove it now though, because (a) the reason for its existence is no longer valid, and (b) _device_activate() may now be called from inside nm_device_state_changed() and thus it cannot change to a new state inside the function.
-rw-r--r--src/devices/nm-device.c58
-rw-r--r--src/devices/nm-device.h2
-rw-r--r--src/nm-manager.c13
3 files changed, 43 insertions, 30 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 9c21b19e75..dca4257b96 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -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:
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index 9a6c77ad99..c346ccb42e 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -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);
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 7cb71a63c7..da99a02d77 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -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;
}