summaryrefslogtreecommitdiff
path: root/src/nm-manager.c
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2020-08-11 15:34:59 +0200
committerThomas Haller <thaller@redhat.com>2020-08-12 08:32:08 +0200
commite6418f03d3b2de0c8d9ed37c8594b699183eba7b (patch)
treeb4f0e874351a61bd968cf974455fef7e44319b07 /src/nm-manager.c
parent698c4ae35efbfce105c399300c413350682b9aac (diff)
downloadNetworkManager-th/settings-wait-device-timeout.tar.gz
settings: rework wait-device-timeout handling and consider device compatibilityth/settings-wait-device-timeout
A profile can configure "connection.wait-device-timeout" to indicate that startup complete is blocked until a suitable device around. This is useful for NetworkManager-wait-online and initrd mode. Previously, we looked at NMPlatform whether a link with matching interface-name was present. That is wrong because it cannot handle profiles that rely on "ethernet.mac-address" setting or other "match" settings. Also, the mere presence of the link does not yet mean that the NMDevice was created and ready. In fact, there is a race here: NMPlatform indicates that the device is ready (unblocking NMSettings), but there is no corresponding NMDevice yet which keeps NetworkManager busy to block startup complete. Rework this. Now, only check whether there is a compatible device for the profile. Since we wait for compatible devices, it works now not only for the interface name. Note that we do some optimizations so that we don't have to re-evaluate all profiles (w.r.t. all devices) whenever something on the device changes: we only care about this when all devices finally become ready. Also, we no longer start the timeout for "connection.wait-device-timeout" when the profile appears. Instead, there is one system-wide start time (NMSettingsPrivate.startup_complete_start_timestamp_msec). That simplifies code and makes sense: we start waiting when NetworkManager is starting, not when the profile gets added. Also, we wait for all profiles to become ready together.
Diffstat (limited to 'src/nm-manager.c')
-rw-r--r--src/nm-manager.c32
1 files changed, 25 insertions, 7 deletions
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 487446d541..8e8723349a 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -1561,13 +1561,6 @@ check_if_startup_complete (NMManager *self)
if (!priv->devices_inited)
return;
- reason = nm_settings_get_startup_complete_blocked_reason (priv->settings);
- if (reason) {
- _LOGD (LOGD_CORE, "startup complete is waiting for connection (%s)",
- reason);
- return;
- }
-
c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) {
reason = nm_device_has_pending_action_reason (device);
if (reason) {
@@ -1578,6 +1571,31 @@ check_if_startup_complete (NMManager *self)
}
}
+ /* All NMDevice must be ready. But also NMSettings tracks profiles that wait for
+ * ready devices via "connection.wait-device-timeout".
+ *
+ * Note that we only re-check nm_settings_get_startup_complete_blocked_reason() when
+ * all of the devices become ready (again).
+ *
+ * For example, assume we have device "eth1" and "profile-eth2" which waits for "eth2".
+ * If "eth1" is ready (no pending action), we only need to re-evaluate "profile-eth2"
+ * if we have another device ("eth2"), that becomes non-ready (had pending actions)
+ * and again become ready. We don't need to check "profile-eth2" until "eth2" becomes
+ * non-ready.
+ * That is why nm_settings_get_startup_complete_blocked_reason() only has any significance
+ * if all devices are ready too. It allows us to cut down the number of checks whether
+ * NMSettings is ready. That's because we don't need to re-evaluate on minor changes of
+ * a device, only when all devices become managed and ready. */
+
+ g_signal_handlers_block_by_func (priv->settings, settings_startup_complete_changed, self);
+ reason = nm_settings_get_startup_complete_blocked_reason (priv->settings, TRUE);
+ g_signal_handlers_unblock_by_func (priv->settings, settings_startup_complete_changed, self);
+ if (reason) {
+ _LOGD (LOGD_CORE, "startup complete is waiting for connection (%s)",
+ reason);
+ return;
+ }
+
_LOGI (LOGD_CORE, "startup complete");
priv->startup = FALSE;