core: fix duplicating (not removing) active connections

This is a regression introduced by reworked active connections tracking:
7258dd270f core: add the NM_ACTIVE_CONNECTION_STATE_DEACTIVATED state
59420add04 core: track active connections directly in the manager

Because nm-manager.c:active_connection_state_changed() postpones active
connection removal to an idle handler (to be able to receive last property
change notifications), we also need to ensure that NM_ACTIVE_CONNECTION_STATE_DEACTIVATED
state is not changed again in the meantime in nm-activation-request.c:device_state_changed().
After the NMActRequest was deactivated (which is a terminal state) it was still
listening to state changes of its child NMDevice which could be starting a
new activation request.  Thus the new activation's NMDevice state would cause
the old activation request's state to change from DEACTIVATED.  To fix this
stop listening to the child NMDevice when DEACTIVATED becuase there's no point
to doing so anyway.

Reproducer:
Just activate already active connection by clicking it in nm-applet or
run 'nmcli con up id <connnection name>' several times, and then check
active connections with 'nmcli c s'.
This commit is contained in:
Dan Williams
2013-02-11 11:15:45 -06:00
parent 527cbf1924
commit aa5013cf2d
2 changed files with 18 additions and 0 deletions

View File

@@ -297,6 +297,7 @@ nm_act_request_add_share_rule (NMActRequest *req,
static void static void
device_state_changed (NMDevice *device, GParamSpec *pspec, NMActRequest *self) device_state_changed (NMDevice *device, GParamSpec *pspec, NMActRequest *self)
{ {
NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (self);
NMActiveConnectionState ac_state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN; NMActiveConnectionState ac_state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN;
/* Set NMActiveConnection state based on the device's state */ /* Set NMActiveConnection state based on the device's state */
@@ -318,6 +319,13 @@ device_state_changed (NMDevice *device, GParamSpec *pspec, NMActRequest *self)
case NM_DEVICE_STATE_FAILED: case NM_DEVICE_STATE_FAILED:
case NM_DEVICE_STATE_DISCONNECTED: case NM_DEVICE_STATE_DISCONNECTED:
ac_state = NM_ACTIVE_CONNECTION_STATE_DEACTIVATED; ac_state = NM_ACTIVE_CONNECTION_STATE_DEACTIVATED;
/* No longer need to pay attention to device state */
if (priv->device && priv->device_state_id) {
g_signal_handler_disconnect (priv->device, priv->device_state_id);
priv->device_state_id = 0;
}
g_clear_object (&priv->device);
break; break;
default: default:
break; break;

View File

@@ -101,6 +101,10 @@ nm_active_connection_set_state (NMActiveConnection *self,
if (priv->state == new_state) if (priv->state == new_state)
return; return;
/* DEACTIVATED is a terminal state */
if (priv->state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED)
g_return_if_fail (new_state != NM_ACTIVE_CONNECTION_STATE_DEACTIVATED);
old_state = priv->state; old_state = priv->state;
priv->state = new_state; priv->state = new_state;
g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_STATE); g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_STATE);
@@ -110,6 +114,12 @@ nm_active_connection_set_state (NMActiveConnection *self,
nm_settings_connection_update_timestamp (NM_SETTINGS_CONNECTION (priv->connection), nm_settings_connection_update_timestamp (NM_SETTINGS_CONNECTION (priv->connection),
(guint64) time (NULL), TRUE); (guint64) time (NULL), TRUE);
} }
if (priv->state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) {
/* Device is no longer relevant when deactivated */
g_clear_object (&priv->device);
g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DEVICES);
}
} }
const char * const char *