diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 5c87525b44..660e26a59d 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -288,6 +288,7 @@ typedef struct { /* master interface for bridge/bond/team slave */ NMDevice * master; gboolean enslaved; + guint master_ready_id; /* slave management */ gboolean is_master; @@ -1935,10 +1936,61 @@ nm_device_ip_config_should_fail (NMDevice *self, gboolean ip6) return FALSE; } +static void +master_ready_cb (NMActiveConnection *active, + GParamSpec *pspec, + NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMActiveConnection *master; + + g_assert (priv->state == NM_DEVICE_STATE_PREPARE); + + /* Notify a master device that it has a new slave */ + g_assert (nm_active_connection_get_master_ready (active)); + master = nm_active_connection_get_master (active); + + priv->master = g_object_ref (nm_active_connection_get_device (master)); + nm_device_master_add_slave (priv->master, self); + + nm_log_dbg (LOGD_DEVICE, "(%s): master connection ready; master device %s", + nm_device_get_iface (self), + nm_device_get_iface (priv->master)); + + if (priv->master_ready_id) { + g_signal_handler_disconnect (active, priv->master_ready_id); + priv->master_ready_id = 0; + } + + nm_device_activate_schedule_stage2_device_config (self); +} + static NMActStageReturn act_stage1_prepare (NMDevice *self, NMDeviceStateReason *reason) { - return NM_ACT_STAGE_RETURN_SUCCESS; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; + NMActiveConnection *active = NM_ACTIVE_CONNECTION (priv->act_request); + + if (nm_active_connection_get_master (active)) { + /* If the master connection is ready for slaves, attach ourselves */ + if (nm_active_connection_get_master_ready (active)) + master_ready_cb (active, NULL, self); + else { + nm_log_dbg (LOGD_DEVICE, "(%s): waiting for master connection to become ready", + nm_device_get_iface (self)); + + /* Attach a signal handler and wait for the master connection to begin activating */ + g_assert (priv->master_ready_id == 0); + priv->master_ready_id = g_signal_connect (active, + "notify::" NM_ACTIVE_CONNECTION_INT_MASTER_READY, + (GCallback) master_ready_cb, + self); + ret = NM_ACT_STAGE_RETURN_POSTPONE; + } + } + + return ret; } /* @@ -4024,6 +4076,11 @@ clear_act_request (NMDevice *self) nm_active_connection_set_default (NM_ACTIVE_CONNECTION (priv->act_request), FALSE); + if (priv->master_ready_id) { + g_signal_handler_disconnect (priv->act_request, priv->master_ready_id); + priv->master_ready_id = 0; + } + g_object_unref (priv->act_request); priv->act_request = NULL; } @@ -4427,9 +4484,6 @@ nm_device_activate (NMDevice *self, NMActRequest *req) nm_device_state_changed (self, NM_DEVICE_STATE_IP_CONFIG, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); nm_device_activate_schedule_stage3_ip_config_start (self); } else { - NMActiveConnection *master; - NMDevice *master_device; - /* 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 @@ -4437,20 +4491,6 @@ nm_device_activate (NMDevice *self, NMActRequest *req) */ nm_device_state_changed (self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE); - /* Handle any dependencies this connection might have */ - master = nm_active_connection_get_master (NM_ACTIVE_CONNECTION (req)); - if (master) { - master_device = nm_active_connection_get_device (master); - if (master_device) { - /* Master should at least already be activating */ - g_assert (nm_device_get_state (master_device) > NM_DEVICE_STATE_DISCONNECTED); - - g_assert (priv->master == NULL); - priv->master = g_object_ref (master_device); - nm_device_master_add_slave (master_device, self); - } - } - nm_device_activate_schedule_stage1_device_prepare (self); } } @@ -5033,6 +5073,7 @@ dispose (GObject *object) dnsmasq_cleanup (self); g_warn_if_fail (priv->slaves == NULL); + g_assert (priv->master_ready_id == 0); /* Take the device itself down and clear its IPv4 configuration */ if (nm_device_get_managed (self) && deconfigure) {