settings: prune old entries from keyfile databases

We have two GKeyfile files (timestamps and seen-bssids).

When a profile was deleted while NetworkManager was running, then
entries were removed from these keyfiles. But if a profile disappeared
while NetworkManger was stopped, then those UUIDs piled up.
This also happens if you have temporary connections in /run and reboot.

We need a way to garbage collect entries that are no longer relevant.

As the keyfile databases only get loaded once from disk, we will prune
all UUIDs for which we have no more connection loaded, on the first time
we write out the files again.

Note what this means: if you "temporarily" remove a connection profile
(without NetworkManager noticing) and restore it later, then the additional
information might have been pruned. There is no way how NetworkManager
could know that this UUID is coming back. The alternative is what we did
before: pile them up indefinitely. That seems more problematic.
This commit is contained in:
Thomas Haller 2021-06-24 21:47:15 +02:00
parent f59def45c1
commit 2e720a1dc8
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728

View file

@ -388,6 +388,9 @@ typedef struct {
guint kf_db_flush_idle_id_timestamps;
guint kf_db_flush_idle_id_seen_bssids;
bool kf_db_pruned_timestamps;
bool kf_db_pruned_seen_bssid;
bool started : 1;
/* Whether NMSettingsConnections changed in a way that affects the comparison
@ -3684,6 +3687,37 @@ again:
/*****************************************************************************/
static gboolean
_kf_db_prune_predicate(const char *uuid, gpointer user_data)
{
return !!nm_settings_get_connection_by_uuid(user_data, uuid);
}
static void
_kf_db_to_file(NMSettings *self, gboolean is_timestamps, gboolean force_write)
{
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE(self);
NMKeyFileDB * kf_db;
bool * p_kf_db_pruned;
if (is_timestamps) {
kf_db = priv->kf_db_timestamps;
p_kf_db_pruned = &priv->kf_db_pruned_timestamps;
} else {
kf_db = priv->kf_db_seen_bssids;
p_kf_db_pruned = &priv->kf_db_pruned_seen_bssid;
}
if (!*p_kf_db_pruned) {
/* we only prune the DB once, because afterwards every
* add/remove of an connection will lead to a direct update. */
*p_kf_db_pruned = TRUE;
nm_key_file_db_prune(kf_db, _kf_db_prune_predicate, self);
}
nm_key_file_db_to_file(kf_db, force_write);
}
G_GNUC_PRINTF(4, 5)
static void
_kf_db_log_fcn(NMKeyFileDB *kf_db, int syslog_level, gpointer user_data, const char *fmt, ...)
@ -3732,7 +3766,7 @@ _kf_db_got_dirty_flush(NMSettings *self, gboolean is_timestamps)
}
if (nm_key_file_db_is_dirty(kf_db))
nm_key_file_db_to_file(kf_db, FALSE);
_kf_db_to_file(self, is_timestamps, FALSE);
else {
_LOGT("[%s-keyfile]: skip saving changes to \"%s\"",
prefix,
@ -3785,15 +3819,10 @@ _kf_db_got_dirty_fcn(NMKeyFileDB *kf_db, gpointer user_data)
void
nm_settings_kf_db_write(NMSettings *self)
{
NMSettingsPrivate *priv;
g_return_if_fail(NM_IS_SETTINGS(self));
priv = NM_SETTINGS_GET_PRIVATE(self);
if (priv->kf_db_timestamps)
nm_key_file_db_to_file(priv->kf_db_timestamps, TRUE);
if (priv->kf_db_seen_bssids)
nm_key_file_db_to_file(priv->kf_db_seen_bssids, TRUE);
_kf_db_to_file(self, TRUE, TRUE);
_kf_db_to_file(self, FALSE, TRUE);
}
/*****************************************************************************/
@ -4031,8 +4060,8 @@ finalize(GObject *object)
nm_clear_g_source(&priv->kf_db_flush_idle_id_timestamps);
nm_clear_g_source(&priv->kf_db_flush_idle_id_seen_bssids);
nm_key_file_db_to_file(priv->kf_db_timestamps, FALSE);
nm_key_file_db_to_file(priv->kf_db_seen_bssids, FALSE);
_kf_db_to_file(self, TRUE, FALSE);
_kf_db_to_file(self, FALSE, FALSE);
nm_key_file_db_destroy(priv->kf_db_timestamps);
nm_key_file_db_destroy(priv->kf_db_seen_bssids);