core: add generic queued state transitions
There are now three places we need delayed state transitions: 1) unavailable to disconnected 2) failed to disconnected 3) bond unavailable to disconnected (3) wasn't doing a delayed transition, but we can't change state from inside a state-change handler otherwise we may not end up fully processing the current state chagne. So it needs a delayed transition too; add some generic code to make that easier to do.
This commit is contained in:
@@ -342,7 +342,7 @@ device_state_changed (NMDevice *device,
|
|||||||
switch (priv->type) {
|
switch (priv->type) {
|
||||||
case NM_ETHERNET_TYPE_BOND:
|
case NM_ETHERNET_TYPE_BOND:
|
||||||
/* Use NM_DEVICE_STATE_REASON_CARRIER to make sure num retries is reset */
|
/* Use NM_DEVICE_STATE_REASON_CARRIER to make sure num retries is reset */
|
||||||
nm_device_state_changed (device, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_CARRIER);
|
nm_device_queue_state (device, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_CARRIER);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
115
src/nm-device.c
115
src/nm-device.c
@@ -153,13 +153,18 @@ typedef enum {
|
|||||||
IP_DONE
|
IP_DONE
|
||||||
} IpState;
|
} IpState;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
NMDeviceState state;
|
||||||
|
NMDeviceStateReason reason;
|
||||||
|
guint id;
|
||||||
|
} QueuedState;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
gboolean disposed;
|
gboolean disposed;
|
||||||
gboolean initialized;
|
gboolean initialized;
|
||||||
|
|
||||||
NMDeviceState state;
|
NMDeviceState state;
|
||||||
guint failed_to_disconnected_id;
|
QueuedState queued_state;
|
||||||
guint unavailable_to_disconnected_id;
|
|
||||||
|
|
||||||
char * udi;
|
char * udi;
|
||||||
char * path;
|
char * path;
|
||||||
@@ -2852,22 +2857,16 @@ clear_act_request (NMDevice *self)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
delayed_transitions_clear (NMDevice *self)
|
queued_state_clear (NMDevice *self)
|
||||||
{
|
{
|
||||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||||
|
|
||||||
if (priv->failed_to_disconnected_id) {
|
if (priv->queued_state.id) {
|
||||||
nm_log_dbg (LOGD_DEVICE, "(%s): clearing failed->disconnected transition",
|
nm_log_dbg (LOGD_DEVICE, "(%s): clearing queued state transition (id %d)",
|
||||||
nm_device_get_iface (self));
|
nm_device_get_iface (self), priv->queued_state.id);
|
||||||
g_source_remove (priv->failed_to_disconnected_id);
|
g_source_remove (priv->queued_state.id);
|
||||||
priv->failed_to_disconnected_id = 0;
|
|
||||||
}
|
|
||||||
if (priv->unavailable_to_disconnected_id) {
|
|
||||||
nm_log_dbg (LOGD_DEVICE, "(%s): clearing unavailable->disconnected transition",
|
|
||||||
nm_device_get_iface (self));
|
|
||||||
g_source_remove (priv->unavailable_to_disconnected_id);
|
|
||||||
priv->unavailable_to_disconnected_id = 0;
|
|
||||||
}
|
}
|
||||||
|
memset (&priv->queued_state, 0, sizeof (priv->queued_state));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -3018,8 +3017,8 @@ nm_device_deactivate (NMDevice *self, NMDeviceStateReason reason)
|
|||||||
activation_source_clear (self, TRUE, AF_INET);
|
activation_source_clear (self, TRUE, AF_INET);
|
||||||
activation_source_clear (self, TRUE, AF_INET6);
|
activation_source_clear (self, TRUE, AF_INET6);
|
||||||
|
|
||||||
/* Clear any delayed transitions */
|
/* Clear any queued transitions */
|
||||||
delayed_transitions_clear (self);
|
queued_state_clear (self);
|
||||||
|
|
||||||
priv->ip4_state = priv->ip6_state = IP_NONE;
|
priv->ip4_state = priv->ip6_state = IP_NONE;
|
||||||
|
|
||||||
@@ -3493,8 +3492,8 @@ dispose (GObject *object)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear any delayed transitions */
|
/* Clear any queued transitions */
|
||||||
delayed_transitions_clear (self);
|
queued_state_clear (self);
|
||||||
|
|
||||||
/* Clean up and stop DHCP */
|
/* Clean up and stop DHCP */
|
||||||
dhcp4_cleanup (self, take_down, FALSE);
|
dhcp4_cleanup (self, take_down, FALSE);
|
||||||
@@ -3909,32 +3908,6 @@ nm_device_class_init (NMDeviceClass *klass)
|
|||||||
dbus_g_error_domain_register (NM_DEVICE_ERROR, NULL, NM_TYPE_DEVICE_ERROR);
|
dbus_g_error_domain_register (NM_DEVICE_ERROR, NULL, NM_TYPE_DEVICE_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
failed_to_disconnected (gpointer user_data)
|
|
||||||
{
|
|
||||||
NMDevice *self = NM_DEVICE (user_data);
|
|
||||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
|
||||||
|
|
||||||
nm_log_dbg (LOGD_DEVICE, "(%s): running failed->disconnected transition",
|
|
||||||
nm_device_get_iface (self));
|
|
||||||
priv->failed_to_disconnected_id = 0;
|
|
||||||
nm_device_state_changed (self, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_NONE);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
unavailable_to_disconnected (gpointer user_data)
|
|
||||||
{
|
|
||||||
NMDevice *self = NM_DEVICE (user_data);
|
|
||||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
|
||||||
|
|
||||||
nm_log_dbg (LOGD_DEVICE, "(%s): running unavailable->disconnected transition",
|
|
||||||
nm_device_get_iface (self));
|
|
||||||
priv->unavailable_to_disconnected_id = 0;
|
|
||||||
nm_device_state_changed (self, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_NONE);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
nm_device_set_firmware_missing (NMDevice *self, gboolean new_missing)
|
nm_device_set_firmware_missing (NMDevice *self, gboolean new_missing)
|
||||||
{
|
{
|
||||||
@@ -4128,8 +4101,8 @@ nm_device_state_changed (NMDevice *device,
|
|||||||
state,
|
state,
|
||||||
reason);
|
reason);
|
||||||
|
|
||||||
/* Clear any delayed transitions */
|
/* Clear any queued transitions */
|
||||||
delayed_transitions_clear (device);
|
queued_state_clear (device);
|
||||||
|
|
||||||
/* Cache the activation request for the dispatcher */
|
/* Cache the activation request for the dispatcher */
|
||||||
req = priv->act_request ? g_object_ref (priv->act_request) : NULL;
|
req = priv->act_request ? g_object_ref (priv->act_request) : NULL;
|
||||||
@@ -4182,7 +4155,7 @@ nm_device_state_changed (NMDevice *device,
|
|||||||
if (nm_device_is_available (device)) {
|
if (nm_device_is_available (device)) {
|
||||||
nm_log_dbg (LOGD_DEVICE, "(%s): device is available, will transition to DISCONNECTED",
|
nm_log_dbg (LOGD_DEVICE, "(%s): device is available, will transition to DISCONNECTED",
|
||||||
nm_device_get_iface (device));
|
nm_device_get_iface (device));
|
||||||
priv->unavailable_to_disconnected_id = g_idle_add (unavailable_to_disconnected, device);
|
nm_device_queue_state (device, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_NONE);
|
||||||
} else {
|
} else {
|
||||||
nm_log_dbg (LOGD_DEVICE, "(%s): device not yet available for transition to DISCONNECTED",
|
nm_log_dbg (LOGD_DEVICE, "(%s): device not yet available for transition to DISCONNECTED",
|
||||||
nm_device_get_iface (device));
|
nm_device_get_iface (device));
|
||||||
@@ -4199,7 +4172,7 @@ nm_device_state_changed (NMDevice *device,
|
|||||||
* immediately because we can't change states again from the state
|
* immediately because we can't change states again from the state
|
||||||
* handler for a variety of reasons.
|
* handler for a variety of reasons.
|
||||||
*/
|
*/
|
||||||
priv->failed_to_disconnected_id = g_idle_add (failed_to_disconnected, device);
|
nm_device_queue_state (device, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_NONE);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -4213,6 +4186,52 @@ nm_device_state_changed (NMDevice *device,
|
|||||||
g_object_unref (req);
|
g_object_unref (req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
queued_set_state (gpointer user_data)
|
||||||
|
{
|
||||||
|
NMDevice *self = NM_DEVICE (user_data);
|
||||||
|
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||||
|
|
||||||
|
if (priv->queued_state.id) {
|
||||||
|
priv->queued_state.id = 0;
|
||||||
|
|
||||||
|
nm_log_dbg (LOGD_DEVICE, "(%s): running queued state change to %s (id %d)",
|
||||||
|
nm_device_get_iface (self),
|
||||||
|
state_to_string (priv->queued_state.state),
|
||||||
|
priv->queued_state.id);
|
||||||
|
nm_device_state_changed (self, priv->queued_state.state, priv->queued_state.reason);
|
||||||
|
}
|
||||||
|
queued_state_clear (self);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nm_device_queue_state (NMDevice *self,
|
||||||
|
NMDeviceState state,
|
||||||
|
NMDeviceStateReason reason)
|
||||||
|
{
|
||||||
|
NMDevicePrivate *priv;
|
||||||
|
|
||||||
|
g_return_if_fail (self != NULL);
|
||||||
|
g_return_if_fail (NM_IS_DEVICE (self));
|
||||||
|
|
||||||
|
priv = NM_DEVICE_GET_PRIVATE (self);
|
||||||
|
|
||||||
|
/* We should only ever have one delayed state transition at a time */
|
||||||
|
if (priv->queued_state.id) {
|
||||||
|
g_warn_if_fail (priv->queued_state.id == 0);
|
||||||
|
queued_state_clear (self);
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->queued_state.state = state;
|
||||||
|
priv->queued_state.reason = reason;
|
||||||
|
priv->queued_state.id = g_idle_add (queued_set_state, self);
|
||||||
|
|
||||||
|
nm_log_dbg (LOGD_DEVICE, "(%s): queued state change to %s (id %d)",
|
||||||
|
nm_device_get_iface (self), state_to_string (state),
|
||||||
|
priv->queued_state.id);
|
||||||
|
}
|
||||||
|
|
||||||
NMDeviceState
|
NMDeviceState
|
||||||
nm_device_get_state (NMDevice *device)
|
nm_device_get_state (NMDevice *device)
|
||||||
{
|
{
|
||||||
|
@@ -228,6 +228,10 @@ void nm_device_state_changed (NMDevice *device,
|
|||||||
NMDeviceState state,
|
NMDeviceState state,
|
||||||
NMDeviceStateReason reason);
|
NMDeviceStateReason reason);
|
||||||
|
|
||||||
|
void nm_device_queue_state (NMDevice *self,
|
||||||
|
NMDeviceState state,
|
||||||
|
NMDeviceStateReason reason);
|
||||||
|
|
||||||
gboolean nm_device_get_firmware_missing (NMDevice *self);
|
gboolean nm_device_get_firmware_missing (NMDevice *self);
|
||||||
|
|
||||||
gboolean nm_device_activate (NMDevice *device, NMActRequest *req, GError **error);
|
gboolean nm_device_activate (NMDevice *device, NMActRequest *req, GError **error);
|
||||||
|
Reference in New Issue
Block a user