diff options
author | Thomas Haller <thaller@redhat.com> | 2022-04-14 13:09:05 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2022-04-15 09:04:30 +0200 |
commit | cef5b8dd46126f19c208f2469c6b8b6e4aa04030 (patch) | |
tree | b36933ecc18c14da9be734ee9ce2b2275ecf6ded | |
parent | f2abcf20827deaaaf54082dbc74657ab19666dcd (diff) |
dns: prevent update-pending to hang indefinitely
For example, if you have a dnsmasq service running and bound to port 53, then
NetworkManager's [main].dns=dnsmasq will fail to start. And we keep retrying
to start it. But then update pending would hang indefinitely, and devices could
not become active. That must not happen.
Give the DNS update only 5 seconds. If it's not done by then, assume we
have a problem and unblock.
-rw-r--r-- | src/core/dns/nm-dns-manager.c | 43 |
1 files changed, 42 insertions, 1 deletions
diff --git a/src/core/dns/nm-dns-manager.c b/src/core/dns/nm-dns-manager.c index 0d6ade2b2d..afda300bd2 100644 --- a/src/core/dns/nm-dns-manager.c +++ b/src/core/dns/nm-dns-manager.c @@ -56,6 +56,8 @@ #define HAS_NETCONFIG 1 #endif +#define UPDATE_PENDING_UNBLOCK_TIMEOUT_MSEC 5000 + /*****************************************************************************/ typedef enum { SR_SUCCESS, SR_NOTFOUND, SR_ERROR } SpawnResult; @@ -92,6 +94,11 @@ typedef struct { CList ip_data_lst_head; GVariant *config_variant; + /* A DNS plugin should not be marked as pending indefinitely. + * We are only blocked if "update_pending" is TRUE and we have + * "update_pending_unblock" timer ticking. */ + GSource *update_pending_unblock; + bool ip_data_lst_need_sort : 1; bool configs_lst_need_sort : 1; @@ -222,6 +229,25 @@ _update_pending_detect(NMDnsManager *self) return FALSE; } +static gboolean +_update_pending_unblock_cb(gpointer user_data) +{ + NMDnsManager *self = user_data; + NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE(self); + + nm_assert(priv->update_pending); + nm_assert(priv->update_pending_unblock); + nm_assert(_update_pending_detect(self)); + + nm_clear_g_source_inst(&priv->update_pending_unblock); + + _LOGW( + "update-pending changed: DNS plugin did not become ready again. Assume something is wrong"); + + _notify(self, PROP_UPDATE_PENDING); + return G_SOURCE_CONTINUE; +} + static void _update_pending_maybe_changed(NMDnsManager *self) { @@ -232,6 +258,14 @@ _update_pending_maybe_changed(NMDnsManager *self) if (priv->update_pending == update_pending) return; + if (update_pending) { + nm_assert(!priv->update_pending_unblock); + priv->update_pending_unblock = nm_g_timeout_add_source(UPDATE_PENDING_UNBLOCK_TIMEOUT_MSEC, + _update_pending_unblock_cb, + self); + } else + nm_clear_g_source_inst(&priv->update_pending_unblock); + priv->update_pending = update_pending; _LOGD("update-pending changed: %spending", update_pending ? "" : "not "); _notify(self, PROP_UPDATE_PENDING); @@ -252,7 +286,12 @@ nm_dns_manager_get_update_pending(NMDnsManager *self) priv = NM_DNS_MANAGER_GET_PRIVATE(self); nm_assert(priv->update_pending == _update_pending_detect(self)); - return priv->update_pending; + nm_assert(priv->update_pending || !priv->update_pending_unblock); + + /* update-pending can only be TRUE for a certain time (before we assume + * something is really wrong with the plugin). That is, as long as + * update_pending_unblock is ticking. */ + return !!priv->update_pending_unblock; } /*****************************************************************************/ @@ -2727,6 +2766,8 @@ dispose(GObject *object) _clear_sd_resolved_plugin(self); _clear_plugin(self); + nm_clear_g_source_inst(&priv->update_pending_unblock); + c_list_for_each_entry_safe (ip_data, ip_data_safe, &priv->ip_data_lst_head, ip_data_lst) _dns_config_ip_data_free(ip_data); |